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,985 @@
|
|
|
1
|
+
# Menu Reference
|
|
2
|
+
|
|
3
|
+
The menu system controls the navigation layout of your LCP Ruby application. It supports top bar, sidebar, or combined layouts with dropdown grouping, custom links, separators, and role-based visibility.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
LcpRuby.configure do |config|
|
|
9
|
+
config.menu_mode = :auto # :auto (default) or :strict
|
|
10
|
+
end
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
| Mode | No menu.yml | menu.yml exists |
|
|
14
|
+
|------|------------|-----------------|
|
|
15
|
+
| `:auto` | Auto-generate nav from view groups | Use menu + auto-append unreferenced view groups |
|
|
16
|
+
| `:strict` | Raises `MetadataError` | Use menu only (sole source of truth) |
|
|
17
|
+
|
|
18
|
+
### Auto-append transparency log
|
|
19
|
+
|
|
20
|
+
In `:auto` mode, when the loader auto-appends view groups that aren't explicitly referenced in `menu.yml`, it emits a single info-level log line at boot:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
[LcpRuby] Auto-appended 4 view groups to top_menu: alpha, bravo, charlie, delta.
|
|
24
|
+
Add them to config/lcp_ruby/menu.yml for custom ordering or dropdown placement,
|
|
25
|
+
or set `navigation: { auto_append: false }` on the view group to hide it from the menu.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The log fires only when at least one view group was auto-appended. It is silent when `menu.yml` already references every navigable view group, and never fires in `:strict` mode (no auto-append runs).
|
|
29
|
+
|
|
30
|
+
The opt-out is per view group: set `navigation: { auto_append: false }` (in `config/lcp_ruby/views/<name>.rb`/`.yml`) on infrastructure view groups (e.g. `audit_logs`, `job_executions`) that should stay accessible via URL but invisible in navigation.
|
|
31
|
+
|
|
32
|
+
## File Location
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
config/lcp_ruby/menu.yml
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Entity Generator Markers
|
|
39
|
+
|
|
40
|
+
Files seeded by `rails generate lcp_ruby:install` (or `lcp new`) include single-line **insertion markers** for the entity generator's `--menu=...` flag:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
menu:
|
|
44
|
+
top_menu:
|
|
45
|
+
- view_group: items
|
|
46
|
+
# lcp:menu top # entity generator marker - do not edit/delete
|
|
47
|
+
sidebar_menu:
|
|
48
|
+
# lcp:menu sidebar # entity generator marker - do not edit/delete
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`rails generate lcp_ruby:entity Student … --menu=ROOT` inserts the new `- view_group: student` entry **immediately above** the matching marker. Dropdown markers (`# lcp:menu top > "School"`) are added automatically when `--menu=NewLabel` auto-creates a dropdown.
|
|
52
|
+
|
|
53
|
+
**Don't delete markers.** Editing other lines (reordering, adding labels, restructuring) is fine — only the marker comment lines themselves need to stay intact for future generator runs. Apps generated before this feature can opt in by pasting the marker manually (see [`docs/guides/menu.md`](../guides/menu.md) for the `--menu` walkthrough).
|
|
54
|
+
|
|
55
|
+
The install generator's `--menu-layout=top|sidebar|both` (default `both`) seeds the corresponding section blocks + markers. `lcp new` exposes the same flag and asks during the interactive wizard.
|
|
56
|
+
|
|
57
|
+
## YAML Schema
|
|
58
|
+
|
|
59
|
+
The file **must** use `menu:` as the top-level YAML key, and **at least one** of `top_menu` or `sidebar_menu` must be present. Omitting both raises `MetadataError` at boot. Other key names (e.g., `items`, `nav_menu`) are not recognized.
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
menu:
|
|
63
|
+
top_menu: # Top bar navigation items
|
|
64
|
+
- ...
|
|
65
|
+
sidebar_menu: # Sidebar navigation items
|
|
66
|
+
- ...
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
> **Minimal valid menu file:**
|
|
70
|
+
> ```yaml
|
|
71
|
+
> menu:
|
|
72
|
+
> top_menu: []
|
|
73
|
+
> ```
|
|
74
|
+
|
|
75
|
+
**Layout mode** is determined by which keys are present:
|
|
76
|
+
|
|
77
|
+
| Keys present | Layout |
|
|
78
|
+
|-------------|--------|
|
|
79
|
+
| Only `top_menu` | Top bar |
|
|
80
|
+
| Only `sidebar_menu` | Sidebar |
|
|
81
|
+
| Both | Top bar + sidebar |
|
|
82
|
+
|
|
83
|
+
## Menu Item Types
|
|
84
|
+
|
|
85
|
+
Each item in the menu arrays must be one of four types, determined by which key is present:
|
|
86
|
+
|
|
87
|
+
### View Group Reference
|
|
88
|
+
|
|
89
|
+
References an existing view group. Label, icon, and slug are resolved from the view group's primary presenter.
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
- view_group: deals
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Optional overrides:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
- view_group: deals
|
|
99
|
+
label: "My Deals" # Override resolved label
|
|
100
|
+
icon: dollar # Override resolved icon
|
|
101
|
+
visible_when:
|
|
102
|
+
role: [admin, manager]
|
|
103
|
+
position: bottom # Pin to sidebar bottom
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Group (Dropdown / Collapsible Section)
|
|
107
|
+
|
|
108
|
+
Container for nested items. Renders as a dropdown in top bar, collapsible section in sidebar.
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
- label: "CRM"
|
|
112
|
+
icon: briefcase
|
|
113
|
+
children:
|
|
114
|
+
- view_group: deals
|
|
115
|
+
- view_group: companies
|
|
116
|
+
- separator: true
|
|
117
|
+
- label: "Reports"
|
|
118
|
+
url: /crm/reports
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Required:** `label`
|
|
122
|
+
|
|
123
|
+
### Custom Link
|
|
124
|
+
|
|
125
|
+
Link to an external or host app URL.
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
- label: "Dashboard"
|
|
129
|
+
icon: home
|
|
130
|
+
url: /dashboard
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Required:** `label`, `url`
|
|
134
|
+
|
|
135
|
+
**HTTP method.** GET-style URLs render as `<a>` and integrate with Turbo Drive (SPA-style navigation). For non-GET destinations (sign-out via DELETE, host actions via POST/PUT/PATCH) add `method:` and the framework renders a `button_to` form with CSRF token + Rails `_method` override:
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
- url: "/users/sign_out"
|
|
139
|
+
method: delete
|
|
140
|
+
label: "Sign out"
|
|
141
|
+
icon: log-out
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`method:` accepts `get`, `post`, `put`, `patch`, `delete` (case-insensitive). Invalid on `view_group:`, `children:` (groups always GET-equivalent), and `separator:`. See [Method-Aware Rendering](#method-aware-rendering).
|
|
145
|
+
|
|
146
|
+
### Presenter Link (slug-rename-resilient)
|
|
147
|
+
|
|
148
|
+
Resolve the URL through an LCP presenter's `record_alias` and action contract instead of hardcoding it. When the host renames the presenter slug, the link still works.
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
- presenter: my_settings
|
|
152
|
+
alias: me # resolved via record_aliases on the presenter
|
|
153
|
+
action: edit # built-in CRUD or a custom action name
|
|
154
|
+
label: "My Settings"
|
|
155
|
+
icon: settings
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Keys:**
|
|
159
|
+
|
|
160
|
+
| Key | Required | Notes |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| `presenter` | yes | Presenter slug as declared in `config/lcp_ruby/presenters/`. |
|
|
163
|
+
| `action` | yes | Built-in (`show` / `edit` / `new` / `destroy` / `index`) or a custom action name declared on the presenter under `actions: collection:` / `actions: single:` / `actions: batch:` / `actions: form:`. |
|
|
164
|
+
| `alias` | for `show` / `edit` / `destroy` and single-record custom actions | Record alias declared under the presenter's `record_aliases:`. Omit for `index` / `new` / collection-context custom actions. |
|
|
165
|
+
| `defaults` | no | Extra query parameters forwarded to the resolved URL (see [Path Templating](#path-templating)). |
|
|
166
|
+
|
|
167
|
+
**Default HTTP method:** `:get` for show/edit/new/index, `:delete` for destroy, `:post` for custom actions. Override with `method:`.
|
|
168
|
+
|
|
169
|
+
**Permission gating.** `presenter:` items run the same `can_access_presenter?` check as the presenter toolbar plus `can?(action)` for built-ins or `can_execute_action?(action)` for custom actions. Items the current user cannot execute are hidden.
|
|
170
|
+
|
|
171
|
+
See [Presenter Resolver](#presenter-resolver) for URL shape per action type.
|
|
172
|
+
|
|
173
|
+
### Computed Item (`provider:`)
|
|
174
|
+
|
|
175
|
+
Compute the whole item (or a sibling array of items) at render time. Use for "Current organization" links, multi-tenant switchers, "recently visited" lists, or anything that depends on runtime data.
|
|
176
|
+
|
|
177
|
+
```yaml
|
|
178
|
+
- provider: current_org_link
|
|
179
|
+
options: { variant: compact }
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The provider class is registered under the `menu_items` services category at `app/lcp_services/menu_items/<name>.rb` (namespaced `LcpRuby::HostServices::MenuItems::<Name>`). It implements `.call(options:, current_user:, request_context:)` and returns:
|
|
183
|
+
|
|
184
|
+
| Return | Behaviour |
|
|
185
|
+
|---|---|
|
|
186
|
+
| Hash | Single item — replaces the YAML position. |
|
|
187
|
+
| Array of hashes | Sibling expansion at the YAML position. |
|
|
188
|
+
| `nil` or `[]` | Item silently collapses (no rendering). |
|
|
189
|
+
|
|
190
|
+
The returned hash uses standard MenuItem keys (`url`, `label`, `icon`, `method`, `badge`, …); `provider:` and `panel_provider:` chains are forbidden inside the return.
|
|
191
|
+
|
|
192
|
+
See [Computed Items](#computed-items-provider).
|
|
193
|
+
|
|
194
|
+
### Custom Renderers (`render:` / `render_panel:` / `widget:`)
|
|
195
|
+
|
|
196
|
+
Three escape hatches for items whose visible content cannot be expressed by the standard `<icon> <label>` shape.
|
|
197
|
+
|
|
198
|
+
| Key | Replaces | Wrapper element |
|
|
199
|
+
|---|---|---|
|
|
200
|
+
| `render:` | the inner HTML of the link/button **trigger** | framework keeps `<a>` / `<button_to>` / dropdown-toggle wrapper |
|
|
201
|
+
| `render_panel:` | the inner HTML of a `:group`'s **dropdown panel** | framework keeps the `<div class="lcp-nav-dropdown-menu">` wrapper |
|
|
202
|
+
| `widget: true` | the entire item — drops the `<a>` / `<button_to>` wrapper | bare `<li class="lcp-menu-widget">` |
|
|
203
|
+
|
|
204
|
+
Path is `<namespace>/<name>` and resolves to `app/views/<namespace>/menu_renderers/_<name>.html.erb`. The framework ships two renderers:
|
|
205
|
+
|
|
206
|
+
- `lcp_ruby/user_menu` — avatar + display name + caret (corner user-menu trigger).
|
|
207
|
+
- `lcp_ruby/user_menu_panel` — profile-card header + items list (corner user-menu panel).
|
|
208
|
+
|
|
209
|
+
```yaml
|
|
210
|
+
# Combined: custom trigger + custom panel
|
|
211
|
+
- render: lcp_ruby/user_menu
|
|
212
|
+
render_panel: lcp_ruby/user_menu_panel
|
|
213
|
+
position: right
|
|
214
|
+
aria_label: "User menu"
|
|
215
|
+
children:
|
|
216
|
+
- presenter: my_settings
|
|
217
|
+
alias: me
|
|
218
|
+
action: edit
|
|
219
|
+
- url: "{lcp_ruby.destroy_user_session_path}"
|
|
220
|
+
method: delete
|
|
221
|
+
label: "Sign out"
|
|
222
|
+
|
|
223
|
+
# Widget: search box that needs to drop the wrapper to receive clicks
|
|
224
|
+
- widget: true
|
|
225
|
+
render: my_app/quick_search
|
|
226
|
+
aria_label: "Search the app"
|
|
227
|
+
position: right
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Provided locals to render partials:
|
|
231
|
+
|
|
232
|
+
| Partial | Locals |
|
|
233
|
+
|---|---|
|
|
234
|
+
| `render:` (trigger) | `item:` (the MenuItem), `disabled:` (boolean) |
|
|
235
|
+
| `render_panel:` | `item:` (the parent group), `items:` (already filtered children — call `panel_items_for(item)` from inside) |
|
|
236
|
+
| `widget:` | `item:`, `disabled:`, `bare:` (boolean — true when nested inside a panel via `render_menu_item`) |
|
|
237
|
+
|
|
238
|
+
See [Custom Renderers](#custom-renderers).
|
|
239
|
+
|
|
240
|
+
### Separator
|
|
241
|
+
|
|
242
|
+
Visual divider between items.
|
|
243
|
+
|
|
244
|
+
```yaml
|
|
245
|
+
- separator: true
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Icon-Only Items
|
|
249
|
+
|
|
250
|
+
Render an item with only an icon (no visible label) — typical for a notifications bell, help link, or compact secondary entry. Boot validation requires every item to render either a label or an icon, and icon-only items must carry an `aria_label` for screen-reader access:
|
|
251
|
+
|
|
252
|
+
```yaml
|
|
253
|
+
# Notifications bell — view_group keeps slug-based active state and the
|
|
254
|
+
# usual presenter permission check.
|
|
255
|
+
- view_group: notifications
|
|
256
|
+
icon: bell
|
|
257
|
+
label: false # opt out of the presenter's label fallback
|
|
258
|
+
aria_label: "Notifications"
|
|
259
|
+
position: right
|
|
260
|
+
badge:
|
|
261
|
+
provider: unread_notifications
|
|
262
|
+
renderer: count_badge
|
|
263
|
+
|
|
264
|
+
# Plain icon-only link to a host route.
|
|
265
|
+
- url: /help
|
|
266
|
+
icon: life-buoy
|
|
267
|
+
aria_label: "Help"
|
|
268
|
+
position: right
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Required:** `icon` (or a view_group whose presenter supplies one) and `aria_label` (or `aria_label_key`).
|
|
272
|
+
|
|
273
|
+
For `view_group` items, omit `label:` to keep the presenter's label as the fallback; set `label: false` to suppress that fallback and go icon-only. For `link`/`group` items, just omit `label:`.
|
|
274
|
+
|
|
275
|
+
The `aria_label` value goes through i18n auto-lookup at `lcp_ruby.menu.aria.<slug>` (sub-namespace prevents collisions with `lcp_ruby.menu.<slug>` for the same literal). Use `aria_label_key:` for an explicit key.
|
|
276
|
+
|
|
277
|
+
The icon placeholder is always emitted with `aria-hidden="true"` so the icon never leaks into the accessible name. The link/button takes its accessible name from either the visible label or `aria_label` — never from the icon.
|
|
278
|
+
|
|
279
|
+
#### Icon rendering
|
|
280
|
+
|
|
281
|
+
The `icon:` value is a [Lucide](https://lucide.dev/icons/) icon name (kebab-case: `bell`, `life-buoy`, `chart-bar`, …). The platform layout ships Lucide as a vendored asset and replaces every `<i data-lucide="…">` placeholder with an inline SVG on first paint and on every Turbo navigation.
|
|
282
|
+
|
|
283
|
+
Markup the helper emits:
|
|
284
|
+
|
|
285
|
+
```html
|
|
286
|
+
<i data-lucide="bell" class="lcp-menu-icon" aria-hidden="true"></i>
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
After Lucide replacement:
|
|
290
|
+
|
|
291
|
+
```html
|
|
292
|
+
<svg class="lucide lucide-bell lcp-menu-icon" aria-hidden="true">…</svg>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
The SVG inherits the link's text colour via `currentColor` and is sized via the `.lcp-menu-icon` CSS hook (defaults: `1rem` in top nav, `0.9rem` in dropdowns, `1.05rem` in sidebar). Hosts override the icon size by re-declaring `.lcp-menu-icon` width/height in their own stylesheet.
|
|
296
|
+
|
|
297
|
+
To use a different icon set (Heroicons, FontAwesome, Material Symbols, …), override the `menu_item_icon_html` helper in your host application — its single responsibility is to map a string identifier to the icon library's preferred markup.
|
|
298
|
+
|
|
299
|
+
See [`docs/design/menu_icon_only_items.md`](../design/menu_icon_only_items.md) for the full design.
|
|
300
|
+
|
|
301
|
+
## Optional Keys
|
|
302
|
+
|
|
303
|
+
These keys can be added to any item (except separators):
|
|
304
|
+
|
|
305
|
+
| Key | Type | Description |
|
|
306
|
+
|-----|------|-------------|
|
|
307
|
+
| `label` | string \| `false` | Display text. Omit for `link`/`group` to render icon-only. `false` is an explicit opt-out from the view_group presenter fallback (see [Icon-Only Items](#icon-only-items)). |
|
|
308
|
+
| `label_key` | string | Explicit i18n key for the label (highest priority, see [Label Resolution](#label-resolution)) |
|
|
309
|
+
| `icon` | string | Icon name (resolved from presenter for view groups). Always rendered with `aria-hidden="true"`. |
|
|
310
|
+
| `aria_label` | string | Accessible name. Required when no visible label renders. Auto-looks up `lcp_ruby.menu.aria.<slug>`. |
|
|
311
|
+
| `aria_label_key` | string | Explicit i18n key for `aria_label`. Mirrors `label_key` for `label`. |
|
|
312
|
+
| `method` | string | HTTP method — `get`/`post`/`put`/`patch`/`delete`. Non-GET renders as `button_to`. Invalid on view_group/group/separator. See [Method-Aware Rendering](#method-aware-rendering). |
|
|
313
|
+
| `defaults` | object | Extra query params forwarded to the resolved URL. String values support [path-template tokens](#path-templating). |
|
|
314
|
+
| `visible_when` | object | Conditional visibility — full ConditionEvaluator surface (see [Conditional Visibility](#conditional-visibility)) |
|
|
315
|
+
| `disable_when` | object | Renders the item visible but in a disabled (greyed-out, non-clickable) state. Same shape as `visible_when:`. See [Disabled State](#disabled-state). |
|
|
316
|
+
| `position` | string | `"bottom"` pins item to sidebar bottom; `"right"` right-aligns item in top bar (see [Position](#position)) |
|
|
317
|
+
| `badge` | object | Dynamic badge display (see [Badges](#badges) section) |
|
|
318
|
+
| `options` | object | Free-form options hash forwarded to a `provider:` or `panel_provider:` (kwarg `options:`). Use to parameterize one provider with different configurations. |
|
|
319
|
+
|
|
320
|
+
### Label Resolution
|
|
321
|
+
|
|
322
|
+
Menu item labels are resolved in this order (first match wins):
|
|
323
|
+
|
|
324
|
+
1. **`label_key`** — explicit i18n key: `I18n.t(label_key, default: label)`
|
|
325
|
+
2. **`label`** — auto-lookup via `I18n.t("lcp_ruby.menu.<parameterized_label>", default: label)`. E.g., label `"HR Turnover"` looks up key `lcp_ruby.menu.hr_turnover`.
|
|
326
|
+
3. **View group fallback** — for view group items without a label, the primary presenter's `resolved_label` is used (which itself resolves via `lcp_ruby.models.<model>.other`).
|
|
327
|
+
|
|
328
|
+
See [i18n Reference](i18n.md#menu-labels) for locale file examples.
|
|
329
|
+
|
|
330
|
+
### Position
|
|
331
|
+
|
|
332
|
+
The `position: bottom` key pins menu items to the bottom of the sidebar. Multiple items with `position: bottom` stack in definition order. This is typically used for settings and logout links:
|
|
333
|
+
|
|
334
|
+
```yaml
|
|
335
|
+
- label: "Settings"
|
|
336
|
+
icon: settings
|
|
337
|
+
url: /settings
|
|
338
|
+
position: bottom
|
|
339
|
+
- label: "Log out"
|
|
340
|
+
icon: log-out
|
|
341
|
+
url: /logout
|
|
342
|
+
position: bottom
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
In top bar layout, `position: bottom` has no effect — items render in definition order.
|
|
346
|
+
|
|
347
|
+
**Top bar right alignment.** In `top_menu`, `position: right` moves a top-level item to a right-aligned zone after a flex spacer. Multiple right-aligned items render in YAML definition order. Use for profile, settings, log out, notifications, and similar secondary entries:
|
|
348
|
+
|
|
349
|
+
```yaml
|
|
350
|
+
top_menu:
|
|
351
|
+
- view_group: dashboard
|
|
352
|
+
- view_group: reports
|
|
353
|
+
- url: /profile/me
|
|
354
|
+
label: "Profile"
|
|
355
|
+
icon: user
|
|
356
|
+
position: right
|
|
357
|
+
- label: "Log out"
|
|
358
|
+
icon: log-out
|
|
359
|
+
url: /logout
|
|
360
|
+
position: right
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Semantics per menu layout:**
|
|
364
|
+
|
|
365
|
+
| Layout | `position: "bottom"` | `position: "right"` |
|
|
366
|
+
|--------|----------------------|---------------------|
|
|
367
|
+
| `top_menu` | ignored | **right-aligned** |
|
|
368
|
+
| `sidebar_menu` | pinned to footer | ignored |
|
|
369
|
+
|
|
370
|
+
Only the diagonal combinations (`sidebar + bottom`, `top + right`) are meaningful; the other two are silently ignored. `position` applies only to **top-level** items — dropdown children ignore it. Separators support `position: right` and join the right-aligned zone.
|
|
371
|
+
|
|
372
|
+
## Nested Sub-Groups
|
|
373
|
+
|
|
374
|
+
Groups can contain sub-groups (one additional level of `children:`) for organizing large menus. Maximum nesting depth is **2 levels** of `children:`. Deeper nesting raises a `MetadataError` at boot.
|
|
375
|
+
|
|
376
|
+
```yaml
|
|
377
|
+
- label: "Features"
|
|
378
|
+
children:
|
|
379
|
+
- view_group: basic_fields
|
|
380
|
+
- separator: true
|
|
381
|
+
- label: "Search & Filters" # Sub-group (level 2)
|
|
382
|
+
children:
|
|
383
|
+
- view_group: advanced_search
|
|
384
|
+
- view_group: saved_filters
|
|
385
|
+
- label: "Workflow" # Sub-group (level 2)
|
|
386
|
+
children:
|
|
387
|
+
- view_group: workflows
|
|
388
|
+
- view_group: approval_tasks
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Top menu:** Sub-groups render as flyout submenus that open to the right on hover. If the flyout would overflow the viewport, it flips horizontally (opens left) or vertically (aligns bottom). Keyboard users can Tab into submenus via `:focus-within`. Sub-group labels have `aria-haspopup="true"`.
|
|
392
|
+
|
|
393
|
+
**Sidebar:** Sub-groups render as nested collapsible sections with additional indentation. Click to expand/collapse (same interaction as top-level groups).
|
|
394
|
+
|
|
395
|
+
**Active state:** propagates through nested sub-groups — if any item inside a sub-group matches the current slug, both the sub-group and its parent group are highlighted.
|
|
396
|
+
|
|
397
|
+
**Empty sub-group hiding:** if all children of a sub-group are filtered out by `visible_when` constraints, the sub-group itself is hidden (same as top-level groups).
|
|
398
|
+
|
|
399
|
+
Sub-groups support all the same features as top-level groups: `visible_when`, `badge`, and child types (`view_group`, `link`, `separator`).
|
|
400
|
+
|
|
401
|
+
## Conditional Visibility
|
|
402
|
+
|
|
403
|
+
Use `visible_when` to gate menu items. The condition is evaluated through `LcpRuby::ConditionEvaluator` with **no record context** — menu items are global navigation, so only conditions that don't need a record are supported:
|
|
404
|
+
|
|
405
|
+
| Shape | Supported? | Notes |
|
|
406
|
+
|-------|-----------|-------|
|
|
407
|
+
| `service:` (+ optional `params:`) | ✅ | Full kwargs via `params:`. Built-in: `current_user_role`. |
|
|
408
|
+
| `all:` / `any:` / `not:` (compound) | ✅ | Recurses into children with the same restrictions. |
|
|
409
|
+
| `field:` | ❌ | Rejected by validator — needs a record (menu has none). |
|
|
410
|
+
| `collection:` | ❌ | Rejected by validator — needs a record. |
|
|
411
|
+
| `role: [...]` (legacy shorthand) | ❌ | Rejected by validator with migration hint. |
|
|
412
|
+
|
|
413
|
+
### Built-in: `current_user_role`
|
|
414
|
+
|
|
415
|
+
Restrict by role using the canonical service form:
|
|
416
|
+
|
|
417
|
+
```yaml
|
|
418
|
+
- label: "Admin"
|
|
419
|
+
visible_when:
|
|
420
|
+
service: current_user_role
|
|
421
|
+
params:
|
|
422
|
+
in: [admin]
|
|
423
|
+
children:
|
|
424
|
+
- view_group: users
|
|
425
|
+
- view_group: settings
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
The user's role is read via `LcpRuby.user_roles(user)`, which honours `Configuration#role_method` (default: `:lcp_role`). The user model contract is "respond to `role_method` returning a string or array of strings" — works with Devise, host User models, and `:none`/`:built_in`/`:external` auth modes.
|
|
429
|
+
|
|
430
|
+
`params:` accepts:
|
|
431
|
+
- `in:` — list of allowed roles (visible if user has *any*).
|
|
432
|
+
- `not_in:` — list of denied roles (visible if user has *none*).
|
|
433
|
+
|
|
434
|
+
### Compound conditions
|
|
435
|
+
|
|
436
|
+
Combine multiple checks with `all:`/`any:`/`not:`:
|
|
437
|
+
|
|
438
|
+
```yaml
|
|
439
|
+
- label: "Reports"
|
|
440
|
+
visible_when:
|
|
441
|
+
any:
|
|
442
|
+
- service: current_user_role
|
|
443
|
+
params: { in: [admin] }
|
|
444
|
+
- service: feature_flag # host-registered service
|
|
445
|
+
params: { flag: reports_beta }
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
```yaml
|
|
449
|
+
- label: "Public"
|
|
450
|
+
visible_when:
|
|
451
|
+
not:
|
|
452
|
+
service: current_user_role
|
|
453
|
+
params: { in: [guest] }
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Other access checks
|
|
457
|
+
|
|
458
|
+
View group items additionally check **presenter accessibility** via the permission system, regardless of `visible_when`. A user without `index` CRUD on the model never sees the item, even if the role gate would pass.
|
|
459
|
+
|
|
460
|
+
### Migration from legacy `role:` shorthand
|
|
461
|
+
|
|
462
|
+
If you used the pre-upgrade form:
|
|
463
|
+
|
|
464
|
+
```yaml
|
|
465
|
+
# old (rejected by validator)
|
|
466
|
+
visible_when:
|
|
467
|
+
role: [admin]
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Rewrite as:
|
|
471
|
+
|
|
472
|
+
```yaml
|
|
473
|
+
visible_when:
|
|
474
|
+
service: current_user_role
|
|
475
|
+
params:
|
|
476
|
+
in: [admin]
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
See [`condition-operators.md`](condition-operators.md) for the full condition syntax reference, and [`engine-configuration.md#role_method`](engine-configuration.md#role_method) for the user-role contract.
|
|
480
|
+
|
|
481
|
+
## Path Templating
|
|
482
|
+
|
|
483
|
+
`url:`, `label:`, `aria_label:`, and any string value inside `defaults:` may contain `{namespace.member[.member2[.member3]]}` placeholders that resolve at render time:
|
|
484
|
+
|
|
485
|
+
| Namespace | Hops | Resolves to |
|
|
486
|
+
|---|---|---|
|
|
487
|
+
| `current_user.<a>[.<b>[.<c>]]` | 1–3 | `public_send` chain on `LcpRuby::Current.user`. e.g. `{current_user.id}`, `{current_user.organization.slug}`. |
|
|
488
|
+
| `lcp_ruby.<helper>` | 1 | Engine route helper from `LcpRuby::Engine.routes.url_helpers`. e.g. `{lcp_ruby.destroy_user_session_path}`. |
|
|
489
|
+
| `application.<helper>` | 1 | Host-app route helper from `Rails.application.routes.url_helpers`. e.g. `{application.root_path}`. |
|
|
490
|
+
|
|
491
|
+
```yaml
|
|
492
|
+
- url: "/orgs/{current_user.organization.slug}/members/{current_user.id}"
|
|
493
|
+
label: "Profile of {current_user.name}"
|
|
494
|
+
- url: "{lcp_ruby.destroy_user_session_path}"
|
|
495
|
+
method: delete
|
|
496
|
+
label: "Sign out"
|
|
497
|
+
- defaults: { scope: "user-{current_user.id}" }
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
**Validation.** Tokens are validated structurally at config-load time (grammar, namespace allowlist, hop count) and again at boot/`to_prepare` time for route-helper existence + arity (helpers requiring required arguments are rejected — only argument-less helpers work in templates). Malformed tokens, unknown namespaces, or 4+ hops fail validation at boot.
|
|
501
|
+
|
|
502
|
+
**Runtime errors.** A `current_user.<chain>` that hits `nil` mid-chain or calls a method the receiver doesn't respond to raises `LcpRuby::MenuRenderError`. In development/test the error surfaces; in production the error is recorded via `LcpRuby.record_error` and the affected item silently drops.
|
|
503
|
+
|
|
504
|
+
## Method-Aware Rendering
|
|
505
|
+
|
|
506
|
+
The `method:` key controls which Rails helper is used to render the item:
|
|
507
|
+
|
|
508
|
+
| `method:` | Renders | Notes |
|
|
509
|
+
|---|---|---|
|
|
510
|
+
| omitted, `get` | `<a href>` (with `link_to`) | Default. Integrates with Turbo Drive. |
|
|
511
|
+
| `post`, `put`, `patch`, `delete` | `<form><button>` (with `button_to`) | Includes CSRF authenticity token + Rails `_method` hidden field for non-POST. |
|
|
512
|
+
|
|
513
|
+
Default per destination:
|
|
514
|
+
|
|
515
|
+
| Destination | Default method |
|
|
516
|
+
|---|---|
|
|
517
|
+
| `url:` | `:get` |
|
|
518
|
+
| `view_group:` | `:get` (always — index pages are GET) |
|
|
519
|
+
| `presenter: ... action: show/edit/index/new` | `:get` |
|
|
520
|
+
| `presenter: ... action: destroy` | `:delete` |
|
|
521
|
+
| `presenter: ... action: <custom>` | `:post` |
|
|
522
|
+
|
|
523
|
+
`disable_when:` works for both shapes — the disabled `<button>` is natively non-activatable; the disabled `<a>` is gated by a Stimulus `lcp-menu` controller that prevents click activation client-side.
|
|
524
|
+
|
|
525
|
+
## Presenter Resolver
|
|
526
|
+
|
|
527
|
+
The `presenter:` + `alias:` + `action:` triple resolves to a URL via the engine's resourceful routing scope (`/:lcp_slug/...`). URL shapes:
|
|
528
|
+
|
|
529
|
+
| Action | URL shape | Helper used |
|
|
530
|
+
|---|---|---|
|
|
531
|
+
| `index` | `/<slug>` | `resources_path(lcp_slug:)` |
|
|
532
|
+
| `new` | `/<slug>/new` | `new_resource_path(lcp_slug:)` |
|
|
533
|
+
| `show` | `/<slug>/<alias>` | `resource_path(lcp_slug:, id:)` |
|
|
534
|
+
| `edit` | `/<slug>/<alias>/edit` | `edit_resource_path(lcp_slug:, id:)` |
|
|
535
|
+
| `destroy` | `/<slug>/<alias>` (DELETE) | `destroy_resource_path(lcp_slug:, id:)` |
|
|
536
|
+
| custom + `alias:` | `/<slug>/<alias>/actions/<action_name>` | `single_action_path(lcp_slug:, id:, action_name:)` |
|
|
537
|
+
| custom (no alias) | `/<slug>/actions/<action_name>` | `collection_action_path(lcp_slug:, action_name:)` |
|
|
538
|
+
|
|
539
|
+
`alias:` values are presenter-level — declared under `record_aliases:` on the presenter (e.g. `me: { resolve: current_user }` resolves the segment to the current user's id at request time). The same model can have different aliases in different presenters.
|
|
540
|
+
|
|
541
|
+
`defaults:` forwards extra query parameters to the helper. String values pass through path templating, so `defaults: { scope: "user-{current_user.id}" }` works.
|
|
542
|
+
|
|
543
|
+
## Disabled State
|
|
544
|
+
|
|
545
|
+
`disable_when:` mirrors `visible_when:` — same condition shapes (`service:` + `params:`, compound `all`/`any`/`not`) — but instead of hiding the item, the platform renders it visible with the disabled affordance:
|
|
546
|
+
|
|
547
|
+
```yaml
|
|
548
|
+
- presenter: notifications
|
|
549
|
+
action: mark_all_read
|
|
550
|
+
label: "Mark all as read"
|
|
551
|
+
icon: check
|
|
552
|
+
disable_when:
|
|
553
|
+
service: notifications_unread_count
|
|
554
|
+
params: { eq: 0 }
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
Effects when the condition evaluates true:
|
|
558
|
+
|
|
559
|
+
- Visual: `lcp-menu-item--disabled` class on the link/button.
|
|
560
|
+
- A11y: `aria-disabled="true"` on `<a>` items, native `disabled` on `<button>` items.
|
|
561
|
+
- Click activation: Stimulus `lcp-menu` controller's `prevent` action blocks click + keyboard activation on `<a>` items (native `<button disabled>` already blocks both).
|
|
562
|
+
- Dropdown trigger: the `lcp-nav-dropdown--disabled` modifier on the `<li>` also suppresses the hover-open behaviour, so a disabled group-trigger does not reveal its panel.
|
|
563
|
+
|
|
564
|
+
`disable_when:` is a **UI affordance, not a security boundary**. The endpoint behind the URL must enforce its own authorization — a determined user can copy the disabled URL out of the DOM. Use `visible_when:` (or server-side authorization) for security gating.
|
|
565
|
+
|
|
566
|
+
In production, errors from a `disable_when:` service are swallowed and the item renders enabled (failure-bias toward usability — prevents a service outage from locking users out of working buttons). In dev/test the error is raised. See `MenuItem#meets_enabled?`.
|
|
567
|
+
|
|
568
|
+
## Computed Items (`provider:`)
|
|
569
|
+
|
|
570
|
+
A `provider:` item delegates the entire item construction to a Ruby class:
|
|
571
|
+
|
|
572
|
+
```ruby
|
|
573
|
+
# app/lcp_services/menu_items/current_org_link.rb
|
|
574
|
+
module LcpRuby::HostServices::MenuItems
|
|
575
|
+
class CurrentOrgLink
|
|
576
|
+
def self.call(options:, current_user:, request_context:)
|
|
577
|
+
org = current_user&.current_organization
|
|
578
|
+
return nil unless org
|
|
579
|
+
|
|
580
|
+
{
|
|
581
|
+
url: "/orgs/#{org.slug}",
|
|
582
|
+
label: org.name,
|
|
583
|
+
icon: "building",
|
|
584
|
+
badge: { provider: "org_unread_count", renderer: "count_badge" }
|
|
585
|
+
}
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Wired via `provider:` in YAML:
|
|
592
|
+
|
|
593
|
+
```yaml
|
|
594
|
+
- provider: current_org_link
|
|
595
|
+
- provider: recent_records
|
|
596
|
+
options: { limit: 5 }
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
**Return shapes:**
|
|
600
|
+
|
|
601
|
+
| Return | Walker behaviour |
|
|
602
|
+
|---|---|
|
|
603
|
+
| Hash | One MenuItem replaces the YAML position. |
|
|
604
|
+
| Array of hashes | `flat_map` — each hash becomes a sibling. |
|
|
605
|
+
| `nil` / `[]` | Silent collapse (no item rendered, no warning). |
|
|
606
|
+
|
|
607
|
+
**Constraints on returns:**
|
|
608
|
+
|
|
609
|
+
- The hash's keys are validated against the standard MenuItem allowlist; `provider:` and `panel_provider:` chains are forbidden (each YAML position resolves to one source — chains would invite recursion bugs).
|
|
610
|
+
- Returned `:group` items are recursed for visibility filtering before being rendered.
|
|
611
|
+
- Depth is threaded through the walker so providers cannot bypass the `MAX_NESTING_DEPTH` (currently 2) limit by returning deeply nested structures.
|
|
612
|
+
|
|
613
|
+
**Modifier inheritance.** Static modifier keys on the YAML provider item (`label`, `icon`, `position`, `badge`, `visible_when`, `disable_when`, `aria_label`, `render`) are inherited by each returned hash unless the provider overrides them. Destination keys are stripped on the YAML side (the provider supplies the destination).
|
|
614
|
+
|
|
615
|
+
**Performance.** Providers fire on every render. The platform does **not** cache by default — provider authors are responsible for fragment caching by `[name, current_user.id, options.hash]`. Consider wrapping the body in `Rails.cache.fetch` for expensive computations.
|
|
616
|
+
|
|
617
|
+
## Custom Renderers
|
|
618
|
+
|
|
619
|
+
The three render slots (`render:`, `render_panel:`, `widget:`) compose with destinations (`presenter:`, `url:`, `provider:`, `children:`) and modifiers (`disable_when:`, `visible_when:`, `position:`).
|
|
620
|
+
|
|
621
|
+
### `render:` — custom trigger HTML
|
|
622
|
+
|
|
623
|
+
Replaces the inner content of the link/button wrapper. Use for items where the visible content is more than `<icon> <label>` — e.g. avatar + display name + caret on the user menu trigger.
|
|
624
|
+
|
|
625
|
+
The framework still owns:
|
|
626
|
+
|
|
627
|
+
- The wrapping element (`<a>`, `<button_to>` form, or `<button class="lcp-nav-dropdown-toggle">` for groups).
|
|
628
|
+
- ARIA attributes (`role`, `aria-label`, `aria-disabled`).
|
|
629
|
+
- Active-state class.
|
|
630
|
+
- Badge placement (rendered after the partial output, unless badge is suppressed via no-badge YAML).
|
|
631
|
+
|
|
632
|
+
The partial output is constrained to phrasing/inline content (HTML forbids block-level inside `<a>`/`<button>`). To emit block content, combine with `widget: true`.
|
|
633
|
+
|
|
634
|
+
### `render_panel:` — custom dropdown panel HTML
|
|
635
|
+
|
|
636
|
+
Replaces the inner content of a `:group`'s dropdown panel. The framework keeps the `<div class="lcp-nav-dropdown-menu lcp-nav-dropdown-menu--custom">` wrapper.
|
|
637
|
+
|
|
638
|
+
Locals: `item:` (parent group MenuItem) and `items:` (already filtered children — equivalent to `panel_items_for(item)`). Block-level HTML allowed (panel is `<div>`-wrapped).
|
|
639
|
+
|
|
640
|
+
Pair with `panel_provider:` to pull panel children from a Ruby class:
|
|
641
|
+
|
|
642
|
+
```yaml
|
|
643
|
+
- render_panel: my_app/tenant_switcher_panel
|
|
644
|
+
panel_provider: user_tenants
|
|
645
|
+
children: [] # explicit "no static children"
|
|
646
|
+
options: { current_only: false }
|
|
647
|
+
aria_label: "Switch tenant"
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### `widget: true` — drop the wrapper
|
|
651
|
+
|
|
652
|
+
Lifts the inline-content constraint by removing the wrapping `<a>`/`<button_to>` entirely. The framework keeps `<li class="lcp-menu-widget">` for layout consistency; the `render:` partial owns everything inside.
|
|
653
|
+
|
|
654
|
+
Use for menu items whose inner HTML is itself interactive — search inputs, theme switchers, language pickers — where a wrapping link/button would swallow events.
|
|
655
|
+
|
|
656
|
+
```yaml
|
|
657
|
+
- widget: true
|
|
658
|
+
render: my_app/quick_search
|
|
659
|
+
aria_label: "Search the app"
|
|
660
|
+
position: right
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
**Required** with `widget: true`: `render:`. **Forbidden** with `widget: true`: `url:`, `presenter:`, `view_group:`, `children:`, `separator:` (no destination URL — there's no wrapper to attach it to). `provider:` is allowed (provider returns widget data, render: produces the markup).
|
|
664
|
+
|
|
665
|
+
## Detection Priority
|
|
666
|
+
|
|
667
|
+
When parsing a menu item hash, keys are checked in this order:
|
|
668
|
+
|
|
669
|
+
1. `separator` — separator item
|
|
670
|
+
2. `view_group` — view group reference
|
|
671
|
+
3. `children` — group with nested items
|
|
672
|
+
4. `url`, `presenter`, `provider`, or `widget` — link-typed item
|
|
673
|
+
|
|
674
|
+
## Auto Mode Behavior
|
|
675
|
+
|
|
676
|
+
In `:auto` mode (the default):
|
|
677
|
+
|
|
678
|
+
1. If no `menu.yml` exists, navigation is auto-generated from view groups (same as before)
|
|
679
|
+
2. If `menu.yml` exists, it is used as the menu definition
|
|
680
|
+
3. Any navigable view groups not referenced in `menu.yml` are automatically appended to `top_menu`
|
|
681
|
+
4. View groups with `navigation: false` are excluded from auto-generation and auto-append
|
|
682
|
+
|
|
683
|
+
## Strict Mode Behavior
|
|
684
|
+
|
|
685
|
+
In `:strict` mode:
|
|
686
|
+
|
|
687
|
+
1. `menu.yml` is required — raises `MetadataError` if missing
|
|
688
|
+
2. The menu is the sole source of truth — no auto-append
|
|
689
|
+
3. View groups must not have `navigation` config (only `navigation: false` is allowed)
|
|
690
|
+
|
|
691
|
+
## Badges
|
|
692
|
+
|
|
693
|
+
Menu items can display dynamic badges — counts, text labels, or icons — populated by data providers.
|
|
694
|
+
|
|
695
|
+
### Badge YAML Schema
|
|
696
|
+
|
|
697
|
+
```yaml
|
|
698
|
+
- view_group: tasks
|
|
699
|
+
badge:
|
|
700
|
+
provider: open_tasks # Required: data provider name
|
|
701
|
+
renderer: count_badge # One of: renderer, template, or partial
|
|
702
|
+
options: # Optional: passed to renderer
|
|
703
|
+
color: "#dc3545"
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
Exactly one rendering form must be specified:
|
|
707
|
+
|
|
708
|
+
| Key | Description |
|
|
709
|
+
|-----|-------------|
|
|
710
|
+
| `renderer` | A `Display::BaseRenderer` subclass from `Display::RendererRegistry` |
|
|
711
|
+
| `template` | String with `{key}` interpolation, wrapped in a badge `<span>` |
|
|
712
|
+
| `partial` | Rails partial path, receives `data` local variable |
|
|
713
|
+
|
|
714
|
+
### Data Providers
|
|
715
|
+
|
|
716
|
+
Data providers are registered in `Services::Registry` under the `data_providers` category. They are auto-discovered from `app/lcp_services/data_providers/`.
|
|
717
|
+
|
|
718
|
+
**Contract:** `call(user:)` → data (any shape) or `nil` (nil = hide badge).
|
|
719
|
+
|
|
720
|
+
```ruby
|
|
721
|
+
# app/lcp_services/data_providers/open_tasks.rb
|
|
722
|
+
module LcpRuby::HostServices::DataProviders
|
|
723
|
+
class OpenTasks
|
|
724
|
+
def self.call(user:)
|
|
725
|
+
LcpRuby::Dynamic::Task.where(status: "open").count
|
|
726
|
+
end
|
|
727
|
+
end
|
|
728
|
+
end
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Built-in Badge Renderers
|
|
732
|
+
|
|
733
|
+
| Renderer | Input | Output |
|
|
734
|
+
|----------|-------|--------|
|
|
735
|
+
| `count_badge` | Positive `Integer` | Red pill with count (nil for 0 or non-integer) |
|
|
736
|
+
| `text_badge` | `String` or `Hash` with `"text"`, optional `"color"` | Uppercase text badge with optional background color |
|
|
737
|
+
| `icon_badge` | `String` or `Hash` with `"icon"`, optional `"color"` | Icon element with optional color |
|
|
738
|
+
|
|
739
|
+
### Template Form
|
|
740
|
+
|
|
741
|
+
For the `template` form, `{key}` placeholders are interpolated from the provider data:
|
|
742
|
+
|
|
743
|
+
- If provider returns a **Hash**, keys are available directly: `{count}`, `{label}`
|
|
744
|
+
- If provider returns a **simple value** (Integer, String), use `{value}`
|
|
745
|
+
|
|
746
|
+
```yaml
|
|
747
|
+
- view_group: inbox
|
|
748
|
+
badge:
|
|
749
|
+
provider: unread_messages
|
|
750
|
+
template: "{count} new"
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### Partial Form
|
|
754
|
+
|
|
755
|
+
The partial receives a `data` local variable with the provider's return value:
|
|
756
|
+
|
|
757
|
+
```yaml
|
|
758
|
+
- view_group: system_health
|
|
759
|
+
badge:
|
|
760
|
+
provider: health_status
|
|
761
|
+
partial: "badges/health_indicator"
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Badge Examples
|
|
765
|
+
|
|
766
|
+
```yaml
|
|
767
|
+
menu:
|
|
768
|
+
sidebar_menu:
|
|
769
|
+
# Count badge on tasks
|
|
770
|
+
- view_group: tasks
|
|
771
|
+
badge:
|
|
772
|
+
provider: open_tasks
|
|
773
|
+
renderer: count_badge
|
|
774
|
+
|
|
775
|
+
# Text badge with color
|
|
776
|
+
- view_group: inbox
|
|
777
|
+
badge:
|
|
778
|
+
provider: unread_messages
|
|
779
|
+
template: "{count} new"
|
|
780
|
+
|
|
781
|
+
# Badge on a group
|
|
782
|
+
- label: "CRM"
|
|
783
|
+
badge:
|
|
784
|
+
provider: crm_alerts
|
|
785
|
+
renderer: text_badge
|
|
786
|
+
options:
|
|
787
|
+
color: "#dc3545"
|
|
788
|
+
children:
|
|
789
|
+
- view_group: deals
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
## Complete Example
|
|
793
|
+
|
|
794
|
+
```yaml
|
|
795
|
+
menu:
|
|
796
|
+
top_menu:
|
|
797
|
+
- view_group: deals
|
|
798
|
+
- label: "CRM"
|
|
799
|
+
icon: briefcase
|
|
800
|
+
children:
|
|
801
|
+
- view_group: companies
|
|
802
|
+
- view_group: contacts
|
|
803
|
+
- separator: true
|
|
804
|
+
- label: "Reports" # Nested sub-group (flyout)
|
|
805
|
+
children:
|
|
806
|
+
- view_group: monthly_reports
|
|
807
|
+
- view_group: annual_reports
|
|
808
|
+
- label: "External"
|
|
809
|
+
url: /crm/reports
|
|
810
|
+
|
|
811
|
+
sidebar_menu:
|
|
812
|
+
- view_group: deals
|
|
813
|
+
- label: "CRM"
|
|
814
|
+
icon: briefcase
|
|
815
|
+
children:
|
|
816
|
+
- view_group: companies
|
|
817
|
+
- view_group: contacts
|
|
818
|
+
- label: "Reports" # Nested sub-group (collapsible)
|
|
819
|
+
children:
|
|
820
|
+
- view_group: monthly_reports
|
|
821
|
+
- view_group: annual_reports
|
|
822
|
+
- label: "Settings"
|
|
823
|
+
icon: settings
|
|
824
|
+
position: bottom
|
|
825
|
+
visible_when:
|
|
826
|
+
role: [admin]
|
|
827
|
+
children:
|
|
828
|
+
- view_group: users
|
|
829
|
+
- view_group: audit_log
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
## Responsive Behavior
|
|
833
|
+
|
|
834
|
+
The top nav and sidebar adapt to viewport size via the `responsive:`
|
|
835
|
+
block in `menu.yml`. When the block is omitted, sensible defaults apply
|
|
836
|
+
out of the box — every LCP app gets responsive navigation with zero
|
|
837
|
+
configuration. See [docs/design/responsive-menu.md](../design/responsive-menu.md)
|
|
838
|
+
for the full design rationale.
|
|
839
|
+
|
|
840
|
+
### Top-nav modes
|
|
841
|
+
|
|
842
|
+
```yaml
|
|
843
|
+
menu:
|
|
844
|
+
responsive:
|
|
845
|
+
top_menu:
|
|
846
|
+
mode: overflow_more # none | wrap | overflow_more | hamburger
|
|
847
|
+
breakpoint: 768 # px
|
|
848
|
+
more:
|
|
849
|
+
label_key: lcp_ruby.nav.more
|
|
850
|
+
icon: more-horizontal
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
| Mode | Behavior |
|
|
854
|
+
|---|---|
|
|
855
|
+
| `none` | No responsive adaptation. Use only if your host stylesheet owns layout. |
|
|
856
|
+
| `wrap` | Items that don't fit wrap onto subsequent rows. CSS-only. |
|
|
857
|
+
| `overflow_more` *(default)* | Items that don't fit collapse into a synthesized *More* dropdown. Items with `pin: always` or `position: right` never collapse. |
|
|
858
|
+
| `hamburger` | Below `breakpoint`, the entire left zone hides behind a hamburger drawer. |
|
|
859
|
+
|
|
860
|
+
### Sidebar modes
|
|
861
|
+
|
|
862
|
+
```yaml
|
|
863
|
+
menu:
|
|
864
|
+
responsive:
|
|
865
|
+
sidebar_menu:
|
|
866
|
+
above_breakpoint: rail # none | rail
|
|
867
|
+
below_breakpoint: off_canvas # none | off_canvas
|
|
868
|
+
breakpoint: 1024
|
|
869
|
+
user_toggle: true
|
|
870
|
+
persist: cookie # cookie | local_storage | none
|
|
871
|
+
initial: expanded # expanded | collapsed | auto
|
|
872
|
+
auto_inject_toggle: true
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
| State | Behavior |
|
|
876
|
+
|---|---|
|
|
877
|
+
| `above_breakpoint: rail` | Viewport >= breakpoint: sidebar can collapse to icon-only rail. User toggle is sticky at top. State persists via cookie (1y, path-scoped to engine mount). |
|
|
878
|
+
| `above_breakpoint: none` | Viewport >= breakpoint: sidebar always full width. |
|
|
879
|
+
| `below_breakpoint: off_canvas` | Viewport < breakpoint: sidebar hides off-screen and opens via an auto-injected `sidebar_toggle` button in `top_menu` (suppressed by `auto_inject_toggle: false` or an explicit `- sidebar_toggle: true` item). |
|
|
880
|
+
| `below_breakpoint: none` | Viewport < breakpoint: sidebar stays inline (may overflow horizontally). |
|
|
881
|
+
|
|
882
|
+
### Per-item responsive keys
|
|
883
|
+
|
|
884
|
+
Apply to any `top_menu` item (most keys also accepted on children for
|
|
885
|
+
forward compat, but only the `overflow_more` measurement loop reads
|
|
886
|
+
`responsive_priority` / `pin`):
|
|
887
|
+
|
|
888
|
+
| Key | Type | Effect |
|
|
889
|
+
|---|---|---|
|
|
890
|
+
| `responsive_priority` | integer | Higher = collapse later. `position: right` and `pin: always` implicitly priority infinity. |
|
|
891
|
+
| `pin` | `always` | Never collapses into *More*. |
|
|
892
|
+
| `hide_below` | px integer | Hide on viewports narrower than this value (presentational only, not a permission boundary). |
|
|
893
|
+
| `show_below` | px integer | Show ONLY on viewports narrower than this value. Mutex with `hide_below`. |
|
|
894
|
+
| `collapse_label_below` | px integer | (Sidebar) Drop the visible label and show icon only when viewport is narrower than this value. |
|
|
895
|
+
|
|
896
|
+
### Escape hatch
|
|
897
|
+
|
|
898
|
+
To disable all responsive behavior (e.g. a host with custom responsive
|
|
899
|
+
CSS):
|
|
900
|
+
|
|
901
|
+
```yaml
|
|
902
|
+
menu:
|
|
903
|
+
responsive:
|
|
904
|
+
top_menu: { mode: none }
|
|
905
|
+
sidebar_menu: { above_breakpoint: none, below_breakpoint: none }
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
### sidebar_toggle marker
|
|
909
|
+
|
|
910
|
+
```yaml
|
|
911
|
+
top_menu:
|
|
912
|
+
- sidebar_toggle: true
|
|
913
|
+
label_key: lcp_ruby.nav.menu
|
|
914
|
+
icon: menu
|
|
915
|
+
position: left
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
Renders a button that opens the sidebar's off-canvas drawer.
|
|
919
|
+
Platform-owned UI chrome — carries no destination URL. The framework
|
|
920
|
+
auto-injects one of these when `below_breakpoint: off_canvas` is active
|
|
921
|
+
and no explicit one is authored; opt out with
|
|
922
|
+
`auto_inject_toggle: false`.
|
|
923
|
+
|
|
924
|
+
### Mobile header (sidebar-only layouts)
|
|
925
|
+
|
|
926
|
+
When a host app has `sidebar_menu` only (no `top_menu`) and the policy
|
|
927
|
+
keeps `below_breakpoint: off_canvas` + `auto_inject_toggle: true`
|
|
928
|
+
(both defaults), the platform renders a thin sticky `_mobile_header.html.erb`
|
|
929
|
+
strip above the layout. Below the sidebar breakpoint the strip becomes
|
|
930
|
+
visible with a hamburger button that opens the sidebar drawer; above
|
|
931
|
+
breakpoint it's hidden via CSS (`body.lcp-sidebar-off-canvas-active`
|
|
932
|
+
class toggled by `lcp-responsive-sidebar` from its `matchMedia`
|
|
933
|
+
listener).
|
|
934
|
+
|
|
935
|
+
The off-canvas drawer overrides the rail-collapsed width — even if the
|
|
936
|
+
user persisted `lcp_sidebar=collapsed` in the rail-mode cookie, opening
|
|
937
|
+
the drawer on a narrow viewport shows full-width labels
|
|
938
|
+
(`min(80vw, 280px)`).
|
|
939
|
+
|
|
940
|
+
Suppress the mobile header by either (a) authoring an explicit
|
|
941
|
+
`sidebar_toggle:` somewhere in `top_menu` (only works if you also add a
|
|
942
|
+
`top_menu`; sidebar-only layouts don't have one), or (b) setting
|
|
943
|
+
`responsive.sidebar_menu.auto_inject_toggle: false` (sidebar drawer
|
|
944
|
+
then has no built-in trigger — author your own).
|
|
945
|
+
|
|
946
|
+
### Rail-collapsed flyouts
|
|
947
|
+
|
|
948
|
+
When the sidebar is in `above_breakpoint: rail` mode AND the user has
|
|
949
|
+
collapsed it (`data-rail="collapsed"`), group items show only their
|
|
950
|
+
icons. Clicking a group icon opens its `children` as an
|
|
951
|
+
absolute-positioned flyout panel to the right of the rail:
|
|
952
|
+
|
|
953
|
+
- Only one flyout open at a time per page.
|
|
954
|
+
- ESC closes the open flyout.
|
|
955
|
+
- Outside-click closes (single shared capture-phase document listener).
|
|
956
|
+
- Leaf items (`view_group:`, `url:`, `presenter:`) inside the flyout
|
|
957
|
+
are standard `<a>` links — click navigates.
|
|
958
|
+
|
|
959
|
+
CSS uses `overflow: visible` on the rail (`.lcp-sidebar[data-rail=
|
|
960
|
+
"collapsed"]`) instead of the default `overflow-y: auto`, so the
|
|
961
|
+
flyout can escape the rail's right edge. Trade-off: the rail loses
|
|
962
|
+
vertical scroll. Hosts with 20+ groups can set
|
|
963
|
+
`responsive.sidebar_menu.above_breakpoint: none` to keep the sidebar
|
|
964
|
+
full-width and skip rail mode entirely.
|
|
965
|
+
|
|
966
|
+
### Custom trigger renderers in sidebar (`render:`)
|
|
967
|
+
|
|
968
|
+
`render: lcp_ruby/user_menu` (or any custom trigger partial) works in
|
|
969
|
+
both top-nav and sidebar contexts. In the sidebar:
|
|
970
|
+
|
|
971
|
+
- The trigger renders in the configured group's `.lcp-sidebar-group-toggle`
|
|
972
|
+
button — full content control via the partial.
|
|
973
|
+
- Framework drops its native badge + arrow when `render:` is set,
|
|
974
|
+
matching top-nav behavior.
|
|
975
|
+
- The item is **not** treated as icon-only even if no `label:` is
|
|
976
|
+
authored — the renderer is presumed to supply its own visible label.
|
|
977
|
+
This keeps `Demo User (admin)`-style triggers aligned at the icon
|
|
978
|
+
column (~16 px) like other group headers, instead of being centered
|
|
979
|
+
like the notifications bell / help link / other intentionally-icon-only
|
|
980
|
+
items.
|
|
981
|
+
|
|
982
|
+
In rail-collapsed mode, the avatar (`.lcp-user-menu__avatar`) remains
|
|
983
|
+
visible as the rail icon, while the label / caret hide along with other
|
|
984
|
+
labels.
|
|
985
|
+
|