forked from thoughtbot/administrate
/
dashboard_generator.rb
143 lines (119 loc) · 3.7 KB
/
dashboard_generator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
require "rails/generators/named_base"
module Administrate
module Generators
class DashboardGenerator < Rails::Generators::NamedBase
ATTRIBUTE_TYPE_MAPPING = {
boolean: "Field::Boolean",
date: "Field::Date",
datetime: "Field::DateTime",
enum: "Field::String",
float: "Field::Number",
integer: "Field::Number",
time: "Field::Time",
text: "Field::Text",
string: "Field::String",
}
ATTRIBUTE_OPTIONS_MAPPING = {
enum: { searchable: false },
float: { decimals: 2 },
}
DEFAULT_FIELD_TYPE = "Field::String.with_options(searchable: false)"
COLLECTION_ATTRIBUTE_LIMIT = 4
READ_ONLY_ATTRIBUTES = %w[id created_at updated_at]
class_option :namespace, type: :string, default: "admin"
source_root File.expand_path("../templates", __FILE__)
def create_dashboard_definition
template(
"dashboard.rb.erb",
Rails.root.join("app/dashboards/#{file_name}_dashboard.rb"),
)
end
def create_resource_controller
destination = Rails.root.join(
"app/controllers/#{namespace}/#{file_name.pluralize}_controller.rb",
)
template("controller.rb.erb", destination)
end
private
def namespace
options[:namespace]
end
def attributes
klass.reflections.keys +
klass.columns.map(&:name) -
redundant_attributes
end
def form_attributes
attributes - READ_ONLY_ATTRIBUTES
end
def redundant_attributes
klass.reflections.keys.flat_map do |relationship|
redundant_attributes_for(relationship)
end.compact
end
def redundant_attributes_for(relationship)
case association_type(relationship)
when "Field::Polymorphic"
[relationship + "_id", relationship + "_type"]
when "Field::BelongsTo"
relationship + "_id"
end
end
def field_type(attribute)
type = column_type_for_attribute(attribute.to_s)
if type
ATTRIBUTE_TYPE_MAPPING.fetch(type, DEFAULT_FIELD_TYPE) +
options_string(ATTRIBUTE_OPTIONS_MAPPING.fetch(type, {}))
else
association_type(attribute)
end
end
def column_type_for_attribute(attr)
if enum_column?(attr)
:enum
else
column_types(attr)
end
end
def enum_column?(attr)
klass.respond_to?(:defined_enums) &&
klass.defined_enums.keys.include?(attr)
end
def column_types(attr)
klass.columns.find { |column| column.name == attr }.try(:type)
end
def association_type(attribute)
relationship = klass.reflections[attribute.to_s]
if relationship.has_one?
"Field::HasOne"
elsif relationship.collection?
"Field::HasMany" + relationship_options_string(relationship)
elsif relationship.polymorphic?
"Field::Polymorphic"
else
"Field::BelongsTo" + relationship_options_string(relationship)
end
end
def klass
@klass ||= Object.const_get(class_name)
end
def relationship_options_string(relationship)
if relationship.class_name != relationship.name.to_s.classify
options_string(class_name: relationship.class_name)
else
""
end
end
def options_string(options)
if options.any?
".with_options(#{inspect_hash_as_ruby(options)})"
else
""
end
end
def inspect_hash_as_ruby(hash)
hash.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
end
end
end
end