plutonium 0.14.0 → 0.15.0.pre.rc1
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 copy.md +1 -1
- data/README.md +1 -1
- data/app/assets/plutonium.css +1 -1
- data/app/views/{application → plutonium}/_resource_header.html copy.erb +1 -1
- data/app/views/{application → plutonium}/_resource_header.html.erb +1 -1
- data/app/views/{application → plutonium}/_resource_sidebar.html.erb +2 -0
- data/app/views/resource/_resource_details.html.erb +1 -36
- data/app/views/resource/_resource_form.html.erb +1 -5
- data/app/views/resource/_resource_table.html.erb +315 -85
- data/app/views/resource/edit.html.erb +1 -5
- data/app/views/resource/index.html.erb +1 -5
- data/app/views/resource/new.html.erb +1 -5
- data/app/views/resource/show.html.erb +1 -5
- data/config/initializers/pagy.rb +1 -0
- data/config/initializers/rabl.rb +27 -20
- data/gemfiles/rails_7.gemfile.lock +5 -1
- data/lib/generators/pu/core/assets/assets_generator.rb +2 -2
- data/lib/generators/pu/core/install/install_generator.rb +0 -3
- data/lib/generators/pu/core/install/templates/app/controllers/plutonium_controller.rb.tt +2 -0
- data/lib/generators/pu/core/install/templates/app/controllers/resource_controller.rb.tt +21 -1
- data/lib/generators/pu/core/install/templates/app/definitions/resource_definition.rb.tt +2 -0
- data/lib/generators/pu/core/install/templates/app/models/resource_record.rb.tt +0 -2
- data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +5 -2
- data/lib/generators/pu/eject/shell/shell_generator.rb +2 -2
- data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +19 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/logger.rb +1 -1
- data/lib/generators/pu/lib/plutonium_generators/generator.rb +5 -3
- data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +26 -2
- data/lib/generators/pu/pkg/{feature/feature_generator.rb → package/package_generator.rb} +4 -4
- data/lib/generators/pu/pkg/{feature → package}/templates/app/controllers/resource_controller.rb.tt +0 -2
- data/lib/generators/pu/pkg/package/templates/app/definitions/resource_definition.rb.tt +4 -0
- data/lib/generators/pu/pkg/package/templates/app/query_objects/resource_query_object.rb.tt +4 -0
- data/lib/generators/pu/pkg/{app/app_generator.rb → portal/portal_generator.rb} +10 -8
- data/lib/generators/pu/pkg/{app → portal}/templates/app/controllers/concerns/controller.rb.tt +3 -7
- data/lib/generators/pu/pkg/{app → portal}/templates/app/controllers/dashboard_controller.rb.tt +1 -1
- data/lib/generators/pu/pkg/portal/templates/app/controllers/plutonium_controller.rb.tt +5 -0
- data/lib/generators/pu/pkg/{app/templates/app/controllers/controller.rb.tt → portal/templates/app/controllers/resource_controller.rb.tt} +1 -1
- data/lib/generators/pu/pkg/portal/templates/app/definitions/resource_definition.rb.tt +4 -0
- data/lib/generators/pu/pkg/{app → portal}/templates/app/views/package/dashboard/index.html.erb +2 -1
- data/lib/generators/pu/res/conn/conn_generator.rb +78 -3
- data/lib/generators/pu/res/conn/templates/app/controllers/resource_controller.rb.tt +1 -1
- data/lib/generators/pu/res/conn/templates/app/definitions/resource_definition.rb.tt +3 -0
- data/lib/generators/pu/res/conn/templates/app/policies/resource_policy.rb.tt +29 -1
- data/lib/generators/pu/res/conn/templates/app/presenters/resource_presenter.rb.tt +1 -1
- data/lib/generators/pu/res/conn/templates/app/query_objects/resource_query_object.rb.tt +1 -1
- data/lib/generators/pu/res/model/model_generator.rb +0 -7
- data/lib/generators/pu/res/model/templates/model.rb.tt +4 -1
- data/lib/generators/pu/res/scaffold/scaffold_generator.rb +22 -4
- data/lib/generators/pu/res/scaffold/templates/controller.rb.tt +0 -1
- data/lib/generators/pu/res/scaffold/templates/definition.rb.tt +4 -0
- data/lib/generators/pu/res/scaffold/templates/policy.rb.tt +2 -2
- data/lib/generators/pu/rodauth/templates/app/controllers/rodauth_controller.rb.tt +1 -1
- data/lib/generators/pu/rodauth/templates/app/rodauth/account_rodauth_plugin.rb.tt +270 -0
- data/lib/plutonium/action/README.md +0 -0
- data/lib/plutonium/action/base.rb +103 -0
- data/lib/plutonium/action/interactive.rb +117 -0
- data/lib/plutonium/action/route_options.rb +65 -0
- data/lib/plutonium/action/simple.rb +8 -0
- data/lib/plutonium/auth.rb +1 -1
- data/lib/plutonium/configuration.rb +130 -0
- data/lib/plutonium/core/actions/collection.rb +1 -1
- data/lib/plutonium/core/associations/renderers/factory.rb +3 -1
- data/lib/plutonium/core/autodiscovery/association_renderer_discoverer.rb +1 -1
- data/lib/plutonium/core/autodiscovery/input_discoverer.rb +1 -1
- data/lib/plutonium/core/autodiscovery/renderer_discoverer.rb +1 -1
- data/lib/plutonium/core/controller.rb +110 -0
- data/lib/plutonium/core/controllers/authorizable.rb +12 -35
- data/lib/plutonium/core/controllers/bootable.rb +38 -7
- data/lib/plutonium/core/controllers/entity_scoping.rb +6 -2
- data/lib/plutonium/core/fields/renderers/association_renderer.rb +1 -1
- data/lib/plutonium/core/ui/collection.rb +1 -1
- data/lib/plutonium/core/ui/detail.rb +1 -1
- data/lib/plutonium/core/ui/form.rb +1 -1
- data/lib/plutonium/definition/actions.rb +50 -0
- data/lib/plutonium/definition/base.rb +92 -0
- data/lib/plutonium/definition/config_attr.rb +30 -0
- data/lib/plutonium/definition/defineable_props.rb +96 -0
- data/lib/plutonium/definition/search.rb +21 -0
- data/lib/plutonium/engine/validator.rb +30 -0
- data/lib/plutonium/engine.rb +25 -0
- data/lib/plutonium/helpers/assets_helper.rb +73 -20
- data/lib/plutonium/helpers/form_helper.rb +1 -3
- data/lib/plutonium/interaction/README.md +369 -0
- data/lib/plutonium/interaction/base.rb +75 -0
- data/lib/plutonium/interaction/concerns/presentable.rb +61 -0
- data/lib/plutonium/interaction/concerns/workflow_dsl.rb +82 -0
- data/lib/plutonium/interaction/outcome.rb +129 -0
- data/lib/plutonium/interaction/response/base.rb +63 -0
- data/lib/plutonium/interaction/response/null.rb +33 -0
- data/lib/plutonium/interaction/response/redirect.rb +30 -0
- data/lib/plutonium/interaction/response/render.rb +28 -0
- data/lib/plutonium/lib/bit_flags.rb +70 -9
- data/lib/plutonium/lib/overlayed_hash.rb +86 -0
- data/lib/plutonium/lib/smart_cache.rb +171 -0
- data/lib/plutonium/models/has_cents.rb +170 -0
- data/lib/plutonium/{pkg/base.rb → package/engine.rb} +10 -2
- data/lib/plutonium/{application → portal}/controller.rb +3 -11
- data/lib/plutonium/{application → portal}/dynamic_controllers.rb +4 -4
- data/lib/plutonium/portal/engine.rb +15 -0
- data/lib/plutonium/railtie.rb +35 -15
- data/lib/plutonium/reloader.rb +71 -29
- data/lib/plutonium/resource/controller.rb +51 -34
- data/lib/plutonium/resource/controllers/authorizable.rb +128 -0
- data/lib/plutonium/{core → resource}/controllers/crud_actions.rb +23 -22
- data/lib/plutonium/resource/controllers/defineable.rb +26 -0
- data/lib/plutonium/{core → resource}/controllers/interactive_actions.rb +12 -12
- data/lib/plutonium/resource/controllers/presentable.rb +41 -0
- data/lib/plutonium/resource/controllers/queryable.rb +44 -0
- data/lib/plutonium/resource/definition.rb +6 -0
- data/lib/plutonium/resource/policy.rb +25 -13
- data/lib/plutonium/resource/query_object.rb +50 -51
- data/lib/plutonium/resource/record.rb +6 -89
- data/lib/plutonium/resource/register.rb +82 -0
- data/lib/plutonium/routing/mapper_extensions.rb +1 -1
- data/lib/plutonium/routing/resource_registration.rb +1 -1
- data/lib/plutonium/routing/route_set_extensions.rb +6 -18
- data/lib/plutonium/ui/action_button.rb +125 -0
- data/lib/plutonium/ui/breadcrumbs.rb +163 -0
- data/lib/plutonium/ui/component/base.rb +13 -0
- data/lib/plutonium/ui/component/behaviour.rb +38 -0
- data/lib/plutonium/ui/component/kit.rb +31 -0
- data/lib/plutonium/ui/component/methods.rb +54 -0
- data/lib/plutonium/ui/display/base.rb +25 -0
- data/lib/plutonium/ui/display/component/association.rb +26 -0
- data/lib/plutonium/ui/display/resource.rb +77 -0
- data/lib/plutonium/ui/display/theme.rb +27 -0
- data/lib/plutonium/ui/dyna_frame/content.rb +20 -0
- data/lib/plutonium/ui/empty_card.rb +20 -0
- data/lib/plutonium/ui/form/base.rb +37 -0
- data/lib/plutonium/ui/form/resource.rb +75 -0
- data/lib/plutonium/ui/form/theme.rb +42 -0
- data/lib/plutonium/ui/page/base.rb +112 -0
- data/lib/plutonium/ui/page/edit.rb +23 -0
- data/lib/plutonium/ui/page/index.rb +27 -0
- data/lib/plutonium/ui/page/new.rb +23 -0
- data/lib/plutonium/ui/page/show.rb +27 -0
- data/lib/plutonium/ui/page_header.rb +49 -0
- data/lib/plutonium/ui/table/base.rb +13 -0
- data/lib/plutonium/ui/table/components/pagy_info.rb +70 -0
- data/lib/plutonium/ui/table/components/pagy_page_info.rb +70 -0
- data/lib/plutonium/ui/table/components/pagy_pagination.rb +105 -0
- data/lib/plutonium/ui/table/components/scopes_bar.rb +136 -0
- data/lib/plutonium/ui/table/components/search_bar.rb +158 -0
- data/lib/plutonium/ui/table/display_theme.rb +21 -0
- data/lib/plutonium/ui/table/resource.rb +98 -0
- data/lib/plutonium/ui/table/theme.rb +35 -0
- data/lib/plutonium/ui.rb +9 -0
- data/lib/plutonium/version.rb +5 -1
- data/lib/plutonium.rb +53 -26
- data/package-lock.json +19 -22
- data/package.json +4 -4
- data/sig/.keep +0 -0
- data/src/css/plutonium.css +15 -0
- data/tailwind.options.js +11 -3
- metadata +220 -81
- data/lib/generators/pu/core/install/templates/app/presenters/resource_presenter.rb.tt +0 -2
- data/lib/generators/pu/core/install/templates/app/query_objects/resource_query_object.rb.tt +0 -2
- data/lib/generators/pu/pkg/feature/templates/app/query_objects/resource_query_object.rb.tt +0 -4
- data/lib/plutonium/concerns/resource_validatable.rb +0 -34
- data/lib/plutonium/config.rb +0 -9
- data/lib/plutonium/core/controllers/base.rb +0 -101
- data/lib/plutonium/core/controllers/presentable.rb +0 -65
- data/lib/plutonium/core/controllers/queryable.rb +0 -28
- data/lib/plutonium/pkg/app.rb +0 -35
- data/lib/plutonium/pkg/concerns/resource_validatable.rb +0 -36
- data/lib/plutonium/pkg/feature.rb +0 -18
- data/lib/plutonium/policy/initializer.rb +0 -22
- data/lib/plutonium/policy/scope.rb +0 -19
- data/lib/plutonium/pundit/context.rb +0 -18
- data/lib/plutonium/pundit/policy_finder.rb +0 -25
- data/lib/plutonium/resource/policy_context.rb +0 -5
- data/lib/plutonium/resource_register.rb +0 -83
- data/lib/plutonium/smart_cache.rb +0 -151
- data/sig/plutonium.rbs +0 -12
- /data/app/views/{application → plutonium}/_flash.html.erb +0 -0
- /data/app/views/{application → plutonium}/_flash_alerts.html.erb +0 -0
- /data/app/views/{application → plutonium}/_flash_toasts.html.erb +0 -0
- /data/lib/generators/pu/pkg/{app/templates/app/views/package → package/templates}/.keep +0 -0
- /data/lib/generators/pu/pkg/{feature → package}/templates/app/interactions/resource_interaction.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{feature → package}/templates/app/models/resource_record.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{feature → package}/templates/app/policies/resource_policy.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{feature → package}/templates/app/presenters/resource_presenter.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{feature → package}/templates/lib/engine.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{app → portal}/templates/app/policies/resource_policy.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{app → portal}/templates/app/presenters/resource_presenter.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{app → portal}/templates/app/query_objects/resource_query_object.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{feature/templates → portal/templates/app/views/package}/.keep +0 -0
- /data/lib/generators/pu/pkg/{app → portal}/templates/config/routes.rb.tt +0 -0
- /data/lib/generators/pu/pkg/{app → portal}/templates/lib/engine.rb.tt +0 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
module Components
|
|
7
|
+
class ScopesBar < Plutonium::UI::Component::Base
|
|
8
|
+
include Plutonium::UI::Component::Behaviour
|
|
9
|
+
|
|
10
|
+
def view_template
|
|
11
|
+
div(
|
|
12
|
+
class:
|
|
13
|
+
# "flex flex-wrap justify-between items-center gap-4 p-4 bg-white border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700 mb-4"
|
|
14
|
+
"flex flex-wrap justify-between items-center gap-4 mb-4"
|
|
15
|
+
) do
|
|
16
|
+
div(class: "flex flex-wrap items-center gap-2") do
|
|
17
|
+
name = "all"
|
|
18
|
+
if current_scope.blank?
|
|
19
|
+
a(
|
|
20
|
+
id: "#{name}-scope",
|
|
21
|
+
href: current_query_object.build_url(scope: nil),
|
|
22
|
+
class:
|
|
23
|
+
"px-4 py-2 text-sm font-medium text-white bg-primary-700 border border-primary-700 rounded-lg hover:bg-primary-800 focus:z-10 focus:ring-2 focus:ring-primary-700 focus:text-white dark:bg-primary-600 dark:border-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
|
|
24
|
+
) { name.humanize }
|
|
25
|
+
else
|
|
26
|
+
a(
|
|
27
|
+
id: "#{name}-scope",
|
|
28
|
+
href: current_query_object.build_url(scope: nil),
|
|
29
|
+
class:
|
|
30
|
+
"px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 hover:text-gray-700 focus:z-10 focus:ring-2 focus:ring-gray-300 focus:text-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:focus:text-white"
|
|
31
|
+
) { name.humanize }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
current_query_object.scope_definitions.each do |name, definition|
|
|
35
|
+
if name == current_scope
|
|
36
|
+
a(
|
|
37
|
+
id: "#{name}-scope",
|
|
38
|
+
href: current_query_object.build_url(scope: name),
|
|
39
|
+
class:
|
|
40
|
+
"px-4 py-2 text-sm font-medium text-white bg-primary-700 border border-primary-700 rounded-lg hover:bg-primary-800 focus:z-10 focus:ring-2 focus:ring-primary-700 focus:text-white dark:bg-primary-600 dark:border-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
|
|
41
|
+
) { name.humanize }
|
|
42
|
+
else
|
|
43
|
+
a(
|
|
44
|
+
id: "#{name}-scope",
|
|
45
|
+
href: current_query_object.build_url(scope: name),
|
|
46
|
+
class:
|
|
47
|
+
"px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 hover:text-gray-700 focus:z-10 focus:ring-2 focus:ring-gray-300 focus:text-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:focus:text-white"
|
|
48
|
+
) { name.humanize }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# div(class: "flex flex-wrap items-center gap-2") do
|
|
54
|
+
# button(
|
|
55
|
+
# class:
|
|
56
|
+
# "inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-red-700 rounded-lg hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-800"
|
|
57
|
+
# ) do
|
|
58
|
+
# svg(
|
|
59
|
+
# class: "w-4 h-4 mr-2",
|
|
60
|
+
# fill: "none",
|
|
61
|
+
# stroke: "currentColor",
|
|
62
|
+
# viewbox: "0 0 24 24",
|
|
63
|
+
# xmlns: "http://www.w3.org/2000/svg"
|
|
64
|
+
# ) do |s|
|
|
65
|
+
# s.path(
|
|
66
|
+
# stroke_linecap: "round",
|
|
67
|
+
# stroke_linejoin: "round",
|
|
68
|
+
# stroke_width: "2",
|
|
69
|
+
# d:
|
|
70
|
+
# "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
71
|
+
# )
|
|
72
|
+
# end
|
|
73
|
+
# plain " Delete Selected "
|
|
74
|
+
# end
|
|
75
|
+
# button(
|
|
76
|
+
# class:
|
|
77
|
+
# "inline-flex items-center px-3 py-2 text-sm font-medium text-white bg-yellow-700 rounded-lg hover:bg-yellow-800 focus:ring-4 focus:outline-none focus:ring-yellow-300 dark:bg-yellow-600 dark:hover:bg-yellow-700 dark:focus:ring-yellow-800"
|
|
78
|
+
# ) do
|
|
79
|
+
# svg(
|
|
80
|
+
# class: "w-4 h-4 mr-2",
|
|
81
|
+
# fill: "none",
|
|
82
|
+
# stroke: "currentColor",
|
|
83
|
+
# viewbox: "0 0 24 24",
|
|
84
|
+
# xmlns: "http://www.w3.org/2000/svg"
|
|
85
|
+
# ) do |s|
|
|
86
|
+
# s.path(
|
|
87
|
+
# stroke_linecap: "round",
|
|
88
|
+
# stroke_linejoin: "round",
|
|
89
|
+
# stroke_width: "2",
|
|
90
|
+
# d:
|
|
91
|
+
# "M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"
|
|
92
|
+
# )
|
|
93
|
+
# end
|
|
94
|
+
# plain " Archive Selected "
|
|
95
|
+
# end
|
|
96
|
+
# button(
|
|
97
|
+
# id: "dropdownActionButton",
|
|
98
|
+
# data_dropdown_toggle: "dropdownAction",
|
|
99
|
+
# class:
|
|
100
|
+
# "inline-flex items-center text-gray-500 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-lg text-sm px-3 py-2 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700",
|
|
101
|
+
# type: "button"
|
|
102
|
+
# ) do
|
|
103
|
+
# span(class: "sr-only") { "Action button" }
|
|
104
|
+
# plain " More Actions "
|
|
105
|
+
# svg(
|
|
106
|
+
# class: "w-2.5 h-2.5 ml-2.5",
|
|
107
|
+
# aria_hidden: "true",
|
|
108
|
+
# xmlns: "http://www.w3.org/2000/svg",
|
|
109
|
+
# fill: "none",
|
|
110
|
+
# viewbox: "0 0 10 6"
|
|
111
|
+
# ) do |s|
|
|
112
|
+
# s.path(
|
|
113
|
+
# stroke: "currentColor",
|
|
114
|
+
# stroke_linecap: "round",
|
|
115
|
+
# stroke_linejoin: "round",
|
|
116
|
+
# stroke_width: "2",
|
|
117
|
+
# d: "m1 1 4 4 4-4"
|
|
118
|
+
# )
|
|
119
|
+
# end
|
|
120
|
+
# end
|
|
121
|
+
# end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def current_scope = resource_query_params[:scope]
|
|
128
|
+
|
|
129
|
+
def render?
|
|
130
|
+
current_query_object.scope_definitions.present?
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
module Components
|
|
7
|
+
class SearchBar < Plutonium::UI::Component::Base
|
|
8
|
+
def view_template
|
|
9
|
+
original_attributes = Phlex::HTML::EVENT_ATTRIBUTES
|
|
10
|
+
temp_attributes = Phlex::HTML::EVENT_ATTRIBUTES.dup
|
|
11
|
+
temp_attributes.delete("oninput")
|
|
12
|
+
temp_attributes.delete("onclick")
|
|
13
|
+
Phlex::HTML.const_set(:EVENT_ATTRIBUTES, temp_attributes)
|
|
14
|
+
|
|
15
|
+
div(
|
|
16
|
+
class:
|
|
17
|
+
# "p-4 bg-white border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700 space-y-2 mb-4"
|
|
18
|
+
"space-y-2 mb-4"
|
|
19
|
+
) do
|
|
20
|
+
search_query = current_query_object.search_query
|
|
21
|
+
query_params = resource_query_params
|
|
22
|
+
render Phlexi::Form(:q, attributes: {data: {controller: "form", turbo_frame: nil}}) {
|
|
23
|
+
div(class: "relative") do
|
|
24
|
+
div(class: "absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none") do
|
|
25
|
+
svg(
|
|
26
|
+
class: "w-5 h-5 text-gray-500 dark:text-gray-400",
|
|
27
|
+
aria_hidden: "true",
|
|
28
|
+
fill: "currentColor",
|
|
29
|
+
viewbox: "0 0 20 20",
|
|
30
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
31
|
+
) do |s|
|
|
32
|
+
s.path(
|
|
33
|
+
fill_rule: "evenodd",
|
|
34
|
+
d:
|
|
35
|
+
"M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z",
|
|
36
|
+
clip_rule: "evenodd"
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
render field(:search, value: search_query)
|
|
41
|
+
.placeholder("Search...")
|
|
42
|
+
.input_tag(
|
|
43
|
+
id: "search",
|
|
44
|
+
value: search_query,
|
|
45
|
+
class: "block w-full p-2 pl-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500",
|
|
46
|
+
data: {
|
|
47
|
+
action: "form#submit",
|
|
48
|
+
turbo_permanent: true
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
render field(:scope, value: query_params[:scope]).input_tag(type: :hidden)
|
|
53
|
+
render field(:sort_fields, value: query_params[:sort_fields]).input_array_tag do |f|
|
|
54
|
+
render f.input_tag(type: :hidden)
|
|
55
|
+
end
|
|
56
|
+
nest_one(:sort_directions) do |directions|
|
|
57
|
+
query_params[:sort_directions]&.each do |name, value|
|
|
58
|
+
render directions.field(name, value:).input_tag(hidden: true)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# div(class: "flex flex-wrap items-center gap-4") do
|
|
65
|
+
# span(class: "text-sm font-medium text-gray-900 dark:text-white") do
|
|
66
|
+
# "Filters:"
|
|
67
|
+
# end
|
|
68
|
+
# select(
|
|
69
|
+
# id: "category-filter",
|
|
70
|
+
# class:
|
|
71
|
+
# "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
72
|
+
# ) do
|
|
73
|
+
# option(selected: "selected", value: "") { "All Categories" }
|
|
74
|
+
# option(value: "technology") { "Technology" }
|
|
75
|
+
# option(value: "science") { "Science" }
|
|
76
|
+
# option(value: "health") { "Health" }
|
|
77
|
+
# end
|
|
78
|
+
# div(class: "flex items-center space-x-2") do
|
|
79
|
+
# input(
|
|
80
|
+
# type: "date",
|
|
81
|
+
# id: "start-date",
|
|
82
|
+
# class:
|
|
83
|
+
# "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
84
|
+
# )
|
|
85
|
+
# span(class: "text-gray-500 dark:text-gray-400") { "to" }
|
|
86
|
+
# input(
|
|
87
|
+
# type: "date",
|
|
88
|
+
# id: "end-date",
|
|
89
|
+
# class:
|
|
90
|
+
# "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
91
|
+
# )
|
|
92
|
+
# end
|
|
93
|
+
# select(
|
|
94
|
+
# id: "author-filter",
|
|
95
|
+
# class:
|
|
96
|
+
# "bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
|
97
|
+
# ) do
|
|
98
|
+
# option(selected: "selected", value: "") { "All Authors" }
|
|
99
|
+
# option(value: "john-doe") { "John Doe" }
|
|
100
|
+
# option(value: "jane-smith") { "Jane Smith" }
|
|
101
|
+
# end
|
|
102
|
+
# button(
|
|
103
|
+
# onclick: "applyFilters()",
|
|
104
|
+
# class:
|
|
105
|
+
# "inline-flex items-center text-white bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:ring-primary-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-primary-600 dark:hover:bg-primary-700 focus:outline-none dark:focus:ring-primary-800"
|
|
106
|
+
# ) do
|
|
107
|
+
# svg(
|
|
108
|
+
# class: "w-4 h-4 mr-2",
|
|
109
|
+
# fill: "currentColor",
|
|
110
|
+
# viewbox: "0 0 20 20",
|
|
111
|
+
# xmlns: "http://www.w3.org/2000/svg"
|
|
112
|
+
# ) do |s|
|
|
113
|
+
# s.path(
|
|
114
|
+
# fill_rule: "evenodd",
|
|
115
|
+
# d:
|
|
116
|
+
# "M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z",
|
|
117
|
+
# clip_rule: "evenodd"
|
|
118
|
+
# )
|
|
119
|
+
# end
|
|
120
|
+
# plain " Apply Filters "
|
|
121
|
+
# end
|
|
122
|
+
# button(
|
|
123
|
+
# onclick: "clearFilters()",
|
|
124
|
+
# class:
|
|
125
|
+
# "inline-flex items-center text-gray-900 bg-white border border-gray-300 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-lg text-sm px-4 py-2 dark:bg-gray-800 dark:text-white dark:border-gray-600 dark:hover:bg-gray-700 dark:hover:border-gray-600 dark:focus:ring-gray-700"
|
|
126
|
+
# ) do
|
|
127
|
+
# svg(
|
|
128
|
+
# class: "w-4 h-4 mr-2",
|
|
129
|
+
# fill: "currentColor",
|
|
130
|
+
# viewbox: "0 0 20 20",
|
|
131
|
+
# xmlns: "http://www.w3.org/2000/svg"
|
|
132
|
+
# ) do |s|
|
|
133
|
+
# s.path(
|
|
134
|
+
# fill_rule: "evenodd",
|
|
135
|
+
# d:
|
|
136
|
+
# "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
|
|
137
|
+
# clip_rule: "evenodd"
|
|
138
|
+
# )
|
|
139
|
+
# end
|
|
140
|
+
# plain " Clear Filters "
|
|
141
|
+
# end
|
|
142
|
+
# end
|
|
143
|
+
end
|
|
144
|
+
ensure
|
|
145
|
+
# TODO: remove this once Phlex adds support for SafeValues
|
|
146
|
+
Phlex::HTML.const_set(:EVENT_ATTRIBUTES, original_attributes)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
def render?
|
|
152
|
+
current_query_object.search_filter.present? && current_policy.allowed_to?(:search?)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
class DisplayTheme < Phlexi::Table::DisplayTheme
|
|
7
|
+
def self.theme
|
|
8
|
+
super.merge({
|
|
9
|
+
string: "max-h-[150px] overflow-y-auto",
|
|
10
|
+
prefixed_icon: "w-4 h-4 mr-1",
|
|
11
|
+
link: "text-primary-600 dark:text-primary-500",
|
|
12
|
+
color: "flex items-center",
|
|
13
|
+
color_indicator: "w-10 h-10 rounded-full mr-2",
|
|
14
|
+
email: "flex items-center text-primary-600 dark:text-primary-500 whitespace-nowrap",
|
|
15
|
+
json: "max-h-[150px] overflow-y-auto whitespace-pre font-mono shadow-inner p-4"
|
|
16
|
+
})
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
class Resource < Plutonium::UI::Component::Base
|
|
7
|
+
attr_reader :collection, :resource_fields, :resource_definition
|
|
8
|
+
|
|
9
|
+
def initialize(collection, resource_fields:, resource_definition:)
|
|
10
|
+
@collection = collection
|
|
11
|
+
@resource_fields = resource_fields
|
|
12
|
+
@resource_definition = resource_definition
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def view_template
|
|
16
|
+
render_search_bar
|
|
17
|
+
render_scopes_bar
|
|
18
|
+
|
|
19
|
+
collection.empty? ? render_empty_card : render_table
|
|
20
|
+
|
|
21
|
+
render_footer
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def render_search_bar
|
|
27
|
+
TableSearchBar()
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def render_scopes_bar
|
|
31
|
+
TableScopesBar()
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def render_empty_card
|
|
35
|
+
EmptyCard("No #{resource_name_plural(resource_class)} match your query") {
|
|
36
|
+
action = resource_definition.defined_actions[:new]
|
|
37
|
+
if action&.permitted_by?(current_policy)
|
|
38
|
+
url = resource_url_for(resource_class, *action.route_options.url_args, **action.route_options.url_options)
|
|
39
|
+
ActionButton(action, url:)
|
|
40
|
+
end
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def render_table
|
|
45
|
+
render Plutonium::UI::Table::Base.new(collection) do |table|
|
|
46
|
+
@resource_fields.each do |name|
|
|
47
|
+
# column :name, as: :string
|
|
48
|
+
# column :description, class: "text-red-700"
|
|
49
|
+
# column :age, align: :end
|
|
50
|
+
# column :dob do |proxy|
|
|
51
|
+
# proxy.field(:dob).date_tag
|
|
52
|
+
# end
|
|
53
|
+
|
|
54
|
+
column_definition = resource_definition.defined_columns[name] || {}
|
|
55
|
+
column_display_options = column_definition[:options] || {}
|
|
56
|
+
display_field_as = column_display_options.delete(:as)
|
|
57
|
+
align_field_to = column_display_options.delete(:align)
|
|
58
|
+
|
|
59
|
+
display_block = column_definition[:block] || ->(wrapped_object, key) {
|
|
60
|
+
f = wrapped_object.field(key)
|
|
61
|
+
display_field_as ||= f.inferred_field_component
|
|
62
|
+
f.send(:"#{display_field_as}_tag", **column_display_options)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
field_options = resource_definition.defined_fields[name] ? resource_definition.defined_fields[name][:options] : {}
|
|
66
|
+
field_options[:as] = display_field_as
|
|
67
|
+
field_options[:align] = align_field_to if align_field_to
|
|
68
|
+
table.column name, **field_options, sort_params: current_query_object.sort_params_for(name), &display_block
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
table.actions do |wrapped_object|
|
|
72
|
+
record = wrapped_object.unwrapped
|
|
73
|
+
policy = policy_for(record:)
|
|
74
|
+
|
|
75
|
+
div(class: "flex space-x-2") {
|
|
76
|
+
resource_definition.defined_actions
|
|
77
|
+
.select { |k, a| a.collection_record_action? && policy.allowed_to?(:"#{k}?") }
|
|
78
|
+
.values
|
|
79
|
+
.each { |action|
|
|
80
|
+
url = resource_url_for(record, *action.route_options.url_args, **action.route_options.url_options)
|
|
81
|
+
|
|
82
|
+
ActionButton(action, url:, variant: :table)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def render_footer
|
|
90
|
+
div(class: "sticky bottom-[-2px] p-4 pb-6 w-full z-50 bg-gray-50 dark:bg-gray-900") {
|
|
91
|
+
TableInfo(pagy_instance)
|
|
92
|
+
TablePagination(pagy_instance)
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
class Theme < Phlexi::Table::Theme
|
|
7
|
+
def self.theme
|
|
8
|
+
super.merge({
|
|
9
|
+
selection_checkbox: "w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600",
|
|
10
|
+
name_column: "font-medium text-gray-900 whitespace-nowrap dark:text-white",
|
|
11
|
+
align_start: "text-start",
|
|
12
|
+
align_end: "text-end",
|
|
13
|
+
wrapper: "relative overflow-x-auto shadow-md sm:rounded-lg",
|
|
14
|
+
base: "w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400",
|
|
15
|
+
caption: "p-5 text-lg font-semibold text-left rtl:text-right text-gray-900 bg-white dark:text-white dark:bg-gray-800",
|
|
16
|
+
description: "mt-1 text-sm font-normal text-gray-500 dark:text-gray-400",
|
|
17
|
+
header: "text-xs text-gray-700 uppercase bg-gray-200 dark:bg-gray-700 dark:text-gray-400",
|
|
18
|
+
header_grouping_cell: "px-6 py-3 text-center text-sm border-b border-t border-r last:border-r-0 dark:border-gray-800",
|
|
19
|
+
header_cell: "px-6 py-3",
|
|
20
|
+
header_cell_content_wrapper: "inline-flex items-center",
|
|
21
|
+
header_cell_sort_wrapper: "flex items-center",
|
|
22
|
+
header_cell_sort_indicator: "ml-1.5",
|
|
23
|
+
body_row: "bg-white border-b last:border-none dark:bg-gray-800 dark:border-gray-700",
|
|
24
|
+
body_cell: "px-6 py-4 whitespace-pre max-w-[310px] hover:max-w-[600px] overflow-hidden text-ellipsis transition-all duration-300 ease-in-out",
|
|
25
|
+
sort_icon: "w-3 h-3",
|
|
26
|
+
sort_icon_active: "text-primary-600",
|
|
27
|
+
sort_index_clear_link: "ml-2",
|
|
28
|
+
sort_index_clear_link_text: "text-xs font-bold",
|
|
29
|
+
sort_index_clear_link_icon: "ml-1 text-red-600"
|
|
30
|
+
})
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/plutonium/ui.rb
ADDED
data/lib/plutonium/version.rb
CHANGED
data/lib/plutonium.rb
CHANGED
|
@@ -1,57 +1,84 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
require "zeitwerk"
|
|
4
|
+
require "action_policy"
|
|
5
|
+
require "phlex"
|
|
6
|
+
require "phlex-rails"
|
|
7
|
+
require "phlex/tabler_icons"
|
|
8
|
+
require "phlexi-display"
|
|
9
|
+
require "phlexi-form"
|
|
10
|
+
require "phlexi-table"
|
|
9
11
|
|
|
10
|
-
require_relative "plutonium/
|
|
12
|
+
require_relative "plutonium/configuration"
|
|
11
13
|
|
|
14
|
+
# Plutonium module
|
|
15
|
+
#
|
|
16
|
+
# This module provides the main functionality for the Plutonium gem.
|
|
17
|
+
# It sets up autoloading using Zeitwerk and provides utility methods
|
|
18
|
+
# for accessing gem-related information.
|
|
12
19
|
module Plutonium
|
|
13
|
-
# Custom error class for
|
|
20
|
+
# Custom error class for Plutonium-specific exceptions
|
|
14
21
|
class Error < StandardError; end
|
|
15
22
|
|
|
23
|
+
# Set up Zeitwerk loader for the Plutonium gem
|
|
24
|
+
# @return [Zeitwerk::Loader] configured Zeitwerk loader instance
|
|
25
|
+
Loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false).tap do |loader|
|
|
26
|
+
loader.ignore("#{__dir__}/generators")
|
|
27
|
+
loader.ignore("#{__dir__}/plutonium/railtie.rb")
|
|
28
|
+
loader.inflector.inflect("ui" => "UI")
|
|
29
|
+
loader.enable_reloading if defined?(Rails.env) && Rails.env.development?
|
|
30
|
+
loader.setup
|
|
31
|
+
end
|
|
32
|
+
|
|
16
33
|
class << self
|
|
17
|
-
|
|
34
|
+
def deprecator
|
|
35
|
+
@deprecator ||= ActiveSupport::Deprecation.new("1.0", "Plutonium")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Get the root directory of the gem
|
|
39
|
+
#
|
|
40
|
+
# @return [Pathname] the root directory path
|
|
18
41
|
def root
|
|
19
|
-
Pathname.new(File.expand_path("..", __dir__))
|
|
42
|
+
@root ||= Pathname.new(File.expand_path("..", __dir__))
|
|
20
43
|
end
|
|
21
44
|
|
|
22
|
-
#
|
|
45
|
+
# Get the root directory of the lib folder of the gem
|
|
46
|
+
#
|
|
47
|
+
# @return [Pathname] the lib root directory path
|
|
23
48
|
def lib_root
|
|
24
|
-
root.join("lib", "plutonium")
|
|
49
|
+
@lib_root ||= root.join("lib", "plutonium")
|
|
25
50
|
end
|
|
26
51
|
|
|
27
|
-
#
|
|
52
|
+
# Get the Rails logger
|
|
53
|
+
#
|
|
54
|
+
# @return [Logger] the Rails logger instance
|
|
28
55
|
def logger
|
|
29
56
|
Rails.logger
|
|
30
57
|
end
|
|
31
58
|
|
|
32
|
-
#
|
|
59
|
+
# Get the name of the application
|
|
60
|
+
#
|
|
61
|
+
# @return [String] the application name
|
|
33
62
|
def application_name
|
|
34
63
|
@application_name || Rails.application.class.module_parent_name
|
|
35
64
|
end
|
|
36
65
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
66
|
+
# Set the name of the application
|
|
67
|
+
#
|
|
68
|
+
# @param [String] name the name of the application
|
|
39
69
|
attr_writer :application_name
|
|
40
70
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
ActiveModel::Type::Boolean.new.cast(ENV["PLUTONIUM_DEV"]).present?
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Eager loads Rails application if not already eager loaded
|
|
71
|
+
# Eager load Rails application if not already eager loaded
|
|
72
|
+
#
|
|
47
73
|
# @return [void]
|
|
48
74
|
def eager_load_rails!
|
|
49
|
-
return if Rails.
|
|
75
|
+
return if @rails_eager_loaded || Rails.application.config.eager_load
|
|
50
76
|
|
|
51
|
-
Rails.application.eager_load!
|
|
77
|
+
Rails.application.eager_load!
|
|
52
78
|
@rails_eager_loaded = true
|
|
53
79
|
end
|
|
54
80
|
end
|
|
55
81
|
end
|
|
56
82
|
|
|
57
|
-
|
|
83
|
+
# Load Railtie if Rails is defined
|
|
84
|
+
require_relative "plutonium/railtie" if defined?(Rails::Railtie)
|