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
|
@@ -4,6 +4,9 @@ import { Application } from "@thoughtbot/superglue"
|
|
|
4
4
|
import { buildVisitAndRemote } from "./application_visit"
|
|
5
5
|
import { pageToPageMapping } from "./page_to_page_mapping"
|
|
6
6
|
import { store } from "./store"
|
|
7
|
+
import "../../views/<%= namespace_name %>/fields"
|
|
8
|
+
import "../../views/<%= namespace_name %>/components"
|
|
9
|
+
import "../../views/<%= namespace_name %>/components/ui"
|
|
7
10
|
|
|
8
11
|
if (typeof window !== "undefined") {
|
|
9
12
|
document.addEventListener("DOMContentLoaded", function () {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "default",
|
|
4
|
+
"rsc": false,
|
|
5
|
+
"tsx": false,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "",
|
|
8
|
+
"css": "app/assets/stylesheets/<%= namespace_name %>.css",
|
|
9
|
+
"baseColor": "zinc",
|
|
10
|
+
"cssVariables": true
|
|
11
|
+
},
|
|
12
|
+
"aliases": {
|
|
13
|
+
"components": "app/views/<%= namespace_name %>/components",
|
|
14
|
+
"ui": "app/views/<%= namespace_name %>/components/ui",
|
|
15
|
+
"utils": "terrazzo"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Resource-specific page mappings generated by Terrazzo.
|
|
2
|
+
// Add manual custom pages to custom_page_mapping.js instead.
|
|
3
|
+
|
|
4
|
+
// Terrazzo generated page imports start
|
|
5
|
+
// Terrazzo generated page imports end
|
|
6
|
+
|
|
7
|
+
export const generatedPageMapping = {
|
|
8
|
+
// Terrazzo generated page mappings start
|
|
9
|
+
// Terrazzo generated page mappings end
|
|
10
|
+
}
|
|
@@ -2,14 +2,22 @@ import AdminIndex from "../../views/<%= namespace_name %>/application/index";
|
|
|
2
2
|
import AdminShow from "../../views/<%= namespace_name %>/application/show";
|
|
3
3
|
import AdminNew from "../../views/<%= namespace_name %>/application/new";
|
|
4
4
|
import AdminEdit from "../../views/<%= namespace_name %>/application/edit";
|
|
5
|
+
import { generatedPageMapping } from "./generated_page_mapping";
|
|
6
|
+
import { customPageMapping } from "./custom_page_mapping";
|
|
5
7
|
|
|
6
|
-
const
|
|
8
|
+
const applicationPages = {
|
|
7
9
|
'<%= namespace_name %>/application/index': AdminIndex,
|
|
8
10
|
'<%= namespace_name %>/application/show': AdminShow,
|
|
9
11
|
'<%= namespace_name %>/application/new': AdminNew,
|
|
10
12
|
'<%= namespace_name %>/application/edit': AdminEdit,
|
|
11
13
|
}
|
|
12
14
|
|
|
15
|
+
const pages = {
|
|
16
|
+
...applicationPages,
|
|
17
|
+
...generatedPageMapping,
|
|
18
|
+
...customPageMapping,
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
// Resolves resource-specific page identifiers (e.g. "admin/orders/index")
|
|
14
22
|
// with fallback to the shared application component (e.g. "admin/application/index").
|
|
15
23
|
export const pageToPageMapping = new Proxy(pages, {
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<%%= csp_meta_tag %>
|
|
8
8
|
<%%= yield :head %>
|
|
9
9
|
<% if vite? -%>
|
|
10
|
-
<%%=
|
|
11
|
-
<%%= vite_javascript_tag "<%=
|
|
10
|
+
<%%= vite_client_tag %>
|
|
11
|
+
<%%= vite_javascript_tag "<%= vite_entry_point_tag_name %>" %>
|
|
12
12
|
<% else -%>
|
|
13
13
|
<%%= javascript_include_tag "<%= namespace_name %>", type: "module" %>
|
|
14
14
|
<% end -%>
|
|
@@ -11,36 +11,25 @@ module Terrazzo
|
|
|
11
11
|
def insert_routes
|
|
12
12
|
namespace_name = options[:namespace]
|
|
13
13
|
models = application_models
|
|
14
|
+
raise_no_models_error if models.empty?
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
namespaced = {}
|
|
17
|
-
top_level = []
|
|
16
|
+
route_tree = empty_route_tree
|
|
18
17
|
|
|
19
18
|
models.each do |model|
|
|
20
19
|
parts = model.name.split("::")
|
|
21
20
|
if parts.size > 1
|
|
22
|
-
|
|
21
|
+
namespaces = parts[0..-2].map(&:underscore)
|
|
23
22
|
resource = parts.last.underscore.pluralize
|
|
24
|
-
|
|
25
|
-
namespaced[ns] << resource
|
|
23
|
+
add_route_resource(route_tree, namespaces, resource)
|
|
26
24
|
else
|
|
27
|
-
|
|
25
|
+
add_route_resource(route_tree, [], model.model_name.plural)
|
|
28
26
|
end
|
|
29
27
|
end
|
|
30
28
|
|
|
31
|
-
lines =
|
|
32
|
-
|
|
29
|
+
lines = route_lines(route_tree, indent_level: 1)
|
|
30
|
+
first_resource = first_route_target(route_tree)
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
lines << ""
|
|
36
|
-
lines << " namespace :#{ns} do"
|
|
37
|
-
resources.sort.each { |r| lines << " resources :#{r}" }
|
|
38
|
-
lines << " end"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
first_resource = top_level.sort.first || namespaced.values.flatten.first || "dashboard"
|
|
42
|
-
|
|
43
|
-
route_block = <<~RUBY.indent(2)
|
|
32
|
+
route_block = <<~RUBY
|
|
44
33
|
namespace :#{namespace_name} do
|
|
45
34
|
#{lines.join("\n")}
|
|
46
35
|
|
|
@@ -55,7 +44,7 @@ module Terrazzo
|
|
|
55
44
|
say ""
|
|
56
45
|
lines.each { |line| say line }
|
|
57
46
|
say ""
|
|
58
|
-
say "
|
|
47
|
+
say " root to: \"#{first_resource}#index\"", :green if first_resource
|
|
59
48
|
say ""
|
|
60
49
|
return
|
|
61
50
|
end
|
|
@@ -78,6 +67,52 @@ module Terrazzo
|
|
|
78
67
|
end.select { |klass| klass < ApplicationRecord && !klass.abstract_class? }
|
|
79
68
|
.sort_by { |klass| klass.name }
|
|
80
69
|
end
|
|
70
|
+
|
|
71
|
+
def empty_route_tree
|
|
72
|
+
{ resources: [], namespaces: {} }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def add_route_resource(tree, namespaces, resource)
|
|
76
|
+
if namespaces.empty?
|
|
77
|
+
tree[:resources] << resource
|
|
78
|
+
return
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
namespace = namespaces.first
|
|
82
|
+
child_tree = tree[:namespaces][namespace] ||= empty_route_tree
|
|
83
|
+
add_route_resource(child_tree, namespaces.drop(1), resource)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def route_lines(tree, indent_level:)
|
|
87
|
+
indent = " " * indent_level
|
|
88
|
+
lines = tree[:resources].uniq.sort.map { |resource| "#{indent}resources :#{resource}" }
|
|
89
|
+
|
|
90
|
+
tree[:namespaces].sort.each do |namespace, child_tree|
|
|
91
|
+
lines << "" if lines.any?
|
|
92
|
+
lines << "#{indent}namespace :#{namespace} do"
|
|
93
|
+
lines.concat(route_lines(child_tree, indent_level: indent_level + 1))
|
|
94
|
+
lines << "#{indent}end"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
lines
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def first_route_target(tree)
|
|
101
|
+
resource = tree[:resources].uniq.sort.first
|
|
102
|
+
return resource if resource
|
|
103
|
+
|
|
104
|
+
namespace, child_tree = tree[:namespaces].sort.first
|
|
105
|
+
child_target = first_route_target(child_tree) if child_tree
|
|
106
|
+
return "#{namespace}/#{child_target}" if namespace && child_target
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def raise_no_models_error
|
|
110
|
+
raise Thor::Error, <<~MESSAGE
|
|
111
|
+
Terrazzo could not find any ApplicationRecord models to route.
|
|
112
|
+
|
|
113
|
+
Add at least one model first, then run `bin/rails generate terrazzo:routes` again.
|
|
114
|
+
MESSAGE
|
|
115
|
+
end
|
|
81
116
|
end
|
|
82
117
|
end
|
|
83
118
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require_relative "generated_defaults_helper"
|
|
2
3
|
require_relative "page_mapping_helper"
|
|
3
4
|
|
|
4
5
|
module Terrazzo
|
|
5
6
|
module Generators
|
|
6
7
|
module Views
|
|
7
8
|
class EditGenerator < Rails::Generators::Base
|
|
9
|
+
include GeneratedDefaultsHelper
|
|
8
10
|
include PageMappingHelper
|
|
9
11
|
|
|
10
12
|
source_root File.expand_path("templates", __dir__)
|
|
@@ -14,17 +16,22 @@ module Terrazzo
|
|
|
14
16
|
|
|
15
17
|
class_option :namespace, type: :string, default: "admin",
|
|
16
18
|
desc: "Admin namespace"
|
|
19
|
+
class_option :with_counterpart, type: :boolean, default: nil,
|
|
20
|
+
desc: "Also eject the new view that shares this form partial"
|
|
17
21
|
|
|
18
22
|
def copy_edit_template
|
|
23
|
+
ensure_page_barrels
|
|
24
|
+
|
|
19
25
|
if resource.present?
|
|
20
26
|
eject_json_props
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
copy_resource_page_file "pages/edit.jsx", "app/views/#{namespace_name}/#{resource_path}/edit.jsx"
|
|
28
|
+
copy_resource_page_file_unless_exists "pages/_form.jsx", "app/views/#{namespace_name}/#{resource_path}/_form.jsx"
|
|
23
29
|
register_page_mapping("edit")
|
|
24
30
|
eject_new_view if should_eject_new?
|
|
25
31
|
else
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
copy_file_over_generated "pages/edit.jsx", "app/views/#{namespace_name}/application/edit.jsx",
|
|
33
|
+
generated_content: generated_page_stub("edit")
|
|
34
|
+
copy_file_unless_exists "pages/_form.jsx", "app/views/#{namespace_name}/application/_form.jsx"
|
|
28
35
|
eject_new_view if should_eject_new?
|
|
29
36
|
end
|
|
30
37
|
end
|
|
@@ -45,7 +52,9 @@ module Terrazzo
|
|
|
45
52
|
else
|
|
46
53
|
"app/views/#{namespace_name}/application/new.jsx"
|
|
47
54
|
end
|
|
55
|
+
return true if generated_file?(new_path, generated_page_stub("new"))
|
|
48
56
|
return false if File.exist?(new_path)
|
|
57
|
+
return options[:with_counterpart] unless options[:with_counterpart].nil?
|
|
49
58
|
|
|
50
59
|
yes?("Also eject the new view to share the custom form partial? (y/n)")
|
|
51
60
|
end
|
|
@@ -53,10 +62,11 @@ module Terrazzo
|
|
|
53
62
|
def eject_new_view
|
|
54
63
|
if resource.present?
|
|
55
64
|
eject_new_json_props
|
|
56
|
-
|
|
65
|
+
copy_resource_page_file "pages/new.jsx", "app/views/#{namespace_name}/#{resource_path}/new.jsx"
|
|
57
66
|
register_page_mapping("new")
|
|
58
67
|
else
|
|
59
|
-
|
|
68
|
+
copy_file_over_generated "pages/new.jsx", "app/views/#{namespace_name}/application/new.jsx",
|
|
69
|
+
generated_content: generated_page_stub("new")
|
|
60
70
|
end
|
|
61
71
|
end
|
|
62
72
|
|
|
@@ -68,10 +78,6 @@ module Terrazzo
|
|
|
68
78
|
RUBY
|
|
69
79
|
end
|
|
70
80
|
|
|
71
|
-
def resource_path
|
|
72
|
-
resource.underscore.pluralize
|
|
73
|
-
end
|
|
74
|
-
|
|
75
81
|
def namespace_name
|
|
76
82
|
options[:namespace]
|
|
77
83
|
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "generators/terrazzo/eject/eject_generator"
|
|
2
|
+
|
|
3
|
+
module Terrazzo
|
|
4
|
+
module Generators
|
|
5
|
+
module Views
|
|
6
|
+
module EjectCompatibility
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def run_eject(target)
|
|
10
|
+
Terrazzo::Generators::EjectGenerator.start(
|
|
11
|
+
[target, "--namespace=#{namespace_name}"],
|
|
12
|
+
destination_root: destination_root,
|
|
13
|
+
behavior: behavior
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require "generators/terrazzo/views/eject_compatibility"
|
|
2
3
|
|
|
3
4
|
module Terrazzo
|
|
4
5
|
module Generators
|
|
5
6
|
module Views
|
|
6
7
|
class FieldGenerator < Rails::Generators::Base
|
|
8
|
+
include EjectCompatibility
|
|
9
|
+
|
|
7
10
|
source_root File.expand_path("templates", __dir__)
|
|
8
11
|
|
|
9
12
|
class_option :namespace, type: :string, default: "admin",
|
|
@@ -13,16 +16,25 @@ module Terrazzo
|
|
|
13
16
|
desc: "Specific field type to copy (e.g., string, number) or 'all'"
|
|
14
17
|
|
|
15
18
|
def copy_field_templates
|
|
16
|
-
|
|
17
|
-
directory "fields", "app/views/#{namespace_name}/fields"
|
|
18
|
-
else
|
|
19
|
-
directory "fields/shared", "app/views/#{namespace_name}/fields/shared"
|
|
20
|
-
directory "fields/#{field_type}", "app/views/#{namespace_name}/fields/#{field_type}"
|
|
21
|
-
end
|
|
19
|
+
field_types_to_eject.each { |name| run_eject("fields/#{name}") }
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
private
|
|
25
23
|
|
|
24
|
+
def field_types_to_eject
|
|
25
|
+
return built_in_field_types if field_type == "all"
|
|
26
|
+
|
|
27
|
+
[field_type == "money" ? "number" : field_type]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def built_in_field_types
|
|
31
|
+
Dir[File.join(self.class.source_root, "fields/*")]
|
|
32
|
+
.select { |path| File.directory?(path) }
|
|
33
|
+
.map { |path| File.basename(path) }
|
|
34
|
+
.reject { |name| name == "shared" }
|
|
35
|
+
.sort
|
|
36
|
+
end
|
|
37
|
+
|
|
26
38
|
def namespace_name
|
|
27
39
|
options[:namespace]
|
|
28
40
|
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
module Terrazzo
|
|
2
|
+
module Generators
|
|
3
|
+
module Views
|
|
4
|
+
module GeneratedDefaultsHelper
|
|
5
|
+
PAGE_COMPONENTS = {
|
|
6
|
+
"index" => "AdminIndex",
|
|
7
|
+
"show" => "AdminShow",
|
|
8
|
+
"new" => "AdminNew",
|
|
9
|
+
"edit" => "AdminEdit",
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def copy_file_over_generated(source, destination, generated_content:)
|
|
15
|
+
options = generated_file?(destination, generated_content) ? { force: true } : {}
|
|
16
|
+
|
|
17
|
+
copy_file source, destination, **options
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def copy_file_unless_exists(source, destination)
|
|
21
|
+
if File.exist?(File.join(destination_root, destination))
|
|
22
|
+
say_status :skip, destination, :yellow
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
copy_file source, destination
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def copy_resource_page_file(source, destination)
|
|
30
|
+
before = read_destination(destination)
|
|
31
|
+
generated_before = before == read_template(source)
|
|
32
|
+
|
|
33
|
+
copy_file source, destination
|
|
34
|
+
after = read_destination(destination)
|
|
35
|
+
rewrite_resource_page_imports(destination) if after && (before.nil? || after != before || generated_before)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def copy_resource_page_file_unless_exists(source, destination)
|
|
39
|
+
if File.exist?(File.join(destination_root, destination))
|
|
40
|
+
rewrite_resource_page_imports(destination) if read_destination(destination) == read_template(source)
|
|
41
|
+
say_status :skip, destination, :yellow
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
copy_file source, destination
|
|
46
|
+
rewrite_resource_page_imports(destination)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def generated_file?(destination, generated_content)
|
|
50
|
+
path = File.join(destination_root, destination)
|
|
51
|
+
File.exist?(path) && File.read(path) == generated_content
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def generated_page_stub(name)
|
|
55
|
+
component = PAGE_COMPONENTS.fetch(name)
|
|
56
|
+
|
|
57
|
+
%(export { #{component} as default } from "terrazzo/pages";\n)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def generated_navigation_partial
|
|
61
|
+
<<~RUBY
|
|
62
|
+
resources = Terrazzo::Namespace.new(namespace).navigation_resources
|
|
63
|
+
navigation_groups = resources.group_by(&:navigation_group).map do |label, items|
|
|
64
|
+
{ label: label, items: items }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
json.array! navigation_groups do |group|
|
|
68
|
+
json.label group[:label]
|
|
69
|
+
json.items do
|
|
70
|
+
json.array! group[:items] do |r|
|
|
71
|
+
json.label r.navigation_label
|
|
72
|
+
json.path url_for(controller: "/\#{r.controller_path}", action: :index, only_path: true)
|
|
73
|
+
json.active r.controller_path == controller_path
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
RUBY
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def rewrite_resource_page_imports(destination)
|
|
81
|
+
path = File.join(destination_root, destination)
|
|
82
|
+
source = File.read(path)
|
|
83
|
+
prefix = page_barrel_import_prefix(destination)
|
|
84
|
+
rewritten = source.gsub(/from "\.\.\/(fields|components(?:\/ui)?)"/) do
|
|
85
|
+
%(from "#{prefix}#{Regexp.last_match(1)}")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
File.write(path, rewritten) if rewritten != source
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def read_destination(destination)
|
|
92
|
+
path = File.join(destination_root, destination)
|
|
93
|
+
File.read(path) if File.exist?(path)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def read_template(source)
|
|
97
|
+
File.read(File.join(self.class.source_root, source))
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def page_barrel_import_prefix(destination)
|
|
101
|
+
relative_path = destination.delete_prefix("app/views/#{namespace_name}/")
|
|
102
|
+
directory = File.dirname(relative_path)
|
|
103
|
+
depth = directory.split("/").reject(&:empty?).length
|
|
104
|
+
|
|
105
|
+
"../" * depth
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require_relative "generated_defaults_helper"
|
|
2
3
|
require_relative "page_mapping_helper"
|
|
3
4
|
|
|
4
5
|
module Terrazzo
|
|
5
6
|
module Generators
|
|
6
7
|
module Views
|
|
7
8
|
class IndexGenerator < Rails::Generators::Base
|
|
9
|
+
include GeneratedDefaultsHelper
|
|
8
10
|
include PageMappingHelper
|
|
9
11
|
|
|
10
12
|
source_root File.expand_path("templates", __dir__)
|
|
@@ -16,14 +18,17 @@ module Terrazzo
|
|
|
16
18
|
desc: "Admin namespace"
|
|
17
19
|
|
|
18
20
|
def copy_index_template
|
|
21
|
+
ensure_page_barrels
|
|
22
|
+
|
|
19
23
|
if resource.present?
|
|
20
24
|
eject_json_props
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
copy_resource_page_file "pages/index.jsx", "app/views/#{namespace_name}/#{resource_path}/index.jsx"
|
|
26
|
+
copy_resource_page_file_unless_exists "pages/_collection.jsx", "app/views/#{namespace_name}/#{resource_path}/_collection.jsx"
|
|
23
27
|
register_page_mapping("index")
|
|
24
28
|
else
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
copy_file_over_generated "pages/index.jsx", "app/views/#{namespace_name}/application/index.jsx",
|
|
30
|
+
generated_content: generated_page_stub("index")
|
|
31
|
+
copy_file_unless_exists "pages/_collection.jsx", "app/views/#{namespace_name}/application/_collection.jsx"
|
|
27
32
|
end
|
|
28
33
|
end
|
|
29
34
|
|
|
@@ -37,10 +42,6 @@ module Terrazzo
|
|
|
37
42
|
RUBY
|
|
38
43
|
end
|
|
39
44
|
|
|
40
|
-
def resource_path
|
|
41
|
-
resource.underscore.pluralize
|
|
42
|
-
end
|
|
43
|
-
|
|
44
45
|
def namespace_name
|
|
45
46
|
options[:namespace]
|
|
46
47
|
end
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require "generators/terrazzo/views/eject_compatibility"
|
|
2
3
|
|
|
3
4
|
module Terrazzo
|
|
4
5
|
module Generators
|
|
5
6
|
module Views
|
|
6
7
|
class LayoutGenerator < Rails::Generators::Base
|
|
8
|
+
include EjectCompatibility
|
|
9
|
+
|
|
7
10
|
source_root File.expand_path("templates", __dir__)
|
|
8
11
|
|
|
9
12
|
class_option :namespace, type: :string, default: "admin",
|
|
10
13
|
desc: "Admin namespace"
|
|
11
14
|
|
|
12
15
|
def copy_layout_components
|
|
13
|
-
|
|
14
|
-
copy_file "components/#{file}", "app/views/#{namespace_name}/components/#{file}"
|
|
15
|
-
end
|
|
16
|
+
run_eject("components/Layout")
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
private
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require "generators/terrazzo/views/eject_compatibility"
|
|
2
3
|
|
|
3
4
|
module Terrazzo
|
|
4
5
|
module Generators
|
|
5
6
|
module Views
|
|
6
7
|
class NavigationGenerator < Rails::Generators::Base
|
|
8
|
+
include EjectCompatibility
|
|
9
|
+
|
|
7
10
|
source_root File.expand_path("templates", __dir__)
|
|
8
11
|
|
|
9
12
|
class_option :namespace, type: :string, default: "admin",
|
|
10
13
|
desc: "Admin namespace"
|
|
11
14
|
|
|
12
15
|
def copy_navigation
|
|
13
|
-
|
|
16
|
+
run_eject("navigation")
|
|
17
|
+
run_eject("components/app-sidebar")
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
private
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
require "rails/generators"
|
|
2
|
+
require_relative "generated_defaults_helper"
|
|
2
3
|
require_relative "page_mapping_helper"
|
|
3
4
|
|
|
4
5
|
module Terrazzo
|
|
5
6
|
module Generators
|
|
6
7
|
module Views
|
|
7
8
|
class NewGenerator < Rails::Generators::Base
|
|
9
|
+
include GeneratedDefaultsHelper
|
|
8
10
|
include PageMappingHelper
|
|
9
11
|
|
|
10
12
|
source_root File.expand_path("templates", __dir__)
|
|
@@ -14,17 +16,22 @@ module Terrazzo
|
|
|
14
16
|
|
|
15
17
|
class_option :namespace, type: :string, default: "admin",
|
|
16
18
|
desc: "Admin namespace"
|
|
19
|
+
class_option :with_counterpart, type: :boolean, default: nil,
|
|
20
|
+
desc: "Also eject the edit view that shares this form partial"
|
|
17
21
|
|
|
18
22
|
def copy_new_template
|
|
23
|
+
ensure_page_barrels
|
|
24
|
+
|
|
19
25
|
if resource.present?
|
|
20
26
|
eject_json_props
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
copy_resource_page_file "pages/new.jsx", "app/views/#{namespace_name}/#{resource_path}/new.jsx"
|
|
28
|
+
copy_resource_page_file_unless_exists "pages/_form.jsx", "app/views/#{namespace_name}/#{resource_path}/_form.jsx"
|
|
23
29
|
register_page_mapping("new")
|
|
24
30
|
eject_edit_view if should_eject_edit?
|
|
25
31
|
else
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
copy_file_over_generated "pages/new.jsx", "app/views/#{namespace_name}/application/new.jsx",
|
|
33
|
+
generated_content: generated_page_stub("new")
|
|
34
|
+
copy_file_unless_exists "pages/_form.jsx", "app/views/#{namespace_name}/application/_form.jsx"
|
|
28
35
|
eject_edit_view if should_eject_edit?
|
|
29
36
|
end
|
|
30
37
|
end
|
|
@@ -45,7 +52,9 @@ module Terrazzo
|
|
|
45
52
|
else
|
|
46
53
|
"app/views/#{namespace_name}/application/edit.jsx"
|
|
47
54
|
end
|
|
55
|
+
return true if generated_file?(edit_path, generated_page_stub("edit"))
|
|
48
56
|
return false if File.exist?(edit_path)
|
|
57
|
+
return options[:with_counterpart] unless options[:with_counterpart].nil?
|
|
49
58
|
|
|
50
59
|
yes?("Also eject the edit view to share the custom form partial? (y/n)")
|
|
51
60
|
end
|
|
@@ -53,10 +62,11 @@ module Terrazzo
|
|
|
53
62
|
def eject_edit_view
|
|
54
63
|
if resource.present?
|
|
55
64
|
eject_edit_json_props
|
|
56
|
-
|
|
65
|
+
copy_resource_page_file "pages/edit.jsx", "app/views/#{namespace_name}/#{resource_path}/edit.jsx"
|
|
57
66
|
register_page_mapping("edit")
|
|
58
67
|
else
|
|
59
|
-
|
|
68
|
+
copy_file_over_generated "pages/edit.jsx", "app/views/#{namespace_name}/application/edit.jsx",
|
|
69
|
+
generated_content: generated_page_stub("edit")
|
|
60
70
|
end
|
|
61
71
|
end
|
|
62
72
|
|
|
@@ -68,10 +78,6 @@ module Terrazzo
|
|
|
68
78
|
RUBY
|
|
69
79
|
end
|
|
70
80
|
|
|
71
|
-
def resource_path
|
|
72
|
-
resource.underscore.pluralize
|
|
73
|
-
end
|
|
74
|
-
|
|
75
81
|
def namespace_name
|
|
76
82
|
options[:namespace]
|
|
77
83
|
end
|