plutonium 0.64.0 → 0.65.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 +4 -1
- data/.claude/skills/plutonium-app/SKILL.md +14 -0
- data/.claude/skills/plutonium-dashboard/SKILL.md +161 -0
- data/.claude/skills/plutonium-resource/SKILL.md +94 -14
- data/.claude/skills/plutonium-ui/SKILL.md +22 -1
- data/CHANGELOG.md +59 -0
- data/CLAUDE.md +282 -210
- 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/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 +175 -0
- data/docs/blog/introducing-plutonium-i18n.md +91 -0
- data/docs/blog/introducing-plutonium.md +4 -5
- data/docs/blog/whats-new-async-kanban-wizards.md +1 -1
- data/docs/guides/dashboards.md +300 -0
- data/docs/guides/index.md +1 -0
- data/docs/guides/kanban.md +2 -2
- 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 +2 -2
- data/docs/reference/app/portals.md +2 -0
- data/docs/reference/configuration.md +84 -27
- 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/i18n.md +239 -0
- data/docs/reference/index.md +10 -1
- data/docs/reference/kanban/dsl.md +1 -1
- data/docs/reference/kanban/positioning.md +2 -2
- data/docs/reference/resource/actions.md +1 -1
- data/docs/reference/resource/definition.md +96 -18
- data/docs/reference/resource/export.md +5 -1
- data/docs/reference/resource/index.md +2 -0
- data/docs/reference/{positioning.md → resource/positioning.md} +2 -1
- data/docs/reference/resource/query.md +2 -0
- data/docs/reference/ui/assets.md +8 -0
- data/docs/reference/ui/displays.md +5 -8
- data/docs/reference/ui/index.md +1 -1
- data/docs/reference/wizard/dsl.md +2 -2
- 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/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/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/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 +91 -0
- 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
|
@@ -60,8 +60,8 @@ module Plutonium
|
|
|
60
60
|
# regains the metadata rail that the modal hides.
|
|
61
61
|
def render_modal_details
|
|
62
62
|
render Plutonium::UI::Modal::Centered.new(
|
|
63
|
-
title:
|
|
64
|
-
description:
|
|
63
|
+
title: resolved_page_title,
|
|
64
|
+
description: resolved_page_description,
|
|
65
65
|
size: :lg,
|
|
66
66
|
open_full_url: open_full_page_url
|
|
67
67
|
) do
|
|
@@ -37,8 +37,13 @@ module Plutonium
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
39
|
def wizard_title
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
wizard = @runner.wizard.class.label.presence
|
|
41
|
+
step = @runner.current_step&.label.presence
|
|
42
|
+
if wizard && step
|
|
43
|
+
t("plutonium.wizard.page.title", wizard:, step:)
|
|
44
|
+
else
|
|
45
|
+
wizard || step || t("plutonium.wizard.page.fallback_title")
|
|
46
|
+
end
|
|
42
47
|
end
|
|
43
48
|
|
|
44
49
|
# Centered wizard header: the title and the wizard-level description
|
|
@@ -103,7 +108,7 @@ module Plutonium
|
|
|
103
108
|
div(class: "mb-6") do
|
|
104
109
|
unless step.review?
|
|
105
110
|
span(class: "text-xs font-bold uppercase tracking-wide text-primary-600 dark:text-primary-400") do
|
|
106
|
-
"
|
|
111
|
+
t("plutonium.wizard.page.step_position", position: step_position(step), total: visible_step_count)
|
|
107
112
|
end
|
|
108
113
|
end
|
|
109
114
|
h2(class: "mt-1 text-xl font-semibold tracking-tight text-[var(--pu-text)]") { step.label.to_s }
|
|
@@ -112,7 +117,7 @@ module Plutonium
|
|
|
112
117
|
# shown — when summary is off (the ready panel / custom-only body), that
|
|
113
118
|
# prompt would contradict the body, so we omit it.
|
|
114
119
|
desc = step.description.presence
|
|
115
|
-
desc ||= "
|
|
120
|
+
desc ||= t("plutonium.wizard.page.review_prompt") if step.review? && step.summary?
|
|
116
121
|
if desc
|
|
117
122
|
p(class: "mt-1.5 text-sm text-[var(--pu-text-muted)]") { desc }
|
|
118
123
|
end
|
|
@@ -182,12 +187,12 @@ module Plutonium
|
|
|
182
187
|
|
|
183
188
|
div(class: "pu-wizard-nav flex items-center justify-between gap-3 border-t border-[var(--pu-border)] bg-[var(--pu-surface-alt)] px-6 py-4 sm:px-8") do
|
|
184
189
|
div(class: "flex items-center gap-2") do
|
|
185
|
-
nav_button("
|
|
186
|
-
nav_button("
|
|
190
|
+
nav_button(t("plutonium.wizard.nav.back"), direction: "back", style: "pu-btn-outline", embedded:) if show_back?
|
|
191
|
+
nav_button(t("plutonium.wizard.cancel"), direction: "cancel", style: "pu-btn-ghost", embedded:)
|
|
187
192
|
end
|
|
188
193
|
div(class: "flex items-center gap-2") do
|
|
189
194
|
if finish
|
|
190
|
-
nav_button("
|
|
195
|
+
nav_button(t("plutonium.wizard.nav.finish"), direction: "next", style: "pu-btn-primary", embedded:, disabled: finish_disabled, name: "finish")
|
|
191
196
|
else
|
|
192
197
|
render_forward_buttons(embedded:)
|
|
193
198
|
end
|
|
@@ -209,11 +214,11 @@ module Plutonium
|
|
|
209
214
|
# nothing was persisted, so this isn't a re-edit. Keep "Next" there; the
|
|
210
215
|
# presence of `@errors` is the error-render signal.
|
|
211
216
|
revisiting = @runner.submitted?(step) && @errors.blank?
|
|
212
|
-
continue_label = revisiting ? "
|
|
217
|
+
continue_label = revisiting ? t("plutonium.wizard.nav.save_and_continue") : t("plutonium.wizard.nav.next")
|
|
213
218
|
|
|
214
219
|
if review_shortcut?(step)
|
|
215
220
|
nav_button(continue_label, direction: "next", style: "pu-btn-outline", embedded:, name: "next")
|
|
216
|
-
nav_button("
|
|
221
|
+
nav_button(t("plutonium.wizard.nav.save_and_review"), direction: "next", style: "pu-btn-primary", embedded:, name: "save_review", goto: "review")
|
|
217
222
|
else
|
|
218
223
|
nav_button(continue_label, direction: "next", style: "pu-btn-primary", embedded:, name: "next")
|
|
219
224
|
end
|
|
@@ -305,8 +310,8 @@ module Plutonium
|
|
|
305
310
|
# unsaved edits and the user clicks a control that abandons them.
|
|
306
311
|
def leave_warning(direction)
|
|
307
312
|
case direction
|
|
308
|
-
when "back" then "
|
|
309
|
-
when "cancel" then "
|
|
313
|
+
when "back" then t("plutonium.wizard.nav.unsaved_back")
|
|
314
|
+
when "cancel" then t("plutonium.wizard.nav.unsaved_cancel")
|
|
310
315
|
end
|
|
311
316
|
end
|
|
312
317
|
|
|
@@ -350,14 +355,15 @@ module Plutonium
|
|
|
350
355
|
end
|
|
351
356
|
end
|
|
352
357
|
|
|
353
|
-
# Every finalize error as a full sentence
|
|
354
|
-
#
|
|
355
|
-
#
|
|
358
|
+
# Every finalize error as a full sentence, built by the wizard's own
|
|
359
|
+
# `errors.full_message` so it follows Rails' `errors.format` and attribute
|
|
360
|
+
# translations: a `:base` error renders verbatim; a field error is prefixed
|
|
361
|
+
# with its attribute name — {name: ["has already been taken"]} → "Name has
|
|
356
362
|
# already been taken".
|
|
357
363
|
def review_error_messages
|
|
364
|
+
errors = @runner.wizard.errors
|
|
358
365
|
@errors.flat_map do |attr, msgs|
|
|
359
|
-
|
|
360
|
-
Array(msgs).map { |m| base ? m : "#{attr.to_s.humanize} #{m}" }
|
|
366
|
+
Array(msgs).map { |m| errors.full_message(attr.to_sym, m) }
|
|
361
367
|
end
|
|
362
368
|
end
|
|
363
369
|
|
|
@@ -38,7 +38,7 @@ module Plutonium
|
|
|
38
38
|
div(class: "pu-wizard-header mb-7 text-center") do
|
|
39
39
|
h1(class: "text-2xl font-bold tracking-tight text-[var(--pu-text)]") { @wizard_class.label }
|
|
40
40
|
p(class: "mx-auto mt-1.5 max-w-prose text-[var(--pu-text-muted)]") do
|
|
41
|
-
"
|
|
41
|
+
t("plutonium.wizard.chooser.prompt")
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -64,15 +64,15 @@ module Plutonium
|
|
|
64
64
|
li(class: "flex items-center justify-between gap-4 px-5 py-4", data: {wizard_chooser_entry: entry.current_step}) do
|
|
65
65
|
div(class: "min-w-0") do
|
|
66
66
|
p(class: "truncate text-sm font-semibold text-[var(--pu-text)]") do
|
|
67
|
-
entry.current_step_label.presence || "
|
|
67
|
+
entry.current_step_label.presence || t("plutonium.wizard.chooser.in_progress")
|
|
68
68
|
end
|
|
69
|
-
p(class: "mt-0.5 text-xs text-[var(--pu-text-muted)]") { "
|
|
69
|
+
p(class: "mt-0.5 text-xs text-[var(--pu-text-muted)]") { t("plutonium.wizard.chooser.updated_ago", time: updated_ago(entry)) }
|
|
70
70
|
end
|
|
71
71
|
div(class: "flex items-center gap-2 shrink-0") do
|
|
72
72
|
if entry.resume_url.present?
|
|
73
|
-
a(href: entry.resume_url, class: "pu-btn pu-btn-sm pu-btn-outline", data: {wizard_chooser_resume: true}) { "
|
|
73
|
+
a(href: entry.resume_url, class: "pu-btn pu-btn-sm pu-btn-outline", data: {wizard_chooser_resume: true}) { t("plutonium.wizard.chooser.resume") }
|
|
74
74
|
else
|
|
75
|
-
span(class: "pu-btn pu-btn-sm pu-btn-outline opacity-50 cursor-not-allowed") { "
|
|
75
|
+
span(class: "pu-btn pu-btn-sm pu-btn-outline opacity-50 cursor-not-allowed") { t("plutonium.wizard.chooser.resume") }
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
render_cancel_form(entry) if entry.cancel_url.present?
|
|
@@ -92,19 +92,19 @@ module Plutonium
|
|
|
92
92
|
button(
|
|
93
93
|
type: "submit",
|
|
94
94
|
class: "pu-btn pu-btn-sm pu-btn-soft-danger",
|
|
95
|
-
aria_label: "
|
|
95
|
+
aria_label: t("plutonium.wizard.chooser.cancel_draft", wizard: @wizard_class.label),
|
|
96
96
|
data: {
|
|
97
97
|
wizard_chooser_cancel: true,
|
|
98
|
-
turbo_confirm: "
|
|
98
|
+
turbo_confirm: t("plutonium.wizard.chooser.discard_confirm", wizard: @wizard_class.label)
|
|
99
99
|
}
|
|
100
|
-
) { "
|
|
100
|
+
) { t("plutonium.wizard.cancel") }
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
def render_start_new
|
|
105
105
|
div(class: "border-t border-[var(--pu-border)] bg-[var(--pu-surface-alt)] px-5 py-4") do
|
|
106
106
|
a(href: @start_new_url, class: "pu-btn pu-btn-md pu-btn-primary w-full justify-center", data: {wizard_chooser_start_new: true}) do
|
|
107
|
-
"
|
|
107
|
+
t("plutonium.wizard.chooser.start_new")
|
|
108
108
|
end
|
|
109
109
|
end
|
|
110
110
|
end
|
|
@@ -112,7 +112,7 @@ module Plutonium
|
|
|
112
112
|
def updated_ago(entry)
|
|
113
113
|
helpers.time_ago_in_words(entry.updated_at)
|
|
114
114
|
rescue
|
|
115
|
-
"
|
|
115
|
+
t("plutonium.wizard.chooser.a_while")
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def page_type = :wizard_chooser_page
|
|
@@ -53,12 +53,12 @@ module Plutonium
|
|
|
53
53
|
@wizard.class.label
|
|
54
54
|
end
|
|
55
55
|
p(class: "mx-auto mt-2 max-w-prose text-[var(--pu-text-muted)]") do
|
|
56
|
-
"
|
|
56
|
+
t("plutonium.wizard.completed.message")
|
|
57
57
|
end
|
|
58
58
|
div(class: "mt-7") do
|
|
59
59
|
# Exits the wizard to a different page; opt out of Turbo morph (which
|
|
60
60
|
# would otherwise nest the destination into this page — see Page::Wizard).
|
|
61
|
-
a(href: @exit_url, class: "pu-btn pu-btn-md pu-btn-primary", data: {wizard_completed: "exit", turbo: "false"}) { "
|
|
61
|
+
a(href: @exit_url, class: "pu-btn pu-btn-md pu-btn-primary", data: {wizard_completed: "exit", turbo: "false"}) { t("plutonium.wizard.completed.continue") }
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
64
|
|
|
@@ -134,7 +134,7 @@ module Plutonium
|
|
|
134
134
|
type: "button",
|
|
135
135
|
class: themed(:column_menu_trigger),
|
|
136
136
|
data: {action: "click->table-column-menu#toggle"},
|
|
137
|
-
aria: {label: "
|
|
137
|
+
aria: {label: Plutonium::Translation.t("plutonium.ui.table.column_options")}
|
|
138
138
|
) do
|
|
139
139
|
render Phlex::TablerIcons::Dots.new(class: "w-3 h-3")
|
|
140
140
|
end
|
|
@@ -143,7 +143,7 @@ module Plutonium
|
|
|
143
143
|
class: themed(:column_menu_panel),
|
|
144
144
|
data: {"table-column-menu-target": "panel"}
|
|
145
145
|
) do
|
|
146
|
-
render_menu_item("
|
|
146
|
+
render_menu_item(Plutonium::Translation.t("plutonium.ui.table.clear_sort"), sort_params[:reset_url], icon: Phlex::TablerIcons::X)
|
|
147
147
|
end
|
|
148
148
|
end
|
|
149
149
|
end
|
|
@@ -59,7 +59,7 @@ module Plutonium
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def attachment_extension(attachment)
|
|
62
|
-
attachment.try(:extension) || File.extname(attachment.filename.to_s)
|
|
62
|
+
attachment.try(:extension).presence || File.extname(attachment.filename.to_s).delete(".")
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def normalize_value(value)
|
|
@@ -37,11 +37,27 @@ module Plutonium
|
|
|
37
37
|
|
|
38
38
|
def render_selected_count
|
|
39
39
|
div(class: "text-sm font-medium text-primary-700 dark:text-primary-300") do
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
# The count is live-updated by the Stimulus controller, so the
|
|
41
|
+
# sentence is translated with its placeholder left in and split
|
|
42
|
+
# around it (same pattern as PagyInfo#render_template).
|
|
43
|
+
selected_count_template.split(/(%\{count\})/).each do |part|
|
|
44
|
+
if part == "%{count}"
|
|
45
|
+
span(data: {bulk_actions_target: "selectedCount"}) { "0" }
|
|
46
|
+
else
|
|
47
|
+
plain part
|
|
48
|
+
end
|
|
49
|
+
end
|
|
42
50
|
end
|
|
43
51
|
end
|
|
44
52
|
|
|
53
|
+
# The raw template, placeholder intact. Fetched without `count:` so
|
|
54
|
+
# no pluralisation rule runs on a placeholder; a locale that defines
|
|
55
|
+
# one/other forms contributes its `other` form.
|
|
56
|
+
def selected_count_template
|
|
57
|
+
template = t("plutonium.ui.table.selected_count")
|
|
58
|
+
template.is_a?(Hash) ? template[:other] : template
|
|
59
|
+
end
|
|
60
|
+
|
|
45
61
|
def render_action_buttons
|
|
46
62
|
div(class: "flex items-center gap-1.5") do
|
|
47
63
|
@bulk_actions.each do |action|
|
|
@@ -55,7 +71,7 @@ module Plutonium
|
|
|
55
71
|
type: "button",
|
|
56
72
|
data: {action: "click->bulk-actions#clearSelection"},
|
|
57
73
|
class: "ml-auto text-xs text-primary-700 dark:text-primary-300 hover:underline"
|
|
58
|
-
) { "
|
|
74
|
+
) { t("plutonium.ui.table.clear_selection") }
|
|
59
75
|
end
|
|
60
76
|
|
|
61
77
|
def render_action_button(action)
|
|
@@ -70,8 +70,8 @@ module Plutonium
|
|
|
70
70
|
type: "button",
|
|
71
71
|
draggable: "true",
|
|
72
72
|
class: themed(@variant[:grip]),
|
|
73
|
-
title: "
|
|
74
|
-
aria: {label: "
|
|
73
|
+
title: Plutonium::Translation.t("plutonium.positioning.drag_handle.title"),
|
|
74
|
+
aria: {label: Plutonium::Translation.t("plutonium.positioning.drag_handle.aria_label")},
|
|
75
75
|
data: {positioned_grip: ""}
|
|
76
76
|
) { icon }
|
|
77
77
|
end
|
|
@@ -80,7 +80,7 @@ module Plutonium
|
|
|
80
80
|
a(
|
|
81
81
|
href: @sort_url,
|
|
82
82
|
class: themed(@variant[:disabled]),
|
|
83
|
-
title: "
|
|
83
|
+
title: Plutonium::Translation.t("plutonium.positioning.drag_handle.disabled_title")
|
|
84
84
|
) { icon }
|
|
85
85
|
end
|
|
86
86
|
|
|
@@ -49,18 +49,18 @@ module Plutonium
|
|
|
49
49
|
def render_header
|
|
50
50
|
div(class: "shrink-0 flex items-center justify-between gap-4 px-6 pt-5 pb-4 " \
|
|
51
51
|
"border-b border-[var(--pu-border)]") do
|
|
52
|
-
h2(class: "text-lg font-semibold text-[var(--pu-text)]") { "
|
|
52
|
+
h2(class: "text-lg font-semibold text-[var(--pu-text)]") { t("plutonium.ui.table.filters") }
|
|
53
53
|
div(class: "flex items-center gap-1") do
|
|
54
54
|
button(
|
|
55
55
|
type: "button",
|
|
56
56
|
class: "text-sm text-[var(--pu-text-muted)] hover:text-[var(--pu-text)] px-2 py-1 rounded transition-colors",
|
|
57
57
|
data: {action: "filter-panel#clear"}
|
|
58
|
-
) { "
|
|
58
|
+
) { t("plutonium.ui.table.clear") }
|
|
59
59
|
button(
|
|
60
60
|
type: "button",
|
|
61
61
|
class: "p-1.5 -m-1.5 text-[var(--pu-text-muted)] hover:text-[var(--pu-text)] hover:bg-[var(--pu-surface-alt)] rounded-md transition-colors",
|
|
62
62
|
data: {action: "filter-panel#close"},
|
|
63
|
-
"aria-label": "
|
|
63
|
+
"aria-label": t("plutonium.ui.table.close_filters")
|
|
64
64
|
) do
|
|
65
65
|
render Phlex::TablerIcons::X.new(class: "w-5 h-5")
|
|
66
66
|
end
|
|
@@ -76,9 +76,9 @@ module Plutonium
|
|
|
76
76
|
has_multiple_inputs = inputs.size > 1
|
|
77
77
|
inputs.each do |input_name, _|
|
|
78
78
|
label = if has_multiple_inputs
|
|
79
|
-
"
|
|
79
|
+
t("plutonium.query.filter_input_label", label: query_object.filter_label(filter_name), input: input_name.to_s.humanize.downcase)
|
|
80
80
|
else
|
|
81
|
-
filter_name
|
|
81
|
+
query_object.filter_label(filter_name)
|
|
82
82
|
end
|
|
83
83
|
render_filter_field(nested, definition, input_name, filter_label: label)
|
|
84
84
|
end
|
|
@@ -93,7 +93,7 @@ module Plutonium
|
|
|
93
93
|
render field(:submit).submit_button_tag(
|
|
94
94
|
name: nil,
|
|
95
95
|
class!: "pu-btn pu-btn-md pu-btn-primary"
|
|
96
|
-
) { "
|
|
96
|
+
) { t("plutonium.ui.table.apply") }
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -115,14 +115,15 @@ module Plutonium
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def render_sort_fields
|
|
118
|
-
field :sort_fields do |name|
|
|
118
|
+
field :sort_fields, value: helpers.params.dig(search_param, :sort_fields) do |name|
|
|
119
119
|
render name.input_array_tag do |array|
|
|
120
120
|
render array.input_tag(type: :hidden, hidden: true)
|
|
121
121
|
end
|
|
122
122
|
end
|
|
123
123
|
nest_one :sort_directions do |nested|
|
|
124
124
|
query_object.sort_definitions.each do |filter_name, _|
|
|
125
|
-
|
|
125
|
+
direction_value = helpers.params.dig(search_param, :sort_directions, filter_name)
|
|
126
|
+
nested.field(filter_name, value: direction_value) do |f|
|
|
126
127
|
render f.input_tag(type: :hidden, hidden: true)
|
|
127
128
|
end
|
|
128
129
|
end
|
|
@@ -131,7 +132,7 @@ module Plutonium
|
|
|
131
132
|
|
|
132
133
|
def render_scope_fields
|
|
133
134
|
return if query_object.scope_definitions.blank?
|
|
134
|
-
render field(:scope).input_tag(type: :hidden, hidden: true)
|
|
135
|
+
render field(:scope, value: helpers.params.dig(search_param, :scope)).input_tag(type: :hidden, hidden: true)
|
|
135
136
|
end
|
|
136
137
|
|
|
137
138
|
def render_filter_field(nested, resource_definition, name, filter_label: nil)
|
|
@@ -156,7 +157,7 @@ module Plutonium
|
|
|
156
157
|
div(class: "space-y-1.5") do
|
|
157
158
|
label(class: "text-sm font-medium text-[var(--pu-text)]") { filter_label }
|
|
158
159
|
nested.field(name, value: current_value, **field_options) do |f|
|
|
159
|
-
f.placeholder(input_options[:include_blank] || "
|
|
160
|
+
f.placeholder(input_options[:include_blank] || t("plutonium.ui.table.all")) if input_options[:include_blank]
|
|
160
161
|
render instance_exec(f, &tag_block)
|
|
161
162
|
end
|
|
162
163
|
end
|
|
@@ -32,7 +32,7 @@ module Plutonium
|
|
|
32
32
|
span(class: "inline-flex items-center gap-1.5 h-6 px-2 rounded-full bg-primary-50 border border-primary-200 text-xs text-primary-700 dark:bg-primary-950/40 dark:border-primary-900/60 dark:text-primary-300") do
|
|
33
33
|
span { plain "#{filter[:label]}: #{filter[:value_label]}" }
|
|
34
34
|
a(href: filter[:clear_url],
|
|
35
|
-
aria: {label: "
|
|
35
|
+
aria: {label: t("plutonium.ui.table.remove_filter", filter: filter[:label])},
|
|
36
36
|
class: "ml-0.5 inline-flex items-center justify-center w-4 h-4 rounded hover:bg-primary-200 dark:hover:bg-primary-900/60") do
|
|
37
37
|
render Phlex::TablerIcons::X.new(class: "w-3 h-3")
|
|
38
38
|
end
|
|
@@ -44,14 +44,14 @@ module Plutonium
|
|
|
44
44
|
data: {action: "click->filter-panel#toggle"},
|
|
45
45
|
class: "inline-flex items-center gap-1 h-6 px-2 rounded-full border border-dashed border-[var(--pu-border)] text-xs text-[var(--pu-text-muted)] hover:text-[var(--pu-text)] hover:border-[var(--pu-border-strong)]") do
|
|
46
46
|
render Phlex::TablerIcons::Plus.new(class: "w-3 h-3")
|
|
47
|
-
plain "
|
|
47
|
+
plain t("plutonium.ui.table.filter")
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def render_clear_all_pill
|
|
52
52
|
a(href: clear_all_url,
|
|
53
53
|
class: "inline-flex items-center gap-1 h-6 px-2 rounded-full text-xs text-[var(--pu-text-muted)] hover:text-[var(--pu-text)] underline-offset-2 hover:underline") do
|
|
54
|
-
plain "
|
|
54
|
+
plain t("plutonium.ui.table.clear_all")
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -79,7 +79,7 @@ module Plutonium
|
|
|
79
79
|
|
|
80
80
|
def render_result_count
|
|
81
81
|
div(class: "ml-auto text-xs text-[var(--pu-text-muted)]") do
|
|
82
|
-
plain
|
|
82
|
+
plain t("plutonium.ui.table.result_count", count: @total_count)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
end
|
|
@@ -4,10 +4,24 @@ module Plutonium
|
|
|
4
4
|
module UI
|
|
5
5
|
module Table
|
|
6
6
|
module Components
|
|
7
|
+
# "Displaying articles 11-20 of 100 in total" plus a per-page selector.
|
|
8
|
+
#
|
|
9
|
+
# The sentences come from Pagy's own dictionaries (`pagy.info_tag.*`,
|
|
10
|
+
# `pagy.limit_tag_js`), translated in the current I18n locale, so a host
|
|
11
|
+
# that ships a Pagy locale file gets this component for free. Pagy
|
|
12
|
+
# leaves any placeholder it isn't handed untouched, which is what lets
|
|
13
|
+
# the counts render in bold and the per-page select sit inside its
|
|
14
|
+
# sentence: the template is translated with those placeholders still in
|
|
15
|
+
# place, then split around them.
|
|
7
16
|
class PagyInfo < Plutonium::UI::Component::Base
|
|
8
|
-
|
|
17
|
+
PLACEHOLDER = /(%\{(?:from|to|count|limit_input)\})/
|
|
18
|
+
|
|
19
|
+
# @param item_name [String, nil] the noun for the paginated records
|
|
20
|
+
# ("articles"); defaults to Pagy's generic "items".
|
|
21
|
+
def initialize(pagy, per_page_options: [5, 10, 20, 50, 100], item_name: nil)
|
|
9
22
|
@pagy = pagy
|
|
10
23
|
@per_page_options = (per_page_options + [@pagy.limit]).uniq.sort
|
|
24
|
+
@item_name = item_name
|
|
11
25
|
end
|
|
12
26
|
|
|
13
27
|
def view_template
|
|
@@ -20,36 +34,66 @@ module Plutonium
|
|
|
20
34
|
private
|
|
21
35
|
|
|
22
36
|
def results_info
|
|
37
|
+
key = if @pagy.count.zero?
|
|
38
|
+
"pagy.info_tag.no_items"
|
|
39
|
+
elsif @pagy.in == @pagy.count
|
|
40
|
+
"pagy.info_tag.single_page"
|
|
41
|
+
else
|
|
42
|
+
"pagy.info_tag.multiple_pages"
|
|
43
|
+
end
|
|
44
|
+
|
|
23
45
|
div do
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
b { @pagy.to.to_s }
|
|
28
|
-
plain " of "
|
|
29
|
-
b { @pagy.count }
|
|
30
|
-
plain " results"
|
|
46
|
+
render_template(pagy_template(key, @pagy.count)) do |placeholder|
|
|
47
|
+
b { @pagy.public_send(placeholder).to_s }
|
|
48
|
+
end
|
|
31
49
|
end
|
|
32
50
|
end
|
|
33
51
|
|
|
34
52
|
def per_page_selector
|
|
53
|
+
id = "perPage#{SecureRandom.hex}"
|
|
54
|
+
|
|
35
55
|
div(
|
|
36
56
|
class: "flex items-center space-x-2 mt-2 md:mt-0",
|
|
37
57
|
data_controller: "select-navigator"
|
|
38
58
|
) do
|
|
39
|
-
id
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
label(for: id, class: "flex items-center gap-2") do
|
|
60
|
+
render_template(pagy_template("pagy.limit_tag_js", @pagy.limit)) do
|
|
61
|
+
select(
|
|
62
|
+
id: id, name: "items", class: select_classes,
|
|
63
|
+
data_action: "change->select-navigator#navigate",
|
|
64
|
+
data_select_navigator_target: "select"
|
|
65
|
+
) do
|
|
66
|
+
@per_page_options.each do |option|
|
|
67
|
+
option(value: page_url(option), selected: option == @pagy.limit) { option.to_s }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
48
70
|
end
|
|
49
71
|
end
|
|
50
72
|
end
|
|
51
73
|
end
|
|
52
74
|
|
|
75
|
+
# Translate `key` with the item name filled in and every other
|
|
76
|
+
# placeholder left literal, for {#render_template} to split on.
|
|
77
|
+
def pagy_template(key, count)
|
|
78
|
+
Plutonium::Translation.pagy(key, item_name: item_name(count))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def item_name(count)
|
|
82
|
+
@item_name || Plutonium::Translation.pagy("pagy.item_name", count:)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Emit `template` as text, yielding each remaining placeholder's name
|
|
86
|
+
# (:from, :to, :count, :limit_input) for the caller to render inline.
|
|
87
|
+
def render_template(template)
|
|
88
|
+
template.split(PLACEHOLDER).each do |part|
|
|
89
|
+
if (match = part.match(/\A%\{(\w+)\}\z/))
|
|
90
|
+
yield match[1].to_sym
|
|
91
|
+
else
|
|
92
|
+
plain part
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
53
97
|
def select_classes
|
|
54
98
|
"bg-[var(--pu-surface)] border border-[var(--pu-border)] text-[var(--pu-text)] text-sm rounded-[var(--pu-radius-md)] focus:ring-2 focus:ring-primary-500 focus:border-primary-500 block p-2.5 min-w-[5em]"
|
|
55
99
|
end
|
|
@@ -10,7 +10,7 @@ module Plutonium
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def view_template
|
|
13
|
-
nav(aria_label: "
|
|
13
|
+
nav(aria_label: Plutonium::Translation.pagy("pagy.aria_label.nav", count: @pagy.last), class: "flex justify-center mt-6") do
|
|
14
14
|
ul(class: "inline-flex items-center gap-1 text-sm") do
|
|
15
15
|
prev_link
|
|
16
16
|
page_links
|
|
@@ -24,11 +24,11 @@ module Plutonium
|
|
|
24
24
|
def prev_link
|
|
25
25
|
li do
|
|
26
26
|
if @pagy.previous
|
|
27
|
-
a(href: page_url(@pagy.previous), class: link_classes(true)) {
|
|
27
|
+
a(href: page_url(@pagy.previous), class: link_classes(true), aria_label: previous_label) {
|
|
28
28
|
render Phlex::TablerIcons::ChevronLeft.new
|
|
29
29
|
}
|
|
30
30
|
else
|
|
31
|
-
button(class: disabled_link_classes(true), aria_disabled: "true") {
|
|
31
|
+
button(class: disabled_link_classes(true), aria_disabled: "true", aria_label: previous_label) {
|
|
32
32
|
render Phlex::TablerIcons::ChevronLeft.new
|
|
33
33
|
}
|
|
34
34
|
end
|
|
@@ -38,17 +38,21 @@ module Plutonium
|
|
|
38
38
|
def next_link
|
|
39
39
|
li do
|
|
40
40
|
if @pagy.next
|
|
41
|
-
a(href: page_url(@pagy.next), class: link_classes(false, true)) {
|
|
41
|
+
a(href: page_url(@pagy.next), class: link_classes(false, true), aria_label: next_label) {
|
|
42
42
|
render Phlex::TablerIcons::ChevronRight.new
|
|
43
43
|
}
|
|
44
44
|
else
|
|
45
|
-
button(class: disabled_link_classes(false, true), aria_disabled: "true") {
|
|
45
|
+
button(class: disabled_link_classes(false, true), aria_disabled: "true", aria_label: next_label) {
|
|
46
46
|
render Phlex::TablerIcons::ChevronRight.new
|
|
47
47
|
}
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
+
def previous_label = Plutonium::Translation.pagy("pagy.aria_label.previous")
|
|
53
|
+
|
|
54
|
+
def next_label = Plutonium::Translation.pagy("pagy.aria_label.next")
|
|
55
|
+
|
|
52
56
|
def page_links
|
|
53
57
|
@pagy.send(:series).each do |item|
|
|
54
58
|
li do
|
|
@@ -25,7 +25,7 @@ module Plutonium
|
|
|
25
25
|
button(
|
|
26
26
|
type: "button",
|
|
27
27
|
class: "p-1.5 rounded-[var(--pu-radius-md)] border border-[var(--pu-border)] bg-[var(--pu-surface)] text-[var(--pu-text-muted)] hover:text-[var(--pu-text)] hover:bg-[var(--pu-surface-alt)] hover:border-[var(--pu-border-strong)] transition-colors",
|
|
28
|
-
aria: {expanded: "false", haspopup: "true", label: "
|
|
28
|
+
aria: {expanded: "false", haspopup: "true", label: t("plutonium.ui.table.more_actions")},
|
|
29
29
|
data: {resource_drop_down_target: "trigger"}
|
|
30
30
|
) do
|
|
31
31
|
render Phlex::TablerIcons::DotsVertical.new(class: "w-4 h-4")
|
|
@@ -29,7 +29,7 @@ module Plutonium
|
|
|
29
29
|
id: "all-scope",
|
|
30
30
|
href: current_query_object.build_url(scope: nil),
|
|
31
31
|
class: active ? active_scope_class : inactive_scope_class
|
|
32
|
-
) { "
|
|
32
|
+
) { t("plutonium.ui.table.all") }
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def render_scope_button(name)
|
|
@@ -38,7 +38,11 @@ module Plutonium
|
|
|
38
38
|
id: "#{name}-scope",
|
|
39
39
|
href: current_query_object.build_url(scope: name),
|
|
40
40
|
class: active ? active_scope_class : inactive_scope_class
|
|
41
|
-
) { name
|
|
41
|
+
) { scope_label(name) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def scope_label(name)
|
|
45
|
+
Plutonium::Translation.label_for(:scope, current_query_object.resource_class, name) || name.to_s.humanize
|
|
42
46
|
end
|
|
43
47
|
|
|
44
48
|
def current_scope
|
|
@@ -9,7 +9,7 @@ module Plutonium
|
|
|
9
9
|
return if scopes.empty?
|
|
10
10
|
|
|
11
11
|
nav(role: "tablist",
|
|
12
|
-
aria: {label: "
|
|
12
|
+
aria: {label: t("plutonium.ui.table.scope")},
|
|
13
13
|
class: "flex flex-nowrap items-center gap-1 px-4 py-2 border-b border-[var(--pu-border)] " \
|
|
14
14
|
"overflow-x-auto whitespace-nowrap [scrollbar-width:none] [&::-webkit-scrollbar]:hidden") do
|
|
15
15
|
render_all_pill
|
|
@@ -27,12 +27,12 @@ module Plutonium
|
|
|
27
27
|
role: "tab",
|
|
28
28
|
aria: {selected: active},
|
|
29
29
|
class: pill_classes(active)
|
|
30
|
-
) { "
|
|
30
|
+
) { t("plutonium.ui.table.all") }
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def render_pill(key)
|
|
34
34
|
active = current_query_object.selected_scope.to_s == key.to_s
|
|
35
|
-
label = key.to_s.humanize
|
|
35
|
+
label = Plutonium::Translation.label_for(:scope, current_query_object.resource_class, key) || key.to_s.humanize
|
|
36
36
|
|
|
37
37
|
a(
|
|
38
38
|
id: "#{key}-scope",
|
|
@@ -73,7 +73,7 @@ module Plutonium
|
|
|
73
73
|
# Show X when no actions available for this record
|
|
74
74
|
span(
|
|
75
75
|
class: "inline-flex items-center justify-center size-4 text-[var(--pu-text-subtle)]",
|
|
76
|
-
title: "
|
|
76
|
+
title: Plutonium::Translation.t("plutonium.ui.table.no_bulk_actions")
|
|
77
77
|
) { "✕" }
|
|
78
78
|
else
|
|
79
79
|
input(
|
|
@@ -69,7 +69,7 @@ module Plutonium
|
|
|
69
69
|
data: {action: "click->filter-panel#toggle"}
|
|
70
70
|
) do
|
|
71
71
|
render Phlex::TablerIcons::AdjustmentsHorizontal.new(class: "w-4 h-4 shrink-0")
|
|
72
|
-
span { "
|
|
72
|
+
span { t("plutonium.ui.table.filter") }
|
|
73
73
|
if count > 0
|
|
74
74
|
span(class: "ml-1 inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 " \
|
|
75
75
|
"rounded-full bg-primary-600 text-white text-[10px] font-semibold leading-none") do
|
|
@@ -90,7 +90,7 @@ module Plutonium
|
|
|
90
90
|
type: "search",
|
|
91
91
|
name: "#{@search_param}[search]",
|
|
92
92
|
value: @search_value,
|
|
93
|
-
placeholder: "
|
|
93
|
+
placeholder: t("plutonium.ui.table.search_placeholder"),
|
|
94
94
|
class: "pu-input pu-input-toolbar pu-input-icon-left w-[220px]",
|
|
95
95
|
# turbo-permanent + a stable id keep the DOM node
|
|
96
96
|
# across Turbo morphs so focus / caret / IME state
|