plutonium 0.64.0 → 0.66.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/.claude/skills/plutonium/SKILL.md +44 -41
- data/.claude/skills/plutonium-app/SKILL.md +115 -59
- data/.claude/skills/plutonium-async-interactions/SKILL.md +19 -19
- data/.claude/skills/plutonium-auth/SKILL.md +119 -53
- data/.claude/skills/plutonium-behavior/SKILL.md +110 -78
- data/.claude/skills/plutonium-dashboard/SKILL.md +168 -0
- data/.claude/skills/plutonium-kanban/SKILL.md +81 -49
- data/.claude/skills/plutonium-resource/SKILL.md +236 -145
- data/.claude/skills/plutonium-tenancy/SKILL.md +104 -55
- data/.claude/skills/plutonium-testing/SKILL.md +130 -33
- data/.claude/skills/plutonium-ui/SKILL.md +171 -95
- data/.claude/skills/plutonium-wizard/SKILL.md +93 -82
- data/CHANGELOG.md +80 -0
- data/CLAUDE.md +282 -210
- data/README.md +9 -9
- data/SECURITY.md +1 -1
- data/app/assets/plutonium-charts.js +20604 -0
- data/app/assets/plutonium-charts.js.map +7 -0
- data/app/assets/plutonium-charts.min.js +41 -0
- data/app/assets/plutonium-charts.min.js.map +7 -0
- data/app/assets/plutonium.css +1 -1
- data/app/assets/plutonium.js +794 -629
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +48 -48
- data/app/assets/plutonium.min.js.map +4 -4
- data/app/views/plutonium/_flash_alerts.html.erb +2 -2
- data/app/views/plutonium/_resource_header.html.erb +2 -2
- data/app/views/plutonium/_resource_sidebar.html.erb +11 -2
- data/app/views/plutonium/_toast.html.erb +2 -2
- data/app/views/rodauth/_login_form.html.erb +1 -1
- data/app/views/rodauth/_password_visibility.html.erb +1 -1
- data/app/views/rodauth/add_recovery_codes.html.erb +2 -2
- data/app/views/rodauth/change_login.html.erb +2 -2
- data/app/views/rodauth/create_account.html.erb +4 -4
- data/app/views/rodauth/reset_password_request.html.erb +1 -1
- data/app/views/rodauth/verify_account_resend.html.erb +1 -1
- data/app/views/rodauth/webauthn_remove.html.erb +1 -1
- data/config/brakeman.ignore +4 -4
- data/config/initializers/rabl.rb +0 -40
- data/config/locales/en/api_client.yml +22 -0
- data/config/locales/en/async.yml +34 -0
- data/config/locales/en/dashboard.yml +25 -0
- data/config/locales/en/invites.yml +37 -0
- data/config/locales/en/js.yml +40 -0
- data/config/locales/en/kanban.yml +28 -0
- data/config/locales/en/plutonium.yml +26 -0
- data/config/locales/en/positioning.yml +14 -0
- data/config/locales/en/profile.yml +29 -0
- data/config/locales/en/resource.yml +60 -0
- data/config/locales/en/ui.yml +93 -0
- data/config/locales/en/wizard.yml +46 -0
- data/docs/.vitepress/config.ts +34 -1
- data/docs/.vitepress/sync-skills.mjs +6 -3
- data/docs/.vitepress/theme/components/HomeHero.vue +1 -1
- data/docs/.vitepress/theme/components/HomeInTheBox.vue +14 -0
- data/docs/.vitepress/theme/custom.css +34 -377
- data/docs/blog/introducing-plutonium-dashboards.md +174 -0
- data/docs/blog/introducing-plutonium-i18n.md +90 -0
- data/docs/blog/introducing-plutonium.md +4 -5
- data/docs/blog/whats-new-async-kanban-wizards.md +1 -1
- data/docs/getting-started/installation.md +5 -5
- data/docs/getting-started/tutorial/02-first-resource.md +3 -3
- data/docs/getting-started/tutorial/03-authentication.md +7 -7
- data/docs/getting-started/tutorial/04-authorization.md +21 -4
- data/docs/getting-started/tutorial/05-custom-actions.md +2 -2
- data/docs/getting-started/tutorial/06-nested-resources.md +5 -2
- data/docs/getting-started/tutorial/07-author-portal.md +2 -2
- data/docs/getting-started/tutorial/08-customizing-ui.md +45 -30
- data/docs/getting-started/tutorial/index.md +1 -1
- data/docs/guides/adding-resources.md +10 -7
- data/docs/guides/authentication.md +25 -25
- data/docs/guides/authorization.md +24 -24
- data/docs/guides/creating-packages.md +17 -17
- data/docs/guides/custom-actions.md +32 -32
- data/docs/guides/customizing-ui.md +29 -26
- data/docs/guides/dashboards.md +300 -0
- data/docs/guides/index.md +4 -3
- data/docs/guides/kanban.md +56 -56
- data/docs/guides/multi-tenancy.md +35 -22
- data/docs/guides/nested-resources.md +21 -21
- data/docs/guides/performance.md +3 -3
- data/docs/guides/search-filtering.md +13 -13
- data/docs/guides/testing.md +16 -12
- data/docs/guides/theming.md +32 -17
- data/docs/guides/troubleshooting.md +2 -2
- data/docs/guides/user-invites.md +17 -17
- data/docs/guides/user-profile.md +51 -24
- data/docs/guides/wizards.md +55 -55
- data/docs/public/images/blog/dashboards-card-error.png +0 -0
- data/docs/public/images/blog/dashboards-loading.png +0 -0
- data/docs/public/images/blog/dashboards-overview.png +0 -0
- data/docs/public/images/blog/dashboards-sidebar.png +0 -0
- data/docs/public/images/blog/i18n-es-admin.png +0 -0
- data/docs/public/images/guides/dashboard-card-error.png +0 -0
- data/docs/public/images/guides/dashboard-loading.png +0 -0
- data/docs/public/images/guides/dashboard-overview.png +0 -0
- data/docs/public/images/guides/dashboard-sidebar.png +0 -0
- data/docs/reference/app/generators.md +24 -24
- data/docs/reference/app/index.md +15 -18
- data/docs/reference/app/packages.md +8 -8
- data/docs/reference/app/portals.md +77 -29
- data/docs/reference/auth/accounts.md +15 -15
- data/docs/reference/auth/index.md +12 -12
- data/docs/reference/auth/profile.md +67 -29
- data/docs/reference/behavior/async-interactions.md +24 -24
- data/docs/reference/behavior/controllers.md +28 -28
- data/docs/reference/behavior/index.md +5 -5
- data/docs/reference/behavior/interactions.md +44 -44
- data/docs/reference/behavior/policies.md +48 -28
- data/docs/reference/configuration.md +88 -31
- data/docs/reference/dashboard/dsl.md +123 -0
- data/docs/reference/dashboard/index.md +35 -0
- data/docs/reference/dashboard/registration.md +76 -0
- data/docs/reference/generators/lite.md +7 -7
- data/docs/reference/i18n.md +262 -0
- data/docs/reference/index.md +11 -2
- data/docs/reference/kanban/authorization.md +9 -9
- data/docs/reference/kanban/dsl.md +33 -33
- data/docs/reference/kanban/index.md +1 -1
- data/docs/reference/kanban/positioning.md +18 -16
- data/docs/reference/resource/actions.md +51 -51
- data/docs/reference/resource/definition.md +166 -88
- data/docs/reference/resource/export.md +11 -7
- data/docs/reference/resource/index.md +16 -14
- data/docs/reference/resource/model.md +24 -24
- data/docs/reference/{positioning.md → resource/positioning.md} +78 -75
- data/docs/reference/resource/query.md +14 -12
- data/docs/reference/tenancy/entity-scoping.md +65 -35
- data/docs/reference/tenancy/index.md +11 -11
- data/docs/reference/tenancy/invites.md +20 -20
- data/docs/reference/tenancy/nested-resources.md +13 -13
- data/docs/reference/testing/index.md +116 -22
- data/docs/reference/ui/assets.md +65 -25
- data/docs/reference/ui/components.md +20 -20
- data/docs/reference/ui/displays.md +19 -22
- data/docs/reference/ui/forms.md +35 -35
- data/docs/reference/ui/index.md +17 -15
- data/docs/reference/ui/layouts.md +21 -21
- data/docs/reference/ui/pages.md +22 -22
- data/docs/reference/ui/tables.md +7 -7
- data/docs/reference/wizard/anchoring-resume.md +33 -32
- data/docs/reference/wizard/dsl.md +45 -45
- data/docs/reference/wizard/index.md +6 -6
- data/docs/reference/wizard/one-time.md +18 -18
- data/docs/reference/wizard/registration-launch.md +32 -32
- data/docs/reference/wizard/storage-config.md +23 -23
- data/esbuild.config.js +5 -2
- data/gemfiles/rails_7.gemfile.lock +2 -2
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/active_model/validations/array_validator.rb +1 -1
- data/lib/active_model/validations/attached_validator.rb +1 -1
- data/lib/active_model/validations/url_validator.rb +2 -2
- data/lib/generators/pu/core/assets/assets_generator.rb +36 -21
- data/lib/generators/pu/core/assets/templates/postcss.config.js +1 -1
- data/lib/generators/pu/core/update/update_generator.rb +3 -2
- data/lib/generators/pu/dashboard/dashboard_generator.rb +96 -0
- data/lib/generators/pu/dashboard/templates/dashboard.rb.tt +25 -0
- data/lib/generators/pu/docker/install/install_generator.rb +58 -0
- data/lib/generators/pu/docker/install/templates/Dockerfile.dev.tt +18 -3
- data/lib/generators/pu/docker/install/templates/Dockerfile.tt +20 -5
- data/lib/generators/pu/docker/install/templates/{docker-compose.yml → docker-compose.yml.tt} +1 -1
- data/lib/generators/pu/gem/dotenv/dotenv_generator.rb +1 -1
- data/lib/generators/pu/invites/invitable_generator.rb +18 -1
- data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +0 -95
- data/lib/generators/pu/lib/plutonium_generators/concerns/js_package_manager.rb +146 -0
- data/lib/generators/pu/lib/plutonium_generators/generator.rb +1 -17
- data/lib/generators/pu/pkg/package/package_generator.rb +1 -0
- data/lib/generators/pu/pkg/package/templates/config/locales/en.yml.tt +28 -0
- data/lib/generators/pu/pkg/portal/portal_generator.rb +1 -0
- data/lib/generators/pu/pkg/portal/templates/config/locales/en.yml.tt +30 -0
- data/lib/generators/pu/profile/conn_generator.rb +6 -0
- data/lib/generators/pu/res/scaffold/scaffold_generator.rb +0 -8
- data/lib/generators/pu/rodauth/concerns/feature_selector.rb +0 -18
- data/lib/plutonium/action/base.rb +27 -3
- data/lib/plutonium/action/interactive.rb +17 -4
- data/lib/plutonium/api_client/concerns/create_api_client.rb +12 -11
- data/lib/plutonium/api_client/concerns/disable_api_client.rb +3 -3
- data/lib/plutonium/auth/sequel_adapter.rb +1 -1
- data/lib/plutonium/configuration.rb +5 -0
- data/lib/plutonium/core/controller.rb +25 -1
- data/lib/plutonium/core/controllers/authorizable.rb +1 -1
- data/lib/plutonium/dashboard/base.rb +114 -0
- data/lib/plutonium/dashboard/card.rb +200 -0
- data/lib/plutonium/dashboard/controller.rb +101 -0
- data/lib/plutonium/dashboard/dsl.rb +104 -0
- data/lib/plutonium/dashboard/register.rb +40 -0
- data/lib/plutonium/dashboard/route_resolution.rb +30 -0
- data/lib/plutonium/dashboard.rb +42 -0
- data/lib/plutonium/definition/actions.rb +6 -1
- data/lib/plutonium/definition/base.rb +41 -3
- data/lib/plutonium/definition/index_views.rb +1 -1
- data/lib/plutonium/definition/positioning.rb +1 -1
- data/lib/plutonium/definition/presentable.rb +2 -2
- data/lib/plutonium/helpers/assets_helper.rb +15 -2
- data/lib/plutonium/helpers/display_helper.rb +10 -2
- data/lib/plutonium/interaction/async/context.rb +6 -8
- data/lib/plutonium/interaction/async/executor.rb +6 -7
- data/lib/plutonium/interaction/async/run.rb +2 -2
- data/lib/plutonium/interaction/async/run_definition.rb +1 -1
- data/lib/plutonium/interaction/base.rb +2 -0
- data/lib/plutonium/interaction/concerns/dispatchable.rb +15 -3
- data/lib/plutonium/invites/concerns/cancel_invite.rb +3 -3
- data/lib/plutonium/invites/concerns/invite_token.rb +25 -7
- data/lib/plutonium/invites/concerns/invite_user.rb +10 -5
- data/lib/plutonium/invites/concerns/resend_invite.rb +4 -4
- data/lib/plutonium/invites/controller.rb +11 -11
- data/lib/plutonium/kanban/column.rb +13 -3
- data/lib/plutonium/kanban/dsl.rb +7 -4
- data/lib/plutonium/models/has_cents.rb +1 -1
- data/lib/plutonium/profile/security_section.rb +10 -18
- data/lib/plutonium/query/filter.rb +10 -1
- data/lib/plutonium/query/filters/association.rb +27 -2
- data/lib/plutonium/query/filters/boolean.rb +4 -4
- data/lib/plutonium/query/filters/date.rb +4 -17
- data/lib/plutonium/query/filters/date_range.rb +2 -2
- data/lib/plutonium/query/filters/select.rb +10 -1
- data/lib/plutonium/query/filters/text.rb +9 -12
- data/lib/plutonium/railtie.rb +17 -0
- data/lib/plutonium/resource/controller.rb +10 -5
- data/lib/plutonium/resource/controllers/crud_actions.rb +17 -20
- data/lib/plutonium/resource/controllers/export_csv.rb +19 -9
- data/lib/plutonium/resource/controllers/kanban_actions.rb +16 -16
- data/lib/plutonium/resource/controllers/position_actions.rb +5 -5
- data/lib/plutonium/resource/controllers/typeahead.rb +24 -1
- data/lib/plutonium/resource/query_object.rb +30 -3
- data/lib/plutonium/resource/record/associated_with.rb +23 -2
- data/lib/plutonium/routing/dashboard_registration.rb +137 -0
- data/lib/plutonium/routing/resource_registration.rb +5 -0
- data/lib/plutonium/routing/route_set_extensions.rb +2 -1
- data/lib/plutonium/translation.rb +227 -0
- data/lib/plutonium/ui/actions_dropdown.rb +2 -2
- data/lib/plutonium/ui/breadcrumbs.rb +3 -3
- data/lib/plutonium/ui/color_mode_selector.rb +1 -1
- data/lib/plutonium/ui/component/behaviour.rb +46 -0
- data/lib/plutonium/ui/component/methods.rb +4 -0
- data/lib/plutonium/ui/dashboard/board.rb +80 -0
- data/lib/plutonium/ui/dashboard/card.rb +127 -0
- data/lib/plutonium/ui/dashboard/chart.rb +43 -0
- data/lib/plutonium/ui/dashboard/custom.rb +32 -0
- data/lib/plutonium/ui/dashboard/frame.rb +25 -0
- data/lib/plutonium/ui/dashboard/metric.rb +137 -0
- data/lib/plutonium/ui/dashboard/skeleton.rb +40 -0
- data/lib/plutonium/ui/display/components/attachment.rb +1 -1
- data/lib/plutonium/ui/display/components/badge.rb +7 -1
- data/lib/plutonium/ui/display/components/boolean.rb +2 -2
- data/lib/plutonium/ui/display/resource.rb +23 -16
- data/lib/plutonium/ui/export_button.rb +3 -3
- data/lib/plutonium/ui/form/components/key_value_store.rb +5 -5
- data/lib/plutonium/ui/form/components/password.rb +2 -2
- data/lib/plutonium/ui/form/components/resource_select.rb +27 -0
- data/lib/plutonium/ui/form/components/secure_association.rb +2 -0
- data/lib/plutonium/ui/form/components/uppy.rb +11 -3
- data/lib/plutonium/ui/form/concerns/renders_nested_resource_fields.rb +1 -1
- data/lib/plutonium/ui/form/concerns/renders_repeater_row_controls.rb +5 -4
- data/lib/plutonium/ui/form/concerns/renders_structured_inputs.rb +1 -1
- data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +7 -1
- data/lib/plutonium/ui/form/query.rb +8 -8
- data/lib/plutonium/ui/form/resource.rb +54 -26
- data/lib/plutonium/ui/frame_navigator_panel.rb +4 -4
- data/lib/plutonium/ui/grid/card.rb +3 -3
- data/lib/plutonium/ui/grid/resource.rb +3 -3
- data/lib/plutonium/ui/interaction/async/run_progress.rb +6 -6
- data/lib/plutonium/ui/interaction/async/running_banner.rb +2 -2
- data/lib/plutonium/ui/kanban/column.rb +6 -6
- data/lib/plutonium/ui/layout/base.rb +19 -1
- data/lib/plutonium/ui/layout/header.rb +1 -1
- data/lib/plutonium/ui/layout/icon_rail.rb +4 -4
- data/lib/plutonium/ui/layout/rodauth_layout.rb +1 -1
- data/lib/plutonium/ui/layout/sidebar.rb +1 -1
- data/lib/plutonium/ui/layout/topbar.rb +2 -2
- data/lib/plutonium/ui/modal/base.rb +4 -4
- data/lib/plutonium/ui/nav_grid_menu.rb +1 -1
- data/lib/plutonium/ui/nav_user.rb +2 -2
- data/lib/plutonium/ui/page/base.rb +10 -2
- data/lib/plutonium/ui/page/dashboard.rb +54 -0
- data/lib/plutonium/ui/page/edit.rb +3 -3
- data/lib/plutonium/ui/page/interactive_action.rb +2 -2
- data/lib/plutonium/ui/page/new.rb +3 -3
- data/lib/plutonium/ui/page/show.rb +2 -2
- data/lib/plutonium/ui/page/wizard.rb +22 -16
- data/lib/plutonium/ui/page/wizard_chooser.rb +10 -10
- data/lib/plutonium/ui/page/wizard_completed.rb +2 -2
- data/lib/plutonium/ui/skeleton_table.rb +1 -1
- data/lib/plutonium/ui/table/base.rb +2 -2
- data/lib/plutonium/ui/table/components/attachment.rb +1 -1
- data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +19 -3
- data/lib/plutonium/ui/table/components/drag_handle.rb +3 -3
- data/lib/plutonium/ui/table/components/filter_form.rb +11 -10
- data/lib/plutonium/ui/table/components/filter_pills.rb +4 -4
- data/lib/plutonium/ui/table/components/pagy_info.rb +61 -17
- data/lib/plutonium/ui/table/components/pagy_pagination.rb +9 -5
- data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +1 -1
- data/lib/plutonium/ui/table/components/scopes_bar.rb +6 -2
- data/lib/plutonium/ui/table/components/scopes_pills.rb +3 -3
- data/lib/plutonium/ui/table/components/selection_column.rb +1 -1
- data/lib/plutonium/ui/table/components/toolbar.rb +2 -2
- data/lib/plutonium/ui/table/components/view_switcher.rb +12 -8
- data/lib/plutonium/ui/table/resource.rb +53 -17
- data/lib/plutonium/ui/wizard/review.rb +7 -7
- data/lib/plutonium/ui/wizard/stepper.rb +1 -1
- data/lib/plutonium/ui/wizard/summary_display.rb +6 -0
- data/lib/plutonium/version.rb +1 -1
- data/lib/plutonium/wizard/base.rb +2 -0
- data/lib/plutonium/wizard/driving.rb +8 -2
- data/lib/plutonium/wizard/dsl.rb +4 -2
- data/lib/plutonium/wizard/field_importer.rb +1 -8
- data/lib/plutonium/wizard/review_step.rb +8 -1
- data/lib/plutonium/wizard/step.rb +14 -3
- data/package.json +4 -2
- data/plutonium.gemspec +4 -1
- data/postcss-gem-import.cjs +34 -0
- data/postcss-gem-import.js +3 -28
- data/src/css/components.css +101 -10
- data/src/css/slim_select.css +0 -38
- data/src/css/tokens.css +24 -0
- data/src/js/controllers/attachment_input_controller.js +15 -6
- data/src/js/controllers/chart_controller.js +162 -0
- data/src/js/controllers/clipboard_controller.js +3 -2
- data/src/js/controllers/dirty_form_guard_controller.js +4 -3
- data/src/js/controllers/easymde_controller.js +3 -0
- data/src/js/controllers/filter_panel_controller.js +15 -6
- data/src/js/controllers/flatpickr_controller.js +8 -0
- data/src/js/controllers/frame_refresh_controller.js +59 -0
- data/src/js/controllers/intl_tel_input_controller.js +5 -0
- data/src/js/controllers/register_controllers.js +4 -0
- data/src/js/controllers/slim_select_controller.js +79 -176
- data/src/js/core.js +9 -1
- data/src/js/i18n.js +69 -0
- data/src/js/plutonium-charts.js +15 -0
- data/src/js/turbo/turbo_confirm.js +5 -3
- metadata +64 -16
- data/.yarnrc.yml +0 -8
- data/config/initializers/hotwire_turbo_monkey_patches.rb +0 -12
- data/lib/generators/pu/field/input/input_generator.rb +0 -32
- data/lib/generators/pu/field/input/templates/input.rb.tt +0 -15
- data/lib/generators/pu/lib/plutonium_generators/concerns/config.rb +0 -39
- data/lib/generators/pu/lib/plutonium_generators/concerns/serializer.rb +0 -39
- data/lib/generators/pu/lib/plutonium_generators/installer.rb +0 -205
- data/lib/generators/pu/res/scaffold/templates/presenter.rb.tt +0 -13
- data/lib/generators/pu/res/scaffold/templates/query_object.rb.tt +0 -17
- data/public/plutonium-assets/application.js +0 -31419
- data/public/plutonium-assets/plutonium.ico +0 -0
- data/yarn.lock +0 -6858
|
@@ -69,10 +69,15 @@ module Plutonium
|
|
|
69
69
|
::Invites::UserInvite
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
# Override to specify the membership model class
|
|
72
|
+
# Override to specify the membership model class. There is no default
|
|
73
|
+
# because the membership join model is app-specific (e.g. OrganizationUser).
|
|
74
|
+
# Omitting the override raises NotImplementedError so the failure is
|
|
75
|
+
# actionable instead of a confusing NameError on a non-existent constant.
|
|
73
76
|
# @return [Class]
|
|
74
77
|
def membership_class
|
|
75
|
-
|
|
78
|
+
raise NotImplementedError,
|
|
79
|
+
"#{self.class}#membership_class must return the membership model class. " \
|
|
80
|
+
"Specify --membership-model when generating, or override this method."
|
|
76
81
|
end
|
|
77
82
|
|
|
78
83
|
# Override to specify the user model class
|
|
@@ -109,7 +114,7 @@ module Plutonium
|
|
|
109
114
|
|
|
110
115
|
# Override to customize success message
|
|
111
116
|
def success_message
|
|
112
|
-
"
|
|
117
|
+
I18n.t("plutonium.invites.invite_user.sent", email: email)
|
|
113
118
|
end
|
|
114
119
|
|
|
115
120
|
# Override to specify the entity association name on membership
|
|
@@ -141,7 +146,7 @@ module Plutonium
|
|
|
141
146
|
membership_entity_attribute => entity,
|
|
142
147
|
user_association => existing_user
|
|
143
148
|
)
|
|
144
|
-
errors.add(:email,
|
|
149
|
+
errors.add(:email, :already_a_member) if membership
|
|
145
150
|
end
|
|
146
151
|
|
|
147
152
|
def no_pending_invitation
|
|
@@ -152,7 +157,7 @@ module Plutonium
|
|
|
152
157
|
:email => email,
|
|
153
158
|
:state => :pending
|
|
154
159
|
)
|
|
155
|
-
errors.add(:email,
|
|
160
|
+
errors.add(:email, :already_has_pending_invitation) if pending
|
|
156
161
|
end
|
|
157
162
|
|
|
158
163
|
# Override if user association has a different name
|
|
@@ -26,14 +26,14 @@ module Plutonium
|
|
|
26
26
|
extend ActiveSupport::Concern
|
|
27
27
|
|
|
28
28
|
included do
|
|
29
|
-
presents label: "
|
|
29
|
+
presents label: t("plutonium.invites.resend_invite.label"), icon: Phlex::TablerIcons::MailForward
|
|
30
30
|
|
|
31
31
|
attribute :resource
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def execute
|
|
35
35
|
unless resource.pending?
|
|
36
|
-
return failed("
|
|
36
|
+
return failed(I18n.t("plutonium.invites.resend_invite.not_pending"))
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
resource.update!(expires_at: new_expiry)
|
|
@@ -41,7 +41,7 @@ module Plutonium
|
|
|
41
41
|
|
|
42
42
|
succeed(resource).with_message(success_message)
|
|
43
43
|
rescue => error
|
|
44
|
-
failed("
|
|
44
|
+
failed(I18n.t("plutonium.invites.resend_invite.failed", error: error.message))
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
private
|
|
@@ -58,7 +58,7 @@ module Plutonium
|
|
|
58
58
|
|
|
59
59
|
# Override to customize success message
|
|
60
60
|
def success_message
|
|
61
|
-
"
|
|
61
|
+
I18n.t("plutonium.invites.resend_invite.resent", email: resource.email)
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
64
|
end
|
|
@@ -57,7 +57,7 @@ module Plutonium
|
|
|
57
57
|
@invite.validate_email_constraints!(current_user.email)
|
|
58
58
|
render :show
|
|
59
59
|
rescue ActiveRecord::RecordInvalid => e
|
|
60
|
-
@error_title = "
|
|
60
|
+
@error_title = t("plutonium.invites.controller.email_validation_error")
|
|
61
61
|
@error_message = e.record.errors.full_messages.join(", ")
|
|
62
62
|
render :error, status: :forbidden
|
|
63
63
|
end
|
|
@@ -74,7 +74,7 @@ module Plutonium
|
|
|
74
74
|
|
|
75
75
|
unless current_user
|
|
76
76
|
redirect_to invitation_path_for(params[:token]),
|
|
77
|
-
alert: "
|
|
77
|
+
alert: t("plutonium.invites.controller.sign_in_to_accept")
|
|
78
78
|
return
|
|
79
79
|
end
|
|
80
80
|
|
|
@@ -82,9 +82,9 @@ module Plutonium
|
|
|
82
82
|
cookies.delete(:pending_invitation)
|
|
83
83
|
|
|
84
84
|
redirect_to after_accept_path,
|
|
85
|
-
notice: "
|
|
85
|
+
notice: t("plutonium.invites.controller.accepted", entity: @invite.entity.to_label)
|
|
86
86
|
rescue ActiveRecord::RecordInvalid => e
|
|
87
|
-
@error_title = "
|
|
87
|
+
@error_title = t("plutonium.invites.controller.acceptance_error")
|
|
88
88
|
@error_message = e.record.errors.full_messages.join(", ")
|
|
89
89
|
render :error, status: :forbidden
|
|
90
90
|
end
|
|
@@ -112,8 +112,8 @@ module Plutonium
|
|
|
112
112
|
invite = invite_class.find_for_acceptance(token)
|
|
113
113
|
|
|
114
114
|
unless invite
|
|
115
|
-
@error_title = "
|
|
116
|
-
@error_message = "
|
|
115
|
+
@error_title = t("plutonium.invites.controller.invalid_or_expired")
|
|
116
|
+
@error_message = t("plutonium.invites.controller.no_longer_valid")
|
|
117
117
|
render :error, status: :not_found
|
|
118
118
|
return nil
|
|
119
119
|
end
|
|
@@ -131,7 +131,7 @@ module Plutonium
|
|
|
131
131
|
password_confirmation = params[:password_confirmation]
|
|
132
132
|
|
|
133
133
|
if password != password_confirmation
|
|
134
|
-
flash.now[:alert] =
|
|
134
|
+
flash.now[:alert] = t("plutonium.invites.controller.passwords_dont_match")
|
|
135
135
|
render :signup
|
|
136
136
|
return
|
|
137
137
|
end
|
|
@@ -140,7 +140,7 @@ module Plutonium
|
|
|
140
140
|
ActiveRecord::Base.transaction do
|
|
141
141
|
existing_user = user_class.find_by(email: email)
|
|
142
142
|
if existing_user
|
|
143
|
-
flash.now[:alert] = "
|
|
143
|
+
flash.now[:alert] = t("plutonium.invites.controller.account_exists")
|
|
144
144
|
render :signup
|
|
145
145
|
return
|
|
146
146
|
end
|
|
@@ -153,7 +153,7 @@ module Plutonium
|
|
|
153
153
|
sign_in_user(user)
|
|
154
154
|
redirect_to after_accept_path
|
|
155
155
|
else
|
|
156
|
-
flash.now[:alert] = "
|
|
156
|
+
flash.now[:alert] = t("plutonium.invites.controller.create_account_failed")
|
|
157
157
|
render :signup
|
|
158
158
|
end
|
|
159
159
|
end
|
|
@@ -161,11 +161,11 @@ module Plutonium
|
|
|
161
161
|
flash.now[:alert] = if e.record.is_a?(invite_class)
|
|
162
162
|
e.record.errors.full_messages.join(", ")
|
|
163
163
|
else
|
|
164
|
-
"
|
|
164
|
+
t("plutonium.invites.controller.create_account_failed_with_error", error: e.record.errors.full_messages.join(", "))
|
|
165
165
|
end
|
|
166
166
|
render :signup
|
|
167
167
|
rescue => e
|
|
168
|
-
flash.now[:alert] = "
|
|
168
|
+
flash.now[:alert] = t("plutonium.invites.controller.create_account_failed_with_error", error: e.message)
|
|
169
169
|
render :signup
|
|
170
170
|
end
|
|
171
171
|
end
|
|
@@ -12,10 +12,19 @@ module Plutonium
|
|
|
12
12
|
lost: {color: :red, collapsed: true}
|
|
13
13
|
}.freeze
|
|
14
14
|
|
|
15
|
-
attr_reader :key, :
|
|
15
|
+
attr_reader :key, :color, :wip, :scope, :on_enter, :on_exit, :accepts, :actions, :enter_interaction
|
|
16
|
+
|
|
17
|
+
# `label:` if given, else plutonium.kanban_columns.<model>.<key>, else the
|
|
18
|
+
# titleized key. Resolved on every read so it follows the request locale.
|
|
19
|
+
def label
|
|
20
|
+
Plutonium::Translation.resolve(@label) ||
|
|
21
|
+
Plutonium::Translation.label_for(:kanban_column, @resource_class, key) ||
|
|
22
|
+
key.to_s.titleize
|
|
23
|
+
end
|
|
16
24
|
|
|
17
25
|
def initialize(key, label: nil, color: nil, wip: nil, scope: nil, on_enter: nil, on_exit: nil, on_drop: nil,
|
|
18
|
-
collapsed: nil, add: nil, accepts: nil, locked: nil, role: nil, enter_interaction: nil, drop_interaction: nil
|
|
26
|
+
collapsed: nil, add: nil, accepts: nil, locked: nil, role: nil, enter_interaction: nil, drop_interaction: nil,
|
|
27
|
+
resource_class: nil)
|
|
19
28
|
# on_drop:/drop_interaction: were renamed to on_enter:/enter_interaction:.
|
|
20
29
|
# Resolve the deprecated aliases first (dev/test raise; deployed envs warn
|
|
21
30
|
# and map — see resolve_renamed_option) so the rest of initialize only
|
|
@@ -48,7 +57,8 @@ module Plutonium
|
|
|
48
57
|
raise ArgumentError, "kanban column `accepts:` no longer accepts a Proc; use true/false or an Array of source keys, and put record/user conditions in the kanban_move? policy."
|
|
49
58
|
end
|
|
50
59
|
@key = key.to_sym
|
|
51
|
-
@label = label
|
|
60
|
+
@label = label
|
|
61
|
+
@resource_class = resource_class
|
|
52
62
|
@color = color.nil? ? preset[:color] : color
|
|
53
63
|
@wip = wip
|
|
54
64
|
@scope = scope
|
data/lib/plutonium/kanban/dsl.rb
CHANGED
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
module Plutonium
|
|
4
4
|
module Kanban
|
|
5
5
|
class DSL
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
# `resource_class:` lets column labels resolve through the
|
|
7
|
+
# plutonium.kanban_columns.<model>.<key> convention.
|
|
8
|
+
def self.build(resource_class: nil, &block)
|
|
9
|
+
dsl = new(resource_class:)
|
|
8
10
|
dsl.instance_eval(&block) if block
|
|
9
11
|
dsl.to_board
|
|
10
12
|
end
|
|
11
13
|
|
|
12
|
-
def initialize
|
|
14
|
+
def initialize(resource_class: nil)
|
|
15
|
+
@resource_class = resource_class
|
|
13
16
|
@columns = []
|
|
14
17
|
@columns_block = nil
|
|
15
18
|
@card_fields = nil
|
|
@@ -24,7 +27,7 @@ module Plutonium
|
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
def column(key, **opts, &blk)
|
|
27
|
-
col = Column.new(key, **opts)
|
|
30
|
+
col = Column.new(key, resource_class: @resource_class, **opts)
|
|
28
31
|
col.instance_eval(&blk) if blk
|
|
29
32
|
@columns << col
|
|
30
33
|
end
|
|
@@ -4,46 +4,34 @@ module Plutonium
|
|
|
4
4
|
module Profile
|
|
5
5
|
# Renders security settings links based on enabled Rodauth features.
|
|
6
6
|
class SecuritySection < Plutonium::UI::Component::Base
|
|
7
|
+
# Labels and descriptions come from
|
|
8
|
+
# plutonium.profile.security_section.features.<feature>.{label,description}.
|
|
7
9
|
FEATURES = {
|
|
8
10
|
change_password: {
|
|
9
|
-
label: "Change Password",
|
|
10
|
-
description: "Update your account password",
|
|
11
11
|
icon: Phlex::TablerIcons::Key,
|
|
12
12
|
path_method: :change_password_path
|
|
13
13
|
},
|
|
14
14
|
change_login: {
|
|
15
|
-
label: "Change Email",
|
|
16
|
-
description: "Update your email address",
|
|
17
15
|
icon: Phlex::TablerIcons::Mail,
|
|
18
16
|
path_method: :change_login_path
|
|
19
17
|
},
|
|
20
18
|
otp: {
|
|
21
|
-
label: "Two-Factor Authentication",
|
|
22
|
-
description: "Add an extra layer of security",
|
|
23
19
|
icon: Phlex::TablerIcons::DeviceMobile,
|
|
24
20
|
path_method: :otp_setup_path
|
|
25
21
|
},
|
|
26
22
|
recovery_codes: {
|
|
27
|
-
label: "Recovery Codes",
|
|
28
|
-
description: "View or regenerate backup codes",
|
|
29
23
|
icon: Phlex::TablerIcons::FileCode,
|
|
30
24
|
path_method: :recovery_codes_path
|
|
31
25
|
},
|
|
32
26
|
webauthn: {
|
|
33
|
-
label: "Security Keys",
|
|
34
|
-
description: "Manage passkeys and security keys",
|
|
35
27
|
icon: Phlex::TablerIcons::Fingerprint,
|
|
36
28
|
path_method: :webauthn_setup_path
|
|
37
29
|
},
|
|
38
30
|
active_sessions: {
|
|
39
|
-
label: "Active Sessions",
|
|
40
|
-
description: "View and manage your sessions",
|
|
41
31
|
icon: Phlex::TablerIcons::DevicesCheck,
|
|
42
32
|
path_method: :active_sessions_path
|
|
43
33
|
},
|
|
44
34
|
close_account: {
|
|
45
|
-
label: "Close Account",
|
|
46
|
-
description: "Permanently delete your account",
|
|
47
35
|
icon: Phlex::TablerIcons::Trash,
|
|
48
36
|
path_method: :close_account_path,
|
|
49
37
|
danger: true
|
|
@@ -61,8 +49,8 @@ module Plutonium
|
|
|
61
49
|
|
|
62
50
|
def render_section_header
|
|
63
51
|
div(class: "mb-4") do
|
|
64
|
-
h2(class: "text-lg font-semibold text-[var(--pu-text)]") { "
|
|
65
|
-
p(class: "text-sm text-[var(--pu-text-muted)]") { "
|
|
52
|
+
h2(class: "text-lg font-semibold text-[var(--pu-text)]") { t("plutonium.profile.security_section.title") }
|
|
53
|
+
p(class: "text-sm text-[var(--pu-text-muted)]") { t("plutonium.profile.security_section.description") }
|
|
66
54
|
end
|
|
67
55
|
end
|
|
68
56
|
|
|
@@ -95,8 +83,8 @@ module Plutonium
|
|
|
95
83
|
|
|
96
84
|
# Content
|
|
97
85
|
div(class: "flex-grow") do
|
|
98
|
-
div(class: "font-medium") {
|
|
99
|
-
div(class: "text-sm text-[var(--pu-text-muted)]") {
|
|
86
|
+
div(class: "font-medium") { feature_text(feature, :label) }
|
|
87
|
+
div(class: "text-sm text-[var(--pu-text-muted)]") { feature_text(feature, :description) }
|
|
100
88
|
end
|
|
101
89
|
|
|
102
90
|
# Arrow
|
|
@@ -106,6 +94,10 @@ module Plutonium
|
|
|
106
94
|
end
|
|
107
95
|
end
|
|
108
96
|
|
|
97
|
+
def feature_text(feature, slot)
|
|
98
|
+
t("plutonium.profile.security_section.features.#{feature}.#{slot}")
|
|
99
|
+
end
|
|
100
|
+
|
|
109
101
|
def enabled_features
|
|
110
102
|
FEATURES.select { |feature, _config| feature_enabled?(feature) }
|
|
111
103
|
end
|
|
@@ -19,10 +19,19 @@ module Plutonium
|
|
|
19
19
|
|
|
20
20
|
attr_reader :resource_class
|
|
21
21
|
|
|
22
|
-
def initialize(key:, resource_class: nil)
|
|
22
|
+
def initialize(key:, resource_class: nil, label: nil)
|
|
23
23
|
super()
|
|
24
24
|
@key = key
|
|
25
25
|
@resource_class = resource_class
|
|
26
|
+
@label = label
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# The filter's display label: `label:` if given, else the
|
|
30
|
+
# plutonium.filters.<model>.<key> convention, else the humanized key.
|
|
31
|
+
def label
|
|
32
|
+
Plutonium::Translation.resolve(@label) ||
|
|
33
|
+
Plutonium::Translation.label_for(:filter, resource_class, key) ||
|
|
34
|
+
key.to_s.humanize
|
|
26
35
|
end
|
|
27
36
|
end
|
|
28
37
|
end
|
|
@@ -27,7 +27,14 @@ module Plutonium
|
|
|
27
27
|
return "" if value.blank?
|
|
28
28
|
ids = decode_ids(value)
|
|
29
29
|
return "" if ids.empty?
|
|
30
|
-
|
|
30
|
+
# Resolve labels through the same scope-honouring relation that the
|
|
31
|
+
# dropdown (ResourceSelect#authorized_relation) and the typeahead
|
|
32
|
+
# (Typeahead#filter_association) already enforce. A bare
|
|
33
|
+
# `association_class.where(id: ids)` here would widen past the
|
|
34
|
+
# configured `scope:` and let a crafted `?q[<key>][value]=<out-of-scope
|
|
35
|
+
# id>` render the hidden record's `to_label` into the active-filter
|
|
36
|
+
# pill even though the matching filter was dropped at submission.
|
|
37
|
+
records = scoped_relation.where(id: ids)
|
|
31
38
|
records.map { |r| r.respond_to?(:to_label) ? r.to_label : r.to_s }.join(", ")
|
|
32
39
|
rescue
|
|
33
40
|
Array(value).reject(&:blank?).join(", ")
|
|
@@ -45,7 +52,8 @@ module Plutonium
|
|
|
45
52
|
as: :resource_select,
|
|
46
53
|
association_class: association_class,
|
|
47
54
|
multiple: @multiple,
|
|
48
|
-
include_blank: @multiple ? false : "
|
|
55
|
+
include_blank: @multiple ? false : Plutonium::Translation.t("plutonium.query.all"),
|
|
56
|
+
scope: @scope_proc
|
|
49
57
|
end
|
|
50
58
|
|
|
51
59
|
private
|
|
@@ -86,6 +94,23 @@ module Plutonium
|
|
|
86
94
|
def infer_class_from_key
|
|
87
95
|
key.to_s.classify.constantize
|
|
88
96
|
end
|
|
97
|
+
|
|
98
|
+
# The relation used to resolve `humanize_value` labels, narrowed by the
|
|
99
|
+
# configured `scope:` exactly like ResourceSelect#apply_scope and
|
|
100
|
+
# Typeahead#apply_scope. The arity dispatch — Symbol, zero-arg Proc
|
|
101
|
+
# (kanban form `-> { ... }`), one-arg Proc (documented form
|
|
102
|
+
# `->(s) { s.active }`), nil — must stay in lock-step with those two
|
|
103
|
+
# sites; any divergence re-opens the leak this method closes. Unsupported
|
|
104
|
+
# scope types raise ArgumentError loudly rather than silently widening.
|
|
105
|
+
def scoped_relation
|
|
106
|
+
relation = association_class.all
|
|
107
|
+
case @scope_proc
|
|
108
|
+
when Symbol then relation.public_send(@scope_proc)
|
|
109
|
+
when Proc then @scope_proc.arity.zero? ? relation.instance_exec(&@scope_proc) : @scope_proc.call(relation)
|
|
110
|
+
when nil then relation
|
|
111
|
+
else raise ArgumentError, "Unsupported association scope: #{@scope_proc.inspect} (expected Symbol, Proc, or nil)"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
89
114
|
end
|
|
90
115
|
end
|
|
91
116
|
end
|
|
@@ -10,10 +10,10 @@ module Plutonium
|
|
|
10
10
|
# filter :published, with: :boolean, true_label: "Published", false_label: "Draft"
|
|
11
11
|
#
|
|
12
12
|
class Boolean < Filter
|
|
13
|
-
def initialize(true_label:
|
|
13
|
+
def initialize(true_label: nil, false_label: nil, **)
|
|
14
14
|
super(**)
|
|
15
|
-
@true_label = true_label
|
|
16
|
-
@false_label = false_label
|
|
15
|
+
@true_label = true_label || Plutonium::Translation.t("plutonium.boolean.true")
|
|
16
|
+
@false_label = false_label || Plutonium::Translation.t("plutonium.boolean.false")
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def humanize_value(value)
|
|
@@ -32,7 +32,7 @@ module Plutonium
|
|
|
32
32
|
input :value,
|
|
33
33
|
as: :select,
|
|
34
34
|
choices: [[@true_label, "true"], [@false_label, "false"]],
|
|
35
|
-
include_blank: "
|
|
35
|
+
include_blank: Plutonium::Translation.t("plutonium.query.all")
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
end
|
|
@@ -73,23 +73,10 @@ module Plutonium
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def generate_placeholder
|
|
76
|
-
base =
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
when :not_eq
|
|
81
|
-
"#{base} not on..."
|
|
82
|
-
when :lt
|
|
83
|
-
"#{base} before..."
|
|
84
|
-
when :lteq
|
|
85
|
-
"#{base} on or before..."
|
|
86
|
-
when :gt
|
|
87
|
-
"#{base} after..."
|
|
88
|
-
when :gteq
|
|
89
|
-
"#{base} on or after..."
|
|
90
|
-
else
|
|
91
|
-
base
|
|
92
|
-
end
|
|
76
|
+
base = label
|
|
77
|
+
return base if @predicate == :eq
|
|
78
|
+
|
|
79
|
+
Plutonium::Translation.t("plutonium.query.filters.date.#{@predicate}", label: base)
|
|
93
80
|
end
|
|
94
81
|
end
|
|
95
82
|
end
|
|
@@ -34,8 +34,8 @@ module Plutonium
|
|
|
34
34
|
def customize_inputs
|
|
35
35
|
input :from, as: :date
|
|
36
36
|
input :to, as: :date
|
|
37
|
-
field :from, placeholder: @from_label || "
|
|
38
|
-
field :to, placeholder: @to_label || "
|
|
37
|
+
field :from, placeholder: @from_label || Plutonium::Translation.t("plutonium.query.filters.date_range.from", label: label)
|
|
38
|
+
field :to, placeholder: @to_label || Plutonium::Translation.t("plutonium.query.filters.date_range.to", label: label)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
private
|
|
@@ -29,12 +29,21 @@ module Plutonium
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Active-filter pill text: each chosen value through the enum-value
|
|
33
|
+
# convention (activerecord.attributes.<model>.<key>/<value> or
|
|
34
|
+
# plutonium.values.<model>.<key>.<value>), else the raw value.
|
|
35
|
+
def humanize_value(value)
|
|
36
|
+
Array(value).reject(&:blank?).map do |choice|
|
|
37
|
+
Plutonium::Translation.value_label(resource_class, key, choice) || choice.to_s
|
|
38
|
+
end.join(", ")
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
def customize_inputs
|
|
33
42
|
input :value,
|
|
34
43
|
as: :select,
|
|
35
44
|
choices: resolved_choices,
|
|
36
45
|
multiple: @multiple,
|
|
37
|
-
include_blank: @multiple ? false : "
|
|
46
|
+
include_blank: @multiple ? false : Plutonium::Translation.t("plutonium.query.all")
|
|
38
47
|
end
|
|
39
48
|
|
|
40
49
|
private
|
|
@@ -52,19 +52,16 @@ module Plutonium
|
|
|
52
52
|
private
|
|
53
53
|
|
|
54
54
|
def generate_placeholder
|
|
55
|
-
base =
|
|
56
|
-
case @predicate
|
|
57
|
-
when :matches, :not_matches
|
|
58
|
-
|
|
59
|
-
when :
|
|
60
|
-
|
|
61
|
-
when :ends_with
|
|
62
|
-
"#{base} ends with..."
|
|
63
|
-
when :contains, :not_contains
|
|
64
|
-
"#{base} contains..."
|
|
65
|
-
else
|
|
66
|
-
base
|
|
55
|
+
base = label
|
|
56
|
+
phrase = case @predicate
|
|
57
|
+
when :matches, :not_matches then :matches
|
|
58
|
+
when :starts_with then :starts_with
|
|
59
|
+
when :ends_with then :ends_with
|
|
60
|
+
when :contains, :not_contains then :contains
|
|
67
61
|
end
|
|
62
|
+
return base unless phrase
|
|
63
|
+
|
|
64
|
+
Plutonium::Translation.t("plutonium.query.filters.text.#{phrase}", label: base)
|
|
68
65
|
end
|
|
69
66
|
|
|
70
67
|
def sanitize_like(string)
|
data/lib/plutonium/railtie.rb
CHANGED
|
@@ -16,6 +16,7 @@ module Plutonium
|
|
|
16
16
|
# end
|
|
17
17
|
PRECOMPILE_ASSETS = %w[
|
|
18
18
|
plutonium.js plutonium.js.map plutonium.min.js plutonium.min.js.map
|
|
19
|
+
plutonium-charts.js plutonium-charts.js.map plutonium-charts.min.js plutonium-charts.min.js.map
|
|
19
20
|
plutonium.css plutonium.png plutonium.ico
|
|
20
21
|
].freeze
|
|
21
22
|
|
|
@@ -25,6 +26,8 @@ module Plutonium
|
|
|
25
26
|
|
|
26
27
|
initializer "plutonium.rescue_responses", before: "action_dispatch.configure" do |app|
|
|
27
28
|
app.config.action_dispatch.rescue_responses["ActionPolicy::Unauthorized"] = :forbidden
|
|
29
|
+
app.config.action_dispatch.rescue_responses["Plutonium::Dashboard::UnknownCardError"] = :not_found
|
|
30
|
+
app.config.action_dispatch.rescue_responses["Plutonium::Dashboard::UnknownDashboardError"] = :not_found
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
initializer "plutonium.deprecator" do |app|
|
|
@@ -39,6 +42,19 @@ module Plutonium
|
|
|
39
42
|
load_plutonium_initializers
|
|
40
43
|
end
|
|
41
44
|
|
|
45
|
+
# Plutonium is a Railtie, not an Engine, so it gets no config/locales path
|
|
46
|
+
# for free. Register it the way Rails::Engine#add_locales does: through
|
|
47
|
+
# railties_load_path, which the I18n railtie unshifts ahead of the app's
|
|
48
|
+
# own locales in registration order. Registering before every engine's
|
|
49
|
+
# add_locales puts the gem's strings at the lowest precedence: a package or
|
|
50
|
+
# portal engine's config/locales overrides them, and the host app overrides
|
|
51
|
+
# both.
|
|
52
|
+
initializer "plutonium.i18n", before: :add_locales do
|
|
53
|
+
locales = Rails::Paths::Root.new(Plutonium.root.to_s)
|
|
54
|
+
locales.add "config/locales", glob: "**/*.{rb,yml}"
|
|
55
|
+
config.i18n.railties_load_path << locales["config/locales"]
|
|
56
|
+
end
|
|
57
|
+
|
|
42
58
|
initializer "plutonium.register_migrations" do
|
|
43
59
|
Plutonium::Migrations.register(:wizards, Plutonium.root.join("db/migrate/wizard").to_s)
|
|
44
60
|
Plutonium::Migrations.register(:async_interactions, Plutonium.root.join("db/migrate/async_interactions").to_s)
|
|
@@ -131,6 +147,7 @@ module Plutonium
|
|
|
131
147
|
def extend_action_dispatch
|
|
132
148
|
ActionDispatch::Routing::Mapper.prepend Plutonium::Routing::MapperExtensions
|
|
133
149
|
ActionDispatch::Routing::Mapper.prepend Plutonium::Routing::WizardRegistration
|
|
150
|
+
ActionDispatch::Routing::Mapper.prepend Plutonium::Routing::DashboardRegistration
|
|
134
151
|
ActionDispatch::Routing::RouteSet.prepend Plutonium::Routing::RouteSetExtensions
|
|
135
152
|
Rails::Engine.include Plutonium::Routing::ResourceRegistration
|
|
136
153
|
end
|
|
@@ -188,14 +188,19 @@ module Plutonium
|
|
|
188
188
|
end
|
|
189
189
|
end
|
|
190
190
|
|
|
191
|
-
# Attachment/file input names (as Strings)
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
191
|
+
# Attachment/file input names (as Strings) for the current resource —
|
|
192
|
+
# inputs declared with a file `as:` (`:file`/`:uppy`/`:attachment`)
|
|
193
|
+
# unioned with the attachments reflected on the model, so auto-detected
|
|
194
|
+
# attachments (no `input` declaration) are covered too. Excluded from the
|
|
195
|
+
# extraction-record pre-assignment so a single-read Rack upload isn't
|
|
196
|
+
# consumed before create/update reads it.
|
|
195
197
|
def attachment_input_keys
|
|
196
|
-
current_definition.defined_inputs.filter_map { |name, config|
|
|
198
|
+
declared = current_definition.defined_inputs.filter_map { |name, config|
|
|
197
199
|
name.to_s if Plutonium::Definition::InputAliases.file_input?(config.dig(:options, :as))
|
|
198
200
|
}
|
|
201
|
+
reflected = (resource_class.has_one_attached_field_names + resource_class.has_many_attached_field_names)
|
|
202
|
+
.map(&:to_s)
|
|
203
|
+
declared | reflected
|
|
199
204
|
end
|
|
200
205
|
|
|
201
206
|
# Returns the resource parameters, including scoped and parent parameters
|