lcp 0.1.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 +7 -0
- data/.claude/skills/lcp-custom-field/SKILL.md +205 -0
- data/.claude/skills/lcp-getting-started/SKILL.md +332 -0
- data/.claude/skills/lcp-host-binding/SKILL.md +287 -0
- data/.claude/skills/lcp-model/SKILL.md +185 -0
- data/.claude/skills/lcp-permissions/SKILL.md +176 -0
- data/.claude/skills/lcp-presenter/SKILL.md +194 -0
- data/.claude/skills/lcp-workflow/SKILL.md +281 -0
- data/CHANGELOG.md +69 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +17 -0
- data/app/assets/javascripts/lcp_ruby/application.js +58 -0
- data/app/assets/javascripts/lcp_ruby/controllers/advanced_filter_controller.js +1521 -0
- data/app/assets/javascripts/lcp_ruby/controllers/approval_actions_controller.js +24 -0
- data/app/assets/javascripts/lcp_ruby/controllers/array_input_controller.js +156 -0
- data/app/assets/javascripts/lcp_ruby/controllers/batch_select_controller.js +405 -0
- data/app/assets/javascripts/lcp_ruby/controllers/cascading_selects_controller.js +436 -0
- data/app/assets/javascripts/lcp_ruby/controllers/char_counter_controller.js +28 -0
- data/app/assets/javascripts/lcp_ruby/controllers/clipboard_controller.js +62 -0
- data/app/assets/javascripts/lcp_ruby/controllers/conditional_rendering_controller.js +178 -0
- data/app/assets/javascripts/lcp_ruby/controllers/confirm_dialog_controller.js +131 -0
- data/app/assets/javascripts/lcp_ruby/controllers/custom_fields_manage_controller.js +80 -0
- data/app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js +421 -0
- data/app/assets/javascripts/lcp_ruby/controllers/dialog_nested_controller.js +182 -0
- data/app/assets/javascripts/lcp_ruby/controllers/direct_upload_controller.js +100 -0
- data/app/assets/javascripts/lcp_ruby/controllers/drawer_controller.js +205 -0
- data/app/assets/javascripts/lcp_ruby/controllers/dropdown_controller.js +160 -0
- data/app/assets/javascripts/lcp_ruby/controllers/export_dialog_controller.js +15 -0
- data/app/assets/javascripts/lcp_ruby/controllers/field_picker_controller.js +290 -0
- data/app/assets/javascripts/lcp_ruby/controllers/file_upload_controller.js +135 -0
- data/app/assets/javascripts/lcp_ruby/controllers/filter_auto_submit_controller.js +46 -0
- data/app/assets/javascripts/lcp_ruby/controllers/filter_dirty_controller.js +94 -0
- data/app/assets/javascripts/lcp_ruby/controllers/form_actions_controller.js +68 -0
- data/app/assets/javascripts/lcp_ruby/controllers/form_handling_controller.js +67 -0
- data/app/assets/javascripts/lcp_ruby/controllers/import_dialog_controller.js +142 -0
- data/app/assets/javascripts/lcp_ruby/controllers/import_mapper_controller.js +322 -0
- data/app/assets/javascripts/lcp_ruby/controllers/index_sortable_controller.js +388 -0
- data/app/assets/javascripts/lcp_ruby/controllers/inline_create_controller.js +137 -0
- data/app/assets/javascripts/lcp_ruby/controllers/kanban_board_controller.js +290 -0
- data/app/assets/javascripts/lcp_ruby/controllers/menu_controller.js +19 -0
- data/app/assets/javascripts/lcp_ruby/controllers/nested_forms_controller.js +261 -0
- data/app/assets/javascripts/lcp_ruby/controllers/responsive_sidebar_controller.js +161 -0
- data/app/assets/javascripts/lcp_ruby/controllers/responsive_top_nav_controller.js +394 -0
- data/app/assets/javascripts/lcp_ruby/controllers/saved_filters_controller.js +129 -0
- data/app/assets/javascripts/lcp_ruby/controllers/search_controller.js +82 -0
- data/app/assets/javascripts/lcp_ruby/controllers/selection_controller.js +33 -0
- data/app/assets/javascripts/lcp_ruby/controllers/sidebar_controller.js +83 -0
- data/app/assets/javascripts/lcp_ruby/controllers/sidebar_toggle_controller.js +66 -0
- data/app/assets/javascripts/lcp_ruby/controllers/slider_controller.js +26 -0
- data/app/assets/javascripts/lcp_ruby/controllers/submenu_controller.js +55 -0
- data/app/assets/javascripts/lcp_ruby/controllers/tom_select_controller.js +168 -0
- data/app/assets/javascripts/lcp_ruby/controllers/tree_index_controller.js +106 -0
- data/app/assets/javascripts/lcp_ruby/controllers/tree_reparent_controller.js +182 -0
- data/app/assets/javascripts/lcp_ruby/controllers/tree_select_controller.js +119 -0
- data/app/assets/javascripts/lcp_ruby/controllers/ui_components_controller.js +135 -0
- data/app/assets/javascripts/lcp_ruby/controllers/zone_tabs_controller.js +66 -0
- data/app/assets/javascripts/lcp_ruby/dev_toolbar.js +494 -0
- data/app/assets/javascripts/lcp_ruby/i18n.js.erb +29 -0
- data/app/assets/javascripts/lcp_ruby/lucide_init.js +24 -0
- data/app/assets/javascripts/lcp_ruby/stimulus_bootstrap.js +7 -0
- data/app/assets/javascripts/lcp_ruby/utils.js +119 -0
- data/app/assets/javascripts/lcp_ruby/xhr_fetch.js +411 -0
- data/app/assets/stylesheets/lcp_ruby/application.css +1940 -0
- data/app/assets/stylesheets/lcp_ruby/dev_toolbar.css +355 -0
- data/app/controllers/concerns/lcp_ruby/dialog_rendering.rb +167 -0
- data/app/controllers/concerns/lcp_ruby/form_action_execution.rb +249 -0
- data/app/controllers/concerns/lcp_ruby/page_authorization.rb +105 -0
- data/app/controllers/concerns/lcp_ruby/zone_resolution.rb +199 -0
- data/app/controllers/lcp_ruby/actions_controller.rb +481 -0
- data/app/controllers/lcp_ruby/application_controller.rb +59 -0
- data/app/controllers/lcp_ruby/approval_tasks_controller.rb +98 -0
- data/app/controllers/lcp_ruby/auth/base_controller.rb +58 -0
- data/app/controllers/lcp_ruby/auth/callbacks_controller.rb +103 -0
- data/app/controllers/lcp_ruby/auth/passwords_controller.rb +15 -0
- data/app/controllers/lcp_ruby/auth/registrations_controller.rb +37 -0
- data/app/controllers/lcp_ruby/auth/sessions_controller.rb +112 -0
- data/app/controllers/lcp_ruby/custom_fields_controller.rb +370 -0
- data/app/controllers/lcp_ruby/dev_toolbar_controller.rb +197 -0
- data/app/controllers/lcp_ruby/dialogs_controller.rb +199 -0
- data/app/controllers/lcp_ruby/health_controller.rb +23 -0
- data/app/controllers/lcp_ruby/impersonation_controller.rb +32 -0
- data/app/controllers/lcp_ruby/landing_controller.rb +49 -0
- data/app/controllers/lcp_ruby/metrics_controller.rb +17 -0
- data/app/controllers/lcp_ruby/resources_controller.rb +2218 -0
- data/app/controllers/lcp_ruby/saved_filters_controller.rb +221 -0
- data/app/helpers/lcp_ruby/condition_helper.rb +87 -0
- data/app/helpers/lcp_ruby/dashboard_helper.rb +45 -0
- data/app/helpers/lcp_ruby/dev_toolbar_helper.rb +17 -0
- data/app/helpers/lcp_ruby/dialog_helper.rb +27 -0
- data/app/helpers/lcp_ruby/display/card_helper.rb +317 -0
- data/app/helpers/lcp_ruby/display_helper.rb +63 -0
- data/app/helpers/lcp_ruby/display_template_helper.rb +100 -0
- data/app/helpers/lcp_ruby/form_helper.rb +1020 -0
- data/app/helpers/lcp_ruby/grouped_query_helper.rb +107 -0
- data/app/helpers/lcp_ruby/i18n_payload_helper.rb +197 -0
- data/app/helpers/lcp_ruby/layout_helper.rb +832 -0
- data/app/helpers/lcp_ruby/link_through_helper.rb +29 -0
- data/app/helpers/lcp_ruby/oidc_button_helper.rb +59 -0
- data/app/helpers/lcp_ruby/search_helper.rb +31 -0
- data/app/helpers/lcp_ruby/tree_helper.rb +140 -0
- data/app/helpers/lcp_ruby/view_slot_helper.rb +33 -0
- data/app/models/lcp_ruby/user.rb +61 -0
- data/app/views/layouts/lcp_ruby/application.html.erb +168 -0
- data/app/views/layouts/lcp_ruby/auth.html.erb +170 -0
- data/app/views/lcp_ruby/auth/callbacks/failure.html.erb +18 -0
- data/app/views/lcp_ruby/auth/mailer/reset_password_instructions.html.erb +9 -0
- data/app/views/lcp_ruby/auth/passwords/edit.html.erb +34 -0
- data/app/views/lcp_ruby/auth/passwords/new.html.erb +24 -0
- data/app/views/lcp_ruby/auth/registrations/edit.html.erb +48 -0
- data/app/views/lcp_ruby/auth/registrations/new.html.erb +46 -0
- data/app/views/lcp_ruby/auth/sessions/new.html.erb +55 -0
- data/app/views/lcp_ruby/auth/shared/_links.html.erb +13 -0
- data/app/views/lcp_ruby/custom_fields/_manage_row.html.erb +82 -0
- data/app/views/lcp_ruby/custom_fields/manage.html.erb +47 -0
- data/app/views/lcp_ruby/dialogs/_dialog_composite_frame.html.erb +87 -0
- data/app/views/lcp_ruby/dialogs/_dialog_frame.html.erb +60 -0
- data/app/views/lcp_ruby/dialogs/_dialog_show_frame.html.erb +14 -0
- data/app/views/lcp_ruby/dialogs/_show_secret.html.erb +10 -0
- data/app/views/lcp_ruby/dialogs/_success.html.erb +1 -0
- data/app/views/lcp_ruby/errors/not_found.html.erb +5 -0
- data/app/views/lcp_ruby/menu_renderers/_user_menu.html.erb +51 -0
- data/app/views/lcp_ruby/menu_renderers/_user_menu_panel.html.erb +32 -0
- data/app/views/lcp_ruby/navigation/_auto_top.html.erb +16 -0
- data/app/views/lcp_ruby/navigation/_both_sidebar.html.erb +1 -0
- data/app/views/lcp_ruby/navigation/_both_top.html.erb +1 -0
- data/app/views/lcp_ruby/navigation/_impersonation_banner.html.erb +14 -0
- data/app/views/lcp_ruby/navigation/_item_content.html.erb +23 -0
- data/app/views/lcp_ruby/navigation/_link_or_button.html.erb +51 -0
- data/app/views/lcp_ruby/navigation/_mobile_header.html.erb +23 -0
- data/app/views/lcp_ruby/navigation/_panel_item.html.erb +32 -0
- data/app/views/lcp_ruby/navigation/_sidebar.html.erb +38 -0
- data/app/views/lcp_ruby/navigation/_sidebar_item.html.erb +38 -0
- data/app/views/lcp_ruby/navigation/_sidebar_toggle.html.erb +32 -0
- data/app/views/lcp_ruby/navigation/_top.html.erb +26 -0
- data/app/views/lcp_ruby/navigation/_top_item.html.erb +112 -0
- data/app/views/lcp_ruby/navigation/_widget_item.html.erb +14 -0
- data/app/views/lcp_ruby/resources/_action_button.html.erb +138 -0
- data/app/views/lcp_ruby/resources/_advanced_filter.html.erb +55 -0
- data/app/views/lcp_ruby/resources/_api_status_banner.html.erb +11 -0
- data/app/views/lcp_ruby/resources/_association_list.html.erb +132 -0
- data/app/views/lcp_ruby/resources/_audit_history.html.erb +66 -0
- data/app/views/lcp_ruby/resources/_batch_toolbar.html.erb +54 -0
- data/app/views/lcp_ruby/resources/_filter_form.html.erb +57 -0
- data/app/views/lcp_ruby/resources/_form.html.erb +73 -0
- data/app/views/lcp_ruby/resources/_form_action_button.html.erb +20 -0
- data/app/views/lcp_ruby/resources/_form_action_dropdown_item.html.erb +17 -0
- data/app/views/lcp_ruby/resources/_form_actions.html.erb +38 -0
- data/app/views/lcp_ruby/resources/_form_section.html.erb +235 -0
- data/app/views/lcp_ruby/resources/_grid_page.html.erb +17 -0
- data/app/views/lcp_ruby/resources/_grouped_index.html.erb +61 -0
- data/app/views/lcp_ruby/resources/_inline_create_form.html.erb +50 -0
- data/app/views/lcp_ruby/resources/_json_items_list.html.erb +77 -0
- data/app/views/lcp_ruby/resources/_json_nested_fields.html.erb +30 -0
- data/app/views/lcp_ruby/resources/_kanban_card.html.erb +31 -0
- data/app/views/lcp_ruby/resources/_kanban_card_body.html.erb +17 -0
- data/app/views/lcp_ruby/resources/_kanban_column.html.erb +33 -0
- data/app/views/lcp_ruby/resources/_kanban_column_header.html.erb +10 -0
- data/app/views/lcp_ruby/resources/_kanban_index.html.erb +17 -0
- data/app/views/lcp_ruby/resources/_nested_field_cell.html.erb +33 -0
- data/app/views/lcp_ruby/resources/_nested_fields.html.erb +26 -0
- data/app/views/lcp_ruby/resources/_nested_row_content.html.erb +65 -0
- data/app/views/lcp_ruby/resources/_scope_filters.html.erb +71 -0
- data/app/views/lcp_ruby/resources/_semantic_index_page.html.erb +162 -0
- data/app/views/lcp_ruby/resources/_semantic_page.html.erb +121 -0
- data/app/views/lcp_ruby/resources/_show_sections.html.erb +128 -0
- data/app/views/lcp_ruby/resources/_table_index.html.erb +169 -0
- data/app/views/lcp_ruby/resources/_tile_card.html.erb +26 -0
- data/app/views/lcp_ruby/resources/_tile_card_body.html.erb +19 -0
- data/app/views/lcp_ruby/resources/_tiles_index.html.erb +15 -0
- data/app/views/lcp_ruby/resources/_transition_button.html.erb +33 -0
- data/app/views/lcp_ruby/resources/_tree_index.html.erb +61 -0
- data/app/views/lcp_ruby/resources/_view_switcher.html.erb +24 -0
- data/app/views/lcp_ruby/resources/edit.html.erb +9 -0
- data/app/views/lcp_ruby/resources/index.html.erb +80 -0
- data/app/views/lcp_ruby/resources/new.html.erb +9 -0
- data/app/views/lcp_ruby/resources/show.html.erb +37 -0
- data/app/views/lcp_ruby/shared/_breadcrumbs.html.erb +15 -0
- data/app/views/lcp_ruby/shared/_custom_partial_error.html.erb +3 -0
- data/app/views/lcp_ruby/shared/_flash_messages.html.erb +19 -0
- data/app/views/lcp_ruby/slots/index/_advanced_filter.html.erb +3 -0
- data/app/views/lcp_ruby/slots/index/_collection_actions.html.erb +50 -0
- data/app/views/lcp_ruby/slots/index/_manage_all.html.erb +4 -0
- data/app/views/lcp_ruby/slots/index/_pagination_footer.html.erb +71 -0
- data/app/views/lcp_ruby/slots/index/_predefined_filters.html.erb +8 -0
- data/app/views/lcp_ruby/slots/index/_saved_filters.html.erb +87 -0
- data/app/views/lcp_ruby/slots/index/_search.html.erb +52 -0
- data/app/views/lcp_ruby/slots/index/_search_parameter.html.erb +72 -0
- data/app/views/lcp_ruby/slots/index/_sort_dropdown.html.erb +21 -0
- data/app/views/lcp_ruby/slots/index/_summary_bar.html.erb +22 -0
- data/app/views/lcp_ruby/slots/index/_view_switcher.html.erb +1 -0
- data/app/views/lcp_ruby/slots/show/_approval_status.html.erb +8 -0
- data/app/views/lcp_ruby/slots/show/_back_to_list.html.erb +1 -0
- data/app/views/lcp_ruby/slots/show/_copy_url.html.erb +5 -0
- data/app/views/lcp_ruby/slots/show/_single_actions.html.erb +4 -0
- data/app/views/lcp_ruby/slots/show/_view_switcher.html.erb +1 -0
- data/app/views/lcp_ruby/widgets/_approval_status.html.erb +150 -0
- data/app/views/lcp_ruby/widgets/_chart.html.erb +36 -0
- data/app/views/lcp_ruby/widgets/_embed.html.erb +13 -0
- data/app/views/lcp_ruby/widgets/_kpi_card.html.erb +29 -0
- data/app/views/lcp_ruby/widgets/_list.html.erb +17 -0
- data/app/views/lcp_ruby/widgets/_presenter_zone.html.erb +84 -0
- data/app/views/lcp_ruby/widgets/_record_show_zone.html.erb +11 -0
- data/app/views/lcp_ruby/widgets/_text.html.erb +3 -0
- data/app/views/lcp_ruby/widgets/_workflow_graph.html.erb +32 -0
- data/app/views/lcp_ruby/zones/_custom_zone.html.erb +16 -0
- data/app/views/lcp_ruby/zones/_error.html.erb +5 -0
- data/app/views/lcp_ruby/zones/_zone_frame.html.erb +25 -0
- data/app/views/lcp_ruby/zones/_zone_search.html.erb +20 -0
- data/config/locales/cs.yml +859 -0
- data/config/locales/en.yml +731 -0
- data/config/routes.rb +119 -0
- data/docs/README.md +225 -0
- data/docs/architecture.md +212 -0
- data/docs/feature-catalog.md +763 -0
- data/docs/feature-catalog.yml +20911 -0
- data/docs/getting-started.md +1187 -0
- data/docs/guides/action-buttons.md +537 -0
- data/docs/guides/adding-locale.md +353 -0
- data/docs/guides/api-backed-models.md +478 -0
- data/docs/guides/attachments.md +399 -0
- data/docs/guides/auditing.md +333 -0
- data/docs/guides/batch-actions.md +342 -0
- data/docs/guides/composite-pages.md +1290 -0
- data/docs/guides/computed-fields.md +350 -0
- data/docs/guides/conditional-rendering.md +832 -0
- data/docs/guides/custom-actions.md +238 -0
- data/docs/guides/custom-fields.md +439 -0
- data/docs/guides/custom-renderers.md +234 -0
- data/docs/guides/custom-types.md +274 -0
- data/docs/guides/dashboards.md +504 -0
- data/docs/guides/debugging/README.md +38 -0
- data/docs/guides/debugging/controllers.md +147 -0
- data/docs/guides/debugging/data.md +165 -0
- data/docs/guides/debugging/metadata.md +143 -0
- data/docs/guides/debugging/models.md +126 -0
- data/docs/guides/debugging/permissions.md +147 -0
- data/docs/guides/debugging/presenters.md +151 -0
- data/docs/guides/developer-tools.md +418 -0
- data/docs/guides/dialogs.md +392 -0
- data/docs/guides/display-types.md +1430 -0
- data/docs/guides/eager-loading.md +230 -0
- data/docs/guides/event-handlers.md +135 -0
- data/docs/guides/export.md +305 -0
- data/docs/guides/extensibility.md +761 -0
- data/docs/guides/groups.md +220 -0
- data/docs/guides/hierarchical-authorization.md +427 -0
- data/docs/guides/host-application.md +556 -0
- data/docs/guides/host-controller-integration.md +473 -0
- data/docs/guides/impersonation.md +83 -0
- data/docs/guides/import.md +165 -0
- data/docs/guides/inherited-permissions.md +459 -0
- data/docs/guides/menu.md +373 -0
- data/docs/guides/monitoring.md +254 -0
- data/docs/guides/oidc-setup.md +399 -0
- data/docs/guides/permission-source.md +205 -0
- data/docs/guides/permissions.md +364 -0
- data/docs/guides/presenters.md +2324 -0
- data/docs/guides/record-aliases.md +303 -0
- data/docs/guides/rendering-extension-points.md +280 -0
- data/docs/guides/role-source.md +288 -0
- data/docs/guides/selectbox.md +516 -0
- data/docs/guides/sequences.md +291 -0
- data/docs/guides/soft-delete.md +460 -0
- data/docs/guides/theming.md +129 -0
- data/docs/guides/tiles.md +383 -0
- data/docs/guides/tree-structures.md +297 -0
- data/docs/guides/userstamps.md +288 -0
- data/docs/guides/view-groups.md +259 -0
- data/docs/guides/view-slots.md +352 -0
- data/docs/guides/virtual-columns.md +810 -0
- data/docs/guides/workflow.md +692 -0
- data/docs/reference/api-backed-models.md +404 -0
- data/docs/reference/api-tokens.md +128 -0
- data/docs/reference/auditing.md +277 -0
- data/docs/reference/boot_lifecycle.md +188 -0
- data/docs/reference/cascading_selects.md +189 -0
- data/docs/reference/condition-operators.md +445 -0
- data/docs/reference/custom-fields.md +483 -0
- data/docs/reference/dialogs.md +286 -0
- data/docs/reference/doctor.md +168 -0
- data/docs/reference/dynamic-references.md +95 -0
- data/docs/reference/eager-loading.md +192 -0
- data/docs/reference/engine-configuration.md +989 -0
- data/docs/reference/export.md +309 -0
- data/docs/reference/forms.md +68 -0
- data/docs/reference/groups.md +176 -0
- data/docs/reference/host-controller-integration.md +342 -0
- data/docs/reference/i18n.md +497 -0
- data/docs/reference/i18n_check.md +351 -0
- data/docs/reference/import.md +260 -0
- data/docs/reference/invariant_check.md +216 -0
- data/docs/reference/menu.md +985 -0
- data/docs/reference/model-dsl.md +1157 -0
- data/docs/reference/models.md +2972 -0
- data/docs/reference/monitoring.md +222 -0
- data/docs/reference/oidc-bearer.md +269 -0
- data/docs/reference/oidc.md +407 -0
- data/docs/reference/page_filters.md +328 -0
- data/docs/reference/pages.md +1375 -0
- data/docs/reference/permission-source.md +185 -0
- data/docs/reference/permissions.md +715 -0
- data/docs/reference/presenter-dsl.md +1719 -0
- data/docs/reference/presenters.md +3627 -0
- data/docs/reference/role-source.md +227 -0
- data/docs/reference/theme-variables.md +139 -0
- data/docs/reference/tree-structures.md +374 -0
- data/docs/reference/types.md +470 -0
- data/docs/reference/view-groups.md +347 -0
- data/docs/reference/view-slots.md +228 -0
- data/docs/reference/virtual_forms.md +196 -0
- data/docs/reference/workflow-approvals.md +387 -0
- data/docs/reference/workflow.md +651 -0
- data/examples/crm/Gemfile +9 -0
- data/examples/crm/Gemfile.lock +417 -0
- data/examples/crm/Rakefile +2 -0
- data/examples/crm/app/actions/activity/complete.rb +20 -0
- data/examples/crm/app/actions/deal/close_won.rb +20 -0
- data/examples/crm/app/assets/config/manifest.js +3 -0
- data/examples/crm/app/controllers/application_controller.rb +9 -0
- data/examples/crm/app/event_handlers/deal/on_stage_change.rb +17 -0
- data/examples/crm/app/lcp_services/computed/weighted_deal_value.rb +13 -0
- data/examples/crm/app/lcp_services/data_providers/active_contacts_count.rb +14 -0
- data/examples/crm/app/lcp_services/data_providers/open_deals_count.rb +14 -0
- data/examples/crm/app/lcp_services/data_providers/pending_activities_count.rb +15 -0
- data/examples/crm/app/lcp_services/data_providers/pipeline_value.rb +27 -0
- data/examples/crm/app/lcp_services/data_providers/won_deals_count.rb +14 -0
- data/examples/crm/app/lcp_services/defaults/thirty_days_out.rb +11 -0
- data/examples/crm/app/lcp_services/transforms/titlecase.rb +11 -0
- data/examples/crm/app/lcp_services/validators/deal_credit_limit.rb +19 -0
- data/examples/crm/app/lcp_services/validators/deal_documents_required.rb +17 -0
- data/examples/crm/app/renderers/conditional_badge.rb +39 -0
- data/examples/crm/bin/rails +4 -0
- data/examples/crm/bin/rake +4 -0
- data/examples/crm/config/application.rb +31 -0
- data/examples/crm/config/boot.rb +2 -0
- data/examples/crm/config/database.yml +12 -0
- data/examples/crm/config/environment.rb +2 -0
- data/examples/crm/config/initializers/lcp_ruby.rb +45 -0
- data/examples/crm/config/lcp_ruby/menu.yml +53 -0
- data/examples/crm/config/lcp_ruby/models/activity.rb +43 -0
- data/examples/crm/config/lcp_ruby/models/city.rb +19 -0
- data/examples/crm/config/lcp_ruby/models/company.rb +65 -0
- data/examples/crm/config/lcp_ruby/models/contact.rb +62 -0
- data/examples/crm/config/lcp_ruby/models/country.rb +22 -0
- data/examples/crm/config/lcp_ruby/models/custom_field_definition.rb +60 -0
- data/examples/crm/config/lcp_ruby/models/deal.rb +85 -0
- data/examples/crm/config/lcp_ruby/models/deal_category.rb +15 -0
- data/examples/crm/config/lcp_ruby/models/gapfree_sequence.rb +17 -0
- data/examples/crm/config/lcp_ruby/models/region.rb +15 -0
- data/examples/crm/config/lcp_ruby/models/saved_filter.rb +50 -0
- data/examples/crm/config/lcp_ruby/pages/activity_quick_log.yml +19 -0
- data/examples/crm/config/lcp_ruby/pages/company_detail.yml +127 -0
- data/examples/crm/config/lcp_ruby/pages/deals_overview.yml +65 -0
- data/examples/crm/config/lcp_ruby/permissions/activity.yml +40 -0
- data/examples/crm/config/lcp_ruby/permissions/custom_field_definition.yml +16 -0
- data/examples/crm/config/lcp_ruby/permissions/deal.yml +54 -0
- data/examples/crm/config/lcp_ruby/permissions/default.yml +16 -0
- data/examples/crm/config/lcp_ruby/permissions/gapfree_sequence.yml +6 -0
- data/examples/crm/config/lcp_ruby/permissions/saved_filter.yml +27 -0
- data/examples/crm/config/lcp_ruby/presenters/activity.rb +140 -0
- data/examples/crm/config/lcp_ruby/presenters/activity_quick_form.rb +36 -0
- data/examples/crm/config/lcp_ruby/presenters/activity_short.rb +16 -0
- data/examples/crm/config/lcp_ruby/presenters/activity_tiles.rb +35 -0
- data/examples/crm/config/lcp_ruby/presenters/city.rb +53 -0
- data/examples/crm/config/lcp_ruby/presenters/company.rb +147 -0
- data/examples/crm/config/lcp_ruby/presenters/company_activities_zone.rb +26 -0
- data/examples/crm/config/lcp_ruby/presenters/company_archive.rb +37 -0
- data/examples/crm/config/lcp_ruby/presenters/company_contacts_zone.rb +22 -0
- data/examples/crm/config/lcp_ruby/presenters/company_deals_zone.rb +36 -0
- data/examples/crm/config/lcp_ruby/presenters/company_short.rb +21 -0
- data/examples/crm/config/lcp_ruby/presenters/company_show_zone.rb +38 -0
- data/examples/crm/config/lcp_ruby/presenters/company_sidebar.rb +15 -0
- data/examples/crm/config/lcp_ruby/presenters/company_tiles.rb +35 -0
- data/examples/crm/config/lcp_ruby/presenters/contact.rb +120 -0
- data/examples/crm/config/lcp_ruby/presenters/contact_quick_form.rb +17 -0
- data/examples/crm/config/lcp_ruby/presenters/contact_short.rb +20 -0
- data/examples/crm/config/lcp_ruby/presenters/contact_tiles.rb +34 -0
- data/examples/crm/config/lcp_ruby/presenters/country.rb +44 -0
- data/examples/crm/config/lcp_ruby/presenters/custom_fields.rb +124 -0
- data/examples/crm/config/lcp_ruby/presenters/deal.rb +181 -0
- data/examples/crm/config/lcp_ruby/presenters/deal_category.rb +46 -0
- data/examples/crm/config/lcp_ruby/presenters/deal_overview.rb +6 -0
- data/examples/crm/config/lcp_ruby/presenters/deal_pipeline.rb +18 -0
- data/examples/crm/config/lcp_ruby/presenters/deal_short.rb +25 -0
- data/examples/crm/config/lcp_ruby/presenters/deal_tiles.rb +48 -0
- data/examples/crm/config/lcp_ruby/presenters/region.rb +42 -0
- data/examples/crm/config/lcp_ruby/presenters/save_filter_dialog.rb +17 -0
- data/examples/crm/config/lcp_ruby/presenters/saved_filters.rb +93 -0
- data/examples/crm/config/lcp_ruby/views/activities.yml +16 -0
- data/examples/crm/config/lcp_ruby/views/cities.yml +10 -0
- data/examples/crm/config/lcp_ruby/views/companies.yml +14 -0
- data/examples/crm/config/lcp_ruby/views/contacts.yml +16 -0
- data/examples/crm/config/lcp_ruby/views/countries.yml +8 -0
- data/examples/crm/config/lcp_ruby/views/custom_fields.rb +9 -0
- data/examples/crm/config/lcp_ruby/views/deal_categories.yml +8 -0
- data/examples/crm/config/lcp_ruby/views/deals.yml +19 -0
- data/examples/crm/config/lcp_ruby/views/pipeline.yml +10 -0
- data/examples/crm/config/lcp_ruby/views/regions.yml +10 -0
- data/examples/crm/config/lcp_ruby/views/saved_filters.yml +7 -0
- data/examples/crm/config/locales/cs.yml +338 -0
- data/examples/crm/config/locales/en.yml +353 -0
- data/examples/crm/config/routes.rb +4 -0
- data/examples/crm/config/storage.yml +3 -0
- data/examples/crm/config.ru +2 -0
- data/examples/crm/db/migrate/20260219104942_create_active_storage_tables.active_storage.rb +57 -0
- data/examples/crm/db/schema.rb +245 -0
- data/examples/crm/db/seeds.rb +1111 -0
- data/examples/crm/erd.md +163 -0
- data/examples/hr/Gemfile +9 -0
- data/examples/hr/Gemfile.lock +419 -0
- data/examples/hr/Rakefile +6 -0
- data/examples/hr/app/actions/asset/assign_asset.rb +20 -0
- data/examples/hr/app/actions/asset/return_asset.rb +20 -0
- data/examples/hr/app/actions/candidate/advance.rb +32 -0
- data/examples/hr/app/actions/candidate/hire.rb +20 -0
- data/examples/hr/app/actions/candidate/reject_candidate.rb +20 -0
- data/examples/hr/app/actions/expense_claim/approve.rb +21 -0
- data/examples/hr/app/actions/expense_claim/reject.rb +21 -0
- data/examples/hr/app/actions/expense_claim/submit.rb +20 -0
- data/examples/hr/app/actions/interview/complete_interview.rb +20 -0
- data/examples/hr/app/actions/leave_request/approve.rb +21 -0
- data/examples/hr/app/actions/leave_request/cancel.rb +20 -0
- data/examples/hr/app/actions/leave_request/reject.rb +21 -0
- data/examples/hr/app/assets/config/manifest.js +1 -0
- data/examples/hr/app/assets/stylesheets/application.css +10 -0
- data/examples/hr/app/condition_services/is_own_org_unit.rb +14 -0
- data/examples/hr/app/condition_services/is_own_record.rb +20 -0
- data/examples/hr/app/controllers/application_controller.rb +15 -0
- data/examples/hr/app/event_handlers/asset_assignment/on_create.rb +24 -0
- data/examples/hr/app/event_handlers/candidate/on_status_change.rb +18 -0
- data/examples/hr/app/event_handlers/leave_request/on_status_change.rb +45 -0
- data/examples/hr/app/helpers/application_helper.rb +2 -0
- data/examples/hr/app/javascript/application.js +1 -0
- data/examples/hr/app/jobs/application_job.rb +7 -0
- data/examples/hr/app/lcp_services/computed/employee_tenure.rb +28 -0
- data/examples/hr/app/lcp_services/computed/leave_remaining.rb +13 -0
- data/examples/hr/app/lcp_services/data_providers/headcount_text.rb +14 -0
- data/examples/hr/app/lcp_services/data_providers/open_positions_count.rb +14 -0
- data/examples/hr/app/lcp_services/data_providers/pending_expenses_count.rb +14 -0
- data/examples/hr/app/lcp_services/data_providers/pending_leaves_count.rb +14 -0
- data/examples/hr/app/lcp_services/defaults/current_year.rb +11 -0
- data/examples/hr/app/lcp_services/transforms/titlecase.rb +11 -0
- data/examples/hr/app/lcp_services/validators/expense_receipt_required.rb +17 -0
- data/examples/hr/app/lcp_services/validators/leave_balance_check.rb +37 -0
- data/examples/hr/app/models/application_record.rb +3 -0
- data/examples/hr/app/views/layouts/application.html.erb +29 -0
- data/examples/hr/app/views/pwa/manifest.json.erb +22 -0
- data/examples/hr/app/views/pwa/service-worker.js +26 -0
- data/examples/hr/bin/brakeman +7 -0
- data/examples/hr/bin/bundler-audit +6 -0
- data/examples/hr/bin/ci +6 -0
- data/examples/hr/bin/dev +2 -0
- data/examples/hr/bin/docker-entrypoint +8 -0
- data/examples/hr/bin/importmap +4 -0
- data/examples/hr/bin/jobs +6 -0
- data/examples/hr/bin/kamal +27 -0
- data/examples/hr/bin/rails +4 -0
- data/examples/hr/bin/rake +4 -0
- data/examples/hr/bin/rubocop +8 -0
- data/examples/hr/bin/setup +35 -0
- data/examples/hr/bin/thrust +5 -0
- data/examples/hr/config/application.rb +31 -0
- data/examples/hr/config/boot.rb +2 -0
- data/examples/hr/config/bundler-audit.yml +5 -0
- data/examples/hr/config/cache.yml +16 -0
- data/examples/hr/config/ci.rb +20 -0
- data/examples/hr/config/credentials.yml.enc +1 -0
- data/examples/hr/config/database.yml +36 -0
- data/examples/hr/config/deploy.yml +119 -0
- data/examples/hr/config/environment.rb +5 -0
- data/examples/hr/config/environments/development.rb +66 -0
- data/examples/hr/config/environments/production.rb +74 -0
- data/examples/hr/config/environments/test.rb +45 -0
- data/examples/hr/config/importmap.rb +3 -0
- data/examples/hr/config/initializers/assets.rb +7 -0
- data/examples/hr/config/initializers/content_security_policy.rb +29 -0
- data/examples/hr/config/initializers/filter_parameter_logging.rb +8 -0
- data/examples/hr/config/initializers/inflections.rb +16 -0
- data/examples/hr/config/initializers/lcp_ruby.rb +18 -0
- data/examples/hr/config/lcp_ruby/menu.yml +86 -0
- data/examples/hr/config/lcp_ruby/models/announcement.rb +33 -0
- data/examples/hr/config/lcp_ruby/models/asset.rb +73 -0
- data/examples/hr/config/lcp_ruby/models/asset_assignment.rb +39 -0
- data/examples/hr/config/lcp_ruby/models/audit_log.yml +57 -0
- data/examples/hr/config/lcp_ruby/models/candidate.rb +68 -0
- data/examples/hr/config/lcp_ruby/models/custom_field_definition.rb +60 -0
- data/examples/hr/config/lcp_ruby/models/dashboard.rb +17 -0
- data/examples/hr/config/lcp_ruby/models/document.rb +38 -0
- data/examples/hr/config/lcp_ruby/models/employee.rb +128 -0
- data/examples/hr/config/lcp_ruby/models/employee_skill.rb +29 -0
- data/examples/hr/config/lcp_ruby/models/expense_claim.rb +70 -0
- data/examples/hr/config/lcp_ruby/models/goal.rb +48 -0
- data/examples/hr/config/lcp_ruby/models/group.rb +37 -0
- data/examples/hr/config/lcp_ruby/models/group_membership.rb +26 -0
- data/examples/hr/config/lcp_ruby/models/interview.rb +54 -0
- data/examples/hr/config/lcp_ruby/models/job_posting.rb +67 -0
- data/examples/hr/config/lcp_ruby/models/leave_balance.rb +31 -0
- data/examples/hr/config/lcp_ruby/models/leave_request.rb +52 -0
- data/examples/hr/config/lcp_ruby/models/leave_type.rb +35 -0
- data/examples/hr/config/lcp_ruby/models/organization_unit.rb +42 -0
- data/examples/hr/config/lcp_ruby/models/performance_review.rb +59 -0
- data/examples/hr/config/lcp_ruby/models/position.rb +43 -0
- data/examples/hr/config/lcp_ruby/models/skill.rb +27 -0
- data/examples/hr/config/lcp_ruby/models/training_course.rb +53 -0
- data/examples/hr/config/lcp_ruby/models/training_enrollment.rb +35 -0
- data/examples/hr/config/lcp_ruby/pages/dashboard.yml +101 -0
- data/examples/hr/config/lcp_ruby/permissions/announcement.yml +25 -0
- data/examples/hr/config/lcp_ruby/permissions/asset.yml +35 -0
- data/examples/hr/config/lcp_ruby/permissions/audit_log.yml +28 -0
- data/examples/hr/config/lcp_ruby/permissions/candidate.yml +25 -0
- data/examples/hr/config/lcp_ruby/permissions/custom_field_definition.yml +28 -0
- data/examples/hr/config/lcp_ruby/permissions/dashboard.yml +25 -0
- data/examples/hr/config/lcp_ruby/permissions/default.yml +25 -0
- data/examples/hr/config/lcp_ruby/permissions/document.yml +37 -0
- data/examples/hr/config/lcp_ruby/permissions/employee.yml +55 -0
- data/examples/hr/config/lcp_ruby/permissions/expense_claim.yml +45 -0
- data/examples/hr/config/lcp_ruby/permissions/group.yml +27 -0
- data/examples/hr/config/lcp_ruby/permissions/job_posting.yml +34 -0
- data/examples/hr/config/lcp_ruby/permissions/leave_request.yml +45 -0
- data/examples/hr/config/lcp_ruby/permissions/performance_review.yml +42 -0
- data/examples/hr/config/lcp_ruby/presenters/announcement.rb +47 -0
- data/examples/hr/config/lcp_ruby/presenters/asset.rb +69 -0
- data/examples/hr/config/lcp_ruby/presenters/asset_assignment.rb +47 -0
- data/examples/hr/config/lcp_ruby/presenters/audit_logs.yml +43 -0
- data/examples/hr/config/lcp_ruby/presenters/candidate.rb +71 -0
- data/examples/hr/config/lcp_ruby/presenters/custom_fields.rb +124 -0
- data/examples/hr/config/lcp_ruby/presenters/dashboard.rb +37 -0
- data/examples/hr/config/lcp_ruby/presenters/document.rb +46 -0
- data/examples/hr/config/lcp_ruby/presenters/employee.rb +167 -0
- data/examples/hr/config/lcp_ruby/presenters/employee_archive.rb +38 -0
- data/examples/hr/config/lcp_ruby/presenters/employee_directory.rb +27 -0
- data/examples/hr/config/lcp_ruby/presenters/employee_skill.rb +57 -0
- data/examples/hr/config/lcp_ruby/presenters/expense_claim.rb +76 -0
- data/examples/hr/config/lcp_ruby/presenters/goal.rb +60 -0
- data/examples/hr/config/lcp_ruby/presenters/group.rb +48 -0
- data/examples/hr/config/lcp_ruby/presenters/interview.rb +59 -0
- data/examples/hr/config/lcp_ruby/presenters/job_posting.rb +73 -0
- data/examples/hr/config/lcp_ruby/presenters/leave_balance.rb +50 -0
- data/examples/hr/config/lcp_ruby/presenters/leave_request.rb +89 -0
- data/examples/hr/config/lcp_ruby/presenters/leave_type.rb +52 -0
- data/examples/hr/config/lcp_ruby/presenters/organization_unit.rb +56 -0
- data/examples/hr/config/lcp_ruby/presenters/performance_review.rb +87 -0
- data/examples/hr/config/lcp_ruby/presenters/position.rb +54 -0
- data/examples/hr/config/lcp_ruby/presenters/skill.rb +45 -0
- data/examples/hr/config/lcp_ruby/presenters/training_course.rb +61 -0
- data/examples/hr/config/lcp_ruby/presenters/training_enrollment.rb +49 -0
- data/examples/hr/config/lcp_ruby/views/announcements.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/asset_assignments.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/assets.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/audit_logs.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/candidates.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/custom_fields.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/dashboard.yml +6 -0
- data/examples/hr/config/lcp_ruby/views/documents.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/employee_skills.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/employees.yml +14 -0
- data/examples/hr/config/lcp_ruby/views/expense_claims.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/goals.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/groups.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/interviews.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/job_postings.yml +6 -0
- data/examples/hr/config/lcp_ruby/views/leave_balances.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/leave_requests.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/leave_types.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/organization_units.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/performance_reviews.yml +10 -0
- data/examples/hr/config/lcp_ruby/views/positions.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/skills.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/training_courses.yml +8 -0
- data/examples/hr/config/lcp_ruby/views/training_enrollments.yml +10 -0
- data/examples/hr/config/locales/cs.yml +496 -0
- data/examples/hr/config/locales/en.yml +740 -0
- data/examples/hr/config/locales/sk.yml +496 -0
- data/examples/hr/config/puma.rb +42 -0
- data/examples/hr/config/queue.yml +18 -0
- data/examples/hr/config/recurring.yml +15 -0
- data/examples/hr/config/routes.rb +4 -0
- data/examples/hr/config/storage.yml +27 -0
- data/examples/hr/config.ru +6 -0
- data/examples/hr/db/cache_schema.rb +12 -0
- data/examples/hr/db/migrate/20260303202825_create_active_storage_tables.active_storage.rb +57 -0
- data/examples/hr/db/queue_schema.rb +129 -0
- data/examples/hr/db/schema.rb +588 -0
- data/examples/hr/db/seeds.rb +932 -0
- data/examples/hr/erd.md +396 -0
- data/examples/hr/public/400.html +135 -0
- data/examples/hr/public/404.html +135 -0
- data/examples/hr/public/406-unsupported-browser.html +135 -0
- data/examples/hr/public/422.html +135 -0
- data/examples/hr/public/500.html +135 -0
- data/examples/hr/public/icon.svg +3 -0
- data/examples/hr/public/robots.txt +1 -0
- data/examples/showcase/Gemfile +15 -0
- data/examples/showcase/Gemfile.lock +425 -0
- data/examples/showcase/Rakefile +2 -0
- data/examples/showcase/app/actions/showcase_batch_task/assign_batch.rb +20 -0
- data/examples/showcase/app/actions/showcase_batch_task/close_task.rb +21 -0
- data/examples/showcase/app/actions/showcase_condition/approve.rb +20 -0
- data/examples/showcase/app/actions/showcase_permission/lock.rb +20 -0
- data/examples/showcase/app/assets/config/manifest.js +3 -0
- data/examples/showcase/app/assets/stylesheets/application.css +27 -0
- data/examples/showcase/app/condition_services/budget_threshold.rb +16 -0
- data/examples/showcase/app/condition_services/overdue_check.rb +11 -0
- data/examples/showcase/app/controllers/application_controller.rb +2 -0
- data/examples/showcase/app/controllers/docs_controller.rb +48 -0
- data/examples/showcase/app/controllers/host_inventory_items_managed_controller.rb +90 -0
- data/examples/showcase/app/controllers/host_inventory_items_report_controller.rb +39 -0
- data/examples/showcase/app/controllers/host_inventory_items_wizard_controller.rb +50 -0
- data/examples/showcase/app/data_providers/showcase_amount_provider.rb +52 -0
- data/examples/showcase/app/data_providers/weather_station_provider.rb +140 -0
- data/examples/showcase/app/event_handlers/showcase_model/on_status_change.rb +17 -0
- data/examples/showcase/app/event_handlers/showcase_permission/on_status_change.rb +17 -0
- data/examples/showcase/app/event_handlers/showcase_workflow/log_review_exit.rb +16 -0
- data/examples/showcase/app/event_handlers/showcase_workflow/notify_reviewers.rb +15 -0
- data/examples/showcase/app/event_handlers/showcase_workflow/request_submitted.rb +15 -0
- data/examples/showcase/app/lcp_metrics/showcase_metrics.rb +31 -0
- data/examples/showcase/app/lcp_services/computed/showcase_score.rb +18 -0
- data/examples/showcase/app/lcp_services/computed/showcase_total.rb +13 -0
- data/examples/showcase/app/lcp_services/defaults/one_week_from_now.rb +11 -0
- data/examples/showcase/app/lcp_services/menu_items/recent_announcements.rb +36 -0
- data/examples/showcase/app/lcp_services/virtual_columns/project_health.rb +26 -0
- data/examples/showcase/app/model_extensions/lcp_error_log_extension.rb +12 -0
- data/examples/showcase/app/models/host_inventory_item.rb +20 -0
- data/examples/showcase/app/models/platform_profile.rb +27 -0
- data/examples/showcase/app/models/platform_user.rb +5 -0
- data/examples/showcase/app/views/docs/show.html.erb +19 -0
- data/examples/showcase/app/views/host_inventory_items_report/index.html.erb +61 -0
- data/examples/showcase/app/views/host_inventory_items_report/show.html.erb +39 -0
- data/examples/showcase/app/views/layouts/docs.html.erb +46 -0
- data/examples/showcase/app/views/showcase/menu_renderers/_status_pill.html.erb +17 -0
- data/examples/showcase/app/views/showcase_custom/_activity_timeline.html.erb +37 -0
- data/examples/showcase/app/views/showcase_custom/_card_index.html.erb +74 -0
- data/examples/showcase/app/views/showcase_custom/_detail_show.html.erb +115 -0
- data/examples/showcase/app/views/showcase_custom/_location_map.html.erb +29 -0
- data/examples/showcase/app/views/showcase_custom/_location_view.html.erb +34 -0
- data/examples/showcase/app/views/showcase_custom/_quick_stats.html.erb +50 -0
- data/examples/showcase/app/views/showcase_custom/_stats_sidebar.html.erb +42 -0
- data/examples/showcase/app/views/showcase_custom/_tags_editor.html.erb +48 -0
- data/examples/showcase/bin/rails +4 -0
- data/examples/showcase/bin/rake +4 -0
- data/examples/showcase/config/application.rb +37 -0
- data/examples/showcase/config/boot.rb +2 -0
- data/examples/showcase/config/database.yml +12 -0
- data/examples/showcase/config/environment.rb +2 -0
- data/examples/showcase/config/initializers/devise.rb +5 -0
- data/examples/showcase/config/initializers/lcp_ruby.rb +175 -0
- data/examples/showcase/config/lcp_ruby/auth.yml +60 -0
- data/examples/showcase/config/lcp_ruby/jobs/data_import.yml +7 -0
- data/examples/showcase/config/lcp_ruby/jobs/showcase_cleanup.yml +11 -0
- data/examples/showcase/config/lcp_ruby/jobs/showcase_event_triggered.yml +11 -0
- data/examples/showcase/config/lcp_ruby/jobs/showcase_multi_step.yml +9 -0
- data/examples/showcase/config/lcp_ruby/jobs/showcase_webhook.yml +13 -0
- data/examples/showcase/config/lcp_ruby/menu.yml +249 -0
- data/examples/showcase/config/lcp_ruby/models/_base_document.rb +26 -0
- data/examples/showcase/config/lcp_ruby/models/_categorized_document.rb +19 -0
- data/examples/showcase/config/lcp_ruby/models/_contactable.rb +20 -0
- data/examples/showcase/config/lcp_ruby/models/api_token.rb +23 -0
- data/examples/showcase/config/lcp_ruby/models/article.rb +49 -0
- data/examples/showcase/config/lcp_ruby/models/article_tag.rb +10 -0
- data/examples/showcase/config/lcp_ruby/models/author.rb +16 -0
- data/examples/showcase/config/lcp_ruby/models/batch_operation.yml +79 -0
- data/examples/showcase/config/lcp_ruby/models/batch_operation_item.yml +45 -0
- data/examples/showcase/config/lcp_ruby/models/category.rb +23 -0
- data/examples/showcase/config/lcp_ruby/models/comment.rb +21 -0
- data/examples/showcase/config/lcp_ruby/models/custom_field_definition.rb +59 -0
- data/examples/showcase/config/lcp_ruby/models/department.rb +32 -0
- data/examples/showcase/config/lcp_ruby/models/employee.rb +52 -0
- data/examples/showcase/config/lcp_ruby/models/employee_emergency_contact.rb +24 -0
- data/examples/showcase/config/lcp_ruby/models/employee_profile.rb +18 -0
- data/examples/showcase/config/lcp_ruby/models/employee_skill.rb +10 -0
- data/examples/showcase/config/lcp_ruby/models/export_log.yml +27 -0
- data/examples/showcase/config/lcp_ruby/models/export_profile.yml +37 -0
- data/examples/showcase/config/lcp_ruby/models/feature.rb +76 -0
- data/examples/showcase/config/lcp_ruby/models/gapfree_sequence.rb +17 -0
- data/examples/showcase/config/lcp_ruby/models/group.rb +26 -0
- data/examples/showcase/config/lcp_ruby/models/group_membership.rb +21 -0
- data/examples/showcase/config/lcp_ruby/models/group_role_mapping.rb +14 -0
- data/examples/showcase/config/lcp_ruby/models/host_inventory_item.yml +111 -0
- data/examples/showcase/config/lcp_ruby/models/import_profile.rb +30 -0
- data/examples/showcase/config/lcp_ruby/models/import_row.rb +32 -0
- data/examples/showcase/config/lcp_ruby/models/ingredient_def.rb +11 -0
- data/examples/showcase/config/lcp_ruby/models/lcp_error_log.yml +61 -0
- data/examples/showcase/config/lcp_ruby/models/page_config.rb +19 -0
- data/examples/showcase/config/lcp_ruby/models/permission_config.rb +21 -0
- data/examples/showcase/config/lcp_ruby/models/pipeline.rb +15 -0
- data/examples/showcase/config/lcp_ruby/models/pipeline_stage.rb +17 -0
- data/examples/showcase/config/lcp_ruby/models/platform_profile.rb +104 -0
- data/examples/showcase/config/lcp_ruby/models/profile_setting.rb +17 -0
- data/examples/showcase/config/lcp_ruby/models/profile_tag.rb +19 -0
- data/examples/showcase/config/lcp_ruby/models/project.rb +23 -0
- data/examples/showcase/config/lcp_ruby/models/role.rb +24 -0
- data/examples/showcase/config/lcp_ruby/models/saved_filter.rb +50 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_aggregate.rb +93 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_aggregate_company.rb +14 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_aggregate_item.rb +25 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_announcement.rb +20 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_array.rb +45 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_attachment.rb +49 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_audit_log.yml +44 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_audited_record.rb +20 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_batch_task.rb +27 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_business_unit.rb +26 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_condition.rb +24 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_condition_category.rb +16 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_condition_task.rb +16 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_condition_threshold.rb +13 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_contact.rb +22 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_custom_render.rb +38 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_delete_reason.rb +11 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_division.rb +31 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_extensibility.rb +25 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_field.rb +53 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_form.rb +23 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_form_action.rb +38 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_grade.rb +18 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_hr_employee.rb +90 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_item_class.rb +31 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_job_execution.rb +49 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_memo.rb +23 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_model.rb +74 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_organization.rb +31 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_permission.rb +30 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_person.rb +23 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_positioning.rb +19 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_quick_note.rb +13 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_recipe.rb +17 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_report.rb +32 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_school_class.rb +17 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_search.rb +84 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_sequence.rb +46 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_soft_delete.rb +30 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_soft_delete_item.rb +21 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_student.rb +17 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_type_default.rb +49 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_userstamps.rb +26 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_virtual_field.rb +68 -0
- data/examples/showcase/config/lcp_ruby/models/showcase_workflow.rb +54 -0
- data/examples/showcase/config/lcp_ruby/models/skill.rb +22 -0
- data/examples/showcase/config/lcp_ruby/models/tag.rb +16 -0
- data/examples/showcase/config/lcp_ruby/models/user.rb +54 -0
- data/examples/showcase/config/lcp_ruby/models/weather_station.rb +20 -0
- data/examples/showcase/config/lcp_ruby/models/workflow_approval_request.yml +77 -0
- data/examples/showcase/config/lcp_ruby/models/workflow_approval_step.yml +56 -0
- data/examples/showcase/config/lcp_ruby/models/workflow_approval_task.yml +51 -0
- data/examples/showcase/config/lcp_ruby/models/workflow_audit_log.yml +74 -0
- data/examples/showcase/config/lcp_ruby/pages/article_detail.yml +32 -0
- data/examples/showcase/config/lcp_ruby/pages/author_detail.yml +27 -0
- data/examples/showcase/config/lcp_ruby/pages/category_detail.yml +24 -0
- data/examples/showcase/config/lcp_ruby/pages/chart_showcase.yml +151 -0
- data/examples/showcase/config/lcp_ruby/pages/department_detail.yml +55 -0
- data/examples/showcase/config/lcp_ruby/pages/department_explorer.yml +60 -0
- data/examples/showcase/config/lcp_ruby/pages/employee_overview.yml +106 -0
- data/examples/showcase/config/lcp_ruby/pages/employee_transfer_dialog.yml +24 -0
- data/examples/showcase/config/lcp_ruby/pages/hr_turnover_dashboard.yml +288 -0
- data/examples/showcase/config/lcp_ruby/pages/main_dashboard.yml +142 -0
- data/examples/showcase/config/lcp_ruby/pages/monitoring_dashboard.yml +58 -0
- data/examples/showcase/config/lcp_ruby/pages/pipeline_detail.yml +16 -0
- data/examples/showcase/config/lcp_ruby/pages/showcase_custom_zones.yml +39 -0
- data/examples/showcase/config/lcp_ruby/pages/showcase_form_action_dialog.yml +11 -0
- data/examples/showcase/config/lcp_ruby/pages/workflow_request_detail.yml +34 -0
- data/examples/showcase/config/lcp_ruby/permissions/api_token.yml +26 -0
- data/examples/showcase/config/lcp_ruby/permissions/batch_operation.yml +36 -0
- data/examples/showcase/config/lcp_ruby/permissions/custom_field_definition.yml +15 -0
- data/examples/showcase/config/lcp_ruby/permissions/default.yml +28 -0
- data/examples/showcase/config/lcp_ruby/permissions/export_log.yml +23 -0
- data/examples/showcase/config/lcp_ruby/permissions/export_profile.yml +25 -0
- data/examples/showcase/config/lcp_ruby/permissions/gapfree_sequence.yml +6 -0
- data/examples/showcase/config/lcp_ruby/permissions/group.yml +20 -0
- data/examples/showcase/config/lcp_ruby/permissions/group_membership.yml +20 -0
- data/examples/showcase/config/lcp_ruby/permissions/group_role_mapping.yml +20 -0
- data/examples/showcase/config/lcp_ruby/permissions/host_inventory_item.yml +34 -0
- data/examples/showcase/config/lcp_ruby/permissions/import_profile.yml +29 -0
- data/examples/showcase/config/lcp_ruby/permissions/import_row.yml +17 -0
- data/examples/showcase/config/lcp_ruby/permissions/lcp_error_log.yml +8 -0
- data/examples/showcase/config/lcp_ruby/permissions/page_config.yml +15 -0
- data/examples/showcase/config/lcp_ruby/permissions/permission_config.yml +15 -0
- data/examples/showcase/config/lcp_ruby/permissions/platform_profile.yml +23 -0
- data/examples/showcase/config/lcp_ruby/permissions/profile_setting.yml +23 -0
- data/examples/showcase/config/lcp_ruby/permissions/profile_tag.yml +23 -0
- data/examples/showcase/config/lcp_ruby/permissions/role.yml +20 -0
- data/examples/showcase/config/lcp_ruby/permissions/saved_filter.yml +39 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_announcement.yml +22 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_audit_log.yml +15 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_audited_record.yml +15 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_batch_task.yml +31 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_condition.yml +54 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_contact.yml +21 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_custom_render.yml +21 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_delete_reason.yml +12 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_form_action.yml +26 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_grade.yml +33 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_job_execution.yml +23 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_permission.yml +47 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_quick_note.yml +12 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_school_class.yml +37 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_student.yml +43 -0
- data/examples/showcase/config/lcp_ruby/permissions/showcase_workflow.yml +34 -0
- data/examples/showcase/config/lcp_ruby/permissions/workflow_approval_request.yml +18 -0
- data/examples/showcase/config/lcp_ruby/permissions/workflow_approval_step.yml +18 -0
- data/examples/showcase/config/lcp_ruby/permissions/workflow_approval_task.yml +18 -0
- data/examples/showcase/config/lcp_ruby/permissions/workflow_audit_log.yml +19 -0
- data/examples/showcase/config/lcp_ruby/presenters/announcements.rb +59 -0
- data/examples/showcase/config/lcp_ruby/presenters/approval_requests.rb +69 -0
- data/examples/showcase/config/lcp_ruby/presenters/approval_steps.rb +59 -0
- data/examples/showcase/config/lcp_ruby/presenters/approval_tasks.rb +65 -0
- data/examples/showcase/config/lcp_ruby/presenters/article_comments_zone.rb +12 -0
- data/examples/showcase/config/lcp_ruby/presenters/article_related_zone.rb +15 -0
- data/examples/showcase/config/lcp_ruby/presenters/articles.rb +149 -0
- data/examples/showcase/config/lcp_ruby/presenters/articles_tiles.rb +30 -0
- data/examples/showcase/config/lcp_ruby/presenters/author_articles_zone.rb +12 -0
- data/examples/showcase/config/lcp_ruby/presenters/author_show_zone.rb +12 -0
- data/examples/showcase/config/lcp_ruby/presenters/authors.rb +39 -0
- data/examples/showcase/config/lcp_ruby/presenters/batch_operation_items.yml +45 -0
- data/examples/showcase/config/lcp_ruby/presenters/batch_operations.yml +66 -0
- data/examples/showcase/config/lcp_ruby/presenters/categories.rb +50 -0
- data/examples/showcase/config/lcp_ruby/presenters/category_articles_zone.rb +20 -0
- data/examples/showcase/config/lcp_ruby/presenters/category_children_zone.rb +10 -0
- data/examples/showcase/config/lcp_ruby/presenters/comment_quick_add_dialog.rb +15 -0
- data/examples/showcase/config/lcp_ruby/presenters/custom_fields.rb +124 -0
- data/examples/showcase/config/lcp_ruby/presenters/dashboard_employees.rb +16 -0
- data/examples/showcase/config/lcp_ruby/presenters/delete_reason_dialog.rb +13 -0
- data/examples/showcase/config/lcp_ruby/presenters/departments.rb +55 -0
- data/examples/showcase/config/lcp_ruby/presenters/dept_add_employee_dialog.rb +19 -0
- data/examples/showcase/config/lcp_ruby/presenters/dept_children_zone.rb +10 -0
- data/examples/showcase/config/lcp_ruby/presenters/dept_detail_zone.rb +14 -0
- data/examples/showcase/config/lcp_ruby/presenters/dept_employees_zone.rb +16 -0
- data/examples/showcase/config/lcp_ruby/presenters/dept_list_selection_zone.rb +19 -0
- data/examples/showcase/config/lcp_ruby/presenters/employee_overview_index_zone.rb +36 -0
- data/examples/showcase/config/lcp_ruby/presenters/employee_quick_add_dialog.rb +14 -0
- data/examples/showcase/config/lcp_ruby/presenters/employee_show_zone.rb +20 -0
- data/examples/showcase/config/lcp_ruby/presenters/employee_transfer_form_zone.rb +19 -0
- data/examples/showcase/config/lcp_ruby/presenters/employees.rb +165 -0
- data/examples/showcase/config/lcp_ruby/presenters/employees_tiles.rb +33 -0
- data/examples/showcase/config/lcp_ruby/presenters/export_logs.yml +58 -0
- data/examples/showcase/config/lcp_ruby/presenters/export_profiles.yml +70 -0
- data/examples/showcase/config/lcp_ruby/presenters/extensibility_quick_edit_dialog.rb +13 -0
- data/examples/showcase/config/lcp_ruby/presenters/feature_kanban.rb +30 -0
- data/examples/showcase/config/lcp_ruby/presenters/features_card.rb +179 -0
- data/examples/showcase/config/lcp_ruby/presenters/features_hub.rb +44 -0
- data/examples/showcase/config/lcp_ruby/presenters/features_table.rb +37 -0
- data/examples/showcase/config/lcp_ruby/presenters/features_tiles.rb +48 -0
- data/examples/showcase/config/lcp_ruby/presenters/group_memberships.rb +54 -0
- data/examples/showcase/config/lcp_ruby/presenters/group_role_mappings.rb +48 -0
- data/examples/showcase/config/lcp_ruby/presenters/groups.rb +74 -0
- data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items.rb +99 -0
- data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items_managed.rb +84 -0
- data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items_report.rb +40 -0
- data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items_wizard.rb +76 -0
- data/examples/showcase/config/lcp_ruby/presenters/import_profiles.rb +61 -0
- data/examples/showcase/config/lcp_ruby/presenters/import_rows.rb +39 -0
- data/examples/showcase/config/lcp_ruby/presenters/lcp_error_logs.yml +46 -0
- data/examples/showcase/config/lcp_ruby/presenters/my_api_tokens.rb +35 -0
- data/examples/showcase/config/lcp_ruby/presenters/my_api_tokens_create_dialog.rb +27 -0
- data/examples/showcase/config/lcp_ruby/presenters/my_employee_profile.rb +24 -0
- data/examples/showcase/config/lcp_ruby/presenters/my_settings.rb +50 -0
- data/examples/showcase/config/lcp_ruby/presenters/page_configs.rb +56 -0
- data/examples/showcase/config/lcp_ruby/presenters/permission_configs.rb +58 -0
- data/examples/showcase/config/lcp_ruby/presenters/pipeline_edit_zone.rb +11 -0
- data/examples/showcase/config/lcp_ruby/presenters/pipeline_stages.rb +51 -0
- data/examples/showcase/config/lcp_ruby/presenters/pipeline_stages_zone.rb +11 -0
- data/examples/showcase/config/lcp_ruby/presenters/pipelines.rb +40 -0
- data/examples/showcase/config/lcp_ruby/presenters/platform_profiles.rb +90 -0
- data/examples/showcase/config/lcp_ruby/presenters/projects.rb +58 -0
- data/examples/showcase/config/lcp_ruby/presenters/quick_note_dialog.rb +14 -0
- data/examples/showcase/config/lcp_ruby/presenters/roles.rb +60 -0
- data/examples/showcase/config/lcp_ruby/presenters/save_filter_dialog.rb +17 -0
- data/examples/showcase/config/lcp_ruby/presenters/saved_filters.rb +94 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_aggregate_items.rb +61 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_aggregates.rb +115 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_aggregates_tiles.rb +44 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_amount_kanban.rb +31 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_arrays.rb +140 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_attachments.rb +66 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_audit_logs.rb +46 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_audited_records.rb +58 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_batch_tasks.rb +97 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_batch_tasks_archive.rb +52 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_business_units.rb +43 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_conditions.rb +195 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_contacts.rb +82 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_custom_render_with.rb +50 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_custom_sections.rb +88 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_custom_zones_main.rb +75 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_divisions.rb +53 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_extensibility.rb +48 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_fields_card.rb +34 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_fields_table.rb +128 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_fields_tiles.rb +42 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_form_action_dialog.rb +27 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_form_actions.rb +132 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_form_actions_overflow.rb +76 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_forms.rb +110 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_grades.rb +38 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_hr_employees.rb +84 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_item_classes.rb +120 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_job_executions.rb +150 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_memos.rb +96 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_models.rb +112 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_organizations.rb +106 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_people.rb +97 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_permissions.rb +84 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_positioning.rb +61 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_recipes.rb +105 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_recipes_raw.rb +32 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_reports.rb +109 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_school_classes.rb +34 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_searches.rb +226 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_sequences.rb +67 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_soft_delete.rb +88 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_soft_delete_archive.rb +52 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_soft_delete_items.rb +47 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_students.rb +33 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_type_defaults.rb +92 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_userstamps.rb +76 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_virtual_fields.rb +104 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_workflow_admin.rb +24 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_workflow_kanban.rb +36 -0
- data/examples/showcase/config/lcp_ruby/presenters/showcase_workflows.rb +103 -0
- data/examples/showcase/config/lcp_ruby/presenters/tags.rb +35 -0
- data/examples/showcase/config/lcp_ruby/presenters/users.rb +61 -0
- data/examples/showcase/config/lcp_ruby/presenters/weather_stations.rb +60 -0
- data/examples/showcase/config/lcp_ruby/presenters/workflow_audit_logs.rb +76 -0
- data/examples/showcase/config/lcp_ruby/presenters/workflow_request_audit_zone.rb +28 -0
- data/examples/showcase/config/lcp_ruby/theme.yml +2 -0
- data/examples/showcase/config/lcp_ruby/types/currency.yml +15 -0
- data/examples/showcase/config/lcp_ruby/types/percentage.yml +16 -0
- data/examples/showcase/config/lcp_ruby/types/rating.yml +20 -0
- data/examples/showcase/config/lcp_ruby/views/announcements.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/approval_requests.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/approval_steps.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/approval_tasks.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/articles.yml +12 -0
- data/examples/showcase/config/lcp_ruby/views/authors.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/batch_operation_items.yml +6 -0
- data/examples/showcase/config/lcp_ruby/views/batch_operations.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/categories.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/custom_fields.rb +8 -0
- data/examples/showcase/config/lcp_ruby/views/dashboard.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/department_explorer.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/departments.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/employee_overview.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/employees.yml +12 -0
- data/examples/showcase/config/lcp_ruby/views/export_logs.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/export_profiles.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/features.yml +19 -0
- data/examples/showcase/config/lcp_ruby/views/group_memberships.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/group_role_mappings.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/groups.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/host_inventory_items.yml +16 -0
- data/examples/showcase/config/lcp_ruby/views/hr_turnover_dashboard.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/import_profiles.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/import_rows.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/lcp_error_logs.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/monitoring.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/my_api_tokens.rb +9 -0
- data/examples/showcase/config/lcp_ruby/views/page_configs.yml +11 -0
- data/examples/showcase/config/lcp_ruby/views/permission_configs.yml +11 -0
- data/examples/showcase/config/lcp_ruby/views/pipeline_stages.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/pipelines.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/platform_profiles.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/projects.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/roles.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/saved_filters.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_aggregate_items.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_aggregates.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_arrays.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_attachments.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_audit_logs.yml +11 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_audited_records.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_batch_tasks.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_business_units.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_conditions.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_contacts.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_custom_render_with.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_custom_sections.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_custom_zones.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_divisions.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_extensibility.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_fields.yml +13 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_form_actions.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_forms.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_grades.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_hr_employees.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_item_classes.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_job_executions.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_memos.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_models.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_organizations.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_people.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_permissions.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_positioning.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_recipes.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_reports.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_school_classes.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_searches.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_sequences.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_soft_delete.yml +10 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_soft_delete_items.yml +8 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_students.yml +9 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_userstamps.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_virtual_fields.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/showcase_workflows.yml +16 -0
- data/examples/showcase/config/lcp_ruby/views/tags.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/users.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/weather_stations.yml +7 -0
- data/examples/showcase/config/lcp_ruby/views/workflow_audit_logs.yml +9 -0
- data/examples/showcase/config/lcp_ruby/workflows/showcase_form_action.rb +48 -0
- data/examples/showcase/config/lcp_ruby/workflows/showcase_workflow.rb +199 -0
- data/examples/showcase/config/locales/cs.yml +2818 -0
- data/examples/showcase/config/locales/en.yml +67 -0
- data/examples/showcase/config/locales/lcp_ruby/api_tokens.cs.yml +46 -0
- data/examples/showcase/config/locales/lcp_ruby/api_tokens.en.yml +49 -0
- data/examples/showcase/config/routes.rb +21 -0
- data/examples/showcase/config/storage.yml +3 -0
- data/examples/showcase/config.ru +2 -0
- data/examples/showcase/db/migrate/20260219124321_create_active_storage_tables.active_storage.rb +57 -0
- data/examples/showcase/db/migrate/20260220072723_create_lcp_ruby_users.rb +42 -0
- data/examples/showcase/db/migrate/20260406120000_create_host_inventory_items.rb +32 -0
- data/examples/showcase/db/migrate/20260428134542_add_oidc_columns_to_lcp_ruby_users.rb +13 -0
- data/examples/showcase/db/migrate/20260502120000_create_platform_profiles.rb +19 -0
- data/examples/showcase/db/schema.rb +1222 -0
- data/examples/showcase/db/seeds.rb +3085 -0
- data/examples/showcase/erd.md +567 -0
- data/examples/showcase/test/fixtures/import_articles.csv +4 -0
- data/examples/showcase/test/fixtures/import_employees.csv +4 -0
- data/examples/todo/Gemfile +8 -0
- data/examples/todo/Gemfile.lock +415 -0
- data/examples/todo/Rakefile +2 -0
- data/examples/todo/app/assets/config/manifest.js +1 -0
- data/examples/todo/app/controllers/application_controller.rb +6 -0
- data/examples/todo/app/lcp_services/defaults/one_week_from_now.rb +11 -0
- data/examples/todo/bin/rails +4 -0
- data/examples/todo/bin/rake +4 -0
- data/examples/todo/config/application.rb +31 -0
- data/examples/todo/config/boot.rb +2 -0
- data/examples/todo/config/database.yml +12 -0
- data/examples/todo/config/environment.rb +2 -0
- data/examples/todo/config/lcp_ruby/models/todo_item.yml +67 -0
- data/examples/todo/config/lcp_ruby/models/todo_list.yml +49 -0
- data/examples/todo/config/lcp_ruby/permissions/default.yml +10 -0
- data/examples/todo/config/lcp_ruby/permissions/todo_item.yml +21 -0
- data/examples/todo/config/lcp_ruby/presenters/todo_item.yml +75 -0
- data/examples/todo/config/lcp_ruby/presenters/todo_list.yml +68 -0
- data/examples/todo/config/lcp_ruby/views/todo_items.yml +11 -0
- data/examples/todo/config/lcp_ruby/views/todo_lists.yml +9 -0
- data/examples/todo/config/routes.rb +4 -0
- data/examples/todo/config/storage.yml +3 -0
- data/examples/todo/config.ru +2 -0
- data/examples/todo/db/migrate/20260219103416_create_active_storage_tables.active_storage.rb +57 -0
- data/examples/todo/db/schema.rb +63 -0
- data/examples/todo/db/seeds.rb +24 -0
- data/examples/todo/erd.md +21 -0
- data/exe/lcp +33 -0
- data/lib/generators/lcp_ruby/agent_setup_generator.rb +102 -0
- data/lib/generators/lcp_ruby/api_tokens_generator.rb +102 -0
- data/lib/generators/lcp_ruby/auditing_generator.rb +54 -0
- data/lib/generators/lcp_ruby/background_jobs_generator.rb +61 -0
- data/lib/generators/lcp_ruby/batch_operations_generator.rb +62 -0
- data/lib/generators/lcp_ruby/claude_skills_generator.rb +47 -0
- data/lib/generators/lcp_ruby/custom_fields_generator.rb +54 -0
- data/lib/generators/lcp_ruby/dsl_to_yaml.rb +72 -0
- data/lib/generators/lcp_ruby/entity/color_palette.rb +22 -0
- data/lib/generators/lcp_ruby/entity/field_descriptor.rb +24 -0
- data/lib/generators/lcp_ruby/entity/field_token_parser.rb +101 -0
- data/lib/generators/lcp_ruby/entity/role_discovery.rb +45 -0
- data/lib/generators/lcp_ruby/entity_generator.rb +1104 -0
- data/lib/generators/lcp_ruby/export_generator.rb +71 -0
- data/lib/generators/lcp_ruby/format_support.rb +56 -0
- data/lib/generators/lcp_ruby/gapfree_sequences_generator.rb +64 -0
- data/lib/generators/lcp_ruby/groups_generator.rb +94 -0
- data/lib/generators/lcp_ruby/host_controller_generator.rb +202 -0
- data/lib/generators/lcp_ruby/import_generator.rb +96 -0
- data/lib/generators/lcp_ruby/install_auth_generator.rb +432 -0
- data/lib/generators/lcp_ruby/install_generator.rb +319 -0
- data/lib/generators/lcp_ruby/monitoring_generator.rb +58 -0
- data/lib/generators/lcp_ruby/oidc_role_mappings_generator.rb +60 -0
- data/lib/generators/lcp_ruby/pages_generator.rb +66 -0
- data/lib/generators/lcp_ruby/permission_source_generator.rb +66 -0
- data/lib/generators/lcp_ruby/role_model_generator.rb +73 -0
- data/lib/generators/lcp_ruby/saved_filters_generator.rb +62 -0
- data/lib/generators/lcp_ruby/templates/add_oidc_columns_to_lcp_ruby_users.rb.erb +13 -0
- data/lib/generators/lcp_ruby/templates/agent_setup/agents_md.md +3 -0
- data/lib/generators/lcp_ruby/templates/agent_setup/claude_md.md +12 -0
- data/lib/generators/lcp_ruby/templates/api_tokens/create_dialog.rb +31 -0
- data/lib/generators/lcp_ruby/templates/api_tokens/locales.en.yml +43 -0
- data/lib/generators/lcp_ruby/templates/api_tokens/model.rb +23 -0
- data/lib/generators/lcp_ruby/templates/api_tokens/permissions.yml +30 -0
- data/lib/generators/lcp_ruby/templates/api_tokens/presenter.rb +38 -0
- data/lib/generators/lcp_ruby/templates/api_tokens/view_group.rb +13 -0
- data/lib/generators/lcp_ruby/templates/auditing/model.rb +34 -0
- data/lib/generators/lcp_ruby/templates/auditing/permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/auditing/presenter.rb +41 -0
- data/lib/generators/lcp_ruby/templates/auditing/view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/background_jobs/model.rb +59 -0
- data/lib/generators/lcp_ruby/templates/background_jobs/permissions.yml +22 -0
- data/lib/generators/lcp_ruby/templates/background_jobs/presenter.rb +82 -0
- data/lib/generators/lcp_ruby/templates/background_jobs/view_group.rb +9 -0
- data/lib/generators/lcp_ruby/templates/batch_operations/item_model.rb +28 -0
- data/lib/generators/lcp_ruby/templates/batch_operations/item_presenter.rb +43 -0
- data/lib/generators/lcp_ruby/templates/batch_operations/model.rb +42 -0
- data/lib/generators/lcp_ruby/templates/batch_operations/permissions.yml +44 -0
- data/lib/generators/lcp_ruby/templates/batch_operations/presenter.rb +61 -0
- data/lib/generators/lcp_ruby/templates/batch_operations/view_group.rb +9 -0
- data/lib/generators/lcp_ruby/templates/create_lcp_ruby_users.rb.erb +50 -0
- data/lib/generators/lcp_ruby/templates/custom_fields/model.rb +60 -0
- data/lib/generators/lcp_ruby/templates/custom_fields/permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/custom_fields/presenter.rb +128 -0
- data/lib/generators/lcp_ruby/templates/custom_fields/view_group.rb +9 -0
- data/lib/generators/lcp_ruby/templates/entity/model.rb +42 -0
- data/lib/generators/lcp_ruby/templates/entity/permissions.yml +20 -0
- data/lib/generators/lcp_ruby/templates/entity/presenter.rb +55 -0
- data/lib/generators/lcp_ruby/templates/entity/view_group.rb +8 -0
- data/lib/generators/lcp_ruby/templates/export/export_log_model.rb +30 -0
- data/lib/generators/lcp_ruby/templates/export/export_log_permissions.yml +24 -0
- data/lib/generators/lcp_ruby/templates/export/export_logs_presenter.rb +51 -0
- data/lib/generators/lcp_ruby/templates/export/export_profile_model.rb +28 -0
- data/lib/generators/lcp_ruby/templates/export/export_profile_permissions.yml +26 -0
- data/lib/generators/lcp_ruby/templates/export/export_profiles_presenter.rb +59 -0
- data/lib/generators/lcp_ruby/templates/gapfree_sequences/model.rb +18 -0
- data/lib/generators/lcp_ruby/templates/gapfree_sequences/permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/gapfree_sequences/presenter.rb +51 -0
- data/lib/generators/lcp_ruby/templates/gapfree_sequences/view_group.rb +9 -0
- data/lib/generators/lcp_ruby/templates/groups/group_membership_model.rb +17 -0
- data/lib/generators/lcp_ruby/templates/groups/group_model.rb +28 -0
- data/lib/generators/lcp_ruby/templates/groups/group_permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/groups/group_presenter.rb +53 -0
- data/lib/generators/lcp_ruby/templates/groups/group_role_mapping_model.rb +15 -0
- data/lib/generators/lcp_ruby/templates/groups/group_view_group.rb +9 -0
- data/lib/generators/lcp_ruby/templates/host_controller/controller.rb.erb +131 -0
- data/lib/generators/lcp_ruby/templates/import/data_import_job.yml +7 -0
- data/lib/generators/lcp_ruby/templates/import/import_profile_model.rb +30 -0
- data/lib/generators/lcp_ruby/templates/import/import_profile_permissions.yml +29 -0
- data/lib/generators/lcp_ruby/templates/import/import_profiles_presenter.rb +57 -0
- data/lib/generators/lcp_ruby/templates/import/import_row_model.rb +32 -0
- data/lib/generators/lcp_ruby/templates/import/import_row_permissions.yml +11 -0
- data/lib/generators/lcp_ruby/templates/import/import_rows_presenter.rb +35 -0
- data/lib/generators/lcp_ruby/templates/install/default_permissions.yml +26 -0
- data/lib/generators/lcp_ruby/templates/install/menu.yml.tt +71 -0
- data/lib/generators/lcp_ruby/templates/install/model.rb +20 -0
- data/lib/generators/lcp_ruby/templates/install/permissions.yml +25 -0
- data/lib/generators/lcp_ruby/templates/install/presenter.rb +44 -0
- data/lib/generators/lcp_ruby/templates/install/view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/install_auth/oidc/entra.yml.erb +46 -0
- data/lib/generators/lcp_ruby/templates/install_auth/oidc/generic.yml.erb +55 -0
- data/lib/generators/lcp_ruby/templates/install_auth/oidc/google.yml.erb +42 -0
- data/lib/generators/lcp_ruby/templates/install_auth/oidc/keycloak.yml.erb +45 -0
- data/lib/generators/lcp_ruby/templates/install_auth/oidc/okta.yml.erb +45 -0
- data/lib/generators/lcp_ruby/templates/install_auth/user.rb +36 -0
- data/lib/generators/lcp_ruby/templates/monitoring/model.rb +34 -0
- data/lib/generators/lcp_ruby/templates/monitoring/model_extension.rb +12 -0
- data/lib/generators/lcp_ruby/templates/monitoring/page.yml +49 -0
- data/lib/generators/lcp_ruby/templates/monitoring/permissions.yml +8 -0
- data/lib/generators/lcp_ruby/templates/monitoring/presenter.rb +44 -0
- data/lib/generators/lcp_ruby/templates/oidc_role_mappings/locales.en.yml +15 -0
- data/lib/generators/lcp_ruby/templates/oidc_role_mappings/model.rb +32 -0
- data/lib/generators/lcp_ruby/templates/oidc_role_mappings/permissions.yml +21 -0
- data/lib/generators/lcp_ruby/templates/oidc_role_mappings/presenter.rb +41 -0
- data/lib/generators/lcp_ruby/templates/pages/model.rb +19 -0
- data/lib/generators/lcp_ruby/templates/pages/permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/pages/presenter.rb +51 -0
- data/lib/generators/lcp_ruby/templates/pages/view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/permission_source/model.rb +21 -0
- data/lib/generators/lcp_ruby/templates/permission_source/permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/permission_source/presenter.rb +51 -0
- data/lib/generators/lcp_ruby/templates/permission_source/view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/role_model/model.rb +24 -0
- data/lib/generators/lcp_ruby/templates/role_model/permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/role_model/presenter.rb +62 -0
- data/lib/generators/lcp_ruby/templates/role_model/view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/saved_filters/model.rb +51 -0
- data/lib/generators/lcp_ruby/templates/saved_filters/permissions.yml +44 -0
- data/lib/generators/lcp_ruby/templates/saved_filters/presenter.rb +96 -0
- data/lib/generators/lcp_ruby/templates/saved_filters/save_dialog_presenter.rb +19 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/request_model.rb +50 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/request_permissions.yml +10 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/request_presenter.rb +44 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/request_view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/step_model.rb +36 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/step_permissions.yml +10 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/task_model.rb +34 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/task_permissions.yml +10 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/task_presenter.rb +39 -0
- data/lib/generators/lcp_ruby/templates/workflow_approvals/task_view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/workflow_audit_log/model.rb +48 -0
- data/lib/generators/lcp_ruby/templates/workflow_audit_log/permissions.yml +10 -0
- data/lib/generators/lcp_ruby/templates/workflow_audit_log/presenter.rb +44 -0
- data/lib/generators/lcp_ruby/templates/workflow_audit_log/view_group.rb +10 -0
- data/lib/generators/lcp_ruby/templates/workflow_definition/model.rb +43 -0
- data/lib/generators/lcp_ruby/templates/workflow_definition/permissions.yml +19 -0
- data/lib/generators/lcp_ruby/templates/workflow_definition/presenter.rb +70 -0
- data/lib/generators/lcp_ruby/templates/workflow_definition/view_group.rb +10 -0
- data/lib/generators/lcp_ruby/workflow_approvals_generator.rb +93 -0
- data/lib/generators/lcp_ruby/workflow_audit_log_generator.rb +54 -0
- data/lib/generators/lcp_ruby/workflow_definition_generator.rb +77 -0
- data/lib/lcp.rb +6 -0
- data/lib/lcp_ruby/actions/action_executor.rb +66 -0
- data/lib/lcp_ruby/actions/action_registry.rb +48 -0
- data/lib/lcp_ruby/actions/api_tokens/revoke.rb +13 -0
- data/lib/lcp_ruby/actions/base_action.rb +79 -0
- data/lib/lcp_ruby/actions/form_action_pipeline.rb +138 -0
- data/lib/lcp_ruby/aggregates/query_builder.rb +6 -0
- data/lib/lcp_ruby/api_tokens/model_extension.rb +41 -0
- data/lib/lcp_ruby/api_tokens/resolver_registry.rb +53 -0
- data/lib/lcp_ruby/api_tokens/token_generator.rb +27 -0
- data/lib/lcp_ruby/api_tokens/verifier.rb +38 -0
- data/lib/lcp_ruby/app_template.rb +181 -0
- data/lib/lcp_ruby/array_query.rb +120 -0
- data/lib/lcp_ruby/asset_copier.rb +62 -0
- data/lib/lcp_ruby/association_fk_type.rb +191 -0
- data/lib/lcp_ruby/association_join_column.rb +28 -0
- data/lib/lcp_ruby/association_options_builder.rb +231 -0
- data/lib/lcp_ruby/auditing/audit_writer.rb +258 -0
- data/lib/lcp_ruby/auditing/contract_validator.rb +95 -0
- data/lib/lcp_ruby/auditing/registry.rb +29 -0
- data/lib/lcp_ruby/auditing/setup.rb +49 -0
- data/lib/lcp_ruby/authentication/audit_subscriber.rb +51 -0
- data/lib/lcp_ruby/authentication/bearer_jwt_verifier.rb +139 -0
- data/lib/lcp_ruby/authentication/devise_setup.rb +47 -0
- data/lib/lcp_ruby/authentication/errors.rb +27 -0
- data/lib/lcp_ruby/authentication/http_fetcher.rb +36 -0
- data/lib/lcp_ruby/authentication/jwks_cache.rb +91 -0
- data/lib/lcp_ruby/authentication/oidc_bearer_resolver.rb +84 -0
- data/lib/lcp_ruby/authentication/omniauth_builder.rb +147 -0
- data/lib/lcp_ruby/authentication/provider.rb +108 -0
- data/lib/lcp_ruby/authentication/provider_registry.rb +227 -0
- data/lib/lcp_ruby/authentication/role_mapper.rb +94 -0
- data/lib/lcp_ruby/authentication/test_support.rb +257 -0
- data/lib/lcp_ruby/authentication/user_resolver.rb +169 -0
- data/lib/lcp_ruby/authentication.rb +40 -0
- data/lib/lcp_ruby/authorization/association_lookup.rb +56 -0
- data/lib/lcp_ruby/authorization/authorization_error.rb +12 -0
- data/lib/lcp_ruby/authorization/cache.rb +89 -0
- data/lib/lcp_ruby/authorization/codes.rb +17 -0
- data/lib/lcp_ruby/authorization/impersonated_user.rb +29 -0
- data/lib/lcp_ruby/authorization/includes_hint.rb +110 -0
- data/lib/lcp_ruby/authorization/inherited_parent_validator.rb +142 -0
- data/lib/lcp_ruby/authorization/invariant_check/configuration.rb +132 -0
- data/lib/lcp_ruby/authorization/invariant_error.rb +15 -0
- data/lib/lcp_ruby/authorization/misconfigured_page_error.rb +30 -0
- data/lib/lcp_ruby/authorization/page_gate.rb +57 -0
- data/lib/lcp_ruby/authorization/permission_evaluator.rb +343 -0
- data/lib/lcp_ruby/authorization/policy_factory.rb +91 -0
- data/lib/lcp_ruby/authorization/runtime_invariant_validator.rb +421 -0
- data/lib/lcp_ruby/authorization/scope_builder.rb +227 -0
- data/lib/lcp_ruby/authorization/scope_resolver.rb +28 -0
- data/lib/lcp_ruby/authorized_controller.rb +44 -0
- data/lib/lcp_ruby/background_jobs/base_handler.rb +113 -0
- data/lib/lcp_ruby/background_jobs/change_handler.rb +17 -0
- data/lib/lcp_ruby/background_jobs/contract.rb +16 -0
- data/lib/lcp_ruby/background_jobs/contract_validator.rb +112 -0
- data/lib/lcp_ruby/background_jobs/declarative/base_action.rb +11 -0
- data/lib/lcp_ruby/background_jobs/declarative/call_webhook_action.rb +174 -0
- data/lib/lcp_ruby/background_jobs/declarative/fire_event_action.rb +24 -0
- data/lib/lcp_ruby/background_jobs/declarative/registry.rb +34 -0
- data/lib/lcp_ruby/background_jobs/declarative/run_scope_action.rb +98 -0
- data/lib/lcp_ruby/background_jobs/declarative/send_notification_action.rb +13 -0
- data/lib/lcp_ruby/background_jobs/definition.rb +134 -0
- data/lib/lcp_ruby/background_jobs/enqueue.rb +83 -0
- data/lib/lcp_ruby/background_jobs/errors.rb +9 -0
- data/lib/lcp_ruby/background_jobs/executor_job.rb +111 -0
- data/lib/lcp_ruby/background_jobs/handler_factory.rb +46 -0
- data/lib/lcp_ruby/background_jobs/host_source.rb +33 -0
- data/lib/lcp_ruby/background_jobs/model_source.rb +93 -0
- data/lib/lcp_ruby/background_jobs/registry.rb +81 -0
- data/lib/lcp_ruby/background_jobs/resolver.rb +29 -0
- data/lib/lcp_ruby/background_jobs/schedule_adapter.rb +14 -0
- data/lib/lcp_ruby/background_jobs/setup.rb +145 -0
- data/lib/lcp_ruby/background_jobs/static_source.rb +19 -0
- data/lib/lcp_ruby/background_jobs/steps_executor.rb +52 -0
- data/lib/lcp_ruby/background_jobs/triggers/event_trigger.rb +97 -0
- data/lib/lcp_ruby/background_jobs/triggers/trigger_installer.rb +20 -0
- data/lib/lcp_ruby/background_jobs/unique_key_builder.rb +31 -0
- data/lib/lcp_ruby/batch_actions/base_service.rb +70 -0
- data/lib/lcp_ruby/batch_actions/batch_action_handler.rb +200 -0
- data/lib/lcp_ruby/batch_actions/custom_action_dispatcher.rb +133 -0
- data/lib/lcp_ruby/batch_actions/destroy_service.rb +37 -0
- data/lib/lcp_ruby/batch_actions/permanently_destroy_service.rb +33 -0
- data/lib/lcp_ruby/batch_actions/restore_service.rb +33 -0
- data/lib/lcp_ruby/batch_actions.rb +5 -0
- data/lib/lcp_ruby/bulk_updater.rb +25 -0
- data/lib/lcp_ruby/cli/docs_command.rb +29 -0
- data/lib/lcp_ruby/cli/examples_command.rb +29 -0
- data/lib/lcp_ruby/cli/new_command.rb +509 -0
- data/lib/lcp_ruby/cli/run_command.rb +155 -0
- data/lib/lcp_ruby/cli/skills_command.rb +54 -0
- data/lib/lcp_ruby/cli.rb +74 -0
- data/lib/lcp_ruby/condition_evaluator.rb +366 -0
- data/lib/lcp_ruby/condition_service_registry.rb +58 -0
- data/lib/lcp_ruby/condition_services/current_user_role.rb +28 -0
- data/lib/lcp_ruby/condition_services/feature_flag.rb +63 -0
- data/lib/lcp_ruby/condition_services/impersonating.rb +24 -0
- data/lib/lcp_ruby/conditions/validator.rb +35 -0
- data/lib/lcp_ruby/configuration.rb +431 -0
- data/lib/lcp_ruby/controller/authentication.rb +118 -0
- data/lib/lcp_ruby/controller/authorization.rb +198 -0
- data/lib/lcp_ruby/controller/bearer_authentication.rb +76 -0
- data/lib/lcp_ruby/controller/crud_helpers.rb +233 -0
- data/lib/lcp_ruby/controller/error_handling.rb +94 -0
- data/lib/lcp_ruby/controller/impersonation.rb +70 -0
- data/lib/lcp_ruby/controller/locale_binding.rb +62 -0
- data/lib/lcp_ruby/controller/path_helpers.rb +125 -0
- data/lib/lcp_ruby/controller/presenter_setup.rb +89 -0
- data/lib/lcp_ruby/controller/search.rb +321 -0
- data/lib/lcp_ruby/controller/view_helpers.rb +105 -0
- data/lib/lcp_ruby/current.rb +13 -0
- data/lib/lcp_ruby/custom_fields/applicator.rb +194 -0
- data/lib/lcp_ruby/custom_fields/contract_validator.rb +77 -0
- data/lib/lcp_ruby/custom_fields/definition_change_handler.rb +21 -0
- data/lib/lcp_ruby/custom_fields/query.rb +112 -0
- data/lib/lcp_ruby/custom_fields/registry.rb +70 -0
- data/lib/lcp_ruby/custom_fields/setup.rb +58 -0
- data/lib/lcp_ruby/custom_fields/utils.rb +40 -0
- data/lib/lcp_ruby/custom_fields.rb +9 -0
- data/lib/lcp_ruby/data_source/api_error_placeholder.rb +47 -0
- data/lib/lcp_ruby/data_source/api_filter_translator.rb +72 -0
- data/lib/lcp_ruby/data_source/api_model_concern.rb +131 -0
- data/lib/lcp_ruby/data_source/api_preloader.rb +44 -0
- data/lib/lcp_ruby/data_source/base.rb +85 -0
- data/lib/lcp_ruby/data_source/cached_wrapper.rb +107 -0
- data/lib/lcp_ruby/data_source/host.rb +71 -0
- data/lib/lcp_ruby/data_source/registry.rb +39 -0
- data/lib/lcp_ruby/data_source/resilient_wrapper.rb +67 -0
- data/lib/lcp_ruby/data_source/rest_json.rb +247 -0
- data/lib/lcp_ruby/data_source/setup.rb +57 -0
- data/lib/lcp_ruby/dev_toolbar.rb +8 -0
- data/lib/lcp_ruby/display/base_renderer.rb +21 -0
- data/lib/lcp_ruby/display/count_badge.rb +11 -0
- data/lib/lcp_ruby/display/icon_badge.rb +17 -0
- data/lib/lcp_ruby/display/renderer_registry.rb +138 -0
- data/lib/lcp_ruby/display/renderers/attachment_link.rb +26 -0
- data/lib/lcp_ruby/display/renderers/attachment_list.rb +32 -0
- data/lib/lcp_ruby/display/renderers/attachment_preview.rb +26 -0
- data/lib/lcp_ruby/display/renderers/avatar.rb +14 -0
- data/lib/lcp_ruby/display/renderers/badge.rb +43 -0
- data/lib/lcp_ruby/display/renderers/boolean_icon.rb +54 -0
- data/lib/lcp_ruby/display/renderers/code.rb +39 -0
- data/lib/lcp_ruby/display/renderers/collection.rb +34 -0
- data/lib/lcp_ruby/display/renderers/color_swatch.rb +25 -0
- data/lib/lcp_ruby/display/renderers/concerns/attachment_helpers.rb +73 -0
- data/lib/lcp_ruby/display/renderers/concerns/workflow_helpers.rb +35 -0
- data/lib/lcp_ruby/display/renderers/copy_code.rb +33 -0
- data/lib/lcp_ruby/display/renderers/currency.rb +14 -0
- data/lib/lcp_ruby/display/renderers/date.rb +17 -0
- data/lib/lcp_ruby/display/renderers/datetime.rb +17 -0
- data/lib/lcp_ruby/display/renderers/email_link.rb +15 -0
- data/lib/lcp_ruby/display/renderers/file_size.rb +11 -0
- data/lib/lcp_ruby/display/renderers/heading.rb +11 -0
- data/lib/lcp_ruby/display/renderers/image.rb +17 -0
- data/lib/lcp_ruby/display/renderers/internal_link.rb +23 -0
- data/lib/lcp_ruby/display/renderers/link.rb +15 -0
- data/lib/lcp_ruby/display/renderers/link_list.rb +90 -0
- data/lib/lcp_ruby/display/renderers/markdown.rb +33 -0
- data/lib/lcp_ruby/display/renderers/number.rb +14 -0
- data/lib/lcp_ruby/display/renderers/percentage.rb +12 -0
- data/lib/lcp_ruby/display/renderers/phone_link.rb +15 -0
- data/lib/lcp_ruby/display/renderers/progress_bar.rb +15 -0
- data/lib/lcp_ruby/display/renderers/rating.rb +15 -0
- data/lib/lcp_ruby/display/renderers/record_link.rb +101 -0
- data/lib/lcp_ruby/display/renderers/relative_date.rb +15 -0
- data/lib/lcp_ruby/display/renderers/rich_text.rb +15 -0
- data/lib/lcp_ruby/display/renderers/text.rb +12 -0
- data/lib/lcp_ruby/display/renderers/truncate.rb +17 -0
- data/lib/lcp_ruby/display/renderers/url_link.rb +22 -0
- data/lib/lcp_ruby/display/renderers/workflow_badge.rb +37 -0
- data/lib/lcp_ruby/display/renderers/workflow_timeline.rb +173 -0
- data/lib/lcp_ruby/display/renderers.rb +3 -0
- data/lib/lcp_ruby/display/text_badge.rb +15 -0
- data/lib/lcp_ruby/dsl/condition_builder.rb +190 -0
- data/lib/lcp_ruby/dsl/dsl_loader.rb +365 -0
- data/lib/lcp_ruby/dsl/field_builder.rb +35 -0
- data/lib/lcp_ruby/dsl/job_builder.rb +92 -0
- data/lib/lcp_ruby/dsl/model_builder.rb +544 -0
- data/lib/lcp_ruby/dsl/presenter_builder.rb +1272 -0
- data/lib/lcp_ruby/dsl/source_location_capture.rb +52 -0
- data/lib/lcp_ruby/dsl/type_builder.rb +88 -0
- data/lib/lcp_ruby/dsl/view_group_builder.rb +92 -0
- data/lib/lcp_ruby/dsl/workflow_builder.rb +319 -0
- data/lib/lcp_ruby/dynamic.rb +7 -0
- data/lib/lcp_ruby/dynamic_references/resolver.rb +154 -0
- data/lib/lcp_ruby/dynamic_references/validator.rb +92 -0
- data/lib/lcp_ruby/embed_providers/base.rb +18 -0
- data/lib/lcp_ruby/embed_providers/grafana.rb +38 -0
- data/lib/lcp_ruby/embed_providers/metabase.rb +37 -0
- data/lib/lcp_ruby/engine.rb +680 -0
- data/lib/lcp_ruby/events/async_handler_job.rb +21 -0
- data/lib/lcp_ruby/events/dispatcher.rb +52 -0
- data/lib/lcp_ruby/events/handler_base.rb +51 -0
- data/lib/lcp_ruby/events/handler_registry.rb +49 -0
- data/lib/lcp_ruby/export/data_generator.rb +158 -0
- data/lib/lcp_ruby/export/export_handler.rb +315 -0
- data/lib/lcp_ruby/export/field_tree_builder.rb +219 -0
- data/lib/lcp_ruby/export/setup.rb +94 -0
- data/lib/lcp_ruby/export/value_formatter.rb +223 -0
- data/lib/lcp_ruby/export.rb +9 -0
- data/lib/lcp_ruby/gem_paths.rb +51 -0
- data/lib/lcp_ruby/generators/entity_menu_writer.rb +258 -0
- data/lib/lcp_ruby/generators/feature_registry.rb +208 -0
- data/lib/lcp_ruby/generators/prerequisites.rb +90 -0
- data/lib/lcp_ruby/grouped_query/builder.rb +206 -0
- data/lib/lcp_ruby/grouped_query/result_wrapper.rb +72 -0
- data/lib/lcp_ruby/grouped_query/row.rb +31 -0
- data/lib/lcp_ruby/groups/change_handler.rb +18 -0
- data/lib/lcp_ruby/groups/contract.rb +42 -0
- data/lib/lcp_ruby/groups/contract_validator.rb +110 -0
- data/lib/lcp_ruby/groups/host_loader.rb +54 -0
- data/lib/lcp_ruby/groups/model_loader.rb +186 -0
- data/lib/lcp_ruby/groups/registry.rb +113 -0
- data/lib/lcp_ruby/groups/setup.rb +129 -0
- data/lib/lcp_ruby/groups/yaml_loader.rb +97 -0
- data/lib/lcp_ruby/hash_utils.rb +42 -0
- data/lib/lcp_ruby/i18n_check/configuration.rb +104 -0
- data/lib/lcp_ruby/i18n_check/heuristics.rb +26 -0
- data/lib/lcp_ruby/i18n_check/key_deriver.rb +136 -0
- data/lib/lcp_ruby/i18n_check/offense.rb +29 -0
- data/lib/lcp_ruby/i18n_check/registry_walker.rb +621 -0
- data/lib/lcp_ruby/i18n_check/reporter.rb +96 -0
- data/lib/lcp_ruby/i18n_check/runner.rb +46 -0
- data/lib/lcp_ruby/i18n_check.rb +15 -0
- data/lib/lcp_ruby/i18n_lint.rb +145 -0
- data/lib/lcp_ruby/import/auto_mapper.rb +98 -0
- data/lib/lcp_ruby/import/field_tree_builder.rb +178 -0
- data/lib/lcp_ruby/import/file_parser.rb +223 -0
- data/lib/lcp_ruby/import/import_dialog_handler.rb +410 -0
- data/lib/lcp_ruby/import/import_job_handler.rb +224 -0
- data/lib/lcp_ruby/import/row_processor.rb +281 -0
- data/lib/lcp_ruby/import/setup.rb +277 -0
- data/lib/lcp_ruby/import/value_coercer.rb +143 -0
- data/lib/lcp_ruby/import.rb +14 -0
- data/lib/lcp_ruby/json_item_wrapper.rb +152 -0
- data/lib/lcp_ruby/kanban/board.rb +28 -0
- data/lib/lcp_ruby/kanban/column.rb +28 -0
- data/lib/lcp_ruby/kanban/default_provider.rb +376 -0
- data/lib/lcp_ruby/kanban/host_provider.rb +94 -0
- data/lib/lcp_ruby/kanban/move_result.rb +52 -0
- data/lib/lcp_ruby/kanban/provider_test_harness.rb +54 -0
- data/lib/lcp_ruby/kanban/swimlane.rb +21 -0
- data/lib/lcp_ruby/menu.rb +46 -0
- data/lib/lcp_ruby/metadata/aggregate_definition.rb +6 -0
- data/lib/lcp_ruby/metadata/association_definition.rb +196 -0
- data/lib/lcp_ruby/metadata/auth_validator.rb +222 -0
- data/lib/lcp_ruby/metadata/configuration_validator.rb +7958 -0
- data/lib/lcp_ruby/metadata/contract_result.rb +9 -0
- data/lib/lcp_ruby/metadata/display_template_definition.rb +77 -0
- data/lib/lcp_ruby/metadata/enum_label_resolver.rb +27 -0
- data/lib/lcp_ruby/metadata/erd_generator.rb +274 -0
- data/lib/lcp_ruby/metadata/event_definition.rb +55 -0
- data/lib/lcp_ruby/metadata/field_definition.rb +267 -0
- data/lib/lcp_ruby/metadata/group_definition.rb +31 -0
- data/lib/lcp_ruby/metadata/i18n_label.rb +29 -0
- data/lib/lcp_ruby/metadata/loader.rb +916 -0
- data/lib/lcp_ruby/metadata/menu_definition.rb +116 -0
- data/lib/lcp_ruby/metadata/menu_item.rb +792 -0
- data/lib/lcp_ruby/metadata/menu_item_resolver.rb +105 -0
- data/lib/lcp_ruby/metadata/model_definition.rb +612 -0
- data/lib/lcp_ruby/metadata/model_hash_merger.rb +88 -0
- data/lib/lcp_ruby/metadata/model_inheritance_resolver.rb +165 -0
- data/lib/lcp_ruby/metadata/page_definition.rb +245 -0
- data/lib/lcp_ruby/metadata/path_template.rb +231 -0
- data/lib/lcp_ruby/metadata/permission_definition.rb +237 -0
- data/lib/lcp_ruby/metadata/permission_merger.rb +81 -0
- data/lib/lcp_ruby/metadata/presenter_definition.rb +689 -0
- data/lib/lcp_ruby/metadata/reserved_names.rb +79 -0
- data/lib/lcp_ruby/metadata/responsive_policy.rb +95 -0
- data/lib/lcp_ruby/metadata/schema_validator.rb +172 -0
- data/lib/lcp_ruby/metadata/validation_definition.rb +69 -0
- data/lib/lcp_ruby/metadata/view_group_definition.rb +208 -0
- data/lib/lcp_ruby/metadata/virtual_column_definition.rb +154 -0
- data/lib/lcp_ruby/metadata/zone_definition.rb +423 -0
- data/lib/lcp_ruby/metrics/collector.rb +123 -0
- data/lib/lcp_ruby/metrics/collector_registry.rb +57 -0
- data/lib/lcp_ruby/metrics/error_recorder.rb +70 -0
- data/lib/lcp_ruby/metrics/fingerprint.rb +33 -0
- data/lib/lcp_ruby/metrics/json_query.rb +47 -0
- data/lib/lcp_ruby/metrics/metric_definitions.rb +105 -0
- data/lib/lcp_ruby/metrics/prometheus_check.rb +9 -0
- data/lib/lcp_ruby/metrics/rate_limiter.rb +99 -0
- data/lib/lcp_ruby/metrics/setup.rb +71 -0
- data/lib/lcp_ruby/metrics/subscriber.rb +126 -0
- data/lib/lcp_ruby/model_factory/aggregate_applicator.rb +14 -0
- data/lib/lcp_ruby/model_factory/api_association_applicator.rb +119 -0
- data/lib/lcp_ruby/model_factory/api_builder.rb +85 -0
- data/lib/lcp_ruby/model_factory/array_type.rb +78 -0
- data/lib/lcp_ruby/model_factory/array_type_applicator.rb +33 -0
- data/lib/lcp_ruby/model_factory/association_applicator.rb +201 -0
- data/lib/lcp_ruby/model_factory/attachment_applicator.rb +160 -0
- data/lib/lcp_ruby/model_factory/auditing_applicator.rb +72 -0
- data/lib/lcp_ruby/model_factory/builder.rb +235 -0
- data/lib/lcp_ruby/model_factory/callback_applicator.rb +63 -0
- data/lib/lcp_ruby/model_factory/computed_applicator.rb +55 -0
- data/lib/lcp_ruby/model_factory/default_applicator.rb +85 -0
- data/lib/lcp_ruby/model_factory/enum_applicator.rb +24 -0
- data/lib/lcp_ruby/model_factory/inherited_parent_validator_applicator.rb +39 -0
- data/lib/lcp_ruby/model_factory/label_method_builder.rb +82 -0
- data/lib/lcp_ruby/model_factory/managed_tracking.rb +71 -0
- data/lib/lcp_ruby/model_factory/positioning_applicator.rb +23 -0
- data/lib/lcp_ruby/model_factory/ransack_applicator.rb +66 -0
- data/lib/lcp_ruby/model_factory/registry.rb +33 -0
- data/lib/lcp_ruby/model_factory/schema_manager.rb +655 -0
- data/lib/lcp_ruby/model_factory/scope_applicator.rb +87 -0
- data/lib/lcp_ruby/model_factory/sequence_applicator.rb +173 -0
- data/lib/lcp_ruby/model_factory/service_accessor_applicator.rb +40 -0
- data/lib/lcp_ruby/model_factory/soft_delete_applicator.rb +141 -0
- data/lib/lcp_ruby/model_factory/transform_applicator.rb +51 -0
- data/lib/lcp_ruby/model_factory/tree_applicator.rb +239 -0
- data/lib/lcp_ruby/model_factory/userstamps_applicator.rb +73 -0
- data/lib/lcp_ruby/model_factory/validation_applicator.rb +319 -0
- data/lib/lcp_ruby/model_factory/virtual_column_applicator.rb +79 -0
- data/lib/lcp_ruby/model_factory/workflow_applicator.rb +141 -0
- data/lib/lcp_ruby/pages/change_handler.rb +15 -0
- data/lib/lcp_ruby/pages/contract_validator.rb +74 -0
- data/lib/lcp_ruby/pages/definition_validator.rb +42 -0
- data/lib/lcp_ruby/pages/filter_form.rb +200 -0
- data/lib/lcp_ruby/pages/filter_form_validator.rb +636 -0
- data/lib/lcp_ruby/pages/registry.rb +133 -0
- data/lib/lcp_ruby/pages/resolver.rb +32 -0
- data/lib/lcp_ruby/pages/scope_context_resolver.rb +37 -0
- data/lib/lcp_ruby/pages/scope_filter_set.rb +57 -0
- data/lib/lcp_ruby/pages/setup.rb +46 -0
- data/lib/lcp_ruby/path_utils.rb +12 -0
- data/lib/lcp_ruby/permissions/change_handler.rb +22 -0
- data/lib/lcp_ruby/permissions/contract_validator.rb +74 -0
- data/lib/lcp_ruby/permissions/definition_validator.rb +119 -0
- data/lib/lcp_ruby/permissions/registry.rb +135 -0
- data/lib/lcp_ruby/permissions/setup.rb +51 -0
- data/lib/lcp_ruby/permissions/source_resolver.rb +56 -0
- data/lib/lcp_ruby/presenter/action_set.rb +236 -0
- data/lib/lcp_ruby/presenter/breadcrumb_builder.rb +183 -0
- data/lib/lcp_ruby/presenter/breadcrumb_path_helper.rb +17 -0
- data/lib/lcp_ruby/presenter/column_set.rb +268 -0
- data/lib/lcp_ruby/presenter/enrichment.rb +136 -0
- data/lib/lcp_ruby/presenter/field_value_resolver.rb +237 -0
- data/lib/lcp_ruby/presenter/includes_resolver/association_dependency.rb +59 -0
- data/lib/lcp_ruby/presenter/includes_resolver/dependency_collector.rb +394 -0
- data/lib/lcp_ruby/presenter/includes_resolver/loading_strategy.rb +70 -0
- data/lib/lcp_ruby/presenter/includes_resolver/strategy_resolver.rb +123 -0
- data/lib/lcp_ruby/presenter/includes_resolver.rb +42 -0
- data/lib/lcp_ruby/presenter/layout_builder.rb +467 -0
- data/lib/lcp_ruby/presenter/link_resolver.rb +65 -0
- data/lib/lcp_ruby/presenter/metadata_lookup.rb +28 -0
- data/lib/lcp_ruby/presenter/resolver.rb +25 -0
- data/lib/lcp_ruby/record_aliases/metadata_checker.rb +213 -0
- data/lib/lcp_ruby/record_aliases/setup.rb +212 -0
- data/lib/lcp_ruby/reserved_route_segments.rb +37 -0
- data/lib/lcp_ruby/roles/change_handler.rb +11 -0
- data/lib/lcp_ruby/roles/contract_validator.rb +67 -0
- data/lib/lcp_ruby/roles/registry.rb +89 -0
- data/lib/lcp_ruby/roles/setup.rb +50 -0
- data/lib/lcp_ruby/routing/presenter_routes.rb +104 -0
- data/lib/lcp_ruby/saved_filters/change_handler.rb +13 -0
- data/lib/lcp_ruby/saved_filters/contract_validator.rb +85 -0
- data/lib/lcp_ruby/saved_filters/registry.rb +36 -0
- data/lib/lcp_ruby/saved_filters/resolver.rb +108 -0
- data/lib/lcp_ruby/saved_filters/setup.rb +42 -0
- data/lib/lcp_ruby/saved_filters/stale_field_validator.rb +84 -0
- data/lib/lcp_ruby/schemas/auth.json +208 -0
- data/lib/lcp_ruby/schemas/menu.json +338 -0
- data/lib/lcp_ruby/schemas/model.json +1161 -0
- data/lib/lcp_ruby/schemas/page.json +877 -0
- data/lib/lcp_ruby/schemas/permission.json +454 -0
- data/lib/lcp_ruby/schemas/presenter.json +2274 -0
- data/lib/lcp_ruby/schemas/theme.json +62 -0
- data/lib/lcp_ruby/schemas/type.json +146 -0
- data/lib/lcp_ruby/schemas/view_group.json +163 -0
- data/lib/lcp_ruby/search/custom_field_filter.rb +171 -0
- data/lib/lcp_ruby/search/custom_filter_interceptor.rb +40 -0
- data/lib/lcp_ruby/search/filter_metadata_builder.rb +409 -0
- data/lib/lcp_ruby/search/filter_param_builder.rb +177 -0
- data/lib/lcp_ruby/search/operator_registry.rb +79 -0
- data/lib/lcp_ruby/search/param_sanitizer.rb +25 -0
- data/lib/lcp_ruby/search/parameter_definition.rb +187 -0
- data/lib/lcp_ruby/search/parameterized_scope_applicator.rb +129 -0
- data/lib/lcp_ruby/search/query_builder.rb +143 -0
- data/lib/lcp_ruby/search/query_language_parser.rb +549 -0
- data/lib/lcp_ruby/search/query_language_serializer.rb +193 -0
- data/lib/lcp_ruby/search/quick_search.rb +162 -0
- data/lib/lcp_ruby/search/relative_date_expander.rb +57 -0
- data/lib/lcp_ruby/search_result.rb +70 -0
- data/lib/lcp_ruby/sequences/sequence_manager.rb +51 -0
- data/lib/lcp_ruby/services/accessors/json_field.rb +23 -0
- data/lib/lcp_ruby/services/built_in_accessors.rb +17 -0
- data/lib/lcp_ruby/services/built_in_defaults.rb +22 -0
- data/lib/lcp_ruby/services/built_in_transforms.rb +20 -0
- data/lib/lcp_ruby/services/checker.rb +133 -0
- data/lib/lcp_ruby/services/registry.rb +83 -0
- data/lib/lcp_ruby/skills_installer.rb +73 -0
- data/lib/lcp_ruby/sort/enum_sort_order.rb +38 -0
- data/lib/lcp_ruby/tasks/destroy_order_resolver.rb +57 -0
- data/lib/lcp_ruby/tasks/doctor.rb +294 -0
- data/lib/lcp_ruby/tasks/permission_resolve_formatter.rb +245 -0
- data/lib/lcp_ruby/types/built_in_types.rb +157 -0
- data/lib/lcp_ruby/types/transforms/base_transform.rb +11 -0
- data/lib/lcp_ruby/types/transforms/downcase.rb +11 -0
- data/lib/lcp_ruby/types/transforms/normalize_phone.rb +19 -0
- data/lib/lcp_ruby/types/transforms/normalize_url.rb +16 -0
- data/lib/lcp_ruby/types/transforms/strip.rb +11 -0
- data/lib/lcp_ruby/types/type_definition.rb +112 -0
- data/lib/lcp_ruby/types/type_registry.rb +75 -0
- data/lib/lcp_ruby/url_safety.rb +97 -0
- data/lib/lcp_ruby/user_snapshot.rb +15 -0
- data/lib/lcp_ruby/version.rb +3 -0
- data/lib/lcp_ruby/view_slots/registry.rb +71 -0
- data/lib/lcp_ruby/view_slots/slot_component.rb +22 -0
- data/lib/lcp_ruby/view_slots/slot_context.rb +20 -0
- data/lib/lcp_ruby/virtual_columns/builder.rb +234 -0
- data/lib/lcp_ruby/virtual_columns/collector.rb +186 -0
- data/lib/lcp_ruby/virtual_columns.rb +4 -0
- data/lib/lcp_ruby/virtual_fields/synthetic_marker.rb +17 -0
- data/lib/lcp_ruby/virtual_fields/types/array_of.rb +49 -0
- data/lib/lcp_ruby/virtual_fields/virtual_field.rb +107 -0
- data/lib/lcp_ruby/virtual_fields/virtual_form.rb +144 -0
- data/lib/lcp_ruby/widgets/chart_palette.rb +25 -0
- data/lib/lcp_ruby/widgets/chartkick_check.rb +9 -0
- data/lib/lcp_ruby/widgets/data_resolver.rb +676 -0
- data/lib/lcp_ruby/widgets/date_grouper.rb +54 -0
- data/lib/lcp_ruby/widgets/presenter_zone_resolver.rb +170 -0
- data/lib/lcp_ruby/widgets/record_source_resolver.rb +56 -0
- data/lib/lcp_ruby/widgets/scope_applicator.rb +187 -0
- data/lib/lcp_ruby/workflow/approval/activation_handler.rb +39 -0
- data/lib/lcp_ruby/workflow/approval/approval_definition.rb +117 -0
- data/lib/lcp_ruby/workflow/approval/approver_resolver.rb +98 -0
- data/lib/lcp_ruby/workflow/approval/cleanup_handler.rb +37 -0
- data/lib/lcp_ruby/workflow/approval/contract_validator.rb +96 -0
- data/lib/lcp_ruby/workflow/approval/data_builder.rb +53 -0
- data/lib/lcp_ruby/workflow/approval/discard_handler.rb +51 -0
- data/lib/lcp_ruby/workflow/approval/engine.rb +314 -0
- data/lib/lcp_ruby/workflow/approval/registry.rb +40 -0
- data/lib/lcp_ruby/workflow/approval/resolution_handler.rb +103 -0
- data/lib/lcp_ruby/workflow/approval/setup.rb +138 -0
- data/lib/lcp_ruby/workflow/approval/step_definition.rb +52 -0
- data/lib/lcp_ruby/workflow/approval/step_evaluator.rb +163 -0
- data/lib/lcp_ruby/workflow/approval/system_evaluator.rb +29 -0
- data/lib/lcp_ruby/workflow/approval/task_manager.rb +202 -0
- data/lib/lcp_ruby/workflow/audit_contract_validator.rb +64 -0
- data/lib/lcp_ruby/workflow/audit_registry.rb +24 -0
- data/lib/lcp_ruby/workflow/audit_writer.rb +51 -0
- data/lib/lcp_ruby/workflow/change_handler.rb +14 -0
- data/lib/lcp_ruby/workflow/contract.rb +21 -0
- data/lib/lcp_ruby/workflow/contract_validator.rb +44 -0
- data/lib/lcp_ruby/workflow/errors.rb +12 -0
- data/lib/lcp_ruby/workflow/host_source.rb +19 -0
- data/lib/lcp_ruby/workflow/mermaid_builder.rb +217 -0
- data/lib/lcp_ruby/workflow/model_source.rb +79 -0
- data/lib/lcp_ruby/workflow/registry.rb +113 -0
- data/lib/lcp_ruby/workflow/resolver.rb +32 -0
- data/lib/lcp_ruby/workflow/setup.rb +135 -0
- data/lib/lcp_ruby/workflow/state_definition.rb +59 -0
- data/lib/lcp_ruby/workflow/state_machine.rb +78 -0
- data/lib/lcp_ruby/workflow/static_source.rb +20 -0
- data/lib/lcp_ruby/workflow/transition_action_builder.rb +46 -0
- data/lib/lcp_ruby/workflow/transition_definition.rb +70 -0
- data/lib/lcp_ruby/workflow/transition_executor.rb +140 -0
- data/lib/lcp_ruby/workflow/transition_label_resolver.rb +21 -0
- data/lib/lcp_ruby/workflow/transition_result.rb +20 -0
- data/lib/lcp_ruby/workflow/value_resolver.rb +58 -0
- data/lib/lcp_ruby/workflow/workflow_definition.rb +195 -0
- data/lib/lcp_ruby.rb +764 -0
- data/lib/rubocop/cop/lcp_ruby/no_hardcoded_i18n_string.rb +249 -0
- data/lib/tasks/lcp_ruby.rake +432 -0
- data/lib/tasks/lcp_ruby_assets.rake +37 -0
- data/lib/tasks/lcp_ruby_auth.rake +49 -0
- data/lib/tasks/lcp_ruby_db.rake +76 -0
- data/lib/tasks/lcp_ruby_doctor.rake +20 -0
- data/lib/tasks/lcp_ruby_feature_catalog.rake +61 -0
- data/lib/tasks/lcp_ruby_gapfree_sequences.rake +39 -0
- data/lib/tasks/lcp_ruby_i18n_check.rake +23 -0
- data/lib/tasks/lcp_ruby_i18n_lint.rake +20 -0
- data/lib/tasks/lcp_ruby_invariant_check.rake +72 -0
- data/vendor/assets/javascripts/lcp_ruby/activestorage.min.js +866 -0
- data/vendor/assets/javascripts/lcp_ruby/highlight.min.js +1244 -0
- data/vendor/assets/javascripts/lcp_ruby/lucide.min.js +12 -0
- data/vendor/assets/javascripts/lcp_ruby/stimulus.umd.js +2588 -0
- data/vendor/assets/javascripts/lcp_ruby/tom-select.complete.min.js +444 -0
- data/vendor/assets/stylesheets/lcp_ruby/highlight-github.min.css +12 -0
- data/vendor/assets/stylesheets/lcp_ruby/tom-select.css +412 -0
- metadata +1950 -0
|
@@ -0,0 +1,2274 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://lcp-ruby.dev/schemas/presenter.json",
|
|
4
|
+
"title": "LCP Ruby Presenter Definition",
|
|
5
|
+
"description": "Schema for presenter metadata that defines UI configuration for a model — index table, show page, form, search, and actions. Presenters are defined in config/lcp_ruby/presenters/ as YAML files or via Ruby DSL.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"name": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Unique presenter identifier. Multiple presenters can reference the same model (e.g., 'employees' and 'employees_archived').",
|
|
11
|
+
"examples": ["employees", "deal_pipeline"]
|
|
12
|
+
},
|
|
13
|
+
"model": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "The model this presenter displays. Must match a model name from config/lcp_ruby/models/.",
|
|
16
|
+
"examples": ["employee", "deal"]
|
|
17
|
+
},
|
|
18
|
+
"label": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Human-readable title shown in navigation and page headers.",
|
|
21
|
+
"examples": ["Employees", "Deal Pipeline"]
|
|
22
|
+
},
|
|
23
|
+
"slug": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "URL slug for routing. Defaults to presenter name. Must be unique across all presenters.",
|
|
26
|
+
"examples": ["employees", "deals", "pipeline"]
|
|
27
|
+
},
|
|
28
|
+
"icon": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Icon name shown in navigation and page headers (Lucide icon names).",
|
|
31
|
+
"examples": ["users", "briefcase", "folder-tree"]
|
|
32
|
+
},
|
|
33
|
+
"menu_position": {
|
|
34
|
+
"type": "integer",
|
|
35
|
+
"description": "Position hint for the auto-created view group when this is the only presenter on the model. Lifts the auto-VG entry out of the alphabetical 900+index tier into a configurator-controlled position. Ignored when an explicit view group YAML covers the model. Convention: user-defined positions in 0–899 range, auto-generated start at 900.",
|
|
36
|
+
"examples": [10, 20, 100]
|
|
37
|
+
},
|
|
38
|
+
"default": {
|
|
39
|
+
"type": "boolean",
|
|
40
|
+
"default": false,
|
|
41
|
+
"description": "Marks this presenter as the canonical link target for its model. When the model has multiple presenters, `link: true` / `link_to: :show` resolves to the one marked default. Per-link override via `link_presenter:` on a column/field bypasses this default. Exactly one presenter per model may be marked default; the validator rejects ambiguous configurations at boot."
|
|
42
|
+
},
|
|
43
|
+
"read_only": {
|
|
44
|
+
"type": "boolean",
|
|
45
|
+
"description": "When true, hides create/edit/destroy actions regardless of permissions. Useful for archive or report views."
|
|
46
|
+
},
|
|
47
|
+
"embeddable": {
|
|
48
|
+
"type": "boolean",
|
|
49
|
+
"description": "When true, allows this presenter to be embedded in other pages (e.g., as an association list)."
|
|
50
|
+
},
|
|
51
|
+
"redirect_after": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"description": "Override where the user is redirected after create/update actions.",
|
|
54
|
+
"properties": {
|
|
55
|
+
"create": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"description": "Redirect target after successful create.",
|
|
58
|
+
"enum": ["index", "show", "edit", "new"],
|
|
59
|
+
"default": "show"
|
|
60
|
+
},
|
|
61
|
+
"update": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"description": "Redirect target after successful update.",
|
|
64
|
+
"enum": ["index", "show", "edit", "new"],
|
|
65
|
+
"default": "show"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"examples": [{ "create": "index", "update": "show" }]
|
|
70
|
+
},
|
|
71
|
+
"empty_value": {
|
|
72
|
+
"type": "string",
|
|
73
|
+
"description": "Text displayed for nil/empty field values on show and index pages. Overrides the engine-level default.",
|
|
74
|
+
"examples": ["—", "N/A", "(empty)"]
|
|
75
|
+
},
|
|
76
|
+
"max_inline_actions": {
|
|
77
|
+
"type": "integer",
|
|
78
|
+
"minimum": 1,
|
|
79
|
+
"description": "Maximum number of form action buttons rendered inline before excess overflow into a dropdown. Default: 3.",
|
|
80
|
+
"default": 3
|
|
81
|
+
},
|
|
82
|
+
"scope": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"description": "Base query scope applied to all records in this presenter. 'discarded' shows only soft-deleted records; 'with_discarded' includes both.",
|
|
85
|
+
"enum": ["discarded", "with_discarded"]
|
|
86
|
+
},
|
|
87
|
+
"record_aliases": {
|
|
88
|
+
"type": "object",
|
|
89
|
+
"description": "Named URL segments that resolve to a specific record dynamically. Keys are alias names (e.g., 'me', 'last'). Aliases are presenter-level — the same model may have different aliases in different presenters.",
|
|
90
|
+
"additionalProperties": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"properties": {
|
|
93
|
+
"resolve": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"enum": ["current_user", "field_on_user", "scope"],
|
|
96
|
+
"description": "Resolution strategy. current_user: match belongs_to FK against current_user.id. field_on_user: read a scalar PK value from current_user. scope: call a named scope and take first result."
|
|
97
|
+
},
|
|
98
|
+
"field": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"description": "For current_user strategy: belongs_to association name to match against current_user.id."
|
|
101
|
+
},
|
|
102
|
+
"user_field": {
|
|
103
|
+
"type": "string",
|
|
104
|
+
"description": "For field_on_user strategy: method or column on current_user that returns target record PK."
|
|
105
|
+
},
|
|
106
|
+
"scope": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"description": "For scope strategy: zero-arity named scope on the model. The first result is returned via .first!."
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"required": ["resolve"],
|
|
112
|
+
"additionalProperties": false
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"dialog": {
|
|
116
|
+
"type": "object",
|
|
117
|
+
"description": "Dialog rendering configuration. When present, the presenter can be opened as a modal dialog. Presenters without a slug are dialog-only.",
|
|
118
|
+
"properties": {
|
|
119
|
+
"size": {
|
|
120
|
+
"type": "string",
|
|
121
|
+
"description": "Dialog size.",
|
|
122
|
+
"enum": ["small", "medium", "large", "fullscreen"],
|
|
123
|
+
"default": "medium"
|
|
124
|
+
},
|
|
125
|
+
"title_key": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"description": "I18n key for the dialog title.",
|
|
128
|
+
"examples": ["lcp_ruby.dialogs.quick_edit_title"]
|
|
129
|
+
},
|
|
130
|
+
"closable": {
|
|
131
|
+
"type": "boolean",
|
|
132
|
+
"description": "Whether the dialog shows a close button and can be dismissed.",
|
|
133
|
+
"default": true
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"additionalProperties": false
|
|
137
|
+
},
|
|
138
|
+
"index": { "$ref": "#/$defs/index_config" },
|
|
139
|
+
"show": { "$ref": "#/$defs/show_config" },
|
|
140
|
+
"form": { "$ref": "#/$defs/form_config" },
|
|
141
|
+
"search": { "$ref": "#/$defs/search_config" },
|
|
142
|
+
"actions": { "$ref": "#/$defs/actions_config" },
|
|
143
|
+
"controller": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"description": "Route all CRUD actions for this presenter to a host app controller instead of LCP's ResourcesController. Value is the controller path (e.g., 'checkouts' or 'admin/reports'). Mutually exclusive with action_controllers.",
|
|
146
|
+
"examples": ["checkouts", "admin/reports"]
|
|
147
|
+
},
|
|
148
|
+
"action_controllers": {
|
|
149
|
+
"type": "object",
|
|
150
|
+
"description": "Route specific actions to host app controllers while keeping the rest in LCP's ResourcesController. Keys must be one of the 7 CRUD actions; values are 'controller#action' strings (lowercase, snake_case). Mutually exclusive with controller.",
|
|
151
|
+
"propertyNames": {
|
|
152
|
+
"enum": ["index", "show", "new", "create", "edit", "update", "destroy"]
|
|
153
|
+
},
|
|
154
|
+
"additionalProperties": {
|
|
155
|
+
"type": "string",
|
|
156
|
+
"pattern": "^[a-z][a-z0-9_/]*#[a-z][a-z0-9_]*$"
|
|
157
|
+
},
|
|
158
|
+
"examples": [
|
|
159
|
+
{ "new": "orders/wizard#new", "create": "orders/wizard#create" }
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
"export": { "$ref": "#/$defs/export_config" },
|
|
163
|
+
"import": { "$ref": "#/$defs/import_config" }
|
|
164
|
+
},
|
|
165
|
+
"required": ["name", "model"],
|
|
166
|
+
"additionalProperties": false,
|
|
167
|
+
|
|
168
|
+
"$defs": {
|
|
169
|
+
"condition": {
|
|
170
|
+
"description": "Condition for visible_when/disable_when. Accepts: a field-based condition ({field, operator, value}), a service condition ({service: <name>, params: { ... }} where params are passed as kwargs to the service — see built-in `current_user_role`), a compound (`all`/`any`/`not`), a collection condition ({collection, quantifier, condition}), or a method name string invoked on the record. See docs/reference/condition-operators.md for the full surface.",
|
|
171
|
+
"type": ["object", "string"],
|
|
172
|
+
"examples": [
|
|
173
|
+
{ "field": "status", "operator": "eq", "value": "active" },
|
|
174
|
+
{ "service": "current_user_role", "params": { "in": ["admin", "manager"] } },
|
|
175
|
+
{ "all": [{ "field": "status", "operator": "eq", "value": "draft" }, { "service": "current_user_role", "params": { "in": ["admin"] } }] },
|
|
176
|
+
"can_archive?"
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
"hidden_on": {
|
|
181
|
+
"description": "Hide the element on specific device sizes. Accepts a single value or array.",
|
|
182
|
+
"oneOf": [
|
|
183
|
+
{ "type": "string", "enum": ["mobile", "tablet"] },
|
|
184
|
+
{ "type": "array", "items": { "type": "string", "enum": ["mobile", "tablet"] } }
|
|
185
|
+
],
|
|
186
|
+
"examples": ["mobile", ["mobile", "tablet"]]
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
"item_class_rule": {
|
|
190
|
+
"type": "object",
|
|
191
|
+
"description": "A conditional CSS class rule for index rows/cards. When the condition matches, the CSS class is applied to the element.",
|
|
192
|
+
"properties": {
|
|
193
|
+
"class": {
|
|
194
|
+
"type": "string",
|
|
195
|
+
"description": "One or more CSS class names (space-separated) to apply when the condition matches.",
|
|
196
|
+
"examples": ["lcp-row-danger", "lcp-row-muted lcp-row-strikethrough"]
|
|
197
|
+
},
|
|
198
|
+
"when": {
|
|
199
|
+
"$ref": "#/$defs/condition",
|
|
200
|
+
"description": "Condition evaluated against each record to determine if the class should be applied."
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"required": ["class", "when"],
|
|
204
|
+
"additionalProperties": false
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
"table_column": {
|
|
208
|
+
"type": "object",
|
|
209
|
+
"description": "A column in the index table view.",
|
|
210
|
+
"properties": {
|
|
211
|
+
"field": {
|
|
212
|
+
"type": "string",
|
|
213
|
+
"description": "Field name to display. Supports dot-path for associations (e.g., 'department.name') and template syntax (e.g., '{first_name} {last_name}').",
|
|
214
|
+
"examples": ["name", "department.name", "{first_name} {last_name}"]
|
|
215
|
+
},
|
|
216
|
+
"label": {
|
|
217
|
+
"type": "string",
|
|
218
|
+
"description": "Column header text. Falls back to humanized field name."
|
|
219
|
+
},
|
|
220
|
+
"width": {
|
|
221
|
+
"type": "string",
|
|
222
|
+
"description": "Column width as CSS value.",
|
|
223
|
+
"examples": ["30%", "200px", "auto"]
|
|
224
|
+
},
|
|
225
|
+
"link_to": {
|
|
226
|
+
"type": "string",
|
|
227
|
+
"description": "Make the cell value a link to this action (typically 'show'). Legacy option — always links to the current row. For linking through a belongs_to association (e.g. 'manager.display_name' → manager's show page), use 'link: true' or 'link_through:' instead.",
|
|
228
|
+
"examples": ["show", "edit"]
|
|
229
|
+
},
|
|
230
|
+
"link": {
|
|
231
|
+
"type": "boolean",
|
|
232
|
+
"description": "Render the cell value as a link. Auto-detects the link target from the field: dot-path ('manager.display_name') links to the last belongs_to record in the chain; a plain belongs_to field name ('manager') links to that record; a scalar field links to the current row (equivalent to legacy link_to: show). Use 'link_through:' to override auto-detection."
|
|
233
|
+
},
|
|
234
|
+
"link_through": {
|
|
235
|
+
"type": "string",
|
|
236
|
+
"description": "Name of a belongs_to association on this model to follow for the link target. Implies 'link: true'. Use to override auto-detection when the displayed field's name doesn't correspond to the linked entity (e.g. a precomputed label)."
|
|
237
|
+
},
|
|
238
|
+
"link_presenter": {
|
|
239
|
+
"type": "string",
|
|
240
|
+
"description": "Override the target presenter slug for this link. Use when the linked model has multiple presenters and you want a non-default one (e.g. compact card on index, full detail elsewhere). Falls back to the model's `default: true` presenter when absent.",
|
|
241
|
+
"examples": ["contact_short", "employee_compact"]
|
|
242
|
+
},
|
|
243
|
+
"sortable": {
|
|
244
|
+
"type": "boolean",
|
|
245
|
+
"description": "Allow sorting by this column via clickable header."
|
|
246
|
+
},
|
|
247
|
+
"renderer": {
|
|
248
|
+
"type": "string",
|
|
249
|
+
"description": "Display renderer name from the RendererRegistry (e.g., badge, date, currency, email_link).",
|
|
250
|
+
"examples": ["badge", "date", "currency", "boolean_icon", "email_link"]
|
|
251
|
+
},
|
|
252
|
+
"options": {
|
|
253
|
+
"type": "object",
|
|
254
|
+
"description": "Options passed to the renderer (e.g., color_map for badge renderer).",
|
|
255
|
+
"examples": [{ "color_map": { "active": "green", "inactive": "gray" } }]
|
|
256
|
+
},
|
|
257
|
+
"partial": {
|
|
258
|
+
"type": "string",
|
|
259
|
+
"description": "ERB partial path for fully custom cell rendering. Receives the record as a local.",
|
|
260
|
+
"examples": ["employees/status_cell"]
|
|
261
|
+
},
|
|
262
|
+
"hidden_on": { "$ref": "#/$defs/hidden_on" },
|
|
263
|
+
"pinned": {
|
|
264
|
+
"type": "string",
|
|
265
|
+
"description": "Pin the column to the left or right edge of the table (stays visible during horizontal scroll).",
|
|
266
|
+
"enum": ["left", "right"]
|
|
267
|
+
},
|
|
268
|
+
"summary": {
|
|
269
|
+
"type": "string",
|
|
270
|
+
"description": "Show a summary row at the bottom of the table with the specified aggregation.",
|
|
271
|
+
"enum": ["sum", "avg", "count"]
|
|
272
|
+
},
|
|
273
|
+
"copyable": {
|
|
274
|
+
"type": "boolean",
|
|
275
|
+
"description": "Show a copy-to-clipboard button next to the cell value."
|
|
276
|
+
},
|
|
277
|
+
"visible_when": {
|
|
278
|
+
"$ref": "#/$defs/condition",
|
|
279
|
+
"description": "Conditionally show this column based on a field condition or service."
|
|
280
|
+
},
|
|
281
|
+
"disable_when": {
|
|
282
|
+
"$ref": "#/$defs/condition",
|
|
283
|
+
"description": "Conditionally disable (gray out) this column."
|
|
284
|
+
},
|
|
285
|
+
"aggregate": {
|
|
286
|
+
"type": "string",
|
|
287
|
+
"description": "Aggregate function for grouped query columns (e.g., count, sum, avg, min, max).",
|
|
288
|
+
"enum": ["count", "sum", "avg", "min", "max"]
|
|
289
|
+
},
|
|
290
|
+
"aggregate_field": {
|
|
291
|
+
"type": "string",
|
|
292
|
+
"description": "Field to aggregate over. Defaults to the column field. Required for sum/avg/min/max when different from field."
|
|
293
|
+
},
|
|
294
|
+
"distinct": {
|
|
295
|
+
"type": "boolean",
|
|
296
|
+
"description": "Apply DISTINCT to the aggregate function."
|
|
297
|
+
},
|
|
298
|
+
"display_in_index": {
|
|
299
|
+
"type": "boolean",
|
|
300
|
+
"description": "Per-column opt-in for fields whose type has default_index_visible: false (e.g. :text, :rich_text, :attachment, :json, :array, :file). Without this kwarg, the validator emits a row-unfriendly-column warning suggesting either an explicit renderer or this opt-in. Has no runtime effect — purely a validator-silencer. Default: false.",
|
|
301
|
+
"default": false,
|
|
302
|
+
"examples": [true]
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
"required": ["field"],
|
|
306
|
+
"additionalProperties": false
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
"show_field": {
|
|
310
|
+
"description": "Field in show section. Regular field (has 'field' key), divider (type: divider), or info box (type: info).",
|
|
311
|
+
"type": "object",
|
|
312
|
+
"properties": {
|
|
313
|
+
"field": {
|
|
314
|
+
"type": "string",
|
|
315
|
+
"description": "Field name to display. Supports dot-path and template syntax.",
|
|
316
|
+
"examples": ["name", "department.name", "{first_name} {last_name}"]
|
|
317
|
+
},
|
|
318
|
+
"label": {
|
|
319
|
+
"type": "string",
|
|
320
|
+
"description": "Override the field label."
|
|
321
|
+
},
|
|
322
|
+
"renderer": {
|
|
323
|
+
"type": "string",
|
|
324
|
+
"description": "Display renderer name.",
|
|
325
|
+
"examples": ["badge", "date", "currency", "rich_text", "attachment_gallery"]
|
|
326
|
+
},
|
|
327
|
+
"options": {
|
|
328
|
+
"type": "object",
|
|
329
|
+
"description": "Options passed to the renderer."
|
|
330
|
+
},
|
|
331
|
+
"partial": {
|
|
332
|
+
"type": "string",
|
|
333
|
+
"description": "ERB partial for custom field rendering."
|
|
334
|
+
},
|
|
335
|
+
"col_span": {
|
|
336
|
+
"type": "integer",
|
|
337
|
+
"minimum": 1,
|
|
338
|
+
"description": "Number of grid columns this field spans (for multi-column section layouts).",
|
|
339
|
+
"examples": [2, 3]
|
|
340
|
+
},
|
|
341
|
+
"copyable": {
|
|
342
|
+
"type": "boolean",
|
|
343
|
+
"description": "Show a copy-to-clipboard button next to the value."
|
|
344
|
+
},
|
|
345
|
+
"link": {
|
|
346
|
+
"type": "boolean",
|
|
347
|
+
"description": "Render the field value as a link. Auto-detects the target from a dot-path ('manager.display_name' → manager's show page, 'manager.organizational_unit.name' → org unit's show page) or from a plain belongs_to field name. Use 'link_through:' to override auto-detection."
|
|
348
|
+
},
|
|
349
|
+
"link_through": {
|
|
350
|
+
"type": "string",
|
|
351
|
+
"description": "Name of a belongs_to association on this model to follow for the link target. Implies 'link: true'. Use to override auto-detection when the displayed field's name doesn't correspond to the linked entity."
|
|
352
|
+
},
|
|
353
|
+
"link_presenter": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"description": "Override the target presenter slug for this link. Use when the linked model has multiple presenters and you want a non-default one. Falls back to the model's `default: true` presenter when absent.",
|
|
356
|
+
"examples": ["contact_short", "employee_compact"]
|
|
357
|
+
},
|
|
358
|
+
"hint": {
|
|
359
|
+
"type": "string",
|
|
360
|
+
"description": "Help text displayed below the field value.",
|
|
361
|
+
"examples": ["This value is calculated from the employee's base salary and bonus."]
|
|
362
|
+
},
|
|
363
|
+
"hidden_on": { "$ref": "#/$defs/hidden_on" },
|
|
364
|
+
"visible_when": {
|
|
365
|
+
"$ref": "#/$defs/condition",
|
|
366
|
+
"description": "Conditionally show this field based on a record condition."
|
|
367
|
+
},
|
|
368
|
+
"disable_when": {
|
|
369
|
+
"$ref": "#/$defs/condition",
|
|
370
|
+
"description": "Conditionally disable (gray out) this field."
|
|
371
|
+
},
|
|
372
|
+
"type": {
|
|
373
|
+
"type": "string",
|
|
374
|
+
"description": "Special field types: 'divider' renders a horizontal line, 'info' renders a text box. In nested_fields context, also accepts data types (string, integer, etc.).",
|
|
375
|
+
"enum": ["divider", "info", "string", "text", "integer", "float", "decimal", "boolean", "date", "datetime", "enum"]
|
|
376
|
+
},
|
|
377
|
+
"text": {
|
|
378
|
+
"type": "string",
|
|
379
|
+
"description": "Text content for type: info fields."
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
"additionalProperties": false
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
"form_field": {
|
|
386
|
+
"description": "Field in form section. Regular input (has 'field' key), divider (type: divider), or info box (type: info).",
|
|
387
|
+
"type": "object",
|
|
388
|
+
"properties": {
|
|
389
|
+
"field": {
|
|
390
|
+
"type": "string",
|
|
391
|
+
"description": "Field name matching a model field or association FK.",
|
|
392
|
+
"examples": ["name", "department_id", "status"]
|
|
393
|
+
},
|
|
394
|
+
"label": {
|
|
395
|
+
"type": "string",
|
|
396
|
+
"description": "Override the input label."
|
|
397
|
+
},
|
|
398
|
+
"input_type": {
|
|
399
|
+
"type": "string",
|
|
400
|
+
"description": "Input widget type. Inferred from field type if omitted (e.g., text for string, select for enum, association_select for FK).",
|
|
401
|
+
"examples": ["text", "textarea", "select", "date", "color", "association_select", "rich_text", "file"]
|
|
402
|
+
},
|
|
403
|
+
"placeholder": {
|
|
404
|
+
"type": "string",
|
|
405
|
+
"description": "Placeholder text shown in empty inputs.",
|
|
406
|
+
"examples": ["Enter employee name..."]
|
|
407
|
+
},
|
|
408
|
+
"autofocus": {
|
|
409
|
+
"type": "boolean",
|
|
410
|
+
"description": "Automatically focus this input when the form loads. Only one field per form should have this."
|
|
411
|
+
},
|
|
412
|
+
"prefix": {
|
|
413
|
+
"type": "string",
|
|
414
|
+
"description": "Text or symbol shown before the input (e.g., currency symbol).",
|
|
415
|
+
"examples": ["$", "EUR"]
|
|
416
|
+
},
|
|
417
|
+
"suffix": {
|
|
418
|
+
"type": "string",
|
|
419
|
+
"description": "Text or symbol shown after the input (e.g., unit).",
|
|
420
|
+
"examples": ["%", "kg", "hours"]
|
|
421
|
+
},
|
|
422
|
+
"col_span": {
|
|
423
|
+
"type": "integer",
|
|
424
|
+
"minimum": 1,
|
|
425
|
+
"description": "Number of grid columns this field spans."
|
|
426
|
+
},
|
|
427
|
+
"hint": {
|
|
428
|
+
"type": "string",
|
|
429
|
+
"description": "Help text displayed below the input.",
|
|
430
|
+
"examples": ["Use format: +1-234-567-8900"]
|
|
431
|
+
},
|
|
432
|
+
"readonly": {
|
|
433
|
+
"type": "boolean",
|
|
434
|
+
"description": "Render the field as read-only (displayed but not editable)."
|
|
435
|
+
},
|
|
436
|
+
"visible_when": {
|
|
437
|
+
"$ref": "#/$defs/condition",
|
|
438
|
+
"description": "Conditionally show this field based on other form field values. Evaluated client-side for instant reactivity."
|
|
439
|
+
},
|
|
440
|
+
"disable_when": {
|
|
441
|
+
"$ref": "#/$defs/condition",
|
|
442
|
+
"description": "Conditionally disable this field based on other form field values."
|
|
443
|
+
},
|
|
444
|
+
"default": {
|
|
445
|
+
"description": "Default value pre-filled in the form for new records. Overrides the model-level default."
|
|
446
|
+
},
|
|
447
|
+
"input_options": {
|
|
448
|
+
"type": "object",
|
|
449
|
+
"description": "HTML attributes and widget-specific options for the input element.",
|
|
450
|
+
"examples": [{ "rows": 6 }, { "min": 0, "step": 0.01 }]
|
|
451
|
+
},
|
|
452
|
+
"options": {
|
|
453
|
+
"type": "object",
|
|
454
|
+
"description": "Options passed to the renderer when the field uses a custom renderer instead of the default input."
|
|
455
|
+
},
|
|
456
|
+
"renderer": {
|
|
457
|
+
"type": "string",
|
|
458
|
+
"description": "Use a display renderer instead of an input widget (makes the field read-only in the form)."
|
|
459
|
+
},
|
|
460
|
+
"partial": {
|
|
461
|
+
"type": "string",
|
|
462
|
+
"description": "ERB partial for fully custom input rendering."
|
|
463
|
+
},
|
|
464
|
+
"hidden_on": { "$ref": "#/$defs/hidden_on" },
|
|
465
|
+
"type": {
|
|
466
|
+
"type": "string",
|
|
467
|
+
"description": "Special types: 'divider' renders a horizontal line, 'info' renders a text box. In nested_fields context, also accepts data types (string, integer, etc.).",
|
|
468
|
+
"enum": ["divider", "info", "string", "text", "integer", "float", "decimal", "boolean", "date", "datetime", "enum"]
|
|
469
|
+
},
|
|
470
|
+
"text": {
|
|
471
|
+
"type": "string",
|
|
472
|
+
"description": "Text content for type: info fields."
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
"additionalProperties": false
|
|
476
|
+
},
|
|
477
|
+
|
|
478
|
+
"show_section": {
|
|
479
|
+
"description": "Section in show page layout. Regular field section, association_list (embedded table of related records), json_items_list (items from a JSON column), or audit_history (change log).",
|
|
480
|
+
"type": "object",
|
|
481
|
+
"properties": {
|
|
482
|
+
"section": {
|
|
483
|
+
"type": "string",
|
|
484
|
+
"description": "Section title displayed as the heading. When `section_key` is not set, the title is parameterized and used as the i18n lookup key: lcp_ruby.presenters.<presenter>.sections.<parameterized_title>.",
|
|
485
|
+
"examples": ["Overview", "Contact Details", "Employment History"]
|
|
486
|
+
},
|
|
487
|
+
"section_key": {
|
|
488
|
+
"type": "string",
|
|
489
|
+
"description": "Explicit i18n lookup key for the section heading. Decouples the i18n key from the human-readable label, so non-English literals don't leak into the en locale as fallback values. Lookup: lcp_ruby.presenters.<presenter>.sections.<section_key>. Falls back to the `section` value (or humanized key) when the i18n entry is missing.",
|
|
490
|
+
"examples": ["details", "list_overview", "contact"]
|
|
491
|
+
},
|
|
492
|
+
"type": {
|
|
493
|
+
"type": "string",
|
|
494
|
+
"description": "Section type. Omit for regular field sections. 'custom' delegates rendering to a host-app partial.",
|
|
495
|
+
"enum": ["association_list", "json_items_list", "audit_history", "custom"]
|
|
496
|
+
},
|
|
497
|
+
"partial": {
|
|
498
|
+
"type": "string",
|
|
499
|
+
"description": "For type: custom — host-app partial path to render inside the section wrapper.",
|
|
500
|
+
"examples": ["employees/location_map", "products/custom_gallery"]
|
|
501
|
+
},
|
|
502
|
+
"columns": {
|
|
503
|
+
"type": "integer",
|
|
504
|
+
"minimum": 1,
|
|
505
|
+
"description": "Number of grid columns for field layout within this section.",
|
|
506
|
+
"examples": [2, 3]
|
|
507
|
+
},
|
|
508
|
+
"description": {
|
|
509
|
+
"type": "string",
|
|
510
|
+
"description": "Explanatory text shown below the section title."
|
|
511
|
+
},
|
|
512
|
+
"responsive": {
|
|
513
|
+
"type": "object",
|
|
514
|
+
"description": "Responsive column overrides per breakpoint (e.g., {mobile: 1, tablet: 2})."
|
|
515
|
+
},
|
|
516
|
+
"visible_when": {
|
|
517
|
+
"$ref": "#/$defs/condition",
|
|
518
|
+
"description": "Conditionally show this entire section based on the record's field values."
|
|
519
|
+
},
|
|
520
|
+
"disable_when": {
|
|
521
|
+
"$ref": "#/$defs/condition",
|
|
522
|
+
"description": "Conditionally disable (gray out) this section."
|
|
523
|
+
},
|
|
524
|
+
"fields": {
|
|
525
|
+
"type": "array",
|
|
526
|
+
"description": "Fields displayed in this section (for regular and json_items_list sections).",
|
|
527
|
+
"items": { "$ref": "#/$defs/show_field" }
|
|
528
|
+
},
|
|
529
|
+
"sub_sections": {
|
|
530
|
+
"type": "array",
|
|
531
|
+
"description": "Sub-sections for organizing fields into groups within a json_items_list or nested section.",
|
|
532
|
+
"items": { "$ref": "#/$defs/sub_section" }
|
|
533
|
+
},
|
|
534
|
+
"association": {
|
|
535
|
+
"type": "string",
|
|
536
|
+
"description": "For type: association_list — the association name on the model.",
|
|
537
|
+
"examples": ["employees", "skills", "comments"]
|
|
538
|
+
},
|
|
539
|
+
"json_field": {
|
|
540
|
+
"type": "string",
|
|
541
|
+
"description": "For type: json_items_list — the JSON column name containing the array of items.",
|
|
542
|
+
"examples": ["addresses", "work_history"]
|
|
543
|
+
},
|
|
544
|
+
"target_model": {
|
|
545
|
+
"type": "string",
|
|
546
|
+
"description": "For type: json_items_list — virtual model defining the field schema for each JSON item.",
|
|
547
|
+
"examples": ["address", "work_history_entry"]
|
|
548
|
+
},
|
|
549
|
+
"display_template": {
|
|
550
|
+
"type": "string",
|
|
551
|
+
"description": "For type: association_list — template for rendering each item. Uses {field} interpolation.",
|
|
552
|
+
"examples": ["{name}", "{first_name} {last_name} ({role})"]
|
|
553
|
+
},
|
|
554
|
+
"link": {
|
|
555
|
+
"type": "boolean",
|
|
556
|
+
"description": "For type: association_list — make each item a link to its show page."
|
|
557
|
+
},
|
|
558
|
+
"link_through": {
|
|
559
|
+
"type": "string",
|
|
560
|
+
"description": "For type: association_list — follow this belongs_to association on the target model to resolve the link target."
|
|
561
|
+
},
|
|
562
|
+
"link_presenter": {
|
|
563
|
+
"type": "string",
|
|
564
|
+
"description": "For type: association_list — override the target presenter slug for the link. Use when the linked model has multiple presenters. Falls back to the model's `default: true` presenter when absent.",
|
|
565
|
+
"examples": ["contact_short", "employee_compact"]
|
|
566
|
+
},
|
|
567
|
+
"sort": {
|
|
568
|
+
"type": "object",
|
|
569
|
+
"description": "For type: association_list — default ordering of items.",
|
|
570
|
+
"examples": [{ "created_at": "desc" }]
|
|
571
|
+
},
|
|
572
|
+
"limit": {
|
|
573
|
+
"type": "integer",
|
|
574
|
+
"description": "For type: association_list — maximum number of items to display.",
|
|
575
|
+
"examples": [5, 10]
|
|
576
|
+
},
|
|
577
|
+
"empty_message": {
|
|
578
|
+
"type": "string",
|
|
579
|
+
"description": "Message shown when no items exist.",
|
|
580
|
+
"examples": ["No employees found.", "No history entries yet."]
|
|
581
|
+
},
|
|
582
|
+
"scope": {
|
|
583
|
+
"type": "string",
|
|
584
|
+
"description": "For type: association_list — named scope to apply when loading items.",
|
|
585
|
+
"examples": ["active", "recent"]
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
"required": ["section"],
|
|
589
|
+
"additionalProperties": false
|
|
590
|
+
},
|
|
591
|
+
|
|
592
|
+
"form_section": {
|
|
593
|
+
"description": "Section in form layout. Regular section (title + fields) or nested_fields (editable association or JSON items).",
|
|
594
|
+
"type": "object",
|
|
595
|
+
"properties": {
|
|
596
|
+
"title": {
|
|
597
|
+
"type": "string",
|
|
598
|
+
"description": "Section heading. When `section_key` is not set, the title is parameterized and used as the i18n lookup key: lcp_ruby.presenters.<presenter>.sections.<parameterized_title>.",
|
|
599
|
+
"examples": ["Basic Information", "Address", "Skills"]
|
|
600
|
+
},
|
|
601
|
+
"section_key": {
|
|
602
|
+
"type": "string",
|
|
603
|
+
"description": "Explicit i18n lookup key for the section heading. Decouples the i18n key from the human-readable label. Lookup: lcp_ruby.presenters.<presenter>.sections.<section_key>. Falls back to the `title` value (or humanized key) when the i18n entry is missing.",
|
|
604
|
+
"examples": ["basic_info", "address", "skills"]
|
|
605
|
+
},
|
|
606
|
+
"type": {
|
|
607
|
+
"type": "string",
|
|
608
|
+
"description": "Set to 'nested_fields' for inline editing of associated records or JSON array items. 'custom' delegates rendering to a host-app partial.",
|
|
609
|
+
"enum": ["nested_fields", "custom"]
|
|
610
|
+
},
|
|
611
|
+
"partial": {
|
|
612
|
+
"type": "string",
|
|
613
|
+
"description": "For type: custom — host-app partial path to render inside the form fieldset wrapper.",
|
|
614
|
+
"examples": ["products/variants_editor", "employees/custom_form_section"]
|
|
615
|
+
},
|
|
616
|
+
"additional_permitted_params": {
|
|
617
|
+
"type": "array",
|
|
618
|
+
"description": "For type: custom — extra param names permitted from the custom section's inputs. Supports scalar strings and single-key hash specs for nested params.",
|
|
619
|
+
"items": {
|
|
620
|
+
"oneOf": [
|
|
621
|
+
{ "type": "string" },
|
|
622
|
+
{ "type": "object" }
|
|
623
|
+
]
|
|
624
|
+
},
|
|
625
|
+
"examples": [["variants_json"], [{ "address": ["street", "city", "zip"] }]]
|
|
626
|
+
},
|
|
627
|
+
"columns": {
|
|
628
|
+
"type": "integer",
|
|
629
|
+
"minimum": 1,
|
|
630
|
+
"description": "Number of grid columns for field layout.",
|
|
631
|
+
"examples": [2, 3]
|
|
632
|
+
},
|
|
633
|
+
"description": {
|
|
634
|
+
"type": "string",
|
|
635
|
+
"description": "Explanatory text shown below the section title."
|
|
636
|
+
},
|
|
637
|
+
"responsive": {
|
|
638
|
+
"type": "object",
|
|
639
|
+
"description": "Responsive column overrides per breakpoint."
|
|
640
|
+
},
|
|
641
|
+
"collapsible": {
|
|
642
|
+
"type": "boolean",
|
|
643
|
+
"description": "Allow the section to be collapsed/expanded by clicking the title."
|
|
644
|
+
},
|
|
645
|
+
"collapsed": {
|
|
646
|
+
"type": "boolean",
|
|
647
|
+
"description": "Start the section in collapsed state. Only effective when collapsible: true."
|
|
648
|
+
},
|
|
649
|
+
"visible_when": {
|
|
650
|
+
"$ref": "#/$defs/condition",
|
|
651
|
+
"description": "Conditionally show this section based on form field values."
|
|
652
|
+
},
|
|
653
|
+
"disable_when": {
|
|
654
|
+
"$ref": "#/$defs/condition",
|
|
655
|
+
"description": "Conditionally disable all inputs in this section."
|
|
656
|
+
},
|
|
657
|
+
"fields": {
|
|
658
|
+
"type": "array",
|
|
659
|
+
"description": "Input fields in this section.",
|
|
660
|
+
"items": { "$ref": "#/$defs/form_field" }
|
|
661
|
+
},
|
|
662
|
+
"sub_sections": {
|
|
663
|
+
"type": "array",
|
|
664
|
+
"description": "Sub-sections for organizing fields into titled groups within nested_fields.",
|
|
665
|
+
"items": { "$ref": "#/$defs/sub_section" }
|
|
666
|
+
},
|
|
667
|
+
"association": {
|
|
668
|
+
"type": "string",
|
|
669
|
+
"description": "For type: nested_fields with AR associations — the association name. Requires nested_attributes on the model.",
|
|
670
|
+
"examples": ["addresses", "phone_numbers"]
|
|
671
|
+
},
|
|
672
|
+
"json_field": {
|
|
673
|
+
"type": "string",
|
|
674
|
+
"description": "For type: nested_fields with JSON columns — the JSON column name storing the array of items.",
|
|
675
|
+
"examples": ["addresses", "work_history"]
|
|
676
|
+
},
|
|
677
|
+
"target_model": {
|
|
678
|
+
"type": "string",
|
|
679
|
+
"description": "For type: nested_fields with JSON — virtual model defining field schema and validations for each item.",
|
|
680
|
+
"examples": ["address", "work_history_entry"]
|
|
681
|
+
},
|
|
682
|
+
"allow_add": {
|
|
683
|
+
"type": "boolean",
|
|
684
|
+
"description": "For type: nested_fields — show an 'Add' button to create new items."
|
|
685
|
+
},
|
|
686
|
+
"allow_remove": {
|
|
687
|
+
"type": "boolean",
|
|
688
|
+
"description": "For type: nested_fields — show a 'Remove' button on each item."
|
|
689
|
+
},
|
|
690
|
+
"min": {
|
|
691
|
+
"type": "integer",
|
|
692
|
+
"description": "For type: nested_fields — minimum number of items required."
|
|
693
|
+
},
|
|
694
|
+
"max": {
|
|
695
|
+
"type": "integer",
|
|
696
|
+
"description": "For type: nested_fields — maximum number of items allowed."
|
|
697
|
+
},
|
|
698
|
+
"add_label": {
|
|
699
|
+
"type": "string",
|
|
700
|
+
"description": "For type: nested_fields — custom label for the 'Add' button.",
|
|
701
|
+
"examples": ["Add Address", "Add Skill"]
|
|
702
|
+
},
|
|
703
|
+
"empty_message": {
|
|
704
|
+
"type": "string",
|
|
705
|
+
"description": "For type: nested_fields — message shown when no items exist."
|
|
706
|
+
},
|
|
707
|
+
"sortable": {
|
|
708
|
+
"description": "For type: nested_fields — enable drag-and-drop reordering of items. Boolean true or a config object."
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
"required": ["title"],
|
|
712
|
+
"additionalProperties": false
|
|
713
|
+
},
|
|
714
|
+
|
|
715
|
+
"sub_section": {
|
|
716
|
+
"description": "Sub-section within nested_fields or json_items_list, grouping fields under a titled sub-heading.",
|
|
717
|
+
"type": "object",
|
|
718
|
+
"properties": {
|
|
719
|
+
"title": {
|
|
720
|
+
"type": "string",
|
|
721
|
+
"description": "Sub-section heading.",
|
|
722
|
+
"examples": ["Street Address", "Emergency Contact"]
|
|
723
|
+
},
|
|
724
|
+
"columns": {
|
|
725
|
+
"type": "integer",
|
|
726
|
+
"minimum": 1,
|
|
727
|
+
"description": "Number of grid columns for field layout within this sub-section."
|
|
728
|
+
},
|
|
729
|
+
"collapsible": { "type": "boolean", "description": "Allow collapsing." },
|
|
730
|
+
"collapsed": { "type": "boolean", "description": "Start collapsed." },
|
|
731
|
+
"visible_when": {
|
|
732
|
+
"$ref": "#/$defs/condition",
|
|
733
|
+
"description": "Conditionally show this sub-section."
|
|
734
|
+
},
|
|
735
|
+
"disable_when": {
|
|
736
|
+
"$ref": "#/$defs/condition",
|
|
737
|
+
"description": "Conditionally disable all inputs in this sub-section."
|
|
738
|
+
},
|
|
739
|
+
"fields": {
|
|
740
|
+
"type": "array",
|
|
741
|
+
"description": "Input fields in this sub-section.",
|
|
742
|
+
"items": { "$ref": "#/$defs/form_field" }
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
"required": ["title"],
|
|
746
|
+
"additionalProperties": false
|
|
747
|
+
},
|
|
748
|
+
|
|
749
|
+
"action": {
|
|
750
|
+
"type": "object",
|
|
751
|
+
"description": "A UI action button shown on index or show pages.",
|
|
752
|
+
"properties": {
|
|
753
|
+
"name": {
|
|
754
|
+
"type": "string",
|
|
755
|
+
"description": "Action identifier. Built-in names: show, edit, destroy, create, update, restore, permanently_destroy.",
|
|
756
|
+
"examples": ["show", "edit", "destroy", "archive", "export_pdf"]
|
|
757
|
+
},
|
|
758
|
+
"type": {
|
|
759
|
+
"type": "string",
|
|
760
|
+
"description": "'built_in' for standard CRUD actions; 'custom' for host-app actions; 'dialog' for actions that open a modal dialog; 'transition' for workflow transition overrides.",
|
|
761
|
+
"enum": ["built_in", "custom", "dialog", "transition"]
|
|
762
|
+
},
|
|
763
|
+
"label": {
|
|
764
|
+
"type": "string",
|
|
765
|
+
"description": "Button label text. Falls back to i18n lookup: lcp_ruby.actions.<name>."
|
|
766
|
+
},
|
|
767
|
+
"icon": {
|
|
768
|
+
"type": "string",
|
|
769
|
+
"description": "Lucide icon name for the action button.",
|
|
770
|
+
"examples": ["plus", "pencil", "trash-2", "archive"]
|
|
771
|
+
},
|
|
772
|
+
"confirm": {
|
|
773
|
+
"description": "Confirmation before executing. true uses browser confirm, string provides custom message, object for page-based or styled confirmation dialogs.",
|
|
774
|
+
"oneOf": [
|
|
775
|
+
{ "type": "boolean" },
|
|
776
|
+
{ "type": "string" },
|
|
777
|
+
{
|
|
778
|
+
"type": "object",
|
|
779
|
+
"description": "Page-based confirmation dialog. Opens a presenter-driven dialog form; on success, executes the original action with form data forwarded as confirmation_data params.",
|
|
780
|
+
"properties": {
|
|
781
|
+
"page": {
|
|
782
|
+
"type": "string",
|
|
783
|
+
"description": "Page name referencing a dialog-only presenter (e.g., 'delete_reason_dialog')."
|
|
784
|
+
},
|
|
785
|
+
"size": {
|
|
786
|
+
"type": "string",
|
|
787
|
+
"description": "Override the dialog size from page config.",
|
|
788
|
+
"enum": ["small", "medium", "large", "fullscreen"]
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
"required": ["page"],
|
|
792
|
+
"additionalProperties": false
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
"type": "object",
|
|
796
|
+
"description": "Styled confirmation dialog with custom title and message via i18n keys.",
|
|
797
|
+
"properties": {
|
|
798
|
+
"title_key": {
|
|
799
|
+
"type": "string",
|
|
800
|
+
"description": "I18n key for the confirmation dialog title."
|
|
801
|
+
},
|
|
802
|
+
"message_key": {
|
|
803
|
+
"type": "string",
|
|
804
|
+
"description": "I18n key for the confirmation dialog message."
|
|
805
|
+
},
|
|
806
|
+
"style": {
|
|
807
|
+
"type": "string",
|
|
808
|
+
"description": "Visual style of the confirmation dialog (e.g., 'danger')."
|
|
809
|
+
}
|
|
810
|
+
},
|
|
811
|
+
"additionalProperties": false
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
"type": "object",
|
|
815
|
+
"description": "Role-scoped confirmation.",
|
|
816
|
+
"properties": {
|
|
817
|
+
"except": {
|
|
818
|
+
"type": "array",
|
|
819
|
+
"items": { "type": "string" },
|
|
820
|
+
"description": "Skip confirmation for these roles."
|
|
821
|
+
},
|
|
822
|
+
"only": {
|
|
823
|
+
"type": "array",
|
|
824
|
+
"items": { "type": "string" },
|
|
825
|
+
"description": "Only require confirmation for these roles."
|
|
826
|
+
}
|
|
827
|
+
},
|
|
828
|
+
"additionalProperties": false
|
|
829
|
+
}
|
|
830
|
+
],
|
|
831
|
+
"examples": [true, "Are you sure?", { "page": "delete_reason_dialog" }, { "title_key": "lcp_ruby.dialogs.confirm_delete_title", "message_key": "lcp_ruby.dialogs.confirm_delete_message", "style": "danger" }]
|
|
832
|
+
},
|
|
833
|
+
"confirm_message": {
|
|
834
|
+
"type": "string",
|
|
835
|
+
"description": "Custom confirmation dialog message (alternative to confirm: 'message')."
|
|
836
|
+
},
|
|
837
|
+
"style": {
|
|
838
|
+
"type": "string",
|
|
839
|
+
"description": "Visual style of the button.",
|
|
840
|
+
"examples": ["danger", "primary", "secondary", "warning"]
|
|
841
|
+
},
|
|
842
|
+
"dialog": {
|
|
843
|
+
"type": "object",
|
|
844
|
+
"description": "Dialog configuration for type: dialog actions.",
|
|
845
|
+
"properties": {
|
|
846
|
+
"page": {
|
|
847
|
+
"type": "string",
|
|
848
|
+
"description": "Page name referencing a dialog-only presenter."
|
|
849
|
+
},
|
|
850
|
+
"record": {
|
|
851
|
+
"type": "string",
|
|
852
|
+
"description": "'current' to open the dialog with the current record for editing.",
|
|
853
|
+
"enum": ["current"]
|
|
854
|
+
},
|
|
855
|
+
"on_success": {
|
|
856
|
+
"type": "string",
|
|
857
|
+
"description": "Action after successful dialog submission.",
|
|
858
|
+
"enum": ["reload", "close", "redirect", "confirm_action", "reload_zone", "reload_zones"]
|
|
859
|
+
},
|
|
860
|
+
"size": {
|
|
861
|
+
"type": "string",
|
|
862
|
+
"description": "Override the dialog size from page config.",
|
|
863
|
+
"enum": ["small", "medium", "large", "fullscreen"]
|
|
864
|
+
},
|
|
865
|
+
"defaults": {
|
|
866
|
+
"type": "object",
|
|
867
|
+
"description": "Default field values to pre-fill in the dialog form.",
|
|
868
|
+
"additionalProperties": { "type": "string" }
|
|
869
|
+
},
|
|
870
|
+
"reload_zone": {
|
|
871
|
+
"type": "string",
|
|
872
|
+
"description": "Zone name to refresh when on_success is reload_zone."
|
|
873
|
+
},
|
|
874
|
+
"reload_zones": {
|
|
875
|
+
"type": "array",
|
|
876
|
+
"description": "Zone names to refresh when on_success is reload_zones.",
|
|
877
|
+
"items": { "type": "string" },
|
|
878
|
+
"minItems": 1
|
|
879
|
+
}
|
|
880
|
+
},
|
|
881
|
+
"required": ["page"],
|
|
882
|
+
"additionalProperties": false
|
|
883
|
+
},
|
|
884
|
+
"record": {
|
|
885
|
+
"type": "string",
|
|
886
|
+
"description": "Record context for dialog actions. 'current' passes the current record.",
|
|
887
|
+
"enum": ["current"]
|
|
888
|
+
},
|
|
889
|
+
"visible": {
|
|
890
|
+
"type": "boolean",
|
|
891
|
+
"description": "Explicitly show or hide this action. For transition overrides, set to false to suppress a workflow transition button in this presenter."
|
|
892
|
+
},
|
|
893
|
+
"visible_when": {
|
|
894
|
+
"$ref": "#/$defs/condition",
|
|
895
|
+
"description": "Conditionally show this action based on the record's field values."
|
|
896
|
+
},
|
|
897
|
+
"disable_when": {
|
|
898
|
+
"$ref": "#/$defs/condition",
|
|
899
|
+
"description": "Conditionally disable (gray out) this action."
|
|
900
|
+
},
|
|
901
|
+
"min_selection": {
|
|
902
|
+
"type": "integer",
|
|
903
|
+
"minimum": 1,
|
|
904
|
+
"description": "Batch actions: minimum records that must be selected (default: 1)."
|
|
905
|
+
},
|
|
906
|
+
"max_selection": {
|
|
907
|
+
"type": "integer",
|
|
908
|
+
"minimum": 1,
|
|
909
|
+
"description": "Batch actions: maximum records that can be selected."
|
|
910
|
+
},
|
|
911
|
+
"max_batch_records": {
|
|
912
|
+
"type": "integer",
|
|
913
|
+
"minimum": 1,
|
|
914
|
+
"description": "Batch actions: server-side limit on records affected."
|
|
915
|
+
},
|
|
916
|
+
"result_log": {
|
|
917
|
+
"type": "boolean",
|
|
918
|
+
"description": "Batch actions: enable per-record result tracking in batch operation log."
|
|
919
|
+
},
|
|
920
|
+
"select_all_filter": {
|
|
921
|
+
"type": "boolean",
|
|
922
|
+
"description": "Batch actions: allow 'select all matching filter' mode (default: true)."
|
|
923
|
+
},
|
|
924
|
+
"execution": {
|
|
925
|
+
"type": "string",
|
|
926
|
+
"enum": ["inline", "background", "auto"],
|
|
927
|
+
"description": "Batch actions: execution mode (default: inline)."
|
|
928
|
+
},
|
|
929
|
+
"background_threshold": {
|
|
930
|
+
"type": "integer",
|
|
931
|
+
"minimum": 1,
|
|
932
|
+
"description": "Batch actions: for execution: auto, record count above which action runs as background job (default: 100)."
|
|
933
|
+
},
|
|
934
|
+
"fields": {
|
|
935
|
+
"type": "array",
|
|
936
|
+
"items": { "type": "string" },
|
|
937
|
+
"description": "Batch update: which fields can be bulk-updated."
|
|
938
|
+
},
|
|
939
|
+
"strategy": {
|
|
940
|
+
"type": "string",
|
|
941
|
+
"enum": ["per_record", "bulk"],
|
|
942
|
+
"description": "Batch update: execution strategy (default: per_record)."
|
|
943
|
+
},
|
|
944
|
+
"pipeline": {
|
|
945
|
+
"type": "array",
|
|
946
|
+
"description": "Single actions: ordered list of operations to execute in a single transaction. On show pages there is no save step. Steps: { transition: <name> }, { action: <name> }.",
|
|
947
|
+
"items": {
|
|
948
|
+
"oneOf": [
|
|
949
|
+
{ "type": "string", "const": "save" },
|
|
950
|
+
{
|
|
951
|
+
"type": "object",
|
|
952
|
+
"properties": {
|
|
953
|
+
"transition": { "type": "string", "description": "Workflow transition name to fire." }
|
|
954
|
+
},
|
|
955
|
+
"required": ["transition"],
|
|
956
|
+
"additionalProperties": false
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
"type": "object",
|
|
960
|
+
"properties": {
|
|
961
|
+
"action": { "type": "string", "description": "Custom action name. Resolved as <model>/<name>." }
|
|
962
|
+
},
|
|
963
|
+
"required": ["action"],
|
|
964
|
+
"additionalProperties": false
|
|
965
|
+
}
|
|
966
|
+
]
|
|
967
|
+
},
|
|
968
|
+
"examples": [[{ "transition": "approve" }], [{ "transition": "reject" }, { "action": "notify_rejection" }]]
|
|
969
|
+
},
|
|
970
|
+
"transition": {
|
|
971
|
+
"type": "string",
|
|
972
|
+
"description": "Single actions: sugar for pipeline: [{ transition: <name> }]. Cannot be combined with pipeline or action.",
|
|
973
|
+
"examples": ["approve", "reject"]
|
|
974
|
+
},
|
|
975
|
+
"action": {
|
|
976
|
+
"type": "string",
|
|
977
|
+
"description": "Single actions: sugar for pipeline: [{ action: <name> }]. Cannot be combined with pipeline or transition.",
|
|
978
|
+
"examples": ["generate_report", "send_notification"]
|
|
979
|
+
},
|
|
980
|
+
"batch": {
|
|
981
|
+
"description": "Auto-derive a batch action from this single action. true: inherit name, type, icon, confirm, confirm_message, style, label, action_class. Hash: inherit and override with specified batch-specific options. Ignored on dialog and transition actions.",
|
|
982
|
+
"oneOf": [
|
|
983
|
+
{ "type": "boolean" },
|
|
984
|
+
{
|
|
985
|
+
"type": "object",
|
|
986
|
+
"description": "Batch-specific overrides merged on top of inherited single action attributes.",
|
|
987
|
+
"properties": {
|
|
988
|
+
"execution": {
|
|
989
|
+
"type": "string",
|
|
990
|
+
"enum": ["inline", "background", "auto"],
|
|
991
|
+
"description": "Execution mode. Default: inline."
|
|
992
|
+
},
|
|
993
|
+
"background_threshold": {
|
|
994
|
+
"type": "integer",
|
|
995
|
+
"minimum": 1,
|
|
996
|
+
"description": "For execution: auto — record count above which action runs as background job. Default: 100."
|
|
997
|
+
},
|
|
998
|
+
"min_selection": {
|
|
999
|
+
"type": "integer",
|
|
1000
|
+
"minimum": 1,
|
|
1001
|
+
"description": "Minimum records that must be selected. Default: 1."
|
|
1002
|
+
},
|
|
1003
|
+
"max_selection": {
|
|
1004
|
+
"type": "integer",
|
|
1005
|
+
"minimum": 1,
|
|
1006
|
+
"description": "Maximum records that can be selected."
|
|
1007
|
+
},
|
|
1008
|
+
"max_batch_records": {
|
|
1009
|
+
"type": "integer",
|
|
1010
|
+
"minimum": 1,
|
|
1011
|
+
"description": "Server-side limit on records affected."
|
|
1012
|
+
},
|
|
1013
|
+
"result_log": {
|
|
1014
|
+
"type": "boolean",
|
|
1015
|
+
"description": "Enable per-record result tracking. Requires lcp_ruby:batch_operations generator."
|
|
1016
|
+
},
|
|
1017
|
+
"select_all_filter": {
|
|
1018
|
+
"type": "boolean",
|
|
1019
|
+
"description": "Allow 'select all matching filter' mode."
|
|
1020
|
+
},
|
|
1021
|
+
"confirm": {
|
|
1022
|
+
"type": "boolean",
|
|
1023
|
+
"description": "Override confirm behavior for the batch action."
|
|
1024
|
+
},
|
|
1025
|
+
"confirm_message": {
|
|
1026
|
+
"type": "string",
|
|
1027
|
+
"description": "Override confirmation message for the batch action."
|
|
1028
|
+
},
|
|
1029
|
+
"icon": {
|
|
1030
|
+
"type": "string",
|
|
1031
|
+
"description": "Override icon for the batch action."
|
|
1032
|
+
},
|
|
1033
|
+
"label": {
|
|
1034
|
+
"type": "string",
|
|
1035
|
+
"description": "Override label for the batch action."
|
|
1036
|
+
},
|
|
1037
|
+
"style": {
|
|
1038
|
+
"type": "string",
|
|
1039
|
+
"description": "Override button style for the batch action."
|
|
1040
|
+
}
|
|
1041
|
+
},
|
|
1042
|
+
"additionalProperties": false
|
|
1043
|
+
}
|
|
1044
|
+
],
|
|
1045
|
+
"examples": [true, { "min_selection": 2, "result_log": true }, { "execution": "auto", "background_threshold": 50 }]
|
|
1046
|
+
}
|
|
1047
|
+
},
|
|
1048
|
+
"required": ["name", "type"],
|
|
1049
|
+
"additionalProperties": false
|
|
1050
|
+
},
|
|
1051
|
+
|
|
1052
|
+
"form_action": {
|
|
1053
|
+
"type": "object",
|
|
1054
|
+
"description": "A submit button rendered in the form footer. Each form action defines what happens when the user clicks it — save, redirect, set fields, fire a workflow transition, or execute a custom action.",
|
|
1055
|
+
"properties": {
|
|
1056
|
+
"name": {
|
|
1057
|
+
"type": "string",
|
|
1058
|
+
"description": "Unique identifier. Sent as `_form_action` param to the controller.",
|
|
1059
|
+
"examples": ["save", "save_and_new", "save_and_submit", "cancel"]
|
|
1060
|
+
},
|
|
1061
|
+
"type": {
|
|
1062
|
+
"type": "string",
|
|
1063
|
+
"description": "'built_in' for platform-provided actions (save, cancel). Omit for custom form actions.",
|
|
1064
|
+
"enum": ["built_in"]
|
|
1065
|
+
},
|
|
1066
|
+
"label": {
|
|
1067
|
+
"type": "string",
|
|
1068
|
+
"description": "Button label text. Falls back to i18n lookup chain: presenter-specific -> global -> humanized name.",
|
|
1069
|
+
"examples": ["Save & New", "Save & Submit for Approval"]
|
|
1070
|
+
},
|
|
1071
|
+
"submitting_label": {
|
|
1072
|
+
"type": "string",
|
|
1073
|
+
"description": "In-progress label shown while the form is submitting. Overrides the i18n fallback chain (lcp_ruby.form.submitting.<name>).",
|
|
1074
|
+
"examples": ["Saving…", "Enqueuing import job…"]
|
|
1075
|
+
},
|
|
1076
|
+
"icon": {
|
|
1077
|
+
"type": "string",
|
|
1078
|
+
"description": "Lucide icon name rendered before the label.",
|
|
1079
|
+
"examples": ["send", "globe", "check", "file-text"]
|
|
1080
|
+
},
|
|
1081
|
+
"style": {
|
|
1082
|
+
"type": "string",
|
|
1083
|
+
"description": "Button visual style.",
|
|
1084
|
+
"enum": ["primary", "secondary", "success", "danger", "warning", "outline"],
|
|
1085
|
+
"default": "secondary"
|
|
1086
|
+
},
|
|
1087
|
+
"redirect": {
|
|
1088
|
+
"description": "Where to go after pipeline completes. String for simple targets, hash for cross-presenter navigation. Ignored in dialog context.",
|
|
1089
|
+
"oneOf": [
|
|
1090
|
+
{
|
|
1091
|
+
"type": "string",
|
|
1092
|
+
"enum": ["show", "edit", "new", "index"]
|
|
1093
|
+
},
|
|
1094
|
+
{
|
|
1095
|
+
"type": "object",
|
|
1096
|
+
"description": "Follow an association to a related record's presenter.",
|
|
1097
|
+
"properties": {
|
|
1098
|
+
"association": {
|
|
1099
|
+
"type": "string",
|
|
1100
|
+
"description": "Association name on the model to follow."
|
|
1101
|
+
},
|
|
1102
|
+
"action": {
|
|
1103
|
+
"type": "string",
|
|
1104
|
+
"description": "Target action on the related presenter.",
|
|
1105
|
+
"enum": ["show", "edit", "new", "index"]
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
1108
|
+
"required": ["association"],
|
|
1109
|
+
"additionalProperties": false
|
|
1110
|
+
},
|
|
1111
|
+
{
|
|
1112
|
+
"type": "object",
|
|
1113
|
+
"description": "Navigate to a specific presenter by slug, optionally passing query parameters.",
|
|
1114
|
+
"properties": {
|
|
1115
|
+
"presenter": {
|
|
1116
|
+
"type": "string",
|
|
1117
|
+
"description": "Target presenter slug."
|
|
1118
|
+
},
|
|
1119
|
+
"action": {
|
|
1120
|
+
"type": "string",
|
|
1121
|
+
"description": "Target action.",
|
|
1122
|
+
"enum": ["show", "edit", "new", "index"]
|
|
1123
|
+
},
|
|
1124
|
+
"defaults": {
|
|
1125
|
+
"type": "object",
|
|
1126
|
+
"description": "Query parameters passed to the target. Values use the same expression syntax as set_fields — static values, { field_ref: <field> }, { current_user: id }, etc."
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
"required": ["presenter"],
|
|
1130
|
+
"additionalProperties": false
|
|
1131
|
+
}
|
|
1132
|
+
],
|
|
1133
|
+
"examples": ["show", "edit", "new", { "association": "order", "action": "show" }, { "presenter": "line_items", "action": "new", "defaults": { "order_id": { "field_ref": "id" } } }]
|
|
1134
|
+
},
|
|
1135
|
+
"set_fields": {
|
|
1136
|
+
"type": "object",
|
|
1137
|
+
"description": "Fields to set before the pipeline runs. Same syntax as workflow transition set_fields. Bypasses field-level write permissions (configurator-controlled).",
|
|
1138
|
+
"examples": [{ "status": "published", "published_at": { "date": "now" } }]
|
|
1139
|
+
},
|
|
1140
|
+
"pipeline": {
|
|
1141
|
+
"type": "array",
|
|
1142
|
+
"description": "Ordered list of operations to execute in a single transaction. Steps: 'save', { transition: <name> }, { action: <name> }. Default: [save].",
|
|
1143
|
+
"items": {
|
|
1144
|
+
"oneOf": [
|
|
1145
|
+
{ "type": "string", "const": "save" },
|
|
1146
|
+
{
|
|
1147
|
+
"type": "object",
|
|
1148
|
+
"properties": {
|
|
1149
|
+
"transition": { "type": "string", "description": "Workflow transition name to fire." }
|
|
1150
|
+
},
|
|
1151
|
+
"required": ["transition"],
|
|
1152
|
+
"additionalProperties": false
|
|
1153
|
+
},
|
|
1154
|
+
{
|
|
1155
|
+
"type": "object",
|
|
1156
|
+
"properties": {
|
|
1157
|
+
"action": { "type": "string", "description": "Custom action name. Resolved as <model>/<name>." }
|
|
1158
|
+
},
|
|
1159
|
+
"required": ["action"],
|
|
1160
|
+
"additionalProperties": false
|
|
1161
|
+
}
|
|
1162
|
+
]
|
|
1163
|
+
},
|
|
1164
|
+
"examples": [["save"], ["save", { "transition": "submit" }], ["save", { "transition": "submit" }, { "action": "notify_approvers" }]]
|
|
1165
|
+
},
|
|
1166
|
+
"transition": {
|
|
1167
|
+
"type": "string",
|
|
1168
|
+
"description": "Sugar for pipeline: [save, { transition: <name> }]. Cannot be combined with pipeline or action.",
|
|
1169
|
+
"examples": ["submit", "approve"]
|
|
1170
|
+
},
|
|
1171
|
+
"action": {
|
|
1172
|
+
"type": "string",
|
|
1173
|
+
"description": "Sugar for pipeline: [save, { action: <name> }]. Cannot be combined with pipeline or transition.",
|
|
1174
|
+
"examples": ["generate_invoice", "notify_manager"]
|
|
1175
|
+
},
|
|
1176
|
+
"confirm": {
|
|
1177
|
+
"description": "Confirmation before executing. Same syntax as record action confirm — boolean, string message, or object for styled/role-scoped confirmation.",
|
|
1178
|
+
"oneOf": [
|
|
1179
|
+
{ "type": "boolean" },
|
|
1180
|
+
{ "type": "string" },
|
|
1181
|
+
{
|
|
1182
|
+
"type": "object",
|
|
1183
|
+
"description": "Styled confirmation dialog.",
|
|
1184
|
+
"properties": {
|
|
1185
|
+
"title_key": { "type": "string" },
|
|
1186
|
+
"message_key": { "type": "string" },
|
|
1187
|
+
"style": { "type": "string" }
|
|
1188
|
+
},
|
|
1189
|
+
"additionalProperties": false
|
|
1190
|
+
},
|
|
1191
|
+
{
|
|
1192
|
+
"type": "object",
|
|
1193
|
+
"description": "Role-scoped confirmation.",
|
|
1194
|
+
"properties": {
|
|
1195
|
+
"except": { "type": "array", "items": { "type": "string" } },
|
|
1196
|
+
"only": { "type": "array", "items": { "type": "string" } }
|
|
1197
|
+
},
|
|
1198
|
+
"additionalProperties": false
|
|
1199
|
+
}
|
|
1200
|
+
],
|
|
1201
|
+
"examples": [true, "Submit this PO for approval?"]
|
|
1202
|
+
},
|
|
1203
|
+
"confirm_message": {
|
|
1204
|
+
"type": "string",
|
|
1205
|
+
"description": "Custom confirmation dialog message text.",
|
|
1206
|
+
"examples": ["Submit for approval? You won't be able to edit after this."]
|
|
1207
|
+
},
|
|
1208
|
+
"visible_when": {
|
|
1209
|
+
"$ref": "#/$defs/condition",
|
|
1210
|
+
"description": "Field-value or service condition for visibility."
|
|
1211
|
+
},
|
|
1212
|
+
"disable_when": {
|
|
1213
|
+
"$ref": "#/$defs/condition",
|
|
1214
|
+
"description": "Condition for disabled state."
|
|
1215
|
+
},
|
|
1216
|
+
"only_on": {
|
|
1217
|
+
"type": "string",
|
|
1218
|
+
"description": "Restrict to create or update context. Omit to show on both.",
|
|
1219
|
+
"enum": ["create", "update"]
|
|
1220
|
+
},
|
|
1221
|
+
"only_roles": {
|
|
1222
|
+
"type": "array",
|
|
1223
|
+
"items": { "type": "string" },
|
|
1224
|
+
"description": "Only these roles see this button.",
|
|
1225
|
+
"examples": [["admin", "manager"]]
|
|
1226
|
+
},
|
|
1227
|
+
"except_roles": {
|
|
1228
|
+
"type": "array",
|
|
1229
|
+
"items": { "type": "string" },
|
|
1230
|
+
"description": "These roles do not see this button.",
|
|
1231
|
+
"examples": [["viewer"]]
|
|
1232
|
+
},
|
|
1233
|
+
"dialog_behavior": {
|
|
1234
|
+
"type": "string",
|
|
1235
|
+
"description": "Dialog-only: what happens after successful save. 'close' closes the dialog, 'reset' clears the form and keeps it open, 'reload' reloads the parent page, 'show_result' renders a result partial (one-time secret display, etc.) — requires a 'result' config. Ignored outside dialog context.",
|
|
1236
|
+
"enum": ["close", "reset", "reload", "show_result"]
|
|
1237
|
+
},
|
|
1238
|
+
"result": {
|
|
1239
|
+
"type": "object",
|
|
1240
|
+
"description": "Configuration for dialog_behavior: show_result. Selects a platform-shipped partial via 'style' (currently: 'single_secret'), or renders a host partial via 'partial'. When 'style' is given, 'field' names the in-memory record attribute to display.",
|
|
1241
|
+
"properties": {
|
|
1242
|
+
"style": {
|
|
1243
|
+
"type": "string",
|
|
1244
|
+
"enum": ["single_secret"],
|
|
1245
|
+
"description": "Platform-shipped result style. Maps to app/views/lcp_ruby/dialogs/_<style>.html.erb."
|
|
1246
|
+
},
|
|
1247
|
+
"partial": {
|
|
1248
|
+
"type": "string",
|
|
1249
|
+
"description": "Host-owned partial path (escape hatch). Mutually exclusive with 'style'."
|
|
1250
|
+
},
|
|
1251
|
+
"field": {
|
|
1252
|
+
"type": "string",
|
|
1253
|
+
"description": "Required when 'style' is set: the model attribute to display."
|
|
1254
|
+
},
|
|
1255
|
+
"title_key": {
|
|
1256
|
+
"type": "string",
|
|
1257
|
+
"description": "I18n key for the dialog heading."
|
|
1258
|
+
},
|
|
1259
|
+
"warning_key": {
|
|
1260
|
+
"type": "string",
|
|
1261
|
+
"description": "I18n key for the warning paragraph (e.g., 'this will not be shown again')."
|
|
1262
|
+
}
|
|
1263
|
+
},
|
|
1264
|
+
"additionalProperties": false
|
|
1265
|
+
},
|
|
1266
|
+
"position": {
|
|
1267
|
+
"type": "string",
|
|
1268
|
+
"description": "'inline' renders the button in the row, 'dropdown' forces it into the overflow menu.",
|
|
1269
|
+
"enum": ["inline", "dropdown"],
|
|
1270
|
+
"default": "inline"
|
|
1271
|
+
}
|
|
1272
|
+
},
|
|
1273
|
+
"required": ["name"],
|
|
1274
|
+
"additionalProperties": false
|
|
1275
|
+
},
|
|
1276
|
+
|
|
1277
|
+
"search_filter": {
|
|
1278
|
+
"type": "object",
|
|
1279
|
+
"description": "A predefined filter shown as a tab/chip above the index table. Activates a named scope on the model.",
|
|
1280
|
+
"properties": {
|
|
1281
|
+
"name": {
|
|
1282
|
+
"type": "string",
|
|
1283
|
+
"description": "Filter identifier, usually matching a scope name.",
|
|
1284
|
+
"examples": ["active", "overdue", "my_records"]
|
|
1285
|
+
},
|
|
1286
|
+
"label": {
|
|
1287
|
+
"type": "string",
|
|
1288
|
+
"description": "Display label for the filter tab."
|
|
1289
|
+
},
|
|
1290
|
+
"default": {
|
|
1291
|
+
"type": "boolean",
|
|
1292
|
+
"description": "If true, this filter is active by default when the page loads."
|
|
1293
|
+
},
|
|
1294
|
+
"scope": {
|
|
1295
|
+
"type": "string",
|
|
1296
|
+
"description": "Scope name to activate. Defaults to the filter name if omitted.",
|
|
1297
|
+
"examples": ["active", "with_discarded"]
|
|
1298
|
+
}
|
|
1299
|
+
},
|
|
1300
|
+
"required": ["name", "label"],
|
|
1301
|
+
"additionalProperties": false,
|
|
1302
|
+
"examples": [{ "name": "active", "label": "Active", "default": true }]
|
|
1303
|
+
},
|
|
1304
|
+
|
|
1305
|
+
"search_parameter": {
|
|
1306
|
+
"type": "object",
|
|
1307
|
+
"description": "A typed filter control rendered in the search toolbar (dropdown, toggle, or range input).",
|
|
1308
|
+
"properties": {
|
|
1309
|
+
"name": {
|
|
1310
|
+
"type": "string",
|
|
1311
|
+
"description": "Parameter identifier."
|
|
1312
|
+
},
|
|
1313
|
+
"type": {
|
|
1314
|
+
"type": "string",
|
|
1315
|
+
"description": "Control type.",
|
|
1316
|
+
"enum": ["enum_select", "association_select", "boolean_select", "number_range", "date_range"]
|
|
1317
|
+
},
|
|
1318
|
+
"field": {
|
|
1319
|
+
"type": "string",
|
|
1320
|
+
"description": "Model field name to filter by."
|
|
1321
|
+
},
|
|
1322
|
+
"model": {
|
|
1323
|
+
"type": "string",
|
|
1324
|
+
"description": "Target model name for association_select. Auto-derived from field's belongs_to if omitted."
|
|
1325
|
+
},
|
|
1326
|
+
"options": {
|
|
1327
|
+
"type": "array",
|
|
1328
|
+
"description": "Explicit options for enum_select. Auto-derived from model enum definition if omitted.",
|
|
1329
|
+
"items": { "type": "string" }
|
|
1330
|
+
},
|
|
1331
|
+
"label_key": {
|
|
1332
|
+
"type": "string",
|
|
1333
|
+
"description": "I18n key for the parameter label."
|
|
1334
|
+
},
|
|
1335
|
+
"label_method": {
|
|
1336
|
+
"type": "string",
|
|
1337
|
+
"description": "Method name for display label on association records."
|
|
1338
|
+
},
|
|
1339
|
+
"visible_when": {
|
|
1340
|
+
"type": "object",
|
|
1341
|
+
"description": "Role-based visibility. Only the 'role' key is supported (no condition-based evaluation on index pages).",
|
|
1342
|
+
"properties": {
|
|
1343
|
+
"role": {
|
|
1344
|
+
"oneOf": [
|
|
1345
|
+
{ "type": "string" },
|
|
1346
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
1347
|
+
],
|
|
1348
|
+
"description": "Role name or array of role names that can see this parameter."
|
|
1349
|
+
}
|
|
1350
|
+
},
|
|
1351
|
+
"additionalProperties": false
|
|
1352
|
+
},
|
|
1353
|
+
"search": {
|
|
1354
|
+
"type": "boolean",
|
|
1355
|
+
"description": "Enable server-side search for association_select (remote Tom Select mode)."
|
|
1356
|
+
},
|
|
1357
|
+
"min_query_length": {
|
|
1358
|
+
"type": "integer",
|
|
1359
|
+
"description": "Minimum characters before remote search triggers.",
|
|
1360
|
+
"minimum": 0
|
|
1361
|
+
},
|
|
1362
|
+
"per_page": {
|
|
1363
|
+
"type": "integer",
|
|
1364
|
+
"description": "Results per page for remote search.",
|
|
1365
|
+
"minimum": 1
|
|
1366
|
+
},
|
|
1367
|
+
"include_blank": {
|
|
1368
|
+
"oneOf": [
|
|
1369
|
+
{ "type": "boolean" },
|
|
1370
|
+
{ "type": "string" }
|
|
1371
|
+
],
|
|
1372
|
+
"description": "Label for the blank 'All' option. Set to false to omit, or a string to customize the label."
|
|
1373
|
+
},
|
|
1374
|
+
"col_span": {
|
|
1375
|
+
"type": "integer",
|
|
1376
|
+
"minimum": 1,
|
|
1377
|
+
"description": "Number of grid columns this parameter spans. Range types default to 2 when search columns >= 2."
|
|
1378
|
+
}
|
|
1379
|
+
},
|
|
1380
|
+
"required": ["name", "type", "field"],
|
|
1381
|
+
"additionalProperties": false
|
|
1382
|
+
},
|
|
1383
|
+
|
|
1384
|
+
"default_sort": {
|
|
1385
|
+
"type": "object",
|
|
1386
|
+
"description": "Default sorting applied to the index table on initial load.",
|
|
1387
|
+
"properties": {
|
|
1388
|
+
"field": {
|
|
1389
|
+
"type": "string",
|
|
1390
|
+
"description": "Field name to sort by.",
|
|
1391
|
+
"examples": ["name", "created_at", "status"]
|
|
1392
|
+
},
|
|
1393
|
+
"direction": {
|
|
1394
|
+
"type": "string",
|
|
1395
|
+
"description": "Sort direction.",
|
|
1396
|
+
"enum": ["asc", "desc"],
|
|
1397
|
+
"default": "asc"
|
|
1398
|
+
}
|
|
1399
|
+
},
|
|
1400
|
+
"required": ["field"],
|
|
1401
|
+
"additionalProperties": false,
|
|
1402
|
+
"examples": [{ "field": "created_at", "direction": "desc" }]
|
|
1403
|
+
},
|
|
1404
|
+
|
|
1405
|
+
"card_field": {
|
|
1406
|
+
"type": "object",
|
|
1407
|
+
"description": "A field displayed in a card field list.",
|
|
1408
|
+
"properties": {
|
|
1409
|
+
"field": {
|
|
1410
|
+
"type": "string",
|
|
1411
|
+
"description": "Field name to display. Supports dot-path for associations."
|
|
1412
|
+
},
|
|
1413
|
+
"label": {
|
|
1414
|
+
"type": "string",
|
|
1415
|
+
"description": "Label shown next to the field value."
|
|
1416
|
+
},
|
|
1417
|
+
"renderer": {
|
|
1418
|
+
"type": "string",
|
|
1419
|
+
"description": "Display renderer name. Mutually exclusive with 'partial' (partial wins)."
|
|
1420
|
+
},
|
|
1421
|
+
"options": {
|
|
1422
|
+
"type": "object",
|
|
1423
|
+
"description": "Options passed to the renderer or partial."
|
|
1424
|
+
},
|
|
1425
|
+
"partial": {
|
|
1426
|
+
"type": "string",
|
|
1427
|
+
"description": "Host-app partial path for fully custom cell rendering. Receives locals { value, record, options }. Mutually exclusive with 'renderer' (partial wins)."
|
|
1428
|
+
}
|
|
1429
|
+
},
|
|
1430
|
+
"required": ["field"],
|
|
1431
|
+
"additionalProperties": false
|
|
1432
|
+
},
|
|
1433
|
+
|
|
1434
|
+
"card_config": {
|
|
1435
|
+
"type": "object",
|
|
1436
|
+
"description": "Per-record card interior shared across card-based layouts (tiles, kanban, future). Zone resolution lives in LcpRuby::Display::CardHelper; per-layout body partials compose these zones in their own order.",
|
|
1437
|
+
"properties": {
|
|
1438
|
+
"title_field": {
|
|
1439
|
+
"type": "string",
|
|
1440
|
+
"description": "Field to display as the card title. Required for any card-based layout."
|
|
1441
|
+
},
|
|
1442
|
+
"subtitle_field": {
|
|
1443
|
+
"type": "string",
|
|
1444
|
+
"description": "Field to display as the card subtitle."
|
|
1445
|
+
},
|
|
1446
|
+
"subtitle_renderer": {
|
|
1447
|
+
"type": "string",
|
|
1448
|
+
"description": "Renderer for the subtitle field (e.g., 'badge')."
|
|
1449
|
+
},
|
|
1450
|
+
"subtitle_options": {
|
|
1451
|
+
"type": "object",
|
|
1452
|
+
"description": "Options passed to the subtitle renderer."
|
|
1453
|
+
},
|
|
1454
|
+
"description_field": {
|
|
1455
|
+
"type": "string",
|
|
1456
|
+
"description": "Field for card description text, shown with line clamping."
|
|
1457
|
+
},
|
|
1458
|
+
"description_max_lines": {
|
|
1459
|
+
"type": "integer",
|
|
1460
|
+
"minimum": 1,
|
|
1461
|
+
"description": "Maximum lines for description text before truncation.",
|
|
1462
|
+
"default": 3
|
|
1463
|
+
},
|
|
1464
|
+
"image_field": {
|
|
1465
|
+
"type": "string",
|
|
1466
|
+
"description": "Field containing image URL or Active Storage attachment for the banner image zone."
|
|
1467
|
+
},
|
|
1468
|
+
"image_alt_field": {
|
|
1469
|
+
"type": "string",
|
|
1470
|
+
"description": "Field providing alt text for the banner image. Falls back to title_field value when unset."
|
|
1471
|
+
},
|
|
1472
|
+
"avatar_field": {
|
|
1473
|
+
"type": "string",
|
|
1474
|
+
"description": "Field containing image URL or Active Storage attachment for the small circular avatar zone."
|
|
1475
|
+
},
|
|
1476
|
+
"avatar_alt_field": {
|
|
1477
|
+
"type": "string",
|
|
1478
|
+
"description": "Field providing alt text for the avatar. Defaults to '' (decorative) when unset."
|
|
1479
|
+
},
|
|
1480
|
+
"color_field": {
|
|
1481
|
+
"type": "string",
|
|
1482
|
+
"description": "Field whose value drives the color accent. Mapped through color_map (or workflow state color) to a whitelisted palette token; raw values never reach CSS."
|
|
1483
|
+
},
|
|
1484
|
+
"color_map": {
|
|
1485
|
+
"type": "object",
|
|
1486
|
+
"description": "Maps field values to whitelisted palette tokens.",
|
|
1487
|
+
"additionalProperties": {
|
|
1488
|
+
"type": "string",
|
|
1489
|
+
"enum": ["success", "danger", "warning", "info", "muted", "primary"]
|
|
1490
|
+
}
|
|
1491
|
+
},
|
|
1492
|
+
"actions": {
|
|
1493
|
+
"type": "string",
|
|
1494
|
+
"description": "How to render per-card actions.",
|
|
1495
|
+
"enum": ["dropdown", "inline", "none"],
|
|
1496
|
+
"default": "dropdown"
|
|
1497
|
+
},
|
|
1498
|
+
"render_with": {
|
|
1499
|
+
"type": "string",
|
|
1500
|
+
"pattern": "^[a-z][a-z0-9_/]*$",
|
|
1501
|
+
"description": "Host-app partial path rendering the full card body. Lowercase, slash-separated (e.g., 'my_app/cards/deal'). File must exist at app/views/<path>/_<basename>.html.erb. Validated for shape at boot; existence checked at first render.",
|
|
1502
|
+
"examples": ["my_app/cards/deal", "admin/cards/company"]
|
|
1503
|
+
},
|
|
1504
|
+
"fields": {
|
|
1505
|
+
"type": "array",
|
|
1506
|
+
"description": "Additional fields displayed as label-value pairs in the card.",
|
|
1507
|
+
"items": { "$ref": "#/$defs/card_field" }
|
|
1508
|
+
}
|
|
1509
|
+
},
|
|
1510
|
+
"required": ["title_field"],
|
|
1511
|
+
"additionalProperties": false
|
|
1512
|
+
},
|
|
1513
|
+
|
|
1514
|
+
"tile_config": {
|
|
1515
|
+
"type": "object",
|
|
1516
|
+
"description": "Tile-layout-specific grid configuration. Card zone rendering lives in card_config (sibling 'card:' block).",
|
|
1517
|
+
"properties": {
|
|
1518
|
+
"columns": {
|
|
1519
|
+
"type": "integer",
|
|
1520
|
+
"minimum": 1,
|
|
1521
|
+
"description": "Number of tile columns in the grid.",
|
|
1522
|
+
"default": 3,
|
|
1523
|
+
"examples": [2, 3, 4]
|
|
1524
|
+
}
|
|
1525
|
+
},
|
|
1526
|
+
"additionalProperties": false
|
|
1527
|
+
},
|
|
1528
|
+
|
|
1529
|
+
"kanban_config": {
|
|
1530
|
+
"type": "object",
|
|
1531
|
+
"description": "Kanban-layout-specific configuration. Card zone rendering lives in card_config (sibling 'card:' block). See docs/design/kanban_view.md for the full Phase 1 contract.",
|
|
1532
|
+
"properties": {
|
|
1533
|
+
"provider": {
|
|
1534
|
+
"type": "string",
|
|
1535
|
+
"description": "Custom provider class name (must inherit from LcpRuby::Kanban::HostProvider). When unset, DefaultProvider is used.",
|
|
1536
|
+
"examples": ["TaskUrgencyProvider", "MyApp::CustomKanbanProvider"]
|
|
1537
|
+
},
|
|
1538
|
+
"group_by": {
|
|
1539
|
+
"type": "string",
|
|
1540
|
+
"description": "Field used to bucket records into columns. Required for DefaultProvider (workflow field, enum field, or belongs_to association). Treated as a hint by custom providers.",
|
|
1541
|
+
"examples": ["status", "stage", "assignee"]
|
|
1542
|
+
},
|
|
1543
|
+
"column_order": {
|
|
1544
|
+
"type": "array",
|
|
1545
|
+
"description": "Explicit column ordering. Required when group_by is a belongs_to association (FK list). For workflow/enum, overrides default declared order.",
|
|
1546
|
+
"items": { "type": ["string", "integer"] }
|
|
1547
|
+
},
|
|
1548
|
+
"cards_per_column": {
|
|
1549
|
+
"type": "integer",
|
|
1550
|
+
"minimum": 1,
|
|
1551
|
+
"default": 20,
|
|
1552
|
+
"description": "Maximum cards loaded per column on initial render; remaining loaded via 'Load more' (Turbo Frame)."
|
|
1553
|
+
},
|
|
1554
|
+
"within_column_order": {
|
|
1555
|
+
"type": "string",
|
|
1556
|
+
"description": "ORDER BY expression for cards within a column (e.g., 'created_at DESC'). Defaults: position ASC when model is positioned and scope matches; else created_at DESC; else id DESC."
|
|
1557
|
+
},
|
|
1558
|
+
"show_null_column": {
|
|
1559
|
+
"type": "boolean",
|
|
1560
|
+
"default": false,
|
|
1561
|
+
"description": "Show a leading 'Uncategorized' column for records whose group_by value is NULL."
|
|
1562
|
+
}
|
|
1563
|
+
},
|
|
1564
|
+
"additionalProperties": false
|
|
1565
|
+
},
|
|
1566
|
+
|
|
1567
|
+
"sort_field_entry": {
|
|
1568
|
+
"type": "object",
|
|
1569
|
+
"description": "A field available in the sort dropdown.",
|
|
1570
|
+
"properties": {
|
|
1571
|
+
"field": {
|
|
1572
|
+
"type": "string",
|
|
1573
|
+
"description": "Field name to sort by."
|
|
1574
|
+
},
|
|
1575
|
+
"label": {
|
|
1576
|
+
"type": "string",
|
|
1577
|
+
"description": "Display label in the sort dropdown."
|
|
1578
|
+
}
|
|
1579
|
+
},
|
|
1580
|
+
"required": ["field"],
|
|
1581
|
+
"additionalProperties": false
|
|
1582
|
+
},
|
|
1583
|
+
|
|
1584
|
+
"summary_field": {
|
|
1585
|
+
"type": "object",
|
|
1586
|
+
"description": "A field in the summary bar with an aggregate function.",
|
|
1587
|
+
"properties": {
|
|
1588
|
+
"field": {
|
|
1589
|
+
"type": "string",
|
|
1590
|
+
"description": "Field name to aggregate."
|
|
1591
|
+
},
|
|
1592
|
+
"function": {
|
|
1593
|
+
"type": "string",
|
|
1594
|
+
"description": "SQL aggregate function to apply.",
|
|
1595
|
+
"enum": ["sum", "avg", "count", "min", "max"]
|
|
1596
|
+
},
|
|
1597
|
+
"label": {
|
|
1598
|
+
"type": "string",
|
|
1599
|
+
"description": "Label displayed in the summary bar."
|
|
1600
|
+
},
|
|
1601
|
+
"renderer": {
|
|
1602
|
+
"type": "string",
|
|
1603
|
+
"description": "Display renderer for the aggregate value."
|
|
1604
|
+
},
|
|
1605
|
+
"options": {
|
|
1606
|
+
"type": "object",
|
|
1607
|
+
"description": "Options passed to the renderer."
|
|
1608
|
+
}
|
|
1609
|
+
},
|
|
1610
|
+
"required": ["field", "function"],
|
|
1611
|
+
"additionalProperties": false
|
|
1612
|
+
},
|
|
1613
|
+
|
|
1614
|
+
"summary_config": {
|
|
1615
|
+
"type": "object",
|
|
1616
|
+
"description": "Configuration for the summary bar displayed below the index content.",
|
|
1617
|
+
"properties": {
|
|
1618
|
+
"enabled": {
|
|
1619
|
+
"type": "boolean",
|
|
1620
|
+
"description": "Enable the summary bar."
|
|
1621
|
+
},
|
|
1622
|
+
"fields": {
|
|
1623
|
+
"type": "array",
|
|
1624
|
+
"description": "Fields with aggregate functions to display in the summary bar.",
|
|
1625
|
+
"items": { "$ref": "#/$defs/summary_field" }
|
|
1626
|
+
}
|
|
1627
|
+
},
|
|
1628
|
+
"additionalProperties": false
|
|
1629
|
+
},
|
|
1630
|
+
|
|
1631
|
+
"index_config": {
|
|
1632
|
+
"type": "object",
|
|
1633
|
+
"description": "Configuration for the index (list) page.",
|
|
1634
|
+
"properties": {
|
|
1635
|
+
"render_with": {
|
|
1636
|
+
"type": "string",
|
|
1637
|
+
"description": "Replace the entire index content area with a custom host-app partial. When set, 'layout' is ignored. The search/sort/scope pipeline still runs.",
|
|
1638
|
+
"examples": ["analytics/dashboard", "reports/custom_index"]
|
|
1639
|
+
},
|
|
1640
|
+
"layout": {
|
|
1641
|
+
"type": "string",
|
|
1642
|
+
"description": "Index page layout mode. 'table' (default), 'tiles' for card grid, 'tree' for tree hierarchy, 'kanban' for column-based pipeline view. Ignored when 'render_with' is set.",
|
|
1643
|
+
"enum": ["table", "tiles", "tree", "kanban"]
|
|
1644
|
+
},
|
|
1645
|
+
"reorderable": {
|
|
1646
|
+
"type": "boolean",
|
|
1647
|
+
"description": "Enable drag-and-drop row reordering. Requires positioning on the model."
|
|
1648
|
+
},
|
|
1649
|
+
"description": {
|
|
1650
|
+
"type": "string",
|
|
1651
|
+
"description": "Explanatory text shown above the table."
|
|
1652
|
+
},
|
|
1653
|
+
"default_view": {
|
|
1654
|
+
"type": "string",
|
|
1655
|
+
"description": "Deprecated: use view groups instead.",
|
|
1656
|
+
"default": "table",
|
|
1657
|
+
"examples": ["table", "card", "tree"]
|
|
1658
|
+
},
|
|
1659
|
+
"views_available": {
|
|
1660
|
+
"type": "array",
|
|
1661
|
+
"items": { "type": "string" },
|
|
1662
|
+
"description": "Deprecated: use view groups instead.",
|
|
1663
|
+
"examples": [["table", "card"]]
|
|
1664
|
+
},
|
|
1665
|
+
"default_sort": { "$ref": "#/$defs/default_sort" },
|
|
1666
|
+
"per_page": {
|
|
1667
|
+
"type": "integer",
|
|
1668
|
+
"minimum": 1,
|
|
1669
|
+
"description": "Number of records per page (Kaminari pagination).",
|
|
1670
|
+
"default": 25,
|
|
1671
|
+
"examples": [10, 25, 50, 100]
|
|
1672
|
+
},
|
|
1673
|
+
"per_page_options": {
|
|
1674
|
+
"type": "array",
|
|
1675
|
+
"items": { "type": "integer", "minimum": 1 },
|
|
1676
|
+
"description": "Selectable page sizes shown in a dropdown near pagination.",
|
|
1677
|
+
"examples": [[10, 25, 50, 100]]
|
|
1678
|
+
},
|
|
1679
|
+
"show_record_count": {
|
|
1680
|
+
"type": "boolean",
|
|
1681
|
+
"description": "Show record count text in pagination footer (default: true)."
|
|
1682
|
+
},
|
|
1683
|
+
"pagination_ends": {
|
|
1684
|
+
"type": "boolean",
|
|
1685
|
+
"description": "Show First/Last page links in pagination (default: from global config, false)."
|
|
1686
|
+
},
|
|
1687
|
+
"table_columns": {
|
|
1688
|
+
"type": "array",
|
|
1689
|
+
"description": "Columns displayed in the index table.",
|
|
1690
|
+
"items": { "$ref": "#/$defs/table_column" }
|
|
1691
|
+
},
|
|
1692
|
+
"tile": { "$ref": "#/$defs/tile_config" },
|
|
1693
|
+
"card": { "$ref": "#/$defs/card_config" },
|
|
1694
|
+
"kanban": { "$ref": "#/$defs/kanban_config" },
|
|
1695
|
+
"sort_fields": {
|
|
1696
|
+
"type": "array",
|
|
1697
|
+
"description": "Fields available in the sort dropdown (auto-derived for tiles if omitted).",
|
|
1698
|
+
"items": { "$ref": "#/$defs/sort_field_entry" }
|
|
1699
|
+
},
|
|
1700
|
+
"summary": { "$ref": "#/$defs/summary_config" },
|
|
1701
|
+
"query_mode": {
|
|
1702
|
+
"type": "string",
|
|
1703
|
+
"description": "Query mode for the index. 'grouped' enables GROUP BY aggregation.",
|
|
1704
|
+
"enum": ["grouped"]
|
|
1705
|
+
},
|
|
1706
|
+
"group_by": {
|
|
1707
|
+
"type": "array",
|
|
1708
|
+
"description": "Fields to GROUP BY in grouped query mode. Each item is a field name or an object with field and period (for date truncation).",
|
|
1709
|
+
"items": {
|
|
1710
|
+
"oneOf": [
|
|
1711
|
+
{ "type": "string" },
|
|
1712
|
+
{
|
|
1713
|
+
"type": "object",
|
|
1714
|
+
"properties": {
|
|
1715
|
+
"field": { "type": "string" },
|
|
1716
|
+
"period": { "type": "string", "enum": ["day", "week", "month", "quarter", "year"] }
|
|
1717
|
+
},
|
|
1718
|
+
"required": ["field"],
|
|
1719
|
+
"additionalProperties": false
|
|
1720
|
+
}
|
|
1721
|
+
]
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
"having": {
|
|
1725
|
+
"type": "array",
|
|
1726
|
+
"description": "HAVING conditions for grouped queries.",
|
|
1727
|
+
"items": { "type": "object" }
|
|
1728
|
+
},
|
|
1729
|
+
"limit": {
|
|
1730
|
+
"type": "integer",
|
|
1731
|
+
"description": "Maximum number of group rows to return.",
|
|
1732
|
+
"minimum": 1
|
|
1733
|
+
},
|
|
1734
|
+
"row_click": {
|
|
1735
|
+
"description": "Action triggered when clicking a table row. String for simple actions, object for grouped query filter navigation.",
|
|
1736
|
+
"oneOf": [
|
|
1737
|
+
{ "type": "string" },
|
|
1738
|
+
{
|
|
1739
|
+
"type": "object",
|
|
1740
|
+
"properties": {
|
|
1741
|
+
"mode": { "type": "string", "enum": ["filter"] },
|
|
1742
|
+
"target": { "type": "string", "description": "Target presenter slug to navigate to with group filters applied." }
|
|
1743
|
+
},
|
|
1744
|
+
"required": ["mode", "target"],
|
|
1745
|
+
"additionalProperties": false
|
|
1746
|
+
}
|
|
1747
|
+
],
|
|
1748
|
+
"examples": ["show", "edit", { "mode": "filter", "target": "features" }]
|
|
1749
|
+
},
|
|
1750
|
+
"empty_message": {
|
|
1751
|
+
"type": "string",
|
|
1752
|
+
"description": "Message shown when no records match the current filters.",
|
|
1753
|
+
"examples": ["No employees found."]
|
|
1754
|
+
},
|
|
1755
|
+
"actions_position": {
|
|
1756
|
+
"type": "string",
|
|
1757
|
+
"description": "Position of action buttons in table rows.",
|
|
1758
|
+
"examples": ["right", "left", "dropdown"]
|
|
1759
|
+
},
|
|
1760
|
+
"includes": {
|
|
1761
|
+
"type": "array",
|
|
1762
|
+
"description": "Manual eager loading hints (AR includes). Auto-detected from presenter fields if omitted.",
|
|
1763
|
+
"examples": [["department", "manager"]]
|
|
1764
|
+
},
|
|
1765
|
+
"eager_load": {
|
|
1766
|
+
"type": "array",
|
|
1767
|
+
"description": "Manual eager_load hints (uses LEFT OUTER JOIN). Use for associations that must always be loaded.",
|
|
1768
|
+
"examples": [["company"]]
|
|
1769
|
+
},
|
|
1770
|
+
"tree_view": {
|
|
1771
|
+
"type": "boolean",
|
|
1772
|
+
"description": "Deprecated: use layout: tree instead. Enable tree-structured index view."
|
|
1773
|
+
},
|
|
1774
|
+
"default_expanded": {
|
|
1775
|
+
"description": "For tree layout: how many levels to expand by default. 0 means all collapsed, 'all' means fully expanded.",
|
|
1776
|
+
"oneOf": [
|
|
1777
|
+
{ "type": "integer", "minimum": 0 },
|
|
1778
|
+
{ "type": "string", "const": "all" }
|
|
1779
|
+
],
|
|
1780
|
+
"default": 0,
|
|
1781
|
+
"examples": [0, 2, "all"]
|
|
1782
|
+
},
|
|
1783
|
+
"reparentable": {
|
|
1784
|
+
"type": "boolean",
|
|
1785
|
+
"description": "For tree layout: allow drag-and-drop reparenting of tree nodes."
|
|
1786
|
+
},
|
|
1787
|
+
"item_classes": {
|
|
1788
|
+
"type": "array",
|
|
1789
|
+
"description": "Conditional CSS classes applied to each row/card element based on record field values. All matching rules accumulate.",
|
|
1790
|
+
"items": { "$ref": "#/$defs/item_class_rule" }
|
|
1791
|
+
}
|
|
1792
|
+
},
|
|
1793
|
+
"additionalProperties": false
|
|
1794
|
+
},
|
|
1795
|
+
|
|
1796
|
+
"show_config": {
|
|
1797
|
+
"type": "object",
|
|
1798
|
+
"description": "Configuration for the show (detail) page.",
|
|
1799
|
+
"properties": {
|
|
1800
|
+
"description": {
|
|
1801
|
+
"type": "string",
|
|
1802
|
+
"description": "Explanatory text shown at the top of the show page."
|
|
1803
|
+
},
|
|
1804
|
+
"render_with": {
|
|
1805
|
+
"type": "string",
|
|
1806
|
+
"description": "Replace the entire show content area with a custom host-app partial. Ignored in dialog and composite page contexts.",
|
|
1807
|
+
"examples": ["products/custom_show", "reports/detail_view"]
|
|
1808
|
+
},
|
|
1809
|
+
"copy_url": {
|
|
1810
|
+
"type": "boolean",
|
|
1811
|
+
"description": "Show a 'Copy URL' button in the toolbar for sharing direct links to this record."
|
|
1812
|
+
},
|
|
1813
|
+
"layout": {
|
|
1814
|
+
"type": "array",
|
|
1815
|
+
"description": "Ordered list of sections displayed on the show page.",
|
|
1816
|
+
"items": { "$ref": "#/$defs/show_section" }
|
|
1817
|
+
},
|
|
1818
|
+
"includes": {
|
|
1819
|
+
"type": "array",
|
|
1820
|
+
"description": "Manual eager loading hints for the show page."
|
|
1821
|
+
},
|
|
1822
|
+
"eager_load": {
|
|
1823
|
+
"type": "array",
|
|
1824
|
+
"description": "Manual eager_load hints for the show page."
|
|
1825
|
+
}
|
|
1826
|
+
},
|
|
1827
|
+
"additionalProperties": false
|
|
1828
|
+
},
|
|
1829
|
+
|
|
1830
|
+
"form_config": {
|
|
1831
|
+
"type": "object",
|
|
1832
|
+
"description": "Configuration for the new/edit form.",
|
|
1833
|
+
"properties": {
|
|
1834
|
+
"description": {
|
|
1835
|
+
"type": "string",
|
|
1836
|
+
"description": "Explanatory text shown above the form."
|
|
1837
|
+
},
|
|
1838
|
+
"layout": {
|
|
1839
|
+
"type": "string",
|
|
1840
|
+
"description": "Form layout mode.",
|
|
1841
|
+
"examples": ["stacked", "inline"]
|
|
1842
|
+
},
|
|
1843
|
+
"sections": {
|
|
1844
|
+
"type": "array",
|
|
1845
|
+
"description": "Ordered list of form sections, each containing input fields.",
|
|
1846
|
+
"items": { "$ref": "#/$defs/form_section" }
|
|
1847
|
+
},
|
|
1848
|
+
"includes": {
|
|
1849
|
+
"type": "array",
|
|
1850
|
+
"description": "Manual eager loading hints for the edit form (e.g., for association selects)."
|
|
1851
|
+
},
|
|
1852
|
+
"eager_load": {
|
|
1853
|
+
"type": "array",
|
|
1854
|
+
"description": "Manual eager_load hints for the edit form."
|
|
1855
|
+
}
|
|
1856
|
+
},
|
|
1857
|
+
"additionalProperties": false
|
|
1858
|
+
},
|
|
1859
|
+
|
|
1860
|
+
"search_config": {
|
|
1861
|
+
"type": "object",
|
|
1862
|
+
"description": "Configuration for quick search, predefined filters, and advanced filter builder.",
|
|
1863
|
+
"properties": {
|
|
1864
|
+
"enabled": {
|
|
1865
|
+
"type": "boolean",
|
|
1866
|
+
"description": "Enable the search box on the index page."
|
|
1867
|
+
},
|
|
1868
|
+
"searchable_fields": {
|
|
1869
|
+
"type": "array",
|
|
1870
|
+
"items": { "type": "string" },
|
|
1871
|
+
"description": "Fields included in quick search (text search across multiple fields).",
|
|
1872
|
+
"examples": [["name", "email", "department.name"]]
|
|
1873
|
+
},
|
|
1874
|
+
"placeholder": {
|
|
1875
|
+
"type": "string",
|
|
1876
|
+
"description": "Placeholder text in the search input.",
|
|
1877
|
+
"examples": ["Search employees..."]
|
|
1878
|
+
},
|
|
1879
|
+
"auto_search": {
|
|
1880
|
+
"type": "boolean",
|
|
1881
|
+
"description": "Trigger search automatically as the user types (with debounce) instead of requiring Enter."
|
|
1882
|
+
},
|
|
1883
|
+
"debounce_ms": {
|
|
1884
|
+
"type": "integer",
|
|
1885
|
+
"description": "Debounce delay in milliseconds for auto_search.",
|
|
1886
|
+
"examples": [300, 500]
|
|
1887
|
+
},
|
|
1888
|
+
"min_query_length": {
|
|
1889
|
+
"type": "integer",
|
|
1890
|
+
"description": "Minimum number of characters before auto_search triggers.",
|
|
1891
|
+
"examples": [2, 3]
|
|
1892
|
+
},
|
|
1893
|
+
"default_scope": {
|
|
1894
|
+
"type": "string",
|
|
1895
|
+
"description": "Named scope applied to all search queries as a base filter.",
|
|
1896
|
+
"examples": ["active", "visible"]
|
|
1897
|
+
},
|
|
1898
|
+
"predefined_filters": {
|
|
1899
|
+
"type": "array",
|
|
1900
|
+
"description": "Filter tabs shown above the search results.",
|
|
1901
|
+
"items": { "$ref": "#/$defs/search_filter" }
|
|
1902
|
+
},
|
|
1903
|
+
"columns": {
|
|
1904
|
+
"type": "integer",
|
|
1905
|
+
"minimum": 1,
|
|
1906
|
+
"description": "Number of grid columns for search parameter layout. Default: 1 (stacked)."
|
|
1907
|
+
},
|
|
1908
|
+
"responsive": {
|
|
1909
|
+
"type": "object",
|
|
1910
|
+
"description": "Responsive column overrides per breakpoint.",
|
|
1911
|
+
"properties": {
|
|
1912
|
+
"mobile": {
|
|
1913
|
+
"type": "object",
|
|
1914
|
+
"properties": { "columns": { "type": "integer", "minimum": 1 } },
|
|
1915
|
+
"additionalProperties": false
|
|
1916
|
+
},
|
|
1917
|
+
"tablet": {
|
|
1918
|
+
"type": "object",
|
|
1919
|
+
"properties": { "columns": { "type": "integer", "minimum": 1 } },
|
|
1920
|
+
"additionalProperties": false
|
|
1921
|
+
}
|
|
1922
|
+
},
|
|
1923
|
+
"additionalProperties": false
|
|
1924
|
+
},
|
|
1925
|
+
"parameters": {
|
|
1926
|
+
"type": "array",
|
|
1927
|
+
"description": "Typed filter controls rendered in the search toolbar (dropdowns, toggles, ranges).",
|
|
1928
|
+
"items": { "$ref": "#/$defs/search_parameter" }
|
|
1929
|
+
},
|
|
1930
|
+
"advanced_filter": { "$ref": "#/$defs/advanced_filter_config" }
|
|
1931
|
+
},
|
|
1932
|
+
"additionalProperties": false
|
|
1933
|
+
},
|
|
1934
|
+
|
|
1935
|
+
"advanced_filter_config": {
|
|
1936
|
+
"type": "object",
|
|
1937
|
+
"description": "Configuration for the visual filter builder UI that lets users construct complex queries with multiple conditions.",
|
|
1938
|
+
"properties": {
|
|
1939
|
+
"enabled": {
|
|
1940
|
+
"type": "boolean",
|
|
1941
|
+
"description": "Show the advanced filter builder button on the index page."
|
|
1942
|
+
},
|
|
1943
|
+
"max_conditions": {
|
|
1944
|
+
"type": "integer",
|
|
1945
|
+
"minimum": 1,
|
|
1946
|
+
"description": "Maximum number of filter conditions a user can add.",
|
|
1947
|
+
"default": 10
|
|
1948
|
+
},
|
|
1949
|
+
"max_association_depth": {
|
|
1950
|
+
"type": "integer",
|
|
1951
|
+
"minimum": 1,
|
|
1952
|
+
"maximum": 5,
|
|
1953
|
+
"description": "Maximum depth for filtering on associated model fields (e.g., 1 = direct associations only).",
|
|
1954
|
+
"default": 1
|
|
1955
|
+
},
|
|
1956
|
+
"default_combinator": {
|
|
1957
|
+
"type": "string",
|
|
1958
|
+
"description": "Default logical operator between conditions.",
|
|
1959
|
+
"enum": ["and", "or"],
|
|
1960
|
+
"default": "and"
|
|
1961
|
+
},
|
|
1962
|
+
"allow_or_groups": {
|
|
1963
|
+
"type": "boolean",
|
|
1964
|
+
"description": "Allow users to create OR groups within the filter builder.",
|
|
1965
|
+
"default": true
|
|
1966
|
+
},
|
|
1967
|
+
"query_language": {
|
|
1968
|
+
"type": "boolean",
|
|
1969
|
+
"description": "Enable the text-based query language input alongside the visual builder.",
|
|
1970
|
+
"default": false
|
|
1971
|
+
},
|
|
1972
|
+
"max_nesting_depth": {
|
|
1973
|
+
"type": "integer",
|
|
1974
|
+
"minimum": 1,
|
|
1975
|
+
"maximum": 10,
|
|
1976
|
+
"description": "Maximum nesting depth for condition groups.",
|
|
1977
|
+
"default": 2
|
|
1978
|
+
},
|
|
1979
|
+
"filterable_fields": {
|
|
1980
|
+
"type": "array",
|
|
1981
|
+
"items": { "type": "string" },
|
|
1982
|
+
"description": "Whitelist of fields available in the filter builder. If omitted, all readable fields are available.",
|
|
1983
|
+
"examples": [["name", "status", "department_id", "hire_date"]]
|
|
1984
|
+
},
|
|
1985
|
+
"filterable_fields_except": {
|
|
1986
|
+
"type": "array",
|
|
1987
|
+
"items": { "type": "string" },
|
|
1988
|
+
"description": "Blacklist of fields excluded from the filter builder.",
|
|
1989
|
+
"examples": [["internal_notes", "password_digest"]]
|
|
1990
|
+
},
|
|
1991
|
+
"field_options": {
|
|
1992
|
+
"type": "object",
|
|
1993
|
+
"description": "Per-field customization of available filter operators. Keys are field names.",
|
|
1994
|
+
"additionalProperties": {
|
|
1995
|
+
"type": "object",
|
|
1996
|
+
"properties": {
|
|
1997
|
+
"operators": {
|
|
1998
|
+
"type": "array",
|
|
1999
|
+
"items": { "type": "string" },
|
|
2000
|
+
"description": "List of operators available for this field.",
|
|
2001
|
+
"examples": [["eq", "not_eq", "in", "not_in"]]
|
|
2002
|
+
}
|
|
2003
|
+
},
|
|
2004
|
+
"additionalProperties": false
|
|
2005
|
+
},
|
|
2006
|
+
"examples": [{ "status": { "operators": ["eq", "not_eq", "in"] } }]
|
|
2007
|
+
},
|
|
2008
|
+
"presets": {
|
|
2009
|
+
"type": "array",
|
|
2010
|
+
"description": "Pre-defined filter combinations that users can apply with one click.",
|
|
2011
|
+
"items": {
|
|
2012
|
+
"type": "object",
|
|
2013
|
+
"properties": {
|
|
2014
|
+
"name": {
|
|
2015
|
+
"type": "string",
|
|
2016
|
+
"description": "Preset identifier."
|
|
2017
|
+
},
|
|
2018
|
+
"label": {
|
|
2019
|
+
"type": "string",
|
|
2020
|
+
"description": "Display label for the preset button."
|
|
2021
|
+
},
|
|
2022
|
+
"conditions": {
|
|
2023
|
+
"type": "array",
|
|
2024
|
+
"items": { "type": "object" },
|
|
2025
|
+
"description": "Array of condition objects ({field, operator, value}) applied by this preset."
|
|
2026
|
+
}
|
|
2027
|
+
},
|
|
2028
|
+
"required": ["name"]
|
|
2029
|
+
},
|
|
2030
|
+
"examples": [[{ "name": "active_this_month", "label": "Active This Month", "conditions": [{ "field": "status", "operator": "eq", "value": "active" }] }]]
|
|
2031
|
+
},
|
|
2032
|
+
"custom_filters": {
|
|
2033
|
+
"type": "array",
|
|
2034
|
+
"description": "Custom filter widgets implemented as filter_* methods on the model.",
|
|
2035
|
+
"items": {
|
|
2036
|
+
"type": "object",
|
|
2037
|
+
"properties": {
|
|
2038
|
+
"name": {
|
|
2039
|
+
"type": "string",
|
|
2040
|
+
"description": "Filter name matching a filter_<name> method on the model."
|
|
2041
|
+
},
|
|
2042
|
+
"label": {
|
|
2043
|
+
"type": "string",
|
|
2044
|
+
"description": "Display label in the filter UI."
|
|
2045
|
+
},
|
|
2046
|
+
"type": {
|
|
2047
|
+
"type": "string",
|
|
2048
|
+
"description": "Input type for the custom filter widget.",
|
|
2049
|
+
"examples": ["text", "select", "date_range"]
|
|
2050
|
+
}
|
|
2051
|
+
},
|
|
2052
|
+
"required": ["name"]
|
|
2053
|
+
}
|
|
2054
|
+
},
|
|
2055
|
+
"saved_filters": { "$ref": "#/$defs/saved_filters_config" }
|
|
2056
|
+
},
|
|
2057
|
+
"additionalProperties": false
|
|
2058
|
+
},
|
|
2059
|
+
|
|
2060
|
+
"saved_filters_config": {
|
|
2061
|
+
"type": "object",
|
|
2062
|
+
"description": "Configuration for user-saveable filter presets. Requires the saved_filters generator to create the backing model.",
|
|
2063
|
+
"properties": {
|
|
2064
|
+
"enabled": {
|
|
2065
|
+
"type": "boolean",
|
|
2066
|
+
"description": "Enable the saved filters feature for this presenter."
|
|
2067
|
+
},
|
|
2068
|
+
"display": {
|
|
2069
|
+
"type": "string",
|
|
2070
|
+
"description": "How saved filters are displayed in the UI.",
|
|
2071
|
+
"enum": ["inline", "dropdown", "sidebar"],
|
|
2072
|
+
"default": "inline"
|
|
2073
|
+
},
|
|
2074
|
+
"max_per_user": {
|
|
2075
|
+
"type": "integer",
|
|
2076
|
+
"minimum": 1,
|
|
2077
|
+
"description": "Maximum number of personal saved filters per user.",
|
|
2078
|
+
"default": 50
|
|
2079
|
+
},
|
|
2080
|
+
"max_per_role": {
|
|
2081
|
+
"type": "integer",
|
|
2082
|
+
"minimum": 1,
|
|
2083
|
+
"description": "Maximum number of role-shared saved filters.",
|
|
2084
|
+
"default": 20
|
|
2085
|
+
},
|
|
2086
|
+
"max_global": {
|
|
2087
|
+
"type": "integer",
|
|
2088
|
+
"minimum": 1,
|
|
2089
|
+
"description": "Maximum number of globally visible saved filters.",
|
|
2090
|
+
"default": 30
|
|
2091
|
+
},
|
|
2092
|
+
"max_visible_pinned": {
|
|
2093
|
+
"type": "integer",
|
|
2094
|
+
"minimum": 1,
|
|
2095
|
+
"description": "Maximum number of pinned filters shown inline (overflow goes to dropdown).",
|
|
2096
|
+
"default": 5
|
|
2097
|
+
},
|
|
2098
|
+
"allow_pinning": {
|
|
2099
|
+
"type": "boolean",
|
|
2100
|
+
"description": "Allow users to pin saved filters for quick access.",
|
|
2101
|
+
"default": true
|
|
2102
|
+
},
|
|
2103
|
+
"allow_default": {
|
|
2104
|
+
"type": "boolean",
|
|
2105
|
+
"description": "Allow users to set a saved filter as their personal default.",
|
|
2106
|
+
"default": true
|
|
2107
|
+
},
|
|
2108
|
+
"visibility_options": {
|
|
2109
|
+
"type": "array",
|
|
2110
|
+
"description": "Which visibility levels are available when saving a filter.",
|
|
2111
|
+
"items": { "type": "string", "enum": ["personal", "role", "global", "group"] },
|
|
2112
|
+
"default": ["personal", "role", "global"],
|
|
2113
|
+
"examples": [["personal", "role", "global"], ["personal", "group"]]
|
|
2114
|
+
}
|
|
2115
|
+
},
|
|
2116
|
+
"additionalProperties": false
|
|
2117
|
+
},
|
|
2118
|
+
|
|
2119
|
+
"actions_config": {
|
|
2120
|
+
"type": "object",
|
|
2121
|
+
"description": "Action buttons grouped by context: collection (index page toolbar), single (per-record row actions), batch (multi-select actions), form (form submit buttons).",
|
|
2122
|
+
"properties": {
|
|
2123
|
+
"collection": {
|
|
2124
|
+
"type": "array",
|
|
2125
|
+
"description": "Actions shown in the index page toolbar (e.g., 'Create New').",
|
|
2126
|
+
"items": { "$ref": "#/$defs/action" }
|
|
2127
|
+
},
|
|
2128
|
+
"single": {
|
|
2129
|
+
"type": "array",
|
|
2130
|
+
"description": "Actions shown per record row on the index page and on the show page (e.g., 'Show', 'Edit', 'Delete').",
|
|
2131
|
+
"items": { "$ref": "#/$defs/action" }
|
|
2132
|
+
},
|
|
2133
|
+
"batch": {
|
|
2134
|
+
"type": "array",
|
|
2135
|
+
"description": "Actions available when multiple records are selected (e.g., 'Delete Selected', 'Export').",
|
|
2136
|
+
"items": { "$ref": "#/$defs/action" }
|
|
2137
|
+
},
|
|
2138
|
+
"form": {
|
|
2139
|
+
"type": "array",
|
|
2140
|
+
"description": "Submit buttons rendered in the form footer. When absent, defaults to [save (primary), cancel (secondary)]. When present, only the listed actions appear.",
|
|
2141
|
+
"items": { "$ref": "#/$defs/form_action" }
|
|
2142
|
+
}
|
|
2143
|
+
},
|
|
2144
|
+
"additionalProperties": false
|
|
2145
|
+
},
|
|
2146
|
+
|
|
2147
|
+
"export_config": {
|
|
2148
|
+
"type": "object",
|
|
2149
|
+
"description": "Export configuration. When present, enables CSV/XLSX export for this presenter.",
|
|
2150
|
+
"properties": {
|
|
2151
|
+
"formats": {
|
|
2152
|
+
"type": "array",
|
|
2153
|
+
"description": "Allowed export formats.",
|
|
2154
|
+
"items": { "type": "string", "enum": ["csv", "xlsx"] },
|
|
2155
|
+
"default": ["csv"],
|
|
2156
|
+
"examples": [["csv", "xlsx"]]
|
|
2157
|
+
},
|
|
2158
|
+
"max_records": {
|
|
2159
|
+
"type": "integer",
|
|
2160
|
+
"minimum": 1,
|
|
2161
|
+
"description": "Maximum records per export. Default: 10000.",
|
|
2162
|
+
"default": 10000
|
|
2163
|
+
},
|
|
2164
|
+
"save_history": {
|
|
2165
|
+
"type": "boolean",
|
|
2166
|
+
"description": "Persist each export in the export_log model. Requires the lcp_ruby:export generator.",
|
|
2167
|
+
"default": false
|
|
2168
|
+
},
|
|
2169
|
+
"fields": {
|
|
2170
|
+
"type": "array",
|
|
2171
|
+
"description": "Field whitelist (ceiling). Only these fields can be selected for export. When omitted, all readable fields are available.",
|
|
2172
|
+
"items": { "type": "string" },
|
|
2173
|
+
"examples": [["name", "email", "department_id"]]
|
|
2174
|
+
},
|
|
2175
|
+
"csv_delimiter": {
|
|
2176
|
+
"type": "string",
|
|
2177
|
+
"description": "CSV column delimiter.",
|
|
2178
|
+
"default": ","
|
|
2179
|
+
}
|
|
2180
|
+
},
|
|
2181
|
+
"additionalProperties": false,
|
|
2182
|
+
"examples": [{ "formats": ["csv", "xlsx"], "max_records": 5000 }]
|
|
2183
|
+
},
|
|
2184
|
+
|
|
2185
|
+
"import_config": {
|
|
2186
|
+
"type": "object",
|
|
2187
|
+
"description": "Import configuration. When present, enables CSV/XLSX import for this presenter.",
|
|
2188
|
+
"properties": {
|
|
2189
|
+
"formats": {
|
|
2190
|
+
"type": "array",
|
|
2191
|
+
"description": "Allowed import formats.",
|
|
2192
|
+
"items": { "type": "string", "enum": ["csv", "xlsx"] },
|
|
2193
|
+
"default": ["csv"],
|
|
2194
|
+
"examples": [["csv", "xlsx"]]
|
|
2195
|
+
},
|
|
2196
|
+
"max_rows": {
|
|
2197
|
+
"type": "integer",
|
|
2198
|
+
"minimum": 1,
|
|
2199
|
+
"description": "Maximum rows per import. Default: 10000.",
|
|
2200
|
+
"default": 10000
|
|
2201
|
+
},
|
|
2202
|
+
"max_file_size": {
|
|
2203
|
+
"type": "integer",
|
|
2204
|
+
"minimum": 1,
|
|
2205
|
+
"description": "Maximum file size in bytes. Default: 10485760 (10 MiB).",
|
|
2206
|
+
"default": 10485760
|
|
2207
|
+
},
|
|
2208
|
+
"csv_delimiter": {
|
|
2209
|
+
"type": "string",
|
|
2210
|
+
"description": "CSV column delimiter.",
|
|
2211
|
+
"default": ","
|
|
2212
|
+
},
|
|
2213
|
+
"csv_encoding": {
|
|
2214
|
+
"type": "string",
|
|
2215
|
+
"description": "Expected file encoding. 'auto' detects encoding automatically.",
|
|
2216
|
+
"default": "auto"
|
|
2217
|
+
},
|
|
2218
|
+
"parsing": {
|
|
2219
|
+
"type": "object",
|
|
2220
|
+
"description": "Type coercion rules for imported values.",
|
|
2221
|
+
"properties": {
|
|
2222
|
+
"date_format": {
|
|
2223
|
+
"oneOf": [
|
|
2224
|
+
{ "type": "string" },
|
|
2225
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
2226
|
+
],
|
|
2227
|
+
"description": "Date parsing format(s). Tried in order.",
|
|
2228
|
+
"examples": ["%d.%m.%Y", ["%d.%m.%Y", "%Y-%m-%d"]]
|
|
2229
|
+
},
|
|
2230
|
+
"datetime_format": {
|
|
2231
|
+
"oneOf": [
|
|
2232
|
+
{ "type": "string" },
|
|
2233
|
+
{ "type": "array", "items": { "type": "string" } }
|
|
2234
|
+
],
|
|
2235
|
+
"description": "Datetime parsing format(s)."
|
|
2236
|
+
},
|
|
2237
|
+
"decimal_separator": {
|
|
2238
|
+
"type": "string",
|
|
2239
|
+
"description": "Decimal separator for number parsing.",
|
|
2240
|
+
"examples": [",", "."]
|
|
2241
|
+
},
|
|
2242
|
+
"boolean_true": {
|
|
2243
|
+
"type": "array",
|
|
2244
|
+
"description": "Values recognized as true.",
|
|
2245
|
+
"items": {},
|
|
2246
|
+
"examples": [["true", "yes", "1", "ano"]]
|
|
2247
|
+
},
|
|
2248
|
+
"boolean_false": {
|
|
2249
|
+
"type": "array",
|
|
2250
|
+
"description": "Values recognized as false.",
|
|
2251
|
+
"items": {},
|
|
2252
|
+
"examples": [["false", "no", "0", "ne"]]
|
|
2253
|
+
}
|
|
2254
|
+
},
|
|
2255
|
+
"additionalProperties": false
|
|
2256
|
+
},
|
|
2257
|
+
"nested_associations": {
|
|
2258
|
+
"type": "array",
|
|
2259
|
+
"description": "Whitelist of has_one association names that can be imported via column prefixes (e.g., hire_detail.start_date).",
|
|
2260
|
+
"items": { "type": "string" },
|
|
2261
|
+
"examples": [["hire_detail", "departure_detail"]]
|
|
2262
|
+
},
|
|
2263
|
+
"nested_blank_strategy": {
|
|
2264
|
+
"type": "string",
|
|
2265
|
+
"description": "How to handle blank nested association columns. 'null' sets fields to nil, 'skip' leaves them unchanged.",
|
|
2266
|
+
"enum": ["null", "skip"],
|
|
2267
|
+
"default": "null"
|
|
2268
|
+
}
|
|
2269
|
+
},
|
|
2270
|
+
"additionalProperties": false,
|
|
2271
|
+
"examples": [{ "formats": ["csv", "xlsx"], "max_rows": 1000, "nested_associations": ["hire_detail"] }]
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
}
|