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,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Form
|
|
6
|
+
class Resource < Base
|
|
7
|
+
attr_reader :resource_fields, :resource_definition
|
|
8
|
+
|
|
9
|
+
def initialize(*, resource_fields:, resource_definition:, **, &)
|
|
10
|
+
super(*, **, &)
|
|
11
|
+
@resource_fields = resource_fields
|
|
12
|
+
@resource_definition = resource_definition
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def form_template
|
|
16
|
+
render_fields
|
|
17
|
+
render_actions
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def render_fields
|
|
23
|
+
fields_wrapper {
|
|
24
|
+
resource_fields.each { |name|
|
|
25
|
+
render_resource_field name
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def form_action
|
|
31
|
+
return @form_action unless object.present? && @form_action != false && helpers.present?
|
|
32
|
+
|
|
33
|
+
@form_action ||= resource_url_for(object, action: object.new_record? ? :create : :update)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def render_resource_field(name)
|
|
37
|
+
# input :name, as: :string
|
|
38
|
+
# input :description, class: "col-span-full"
|
|
39
|
+
# input :age, field: {class: "max-h-fit"}
|
|
40
|
+
# input :dob do |f|
|
|
41
|
+
# f.date_tag
|
|
42
|
+
# end
|
|
43
|
+
|
|
44
|
+
when_permitted(name) do
|
|
45
|
+
input_definition = resource_definition.defined_inputs[name] || {}
|
|
46
|
+
input_options = input_definition[:options] || {}
|
|
47
|
+
input_field_as = input_options.delete(:as)
|
|
48
|
+
|
|
49
|
+
input_field_options = input_options.delete(:field) || {}
|
|
50
|
+
input_block = input_definition[:block] || ->(f) {
|
|
51
|
+
input_field_as ||= f.inferred_field_component
|
|
52
|
+
f.send(:"#{input_field_as}_tag", **input_field_options)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
field_options = resource_definition.defined_fields[name] ? resource_definition.defined_fields[name][:options] : {}
|
|
56
|
+
if !input_options[:class] || !input_options[:class].include?("col-span")
|
|
57
|
+
# temp hack to allow col span overrides
|
|
58
|
+
# TODO: remove once we complete theming, which will support merges
|
|
59
|
+
input_options[:class] = tokens("col-span-full", input_options[:class])
|
|
60
|
+
end
|
|
61
|
+
render field(name, **field_options).wrapped(**input_options) do |f|
|
|
62
|
+
render input_block.call(f)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def when_permitted(name, &)
|
|
68
|
+
return unless @resource_fields.include? name
|
|
69
|
+
|
|
70
|
+
yield
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Form
|
|
6
|
+
class Theme < Phlexi::Form::Theme
|
|
7
|
+
def self.theme
|
|
8
|
+
super.merge({
|
|
9
|
+
base: "relative bg-white dark:bg-gray-800 shadow-md sm:rounded-lg my-3 p-6 space-y-6",
|
|
10
|
+
fields_wrapper: "grid grid-cols-1 md:grid-cols-2 2xl:grid-cols-4 gap-6 grid-flow-row-dense",
|
|
11
|
+
actions_wrapper: "flex justify-end space-x-2",
|
|
12
|
+
wrapper: nil,
|
|
13
|
+
inner_wrapper: "w-full",
|
|
14
|
+
# label themes
|
|
15
|
+
label: "mt-2 block mb-2 text-base font-bold",
|
|
16
|
+
invalid_label: "text-red-700 dark:text-red-500",
|
|
17
|
+
valid_label: "text-green-700 dark:text-green-500",
|
|
18
|
+
neutral_label: "text-gray-500 dark:text-gray-400",
|
|
19
|
+
# input themes
|
|
20
|
+
input: "w-full p-2 border rounded-md shadow-sm font-medium text-sm dark:bg-gray-700",
|
|
21
|
+
invalid_input: "bg-red-50 border-red-500 dark:border-red-500 text-red-900 dark:text-red-500 placeholder-red-700 dark:placeholder-red-500 focus:ring-red-500 focus:border-red-500",
|
|
22
|
+
valid_input: "bg-green-50 border-green-500 dark:border-green-500 text-green-900 dark:text-green-400 placeholder-green-700 dark:placeholder-green-500 focus:ring-green-500 focus:border-green-500",
|
|
23
|
+
neutral_input: "border-gray-300 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white focus:ring-primary-500 focus:border-primary-500",
|
|
24
|
+
# color
|
|
25
|
+
color: "pu-color-input appearance-none bg-transparent border-none cursor-pointer w-10 h-10",
|
|
26
|
+
invalid_color: nil,
|
|
27
|
+
valid_color: nil,
|
|
28
|
+
neutral_color: nil,
|
|
29
|
+
# file
|
|
30
|
+
file: "w-full border rounded-md shadow-sm font-medium text-sm dark:bg-gray-700 focus:outline-none",
|
|
31
|
+
# hint themes
|
|
32
|
+
hint: "mt-2 text-sm text-gray-500 dark:text-gray-200",
|
|
33
|
+
# error themes
|
|
34
|
+
error: "mt-2 text-sm text-red-600 dark:text-red-500",
|
|
35
|
+
# button themes
|
|
36
|
+
button: "px-4 py-2 bg-primary-600 text-white rounded-md hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
37
|
+
})
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Page
|
|
6
|
+
class Base < Plutonium::UI::Component::Base
|
|
7
|
+
def initialize(page_title: nil, page_description: nil, page_actions: nil)
|
|
8
|
+
@page_title = page_title
|
|
9
|
+
@page_description = page_description
|
|
10
|
+
@page_actions = page_actions
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def view_template(&)
|
|
14
|
+
render_before_header
|
|
15
|
+
render_header
|
|
16
|
+
render_after_header
|
|
17
|
+
|
|
18
|
+
render_before_content
|
|
19
|
+
render_content(&)
|
|
20
|
+
render_after_content
|
|
21
|
+
|
|
22
|
+
render_before_footer
|
|
23
|
+
render_footer
|
|
24
|
+
render_after_footer
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
attr_reader :page_title, :page_description, :page_actions
|
|
30
|
+
|
|
31
|
+
def render_header
|
|
32
|
+
render_before_breadcrumbs
|
|
33
|
+
render_breadcrumbs
|
|
34
|
+
render_after_breadcrumbs
|
|
35
|
+
|
|
36
|
+
render_before_page_header
|
|
37
|
+
render_page_header
|
|
38
|
+
render_after_page_header
|
|
39
|
+
|
|
40
|
+
render_before_toolbar
|
|
41
|
+
render_toolbar
|
|
42
|
+
render_after_toolbar
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def render_breadcrumbs
|
|
46
|
+
Breadcrumbs()
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def render_page_header
|
|
50
|
+
return unless page_title
|
|
51
|
+
|
|
52
|
+
PageHeader(title: page_title, description: page_description, actions: page_actions)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def render_toolbar
|
|
56
|
+
# Implement toolbar content
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def render_content(&block)
|
|
60
|
+
block ||= proc { render_default_content }
|
|
61
|
+
|
|
62
|
+
DynaFrameContent(&block)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def render_default_content
|
|
66
|
+
raise NotImplementedError, "#{self.class}#render_default_content"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def render_footer
|
|
70
|
+
# Implement footer content
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Customization hooks
|
|
74
|
+
def render_before_header
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def render_after_header
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def render_before_breadcrumbs
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def render_after_breadcrumbs
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def render_before_page_header
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def render_after_page_header
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def render_before_toolbar
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def render_after_toolbar
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def render_before_content
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def render_after_content
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def render_before_footer
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def render_after_footer
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Page
|
|
6
|
+
class Edit < Base
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def page_title
|
|
10
|
+
current_definition.edit_page_title || super || "Edit"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def page_description
|
|
14
|
+
current_definition.edit_page_description || super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render_default_content
|
|
18
|
+
render "resource_form"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Page
|
|
6
|
+
class Index < Base
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def page_title
|
|
10
|
+
super || current_definition.index_page_title || resource_name_plural(resource_class)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def page_description
|
|
14
|
+
super || current_definition.index_page_description
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def page_actions
|
|
18
|
+
super || current_definition.defined_actions.values.select { |a| a.resource_action? && a.permitted_by?(current_policy) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def render_default_content
|
|
22
|
+
render "resource_table"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Page
|
|
6
|
+
class New < Base
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def page_title
|
|
10
|
+
current_definition.new_page_title || super || "New"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def page_description
|
|
14
|
+
current_definition.new_page_description || super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render_default_content
|
|
18
|
+
render "resource_form"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Page
|
|
6
|
+
class Show < Base
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def page_title
|
|
10
|
+
current_definition.show_page_title || super || display_name_of(resource_record)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def page_description
|
|
14
|
+
current_definition.show_page_description || super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def page_actions
|
|
18
|
+
super || current_definition.defined_actions.values.select { |a| a.record_action? && a.permitted_by?(current_policy) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def render_default_content
|
|
22
|
+
render "resource_details"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Plutonium
|
|
2
|
+
module UI
|
|
3
|
+
class PageHeader < Plutonium::UI::Component::Base
|
|
4
|
+
def initialize(title:, description:, actions:)
|
|
5
|
+
@title = title
|
|
6
|
+
@description = description
|
|
7
|
+
@actions = actions || []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template
|
|
11
|
+
div(class: "sm:flex sm:space-y-0 sm:space-x-4 sm:flex-row items-center justify-between space-y-3 mb-6") {
|
|
12
|
+
div {
|
|
13
|
+
phlexi_render(@title) {
|
|
14
|
+
render_title @title
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
phlexi_render(@description) {
|
|
18
|
+
render_description @description
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
div(class: "flex flex-row space-x-2") {
|
|
22
|
+
render_actions
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def render_title(title)
|
|
30
|
+
h2(class: "mb-2 text-3xl font-extrabold leading-none tracking-tight text-gray-900 md:text-4xl dark:text-white") {
|
|
31
|
+
title
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def render_description(description)
|
|
36
|
+
p(class: "text-gray-500 dark:text-gray-400") {
|
|
37
|
+
description
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def render_actions
|
|
42
|
+
@actions.each do |action|
|
|
43
|
+
url = resource_url_for(resource_record || resource_class, *action.route_options.url_args, **action.route_options.url_options)
|
|
44
|
+
ActionButton(action, url:)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
module Components
|
|
7
|
+
class PagyInfo < Plutonium::UI::Component::Base
|
|
8
|
+
include Pagy::Frontend
|
|
9
|
+
|
|
10
|
+
def initialize(pagy, per_page_options: [5, 10, 20, 50, 100])
|
|
11
|
+
@pagy = pagy
|
|
12
|
+
@per_page_options = (per_page_options + [@pagy.limit]).uniq.sort
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def view_template
|
|
16
|
+
div(class: "flex flex-col md:flex-row justify-between items-center text-sm text-gray-500 dark:text-gray-400") do
|
|
17
|
+
results_info
|
|
18
|
+
per_page_selector
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def results_info
|
|
25
|
+
div do
|
|
26
|
+
plain "Showing "
|
|
27
|
+
b { @pagy.from.to_s }
|
|
28
|
+
plain " to "
|
|
29
|
+
b { @pagy.to.to_s }
|
|
30
|
+
plain " of "
|
|
31
|
+
b { @pagy.count }
|
|
32
|
+
plain " results"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def per_page_selector
|
|
37
|
+
original_attributes = Phlex::HTML::EVENT_ATTRIBUTES
|
|
38
|
+
temp_attributes = Phlex::HTML::EVENT_ATTRIBUTES.dup
|
|
39
|
+
temp_attributes.delete("onchange")
|
|
40
|
+
Phlex::HTML.const_set(:EVENT_ATTRIBUTES, temp_attributes)
|
|
41
|
+
|
|
42
|
+
div(class: "flex items-center space-x-2 mt-2 md:mt-0") do
|
|
43
|
+
label(for: "perPage", class: "mr-2") { "Per page" }
|
|
44
|
+
select(id: "perPage", name: "items", class: select_classes, onchange: "window.location.href=this.value") do
|
|
45
|
+
@per_page_options.each do |option|
|
|
46
|
+
option(value: page_url(option), selected: option == @pagy.limit) { option.to_s }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
ensure
|
|
51
|
+
# TODO: remove this once Phlex adds support for SafeValues
|
|
52
|
+
Phlex::HTML.const_set(:EVENT_ATTRIBUTES, original_attributes)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def select_classes
|
|
56
|
+
"bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def page_url(limit)
|
|
60
|
+
original_limit = @pagy.vars[:limit]
|
|
61
|
+
@pagy.vars[:limit] = limit
|
|
62
|
+
pagy_url_for(@pagy, @pagy.page)
|
|
63
|
+
ensure
|
|
64
|
+
@pagy.vars[:limit] = original_limit
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
module Components
|
|
7
|
+
class PagyPageInfo < Plutonium::UI::Component::Base
|
|
8
|
+
include Pagy::Frontend
|
|
9
|
+
|
|
10
|
+
def initialize(pagy, per_page_options: [5, 10, 20, 50, 100])
|
|
11
|
+
@pagy = pagy
|
|
12
|
+
@per_page_options = (per_page_options + [@pagy.limit]).uniq.sort
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def view_template
|
|
16
|
+
div(class: "flex flex-col md:flex-row justify-between items-center text-sm text-gray-500 dark:text-gray-400") do
|
|
17
|
+
results_info
|
|
18
|
+
per_page_selector
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def results_info
|
|
25
|
+
div do
|
|
26
|
+
plain "Showing "
|
|
27
|
+
b { @pagy.from.to_s }
|
|
28
|
+
plain " to "
|
|
29
|
+
b { @pagy.to.to_s }
|
|
30
|
+
plain " of "
|
|
31
|
+
b { @pagy.count }
|
|
32
|
+
plain " results"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def per_page_selector
|
|
37
|
+
original_attributes = Phlex::HTML::EVENT_ATTRIBUTES
|
|
38
|
+
temp_attributes = Phlex::HTML::EVENT_ATTRIBUTES.dup
|
|
39
|
+
temp_attributes.delete("onchange")
|
|
40
|
+
Phlex::HTML.const_set(:EVENT_ATTRIBUTES, temp_attributes)
|
|
41
|
+
|
|
42
|
+
div(class: "flex items-center space-x-2 mt-2 md:mt-0") do
|
|
43
|
+
label(for: "perPage", class: "mr-2") { "Per page" }
|
|
44
|
+
select(id: "perPage", name: "items", class: select_classes, onchange: "window.location.href=this.value") do
|
|
45
|
+
@per_page_options.each do |option|
|
|
46
|
+
option(value: page_url(option), selected: option == @pagy.limit) { option.to_s }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
ensure
|
|
51
|
+
# TODO: remove this once Phlex adds support for SafeValues
|
|
52
|
+
Phlex::HTML.const_set(:EVENT_ATTRIBUTES, original_attributes)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def select_classes
|
|
56
|
+
"bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def page_url(limit)
|
|
60
|
+
original_limit = @pagy.vars[:limit]
|
|
61
|
+
@pagy.vars[:limit] = limit
|
|
62
|
+
pagy_url_for(@pagy, @pagy.page)
|
|
63
|
+
ensure
|
|
64
|
+
@pagy.vars[:limit] = original_limit
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plutonium
|
|
4
|
+
module UI
|
|
5
|
+
module Table
|
|
6
|
+
module Components
|
|
7
|
+
class PagyPagination < Plutonium::UI::Component::Base
|
|
8
|
+
include Pagy::Frontend
|
|
9
|
+
|
|
10
|
+
def initialize(pagy)
|
|
11
|
+
@pagy = pagy
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def view_template
|
|
15
|
+
nav(aria_label: "Page navigation", class: "flex justify-center mt-4") do
|
|
16
|
+
ul(class: "inline-flex -space-x-px text-sm") do
|
|
17
|
+
prev_link
|
|
18
|
+
page_links
|
|
19
|
+
next_link
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def prev_link
|
|
27
|
+
li do
|
|
28
|
+
if @pagy.prev
|
|
29
|
+
a(href: page_url(@pagy.prev), class: link_classes(true)) {
|
|
30
|
+
render Phlex::TablerIcons::ChevronLeft.new
|
|
31
|
+
}
|
|
32
|
+
else
|
|
33
|
+
a(href: "#", class: disabled_link_classes(true), aria_disabled: "true") {
|
|
34
|
+
render Phlex::TablerIcons::ChevronLeft.new
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def next_link
|
|
41
|
+
li do
|
|
42
|
+
if @pagy.next
|
|
43
|
+
a(href: page_url(@pagy.next), class: link_classes(false, true)) {
|
|
44
|
+
render Phlex::TablerIcons::ChevronRight.new
|
|
45
|
+
}
|
|
46
|
+
else
|
|
47
|
+
a(href: "#", class: disabled_link_classes(false, true), aria_disabled: "true") {
|
|
48
|
+
render Phlex::TablerIcons::ChevronRight.new
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def page_links
|
|
55
|
+
@pagy.series.each do |item|
|
|
56
|
+
li do
|
|
57
|
+
case item
|
|
58
|
+
when Integer
|
|
59
|
+
page_link(item)
|
|
60
|
+
when String
|
|
61
|
+
current_page_link(item)
|
|
62
|
+
when :gap
|
|
63
|
+
gap_link
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def page_link(page)
|
|
70
|
+
a(href: page_url(page), class: link_classes) { page.to_s }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def current_page_link(page)
|
|
74
|
+
a(href: "#", class: current_link_classes, aria_current: "page") { page.to_s }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def gap_link
|
|
78
|
+
a(href: "#", class: link_classes, aria_disabled: "true") { "..." }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def link_classes(first = false, last = false)
|
|
82
|
+
classes = ["flex", "items-center", "justify-center", "px-3", "h-8", "leading-tight", "text-gray-500", "bg-white", "border", "border-gray-300", "hover:bg-gray-100", "hover:text-gray-700", "dark:bg-gray-800", "dark:border-gray-700", "dark:text-gray-400", "dark:hover:bg-gray-700", "dark:hover:text-white"]
|
|
83
|
+
classes << "rounded-s-lg" if first
|
|
84
|
+
classes << "rounded-e-lg" if last
|
|
85
|
+
classes.join(" ")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def current_link_classes
|
|
89
|
+
"flex items-center justify-center px-3 h-8 text-blue-600 border border-gray-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def disabled_link_classes(first = false, last = false)
|
|
93
|
+
classes = link_classes(first, last).split
|
|
94
|
+
classes << "opacity-50" << "cursor-not-allowed"
|
|
95
|
+
classes.join(" ")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def page_url(page)
|
|
99
|
+
pagy_url_for(@pagy, page)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|