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,1719 @@
|
|
|
1
|
+
# Presenter DSL Reference
|
|
2
|
+
|
|
3
|
+
File: `config/lcp_ruby/presenters/<name>.rb`
|
|
4
|
+
|
|
5
|
+
The Presenter DSL is a Ruby alternative to [YAML presenter definitions](presenters.md). It produces the same internal representation (`PresenterDefinition`) and feeds through the same pipeline — the DSL builder outputs a hash identical to parsed YAML, which is then processed by `PresenterDefinition.from_hash`.
|
|
6
|
+
|
|
7
|
+
DSL files live alongside YAML files in `config/lcp_ruby/presenters/`. A project can mix both formats, but each presenter name must be unique across all files (defining the same presenter in both `.yml` and `.rb` raises `MetadataError`).
|
|
8
|
+
|
|
9
|
+
## Entry Point
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
LcpRuby.define_presenter :presenter_name do
|
|
13
|
+
# DSL calls here
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
In DSL files loaded by the engine, use `define_presenter` without the `LcpRuby.` prefix:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
# config/lcp_ruby/presenters/deal.rb
|
|
21
|
+
define_presenter :deal do
|
|
22
|
+
model :deal
|
|
23
|
+
label "Deals"
|
|
24
|
+
slug "deals"
|
|
25
|
+
# ...
|
|
26
|
+
end
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Presenter Metadata
|
|
30
|
+
|
|
31
|
+
### `model`
|
|
32
|
+
|
|
33
|
+
| | |
|
|
34
|
+
|---|---|
|
|
35
|
+
| **Required** | yes |
|
|
36
|
+
| **Type** | symbol or string |
|
|
37
|
+
|
|
38
|
+
The model this presenter displays. Must match a defined model name.
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
model :deal
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### `label`
|
|
45
|
+
|
|
46
|
+
| | |
|
|
47
|
+
|---|---|
|
|
48
|
+
| **Required** | no |
|
|
49
|
+
| **Default** | `name.humanize` |
|
|
50
|
+
| **Type** | string |
|
|
51
|
+
|
|
52
|
+
Human-readable name displayed in page headings and navigation.
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
label "Deals"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### `slug`
|
|
59
|
+
|
|
60
|
+
| | |
|
|
61
|
+
|---|---|
|
|
62
|
+
| **Required** | no |
|
|
63
|
+
| **Type** | string |
|
|
64
|
+
|
|
65
|
+
URL slug for routing. When set, the presenter is routable at `/<slug>`.
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
slug "deals"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `icon`
|
|
72
|
+
|
|
73
|
+
| | |
|
|
74
|
+
|---|---|
|
|
75
|
+
| **Required** | no |
|
|
76
|
+
| **Type** | string |
|
|
77
|
+
|
|
78
|
+
Icon identifier for navigation and UI elements.
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
icon "dollar-sign"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `menu_position`
|
|
85
|
+
|
|
86
|
+
> **Deprecated.** Write `config/lcp_ruby/menu.yml` for explicit menu placement — the entity generator's `--menu=...` flag makes this a one-line addition at scaffold time. `menu_position` still works in v1 and emits a one-time info-level log when used; it will be removed in a future release. See [Presenters Reference — `menu_position`](presenters.md#menu_position).
|
|
87
|
+
|
|
88
|
+
| | |
|
|
89
|
+
|---|---|
|
|
90
|
+
| **Required** | no |
|
|
91
|
+
| **Type** | integer |
|
|
92
|
+
|
|
93
|
+
Position hint for the auto-created view group when this is the only presenter on the model. Lifts the auto-VG out of the alphabetical 900+index tier into a configurator-controlled position. Ignored when an explicit view group YAML covers the model. See [Presenters Reference — `menu_position`](presenters.md#menu_position) for the full semantics.
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
menu_position 10
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `default`
|
|
100
|
+
|
|
101
|
+
| | |
|
|
102
|
+
|---|---|
|
|
103
|
+
| **Required** | no (required when the model has multiple routable presenters and any column/field uses `link: true` without a per-link `link_presenter:` override) |
|
|
104
|
+
| **Default** | `false` |
|
|
105
|
+
| **Type** | boolean |
|
|
106
|
+
|
|
107
|
+
Marks this presenter as the canonical link target for its model. When another presenter has `link: true` / `link_to: :show` to a record of this model, the link resolves to the presenter marked `default true`. Exactly one presenter per model may be marked default — the validator rejects duplicates at boot. See [Presenters Reference — Multiple presenters per model](presenters.md#multiple-presenters-per-model) for the full pattern.
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
default true
|
|
111
|
+
# `default` (no arg) is equivalent to `default true`
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `read_only`
|
|
115
|
+
|
|
116
|
+
| | |
|
|
117
|
+
|---|---|
|
|
118
|
+
| **Required** | no |
|
|
119
|
+
| **Default** | `false` |
|
|
120
|
+
| **Type** | boolean |
|
|
121
|
+
|
|
122
|
+
Marks the presenter as read-only (no create/edit/destroy actions).
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
read_only true
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### `embeddable`
|
|
129
|
+
|
|
130
|
+
| | |
|
|
131
|
+
|---|---|
|
|
132
|
+
| **Required** | no |
|
|
133
|
+
| **Default** | `false` |
|
|
134
|
+
| **Type** | boolean |
|
|
135
|
+
|
|
136
|
+
Whether the presenter can be embedded inside another presenter's view.
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
embeddable true
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### `redirect_after`
|
|
143
|
+
|
|
144
|
+
| | |
|
|
145
|
+
|---|---|
|
|
146
|
+
| **Required** | no |
|
|
147
|
+
| **Type** | keyword arguments |
|
|
148
|
+
|
|
149
|
+
Controls where the user is redirected after create or update. Each key maps to a target page. Valid targets: `:index`, `:show`, `:edit`, `:new`. Default for both is `:show`.
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
redirect_after create: :index, update: :index
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### `empty_value`
|
|
156
|
+
|
|
157
|
+
| | |
|
|
158
|
+
|---|---|
|
|
159
|
+
| **Required** | no |
|
|
160
|
+
| **Type** | string |
|
|
161
|
+
|
|
162
|
+
Overrides the placeholder text for nil/blank field values in this presenter. Takes precedence over the global config and i18n key.
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
empty_value "N/A"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `record_alias`
|
|
169
|
+
|
|
170
|
+
| | |
|
|
171
|
+
|---|---|
|
|
172
|
+
| **Required** | no |
|
|
173
|
+
| **Type** | DSL method (name, **opts) |
|
|
174
|
+
|
|
175
|
+
Defines a named URL segment that resolves to a specific record dynamically. Multiple aliases can be defined per presenter. See the [YAML reference](presenters.md#record_aliases) for full semantics.
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
# current_user strategy — /preferences/me resolves via belongs_to FK
|
|
179
|
+
record_alias :me, resolve: :current_user, field: :user
|
|
180
|
+
|
|
181
|
+
# current_user on self — presenter model IS the user model (same table);
|
|
182
|
+
# omit `field:` so /my-settings/me resolves to current_user's own row.
|
|
183
|
+
record_alias :me, resolve: :current_user
|
|
184
|
+
|
|
185
|
+
# scope strategy — /issues/last resolves via named scope
|
|
186
|
+
record_alias :last, resolve: :scope, scope: :latest
|
|
187
|
+
|
|
188
|
+
# field_on_user strategy — /teams/my resolves via current_user.team_id
|
|
189
|
+
record_alias :my, resolve: :field_on_user, user_field: :team_id
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Full example:**
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
define_presenter :my_preferences do
|
|
196
|
+
model :user_preference
|
|
197
|
+
slug "preferences"
|
|
198
|
+
|
|
199
|
+
record_alias :me, resolve: :current_user, field: :user
|
|
200
|
+
|
|
201
|
+
show do
|
|
202
|
+
section do
|
|
203
|
+
field :theme
|
|
204
|
+
field :language
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
form do
|
|
209
|
+
section do
|
|
210
|
+
field :theme
|
|
211
|
+
field :language
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Index Configuration
|
|
218
|
+
|
|
219
|
+
The `index` block configures the list/table view.
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
index do
|
|
223
|
+
description "Manage all deals in your pipeline."
|
|
224
|
+
default_view :table
|
|
225
|
+
views_available :table, :tiles
|
|
226
|
+
default_sort :created_at, :desc
|
|
227
|
+
per_page 25
|
|
228
|
+
column :title, width: "30%", link_to: :show, sortable: true
|
|
229
|
+
column :stage, width: "20%", renderer: :badge, sortable: true
|
|
230
|
+
end
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Index Methods
|
|
234
|
+
|
|
235
|
+
#### `render_with(partial)`
|
|
236
|
+
|
|
237
|
+
Replaces the entire index content area with a custom host-app partial. The search/sort/scope pipeline still runs — the partial receives the processed `records`. When set, `layout` is ignored.
|
|
238
|
+
|
|
239
|
+
```ruby
|
|
240
|
+
index do
|
|
241
|
+
render_with "analytics/dashboard"
|
|
242
|
+
end
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
YAML equivalent: `index: { render_with: "analytics/dashboard" }`
|
|
246
|
+
|
|
247
|
+
#### `description(text)`
|
|
248
|
+
|
|
249
|
+
Descriptive text displayed below the page heading on the index view.
|
|
250
|
+
|
|
251
|
+
```ruby
|
|
252
|
+
description "Browse and filter all deals in your pipeline."
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
#### `default_view(value)`
|
|
256
|
+
|
|
257
|
+
Default view mode. Common values: `:table`, `:tiles`.
|
|
258
|
+
|
|
259
|
+
#### `views_available(*values)`
|
|
260
|
+
|
|
261
|
+
Available view modes the user can switch between.
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
views_available :table, :tiles
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### `default_sort(field, direction)`
|
|
268
|
+
|
|
269
|
+
Default sort column and direction (`:asc` or `:desc`).
|
|
270
|
+
|
|
271
|
+
```ruby
|
|
272
|
+
default_sort :created_at, :desc
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### `reorderable(value)`
|
|
276
|
+
|
|
277
|
+
Enables drag-and-drop reordering of records in the index table. The model must have a [`positioning`](models.md#positioning) configuration.
|
|
278
|
+
|
|
279
|
+
```ruby
|
|
280
|
+
index do
|
|
281
|
+
reorderable true
|
|
282
|
+
column :name, link_to: :show
|
|
283
|
+
column :position, sortable: true
|
|
284
|
+
end
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
When `reorderable true` is set and no explicit `default_sort` is given, the engine auto-applies `default_sort <position_field>, :asc`. See [Presenters Reference — reorderable](presenters.md#reorderable) for full details.
|
|
288
|
+
|
|
289
|
+
#### `per_page(value)`
|
|
290
|
+
|
|
291
|
+
Number of records per page. Default: 25.
|
|
292
|
+
|
|
293
|
+
#### `row_click(value)`
|
|
294
|
+
|
|
295
|
+
Sets the behavior when a user clicks a table row.
|
|
296
|
+
|
|
297
|
+
```ruby
|
|
298
|
+
row_click :show # clicking a row navigates to the show page
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
#### `empty_message(value)`
|
|
302
|
+
|
|
303
|
+
Message displayed when the index table has no records.
|
|
304
|
+
|
|
305
|
+
```ruby
|
|
306
|
+
empty_message "No deals found. Create your first deal to get started."
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### `actions_position(value)`
|
|
310
|
+
|
|
311
|
+
Controls how row-level actions are displayed.
|
|
312
|
+
|
|
313
|
+
| Value | Description |
|
|
314
|
+
|-------|-------------|
|
|
315
|
+
| `:inline` | Actions are rendered as inline buttons (default) |
|
|
316
|
+
| `:dropdown` | Actions appear in a dropdown menu |
|
|
317
|
+
|
|
318
|
+
```ruby
|
|
319
|
+
actions_position :dropdown
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### `includes(*associations)`
|
|
323
|
+
|
|
324
|
+
Manually specify associations to preload for display. See [Eager Loading](eager-loading.md).
|
|
325
|
+
|
|
326
|
+
```ruby
|
|
327
|
+
index do
|
|
328
|
+
includes :company, :contact
|
|
329
|
+
end
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### `eager_load(*associations)`
|
|
333
|
+
|
|
334
|
+
Manually specify associations to eager load via LEFT JOIN. See [Eager Loading](eager-loading.md).
|
|
335
|
+
|
|
336
|
+
```ruby
|
|
337
|
+
index do
|
|
338
|
+
eager_load :company
|
|
339
|
+
end
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### `layout(value)`
|
|
343
|
+
|
|
344
|
+
Sets the index page layout mode: `:table` (default), `:tiles`, or `:tree`.
|
|
345
|
+
|
|
346
|
+
```ruby
|
|
347
|
+
index do
|
|
348
|
+
layout :tiles
|
|
349
|
+
end
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
#### `tile(&block)`
|
|
353
|
+
|
|
354
|
+
Tile-layout-specific grid configuration. Card zone rendering uses the sibling [`card`](#cardblock) block.
|
|
355
|
+
|
|
356
|
+
```ruby
|
|
357
|
+
index do
|
|
358
|
+
layout :tiles
|
|
359
|
+
tile { columns 4 }
|
|
360
|
+
card do
|
|
361
|
+
title_field :name
|
|
362
|
+
# … see card(&block) below
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
| DSL method | Description |
|
|
368
|
+
|---|---|
|
|
369
|
+
| `columns(n)` | Number of grid columns (responsive breakpoints override at narrow widths) |
|
|
370
|
+
|
|
371
|
+
#### `card(&block)`
|
|
372
|
+
|
|
373
|
+
Per-record card interior shared across card-based layouts (tiles, kanban, future). Title becomes a link when index-level [`row_click`](#row_click) is set.
|
|
374
|
+
|
|
375
|
+
```ruby
|
|
376
|
+
index do
|
|
377
|
+
layout :tiles
|
|
378
|
+
row_click :show
|
|
379
|
+
|
|
380
|
+
card do
|
|
381
|
+
title_field :name
|
|
382
|
+
subtitle_field :status, renderer: :badge, options: { color_map: { active: :green } }
|
|
383
|
+
description_field :description, max_lines: 3
|
|
384
|
+
|
|
385
|
+
image_field :cover_image, alt: :cover_alt
|
|
386
|
+
avatar_field "owner.avatar"
|
|
387
|
+
color_field :priority, map: { critical: :danger, high: :warning, normal: :muted }
|
|
388
|
+
|
|
389
|
+
actions :dropdown
|
|
390
|
+
render_with "my_app/cards/deal" # optional full-body override
|
|
391
|
+
|
|
392
|
+
field :price, label: "Price", renderer: :currency, options: { currency: "EUR" }
|
|
393
|
+
field "company.name", label: "Company"
|
|
394
|
+
field :total, partial: "my_app/cells/kpi" # custom partial cell (parity with table columns)
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
| DSL method | Notes |
|
|
400
|
+
|---|---|
|
|
401
|
+
| `title_field(name)` | Required for any card-based layout |
|
|
402
|
+
| `subtitle_field(name, renderer:, options:)` | Optional renderer + options |
|
|
403
|
+
| `description_field(name, max_lines:)` | Plain text, line-clamped via CSS |
|
|
404
|
+
| `image_field(name, alt:)` | Banner image; `alt:` is field name for alt text (falls back to title_field value) |
|
|
405
|
+
| `avatar_field(name, alt:)` | Small circular avatar; alt defaults to "" (decorative) |
|
|
406
|
+
| `color_field(name, map:)` | Accent color from value via whitelist palette tokens (`success`, `danger`, `warning`, `info`, `muted`, `primary`). Raw values never reach CSS. |
|
|
407
|
+
| `actions(:dropdown \| :inline \| :none)` | How per-card actions are rendered |
|
|
408
|
+
| `render_with(path)` | Host-app partial path that overrides the entire card body |
|
|
409
|
+
| `field(name, label:, renderer:, options:, partial:)` | Label-value entry; `partial:` overrides `renderer:` |
|
|
410
|
+
|
|
411
|
+
#### `sort_field(field, label: nil)`
|
|
412
|
+
|
|
413
|
+
Adds a field to the sort dropdown.
|
|
414
|
+
|
|
415
|
+
```ruby
|
|
416
|
+
index do
|
|
417
|
+
sort_field :name, label: "Name"
|
|
418
|
+
sort_field :price, label: "Price"
|
|
419
|
+
end
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
#### `per_page_options(*values)`
|
|
423
|
+
|
|
424
|
+
Selectable page sizes shown in a dropdown near pagination.
|
|
425
|
+
|
|
426
|
+
```ruby
|
|
427
|
+
index do
|
|
428
|
+
per_page 25
|
|
429
|
+
per_page_options 10, 25, 50, 100
|
|
430
|
+
end
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
#### `show_record_count(value = true)`
|
|
434
|
+
|
|
435
|
+
Shows or hides the record count text in the pagination footer. Default `true`.
|
|
436
|
+
|
|
437
|
+
```ruby
|
|
438
|
+
index do
|
|
439
|
+
show_record_count false # hide "Showing X-Y of Z records"
|
|
440
|
+
end
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
#### `pagination_ends(value = true)`
|
|
444
|
+
|
|
445
|
+
Shows "First" and "Last" page links in the pagination footer. Per-presenter override of the global [`LcpRuby.configuration.pagination_ends`](engine-configuration.md#pagination_ends). Default `false`.
|
|
446
|
+
|
|
447
|
+
```ruby
|
|
448
|
+
index do
|
|
449
|
+
pagination_ends true # show First/Last links
|
|
450
|
+
end
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
#### `summary(&block)`
|
|
454
|
+
|
|
455
|
+
Configures the summary bar with aggregate values.
|
|
456
|
+
|
|
457
|
+
```ruby
|
|
458
|
+
index do
|
|
459
|
+
summary do
|
|
460
|
+
enabled true
|
|
461
|
+
field :price, function: :sum, label: "Total Revenue"
|
|
462
|
+
field :price, function: :avg, label: "Average Price"
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### `item_class(classes, when:)`
|
|
468
|
+
|
|
469
|
+
Adds a conditional CSS class rule for index rows/cards. All matching rules accumulate.
|
|
470
|
+
|
|
471
|
+
```ruby
|
|
472
|
+
index do
|
|
473
|
+
item_class "lcp-row-muted lcp-row-strikethrough",
|
|
474
|
+
when: { field: :status, operator: :eq, value: "done" }
|
|
475
|
+
item_class "lcp-row-danger",
|
|
476
|
+
when: { field: :status, operator: :eq, value: "overdue" }
|
|
477
|
+
item_class "lcp-row-bold",
|
|
478
|
+
when: { field: :priority, operator: :eq, value: "critical" }
|
|
479
|
+
end
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
See [Presenters Reference — item_classes](presenters.md#item_classes) for built-in utility classes and detailed attribute reference.
|
|
483
|
+
|
|
484
|
+
#### `column(field_name, **options)`
|
|
485
|
+
|
|
486
|
+
Adds a table column.
|
|
487
|
+
|
|
488
|
+
| Option | Type | Description |
|
|
489
|
+
|--------|------|-------------|
|
|
490
|
+
| `width:` | string | Column width (e.g., `"30%"`) |
|
|
491
|
+
| `label:` | string | Custom column header label (e.g., `"Company"` for a `"company.name"` dot-path field) |
|
|
492
|
+
| `link_to:` | symbol | **Legacy.** Always links the cell to the **current row's** show page, regardless of the column field. Kept for backward compatibility. Prefer `link: true` below for new configurations |
|
|
493
|
+
| `link:` | boolean | Wrap the cell value in a link. Auto-detects the target: dot-path (e.g. `"manager.display_name"`) links to the last belongs_to record in the chain; a plain belongs_to field name links to that record; a scalar field links to the current row (same as legacy `link_to: :show`). Use `link_through:` to override |
|
|
494
|
+
| `link_through:` | symbol | Name of a `belongs_to` association on this model to follow for the link target. Implies `link: true`. Use when the displayed field's name doesn't match the linked entity (e.g. a precomputed label). Incompatible with `link_to: :show` |
|
|
495
|
+
| `link_presenter:` | string/symbol | 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. See [Presenters Reference — Multiple presenters per model](presenters.md#multiple-presenters-per-model) |
|
|
496
|
+
| `sortable:` | boolean | Whether column is sortable |
|
|
497
|
+
| `renderer:` | symbol | Renderer for the field value (`:badge`, `:currency`, `:relative_date`, etc.). Alternatively, use `partial:` to render with a custom view partial |
|
|
498
|
+
| `options:` | hash | Additional renderer configuration (e.g., `{ color_map: { ... } }`) |
|
|
499
|
+
| `hidden_on:` | symbol or array | Responsive breakpoints to hide the column on (e.g., `:mobile`, `[:mobile, :tablet]`) |
|
|
500
|
+
| `pinned:` | symbol | Pin the column to `:left` or `:right` side of the table |
|
|
501
|
+
| `summary:` | symbol | Summary function for the column footer (e.g., `:sum`, `:avg`, `:count`) |
|
|
502
|
+
| `aggregate:` | symbol or hash | (Grouped mode only) Aggregate function. Short form: `:count`. Full form: `{ function: :sum, field: :amount }`. Add `distinct: true` for `AGG(DISTINCT field)` |
|
|
503
|
+
| `group_field:` | symbol or string | (Grouped mode only) References the original `group_by` field when the column name differs (e.g., `column :month, group_field: :issued_at`) |
|
|
504
|
+
| `sort_strategy:` | symbol | Enum columns only. `:definition_order` (default for enums) sorts by position in enum values list. `:value` sorts alphabetically. Applies to grouped and non-grouped views |
|
|
505
|
+
| `display_in_index:` | boolean | Per-column opt-in for fields whose type carries `default_index_visible: false` (`:text`, `:rich_text`, `:attachment`, `:json`, `:array`, `:file`). Without this kwarg the configuration validator emits a row-unfriendly-column warning suggesting either an explicit `renderer:` or this opt-in. Has no runtime effect — purely a validator-silencer. See [`docs/reference/types.md`](types.md#default_index_visible) |
|
|
506
|
+
|
|
507
|
+
### Grouped Query Mode
|
|
508
|
+
|
|
509
|
+
Setting `query_mode :grouped` switches the index from per-record to per-group query. The controller builds `SELECT group_cols, AGG() FROM table GROUP BY group_cols` instead of `SELECT * FROM table`.
|
|
510
|
+
|
|
511
|
+
```ruby
|
|
512
|
+
index do
|
|
513
|
+
query_mode :grouped
|
|
514
|
+
group_by [:category]
|
|
515
|
+
default_sort :feature_count, :desc
|
|
516
|
+
row_click :filter, target: "features"
|
|
517
|
+
|
|
518
|
+
column :category, sortable: true, renderer: :badge
|
|
519
|
+
column :feature_count, aggregate: :count, sortable: true
|
|
520
|
+
end
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
#### `query_mode(value)`
|
|
524
|
+
|
|
525
|
+
Set to `:grouped` to enable grouped query mode.
|
|
526
|
+
|
|
527
|
+
#### `group_by(fields)`
|
|
528
|
+
|
|
529
|
+
Fields to GROUP BY. Accepts simple field names and hash entries for date truncation:
|
|
530
|
+
|
|
531
|
+
```ruby
|
|
532
|
+
group_by [:stage, :region]
|
|
533
|
+
group_by [{ field: :issued_at, period: :month }]
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
Valid periods: `:year`, `:quarter`, `:month`, `:week`, `:day`.
|
|
537
|
+
|
|
538
|
+
#### `having(&block)`
|
|
539
|
+
|
|
540
|
+
Post-aggregation filter (SQL HAVING). The block returns a condition hash or array:
|
|
541
|
+
|
|
542
|
+
```ruby
|
|
543
|
+
having { { field: :product_count, operator: :gte, value: 5 } }
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
Operators: `:eq`, `:neq`, `:gt`, `:gte`, `:lt`, `:lte`.
|
|
547
|
+
|
|
548
|
+
#### `limit(value)`
|
|
549
|
+
|
|
550
|
+
Maximum number of group rows. Disables Kaminari pagination when set.
|
|
551
|
+
|
|
552
|
+
```ruby
|
|
553
|
+
limit 10
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
#### `row_click(:filter, target: "slug")`
|
|
557
|
+
|
|
558
|
+
Clicking a group row navigates to the target presenter's index with auto-generated Ransack filter params from the group column values:
|
|
559
|
+
|
|
560
|
+
```ruby
|
|
561
|
+
row_click :filter, target: "features"
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
#### Grouped Query Example
|
|
565
|
+
|
|
566
|
+
```ruby
|
|
567
|
+
define_presenter :deals_pipeline do
|
|
568
|
+
model :deal
|
|
569
|
+
slug "deals-pipeline"
|
|
570
|
+
|
|
571
|
+
index do
|
|
572
|
+
query_mode :grouped
|
|
573
|
+
group_by [:stage, :region]
|
|
574
|
+
default_sort :total_value, :desc
|
|
575
|
+
having { { field: :deal_count, operator: :gte, value: 3 } }
|
|
576
|
+
limit 20
|
|
577
|
+
row_click :filter, target: "deals"
|
|
578
|
+
|
|
579
|
+
column :stage, sortable: true, renderer: :badge
|
|
580
|
+
column :region, sortable: true
|
|
581
|
+
column :deal_count, aggregate: :count, sortable: true
|
|
582
|
+
column :total_value, aggregate: { function: :sum, field: :value },
|
|
583
|
+
renderer: :currency, sortable: true
|
|
584
|
+
column :avg_value, aggregate: { function: :avg, field: :value },
|
|
585
|
+
renderer: :currency
|
|
586
|
+
column :unique_owners, aggregate: { function: :count, distinct: true, field: :owner_id }
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Show Configuration
|
|
592
|
+
|
|
593
|
+
The `show` block configures the detail view.
|
|
594
|
+
|
|
595
|
+
```ruby
|
|
596
|
+
show do
|
|
597
|
+
description "View deal details and related contacts."
|
|
598
|
+
|
|
599
|
+
section "Deal Information", columns: 2 do
|
|
600
|
+
field :title, renderer: :heading
|
|
601
|
+
field :stage, renderer: :badge
|
|
602
|
+
field :value, renderer: :currency
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
association_list "Contacts", association: :contacts
|
|
606
|
+
end
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Show Methods
|
|
610
|
+
|
|
611
|
+
#### `description(text)`
|
|
612
|
+
|
|
613
|
+
Descriptive text displayed below the page heading on the show view.
|
|
614
|
+
|
|
615
|
+
```ruby
|
|
616
|
+
description "View deal details and related contacts."
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
#### `render_with(partial)`
|
|
620
|
+
|
|
621
|
+
Replaces the entire show content area with a custom host-app partial. Ignored in dialog and composite page contexts.
|
|
622
|
+
|
|
623
|
+
```ruby
|
|
624
|
+
show do
|
|
625
|
+
render_with "products/custom_show"
|
|
626
|
+
end
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
YAML equivalent: `show: { render_with: "products/custom_show" }`
|
|
630
|
+
|
|
631
|
+
#### `copy_url(value)`
|
|
632
|
+
|
|
633
|
+
Controls whether the "Copy link" toolbar button is shown on the show page. Default: `true`. Set to `false` to hide it.
|
|
634
|
+
|
|
635
|
+
```ruby
|
|
636
|
+
show do
|
|
637
|
+
copy_url false
|
|
638
|
+
# ...
|
|
639
|
+
end
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
#### `includes(*associations)` / `eager_load(*associations)`
|
|
643
|
+
|
|
644
|
+
Same as index. Manually specify associations to preload for the show page. Auto-detection handles `association_list` sections automatically. See [Eager Loading](eager-loading.md).
|
|
645
|
+
|
|
646
|
+
#### `custom_section(title, partial:, visible_when: nil)`
|
|
647
|
+
|
|
648
|
+
Creates a section whose content is rendered by a host-app partial. The `fields:` key is not used — the partial owns all content inside the section wrapper.
|
|
649
|
+
|
|
650
|
+
```ruby
|
|
651
|
+
show do
|
|
652
|
+
custom_section "Location", partial: "employees/location_map"
|
|
653
|
+
|
|
654
|
+
custom_section "Map",
|
|
655
|
+
partial: "employees/map_embed",
|
|
656
|
+
visible_when: { field: :latitude, operator: :present }
|
|
657
|
+
end
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
YAML equivalent: `show: { layout: [{ section: "Location", type: custom, partial: "employees/location_map" }] }`
|
|
661
|
+
|
|
662
|
+
#### `section(title, columns: 1, description: nil, responsive: nil, visible_when: nil, disable_when: nil, &block)`
|
|
663
|
+
|
|
664
|
+
Creates a section with fields. The `columns:` option controls the layout grid. The `description:` option adds explanatory text below the section heading. The `responsive:` option controls how the section adapts to different screen sizes. The `visible_when:` and `disable_when:` options control server-side conditional rendering — hidden sections are not rendered in the DOM.
|
|
665
|
+
|
|
666
|
+
```ruby
|
|
667
|
+
show do
|
|
668
|
+
section "Deal Information", columns: 2, description: "Key metrics for this deal", responsive: { mobile: 1 } do
|
|
669
|
+
field :title, renderer: :heading
|
|
670
|
+
field :stage, renderer: :badge
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
section "Metrics",
|
|
674
|
+
visible_when: { field: :stage, operator: :not_eq, value: "lead" } do
|
|
675
|
+
field :priority
|
|
676
|
+
field :progress
|
|
677
|
+
end
|
|
678
|
+
end
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
#### `association_list(title, association:, display_template: nil, link: nil, link_through: nil, sort: nil, limit: nil, empty_message: nil, scope: nil, visible_when: nil, disable_when: nil)`
|
|
682
|
+
|
|
683
|
+
Renders a list of associated records with optional display templates, links, sorting, and limits. The `association:` must match a `has_many` association on the model.
|
|
684
|
+
|
|
685
|
+
| Option | Type | Description |
|
|
686
|
+
|--------|------|-------------|
|
|
687
|
+
| `association:` | symbol | The `has_many` association name (required) |
|
|
688
|
+
| `display_template:` | symbol or string | Name of the display template defined on the target model (e.g., `:default`) |
|
|
689
|
+
| `link:` | boolean | Wrap each record in a link to its show page |
|
|
690
|
+
| `link_through:` | symbol | Follow this `belongs_to` association on the target model to resolve the link target (implies `link: true`) |
|
|
691
|
+
| `link_presenter:` | string/symbol | Override the target presenter slug. Use when the linked model has multiple presenters. Falls back to the model's `default true` presenter |
|
|
692
|
+
| `sort:` | hash | Sort associated records by field and direction (e.g., `{ last_name: :asc }`) |
|
|
693
|
+
| `limit:` | integer | Maximum number of records to display |
|
|
694
|
+
| `empty_message:` | string | Message shown when there are no associated records |
|
|
695
|
+
| `scope:` | symbol | Named scope to apply on the association before rendering |
|
|
696
|
+
|
|
697
|
+
```ruby
|
|
698
|
+
# Basic
|
|
699
|
+
association_list "Deals", association: :deals
|
|
700
|
+
|
|
701
|
+
# With all options
|
|
702
|
+
association_list "Contacts", association: :contacts,
|
|
703
|
+
display_template: :default, link: true,
|
|
704
|
+
sort: { last_name: :asc }, limit: 10,
|
|
705
|
+
empty_message: "No contacts yet.",
|
|
706
|
+
scope: :active
|
|
707
|
+
|
|
708
|
+
# Link through a join model to the real entity
|
|
709
|
+
association_list "Members", association: :group_memberships,
|
|
710
|
+
link_through: :employee
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
When `display_template:` references a display template defined on the target model (see [Models Reference — Display Templates](models.md#display-templates)), each record is rendered with the template's structured layout (title, subtitle, icon, badge). Without `display_template:`, records fall back to plain `to_label` text.
|
|
714
|
+
|
|
715
|
+
When `link_through:` is set, each record links to the related record reached by following the named `belongs_to` association on the target model. This is useful for join/bridge models where the meaningful entity is on the other side of the association. The association must be a non-polymorphic `belongs_to`. If the related record is `nil` or soft-deleted, the item renders without a link.
|
|
716
|
+
|
|
717
|
+
### Section Fields (Show)
|
|
718
|
+
|
|
719
|
+
Inside a show `section` block, use `field` to add display fields:
|
|
720
|
+
|
|
721
|
+
```ruby
|
|
722
|
+
field :name, renderer: :heading
|
|
723
|
+
field :status, renderer: :badge
|
|
724
|
+
field :description, renderer: :rich_text
|
|
725
|
+
field :budget, renderer: :currency
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
| Option | Type | Description |
|
|
729
|
+
|--------|------|-------------|
|
|
730
|
+
| `renderer:` | symbol | Renderer for the field value. Alternatively, use `partial:` to render with a custom view partial |
|
|
731
|
+
| `label:` | string | Custom field label (e.g., `"Company"` for a `"company.name"` dot-path field) |
|
|
732
|
+
| `copyable:` | boolean | Adds a copy-to-clipboard icon next to the field value |
|
|
733
|
+
| `col_span:` | integer | Number of grid columns this field spans |
|
|
734
|
+
| `hidden_on:` | symbol or array | Responsive breakpoints to hide the field on |
|
|
735
|
+
| `link:` | boolean | Wrap the field value in a link to the associated record. Auto-detects the target from a dot-path (e.g. `"manager.display_name"` links to the manager, `"manager.organizational_unit.name"` links to that org unit) or from a plain `belongs_to` field name (`field :manager`). Incompatible with link-emitting renderers (`email_link`, `url_link`, `attachment_link`, `markdown`, `rich_text`, …) |
|
|
736
|
+
| `link_through:` | symbol | Name of a `belongs_to` association on this model to follow for the link target. Implies `link: true`. Use when the displayed field's name doesn't correspond to the linked entity (e.g. a precomputed virtual column / custom field label) |
|
|
737
|
+
| `link_presenter:` | string/symbol | Override the target presenter slug for this link. Use when the linked model has multiple presenters. Falls back to the model's `default true` presenter |
|
|
738
|
+
| `options:` | hash | Additional renderer configuration |
|
|
739
|
+
|
|
740
|
+
## Form Configuration
|
|
741
|
+
|
|
742
|
+
The `form` block configures create and edit forms.
|
|
743
|
+
|
|
744
|
+
```ruby
|
|
745
|
+
form do
|
|
746
|
+
description "Enter the deal details below."
|
|
747
|
+
|
|
748
|
+
section "Deal Details", columns: 2 do
|
|
749
|
+
field :title, placeholder: "Deal title...", autofocus: true
|
|
750
|
+
field :stage, input_type: :select
|
|
751
|
+
field :value, input_type: :number
|
|
752
|
+
field :company_id, input_type: :association_select
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
### Form Methods
|
|
758
|
+
|
|
759
|
+
#### `description(text)`
|
|
760
|
+
|
|
761
|
+
Descriptive text displayed at the top of the form, below error messages.
|
|
762
|
+
|
|
763
|
+
```ruby
|
|
764
|
+
description "Fill in the deal details. Required fields are marked with *."
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### `includes(*associations)` / `eager_load(*associations)`
|
|
768
|
+
|
|
769
|
+
Same as index. Manually specify associations to preload for the form. Auto-detection handles `nested_fields` sections automatically. See [Eager Loading](eager-loading.md).
|
|
770
|
+
|
|
771
|
+
#### `custom_section(title, partial:, visible_when: nil, additional_permitted_params: nil)`
|
|
772
|
+
|
|
773
|
+
Creates a form section whose content is rendered by a host-app partial. The partial receives the `form` builder local for rendering inputs.
|
|
774
|
+
|
|
775
|
+
```ruby
|
|
776
|
+
form do
|
|
777
|
+
custom_section "Variants",
|
|
778
|
+
partial: "products/variants_editor",
|
|
779
|
+
additional_permitted_params: ["variants_json", { "address" => ["street", "city", "zip"] }]
|
|
780
|
+
end
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
YAML equivalent: `form: { sections: [{ title: "Variants", type: custom, partial: "products/variants_editor", additional_permitted_params: [...] }] }`
|
|
784
|
+
|
|
785
|
+
#### `layout(value)`
|
|
786
|
+
|
|
787
|
+
Sets the overall form layout mode.
|
|
788
|
+
|
|
789
|
+
| Value | Description |
|
|
790
|
+
|-------|-------------|
|
|
791
|
+
| `:flat` | All sections rendered sequentially (default) |
|
|
792
|
+
| `:tabs` | Each section rendered as a tab |
|
|
793
|
+
|
|
794
|
+
```ruby
|
|
795
|
+
form do
|
|
796
|
+
layout :tabs
|
|
797
|
+
|
|
798
|
+
section "Basic Info" do
|
|
799
|
+
field :title
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
section "Details" do
|
|
803
|
+
field :description
|
|
804
|
+
end
|
|
805
|
+
end
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
#### `section(title = nil, key: nil, columns: 1, description: nil, collapsible: false, collapsed: false, responsive: nil, visible_when: nil, disable_when: nil, &block)`
|
|
809
|
+
|
|
810
|
+
Creates a form section. Multiple sections create visual groupings. At least one of `title` or `key:` must be given.
|
|
811
|
+
|
|
812
|
+
| Option | Type | Description |
|
|
813
|
+
|--------|------|-------------|
|
|
814
|
+
| `key:` | string | Explicit i18n lookup key. See [Section titles & i18n](#section-titles--i18n) below. |
|
|
815
|
+
| `columns:` | integer | Number of layout columns (default: 1) |
|
|
816
|
+
| `description:` | string | Explanatory text displayed below the section heading |
|
|
817
|
+
| `collapsible:` | boolean | Whether the section can be collapsed/expanded by the user |
|
|
818
|
+
| `collapsed:` | boolean | Whether the section starts in collapsed state (requires `collapsible: true`) |
|
|
819
|
+
| `responsive:` | hash | Responsive column overrides (e.g., `{ mobile: 1 }`) |
|
|
820
|
+
| `visible_when:` | hash | Condition hash for section visibility |
|
|
821
|
+
| `disable_when:` | hash | Condition hash for section disabling |
|
|
822
|
+
|
|
823
|
+
```ruby
|
|
824
|
+
form do
|
|
825
|
+
section "Primary", columns: 2, responsive: { mobile: 1 } do
|
|
826
|
+
field :title
|
|
827
|
+
field :stage, input_type: :select
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
section "Notes", collapsible: true, collapsed: true do
|
|
831
|
+
field :description, input_type: :textarea
|
|
832
|
+
end
|
|
833
|
+
end
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
##### Section titles & i18n
|
|
837
|
+
|
|
838
|
+
Section titles are looked up in i18n under `lcp_ruby.presenters.<presenter>.sections.<key>`. There are two conventions:
|
|
839
|
+
|
|
840
|
+
**Default (English literal as key source).** Without `key:`, the literal title is parameterized to derive the lookup key — `section "List Details"` → looks up `…sections.list_details`. The literal is also the fallback when the i18n entry is missing. **Recommended for new code:** keep the literal in English, then translate via locale files. Non-English literals "work" but they leak into the en locale via the fallback path, mixing structure and text.
|
|
841
|
+
|
|
842
|
+
```ruby
|
|
843
|
+
section "List Details" do
|
|
844
|
+
field :title
|
|
845
|
+
end
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
```yaml
|
|
849
|
+
# config/locales/cs.yml
|
|
850
|
+
cs:
|
|
851
|
+
lcp_ruby:
|
|
852
|
+
presenters:
|
|
853
|
+
project:
|
|
854
|
+
sections:
|
|
855
|
+
list_details: "Detaily seznamu"
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
**Explicit key (`key:` keyword).** Pass `key:` to decouple the i18n lookup from the literal — useful when the configurator wants the structure (DSL) free of any human-readable text:
|
|
859
|
+
|
|
860
|
+
```ruby
|
|
861
|
+
section key: "list_details" do # i18n key only
|
|
862
|
+
field :title
|
|
863
|
+
end
|
|
864
|
+
|
|
865
|
+
# or paired with a literal that acts as the en fallback:
|
|
866
|
+
section "List Details", key: "list_details" do
|
|
867
|
+
field :title
|
|
868
|
+
end
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
When `key:` is set, lookup is `…sections.<key>` verbatim; fallback when missing is the literal title (if given) or a humanized key.
|
|
872
|
+
|
|
873
|
+
The same `key:` keyword is supported by `custom_section`, `json_items_list`, `association_list`, `nested_fields`, and the `section` inside `nested_fields` blocks.
|
|
874
|
+
|
|
875
|
+
#### `nested_fields(title, association: nil, json_field: nil, target_model: nil, **options, &block)`
|
|
876
|
+
|
|
877
|
+
Adds a nested form section for editing a list of structured items inline. Items can come from three data sources:
|
|
878
|
+
|
|
879
|
+
| Option | Type | Description |
|
|
880
|
+
|--------|------|-------------|
|
|
881
|
+
| `association:` | symbol | has_many association name (mutually exclusive with `json_field:`) |
|
|
882
|
+
| `json_field:` | symbol | JSON column name for storing items as array of hashes (mutually exclusive with `association:`) |
|
|
883
|
+
| `target_model:` | symbol | Virtual model name defining item structure and validations (only with `json_field:`) |
|
|
884
|
+
| `allow_add:` | boolean | Show an "Add" button (default: `true`) |
|
|
885
|
+
| `allow_remove:` | boolean | Show a "Remove" button on each row (default: `true`) |
|
|
886
|
+
| `min:` | integer | Minimum number of items |
|
|
887
|
+
| `max:` | integer | Maximum number of items |
|
|
888
|
+
| `add_label:` | string | Custom label for the "Add" button |
|
|
889
|
+
| `empty_message:` | string | Message shown when there are no items |
|
|
890
|
+
| `columns:` | integer | Number of layout columns for each row |
|
|
891
|
+
| `sortable:` | boolean or string | Enable drag-and-drop reordering. `true` uses `position` field, or pass a string for a custom field name |
|
|
892
|
+
| `visible_when:` | hash | Condition hash for nested section visibility |
|
|
893
|
+
| `disable_when:` | hash | Condition hash for nested section disabling |
|
|
894
|
+
|
|
895
|
+
Exactly one of `association:` or `json_field:` is required.
|
|
896
|
+
|
|
897
|
+
**Association source (has_many):**
|
|
898
|
+
|
|
899
|
+
```ruby
|
|
900
|
+
nested_fields "Items", association: :todo_items,
|
|
901
|
+
allow_add: true, allow_remove: true,
|
|
902
|
+
max: 50, add_label: "Add Item", columns: 2 do
|
|
903
|
+
field :title, placeholder: "Item title..."
|
|
904
|
+
field :completed, input_type: :checkbox
|
|
905
|
+
field :due_date, input_type: :date_picker
|
|
906
|
+
end
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
**JSON field source (inline definitions):**
|
|
910
|
+
|
|
911
|
+
When using `json_field:` without `target_model:`, declare field types and labels inline:
|
|
912
|
+
|
|
913
|
+
```ruby
|
|
914
|
+
nested_fields "Workflow Steps", json_field: :steps,
|
|
915
|
+
sortable: true, allow_add: true, allow_remove: true, columns: 2 do
|
|
916
|
+
field :name, type: :string, label: "Step Name"
|
|
917
|
+
field :action_type, type: :string, input_type: :select,
|
|
918
|
+
input_options: { values: %w[review approve notify] }
|
|
919
|
+
field :timeout_days, type: :integer, label: "Timeout (days)",
|
|
920
|
+
visible_when: { field: :action_type, operator: :eq, value: "review" }
|
|
921
|
+
end
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
**JSON field source (model-backed):**
|
|
925
|
+
|
|
926
|
+
When `target_model:` is specified, field metadata (type, label, validations) comes from a virtual model:
|
|
927
|
+
|
|
928
|
+
```ruby
|
|
929
|
+
nested_fields "Addresses", json_field: :addresses, target_model: :address,
|
|
930
|
+
allow_add: true, allow_remove: true, columns: 2 do
|
|
931
|
+
field :street
|
|
932
|
+
field :city
|
|
933
|
+
field :zip
|
|
934
|
+
field :country
|
|
935
|
+
end
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
**Sub-sections in nested rows:**
|
|
939
|
+
|
|
940
|
+
Use `section` blocks (instead of `field` calls) to group fields within each row. You cannot mix `field` and `section` in the same block:
|
|
941
|
+
|
|
942
|
+
```ruby
|
|
943
|
+
nested_fields "Addresses", json_field: :addresses, target_model: :address,
|
|
944
|
+
allow_add: true, allow_remove: true do
|
|
945
|
+
section "Location", columns: 2 do
|
|
946
|
+
field :street
|
|
947
|
+
field :city
|
|
948
|
+
field :zip
|
|
949
|
+
field :country
|
|
950
|
+
end
|
|
951
|
+
section "Additional", collapsible: true, collapsed: true do
|
|
952
|
+
field :notes
|
|
953
|
+
field :is_primary, input_type: :boolean
|
|
954
|
+
end
|
|
955
|
+
end
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
Sub-sections support `columns:`, `collapsible:`, `collapsed:`, `visible_when:`, and `disable_when:`.
|
|
959
|
+
|
|
960
|
+
**With sortable (drag-and-drop reordering):**
|
|
961
|
+
|
|
962
|
+
```ruby
|
|
963
|
+
nested_fields "Items", association: :todo_items,
|
|
964
|
+
sortable: true, add_label: "Add Item" do
|
|
965
|
+
field :title
|
|
966
|
+
field :completed, input_type: :checkbox
|
|
967
|
+
end
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
Set `sortable: true` to use the default `position` field, or `sortable: "sort_order"` for a custom field name. The position field is hidden from the visible form and auto-permitted in the controller.
|
|
971
|
+
|
|
972
|
+
### Form Fields (Section Builder)
|
|
973
|
+
|
|
974
|
+
Inside a form `section` or `nested_fields` block:
|
|
975
|
+
|
|
976
|
+
```ruby
|
|
977
|
+
field :title, placeholder: "Enter title...", autofocus: true
|
|
978
|
+
field :stage, input_type: :select
|
|
979
|
+
field :budget, input_type: :number, prefix: "$"
|
|
980
|
+
field :start_date, input_type: :date_picker
|
|
981
|
+
field :company_id, input_type: :association_select
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
| Option | Type | Description |
|
|
985
|
+
|--------|------|-------------|
|
|
986
|
+
| `input_type:` | symbol | Input widget (`:select`, `:number`, `:text`, `:date_picker`, `:association_select`) |
|
|
987
|
+
| `placeholder:` | string | Placeholder text |
|
|
988
|
+
| `autofocus:` | boolean | Auto-focus on page load |
|
|
989
|
+
| `prefix:` | string | Input prefix (e.g., `"$"`) |
|
|
990
|
+
| `suffix:` | string | Input suffix (e.g., `"kg"`) |
|
|
991
|
+
| `col_span:` | integer | Number of grid columns this field spans (e.g., `2` for a full-width field in a 2-column section) |
|
|
992
|
+
| `hint:` | string | Help text displayed below the input |
|
|
993
|
+
| `readonly:` | boolean | Render the field as read-only |
|
|
994
|
+
| `visible_when:` | hash | Condition hash for conditional visibility. Field-value: `{ field: :status, operator: :eq, value: "active" }`. Service: `{ service: :persisted_check }`. See [Conditional Rendering](../guides/conditional-rendering.md). |
|
|
995
|
+
| `disable_when:` | hash | Condition hash for conditional disabling. Same syntax as `visible_when`. When condition is true, field is visually disabled but values are still submitted. |
|
|
996
|
+
| `default:` | any | Default value for the form input (overrides the model-level default for this form) |
|
|
997
|
+
| `input_options:` | hash | Additional options passed to the input widget (see below) |
|
|
998
|
+
| `options:` | hash | Renderer configuration (e.g., formatting for read-only rendering) |
|
|
999
|
+
| `hidden_on:` | symbol or array | Responsive breakpoints to hide the field on |
|
|
1000
|
+
|
|
1001
|
+
#### `input_options` for Select Fields
|
|
1002
|
+
|
|
1003
|
+
**Enum select** — role-based value filtering:
|
|
1004
|
+
|
|
1005
|
+
```ruby
|
|
1006
|
+
field :stage, input_type: :select,
|
|
1007
|
+
input_options: {
|
|
1008
|
+
include_blank: false,
|
|
1009
|
+
exclude_values: { viewer: ["lead"] },
|
|
1010
|
+
include_values: { intern: ["active", "inactive"] }
|
|
1011
|
+
}
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
**Association select** — scope, sort, label, grouping:
|
|
1015
|
+
|
|
1016
|
+
```ruby
|
|
1017
|
+
field :company_id, input_type: :association_select,
|
|
1018
|
+
input_options: {
|
|
1019
|
+
scope: :active,
|
|
1020
|
+
sort: { name: :asc },
|
|
1021
|
+
label_method: :full_name,
|
|
1022
|
+
include_blank: "-- Choose company --",
|
|
1023
|
+
group_by: :industry
|
|
1024
|
+
}
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
**Dependent (cascading) select** — child select filtered by parent:
|
|
1028
|
+
|
|
1029
|
+
```ruby
|
|
1030
|
+
field :company_id, input_type: :association_select,
|
|
1031
|
+
input_options: { sort: { name: :asc } }
|
|
1032
|
+
|
|
1033
|
+
field :contact_id, input_type: :association_select,
|
|
1034
|
+
input_options: {
|
|
1035
|
+
depends_on: { field: :company_id, foreign_key: :company_id },
|
|
1036
|
+
sort: { last_name: :asc },
|
|
1037
|
+
label_method: :full_name
|
|
1038
|
+
}
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
**Role-based scope** — different scopes per user role:
|
|
1042
|
+
|
|
1043
|
+
```ruby
|
|
1044
|
+
field :company_id, input_type: :association_select,
|
|
1045
|
+
input_options: {
|
|
1046
|
+
scope_by_role: { admin: :all, editor: :active_companies, viewer: :my_companies }
|
|
1047
|
+
}
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
**Multi select** — for `has_many :through` associations:
|
|
1051
|
+
|
|
1052
|
+
```ruby
|
|
1053
|
+
field :tag_ids, input_type: :multi_select,
|
|
1054
|
+
input_options: { association: :tags, sort: { name: :asc }, max: 5 }
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
**File upload** — for attachment fields:
|
|
1058
|
+
|
|
1059
|
+
```ruby
|
|
1060
|
+
field :avatar, input_options: { preview: true, drag_drop: true }
|
|
1061
|
+
field :documents, input_options: { preview: true, drag_drop: true, direct_upload: true }
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
| Option | Type | Default | Description |
|
|
1065
|
+
|--------|------|---------|-------------|
|
|
1066
|
+
| `preview` | boolean | `false` | Show preview of current file (image thumbnail or filename) |
|
|
1067
|
+
| `drag_drop` | boolean | `false` | Enable drag-and-drop upload zone |
|
|
1068
|
+
| `direct_upload` | boolean | `false` | Use Active Storage direct upload |
|
|
1069
|
+
|
|
1070
|
+
Attachment fields auto-resolve to `input_type: :file_upload`. The drop zone text adapts automatically: "Drop file here" for single attachments, "Drop files here" for multiple.
|
|
1071
|
+
|
|
1072
|
+
**Attachment renderers** — for show pages:
|
|
1073
|
+
|
|
1074
|
+
```ruby
|
|
1075
|
+
section "Photos" do
|
|
1076
|
+
field :avatar, renderer: :attachment_preview, options: { variant: "medium" }
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
section "Documents" do
|
|
1080
|
+
field :files, renderer: :attachment_list
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
section "Contract" do
|
|
1084
|
+
field :contract, renderer: :attachment_link
|
|
1085
|
+
end
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
| Renderer | Description |
|
|
1089
|
+
|----------|-------------|
|
|
1090
|
+
| `:attachment_preview` | Image preview with optional variant, download link for non-images |
|
|
1091
|
+
| `:attachment_list` | List of download links with filenames and file sizes |
|
|
1092
|
+
| `:attachment_link` | Single download link with filename |
|
|
1093
|
+
|
|
1094
|
+
For the complete list of `input_options` keys per input type, see [Presenters Reference — Input Options](presenters.md#input-options).
|
|
1095
|
+
|
|
1096
|
+
#### `divider(label: nil)`
|
|
1097
|
+
|
|
1098
|
+
Adds a horizontal divider pseudo-field inside a section. Useful for visually separating groups of related fields.
|
|
1099
|
+
|
|
1100
|
+
```ruby
|
|
1101
|
+
form do
|
|
1102
|
+
section "Contact Details", columns: 2 do
|
|
1103
|
+
field :first_name
|
|
1104
|
+
field :last_name
|
|
1105
|
+
divider label: "Address"
|
|
1106
|
+
field :street, col_span: 2
|
|
1107
|
+
field :city
|
|
1108
|
+
field :zip_code
|
|
1109
|
+
end
|
|
1110
|
+
end
|
|
1111
|
+
```
|
|
1112
|
+
|
|
1113
|
+
#### `info(text)`
|
|
1114
|
+
|
|
1115
|
+
Adds an informational text block inside a section. Renders as a styled callout spanning the full width of the grid. Use this to provide contextual help or explanations within a form or show section.
|
|
1116
|
+
|
|
1117
|
+
```ruby
|
|
1118
|
+
form do
|
|
1119
|
+
section "Pricing", columns: 2 do
|
|
1120
|
+
info "Prices are in USD. Tax is calculated automatically at checkout."
|
|
1121
|
+
field :price, input_type: :number, prefix: "$"
|
|
1122
|
+
field :tax_rate, input_type: :number, suffix: "%"
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
Both `divider` and `info` are available in `section` blocks for both `show` and `form` views.
|
|
1128
|
+
|
|
1129
|
+
## Search Configuration
|
|
1130
|
+
|
|
1131
|
+
The `search` block configures search and filtering.
|
|
1132
|
+
|
|
1133
|
+
```ruby
|
|
1134
|
+
search do
|
|
1135
|
+
searchable_fields :title, :description
|
|
1136
|
+
placeholder "Search projects..."
|
|
1137
|
+
filter :all, label: "All", default: true
|
|
1138
|
+
filter :active, label: "Active", scope: :active
|
|
1139
|
+
filter :recent, label: "Recent", scope: :recent
|
|
1140
|
+
end
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
To disable search entirely, use the keyword argument form:
|
|
1144
|
+
|
|
1145
|
+
```ruby
|
|
1146
|
+
search enabled: false
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
### Search Methods
|
|
1150
|
+
|
|
1151
|
+
#### `enabled(value)`
|
|
1152
|
+
|
|
1153
|
+
Whether search is enabled. Default: `true`.
|
|
1154
|
+
|
|
1155
|
+
#### `searchable_fields(*fields)`
|
|
1156
|
+
|
|
1157
|
+
Fields to search against when the user types a query.
|
|
1158
|
+
|
|
1159
|
+
```ruby
|
|
1160
|
+
searchable_fields :title, :description, :email
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
#### `placeholder(value)`
|
|
1164
|
+
|
|
1165
|
+
Placeholder text for the search input.
|
|
1166
|
+
|
|
1167
|
+
#### `auto_search(value = true)`
|
|
1168
|
+
|
|
1169
|
+
Enables auto-submit on the search form. When `true`, the form submits automatically as the user types after a debounce delay.
|
|
1170
|
+
|
|
1171
|
+
```ruby
|
|
1172
|
+
search do
|
|
1173
|
+
auto_search true
|
|
1174
|
+
end
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
#### `debounce_ms(value)`
|
|
1178
|
+
|
|
1179
|
+
Sets the debounce delay in milliseconds before auto-submit triggers. Default: `300`.
|
|
1180
|
+
|
|
1181
|
+
```ruby
|
|
1182
|
+
debounce_ms 300
|
|
1183
|
+
```
|
|
1184
|
+
|
|
1185
|
+
#### `min_query_length(value)`
|
|
1186
|
+
|
|
1187
|
+
Minimum number of characters before auto-submit triggers. Empty input (length 0) always triggers to clear the search. Default: `2`.
|
|
1188
|
+
|
|
1189
|
+
```ruby
|
|
1190
|
+
min_query_length 2
|
|
1191
|
+
```
|
|
1192
|
+
|
|
1193
|
+
#### `filter(name, label:, default: false, scope: nil)`
|
|
1194
|
+
|
|
1195
|
+
Adds a predefined filter tab.
|
|
1196
|
+
|
|
1197
|
+
| Argument | Type | Description |
|
|
1198
|
+
|----------|------|-------------|
|
|
1199
|
+
| `name` | symbol | Filter identifier |
|
|
1200
|
+
| `label:` | string | Display text |
|
|
1201
|
+
| `default:` | boolean | Whether this filter is selected by default |
|
|
1202
|
+
| `scope:` | symbol | Model scope to apply (must be defined in the model) |
|
|
1203
|
+
|
|
1204
|
+
#### `parameter(name, type:, field: nil, **opts)`
|
|
1205
|
+
|
|
1206
|
+
Adds a typed filter control to the search toolbar. See [Presenters Reference — Search Parameters](presenters.md#search-parameters) for all attributes.
|
|
1207
|
+
|
|
1208
|
+
| Argument | Type | Description |
|
|
1209
|
+
|----------|------|-------------|
|
|
1210
|
+
| `name` | symbol | Parameter identifier |
|
|
1211
|
+
| `type:` | symbol | Control type: `:enum_select`, `:association_select`, `:boolean_select`, `:number_range`, `:date_range` |
|
|
1212
|
+
| `field:` | symbol | Model field name to filter by |
|
|
1213
|
+
|
|
1214
|
+
Additional keyword options: `model:`, `options:`, `label_key:`, `label_method:`, `include_blank:`, `visible_when:`, `search:`, `min_query_length:`, `per_page:`, `col_span:`.
|
|
1215
|
+
|
|
1216
|
+
```ruby
|
|
1217
|
+
search do
|
|
1218
|
+
columns 2
|
|
1219
|
+
searchable_fields :name, :email
|
|
1220
|
+
|
|
1221
|
+
parameter :status, type: :enum_select, field: :status
|
|
1222
|
+
parameter :department, type: :association_select, field: :department_id,
|
|
1223
|
+
label_method: :full_name, include_blank: "Any department"
|
|
1224
|
+
parameter :active, type: :boolean_select, field: :active
|
|
1225
|
+
parameter :salary_range, type: :number_range, field: :salary
|
|
1226
|
+
parameter :hired, type: :date_range, field: :hired_at
|
|
1227
|
+
parameter :tenant, type: :association_select, model: :tenant, field: :tenant_id,
|
|
1228
|
+
visible_when: { role: :admin }
|
|
1229
|
+
end
|
|
1230
|
+
```
|
|
1231
|
+
|
|
1232
|
+
#### `columns(value)`
|
|
1233
|
+
|
|
1234
|
+
Sets the number of grid columns for the search parameter layout. Default: `1` (single column, one parameter per row). Labels are displayed inline beside controls.
|
|
1235
|
+
|
|
1236
|
+
#### `responsive(value)`
|
|
1237
|
+
|
|
1238
|
+
Sets responsive column overrides per breakpoint.
|
|
1239
|
+
|
|
1240
|
+
```ruby
|
|
1241
|
+
search do
|
|
1242
|
+
columns 3
|
|
1243
|
+
responsive mobile: { columns: 1 }, tablet: { columns: 2 }
|
|
1244
|
+
end
|
|
1245
|
+
```
|
|
1246
|
+
|
|
1247
|
+
#### `advanced_filter { ... }`
|
|
1248
|
+
|
|
1249
|
+
Configures the visual filter builder. See [Presenters Reference — Advanced Filter](presenters.md#advanced-filter-attributes) for all options.
|
|
1250
|
+
|
|
1251
|
+
```ruby
|
|
1252
|
+
search do
|
|
1253
|
+
advanced_filter do
|
|
1254
|
+
enabled true
|
|
1255
|
+
max_conditions 20
|
|
1256
|
+
allow_or_groups true
|
|
1257
|
+
query_language true
|
|
1258
|
+
filterable_fields :title, :status, :price, "department.name"
|
|
1259
|
+
field_options :status, operators: %i[eq not_eq in not_in]
|
|
1260
|
+
|
|
1261
|
+
preset :expensive,
|
|
1262
|
+
label: "Expensive items",
|
|
1263
|
+
conditions: [
|
|
1264
|
+
{ field: "price", operator: "gteq", value: "100" }
|
|
1265
|
+
]
|
|
1266
|
+
|
|
1267
|
+
saved_filters do
|
|
1268
|
+
enabled true
|
|
1269
|
+
display :inline
|
|
1270
|
+
max_visible_pinned 5
|
|
1271
|
+
end
|
|
1272
|
+
end
|
|
1273
|
+
end
|
|
1274
|
+
```
|
|
1275
|
+
|
|
1276
|
+
##### `saved_filters { ... }`
|
|
1277
|
+
|
|
1278
|
+
Nested inside `advanced_filter`, enables user-persistent named filters.
|
|
1279
|
+
|
|
1280
|
+
| Method | Type | Description |
|
|
1281
|
+
|--------|------|-------------|
|
|
1282
|
+
| `enabled(value)` | boolean | Enable saved filters (default: `false`) |
|
|
1283
|
+
| `display(value)` | symbol | Display mode: `:inline`, `:dropdown`, `:sidebar` (default: `:inline`) |
|
|
1284
|
+
| `max_visible_pinned(value)` | integer | Max pinned filters shown directly (default: `3`) |
|
|
1285
|
+
|
|
1286
|
+
See [Presenters Reference — Saved Filter Attributes](presenters.md#saved-filter-attributes) for full details.
|
|
1287
|
+
|
|
1288
|
+
## Export Configuration
|
|
1289
|
+
|
|
1290
|
+
Enables data export from the presenter. See [Export Reference](export.md) for full details.
|
|
1291
|
+
|
|
1292
|
+
```ruby
|
|
1293
|
+
export formats: [:csv, :xlsx], max_records: 5000, save_history: true
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
| Argument | Type | Default | Description |
|
|
1297
|
+
|----------|------|---------|-------------|
|
|
1298
|
+
| `formats:` | array | `[:csv]` | Available formats: `:csv`, `:xlsx` |
|
|
1299
|
+
| `max_records:` | integer | `10000` | Safety limit for export size |
|
|
1300
|
+
| `save_history:` | boolean | `false` | Log exports to `export_log` model |
|
|
1301
|
+
| `fields:` | array | all readable | Field ceiling for the picker |
|
|
1302
|
+
| `csv_delimiter:` | string | `","` | CSV column separator |
|
|
1303
|
+
|
|
1304
|
+
## Import Configuration
|
|
1305
|
+
|
|
1306
|
+
Enables data import for the presenter. See [Import Reference](import.md) for full details.
|
|
1307
|
+
|
|
1308
|
+
```ruby
|
|
1309
|
+
import formats: [:csv, :xlsx], max_rows: 5000,
|
|
1310
|
+
nested_associations: [:employee_profile],
|
|
1311
|
+
nested_blank_strategy: "skip",
|
|
1312
|
+
parsing: { date_format: ["%d.%m.%Y", "%Y-%m-%d"] }
|
|
1313
|
+
```
|
|
1314
|
+
|
|
1315
|
+
| Argument | Type | Default | Description |
|
|
1316
|
+
|----------|------|---------|-------------|
|
|
1317
|
+
| `formats:` | array | `[:csv]` | Accepted formats: `:csv`, `:xlsx` |
|
|
1318
|
+
| `max_rows:` | integer | `10000` | Safety limit for import size |
|
|
1319
|
+
| `max_file_size:` | integer | `10485760` | Maximum file size in bytes |
|
|
1320
|
+
| `csv_delimiter:` | string | `","` | CSV column separator |
|
|
1321
|
+
| `csv_encoding:` | string | `"auto"` | CSV encoding detection |
|
|
1322
|
+
| `parsing:` | hash | `{}` | Type coercion options |
|
|
1323
|
+
| `nested_associations:` | array | `nil` (all) | Whitelist of `has_one` associations for import |
|
|
1324
|
+
| `nested_blank_strategy:` | string | `"null"` | `"null"` (set to nil) or `"skip"` (omit blank fields) |
|
|
1325
|
+
|
|
1326
|
+
## Actions
|
|
1327
|
+
|
|
1328
|
+
Actions are defined at the top level of the presenter (not inside a block).
|
|
1329
|
+
|
|
1330
|
+
```ruby
|
|
1331
|
+
action :create, type: :built_in, on: :collection, label: "New Deal", icon: "plus"
|
|
1332
|
+
action :show, type: :built_in, on: :single, icon: "eye"
|
|
1333
|
+
action :edit, type: :built_in, on: :single, icon: "pencil"
|
|
1334
|
+
action :destroy, type: :built_in, on: :single, icon: "trash", confirm: true, style: :danger
|
|
1335
|
+
```
|
|
1336
|
+
|
|
1337
|
+
### Action Arguments
|
|
1338
|
+
|
|
1339
|
+
| Argument | Required | Type | Description |
|
|
1340
|
+
|----------|----------|------|-------------|
|
|
1341
|
+
| `name` | yes | symbol | Action identifier |
|
|
1342
|
+
| `type:` | yes | symbol | `:built_in` or `:custom` |
|
|
1343
|
+
| `on:` | yes | symbol | `:collection`, `:single`, or `:batch` |
|
|
1344
|
+
|
|
1345
|
+
### Action Options
|
|
1346
|
+
|
|
1347
|
+
| Option | Type | Description |
|
|
1348
|
+
|--------|------|-------------|
|
|
1349
|
+
| `label:` | string | Button/link text |
|
|
1350
|
+
| `icon:` | string | Icon identifier |
|
|
1351
|
+
| `confirm:` | boolean | Show confirmation dialog |
|
|
1352
|
+
| `confirm_message:` | string | Custom confirmation message |
|
|
1353
|
+
| `style:` | symbol | Visual style (e.g., `:danger`) |
|
|
1354
|
+
| `visible_when:` | hash | Condition for visibility (see below) |
|
|
1355
|
+
| `disable_when:` | hash | Condition for disabling the action (see [Conditional Rendering](../guides/conditional-rendering.md)) |
|
|
1356
|
+
| `batch:` | boolean or hash | Single actions only. `true` auto-derives a batch action; a Hash merges batch-specific overrides (e.g., `batch: { select_all_filter: false }`). See [Batch Actions Guide](../guides/batch-actions.md#auto-derived-batch-actions). |
|
|
1357
|
+
|
|
1358
|
+
### Batch-Specific Options (for `on: :batch` or `batch:` hash overrides)
|
|
1359
|
+
|
|
1360
|
+
| Option | Type | Description |
|
|
1361
|
+
|--------|------|-------------|
|
|
1362
|
+
| `min_selection:` | integer | Minimum records that must be selected |
|
|
1363
|
+
| `max_selection:` | integer | Maximum records that can be selected |
|
|
1364
|
+
| `max_batch_records:` | integer | Server-side limit on records affected |
|
|
1365
|
+
| `result_log:` | boolean | Enable per-record result tracking |
|
|
1366
|
+
| `select_all_filter:` | boolean | Allow "select all matching filter" mode |
|
|
1367
|
+
| `execution:` | symbol | `:inline`, `:background`, or `:auto` |
|
|
1368
|
+
| `background_threshold:` | integer | Threshold for `:auto` mode |
|
|
1369
|
+
| `strategy:` | symbol | Batch strategy |
|
|
1370
|
+
| `fields:` | array | Fields for batch update |
|
|
1371
|
+
|
|
1372
|
+
### `visible_when` Conditions
|
|
1373
|
+
|
|
1374
|
+
Custom actions can be conditionally visible based on record field values:
|
|
1375
|
+
|
|
1376
|
+
```ruby
|
|
1377
|
+
action :close_won, type: :custom, on: :single,
|
|
1378
|
+
label: "Close as Won", icon: "check-circle",
|
|
1379
|
+
confirm: true, confirm_message: "Mark this deal as won?",
|
|
1380
|
+
visible_when: { field: :stage, operator: :not_in, value: [:closed_won, :closed_lost] }
|
|
1381
|
+
```
|
|
1382
|
+
|
|
1383
|
+
See [Condition Operators](condition-operators.md) for available operators.
|
|
1384
|
+
|
|
1385
|
+
### Form Actions
|
|
1386
|
+
|
|
1387
|
+
Form actions define submit buttons on create/edit forms. Use `form_action` instead of `action` — context is implicit (`on: :form`).
|
|
1388
|
+
|
|
1389
|
+
```ruby
|
|
1390
|
+
form_action :save, type: :built_in, style: :primary, redirect: :show
|
|
1391
|
+
form_action :save_and_new, label: "Save & New", style: :secondary,
|
|
1392
|
+
redirect: :new, only_on: :create
|
|
1393
|
+
form_action :save_and_stay, label: "Save & Continue", style: :secondary,
|
|
1394
|
+
redirect: :edit, only_on: :update
|
|
1395
|
+
form_action :cancel, type: :built_in, style: :secondary
|
|
1396
|
+
```
|
|
1397
|
+
|
|
1398
|
+
### Form Action Arguments
|
|
1399
|
+
|
|
1400
|
+
| Argument | Required | Type | Description |
|
|
1401
|
+
|----------|----------|------|-------------|
|
|
1402
|
+
| `name` | yes | symbol | Action identifier |
|
|
1403
|
+
|
|
1404
|
+
### Form Action Options
|
|
1405
|
+
|
|
1406
|
+
| Option | Type | Description |
|
|
1407
|
+
|--------|------|-------------|
|
|
1408
|
+
| `type:` | symbol | `:built_in` for `save`/`cancel`. Omit for custom form actions. |
|
|
1409
|
+
| `label:` | string | Button text |
|
|
1410
|
+
| `icon:` | string | Icon identifier |
|
|
1411
|
+
| `style:` | symbol | `:primary`, `:secondary`, `:success`, `:danger`, `:warning`, `:outline` |
|
|
1412
|
+
| `redirect:` | symbol or hash | `:show`, `:edit`, `:new`, `:index`. Hash: `{ association: :order, action: :show }` or `{ presenter: "line_items", action: :new, defaults: { order_id: { field_ref: :id } } }`. Ignored in dialog context. |
|
|
1413
|
+
| `set_fields:` | hash | Fields to set before save (same syntax as workflow `set_fields`) |
|
|
1414
|
+
| `only_on:` | symbol | `:create` or `:update` — filter by form context |
|
|
1415
|
+
| `only_roles:` | array | Roles that see this button |
|
|
1416
|
+
| `except_roles:` | array | Roles excluded from seeing this button |
|
|
1417
|
+
| `confirm:` | boolean | Show confirmation dialog |
|
|
1418
|
+
| `confirm_message:` | string | Custom confirmation text |
|
|
1419
|
+
| `visible_when:` | hash | Condition for visibility |
|
|
1420
|
+
| `disable_when:` | hash | Condition for disabled state |
|
|
1421
|
+
| `dialog_behavior:` | symbol | `:close`, `:reset`, `:reload` (dialog context only) |
|
|
1422
|
+
| `pipeline:` | array | Ordered operation sequence in a single transaction. Steps: `:save`, `{ transition: :name }`, `{ action: :name }`. |
|
|
1423
|
+
| `transition:` | symbol | Sugar for `pipeline: [:save, { transition: :name }]`. Cannot combine with `pipeline:` or `action:`. |
|
|
1424
|
+
| `action:` | symbol | Sugar for `pipeline: [:save, { action: :name }]`. Cannot combine with `pipeline:` or `transition:`. |
|
|
1425
|
+
| `position:` | symbol | `:inline` (default) or `:dropdown` (forced into overflow menu). |
|
|
1426
|
+
|
|
1427
|
+
### Form Action Example
|
|
1428
|
+
|
|
1429
|
+
```ruby
|
|
1430
|
+
define_presenter :article_editor do
|
|
1431
|
+
model :article
|
|
1432
|
+
slug "article-editor"
|
|
1433
|
+
|
|
1434
|
+
form do
|
|
1435
|
+
section "Content" do
|
|
1436
|
+
field :title
|
|
1437
|
+
field :body, input_type: :rich_text_editor
|
|
1438
|
+
field :status
|
|
1439
|
+
end
|
|
1440
|
+
end
|
|
1441
|
+
|
|
1442
|
+
form_action :save_draft, label: "Save Draft", style: :secondary, redirect: :edit
|
|
1443
|
+
form_action :save_and_publish, label: "Publish", style: :primary, icon: "globe",
|
|
1444
|
+
set_fields: { status: "published", published_at: { date: :now } },
|
|
1445
|
+
confirm: true, redirect: :show,
|
|
1446
|
+
visible_when: { field: :status, operator: :not_eq, value: "published" }
|
|
1447
|
+
form_action :cancel, type: :built_in, style: :secondary
|
|
1448
|
+
end
|
|
1449
|
+
```
|
|
1450
|
+
|
|
1451
|
+
### Pipeline Example
|
|
1452
|
+
|
|
1453
|
+
Pipeline form actions compose multiple operations (save, workflow transition, custom action) in a single transaction:
|
|
1454
|
+
|
|
1455
|
+
```ruby
|
|
1456
|
+
define_presenter :purchase_order_editor do
|
|
1457
|
+
model :purchase_order
|
|
1458
|
+
slug "po-editor"
|
|
1459
|
+
|
|
1460
|
+
form do
|
|
1461
|
+
section "PO Details" do
|
|
1462
|
+
field :title
|
|
1463
|
+
field :amount, input_type: :number, prefix: "$"
|
|
1464
|
+
field :status
|
|
1465
|
+
end
|
|
1466
|
+
end
|
|
1467
|
+
|
|
1468
|
+
# Simple save (default pipeline: [:save])
|
|
1469
|
+
form_action :save_draft, label: "Save Draft", style: :secondary, redirect: :edit
|
|
1470
|
+
|
|
1471
|
+
# Sugar: transition: expands to pipeline: [:save, { transition: :submit }]
|
|
1472
|
+
form_action :save_and_submit, label: "Save & Submit", style: :primary, icon: "send",
|
|
1473
|
+
transition: :submit, confirm: true,
|
|
1474
|
+
confirm_message: "Submit for approval?",
|
|
1475
|
+
visible_when: { field: :status, operator: :eq, value: "draft" },
|
|
1476
|
+
redirect: :show
|
|
1477
|
+
|
|
1478
|
+
# Explicit pipeline: save + transition + custom action
|
|
1479
|
+
form_action :save_submit_and_notify, label: "Submit & Notify", style: :primary,
|
|
1480
|
+
pipeline: [:save, { transition: :submit }, { action: :notify_approvers }],
|
|
1481
|
+
confirm: true, redirect: :show
|
|
1482
|
+
|
|
1483
|
+
form_action :cancel, type: :built_in, style: :secondary
|
|
1484
|
+
end
|
|
1485
|
+
```
|
|
1486
|
+
|
|
1487
|
+
When no `form_action` is defined, the platform renders default Save and Cancel buttons. See the [Action Buttons & Pipelines Guide](../guides/action-buttons.md) for the full walkthrough, and the [Form Actions Reference](presenters.md#form-actions) for the attribute table.
|
|
1488
|
+
|
|
1489
|
+
## Navigation
|
|
1490
|
+
|
|
1491
|
+
```ruby
|
|
1492
|
+
navigation menu: :main, position: 3
|
|
1493
|
+
```
|
|
1494
|
+
|
|
1495
|
+
| Option | Type | Description |
|
|
1496
|
+
|--------|------|-------------|
|
|
1497
|
+
| `menu:` | symbol | Menu group (e.g., `:main`, `:public`) |
|
|
1498
|
+
| `position:` | integer | Sort order within the menu (optional) |
|
|
1499
|
+
|
|
1500
|
+
## Inheritance
|
|
1501
|
+
|
|
1502
|
+
Presenters can inherit from other presenters using the `inherits:` option. This copies the parent's configuration and lets the child override specific sections.
|
|
1503
|
+
|
|
1504
|
+
```ruby
|
|
1505
|
+
# config/lcp_ruby/presenters/deal_pipeline.rb
|
|
1506
|
+
define_presenter :deal_pipeline, inherits: :deal do
|
|
1507
|
+
label "Deal Pipeline"
|
|
1508
|
+
slug "pipeline"
|
|
1509
|
+
icon "bar-chart"
|
|
1510
|
+
read_only true
|
|
1511
|
+
|
|
1512
|
+
index do
|
|
1513
|
+
default_view :table
|
|
1514
|
+
per_page 50
|
|
1515
|
+
column :title, link_to: :show, sortable: true
|
|
1516
|
+
column :stage, renderer: :badge, sortable: true
|
|
1517
|
+
end
|
|
1518
|
+
|
|
1519
|
+
search enabled: false
|
|
1520
|
+
|
|
1521
|
+
action :show, type: :built_in, on: :single, icon: "eye"
|
|
1522
|
+
|
|
1523
|
+
navigation menu: :main, position: 4
|
|
1524
|
+
end
|
|
1525
|
+
```
|
|
1526
|
+
|
|
1527
|
+
### Inheritance Semantics
|
|
1528
|
+
|
|
1529
|
+
- **Section-level replace**: If a child defines `index`, `show`, `form`, `search`, `actions`, or `navigation`, the child's version completely replaces the parent's. There is no deep merge.
|
|
1530
|
+
- **Unset sections are inherited**: If the child does not define a section, the parent's version is used as-is.
|
|
1531
|
+
- **Top-level attributes**: `name`, `label`, `slug`, `icon`, `read_only`, `embeddable` are always taken from the child when defined. The `model` is inherited from the parent unless the child overrides it.
|
|
1532
|
+
- **Parent must exist**: The parent presenter must be defined in a DSL file in the same directory. Referencing a nonexistent parent raises `MetadataError`.
|
|
1533
|
+
- **No circular inheritance**: Circular chains (A inherits B, B inherits A) are detected and raise `MetadataError`.
|
|
1534
|
+
|
|
1535
|
+
Inheritance is purely a DSL convenience — the result is always a flat hash identical to what you could write in YAML with full duplication.
|
|
1536
|
+
|
|
1537
|
+
## Advanced Field Paths
|
|
1538
|
+
|
|
1539
|
+
### Dot-Notation (Association Traversal)
|
|
1540
|
+
|
|
1541
|
+
Use string field names with dot-notation to traverse associations:
|
|
1542
|
+
|
|
1543
|
+
```ruby
|
|
1544
|
+
index do
|
|
1545
|
+
column "company.name", sortable: true # belongs_to
|
|
1546
|
+
column "company.industry", renderer: :badge # with renderer
|
|
1547
|
+
column "contacts.full_name", renderer: :collection # has_many
|
|
1548
|
+
end
|
|
1549
|
+
|
|
1550
|
+
show do
|
|
1551
|
+
section "Details" do
|
|
1552
|
+
field "company.name"
|
|
1553
|
+
field "company.industry", renderer: :badge
|
|
1554
|
+
field "contacts.full_name", renderer: :collection,
|
|
1555
|
+
options: { limit: 5, separator: " | " }
|
|
1556
|
+
end
|
|
1557
|
+
end
|
|
1558
|
+
```
|
|
1559
|
+
|
|
1560
|
+
### Template Syntax
|
|
1561
|
+
|
|
1562
|
+
Use `{field}` syntax in string field names:
|
|
1563
|
+
|
|
1564
|
+
```ruby
|
|
1565
|
+
index do
|
|
1566
|
+
column "{first_name} {last_name}"
|
|
1567
|
+
column "{company.name}: {title}"
|
|
1568
|
+
end
|
|
1569
|
+
```
|
|
1570
|
+
|
|
1571
|
+
### Collection Renderer
|
|
1572
|
+
|
|
1573
|
+
The `collection` renderer renders arrays from has_many dot-paths:
|
|
1574
|
+
|
|
1575
|
+
```ruby
|
|
1576
|
+
index do
|
|
1577
|
+
column "contacts.full_name", renderer: :collection,
|
|
1578
|
+
options: { limit: 3, overflow: "...", separator: ", " }
|
|
1579
|
+
end
|
|
1580
|
+
```
|
|
1581
|
+
|
|
1582
|
+
### Custom Renderers
|
|
1583
|
+
|
|
1584
|
+
Reference custom renderers (from `app/renderers/`) by name:
|
|
1585
|
+
|
|
1586
|
+
```ruby
|
|
1587
|
+
index do
|
|
1588
|
+
column :stage, renderer: :conditional_badge,
|
|
1589
|
+
options: { rules: [...] }
|
|
1590
|
+
end
|
|
1591
|
+
```
|
|
1592
|
+
|
|
1593
|
+
## DSL vs YAML Equivalence
|
|
1594
|
+
|
|
1595
|
+
| DSL | YAML Equivalent |
|
|
1596
|
+
|-----|----------------|
|
|
1597
|
+
| `model :deal` | `model: deal` |
|
|
1598
|
+
| `label "Deals"` | `label: "Deals"` |
|
|
1599
|
+
| `slug "deals"` | `slug: deals` |
|
|
1600
|
+
| `read_only true` | `read_only: true` |
|
|
1601
|
+
| `index do ... end` | `index: { ... }` |
|
|
1602
|
+
| `includes :company` | `index: { includes: [company] }` |
|
|
1603
|
+
| `eager_load :company` | `index: { eager_load: [company] }` |
|
|
1604
|
+
| `reorderable true` | `index: { reorderable: true }` |
|
|
1605
|
+
| `column :title, sortable: true` | `table_columns: [{ field: title, sortable: true }]` |
|
|
1606
|
+
| `row_click :show` | `index: { row_click: show }` |
|
|
1607
|
+
| `empty_message "No records."` | `index: { empty_message: "No records." }` |
|
|
1608
|
+
| `actions_position :inline` | `index: { actions_position: inline }` |
|
|
1609
|
+
| `show do section "Info", responsive: {...} do ... end end` | `show: { layout: [{ section: "Info", responsive: {...}, ... }] }` |
|
|
1610
|
+
| `show do section "X", visible_when: { field: :f, operator: :eq, value: "v" } do ... end end` | `show: { layout: [{ section: "X", visible_when: { field: f, operator: eq, value: v }, ... }] }` |
|
|
1611
|
+
| `association_list "X", association: :y` | `{ section: "X", type: association_list, association: y }` |
|
|
1612
|
+
| `association_list "X", association: :y, display_template: :default, link: true, sort: { name: :asc }, limit: 5, empty_message: "None.", scope: :active` | `{ section: "X", type: association_list, association: y, display_template: default, link: true, sort: { name: asc }, limit: 5, empty_message: "None.", scope: active }` |
|
|
1613
|
+
| `association_list "X", association: :y, link_through: :z` | `{ section: "X", type: association_list, association: y, link_through: z }` |
|
|
1614
|
+
| `form do layout :tabs end` | `form: { layout: tabs }` |
|
|
1615
|
+
| `form do section "Details", collapsible: true do ... end end` | `form: { sections: [{ title: "Details", collapsible: true, ... }] }` |
|
|
1616
|
+
| `nested_fields "Items", association: :items do ... end` | `form: { sections: [{ type: nested_fields, title: "Items", association: items, ... }] }` |
|
|
1617
|
+
| `nested_fields "Steps", json_field: :steps do ... end` | `form: { sections: [{ type: nested_fields, title: "Steps", json_field: steps, ... }] }` |
|
|
1618
|
+
| `nested_fields "Addr", json_field: :addresses, target_model: :address do ... end` | `form: { sections: [{ type: nested_fields, title: "Addr", json_field: addresses, target_model: address, ... }] }` |
|
|
1619
|
+
| `divider label: "Address"` | `fields: [{ type: divider, label: "Address" }]` |
|
|
1620
|
+
| `field :x, col_span: 2, hint: "Help"` | `fields: [{ field: x, col_span: 2, hint: "Help" }]` |
|
|
1621
|
+
| `field :x, visible_when: { field: :status, operator: :eq, value: "active" }` | `fields: [{ field: x, visible_when: { field: status, operator: eq, value: active } }]` |
|
|
1622
|
+
| `field :x, disable_when: { field: :status, operator: :blank }` | `fields: [{ field: x, disable_when: { field: status, operator: blank } }]` |
|
|
1623
|
+
| `index do render_with "x/y" end` | `index: { render_with: "x/y" }` |
|
|
1624
|
+
| `show do render_with "x/y" end` | `show: { render_with: "x/y" }` |
|
|
1625
|
+
| `show do custom_section "X", partial: "x/y" end` | `show: { layout: [{ section: "X", type: custom, partial: "x/y" }] }` |
|
|
1626
|
+
| `form do custom_section "X", partial: "x/y", additional_permitted_params: ["z"] end` | `form: { sections: [{ title: "X", type: custom, partial: "x/y", additional_permitted_params: [z] }] }` |
|
|
1627
|
+
| `search do ... end` | `search: { ... }` |
|
|
1628
|
+
| `search enabled: false` | `search: { enabled: false }` |
|
|
1629
|
+
| `action :show, type: :built_in, on: :single` | `actions: { single: [{ name: show, type: built_in }] }` |
|
|
1630
|
+
| `navigation menu: :main, position: 1` | `navigation: { menu: main, position: 1 }` |
|
|
1631
|
+
|
|
1632
|
+
For the full YAML attribute reference, see [Presenters Reference](presenters.md).
|
|
1633
|
+
|
|
1634
|
+
## Complete Example
|
|
1635
|
+
|
|
1636
|
+
A deal management presenter demonstrating all DSL features:
|
|
1637
|
+
|
|
1638
|
+
```ruby
|
|
1639
|
+
# config/lcp_ruby/presenters/deal.rb
|
|
1640
|
+
define_presenter :deal do
|
|
1641
|
+
model :deal
|
|
1642
|
+
label "Deals"
|
|
1643
|
+
slug "deals"
|
|
1644
|
+
icon "dollar-sign"
|
|
1645
|
+
|
|
1646
|
+
index do
|
|
1647
|
+
default_view :table
|
|
1648
|
+
default_sort :created_at, :desc
|
|
1649
|
+
per_page 25
|
|
1650
|
+
row_click :show
|
|
1651
|
+
empty_message "No deals yet. Create your first deal to get started."
|
|
1652
|
+
actions_position :dropdown
|
|
1653
|
+
column :title, width: "30%", link_to: :show, sortable: true, pinned: :left
|
|
1654
|
+
column :stage, width: "20%", renderer: :badge, sortable: true,
|
|
1655
|
+
options: { color_map: { lead: "blue", closed_won: "green", closed_lost: "red" } }
|
|
1656
|
+
column :value, width: "20%", renderer: :currency, sortable: true,
|
|
1657
|
+
summary: :sum, hidden_on: :mobile
|
|
1658
|
+
end
|
|
1659
|
+
|
|
1660
|
+
show do
|
|
1661
|
+
section "Deal Information", columns: 2, responsive: { mobile: 1 } do
|
|
1662
|
+
field :title, renderer: :heading, col_span: 2
|
|
1663
|
+
field :stage, renderer: :badge
|
|
1664
|
+
field :value, renderer: :currency
|
|
1665
|
+
end
|
|
1666
|
+
end
|
|
1667
|
+
|
|
1668
|
+
form do
|
|
1669
|
+
layout :tabs
|
|
1670
|
+
|
|
1671
|
+
section "Deal Details", columns: 2, responsive: { mobile: 1 } do
|
|
1672
|
+
field :title, placeholder: "Deal title...", autofocus: true,
|
|
1673
|
+
hint: "A short descriptive name for the deal"
|
|
1674
|
+
field :stage, input_type: :select
|
|
1675
|
+
field :value, input_type: :number, prefix: "$", col_span: 1
|
|
1676
|
+
field :company_id, input_type: :association_select
|
|
1677
|
+
field :contact_id, input_type: :association_select
|
|
1678
|
+
end
|
|
1679
|
+
|
|
1680
|
+
section "Additional Info", collapsible: true, collapsed: true do
|
|
1681
|
+
field :description, input_type: :textarea, col_span: 2
|
|
1682
|
+
divider label: "Internal"
|
|
1683
|
+
field :notes, input_type: :textarea, readonly: true,
|
|
1684
|
+
visible_when: { field: :stage, operator: :not_eq, value: "lead" }
|
|
1685
|
+
end
|
|
1686
|
+
|
|
1687
|
+
nested_fields "Line Items", association: :line_items,
|
|
1688
|
+
allow_add: true, allow_remove: true,
|
|
1689
|
+
max: 20, add_label: "Add Line Item",
|
|
1690
|
+
empty_message: "No line items.", columns: 3 do
|
|
1691
|
+
field :product_name, placeholder: "Product..."
|
|
1692
|
+
field :quantity, input_type: :number, default: 1
|
|
1693
|
+
field :unit_price, input_type: :number, prefix: "$"
|
|
1694
|
+
end
|
|
1695
|
+
end
|
|
1696
|
+
|
|
1697
|
+
search do
|
|
1698
|
+
searchable_fields :title
|
|
1699
|
+
placeholder "Search deals..."
|
|
1700
|
+
filter :all, label: "All", default: true
|
|
1701
|
+
filter :open, label: "Open", scope: :open_deals
|
|
1702
|
+
filter :won, label: "Won", scope: :won
|
|
1703
|
+
filter :lost, label: "Lost", scope: :lost
|
|
1704
|
+
end
|
|
1705
|
+
|
|
1706
|
+
action :create, type: :built_in, on: :collection, label: "New Deal", icon: "plus"
|
|
1707
|
+
action :show, type: :built_in, on: :single, icon: "eye"
|
|
1708
|
+
action :edit, type: :built_in, on: :single, icon: "pencil"
|
|
1709
|
+
action :close_won, type: :custom, on: :single,
|
|
1710
|
+
label: "Close as Won", icon: "check-circle",
|
|
1711
|
+
confirm: true, confirm_message: "Mark this deal as won?",
|
|
1712
|
+
visible_when: { field: :stage, operator: :not_in, value: [:closed_won, :closed_lost] }
|
|
1713
|
+
action :destroy, type: :built_in, on: :single, icon: "trash", confirm: true, style: :danger
|
|
1714
|
+
|
|
1715
|
+
navigation menu: :main, position: 3
|
|
1716
|
+
end
|
|
1717
|
+
```
|
|
1718
|
+
|
|
1719
|
+
Source: `lib/lcp_ruby/dsl/presenter_builder.rb`, `lib/lcp_ruby/dsl/dsl_loader.rb`
|