terrazzo 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +101 -0
- data/Rakefile +1 -0
- data/app/controllers/terrazzo/application_controller.rb +63 -14
- data/app/helpers/terrazzo/collection_actions_helper.rb +38 -13
- data/app/helpers/terrazzo/resource_paths_helper.rb +55 -0
- data/app/views/terrazzo/application/_edit_base.json.props +7 -4
- data/app/views/terrazzo/application/_index_base.json.props +83 -7
- data/app/views/terrazzo/application/_navigation.json.props +7 -4
- data/app/views/terrazzo/application/_new_base.json.props +6 -3
- data/app/views/terrazzo/application/_show_base.json.props +7 -5
- data/lib/generators/terrazzo/dashboard/dashboard_generator.rb +48 -24
- data/lib/generators/terrazzo/dashboard/templates/controller.rb.erb +8 -4
- data/lib/generators/terrazzo/dashboard/templates/dashboard.rb.erb +33 -25
- data/lib/generators/terrazzo/eject/eject_generator.rb +223 -113
- data/lib/generators/terrazzo/field/field_generator.rb +51 -7
- data/lib/generators/terrazzo/field/templates/FormField.jsx.erb +2 -3
- data/lib/generators/terrazzo/install/install_generator.rb +641 -4
- data/lib/generators/terrazzo/install/templates/admin.css +2 -0
- data/lib/generators/terrazzo/install/templates/application.js.erb +3 -0
- data/lib/generators/terrazzo/install/templates/components.json.erb +17 -0
- data/lib/generators/terrazzo/install/templates/custom_page_mapping.js.erb +5 -0
- data/lib/generators/terrazzo/install/templates/generated_page_mapping.js.erb +10 -0
- data/lib/generators/terrazzo/install/templates/jsconfig.json +8 -0
- data/lib/generators/terrazzo/install/templates/page_to_page_mapping.js.erb +9 -1
- data/lib/generators/terrazzo/install/templates/superglue.html.erb.erb +2 -2
- data/lib/generators/terrazzo/routes/routes_generator.rb +55 -20
- data/lib/generators/terrazzo/views/edit_generator.rb +16 -10
- data/lib/generators/terrazzo/views/eject_compatibility.rb +19 -0
- data/lib/generators/terrazzo/views/field_generator.rb +18 -6
- data/lib/generators/terrazzo/views/generated_defaults_helper.rb +110 -0
- data/lib/generators/terrazzo/views/index_generator.rb +9 -8
- data/lib/generators/terrazzo/views/layout_generator.rb +4 -3
- data/lib/generators/terrazzo/views/navigation_generator.rb +5 -1
- data/lib/generators/terrazzo/views/new_generator.rb +16 -10
- data/lib/generators/terrazzo/views/page_mapping_helper.rb +131 -8
- data/lib/generators/terrazzo/views/show_generator.rb +7 -6
- data/lib/generators/terrazzo/views/templates/components/CollectionFilters.jsx +25 -0
- data/lib/generators/terrazzo/views/templates/components/CollectionItemActions.jsx +68 -0
- data/lib/generators/terrazzo/views/templates/components/CollectionToolbarActions.jsx +60 -0
- data/lib/generators/terrazzo/views/templates/components/HasManyPagination.jsx +36 -0
- data/lib/generators/terrazzo/views/templates/components/Layout.jsx +9 -4
- data/lib/generators/terrazzo/views/templates/components/Pagination.jsx +32 -24
- data/lib/generators/terrazzo/views/templates/components/ResourceTable.jsx +172 -0
- data/lib/generators/terrazzo/views/templates/components/SearchBar.jsx +14 -6
- data/lib/generators/terrazzo/views/templates/components/SortableHeader.jsx +7 -5
- data/lib/generators/terrazzo/views/templates/components/app-sidebar.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/components/site-header.jsx +2 -2
- data/lib/generators/terrazzo/views/templates/fields/asset/FormField.jsx +15 -0
- data/lib/generators/terrazzo/views/templates/fields/asset/IndexField.jsx +5 -0
- data/lib/generators/terrazzo/views/templates/fields/asset/ShowField.jsx +13 -0
- data/lib/generators/terrazzo/views/templates/fields/belongs_to/FormField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/boolean/FormField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/boolean/IndexField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/has_many/FormField.jsx +3 -3
- data/lib/generators/terrazzo/views/templates/fields/has_many/IndexField.jsx +4 -3
- data/lib/generators/terrazzo/views/templates/fields/has_many/ShowField.jsx +21 -35
- data/lib/generators/terrazzo/views/templates/fields/has_one/FormField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/hstore/FormField.jsx +5 -5
- data/lib/generators/terrazzo/views/templates/fields/hstore/IndexField.jsx +0 -2
- data/lib/generators/terrazzo/views/templates/fields/hstore/ShowField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/number/IndexField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/number/ShowField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/polymorphic/FormField.jsx +3 -2
- data/lib/generators/terrazzo/views/templates/fields/rich_text/FormField.jsx +2 -2
- data/lib/generators/terrazzo/views/templates/fields/select/FormField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/select/IndexField.jsx +1 -1
- data/lib/generators/terrazzo/views/templates/fields/shared/TextInputFormField.jsx +2 -2
- data/lib/generators/terrazzo/views/templates/fields/text/FormField.jsx +2 -2
- data/lib/generators/terrazzo/views/templates/pages/_collection.jsx +5 -3
- data/lib/generators/terrazzo/views/templates/pages/_form.jsx +37 -30
- data/lib/generators/terrazzo/views/templates/pages/_navigation.json.props +14 -4
- data/lib/generators/terrazzo/views/templates/pages/edit.jsx +6 -4
- data/lib/generators/terrazzo/views/templates/pages/index.jsx +20 -8
- data/lib/generators/terrazzo/views/templates/pages/new.jsx +8 -4
- data/lib/generators/terrazzo/views/templates/pages/show.jsx +30 -32
- data/lib/generators/terrazzo/views/views_generator.rb +9 -5
- data/lib/terrazzo/base_dashboard.rb +167 -5
- data/lib/terrazzo/csv_export.rb +38 -0
- data/lib/terrazzo/field/associative.rb +16 -4
- data/lib/terrazzo/field/base.rb +4 -0
- data/lib/terrazzo/field/belongs_to.rb +1 -2
- data/lib/terrazzo/field/deferred.rb +4 -0
- data/lib/terrazzo/field/has_many.rb +79 -11
- data/lib/terrazzo/field/password.rb +6 -0
- data/lib/terrazzo/field/rich_text.rb +13 -0
- data/lib/terrazzo/generator_helpers.rb +1 -1
- data/lib/terrazzo/has_many_pagination.rb +9 -1
- data/lib/terrazzo/namespace/resource.rb +30 -0
- data/lib/terrazzo/namespace.rb +26 -1
- data/lib/terrazzo/search.rb +29 -9
- data/lib/terrazzo/version.rb +1 -1
- data/lib/terrazzo.rb +1 -0
- data/terrazzo.gemspec +11 -1
- metadata +40 -6
- data/lib/generators/terrazzo/install/templates/application.json.props.erb +0 -17
- data/lib/generators/terrazzo/views/templates/fields/FieldRenderer.jsx +0 -103
- data/lib/generators/terrazzo/views/templates/fields/index.js +0 -81
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require_relative "../views/generated_defaults_helper"
|
|
2
3
|
|
|
3
4
|
module Terrazzo
|
|
4
5
|
module Generators
|
|
5
6
|
class EjectGenerator < Rails::Generators::Base
|
|
7
|
+
include Views::GeneratedDefaultsHelper
|
|
8
|
+
|
|
6
9
|
source_root File.expand_path("../views/templates", __dir__)
|
|
7
10
|
|
|
8
11
|
argument :target, type: :string,
|
|
@@ -22,9 +25,11 @@ module Terrazzo
|
|
|
22
25
|
when "pages"
|
|
23
26
|
eject_page
|
|
24
27
|
when "navigation"
|
|
28
|
+
raise_unknown_target unless target == "navigation"
|
|
29
|
+
|
|
25
30
|
eject_navigation
|
|
26
31
|
else
|
|
27
|
-
|
|
32
|
+
raise_unknown_target
|
|
28
33
|
end
|
|
29
34
|
end
|
|
30
35
|
|
|
@@ -42,13 +47,17 @@ module Terrazzo
|
|
|
42
47
|
options[:namespace]
|
|
43
48
|
end
|
|
44
49
|
|
|
50
|
+
def raise_unknown_target
|
|
51
|
+
raise Thor::Error,
|
|
52
|
+
"Unknown ejection target '#{target}'. Use fields/, components/, ui/, pages/, or navigation"
|
|
53
|
+
end
|
|
54
|
+
|
|
45
55
|
def eject_field
|
|
46
56
|
field_type = component_name
|
|
47
57
|
source_dir = "fields/#{field_type}"
|
|
48
58
|
|
|
49
59
|
unless File.directory?(File.join(self.class.source_root, source_dir))
|
|
50
|
-
|
|
51
|
-
return
|
|
60
|
+
raise Thor::Error, "Unknown field type '#{field_type}'"
|
|
52
61
|
end
|
|
53
62
|
|
|
54
63
|
%w[IndexField.jsx ShowField.jsx FormField.jsx].each do |file|
|
|
@@ -57,25 +66,29 @@ module Terrazzo
|
|
|
57
66
|
copy_file source, "app/views/#{namespace_name}/fields/#{field_type}/#{file}"
|
|
58
67
|
end
|
|
59
68
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"app/views/#{namespace_name}/fields/shared/TextInputFormField.jsx"
|
|
69
|
+
field_shared_dependencies(field_type).each do |dependency|
|
|
70
|
+
copy_file_unless_exists "fields/shared/#{dependency}.jsx",
|
|
71
|
+
"app/views/#{namespace_name}/fields/shared/#{dependency}.jsx"
|
|
64
72
|
end
|
|
65
73
|
|
|
74
|
+
ensure_ui_barrel
|
|
75
|
+
ensure_components_barrel
|
|
66
76
|
update_fields_barrel(field_type)
|
|
67
77
|
end
|
|
68
78
|
|
|
69
79
|
def eject_component
|
|
70
80
|
name = component_name
|
|
71
|
-
source = "components/#{name}.jsx"
|
|
72
81
|
|
|
73
|
-
unless
|
|
74
|
-
|
|
75
|
-
return
|
|
82
|
+
unless component_template_exists?(name)
|
|
83
|
+
raise Thor::Error, "Unknown component '#{name}'"
|
|
76
84
|
end
|
|
77
85
|
|
|
78
|
-
|
|
86
|
+
copy_component_template(name)
|
|
87
|
+
component_dependencies(name).each do |component|
|
|
88
|
+
copy_component_template_unless_exists(component)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
ensure_ui_barrel
|
|
79
92
|
update_components_barrel(name)
|
|
80
93
|
end
|
|
81
94
|
|
|
@@ -84,12 +97,15 @@ module Terrazzo
|
|
|
84
97
|
source = "components/ui/#{name}.jsx"
|
|
85
98
|
|
|
86
99
|
unless File.exist?(File.join(self.class.source_root, source))
|
|
87
|
-
|
|
88
|
-
return
|
|
100
|
+
raise Thor::Error, "Unknown UI component '#{name}'"
|
|
89
101
|
end
|
|
90
102
|
|
|
91
|
-
|
|
103
|
+
copy_ui_template(name)
|
|
92
104
|
update_ui_barrel(name)
|
|
105
|
+
|
|
106
|
+
ui_dependencies(name).each do |component|
|
|
107
|
+
update_ui_barrel(component) if copy_ui_template_unless_exists(component)
|
|
108
|
+
end
|
|
93
109
|
end
|
|
94
110
|
|
|
95
111
|
def eject_page
|
|
@@ -97,142 +113,236 @@ module Terrazzo
|
|
|
97
113
|
source = "pages/#{name}.jsx"
|
|
98
114
|
|
|
99
115
|
unless File.exist?(File.join(self.class.source_root, source))
|
|
100
|
-
|
|
101
|
-
return
|
|
116
|
+
raise Thor::Error, "Unknown page template '#{name}'"
|
|
102
117
|
end
|
|
103
118
|
|
|
104
|
-
|
|
119
|
+
ensure_page_barrels
|
|
120
|
+
copy_file_over_generated source, "app/views/#{namespace_name}/application/#{name}.jsx",
|
|
121
|
+
generated_content: generated_page_stub(name)
|
|
122
|
+
page_dependencies(name).each do |dependency|
|
|
123
|
+
copy_file_unless_exists "pages/#{dependency}.jsx",
|
|
124
|
+
"app/views/#{namespace_name}/application/#{dependency}.jsx"
|
|
125
|
+
end
|
|
126
|
+
eject_generated_form_counterpart(name)
|
|
105
127
|
end
|
|
106
128
|
|
|
107
129
|
def eject_navigation
|
|
108
|
-
source = File.join(Terrazzo::Engine.root, "app/views/terrazzo/application/_navigation.json.props")
|
|
109
130
|
dest = "app/views/#{namespace_name}/application/_navigation.json.props"
|
|
110
|
-
|
|
131
|
+
copy_file_over_generated "pages/_navigation.json.props", dest,
|
|
132
|
+
generated_content: generated_navigation_partial
|
|
111
133
|
say "\nNavigation partial ejected to #{dest}.", :green
|
|
112
134
|
say "Edit it to customize your admin navigation."
|
|
113
135
|
end
|
|
114
136
|
|
|
115
|
-
def field_uses_shared?(field_type)
|
|
116
|
-
%w[string number email url password date date_time time].include?(field_type)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
137
|
def update_fields_barrel(field_type)
|
|
120
|
-
barrel_path = "app/views/#{namespace_name}/fields/index.js"
|
|
121
|
-
barrel_file = File.join(destination_root, barrel_path)
|
|
122
|
-
|
|
123
138
|
type_label = field_type.split("_").map(&:capitalize).join("")
|
|
139
|
+
register_name = "register#{type_label}FieldType"
|
|
124
140
|
local_exports = <<~JS.strip
|
|
125
141
|
// #{type_label} - ejected
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
142
|
+
import { registerFieldType as #{register_name} } from "terrazzo/fields";
|
|
143
|
+
import { IndexField as #{type_label}IndexField } from "./#{field_type}/IndexField";
|
|
144
|
+
import { ShowField as #{type_label}ShowField } from "./#{field_type}/ShowField";
|
|
145
|
+
import { FormField as #{type_label}FormField } from "./#{field_type}/FormField";
|
|
146
|
+
|
|
147
|
+
#{register_name}("#{field_type}", {
|
|
148
|
+
index: #{type_label}IndexField,
|
|
149
|
+
show: #{type_label}ShowField,
|
|
150
|
+
form: #{type_label}FormField,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
export { #{type_label}IndexField, #{type_label}ShowField, #{type_label}FormField };
|
|
129
154
|
JS
|
|
130
155
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# If barrel is still the default re-export-all, replace with explicit exports
|
|
135
|
-
if content.include?('export * from "terrazzo/fields"')
|
|
136
|
-
new_content = build_fields_barrel_with_ejection(field_type)
|
|
137
|
-
create_file barrel_path, new_content, force: true
|
|
138
|
-
else
|
|
139
|
-
# Barrel already has explicit exports; replace the terrazzo re-export
|
|
140
|
-
# for this field type with local imports
|
|
141
|
-
unless content.include?("./#{field_type}/")
|
|
142
|
-
# Remove the existing terrazzo re-export line for this field type
|
|
143
|
-
terrazzo_export = "export { #{type_label}IndexField, #{type_label}ShowField, #{type_label}FormField } from \"terrazzo/fields\";"
|
|
144
|
-
if content.include?(terrazzo_export)
|
|
145
|
-
new_content = content.sub(terrazzo_export, local_exports)
|
|
146
|
-
create_file barrel_path, new_content, force: true
|
|
147
|
-
else
|
|
148
|
-
append_to_file barrel_path, "\n#{local_exports}\n"
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
156
|
+
ensure_fields_barrel
|
|
157
|
+
append_to_barrel(fields_barrel_path, local_exports, "./#{field_type}/IndexField")
|
|
153
158
|
end
|
|
154
159
|
|
|
155
|
-
def
|
|
156
|
-
|
|
157
|
-
string text number boolean date date_time time email url password
|
|
158
|
-
select rich_text belongs_to has_many has_one polymorphic hstore
|
|
159
|
-
]
|
|
160
|
+
def update_components_barrel(name)
|
|
161
|
+
export_name = component_export_name(name)
|
|
160
162
|
|
|
161
|
-
|
|
163
|
+
local_exports = if name == "Layout"
|
|
164
|
+
<<~JS.strip
|
|
165
|
+
// Layout - ejected
|
|
166
|
+
import { setLayout } from "terrazzo";
|
|
167
|
+
import { Layout } from "./Layout";
|
|
162
168
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
setLayout(Layout);
|
|
170
|
+
|
|
171
|
+
export { Layout };
|
|
172
|
+
JS
|
|
173
|
+
else
|
|
174
|
+
<<~JS.strip
|
|
175
|
+
// #{export_name} - ejected
|
|
176
|
+
import { registerComponent as register#{export_name}Component } from "terrazzo/components";
|
|
177
|
+
import { #{export_name} } from "./#{name}";
|
|
178
|
+
|
|
179
|
+
register#{export_name}Component("#{export_name}", #{export_name});
|
|
180
|
+
|
|
181
|
+
export { #{export_name} } from "./#{name}";
|
|
182
|
+
JS
|
|
173
183
|
end
|
|
174
184
|
|
|
175
|
-
|
|
185
|
+
ensure_components_barrel
|
|
186
|
+
append_to_barrel(components_barrel_path, local_exports, "./#{name}")
|
|
176
187
|
end
|
|
177
188
|
|
|
178
|
-
def
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
def update_ui_barrel(name)
|
|
190
|
+
local_exports = ui_component_exports(name)
|
|
191
|
+
ensure_ui_barrel
|
|
192
|
+
append_to_barrel(ui_barrel_path, "// #{name} - ejected\nexport { #{local_exports} } from \"./#{name}\";", "./#{name}")
|
|
193
|
+
end
|
|
183
194
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
195
|
+
def component_export_name(file_name)
|
|
196
|
+
case file_name
|
|
197
|
+
when "app-sidebar" then "AppSidebar"
|
|
198
|
+
when "site-header" then "SiteHeader"
|
|
199
|
+
else file_name
|
|
189
200
|
end
|
|
190
201
|
end
|
|
191
202
|
|
|
192
|
-
def
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
def component_template_exists?(name)
|
|
204
|
+
File.exist?(File.join(self.class.source_root, "components/#{name}.jsx"))
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def copy_component_template(name)
|
|
208
|
+
copy_file "components/#{name}.jsx", "app/views/#{namespace_name}/components/#{name}.jsx"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def copy_component_template_unless_exists(name)
|
|
212
|
+
copy_file_unless_exists "components/#{name}.jsx", "app/views/#{namespace_name}/components/#{name}.jsx"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def copy_ui_template(name)
|
|
216
|
+
copy_file "components/ui/#{name}.jsx", "app/views/#{namespace_name}/components/ui/#{name}.jsx"
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def copy_ui_template_unless_exists(name)
|
|
220
|
+
destination = "app/views/#{namespace_name}/components/ui/#{name}.jsx"
|
|
221
|
+
existed = File.exist?(File.join(destination_root, destination))
|
|
222
|
+
copy_file_unless_exists "components/ui/#{name}.jsx", destination
|
|
223
|
+
!existed
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def eject_generated_form_counterpart(name)
|
|
227
|
+
counterpart = { "edit" => "new", "new" => "edit" }[name]
|
|
228
|
+
return unless counterpart
|
|
229
|
+
|
|
230
|
+
destination = "app/views/#{namespace_name}/application/#{counterpart}.jsx"
|
|
231
|
+
return unless generated_file?(destination, generated_page_stub(counterpart))
|
|
232
|
+
|
|
233
|
+
copy_file "pages/#{counterpart}.jsx", destination, force: true
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def field_shared_dependencies(field_type)
|
|
237
|
+
field_template_paths(field_type).flat_map do |path|
|
|
238
|
+
relative_imports(File.read(path)).filter_map do |specifier|
|
|
239
|
+
next unless specifier.start_with?("../shared/")
|
|
240
|
+
|
|
241
|
+
dependency = File.basename(specifier, ".*")
|
|
242
|
+
next unless template_exists?("fields/shared/#{dependency}.jsx")
|
|
243
|
+
|
|
244
|
+
dependency
|
|
209
245
|
end
|
|
210
|
-
end
|
|
246
|
+
end.uniq
|
|
247
|
+
end
|
|
211
248
|
|
|
212
|
-
|
|
249
|
+
def component_dependencies(name)
|
|
250
|
+
template_dependencies("components/#{name}.jsx", "components")
|
|
213
251
|
end
|
|
214
252
|
|
|
215
|
-
def
|
|
216
|
-
|
|
253
|
+
def page_dependencies(name)
|
|
254
|
+
template_dependencies("pages/#{name}.jsx", "pages")
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def ui_dependencies(name)
|
|
258
|
+
template_dependencies("components/ui/#{name}.jsx", "components/ui")
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def template_dependencies(template, template_root, seen = [])
|
|
262
|
+
template_path = File.join(self.class.source_root, template)
|
|
263
|
+
return [] unless File.exist?(template_path)
|
|
264
|
+
|
|
265
|
+
relative_imports(File.read(template_path)).flat_map do |specifier|
|
|
266
|
+
next unless specifier.start_with?("./")
|
|
267
|
+
|
|
268
|
+
dependency = File.basename(specifier.delete_prefix("./"), ".*")
|
|
269
|
+
dependency_template = "#{template_root}/#{dependency}.jsx"
|
|
270
|
+
next unless template_exists?(dependency_template)
|
|
271
|
+
next if seen.include?(dependency)
|
|
272
|
+
|
|
273
|
+
[dependency, *template_dependencies(dependency_template, template_root, seen + [dependency])]
|
|
274
|
+
end.compact.uniq
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def field_template_paths(field_type)
|
|
278
|
+
Dir[File.join(self.class.source_root, "fields", field_type, "*.jsx")]
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def relative_imports(source)
|
|
282
|
+
source.scan(/from\s+["']([^"']+)["']/).flatten
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def template_exists?(template)
|
|
286
|
+
File.exist?(File.join(self.class.source_root, template))
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def ui_component_exports(name)
|
|
290
|
+
ui_barrel_template = File.read(File.join(self.class.source_root, "components/ui/index.js"))
|
|
291
|
+
match = ui_barrel_template.match(/^export\s*\{(?<exports>[^}]*)\}\s*from\s*["']\.\/#{Regexp.escape(name)}["'];/m)
|
|
292
|
+
raise Thor::Error, "Could not find UI exports for '#{name}'" unless match
|
|
293
|
+
|
|
294
|
+
match[:exports].split(",").map(&:strip).reject(&:empty?).join(", ")
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def ensure_barrel(barrel_path, package_export)
|
|
217
298
|
barrel_file = File.join(destination_root, barrel_path)
|
|
218
299
|
|
|
219
|
-
|
|
300
|
+
unless File.exist?(barrel_file)
|
|
301
|
+
create_file barrel_path, "#{package_export}\n"
|
|
302
|
+
return
|
|
303
|
+
end
|
|
220
304
|
|
|
221
305
|
content = File.read(barrel_file)
|
|
222
|
-
if content.include?(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
new_content += "export * from \"./#{name}\";\n"
|
|
226
|
-
create_file barrel_path, new_content, force: true
|
|
227
|
-
end
|
|
306
|
+
return if content.include?(package_export)
|
|
307
|
+
|
|
308
|
+
prepend_to_file barrel_path, "#{package_export}\n"
|
|
228
309
|
end
|
|
229
310
|
|
|
230
|
-
def
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
311
|
+
def ensure_page_barrels
|
|
312
|
+
ensure_fields_barrel
|
|
313
|
+
ensure_components_barrel
|
|
314
|
+
ensure_ui_barrel
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def ensure_fields_barrel
|
|
318
|
+
ensure_barrel(fields_barrel_path, 'export * from "terrazzo/fields";')
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def ensure_components_barrel
|
|
322
|
+
ensure_barrel(components_barrel_path, 'export * from "terrazzo/components";')
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def ensure_ui_barrel
|
|
326
|
+
ensure_barrel(ui_barrel_path, 'export * from "terrazzo/ui";')
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def fields_barrel_path
|
|
330
|
+
"app/views/#{namespace_name}/fields/index.js"
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def components_barrel_path
|
|
334
|
+
"app/views/#{namespace_name}/components/index.js"
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def ui_barrel_path
|
|
338
|
+
"app/views/#{namespace_name}/components/ui/index.js"
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def append_to_barrel(barrel_path, content, marker)
|
|
342
|
+
barrel_file = File.join(destination_root, barrel_path)
|
|
343
|
+
return if File.exist?(barrel_file) && File.read(barrel_file).include?(marker)
|
|
344
|
+
|
|
345
|
+
append_to_file barrel_path, "\n#{content}\n"
|
|
236
346
|
end
|
|
237
347
|
end
|
|
238
348
|
end
|
|
@@ -10,7 +10,7 @@ module Terrazzo
|
|
|
10
10
|
|
|
11
11
|
def create_field_class
|
|
12
12
|
template "field.rb.erb",
|
|
13
|
-
"app/fields/#{file_name}
|
|
13
|
+
"app/fields/terrazzo/field/#{file_name}.rb"
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def create_jsx_components
|
|
@@ -21,18 +21,32 @@ module Terrazzo
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def register_in_barrel
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
ensure_fields_barrel
|
|
25
|
+
ensure_ui_barrel
|
|
26
26
|
|
|
27
|
+
barrel_path = "app/views/#{namespace_name}/fields/index.js"
|
|
28
|
+
barrel_file = File.join(destination_root, barrel_path)
|
|
29
|
+
return if File.read(barrel_file).include?("./#{file_name}/IndexField")
|
|
30
|
+
|
|
31
|
+
register_name = "register#{class_name}FieldType"
|
|
27
32
|
registration = <<~JS
|
|
28
33
|
|
|
29
34
|
// #{class_name} - custom field
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
import { registerFieldType as #{register_name} } from "terrazzo/fields";
|
|
36
|
+
import { IndexField as #{class_name}IndexField } from "./#{file_name}/IndexField";
|
|
37
|
+
import { ShowField as #{class_name}ShowField } from "./#{file_name}/ShowField";
|
|
38
|
+
import { FormField as #{class_name}FormField } from "./#{file_name}/FormField";
|
|
39
|
+
|
|
40
|
+
#{register_name}("#{file_name}", {
|
|
41
|
+
index: #{class_name}IndexField,
|
|
42
|
+
show: #{class_name}ShowField,
|
|
43
|
+
form: #{class_name}FormField,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export { #{class_name}IndexField, #{class_name}ShowField, #{class_name}FormField };
|
|
33
47
|
JS
|
|
34
48
|
|
|
35
|
-
append_to_file
|
|
49
|
+
append_to_file barrel_path, registration
|
|
36
50
|
|
|
37
51
|
say "\nCustom field '#{file_name}' registered in fields/index.js.", :green
|
|
38
52
|
say "Use it in your dashboard:"
|
|
@@ -44,6 +58,36 @@ module Terrazzo
|
|
|
44
58
|
def namespace_name
|
|
45
59
|
options[:namespace]
|
|
46
60
|
end
|
|
61
|
+
|
|
62
|
+
def ensure_fields_barrel
|
|
63
|
+
barrel_path = "app/views/#{namespace_name}/fields/index.js"
|
|
64
|
+
barrel_file = File.join(destination_root, barrel_path)
|
|
65
|
+
|
|
66
|
+
unless File.exist?(barrel_file)
|
|
67
|
+
create_file barrel_path, %(export * from "terrazzo/fields";\n)
|
|
68
|
+
return
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
content = File.read(barrel_file)
|
|
72
|
+
return if content.include?('export * from "terrazzo/fields";')
|
|
73
|
+
|
|
74
|
+
prepend_to_file barrel_path, %(export * from "terrazzo/fields";\n)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def ensure_ui_barrel
|
|
78
|
+
barrel_path = "app/views/#{namespace_name}/components/ui/index.js"
|
|
79
|
+
barrel_file = File.join(destination_root, barrel_path)
|
|
80
|
+
|
|
81
|
+
unless File.exist?(barrel_file)
|
|
82
|
+
create_file barrel_path, %(export * from "terrazzo/ui";\n)
|
|
83
|
+
return
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
content = File.read(barrel_file)
|
|
87
|
+
return if content.include?('export * from "terrazzo/ui";')
|
|
88
|
+
|
|
89
|
+
prepend_to_file barrel_path, %(export * from "terrazzo/ui";\n)
|
|
90
|
+
end
|
|
47
91
|
end
|
|
48
92
|
end
|
|
49
93
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Input, Label } from "
|
|
2
|
+
import { Input, Label } from "../../components/ui";
|
|
3
3
|
|
|
4
4
|
export function FormField({ attribute, label, value, input, required }) {
|
|
5
5
|
return (
|
|
@@ -9,9 +9,8 @@ export function FormField({ attribute, label, value, input, required }) {
|
|
|
9
9
|
</Label>
|
|
10
10
|
<Input
|
|
11
11
|
type="text"
|
|
12
|
-
id={input.id}
|
|
13
|
-
name={input.name}
|
|
14
12
|
defaultValue={value ?? ""}
|
|
13
|
+
{...input}
|
|
15
14
|
/>
|
|
16
15
|
</div>
|
|
17
16
|
);
|