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
|
@@ -2,7 +2,8 @@ json.pageTitle @page.page_title
|
|
|
2
2
|
|
|
3
3
|
show_field_json = ->(json, field) do
|
|
4
4
|
json.attribute field.attribute.to_s
|
|
5
|
-
json.label field.attribute
|
|
5
|
+
json.label dashboard.attribute_label(field.attribute, :show)
|
|
6
|
+
json.hint dashboard.attribute_hint(field.attribute, :show)
|
|
6
7
|
json.fieldType field.field_type
|
|
7
8
|
json.value field.serialize_value(:show)
|
|
8
9
|
json.options field.serializable_options
|
|
@@ -12,14 +13,14 @@ show_field_json = ->(json, field) do
|
|
|
12
13
|
render_actions = field.options.fetch(:render_actions, true)
|
|
13
14
|
|
|
14
15
|
json.hasManyRowExtras(field.page_records.each_with_object({}) do |record, hash|
|
|
15
|
-
extras = { showPath: (
|
|
16
|
+
extras = { showPath: collection_action_path(record, :show) }
|
|
16
17
|
extras[:collectionItemActions] = collection_item_actions(record) if render_actions
|
|
17
18
|
hash[record.id.to_s] = extras
|
|
18
19
|
end)
|
|
19
20
|
|
|
20
21
|
json.paginationPaths has_many_pagination_paths(field, @resource)
|
|
21
22
|
else
|
|
22
|
-
json.showPath
|
|
23
|
+
json.showPath collection_action_path(field.data, :show)
|
|
23
24
|
end
|
|
24
25
|
end
|
|
25
26
|
end
|
|
@@ -39,8 +40,9 @@ json.attributeGroups do
|
|
|
39
40
|
end
|
|
40
41
|
end
|
|
41
42
|
|
|
42
|
-
json.
|
|
43
|
-
json.
|
|
43
|
+
json.layoutActions Array(dashboard.layout_actions(:show, self, resource: @resource))
|
|
44
|
+
json.editPath route_exists?(:edit) && authorized_action?(@resource, :edit) ? terrazzo_resource_member_path(@resource, action: :edit) : nil
|
|
45
|
+
json.deletePath route_exists?(:destroy) && authorized_action?(@resource, :destroy) ? terrazzo_resource_member_path(@resource, action: :destroy) : nil
|
|
44
46
|
json.indexPath begin
|
|
45
47
|
url_for(controller: controller_path, action: :index, only_path: true)
|
|
46
48
|
rescue ActionController::UrlGenerationError
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require "set"
|
|
2
3
|
require "terrazzo/generator_helpers"
|
|
3
4
|
|
|
4
5
|
module Terrazzo
|
|
@@ -11,7 +12,7 @@ module Terrazzo
|
|
|
11
12
|
class_option :namespace, type: :string, default: "admin",
|
|
12
13
|
desc: "Admin namespace"
|
|
13
14
|
class_option :bundler, type: :string, default: "vite",
|
|
14
|
-
desc: "JavaScript bundler (vite or
|
|
15
|
+
desc: "JavaScript bundler (vite or esbuild)"
|
|
15
16
|
|
|
16
17
|
def create_dashboard
|
|
17
18
|
template "dashboard.rb.erb",
|
|
@@ -24,34 +25,22 @@ module Terrazzo
|
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def update_page_to_page_mapping
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
namespace_name = options[:namespace]
|
|
33
|
-
action_to_component = {
|
|
34
|
-
"index" => "AdminIndex",
|
|
35
|
-
"show" => "AdminShow",
|
|
36
|
-
"new" => "AdminNew",
|
|
37
|
-
"edit" => "AdminEdit"
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
action_to_component.each do |action, component|
|
|
41
|
-
key = "'#{namespace_name}/application/#{action}'"
|
|
42
|
-
mapping_path_content = File.read(mapping_path)
|
|
43
|
-
next if mapping_path_content.include?(key)
|
|
44
|
-
|
|
45
|
-
inject_into_file mapping_path, before: "}" do
|
|
46
|
-
" #{key}: #{component},\n"
|
|
47
|
-
end
|
|
48
|
-
end
|
|
28
|
+
# The generated page mapping falls back from resource identifiers
|
|
29
|
+
# (admin/posts/index) to shared application pages (admin/application/index).
|
|
30
|
+
# Resource-specific page generators register their own mappings in
|
|
31
|
+
# generated_page_mapping.js when needed.
|
|
49
32
|
end
|
|
50
33
|
|
|
51
34
|
private
|
|
52
35
|
|
|
53
36
|
def model_class
|
|
54
37
|
class_name.constantize
|
|
38
|
+
rescue NameError
|
|
39
|
+
raise Thor::Error, <<~MESSAGE
|
|
40
|
+
Terrazzo could not find model '#{class_name}'.
|
|
41
|
+
|
|
42
|
+
Generate the model first, then run `bin/rails generate terrazzo:dashboard #{class_name}` again.
|
|
43
|
+
MESSAGE
|
|
55
44
|
end
|
|
56
45
|
|
|
57
46
|
def attribute_types
|
|
@@ -61,7 +50,7 @@ module Terrazzo
|
|
|
61
50
|
types = {}
|
|
62
51
|
|
|
63
52
|
# ID first
|
|
64
|
-
types[:id] = "Field::
|
|
53
|
+
types[:id] = "Field::String"
|
|
65
54
|
|
|
66
55
|
# Columns
|
|
67
56
|
columns.each do |col|
|
|
@@ -77,11 +66,18 @@ module Terrazzo
|
|
|
77
66
|
else
|
|
78
67
|
Set.new
|
|
79
68
|
end
|
|
69
|
+
rich_text_association_names = rich_text_internal_association_names
|
|
70
|
+
|
|
71
|
+
rich_text_attribute_names.each do |name|
|
|
72
|
+
types[name] = "Field::RichText"
|
|
73
|
+
end
|
|
80
74
|
|
|
81
75
|
# Associations
|
|
82
76
|
associations.each do |assoc|
|
|
83
77
|
# Skip Active Storage internal associations (e.g., document_attachment, document_blob)
|
|
84
78
|
next if active_storage_internal?(assoc.name, attachment_names)
|
|
79
|
+
# Skip Action Text internals (e.g., rich_text_description)
|
|
80
|
+
next if rich_text_association_names.include?(assoc.name)
|
|
85
81
|
|
|
86
82
|
case assoc.macro
|
|
87
83
|
when :belongs_to
|
|
@@ -116,6 +112,22 @@ module Terrazzo
|
|
|
116
112
|
attribute_types.keys.reject { |a| %i[id created_at updated_at].include?(a) }
|
|
117
113
|
end
|
|
118
114
|
|
|
115
|
+
def controller_modules
|
|
116
|
+
[options[:namespace].camelize, *class_path.map(&:camelize)]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def controller_class_name
|
|
120
|
+
"#{file_name.pluralize.camelize}Controller"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def dashboard_modules
|
|
124
|
+
class_path.map(&:camelize)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def dashboard_class_name
|
|
128
|
+
"#{file_name.camelize}Dashboard"
|
|
129
|
+
end
|
|
130
|
+
|
|
119
131
|
def association_foreign_key?(column_name, associations)
|
|
120
132
|
associations.any? do |assoc|
|
|
121
133
|
assoc.macro == :belongs_to &&
|
|
@@ -129,6 +141,18 @@ module Terrazzo
|
|
|
129
141
|
att_s = att.to_s
|
|
130
142
|
name == "#{att_s}_attachment" || name == "#{att_s}_blob" ||
|
|
131
143
|
name == "#{att_s}_attachments" || name == "#{att_s}_blobs"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def rich_text_internal_association_names
|
|
148
|
+
return Set.new unless model_class.respond_to?(:rich_text_association_names)
|
|
149
|
+
|
|
150
|
+
model_class.rich_text_association_names.map(&:to_sym).to_set
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def rich_text_attribute_names
|
|
154
|
+
rich_text_internal_association_names.map do |name|
|
|
155
|
+
name.to_s.sub(/\Arich_text_/, "").to_sym
|
|
132
156
|
end
|
|
133
157
|
end
|
|
134
158
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
<% controller_modules.each_with_index do |module_name, index| -%>
|
|
2
|
+
<%= " " * index %>module <%= module_name %>
|
|
3
|
+
<% end -%>
|
|
4
|
+
<%= " " * controller_modules.size %>class <%= controller_class_name %> < ApplicationController
|
|
5
|
+
<%= " " * controller_modules.size %>end
|
|
6
|
+
<% controller_modules.reverse.each_with_index do |_module_name, index| -%>
|
|
7
|
+
<%= " " * (controller_modules.size - index - 1) %>end
|
|
8
|
+
<% end -%>
|
|
@@ -1,43 +1,51 @@
|
|
|
1
1
|
require "terrazzo/base_dashboard"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
<% dashboard_modules.each_with_index do |module_name, index| -%>
|
|
4
|
+
<%= " " * index %>module <%= module_name %>
|
|
5
|
+
<% end -%>
|
|
6
|
+
<% class_indent = " " * dashboard_modules.size -%>
|
|
7
|
+
<% body_indent = " " * (dashboard_modules.size + 1) -%>
|
|
8
|
+
<%= class_indent %>class <%= dashboard_class_name %> < Terrazzo::BaseDashboard
|
|
9
|
+
<%= body_indent %>ATTRIBUTE_TYPES = {
|
|
5
10
|
<% attribute_types.each do |attr, type| -%>
|
|
6
11
|
<% if has_enum?(attr.to_s) -%>
|
|
7
|
-
|
|
12
|
+
<%= body_indent %> <%= attr %>: <%= type %>.with_options(collection: <%= enum_collection(attr.to_s).inspect %>),
|
|
8
13
|
<% else -%>
|
|
9
|
-
|
|
14
|
+
<%= body_indent %> <%= attr %>: <%= type %>,
|
|
10
15
|
<% end -%>
|
|
11
16
|
<% end -%>
|
|
12
|
-
|
|
17
|
+
<%= body_indent %>}.freeze
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
<%= body_indent %>COLLECTION_ATTRIBUTES = %i[
|
|
15
20
|
<% collection_attributes.each do |attr| -%>
|
|
16
|
-
|
|
21
|
+
<%= body_indent %> <%= attr %>
|
|
17
22
|
<% end -%>
|
|
18
|
-
|
|
23
|
+
<%= body_indent %>].freeze
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
<%= body_indent %>SHOW_PAGE_ATTRIBUTES = %i[
|
|
21
26
|
<% show_page_attributes.each do |attr| -%>
|
|
22
|
-
|
|
27
|
+
<%= body_indent %> <%= attr %>
|
|
23
28
|
<% end -%>
|
|
24
|
-
|
|
29
|
+
<%= body_indent %>].freeze
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
<%= body_indent %>FORM_ATTRIBUTES = %i[
|
|
27
32
|
<% form_attributes.each do |attr| -%>
|
|
28
|
-
|
|
33
|
+
<%= body_indent %> <%= attr %>
|
|
29
34
|
<% end -%>
|
|
30
|
-
|
|
35
|
+
<%= body_indent %>].freeze
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
<%= body_indent %># COLLECTION_FILTERS = {
|
|
38
|
+
<%= body_indent %># active: ->(resources) { resources.where(active: true) },
|
|
39
|
+
<%= body_indent %># recent: ->(resources) { resources.where("created_at > ?", 30.days.ago) },
|
|
40
|
+
<%= body_indent %># }.freeze
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
end
|
|
42
|
+
<%= body_indent %># Override this method to customize how <%= file_name.pluralize.humanize.downcase %> are displayed
|
|
43
|
+
<%= body_indent %># across all pages of the admin dashboard.
|
|
44
|
+
<%= body_indent %>#
|
|
45
|
+
<%= body_indent %># def display_resource(resource)
|
|
46
|
+
<%= body_indent %># "<%= class_name %> ##{resource.id}"
|
|
47
|
+
<%= body_indent %># end
|
|
48
|
+
<%= class_indent %>end
|
|
49
|
+
<% dashboard_modules.reverse.each_with_index do |_module_name, index| -%>
|
|
50
|
+
<%= " " * (dashboard_modules.size - index - 1) %>end
|
|
51
|
+
<% end -%>
|