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,1187 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide walks you through building a two-model TODO application with LCP Ruby — from installation to custom actions and event handlers. By the end, you'll have task lists and tasks with associations, search filters, a custom action, and an event handler.
|
|
4
|
+
|
|
5
|
+
All examples use the **Ruby DSL** as the primary format. YAML equivalents are provided in collapsible blocks.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
| Requirement | Version |
|
|
10
|
+
|-------------|---------|
|
|
11
|
+
| Ruby | >= 3.1 |
|
|
12
|
+
| Rails | >= 8.1 (for `lcp new`) or >= 7.1 (manual setup) |
|
|
13
|
+
| Database | SQLite (development), PostgreSQL (production recommended) |
|
|
14
|
+
|
|
15
|
+
LCP Ruby works with any Rails-supported database. SQLite is fine for development and this tutorial.
|
|
16
|
+
|
|
17
|
+
## Quick Start with `lcp new`
|
|
18
|
+
|
|
19
|
+
The fastest way to create a new LCP Ruby application:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
lcp new my_app
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This launches an interactive wizard that asks about:
|
|
26
|
+
- **Database** — sqlite3, postgresql, or mysql2
|
|
27
|
+
- **Metadata format** — Ruby DSL (default) or YAML
|
|
28
|
+
- **Feature preset** — minimal, standard, full, or custom (choose individual features)
|
|
29
|
+
|
|
30
|
+
Feature presets:
|
|
31
|
+
| Preset | Includes |
|
|
32
|
+
|--------|----------|
|
|
33
|
+
| **minimal** | Core platform only (sample model + presenter + permissions) |
|
|
34
|
+
| **standard** | Core + authentication + auditing + saved filters + export + import |
|
|
35
|
+
| **full** | All 17 feature generators |
|
|
36
|
+
| **custom** | Interactive selection of individual features |
|
|
37
|
+
|
|
38
|
+
After the wizard, `lcp new` runs `rails new` with the right configuration, installs LCP Ruby, runs selected feature generators, and prepares the database. Then:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cd my_app
|
|
42
|
+
rails s
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Visit `http://localhost:3000/items` to see the sample application.
|
|
46
|
+
|
|
47
|
+
To skip the interactive wizard and use defaults (sqlite3, DSL, minimal):
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
lcp new my_app --skip-interactive
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
CLI options: `--database=postgresql`, `--format=yaml`, `--preset=standard`, `--timezone=Europe/Prague`, `--locale=cs` (single-locale) or `--locale=cs,en,de` (multi-locale — first listed is `default_locale`), `--menu-layout=both|top|sidebar`, `--skip-action-text` (omits Trix WYSIWYG; `:rich_text` fields will render as plain textareas).
|
|
54
|
+
|
|
55
|
+
For locale-specific guidance — engine UI translation, fallbacks, `available_locales` ↔ `Accept-Language` interaction, migration from pre-v1 generators — see [guides/adding-locale.md](guides/adding-locale.md).
|
|
56
|
+
|
|
57
|
+
If `lcp new` reports that some feature generators failed (e.g. the
|
|
58
|
+
preset asked for a feature whose prerequisites couldn't be installed),
|
|
59
|
+
the command exits non-zero. Use `--allow-partial` to override and
|
|
60
|
+
continue, then run `bundle exec rake lcp_ruby:doctor` from the new
|
|
61
|
+
app to see exactly what is broken and how to fix it. See
|
|
62
|
+
[reference/doctor.md](reference/doctor.md) for the full diagnostic.
|
|
63
|
+
|
|
64
|
+
`lcp new` also installs [Claude Code skills](#claude-code-skills-ai-assisted-development) into `.claude/skills/` automatically — see the dedicated section below.
|
|
65
|
+
|
|
66
|
+
### Installing from a local checkout
|
|
67
|
+
|
|
68
|
+
If `lcp_ruby` is not yet on RubyGems (pre-release, internal fork), point the generator at a local gem path:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
lcp new my_app --gem-source=path:/abs/path/to/lcp-ruby
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
When you run `lcp` directly from a local clone (`bundle exec exe/lcp …`), the CLI auto-detects the checkout and uses `path:` automatically — you don't need the flag. The flag is only required when the binary is installed elsewhere (gem index, `gem install`, copied binary). The default when no checkout is detected is `rubygems`, which fails until the gem is published.
|
|
75
|
+
|
|
76
|
+
## Manual Installation (existing Rails app)
|
|
77
|
+
|
|
78
|
+
If you have an existing Rails application, use the install generator instead:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Add to Gemfile
|
|
82
|
+
gem "lcp"
|
|
83
|
+
|
|
84
|
+
# Install
|
|
85
|
+
bundle install
|
|
86
|
+
rails generate lcp_ruby:install
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The generator sets up everything: `require "lcp_ruby"` in `application.rb`, engine mount in routes, directory structure, sample model, initializer, and a `current_user` stub.
|
|
90
|
+
|
|
91
|
+
### Scaffolding new entities
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Minimal scaffold — model + presenter + permissions + view group, top-level menu entry
|
|
95
|
+
rails generate lcp_ruby:entity Customer name:string! email:email!:uniq phone:phone \
|
|
96
|
+
--label-method=name --menu=ROOT --menu-icon=users
|
|
97
|
+
|
|
98
|
+
# Richer entity (v2/v3 grammar) — DB constraints, sections, renderers, link, search, color_map
|
|
99
|
+
rails generate lcp_ruby:entity Order \
|
|
100
|
+
'number:string!:uniq' \
|
|
101
|
+
'customer:belongs_to{required}' \
|
|
102
|
+
'status:enum{draft|confirmed|shipped|delivered}!{default:draft}{color_map}' \
|
|
103
|
+
'total:decimal!{renderer:currency}' \
|
|
104
|
+
--label-method=number \
|
|
105
|
+
--display-template='Order {number}' \
|
|
106
|
+
--searchable-fields=number \
|
|
107
|
+
--menu=Sales # auto-creates "Sales" dropdown if it doesn't yet exist
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`lcp_ruby:entity` creates `models/<name>.rb`, `presenters/<plural>.rb`, `permissions/<name>.yml`, `views/<name>.yml` atomically and (when `--menu=...` is passed) inserts the matching `- view_group: <name>` line into `config/lcp_ruby/menu.yml` above the seeded `# lcp:menu <section>` marker. Field grammar covers all built-in types, inline enum values (`enum{a|b|c}`), DB modifiers (`!`, `:uniq`, `:index`, `{default:X}`), associations (`belongs_to`, `has_many`), and v3 presenter modifiers (`{section:NAME}`, `{renderer:NAME}`, `{color_map}`, `{link}`, `{polymorphic}`, `:hidden`, `:search`). Feature flags: `--soft-delete`, `--auditing`, `--custom-fields`, `--positioning`, `--tree`, `--form-layout=tabs`, `--index-fields=a,b,c`, `--menu=[<section>:]ROOT|<Label>[:bottom|:right]`, `--menu-icon=<lucide>`. **Bash users:** single-quote any field token whose braces contain a comma — bash brace-expands `{a,b}` patterns. See [the design spec](design/entity_generator.md) for full grammar and worked examples; the `--menu=...` placement grammar is documented in [`guides/menu.md`](guides/menu.md#adding-entities-to-the-menu).
|
|
111
|
+
|
|
112
|
+
### Adding features
|
|
113
|
+
|
|
114
|
+
Run any of the feature generators after install:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
rails generate lcp_ruby:install_auth # Devise authentication
|
|
118
|
+
rails generate lcp_ruby:api_tokens # Personal Access Tokens (bearer auth)
|
|
119
|
+
rails generate lcp_ruby:auditing # Audit trail
|
|
120
|
+
rails generate lcp_ruby:export # Data export
|
|
121
|
+
rails generate lcp_ruby:import # Data import
|
|
122
|
+
rails generate lcp_ruby:custom_fields # Runtime field definitions
|
|
123
|
+
rails generate lcp_ruby:saved_filters # Saved search filters
|
|
124
|
+
rails generate lcp_ruby:monitoring # Error dashboard
|
|
125
|
+
rails generate lcp_ruby:batch_operations # Bulk operations
|
|
126
|
+
rails generate lcp_ruby:background_jobs # Job tracking
|
|
127
|
+
rails generate lcp_ruby:pages # DB-backed pages
|
|
128
|
+
rails generate lcp_ruby:groups # User groups
|
|
129
|
+
rails generate lcp_ruby:role_model # DB-backed roles
|
|
130
|
+
rails generate lcp_ruby:permission_source # Dynamic permissions
|
|
131
|
+
rails generate lcp_ruby:workflow_definition # Workflows
|
|
132
|
+
rails generate lcp_ruby:workflow_approvals # Approval processes
|
|
133
|
+
rails generate lcp_ruby:workflow_audit_log # Workflow audit
|
|
134
|
+
rails generate lcp_ruby:gapfree_sequences # Sequential numbering
|
|
135
|
+
rails generate lcp_ruby:entity # Scaffold a new entity (see "Scaffolding new entities" above)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
All generators support `--format=dsl` (default) or `--format=yaml`.
|
|
139
|
+
|
|
140
|
+
Each generator declares its prerequisites (e.g. `lcp_ruby:import`
|
|
141
|
+
requires `lcp_ruby:background_jobs` for the FK target; `lcp_ruby:api_tokens`
|
|
142
|
+
requires `lcp_ruby:install_auth` for the user model). If a prereq is
|
|
143
|
+
missing, the generator aborts up-front with a structured
|
|
144
|
+
`Missing prerequisite feature(s): …` message naming what to run first.
|
|
145
|
+
Run `bundle exec rake lcp_ruby:doctor` to see the full feature
|
|
146
|
+
dependency graph.
|
|
147
|
+
|
|
148
|
+
## Claude Code Skills (AI-Assisted Development)
|
|
149
|
+
|
|
150
|
+
LCP Ruby ships a set of [Claude Code](https://claude.ai/code) skills (`lcp-model`, `lcp-presenter`, `lcp-permissions`, `lcp-workflow`, `lcp-custom-field`, `lcp-host-binding`) that auto-trigger when you're authoring the corresponding YAML/DSL configuration. Each skill briefs Claude on the 80/20 syntax + decision points + pitfalls and points at the relevant reference doc for the rest. The result: less time grepping for "how do I declare a `belongs_to` with a business-key join?" and fewer round-trips on common authoring tasks.
|
|
151
|
+
|
|
152
|
+
**Auto-installed by `lcp new`** — you don't need to do anything. The skills land in `.claude/skills/` of the new app. Open the project in Claude Code (CLI, VS Code, or any other client) and skills activate automatically based on context.
|
|
153
|
+
|
|
154
|
+
**Manual install / refresh after gem upgrade:**
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
rails generate lcp_ruby:claude_skills
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This copies `.claude/skills/lcp-*/` from the gem path into the host application, overwriting the existing copies (use `--force=false` to skip existing files). Re-run after `bundle update lcp_ruby` to pick up skills updated for the new gem version — keeps Claude's instructions in sync with the DSL/schema changes you just bundled.
|
|
161
|
+
|
|
162
|
+
**Verify**: list installed skills via `/skills` inside Claude Code, or `ls .claude/skills/` on disk.
|
|
163
|
+
|
|
164
|
+
**For host-app developers**: commit `.claude/skills/lcp-*` to git so the whole team benefits. (`.claude/settings.local.json` is per-user and stays gitignored.)
|
|
165
|
+
|
|
166
|
+
**For platform contributors** (working on `lcp_ruby` itself): the canonical skill files live in `.claude/skills/` of the gem repo and are loaded automatically when you open the gem in Claude Code. The generator copies these same files — single source of truth.
|
|
167
|
+
|
|
168
|
+
## Installation (step-by-step)
|
|
169
|
+
|
|
170
|
+
For full control over the setup, or if the generator doesn't suit your project structure, follow these manual steps.
|
|
171
|
+
|
|
172
|
+
Add LCP Ruby to your Gemfile:
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
gem "lcp"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Asset Pipeline (Sprockets)
|
|
179
|
+
|
|
180
|
+
LCP Ruby bundles its JavaScript and CSS via Sprockets. If your host app uses **Propshaft** (the Rails 8 default), you must also add `sprockets-rails` — otherwise the engine's JS (Stimulus controllers, row-click navigation, advanced filters, form handling) will not load:
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
gem "sprockets-rails"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Then create `app/assets/config/manifest.js` to link the engine assets:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
//= link lcp_ruby/application.js
|
|
190
|
+
//= link lcp_ruby/application.css
|
|
191
|
+
//= link lcp_ruby/tom-select.css
|
|
192
|
+
//= link lcp_ruby/tom-select.complete.min.js
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
> **Note:** If your host app already uses Sprockets, skip this step — the engine assets are picked up automatically.
|
|
196
|
+
|
|
197
|
+
Run `bundle install`.
|
|
198
|
+
|
|
199
|
+
Mount the engine in `config/routes.rb`:
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
Rails.application.routes.draw do
|
|
203
|
+
mount LcpRuby::Engine => "/"
|
|
204
|
+
end
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
> **Tip:** If you want `http://localhost:3000/` to redirect to your first model's index, add a root route pointing to the engine's slug (e.g., `root to: redirect("/task_lists")`).
|
|
208
|
+
|
|
209
|
+
## Configuration
|
|
210
|
+
|
|
211
|
+
Create an initializer at `config/initializers/lcp_ruby.rb`:
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
LcpRuby.configure do |config|
|
|
215
|
+
config.authentication = :none
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
This is the minimal configuration for a quickstart. All other options have sensible defaults.
|
|
220
|
+
|
|
221
|
+
### Authentication Modes
|
|
222
|
+
|
|
223
|
+
| Mode | Use Case | `current_user` |
|
|
224
|
+
|------|----------|----------------|
|
|
225
|
+
| `:none` | Quickstart / prototyping | Not required |
|
|
226
|
+
| `:external` | Existing app with its own auth (Devise, etc.) | Provided by host app |
|
|
227
|
+
| `:built_in` | Standalone app without existing auth | Managed by LCP Ruby |
|
|
228
|
+
|
|
229
|
+
The default is `:external`. This tutorial uses `:none` so you can skip authentication setup entirely. See [Authentication Setup](#authentication-setup) below when you're ready to add auth.
|
|
230
|
+
|
|
231
|
+
See [Engine Configuration](reference/engine-configuration.md) for all available options.
|
|
232
|
+
|
|
233
|
+
## Directory Structure
|
|
234
|
+
|
|
235
|
+
Create the metadata directories:
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
config/lcp_ruby/
|
|
239
|
+
types/ # Custom business type definitions (optional)
|
|
240
|
+
models/ # Model definitions — .rb (DSL) or .yml (YAML)
|
|
241
|
+
presenters/ # UI definitions — .rb (DSL) or .yml (YAML)
|
|
242
|
+
permissions/ # Role-based access control — .yml only
|
|
243
|
+
views/ # View group definitions (optional — auto-created for single-presenter models)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Both `.rb` (DSL) and `.yml` (YAML) files are supported for models and presenters. Each model/presenter name must be unique across all files — defining the same name in both formats raises `MetadataError`.
|
|
247
|
+
|
|
248
|
+
> **Note:** Permissions are YAML-only. There is no DSL loader for permission files.
|
|
249
|
+
|
|
250
|
+
Metadata auto-loads on Rails boot via the `lcp_ruby.load_metadata` initializer.
|
|
251
|
+
|
|
252
|
+
> **Note:** If you plan to use host app extensions (computed services, custom actions, event handlers, condition services), you must exclude their directories from Zeitwerk autoloading. See [Extensibility Guide — Auto-Discovery Setup](guides/extensibility.md#auto-discovery-setup) for details.
|
|
253
|
+
|
|
254
|
+
## Authentication Setup
|
|
255
|
+
|
|
256
|
+
> **Skip this section** if you're using `authentication: :none` (as in this tutorial).
|
|
257
|
+
|
|
258
|
+
When using `authentication: :external`, your host app must provide a `current_user` object. The user model must implement the method configured by `role_method` (default: `lcp_role`), returning an **array of role name strings**:
|
|
259
|
+
|
|
260
|
+
```ruby
|
|
261
|
+
class User < ApplicationRecord
|
|
262
|
+
def lcp_role
|
|
263
|
+
roles.pluck(:name) # => ["admin", "sales_rep"]
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Your `ApplicationController` must provide `current_user` (typically via Devise, Sorcery, or a custom session-based auth):
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
class ApplicationController < ActionController::Base
|
|
272
|
+
before_action :authenticate_user!
|
|
273
|
+
|
|
274
|
+
def current_user
|
|
275
|
+
@current_user ||= User.find_by(id: session[:user_id])
|
|
276
|
+
end
|
|
277
|
+
helper_method :current_user
|
|
278
|
+
end
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The role strings must match the role names defined in your [permissions YAML](reference/permissions.md).
|
|
282
|
+
|
|
283
|
+
### Built-in Authentication
|
|
284
|
+
|
|
285
|
+
When using `authentication: :built_in`, LCP Ruby manages users internally via `LcpRuby::User`. Run the generator to set up the auth tables and routes:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
rails g lcp_ruby:install_auth
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
This adds Devise-based authentication with login/logout/password reset. The generator's post-install message lists the actual URLs.
|
|
292
|
+
|
|
293
|
+
**Devise routes.** The engine mounts Devise under `path: "auth"` with custom path names — these are the URLs Devise users see, **not** the conventional `/users/sign_in`:
|
|
294
|
+
|
|
295
|
+
| Path | What |
|
|
296
|
+
|---|---|
|
|
297
|
+
| `GET /auth/login` | Sign-in form |
|
|
298
|
+
| `DELETE /auth/logout` (also `GET /auth/logout`) | Sign-out |
|
|
299
|
+
| `GET /auth/register` | Sign-up (if Devise registrations are enabled) |
|
|
300
|
+
| `GET /auth/password/new` | Password reset |
|
|
301
|
+
|
|
302
|
+
When the engine is mounted at a non-root path (e.g. `mount LcpRuby::Engine => "/admin"`), prefix accordingly: `/admin/auth/login`.
|
|
303
|
+
|
|
304
|
+
To create initial users, add them in `db/seeds.rb`:
|
|
305
|
+
|
|
306
|
+
```ruby
|
|
307
|
+
LcpRuby::User.find_or_create_by!(email: "admin@example.com") do |u|
|
|
308
|
+
u.name = "Admin User"
|
|
309
|
+
u.password = "password123"
|
|
310
|
+
u.lcp_role = ["admin"]
|
|
311
|
+
u.active = true
|
|
312
|
+
end
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Key attributes:
|
|
316
|
+
- **`email`** (string, required) — login identifier
|
|
317
|
+
- **`name`** (string) — display name
|
|
318
|
+
- **`password`** (string) — minimum 6 characters; `password_confirmation` is optional in seeds
|
|
319
|
+
- **`lcp_role`** (JSON array of strings) — role names matching your permissions YAML, e.g. `["admin"]`, `["viewer", "editor"]`
|
|
320
|
+
- **`active`** (boolean) — must be `true` for the user to log in; inactive users are rejected at sign-in
|
|
321
|
+
- **`profile_data`** (JSON hash, default `{}`) — extensible storage for custom per-user data (preferences, settings, app-specific fields). Access via `user.profile` which returns a hash with indifferent access
|
|
322
|
+
|
|
323
|
+
#### Storing custom data in `profile_data`
|
|
324
|
+
|
|
325
|
+
The `profile_data` JSON column is the recommended way to store per-user preferences or application-specific data without creating a separate model:
|
|
326
|
+
|
|
327
|
+
```ruby
|
|
328
|
+
# Writing
|
|
329
|
+
user.update!(profile_data: { "locale" => "cs", "timezone" => "Europe/Prague", "theme" => "dark" })
|
|
330
|
+
|
|
331
|
+
# Reading (returns HashWithIndifferentAccess)
|
|
332
|
+
user.profile[:locale] # => "cs"
|
|
333
|
+
user.profile["timezone"] # => "Europe/Prague"
|
|
334
|
+
|
|
335
|
+
# Merging new keys without overwriting existing ones
|
|
336
|
+
user.update!(profile_data: user.profile.merge("items_per_page" => 50))
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
For external auth (`:external`), add a `profile_data` JSON column to your own user model if you want the same pattern, or implement custom accessors.
|
|
340
|
+
|
|
341
|
+
The platform itself reads a small set of well-known keys from `profile_data` on every authenticated request (`theme`, `density`, `border_radius`, `locale`). Any writer — a presenter bound to the user model, the `PreferencesController`, a console `update!` — takes effect on the next render. See the [platform-read keys table](reference/engine-configuration.md#keys-the-platform-reads-from-profile_data) in the engine configuration reference, and the showcase `my_settings` presenter for a reference implementation built on `service: json_field` virtual fields.
|
|
342
|
+
|
|
343
|
+
Then run `rails db:seed` to create the users.
|
|
344
|
+
|
|
345
|
+
> **Note:** The `config.authentication = :built_in` line must appear in `config/initializers/lcp_ruby.rb`. If the generator inserts a duplicate line, remove the old one manually.
|
|
346
|
+
|
|
347
|
+
### OIDC Single Sign-On
|
|
348
|
+
|
|
349
|
+
For Microsoft Entra ID, Google Workspace, Okta, Keycloak, or any OIDC-compliant
|
|
350
|
+
identity provider:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
rails g lcp_ruby:install_auth --mode=oidc --provider=entra --with-built-in
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
This scaffolds `config/lcp_ruby/auth.yml` from a per-provider template
|
|
357
|
+
(available: `entra`, `google`, `okta`, `keycloak`, `generic`), adds the
|
|
358
|
+
required DB columns, and writes the host config (`host_url`, `mount_path`)
|
|
359
|
+
into the initializer. `--with-built-in` keeps a Devise password form on the
|
|
360
|
+
login page as a break-glass fallback.
|
|
361
|
+
|
|
362
|
+
See [OIDC Setup](guides/oidc-setup.md) for the full walkthrough — IdP App
|
|
363
|
+
registration, ENV variable options, role mapping, and troubleshooting — and
|
|
364
|
+
[OIDC Reference](reference/oidc.md) for the complete `auth.yml` schema.
|
|
365
|
+
|
|
366
|
+
## Your First Model: Task List
|
|
367
|
+
|
|
368
|
+
Create `config/lcp_ruby/models/task_list.rb`:
|
|
369
|
+
|
|
370
|
+
```ruby
|
|
371
|
+
define_model :task_list do
|
|
372
|
+
label "Task List"
|
|
373
|
+
label_plural "Task Lists"
|
|
374
|
+
|
|
375
|
+
field :title, :string, label: "Title" do
|
|
376
|
+
validates :presence
|
|
377
|
+
validates :length, minimum: 3, maximum: 255
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
field :description, :text, label: "Description"
|
|
381
|
+
|
|
382
|
+
timestamps true
|
|
383
|
+
label_method :title
|
|
384
|
+
end
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
This creates a `task_lists` database table with `title` and `description` columns, plus `created_at`/`updated_at` timestamps.
|
|
388
|
+
|
|
389
|
+
Key concepts:
|
|
390
|
+
- **`field`** — defines a database column with a name and type
|
|
391
|
+
- **`validates`** — adds ActiveRecord validations (inside a field block, the field context is implicit)
|
|
392
|
+
- **`timestamps`** — adds `created_at` and `updated_at` columns
|
|
393
|
+
- **`label_method`** — the method called on records to generate display text (e.g., in association select dropdowns)
|
|
394
|
+
|
|
395
|
+
<details>
|
|
396
|
+
<summary>YAML equivalent</summary>
|
|
397
|
+
|
|
398
|
+
```yaml
|
|
399
|
+
# config/lcp_ruby/models/task_list.yml
|
|
400
|
+
model:
|
|
401
|
+
name: task_list
|
|
402
|
+
label: "Task List"
|
|
403
|
+
label_plural: "Task Lists"
|
|
404
|
+
|
|
405
|
+
fields:
|
|
406
|
+
- name: title
|
|
407
|
+
type: string
|
|
408
|
+
label: "Title"
|
|
409
|
+
validations:
|
|
410
|
+
- type: presence
|
|
411
|
+
- type: length
|
|
412
|
+
options: { minimum: 3, maximum: 255 }
|
|
413
|
+
|
|
414
|
+
- name: description
|
|
415
|
+
type: text
|
|
416
|
+
label: "Description"
|
|
417
|
+
|
|
418
|
+
options:
|
|
419
|
+
timestamps: true
|
|
420
|
+
label_method: title
|
|
421
|
+
```
|
|
422
|
+
</details>
|
|
423
|
+
|
|
424
|
+
See [Models Reference](reference/models.md) for all field types, validations, associations, and more. See [Model DSL Reference](reference/model-dsl.md) for the full DSL syntax.
|
|
425
|
+
|
|
426
|
+
## Your First Presenter: Task List
|
|
427
|
+
|
|
428
|
+
Create `config/lcp_ruby/presenters/task_list.rb`:
|
|
429
|
+
|
|
430
|
+
```ruby
|
|
431
|
+
define_presenter :task_list do
|
|
432
|
+
model :task_list
|
|
433
|
+
label "Task Lists"
|
|
434
|
+
slug "task_lists"
|
|
435
|
+
icon "list"
|
|
436
|
+
|
|
437
|
+
index do
|
|
438
|
+
default_sort :created_at, :desc
|
|
439
|
+
per_page 25
|
|
440
|
+
empty_message "No task lists yet. Create your first list to get started."
|
|
441
|
+
column :title, link_to: :show, sortable: true
|
|
442
|
+
column :description
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
show do
|
|
446
|
+
section "List Details" do
|
|
447
|
+
field :title, renderer: :heading
|
|
448
|
+
field :description
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
form do
|
|
453
|
+
section "List Details" do
|
|
454
|
+
field :title, placeholder: "My shopping list...", autofocus: true
|
|
455
|
+
field :description, input_type: :textarea, placeholder: "Optional description..."
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
search do
|
|
460
|
+
searchable_fields :title, :description
|
|
461
|
+
placeholder "Search lists..."
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
action :create, type: :built_in, on: :collection, label: "New List", icon: "plus"
|
|
465
|
+
action :show, type: :built_in, on: :single, icon: "eye"
|
|
466
|
+
action :edit, type: :built_in, on: :single, icon: "pencil"
|
|
467
|
+
action :destroy, type: :built_in, on: :single, icon: "trash", confirm: true, style: :danger
|
|
468
|
+
end
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Key concepts:
|
|
472
|
+
- **`index`** — configures the list/table view (columns, sorting, pagination, empty state)
|
|
473
|
+
- **`show`** — configures the detail view with sections and renderers
|
|
474
|
+
- **`form`** — configures create/edit forms with input types and placeholders
|
|
475
|
+
- **`search`** — enables text search across specified fields
|
|
476
|
+
- **`action`** — defines UI buttons (built-in CRUD or custom business logic)
|
|
477
|
+
|
|
478
|
+
<details>
|
|
479
|
+
<summary>YAML equivalent</summary>
|
|
480
|
+
|
|
481
|
+
```yaml
|
|
482
|
+
# config/lcp_ruby/presenters/task_list.yml
|
|
483
|
+
presenter:
|
|
484
|
+
name: task_list
|
|
485
|
+
model: task_list
|
|
486
|
+
label: "Task Lists"
|
|
487
|
+
slug: task_lists
|
|
488
|
+
icon: list
|
|
489
|
+
|
|
490
|
+
index:
|
|
491
|
+
default_sort: { field: created_at, direction: desc }
|
|
492
|
+
per_page: 25
|
|
493
|
+
empty_message: "No task lists yet. Create your first list to get started."
|
|
494
|
+
table_columns:
|
|
495
|
+
- { field: title, link_to: show, sortable: true }
|
|
496
|
+
- { field: description }
|
|
497
|
+
|
|
498
|
+
show:
|
|
499
|
+
layout:
|
|
500
|
+
- section: "List Details"
|
|
501
|
+
fields:
|
|
502
|
+
- { field: title, renderer: heading }
|
|
503
|
+
- { field: description }
|
|
504
|
+
|
|
505
|
+
form:
|
|
506
|
+
sections:
|
|
507
|
+
- title: "List Details"
|
|
508
|
+
fields:
|
|
509
|
+
- { field: title, placeholder: "My shopping list...", autofocus: true }
|
|
510
|
+
- { field: description, input_type: textarea, placeholder: "Optional description..." }
|
|
511
|
+
|
|
512
|
+
search:
|
|
513
|
+
enabled: true
|
|
514
|
+
searchable_fields: [title, description]
|
|
515
|
+
placeholder: "Search lists..."
|
|
516
|
+
|
|
517
|
+
actions:
|
|
518
|
+
collection:
|
|
519
|
+
- { name: create, type: built_in, label: "New List", icon: plus }
|
|
520
|
+
single:
|
|
521
|
+
- { name: show, type: built_in, icon: eye }
|
|
522
|
+
- { name: edit, type: built_in, icon: pencil }
|
|
523
|
+
- { name: destroy, type: built_in, icon: trash, confirm: true, style: danger }
|
|
524
|
+
```
|
|
525
|
+
</details>
|
|
526
|
+
|
|
527
|
+
See [Presenters Reference](reference/presenters.md) for all options. See [Presenter DSL Reference](reference/presenter-dsl.md) for the full DSL syntax.
|
|
528
|
+
|
|
529
|
+
## Your First Permissions: Task List
|
|
530
|
+
|
|
531
|
+
Create `config/lcp_ruby/permissions/task_list.yml`:
|
|
532
|
+
|
|
533
|
+
```yaml
|
|
534
|
+
permissions:
|
|
535
|
+
model: task_list
|
|
536
|
+
|
|
537
|
+
roles:
|
|
538
|
+
admin:
|
|
539
|
+
crud: [index, show, create, update, destroy]
|
|
540
|
+
fields: { readable: all, writable: all }
|
|
541
|
+
actions: all
|
|
542
|
+
scope: all
|
|
543
|
+
presenters: all
|
|
544
|
+
|
|
545
|
+
viewer:
|
|
546
|
+
crud: [index, show]
|
|
547
|
+
fields: { readable: all, writable: [] }
|
|
548
|
+
actions: { allowed: [] }
|
|
549
|
+
scope: all
|
|
550
|
+
presenters: all
|
|
551
|
+
|
|
552
|
+
default_role: admin
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Key concepts:
|
|
556
|
+
- **`roles`** — each key is a role name matched against `current_user.lcp_role`
|
|
557
|
+
- **`crud`** — which operations the role can perform (`index`, `show`, `create`, `update`, `destroy`)
|
|
558
|
+
- **`fields`** — which fields the role can read and write (`all` or an explicit list)
|
|
559
|
+
- **`default_role`** — assigned when the user has no matching role (set to `admin` here since we're using `authentication: :none`)
|
|
560
|
+
|
|
561
|
+
> **Warning:** We use `default_role: admin` only because this tutorial runs without authentication. When you switch to `authentication: :external` or `:built_in`, change `default_role` to a restrictive role like `viewer` so unauthenticated or unknown users don't get full access.
|
|
562
|
+
|
|
563
|
+
> **Tip:** You can create `config/lcp_ruby/permissions/_default.yml` with `model: _default` to provide fallback permissions for all models that don't have their own permission file.
|
|
564
|
+
|
|
565
|
+
See [Permissions Reference](reference/permissions.md) for field overrides, record rules, and scope types.
|
|
566
|
+
|
|
567
|
+
## Run and Verify
|
|
568
|
+
|
|
569
|
+
```bash
|
|
570
|
+
bundle exec rails db:prepare
|
|
571
|
+
bundle exec rails server
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Visit `http://localhost:3000/task_lists`. You should see:
|
|
575
|
+
|
|
576
|
+
1. **Empty state** — the message "No task lists yet. Create your first list to get started."
|
|
577
|
+
2. **"New List" button** — click it to open the create form
|
|
578
|
+
3. **Form** — `title` field with placeholder text and autofocus, `description` textarea
|
|
579
|
+
4. **After saving** — redirects to the show page with your list details
|
|
580
|
+
5. **Navigation menu** — "Task Lists" link in the top navigation
|
|
581
|
+
|
|
582
|
+
Try creating a list, editing it, and searching for it by title.
|
|
583
|
+
|
|
584
|
+
## Second Model with Association: Task
|
|
585
|
+
|
|
586
|
+
Now add a `task` model that belongs to a task list.
|
|
587
|
+
|
|
588
|
+
### Update the Task List Model
|
|
589
|
+
|
|
590
|
+
First, update `config/lcp_ruby/models/task_list.rb` to add a `has_many` association:
|
|
591
|
+
|
|
592
|
+
```ruby
|
|
593
|
+
define_model :task_list do
|
|
594
|
+
label "Task List"
|
|
595
|
+
label_plural "Task Lists"
|
|
596
|
+
|
|
597
|
+
field :title, :string, label: "Title" do
|
|
598
|
+
validates :presence
|
|
599
|
+
validates :length, minimum: 3, maximum: 255
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
field :description, :text, label: "Description"
|
|
603
|
+
|
|
604
|
+
has_many :tasks, model: :task, dependent: :destroy
|
|
605
|
+
|
|
606
|
+
timestamps true
|
|
607
|
+
label_method :title
|
|
608
|
+
end
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Update the Task List Presenter
|
|
612
|
+
|
|
613
|
+
Now that task_list has tasks, update the show section in `config/lcp_ruby/presenters/task_list.rb` to display them:
|
|
614
|
+
|
|
615
|
+
```ruby
|
|
616
|
+
show do
|
|
617
|
+
section "List Details" do
|
|
618
|
+
field :title, renderer: :heading
|
|
619
|
+
field :description
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
association_list "Tasks", association: :tasks
|
|
623
|
+
end
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
The `association_list` renders a list of associated records below the detail section. This is auto-detected for eager loading — no manual `includes` needed.
|
|
627
|
+
|
|
628
|
+
<details>
|
|
629
|
+
<summary>YAML equivalent — updated show section</summary>
|
|
630
|
+
|
|
631
|
+
```yaml
|
|
632
|
+
show:
|
|
633
|
+
layout:
|
|
634
|
+
- section: "List Details"
|
|
635
|
+
fields:
|
|
636
|
+
- { field: title, renderer: heading }
|
|
637
|
+
- { field: description }
|
|
638
|
+
- section: "Tasks"
|
|
639
|
+
type: association_list
|
|
640
|
+
association: tasks
|
|
641
|
+
```
|
|
642
|
+
</details>
|
|
643
|
+
|
|
644
|
+
### Create the Task Model
|
|
645
|
+
|
|
646
|
+
Create `config/lcp_ruby/models/task.rb`:
|
|
647
|
+
|
|
648
|
+
```ruby
|
|
649
|
+
define_model :task do
|
|
650
|
+
label "Task"
|
|
651
|
+
label_plural "Tasks"
|
|
652
|
+
|
|
653
|
+
field :title, :string, label: "Title" do
|
|
654
|
+
validates :presence
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
field :status, :enum, label: "Status", default: "pending",
|
|
658
|
+
values: { pending: "Pending", in_progress: "In Progress", completed: "Completed" }
|
|
659
|
+
|
|
660
|
+
field :due_date, :date, label: "Due Date"
|
|
661
|
+
|
|
662
|
+
field :notes, :text, label: "Notes"
|
|
663
|
+
|
|
664
|
+
belongs_to :task_list, model: :task_list, required: true
|
|
665
|
+
|
|
666
|
+
scope :active, where_not: { status: "completed" }
|
|
667
|
+
scope :completed, where: { status: "completed" }
|
|
668
|
+
|
|
669
|
+
on_field_change :on_status_change, field: :status
|
|
670
|
+
|
|
671
|
+
timestamps true
|
|
672
|
+
label_method :title
|
|
673
|
+
end
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
Key concepts:
|
|
677
|
+
- **`belongs_to`** — creates a foreign key (`task_list_id`) linking each task to a task list
|
|
678
|
+
- **`has_many`** — on the parent model, declares the inverse relationship (with `dependent: :destroy` to cascade deletes)
|
|
679
|
+
- **`:enum`** with **`values:`** — a string field constrained to a set of labeled values, rendered as a `<select>` by default
|
|
680
|
+
- **`scope`** — named query filters (used by presenter filter tabs)
|
|
681
|
+
- **`on_field_change`** — declares a field change event that triggers when `status` changes (handler created [later](#adding-an-event-handler))
|
|
682
|
+
|
|
683
|
+
<details>
|
|
684
|
+
<summary>YAML equivalent — task_list.yml (updated)</summary>
|
|
685
|
+
|
|
686
|
+
```yaml
|
|
687
|
+
# config/lcp_ruby/models/task_list.yml
|
|
688
|
+
model:
|
|
689
|
+
name: task_list
|
|
690
|
+
label: "Task List"
|
|
691
|
+
label_plural: "Task Lists"
|
|
692
|
+
|
|
693
|
+
fields:
|
|
694
|
+
- name: title
|
|
695
|
+
type: string
|
|
696
|
+
label: "Title"
|
|
697
|
+
validations:
|
|
698
|
+
- type: presence
|
|
699
|
+
- type: length
|
|
700
|
+
options: { minimum: 3, maximum: 255 }
|
|
701
|
+
|
|
702
|
+
- name: description
|
|
703
|
+
type: text
|
|
704
|
+
label: "Description"
|
|
705
|
+
|
|
706
|
+
associations:
|
|
707
|
+
- type: has_many
|
|
708
|
+
name: tasks
|
|
709
|
+
target_model: task
|
|
710
|
+
dependent: destroy
|
|
711
|
+
|
|
712
|
+
options:
|
|
713
|
+
timestamps: true
|
|
714
|
+
label_method: title
|
|
715
|
+
```
|
|
716
|
+
</details>
|
|
717
|
+
|
|
718
|
+
<details>
|
|
719
|
+
<summary>YAML equivalent — task.yml</summary>
|
|
720
|
+
|
|
721
|
+
```yaml
|
|
722
|
+
# config/lcp_ruby/models/task.yml
|
|
723
|
+
model:
|
|
724
|
+
name: task
|
|
725
|
+
label: "Task"
|
|
726
|
+
label_plural: "Tasks"
|
|
727
|
+
|
|
728
|
+
fields:
|
|
729
|
+
- name: title
|
|
730
|
+
type: string
|
|
731
|
+
label: "Title"
|
|
732
|
+
validations:
|
|
733
|
+
- type: presence
|
|
734
|
+
|
|
735
|
+
- name: status
|
|
736
|
+
type: enum
|
|
737
|
+
label: "Status"
|
|
738
|
+
default: "pending"
|
|
739
|
+
enum_values:
|
|
740
|
+
- { value: pending, label: "Pending" }
|
|
741
|
+
- { value: in_progress, label: "In Progress" }
|
|
742
|
+
- { value: completed, label: "Completed" }
|
|
743
|
+
|
|
744
|
+
- name: due_date
|
|
745
|
+
type: date
|
|
746
|
+
label: "Due Date"
|
|
747
|
+
|
|
748
|
+
- name: notes
|
|
749
|
+
type: text
|
|
750
|
+
label: "Notes"
|
|
751
|
+
|
|
752
|
+
associations:
|
|
753
|
+
- type: belongs_to
|
|
754
|
+
name: task_list
|
|
755
|
+
target_model: task_list
|
|
756
|
+
required: true
|
|
757
|
+
|
|
758
|
+
scopes:
|
|
759
|
+
- name: active
|
|
760
|
+
where_not: { status: "completed" }
|
|
761
|
+
- name: completed
|
|
762
|
+
where: { status: "completed" }
|
|
763
|
+
|
|
764
|
+
events:
|
|
765
|
+
- name: on_status_change
|
|
766
|
+
type: field_change
|
|
767
|
+
field: status
|
|
768
|
+
|
|
769
|
+
options:
|
|
770
|
+
timestamps: true
|
|
771
|
+
label_method: title
|
|
772
|
+
```
|
|
773
|
+
</details>
|
|
774
|
+
|
|
775
|
+
## Second Presenter: Task
|
|
776
|
+
|
|
777
|
+
Create `config/lcp_ruby/presenters/task.rb`:
|
|
778
|
+
|
|
779
|
+
```ruby
|
|
780
|
+
define_presenter :task do
|
|
781
|
+
model :task
|
|
782
|
+
label "Tasks"
|
|
783
|
+
slug "tasks"
|
|
784
|
+
icon "check-square"
|
|
785
|
+
|
|
786
|
+
index do
|
|
787
|
+
default_sort :created_at, :desc
|
|
788
|
+
per_page 25
|
|
789
|
+
empty_message "No tasks yet. Create your first task to get started."
|
|
790
|
+
column :title, link_to: :show, sortable: true
|
|
791
|
+
column "task_list.title", label: "List", sortable: true
|
|
792
|
+
column :status, renderer: :badge, sortable: true
|
|
793
|
+
column :due_date, sortable: true
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
show do
|
|
797
|
+
section "Task Details", columns: 2 do
|
|
798
|
+
field :title, renderer: :heading
|
|
799
|
+
field :status, renderer: :badge
|
|
800
|
+
field "task_list.title", label: "List"
|
|
801
|
+
field :due_date
|
|
802
|
+
field :notes
|
|
803
|
+
end
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
form do
|
|
807
|
+
section "Task Details", columns: 2 do
|
|
808
|
+
field :title, placeholder: "What needs to be done?", autofocus: true
|
|
809
|
+
field :task_list_id, input_type: :association_select
|
|
810
|
+
field :status, input_type: :select
|
|
811
|
+
field :due_date, input_type: :date
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
section "Notes" do
|
|
815
|
+
field :notes, input_type: :textarea, placeholder: "Additional details..."
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
search do
|
|
820
|
+
searchable_fields :title
|
|
821
|
+
placeholder "Search tasks..."
|
|
822
|
+
filter :all, label: "All", default: true
|
|
823
|
+
filter :active, label: "Active", scope: :active
|
|
824
|
+
filter :completed, label: "Completed", scope: :completed
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
action :create, type: :built_in, on: :collection, label: "New Task", icon: "plus"
|
|
828
|
+
action :show, type: :built_in, on: :single, icon: "eye"
|
|
829
|
+
action :edit, type: :built_in, on: :single, icon: "pencil"
|
|
830
|
+
action :destroy, type: :built_in, on: :single, icon: "trash", confirm: true, style: :danger
|
|
831
|
+
end
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
Key concepts:
|
|
835
|
+
- **`"task_list.title"`** — dot-notation traverses the `belongs_to` association to display the related list's title
|
|
836
|
+
- **`label: "List"`** — overrides the auto-generated column header for dot-notation fields
|
|
837
|
+
- **`input_type: :association_select`** — renders a `<select>` dropdown populated from the target model's records (uses `label_method` for display text)
|
|
838
|
+
- **`renderer: :badge`** — renders enum values as colored badges
|
|
839
|
+
- **`filter`** — creates tabbed filters that apply named scopes from the model
|
|
840
|
+
|
|
841
|
+
<details>
|
|
842
|
+
<summary>YAML equivalent</summary>
|
|
843
|
+
|
|
844
|
+
```yaml
|
|
845
|
+
# config/lcp_ruby/presenters/task.yml
|
|
846
|
+
presenter:
|
|
847
|
+
name: task
|
|
848
|
+
model: task
|
|
849
|
+
label: "Tasks"
|
|
850
|
+
slug: tasks
|
|
851
|
+
icon: check-square
|
|
852
|
+
|
|
853
|
+
index:
|
|
854
|
+
default_sort: { field: created_at, direction: desc }
|
|
855
|
+
per_page: 25
|
|
856
|
+
empty_message: "No tasks yet. Create your first task to get started."
|
|
857
|
+
table_columns:
|
|
858
|
+
- { field: title, link_to: show, sortable: true }
|
|
859
|
+
- { field: "task_list.title", label: "List", sortable: true }
|
|
860
|
+
- { field: status, renderer: badge, sortable: true }
|
|
861
|
+
- { field: due_date, sortable: true }
|
|
862
|
+
|
|
863
|
+
show:
|
|
864
|
+
layout:
|
|
865
|
+
- section: "Task Details"
|
|
866
|
+
columns: 2
|
|
867
|
+
fields:
|
|
868
|
+
- { field: title, renderer: heading }
|
|
869
|
+
- { field: status, renderer: badge }
|
|
870
|
+
- { field: "task_list.title", label: "List" }
|
|
871
|
+
- { field: due_date }
|
|
872
|
+
- { field: notes }
|
|
873
|
+
|
|
874
|
+
form:
|
|
875
|
+
sections:
|
|
876
|
+
- title: "Task Details"
|
|
877
|
+
columns: 2
|
|
878
|
+
fields:
|
|
879
|
+
- { field: title, placeholder: "What needs to be done?", autofocus: true }
|
|
880
|
+
- { field: task_list_id, input_type: association_select }
|
|
881
|
+
- { field: status, input_type: select }
|
|
882
|
+
- { field: due_date, input_type: date }
|
|
883
|
+
- title: "Notes"
|
|
884
|
+
fields:
|
|
885
|
+
- { field: notes, input_type: textarea, placeholder: "Additional details..." }
|
|
886
|
+
|
|
887
|
+
search:
|
|
888
|
+
enabled: true
|
|
889
|
+
searchable_fields: [title]
|
|
890
|
+
placeholder: "Search tasks..."
|
|
891
|
+
predefined_filters:
|
|
892
|
+
- { name: all, label: "All", default: true }
|
|
893
|
+
- { name: active, label: "Active", scope: active }
|
|
894
|
+
- { name: completed, label: "Completed", scope: completed }
|
|
895
|
+
|
|
896
|
+
actions:
|
|
897
|
+
collection:
|
|
898
|
+
- { name: create, type: built_in, label: "New Task", icon: plus }
|
|
899
|
+
single:
|
|
900
|
+
- { name: show, type: built_in, icon: eye }
|
|
901
|
+
- { name: edit, type: built_in, icon: pencil }
|
|
902
|
+
- { name: destroy, type: built_in, icon: trash, confirm: true, style: danger }
|
|
903
|
+
```
|
|
904
|
+
</details>
|
|
905
|
+
|
|
906
|
+
## Second Permissions: Task
|
|
907
|
+
|
|
908
|
+
Create `config/lcp_ruby/permissions/task.yml`:
|
|
909
|
+
|
|
910
|
+
```yaml
|
|
911
|
+
permissions:
|
|
912
|
+
model: task
|
|
913
|
+
|
|
914
|
+
roles:
|
|
915
|
+
admin:
|
|
916
|
+
crud: [index, show, create, update, destroy]
|
|
917
|
+
fields: { readable: all, writable: all }
|
|
918
|
+
actions: all
|
|
919
|
+
scope: all
|
|
920
|
+
presenters: all
|
|
921
|
+
|
|
922
|
+
viewer:
|
|
923
|
+
crud: [index, show]
|
|
924
|
+
fields: { readable: all, writable: [] }
|
|
925
|
+
actions: { allowed: [] }
|
|
926
|
+
scope: all
|
|
927
|
+
presenters: all
|
|
928
|
+
|
|
929
|
+
default_role: admin
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
## Run and Verify: Associations
|
|
933
|
+
|
|
934
|
+
Restart the server (the database tables are created on boot when `auto_migrate` is enabled):
|
|
935
|
+
|
|
936
|
+
```bash
|
|
937
|
+
bundle exec rails server
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
Now you should see:
|
|
941
|
+
|
|
942
|
+
1. **Navigation** — both "Task Lists" and "Tasks" in the top menu
|
|
943
|
+
2. **Create a task list first** — go to Task Lists and create one (tasks need a list to belong to)
|
|
944
|
+
3. **Create a task** — go to Tasks, click "New Task"; the "Task list" dropdown shows your lists
|
|
945
|
+
4. **Dot-notation column** — the "List" column on the tasks index shows the related list's title
|
|
946
|
+
5. **Association list** — the task list show page displays its tasks below the detail section
|
|
947
|
+
6. **Filter tabs** — "All", "Active", and "Completed" tabs filter tasks by status scope
|
|
948
|
+
|
|
949
|
+
## Adding a Custom Action
|
|
950
|
+
|
|
951
|
+
Let's add a "Mark Completed" button that sets a task's status to `completed`.
|
|
952
|
+
|
|
953
|
+
### Step 1: Create the Action Class
|
|
954
|
+
|
|
955
|
+
Create `app/actions/task/mark_completed.rb`:
|
|
956
|
+
|
|
957
|
+
```ruby
|
|
958
|
+
module LcpRuby
|
|
959
|
+
module HostActions
|
|
960
|
+
module Task
|
|
961
|
+
class MarkCompleted < LcpRuby::Actions::BaseAction
|
|
962
|
+
def call
|
|
963
|
+
unless record
|
|
964
|
+
return failure(message: "No task specified")
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
if record.status == "completed"
|
|
968
|
+
return failure(message: "Task is already completed")
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
record.update!(status: "completed")
|
|
972
|
+
success(message: "Task '#{record.title}' marked as completed!")
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
end
|
|
976
|
+
end
|
|
977
|
+
end
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
The class is resolved by naming convention: `LcpRuby::HostActions::<Model>::<ActionName>`.
|
|
981
|
+
|
|
982
|
+
### Step 2: Add the Action to the Presenter
|
|
983
|
+
|
|
984
|
+
Update `config/lcp_ruby/presenters/task.rb` — add this action alongside the existing ones:
|
|
985
|
+
|
|
986
|
+
```ruby
|
|
987
|
+
action :mark_completed, type: :custom, on: :single,
|
|
988
|
+
label: "Mark Completed", icon: "check",
|
|
989
|
+
confirm: true, confirm_message: "Mark this task as completed?",
|
|
990
|
+
visible_when: { field: :status, operator: :not_eq, value: "completed" }
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
The `visible_when` condition hides the button when the task is already completed.
|
|
994
|
+
|
|
995
|
+
### Step 3: Add to Permissions
|
|
996
|
+
|
|
997
|
+
Update `config/lcp_ruby/permissions/task.yml` — change `actions: all` to an explicit list that includes `mark_completed`:
|
|
998
|
+
|
|
999
|
+
```yaml
|
|
1000
|
+
permissions:
|
|
1001
|
+
model: task
|
|
1002
|
+
|
|
1003
|
+
roles:
|
|
1004
|
+
admin:
|
|
1005
|
+
crud: [index, show, create, update, destroy]
|
|
1006
|
+
fields: { readable: all, writable: all }
|
|
1007
|
+
actions:
|
|
1008
|
+
allowed: [mark_completed]
|
|
1009
|
+
scope: all
|
|
1010
|
+
presenters: all
|
|
1011
|
+
|
|
1012
|
+
viewer:
|
|
1013
|
+
crud: [index, show]
|
|
1014
|
+
fields: { readable: all, writable: [] }
|
|
1015
|
+
actions: { allowed: [] }
|
|
1016
|
+
scope: all
|
|
1017
|
+
presenters: all
|
|
1018
|
+
|
|
1019
|
+
default_role: admin
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
### Step 4: Enable Auto-Discovery
|
|
1023
|
+
|
|
1024
|
+
Update `config/initializers/lcp_ruby.rb` to discover action and event handler classes:
|
|
1025
|
+
|
|
1026
|
+
```ruby
|
|
1027
|
+
LcpRuby.configure do |config|
|
|
1028
|
+
config.authentication = :none
|
|
1029
|
+
end
|
|
1030
|
+
|
|
1031
|
+
Rails.application.config.after_initialize do
|
|
1032
|
+
app_path = Rails.root.join("app")
|
|
1033
|
+
LcpRuby::Actions::ActionRegistry.discover!(app_path.to_s)
|
|
1034
|
+
LcpRuby::Events::HandlerRegistry.discover!(app_path.to_s)
|
|
1035
|
+
end
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
Restart the server. Tasks that are not yet completed now show a "Mark Completed" button on the show page and in the index row actions.
|
|
1039
|
+
|
|
1040
|
+
## Adding an Event Handler
|
|
1041
|
+
|
|
1042
|
+
The task model already declares `on_field_change :on_status_change, field: :status`. Let's create the handler that responds when a task's status changes.
|
|
1043
|
+
|
|
1044
|
+
Create `app/event_handlers/task/on_status_change.rb`:
|
|
1045
|
+
|
|
1046
|
+
```ruby
|
|
1047
|
+
module LcpRuby
|
|
1048
|
+
module HostEventHandlers
|
|
1049
|
+
module Task
|
|
1050
|
+
class OnStatusChange < LcpRuby::Events::HandlerBase
|
|
1051
|
+
def self.handles_event
|
|
1052
|
+
"on_status_change"
|
|
1053
|
+
end
|
|
1054
|
+
|
|
1055
|
+
def call
|
|
1056
|
+
old_status = old_value("status")
|
|
1057
|
+
new_status = new_value("status")
|
|
1058
|
+
Rails.logger.info(
|
|
1059
|
+
"[TODO] Task '#{record.title}' status changed: #{old_status} -> #{new_status}"
|
|
1060
|
+
)
|
|
1061
|
+
end
|
|
1062
|
+
end
|
|
1063
|
+
end
|
|
1064
|
+
end
|
|
1065
|
+
end
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
Key concepts:
|
|
1069
|
+
- **`self.handles_event`** — returns the event name string matching the model's `on_field_change` declaration
|
|
1070
|
+
- **`old_value` / `new_value`** — access the previous and current field values
|
|
1071
|
+
- **`record`** — the affected ActiveRecord instance
|
|
1072
|
+
- Auto-discovered via `HandlerRegistry.discover!` (added in the previous step)
|
|
1073
|
+
|
|
1074
|
+
The class is resolved by convention: `LcpRuby::HostEventHandlers::<Model>::<HandlerName>`.
|
|
1075
|
+
|
|
1076
|
+
Restart the server, then change a task's status. Check the Rails log to see the event handler output.
|
|
1077
|
+
|
|
1078
|
+
## Dev Workflow
|
|
1079
|
+
|
|
1080
|
+
LCP integrates with Rails' standard development reloader so most metadata edits take effect on the next request — no `pkill puma`, no restart. The exact "what reloads when" is:
|
|
1081
|
+
|
|
1082
|
+
| You edit… | What happens on next request |
|
|
1083
|
+
|---|---|
|
|
1084
|
+
| YAML / DSL Ruby files under `config/lcp_ruby/` | Auto-reload via `Engine.reload!` (registries cleared, dynamic models rebuilt, `LcpRuby.on_models_loaded` callbacks re-fire) |
|
|
1085
|
+
| Ruby files under `app/` (controllers, host actions, host services, custom renderers) | Zeitwerk's standard reload (class redefinition) |
|
|
1086
|
+
| Locale files under `config/locales/` | Rails' i18n reloader |
|
|
1087
|
+
| Initializer files under `config/initializers/` | Requires server restart (Rails initializer chain runs once) |
|
|
1088
|
+
| Gem updates / `Gemfile.lock` changes | Requires server restart |
|
|
1089
|
+
| `LcpRuby.configuration.*` settings | Requires server restart (read once at boot) |
|
|
1090
|
+
|
|
1091
|
+
**Important asymmetry.** Editing only an `app/`-side host file (e.g. a custom action class) reloads the **class** via Zeitwerk, but the LCP registry that holds a reference to the old class is not refreshed until the next YAML edit or manual `LcpRuby::Engine.reload!`. If you find a host action change isn't taking effect, touching any YAML file under `config/lcp_ruby/` (or simply restarting) forces the registry to rebuild.
|
|
1092
|
+
|
|
1093
|
+
**Manual reload.** From the Rails console: `LcpRuby::Engine.reload!`. Useful when you've changed a `LcpRuby.configuration.*` field or want to force a refresh without editing a watched file.
|
|
1094
|
+
|
|
1095
|
+
**Subscribing to reload events.** `ActiveSupport::Notifications` emits `boot.lcp_ruby` on every `load_metadata!` and `reload.lcp_ruby` on every successful reload. See [`docs/reference/boot_lifecycle.md`](reference/boot_lifecycle.md) § Instrumentation.
|
|
1096
|
+
|
|
1097
|
+
The full lifecycle (boot phases, hook ordering, the watcher's glob form) is documented in [`docs/reference/boot_lifecycle.md`](reference/boot_lifecycle.md).
|
|
1098
|
+
|
|
1099
|
+
## Resetting the Database
|
|
1100
|
+
|
|
1101
|
+
LCP-managed tables are created by the platform's `SchemaManager` from your YAML/DSL model definitions — they do **not** live in `db/migrate/`. The standard Rails db lifecycle commands are wired to materialise these tables alongside Rails' own migrations:
|
|
1102
|
+
|
|
1103
|
+
| Command | Behaviour |
|
|
1104
|
+
|---|---|
|
|
1105
|
+
| `rails db:prepare` | Creates DB if missing, runs Rails migrations, then runs `lcp_ruby:ensure_tables` (post-action) so platform tables exist |
|
|
1106
|
+
| `rails db:setup` | Same as `db:prepare` for a fresh DB; also seeds |
|
|
1107
|
+
| `rails db:reset` | Drops + recreates DB via `db:setup`; inherits the platform-table fix transitively |
|
|
1108
|
+
| `rails db:drop db:prepare db:seed` | Works in one process — `lcp_ruby:ensure_tables` recreates platform tables before seeds run |
|
|
1109
|
+
| `rake lcp_ruby:ensure_tables` | Standalone task; idempotent. Runs automatically as a post-action of `db:prepare` / `db:setup`, but you can invoke it directly when needed |
|
|
1110
|
+
|
|
1111
|
+
**`db:reset` vs `db:prepare`.** Use either — both work after this change. Prior to v1 of the boot/reload lifecycle work, `db:reset` would silently leave platform tables un-created; this is no longer the case.
|
|
1112
|
+
|
|
1113
|
+
**`db:migrate`.** Runs Rails migrations only. Does **not** touch platform tables — those are managed by `SchemaManager` at boot. If you need only platform tables refreshed (rare), invoke `rake lcp_ruby:ensure_tables` directly.
|
|
1114
|
+
|
|
1115
|
+
**Adding a new model.** No migration required: define the YAML/DSL, save the file, and on the next request the dev watcher reloads metadata and `SchemaManager` adds the new table. The `auto_migrate: true` configuration default makes this work without explicit action.
|
|
1116
|
+
|
|
1117
|
+
**Removing a model.** Drop the YAML/DSL file. The platform stops registering the model on the next reload, but the **table itself is not dropped automatically** (data preservation is the safer default). To drop the table manually:
|
|
1118
|
+
|
|
1119
|
+
```ruby
|
|
1120
|
+
ActiveRecord::Base.connection.drop_table("legacy_things")
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
## Troubleshooting
|
|
1124
|
+
|
|
1125
|
+
| Problem | Cause | Solution |
|
|
1126
|
+
|---------|-------|----------|
|
|
1127
|
+
| `NoMethodError: undefined method 'lcp_role'` | User model missing role method | Add `lcp_role` method to your User model or use `authentication: :none` |
|
|
1128
|
+
| `MetadataError: Duplicate model` | Same model defined in both `.rb` and `.yml` | Use one format per model |
|
|
1129
|
+
| Action class not found | Not auto-discovered | Add `ActionRegistry.discover!` to your initializer |
|
|
1130
|
+
| Table not created (after `db:reset` or `db:drop db:prepare`) | Pre-v1 behaviour where Rails db tasks skipped `SchemaManager` | Fixed — `db:prepare` and `db:setup` now invoke `lcp_ruby:ensure_tables` automatically. If you've custom-overridden these tasks, ensure they still run the post-action |
|
|
1131
|
+
| Permission YAML edit not taking effect | Old: caches survived dev reload | Fixed — dev watcher reloads on any change under `config/lcp_ruby/`. If a change still doesn't apply, see [Dev Workflow](#dev-workflow) for what reloads vs. requires restart |
|
|
1132
|
+
| `Duplicate presenter '<name>'` after dev reload | Pre-v1 behaviour where reload re-ran loader on populated registries | Fixed — `Engine.reload!` now resets cleanly. Stop and restart the server once after upgrading; subsequent reloads work |
|
|
1133
|
+
| Host action / event handler change not visible | Zeitwerk reloaded the class but LCP registry holds old reference | Touch any YAML file under `config/lcp_ruby/` to force a reload, or run `LcpRuby::Engine.reload!` in the console |
|
|
1134
|
+
| Association select is empty | No records exist in the target model | Create target records first (e.g., create a task list before a task) |
|
|
1135
|
+
| `Pundit::NotAuthorizedError` | Missing permissions file for the model | Create a permissions YAML file or a `_default.yml` fallback |
|
|
1136
|
+
| Custom action button not visible | `visible_when` hides it or action not in `actions.allowed` | Check both presenter `visible_when` conditions and permissions `actions.allowed` |
|
|
1137
|
+
| Search returns no results | Field not included in `searchable_fields` | Add the field to the `search` block's `searchable_fields` |
|
|
1138
|
+
| Event handler not firing | Event not declared in model or handler not discovered | Verify `on_field_change` in model DSL, `handles_event` return value matches the event name, and `HandlerRegistry.discover!` in initializer |
|
|
1139
|
+
|
|
1140
|
+
## Seed Data
|
|
1141
|
+
|
|
1142
|
+
To populate the database with initial records in `db/seeds.rb`, you must load metadata first — otherwise the dynamic model classes do not exist yet:
|
|
1143
|
+
|
|
1144
|
+
```ruby
|
|
1145
|
+
# db/seeds.rb
|
|
1146
|
+
|
|
1147
|
+
# Required: load metadata before accessing dynamic models.
|
|
1148
|
+
# On normal boot this happens automatically, but seeds may run
|
|
1149
|
+
# before the initializer — call explicitly to be safe.
|
|
1150
|
+
LcpRuby::Engine.load_metadata!
|
|
1151
|
+
|
|
1152
|
+
# Access dynamic model classes via registry:
|
|
1153
|
+
TaskList = LcpRuby.registry.model_for("task_list")
|
|
1154
|
+
Task = LcpRuby.registry.model_for("task")
|
|
1155
|
+
|
|
1156
|
+
# Create records as usual:
|
|
1157
|
+
inbox = TaskList.create!(title: "Inbox")
|
|
1158
|
+
Task.create!(title: "Buy milk", task_list: inbox)
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
Key points:
|
|
1162
|
+
- `load_metadata!` is idempotent — safe to call even if already loaded
|
|
1163
|
+
- `model_for` returns the dynamic ActiveRecord class (e.g., `LcpRuby::Dynamic::TaskList`)
|
|
1164
|
+
- Assigning to a constant is optional but convenient for readability
|
|
1165
|
+
|
|
1166
|
+
## Next Steps
|
|
1167
|
+
|
|
1168
|
+
- [Host Application Guide](guides/host-application.md) — Full app bootstrap, optional dependencies (XLSX, charts, metrics), available feature generators
|
|
1169
|
+
- [Models Reference](reference/models.md) — All field types, validations, associations, scopes, and events
|
|
1170
|
+
- [Model DSL Reference](reference/model-dsl.md) — Full Ruby DSL syntax for models
|
|
1171
|
+
- [Presenters Reference](reference/presenters.md) — All index, show, form, search, and action options
|
|
1172
|
+
- [Presenter DSL Reference](reference/presenter-dsl.md) — Full Ruby DSL syntax for presenters (with inheritance)
|
|
1173
|
+
- [Permissions Reference](reference/permissions.md) — Field overrides, record rules, scope types
|
|
1174
|
+
- [Types Reference](reference/types.md) — Business types (email, phone, url, color) and custom types
|
|
1175
|
+
- [Custom Types Guide](guides/custom-types.md) — Practical custom type examples
|
|
1176
|
+
- [Attachments Guide](guides/attachments.md) — File upload with Active Storage
|
|
1177
|
+
- [Custom Actions](guides/custom-actions.md) — Advanced action patterns
|
|
1178
|
+
- [Event Handlers](guides/event-handlers.md) — Async handlers, lifecycle events
|
|
1179
|
+
- [Conditional Rendering](guides/conditional-rendering.md) — `visible_when` and `disable_when` on fields, sections, and actions
|
|
1180
|
+
- [Extensibility Guide](guides/extensibility.md) — Transforms, validators, defaults, computed fields, condition services
|
|
1181
|
+
- [View Groups Guide](guides/view-groups.md) — Multi-view navigation and view switcher
|
|
1182
|
+
- [i18n Reference](reference/i18n.md) — Translating model names, field labels, enums, menu items, and UI strings
|
|
1183
|
+
- [Menu Guide](guides/menu.md) — Custom navigation menus
|
|
1184
|
+
- [Custom Fields Guide](guides/custom-fields.md) — Runtime user-defined fields
|
|
1185
|
+
- [Developer Tools](guides/developer-tools.md) — Validate configuration, generate ERD diagrams, inspect permissions
|
|
1186
|
+
- [Engine Configuration](reference/engine-configuration.md) — All `LcpRuby.configure` options
|
|
1187
|
+
- [Example Apps](examples.md) — Complete TODO and CRM walkthroughs
|