open-loam 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +148 -8
- data/LICENSE +1 -1
- data/README.md +27 -25
- data/app/jobs/{loam → open_loam}/custom_field_reindex_job.rb +6 -6
- data/app/jobs/{loam → open_loam}/event_delivery_job.rb +8 -8
- data/app/jobs/open_loam/event_log_prune_job.rb +15 -0
- data/app/jobs/{loam → open_loam}/event_redelivery_sweep_job.rb +4 -4
- data/app/jobs/{loam → open_loam}/webhook_delivery_job.rb +17 -8
- data/app/models/open_loam/api_token.rb +63 -0
- data/app/models/{loam → open_loam}/audit_record.rb +3 -3
- data/app/models/{loam → open_loam}/auth_attempt.rb +5 -5
- data/app/models/{loam → open_loam}/business_rule.rb +10 -10
- data/app/models/{loam → open_loam}/business_rule_run.rb +5 -5
- data/app/models/{loam → open_loam}/comment.rb +9 -9
- data/app/models/{loam → open_loam}/config.rb +7 -7
- data/app/models/{loam → open_loam}/custom_field_value.rb +5 -5
- data/app/models/{loam → open_loam}/dashboard_widget.rb +5 -5
- data/app/models/open_loam/dictionary.rb +20 -0
- data/app/models/{loam → open_loam}/dictionary_entry.rb +7 -7
- data/app/models/{loam → open_loam}/event_delivery.rb +4 -4
- data/app/models/open_loam/event_record.rb +42 -0
- data/app/models/{loam → open_loam}/field_definition.rb +8 -8
- data/app/models/{loam → open_loam}/inbound_webhook_delivery.rb +4 -4
- data/app/models/{loam → open_loam}/inbound_webhook_source.rb +13 -13
- data/app/models/{loam → open_loam}/membership.rb +6 -6
- data/app/models/{loam → open_loam}/mfa_credential.rb +8 -8
- data/app/models/{loam → open_loam}/notification.rb +10 -10
- data/app/models/{loam → open_loam}/pending_action.rb +70 -26
- data/app/models/{loam → open_loam}/perspective.rb +5 -5
- data/app/models/{loam → open_loam}/progress_job.rb +7 -7
- data/app/models/{loam → open_loam}/record_lock.rb +5 -5
- data/app/models/{loam → open_loam}/scheduled_job.rb +7 -7
- data/app/models/open_loam/search_token.rb +9 -0
- data/app/models/{loam → open_loam}/sso_identity.rb +4 -4
- data/app/models/open_loam/sso_provider.rb +66 -0
- data/app/models/open_loam/tenant.rb +20 -0
- data/app/models/{loam → open_loam}/translation.rb +5 -5
- data/app/models/open_loam/webhook_endpoint.rb +39 -0
- data/app/views/{loam → open_loam}/attachments/_attachments.html.erb +1 -1
- data/app/views/{loam → open_loam}/comments/_comments.html.erb +1 -1
- data/app/views/{loam → open_loam}/custom_fields/_fields.html.erb +6 -2
- data/lib/generators/{loam → open_loam}/entity/entity_generator.rb +9 -9
- data/lib/generators/{loam → open_loam}/entity/templates/api_controller.rb +2 -1
- data/lib/generators/{loam → open_loam}/entity/templates/controller.rb +32 -22
- data/lib/generators/{loam → open_loam}/entity/templates/entity_test.rb +12 -12
- data/lib/generators/{loam → open_loam}/entity/templates/migration.rb +5 -5
- data/lib/generators/{loam → open_loam}/entity/templates/model.rb +10 -10
- data/lib/generators/{loam → open_loam}/entity/templates/policy.rb +1 -1
- data/lib/generators/{loam → open_loam}/entity/templates/views/_form.html.erb +8 -5
- data/lib/generators/{loam → open_loam}/entity/templates/views/deleted.html.erb +7 -7
- data/lib/generators/open_loam/entity/templates/views/edit.html.erb +3 -0
- data/lib/generators/open_loam/entity/templates/views/index.html.erb +94 -0
- data/lib/generators/open_loam/entity/templates/views/new.html.erb +3 -0
- data/lib/generators/open_loam/entity/templates/views/show.html.erb +38 -0
- data/lib/generators/{loam → open_loam}/install/install_generator.rb +58 -47
- data/lib/generators/open_loam/install/templates/AGENTS.md +345 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_controller.rb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_index.html.erb +1 -1
- data/lib/generators/open_loam/install/templates/admin/api_tokens_controller.rb +48 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/api_tokens_index.html.erb +23 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/base_controller.rb +101 -38
- data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_form.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/comments_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/admin/configs_controller.rb +9 -9
- data/lib/generators/open_loam/install/templates/admin/dashboard_controller.rb +12 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_form.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/dictionary_entries_controller.rb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/events_controller.rb +7 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/features_controller.rb +9 -9
- data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_controller.rb +5 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_new.html.erb +2 -2
- data/lib/generators/open_loam/install/templates/admin/history_controller.rb +64 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/history_index.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/imports_controller.rb +25 -13
- data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_new.html.erb +2 -4
- data/lib/generators/open_loam/install/templates/admin/layout.html.erb +76 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_controller.rb +11 -6
- data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_controller.rb +5 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_controller.rb +3 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_index.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_controller.rb +3 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_controller.rb +13 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_index.html.erb +1 -1
- data/lib/generators/open_loam/install/templates/admin/progress_jobs_controller.rb +23 -0
- data/lib/generators/{loam → open_loam}/install/templates/admin/progress_jobs_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/record_locks_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_form.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/search_controller.rb +7 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_controller.rb +33 -34
- data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_controller.rb +6 -6
- data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_form.html.erb +2 -2
- data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_index.html.erb +8 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_controller.rb +7 -5
- data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_new.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin/translations_controller.rb +7 -7
- data/lib/generators/{loam → open_loam}/install/templates/admin/translations_index.html.erb +3 -3
- data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_index.html.erb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/admin.css +1 -1
- data/lib/generators/open_loam/install/templates/api_base_controller.rb +127 -0
- data/lib/generators/{loam → open_loam}/install/templates/guardrails_test.rb +17 -17
- data/lib/generators/open_loam/install/templates/import_job.rb +38 -0
- data/lib/generators/{loam → open_loam}/install/templates/inbound_webhooks_controller.rb +4 -4
- data/lib/generators/{loam → open_loam}/install/templates/initializer.rb +87 -75
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_api_tokens.rb +15 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_audit_records.rb +14 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_auth_attempts.rb → open_loam/install/templates/migrations/create_open_loam_auth_attempts.rb} +3 -3
- data/lib/generators/{loam/install/templates/migrations/create_loam_business_rules.rb → open_loam/install/templates/migrations/create_open_loam_business_rules.rb} +10 -10
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_comments.rb +13 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_configs.rb → open_loam/install/templates/migrations/create_open_loam_configs.rb} +7 -7
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_custom_field_values.rb +19 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dashboard_widgets.rb +12 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dictionaries.rb +11 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_dictionary_entries.rb → open_loam/install/templates/migrations/create_open_loam_dictionary_entries.rb} +6 -6
- data/lib/generators/{loam/install/templates/migrations/create_loam_event_deliveries.rb → open_loam/install/templates/migrations/create_open_loam_event_deliveries.rb} +5 -5
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_event_records.rb +13 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_field_definitions.rb → open_loam/install/templates/migrations/create_open_loam_field_definitions.rb} +4 -4
- data/lib/generators/{loam/install/templates/migrations/create_loam_inbound_webhooks.rb → open_loam/install/templates/migrations/create_open_loam_inbound_webhooks.rb} +9 -10
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_memberships.rb +11 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_mfa_credentials.rb → open_loam/install/templates/migrations/create_open_loam_mfa_credentials.rb} +4 -4
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_notifications.rb +15 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_pending_actions.rb → open_loam/install/templates/migrations/create_open_loam_pending_actions.rb} +9 -9
- data/lib/generators/{loam/install/templates/migrations/create_loam_perspectives.rb → open_loam/install/templates/migrations/create_open_loam_perspectives.rb} +5 -5
- data/lib/generators/{loam/install/templates/migrations/create_loam_progress_jobs.rb → open_loam/install/templates/migrations/create_open_loam_progress_jobs.rb} +5 -5
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_record_locks.rb +16 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_scheduled_jobs.rb → open_loam/install/templates/migrations/create_open_loam_scheduled_jobs.rb} +5 -5
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_search_tokens.rb +18 -0
- data/lib/generators/{loam/install/templates/migrations/create_loam_sso_providers.rb → open_loam/install/templates/migrations/create_open_loam_sso_providers.rb} +15 -12
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_tenants.rb +9 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_translations.rb +15 -0
- data/lib/generators/open_loam/install/templates/migrations/create_open_loam_webhook_endpoints.rb +13 -0
- data/lib/generators/{loam → open_loam}/install/templates/migrations/create_users.rb +1 -1
- data/lib/generators/{loam → open_loam}/install/templates/user.rb +5 -5
- data/lib/generators/{loam → open_loam}/primary_key_options.rb +23 -23
- data/lib/open-loam.rb +2 -2
- data/lib/{loam → open_loam}/attachable.rb +4 -4
- data/lib/{loam → open_loam}/auditable.rb +23 -23
- data/lib/{loam → open_loam}/auth_throttle.rb +20 -12
- data/lib/{loam → open_loam}/base32.rb +1 -1
- data/lib/{loam → open_loam}/bulk.rb +7 -7
- data/lib/{loam → open_loam}/business_rules/actions.rb +7 -7
- data/lib/{loam → open_loam}/business_rules/condition.rb +5 -5
- data/lib/{loam → open_loam}/business_rules.rb +19 -19
- data/lib/{loam → open_loam}/commentable.rb +6 -6
- data/lib/{loam → open_loam}/configs.rb +19 -19
- data/lib/{loam → open_loam}/cron.rb +2 -2
- data/lib/{loam → open_loam}/csv.rb +2 -2
- data/lib/{loam → open_loam}/current.rb +5 -5
- data/lib/{loam → open_loam}/custom_field_index.rb +33 -30
- data/lib/{loam → open_loam}/custom_fields.rb +17 -17
- data/lib/{loam → open_loam}/dashboard.rb +5 -5
- data/lib/{loam → open_loam}/dictionaries.rb +12 -12
- data/lib/{loam → open_loam}/durable_events.rb +19 -19
- data/lib/{loam → open_loam}/encryptable.rb +39 -34
- data/lib/{loam → open_loam}/encryption/cipher.rb +3 -3
- data/lib/{loam → open_loam}/encryption/key_provider.rb +19 -3
- data/lib/{loam → open_loam}/encryption.rb +58 -15
- data/lib/open_loam/engine.rb +65 -0
- data/lib/{loam → open_loam}/enrichers.rb +5 -5
- data/lib/{loam → open_loam}/errors.rb +20 -10
- data/lib/{loam → open_loam}/eval.rb +2 -2
- data/lib/open_loam/event_log.rb +77 -0
- data/lib/{loam → open_loam}/event_stream.rb +14 -14
- data/lib/{loam → open_loam}/eventful.rb +12 -12
- data/lib/{loam → open_loam}/events.rb +5 -5
- data/lib/{loam → open_loam}/export.rb +12 -12
- data/lib/{loam → open_loam}/features.rb +15 -15
- data/lib/{loam → open_loam}/generated_key.rb +6 -6
- data/lib/{loam → open_loam}/import.rb +12 -15
- data/lib/{loam → open_loam}/inbound_webhooks.rb +19 -18
- data/lib/{loam → open_loam}/lifecycle.rb +54 -25
- data/lib/{loam/locales/loam.en.yml → open_loam/locales/open_loam.en.yml} +5 -5
- data/lib/{loam → open_loam}/mcp/server.rb +9 -9
- data/lib/{loam → open_loam}/mcp.rb +31 -22
- data/lib/{loam → open_loam}/notifications.rb +5 -5
- data/lib/{loam → open_loam}/open_api.rb +16 -16
- data/lib/open_loam/outbound_url.rb +100 -0
- data/lib/{loam → open_loam}/overrides.rb +10 -10
- data/lib/{loam → open_loam}/pending_actions.rb +9 -9
- data/lib/{loam → open_loam}/permissions.rb +8 -8
- data/lib/{loam → open_loam}/perspectives.rb +9 -9
- data/lib/{loam → open_loam}/policy.rb +21 -8
- data/lib/{loam → open_loam}/progress.rb +6 -6
- data/lib/{loam → open_loam}/record_locks.rb +9 -9
- data/lib/{loam → open_loam}/scheduler.rb +20 -20
- data/lib/{loam → open_loam}/search/driver.rb +3 -3
- data/lib/{loam → open_loam}/search/like_driver.rb +5 -5
- data/lib/{loam → open_loam}/search/token_driver.rb +16 -16
- data/lib/{loam → open_loam}/search.rb +5 -5
- data/lib/{loam → open_loam}/searchable.rb +22 -22
- data/lib/{loam → open_loam}/soft_deletable.rb +10 -10
- data/lib/{loam → open_loam}/sso/claims.rb +1 -1
- data/lib/{loam → open_loam}/sso/fake_provider.rb +1 -1
- data/lib/open_loam/sso/http_client.rb +51 -0
- data/lib/{loam → open_loam}/sso/oidc_provider.rb +2 -2
- data/lib/{loam → open_loam}/sso.rb +39 -18
- data/lib/{loam → open_loam}/telemetry.rb +6 -6
- data/lib/{loam → open_loam}/tenant_record.rb +10 -10
- data/lib/{loam → open_loam}/test_helpers.rb +4 -4
- data/lib/{loam → open_loam}/totp.rb +3 -3
- data/lib/{loam → open_loam}/translatable.rb +24 -24
- data/lib/{loam → open_loam}/undo.rb +11 -11
- data/lib/open_loam/version.rb +3 -0
- data/lib/{loam → open_loam}/webhooks.rb +4 -4
- data/lib/{loam → open_loam}/widgets.rb +9 -9
- data/lib/{loam → open_loam}/workflow.rb +45 -45
- data/lib/open_loam.rb +124 -0
- data/lib/tasks/open_loam.rake +203 -0
- data/lib/tasks/{loam_eval.rake → open_loam_eval.rake} +7 -7
- data/lib/tasks/open_loam_mcp.rake +20 -0
- metadata +247 -242
- data/app/models/loam/api_token.rb +0 -40
- data/app/models/loam/dictionary.rb +0 -20
- data/app/models/loam/search_token.rb +0 -9
- data/app/models/loam/sso_provider.rb +0 -35
- data/app/models/loam/tenant.rb +0 -20
- data/app/models/loam/webhook_endpoint.rb +0 -26
- data/lib/generators/loam/entity/templates/views/edit.html.erb +0 -3
- data/lib/generators/loam/entity/templates/views/index.html.erb +0 -90
- data/lib/generators/loam/entity/templates/views/new.html.erb +0 -3
- data/lib/generators/loam/entity/templates/views/show.html.erb +0 -36
- data/lib/generators/loam/install/templates/AGENTS.md +0 -341
- data/lib/generators/loam/install/templates/admin/api_tokens_controller.rb +0 -30
- data/lib/generators/loam/install/templates/admin/dashboard_controller.rb +0 -10
- data/lib/generators/loam/install/templates/admin/history_controller.rb +0 -38
- data/lib/generators/loam/install/templates/admin/layout.html.erb +0 -76
- data/lib/generators/loam/install/templates/admin/progress_jobs_controller.rb +0 -19
- data/lib/generators/loam/install/templates/api_base_controller.rb +0 -90
- data/lib/generators/loam/install/templates/import_job.rb +0 -25
- data/lib/generators/loam/install/templates/migrations/create_loam_api_tokens.rb +0 -15
- data/lib/generators/loam/install/templates/migrations/create_loam_audit_records.rb +0 -14
- data/lib/generators/loam/install/templates/migrations/create_loam_comments.rb +0 -13
- data/lib/generators/loam/install/templates/migrations/create_loam_custom_field_values.rb +0 -19
- data/lib/generators/loam/install/templates/migrations/create_loam_dashboard_widgets.rb +0 -12
- data/lib/generators/loam/install/templates/migrations/create_loam_dictionaries.rb +0 -11
- data/lib/generators/loam/install/templates/migrations/create_loam_memberships.rb +0 -11
- data/lib/generators/loam/install/templates/migrations/create_loam_notifications.rb +0 -15
- data/lib/generators/loam/install/templates/migrations/create_loam_record_locks.rb +0 -16
- data/lib/generators/loam/install/templates/migrations/create_loam_search_tokens.rb +0 -18
- data/lib/generators/loam/install/templates/migrations/create_loam_tenants.rb +0 -9
- data/lib/generators/loam/install/templates/migrations/create_loam_translations.rb +0 -15
- data/lib/generators/loam/install/templates/migrations/create_loam_webhook_endpoints.rb +0 -13
- data/lib/loam/engine.rb +0 -57
- data/lib/loam/sso/http_client.rb +0 -42
- data/lib/loam/version.rb +0 -3
- data/lib/loam.rb +0 -122
- data/lib/tasks/loam.rake +0 -171
- data/lib/tasks/loam_mcp.rake +0 -20
- /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/features_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_preview.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_summary.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_activated.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_show.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/pagination.rb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/search_index.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_mfa_challenge.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_edit.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_new.html.erb +0 -0
- /data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_new.html.erb +0 -0
|
@@ -15,34 +15,39 @@ module Admin
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def index
|
|
18
|
-
|
|
19
|
-
@
|
|
18
|
+
authorize!(policy_for(<%= class_name %>.new), :read?)
|
|
19
|
+
@perspective = OpenLoam::Perspectives.resolve("<%= class_name %>", user: current_actor, id: params[:perspective_id])
|
|
20
|
+
@perspectives = OpenLoam::Perspectives.visible_to("<%= class_name %>", user: current_actor)
|
|
20
21
|
@records, @page, @has_next = paginate(index_scope)
|
|
21
|
-
@index_partial = params[:cf_field].present? &&
|
|
22
|
+
@index_partial = params[:cf_field].present? && OpenLoam::CustomFieldIndex.partial? # incomplete-index warning (L-919)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
# CSV of the CURRENT filtered/perspective view — manager-only, policy- and
|
|
25
|
-
# encryption-aware (
|
|
26
|
+
# encryption-aware (OpenLoam::Export).
|
|
26
27
|
def export
|
|
27
28
|
require_role!(:manager)
|
|
28
|
-
send_data
|
|
29
|
+
send_data OpenLoam::Export.csv(index_scope, actor: current_actor),
|
|
29
30
|
filename: "<%= plural_name %>-#{Date.current}.csv", type: "text/csv"
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
# Datatable bulk actions on the selected ids — each is policy-checked per
|
|
33
|
-
# record and tenant-scoped (
|
|
34
|
+
# record and tenant-scoped (OpenLoam::Bulk). Zero selection is a no-op.
|
|
34
35
|
def bulk
|
|
36
|
+
# OpenLoam::Bulk checks the policy PER record (destroy? for soft_delete,
|
|
37
|
+
# update? + writable? for set_field) and silently skips what the actor may
|
|
38
|
+
# not touch, so the authorization is real — it just lives there, not here.
|
|
39
|
+
authorized!
|
|
35
40
|
ids = Array(params[:ids])
|
|
36
41
|
case params[:bulk_action]
|
|
37
42
|
when "soft_delete"
|
|
38
|
-
count =
|
|
43
|
+
count = OpenLoam::Bulk.soft_delete(<%= class_name %>, ids)
|
|
39
44
|
redirect_to polymorphic_path([:admin, <%= class_name %>]), notice: "Deleted #{count} record(s)."
|
|
40
45
|
when "set_field"
|
|
41
|
-
count =
|
|
46
|
+
count = OpenLoam::Bulk.set_field(<%= class_name %>, ids, field: params[:field], value: params[:value])
|
|
42
47
|
redirect_to polymorphic_path([:admin, <%= class_name %>]), notice: "Updated #{count} record(s)."
|
|
43
48
|
when "export"
|
|
44
49
|
require_role!(:manager) # same gate as the dedicated export action
|
|
45
|
-
send_data
|
|
50
|
+
send_data OpenLoam::Export.csv(OpenLoam::Bulk.selected(<%= class_name %>, ids), actor: current_actor),
|
|
46
51
|
filename: "<%= plural_name %>-selected.csv", type: "text/csv"
|
|
47
52
|
else
|
|
48
53
|
redirect_to polymorphic_path([:admin, <%= class_name %>]), alert: "Unknown bulk action."
|
|
@@ -75,7 +80,7 @@ module Admin
|
|
|
75
80
|
attach_files!(@record, policy)
|
|
76
81
|
|
|
77
82
|
if @record.save
|
|
78
|
-
redirect_to [:admin, @record], notice: t("
|
|
83
|
+
redirect_to [:admin, @record], notice: t("open_loam.flash.created", name: <%= class_name %>.model_name.human)
|
|
79
84
|
else
|
|
80
85
|
render :new, status: :unprocessable_entity
|
|
81
86
|
end
|
|
@@ -84,7 +89,7 @@ module Admin
|
|
|
84
89
|
def edit
|
|
85
90
|
authorize!(policy_for(@record), :update?)
|
|
86
91
|
# Take the advisory lock (courtesy) or learn who holds it, for the banner.
|
|
87
|
-
@lock =
|
|
92
|
+
@lock = OpenLoam::RecordLocks.acquire(@record, by: current_actor) || OpenLoam::RecordLocks.active_lock(@record)
|
|
88
93
|
end
|
|
89
94
|
|
|
90
95
|
def update
|
|
@@ -94,15 +99,15 @@ module Admin
|
|
|
94
99
|
attach_files!(@record, policy)
|
|
95
100
|
|
|
96
101
|
if @record.update(permitted_params(policy))
|
|
97
|
-
|
|
98
|
-
redirect_to [:admin, @record], notice: t("
|
|
102
|
+
OpenLoam::RecordLocks.release(@record, by: current_actor)
|
|
103
|
+
redirect_to [:admin, @record], notice: t("open_loam.flash.updated", name: <%= class_name %>.model_name.human)
|
|
99
104
|
else
|
|
100
105
|
render :edit, status: :unprocessable_entity
|
|
101
106
|
end
|
|
102
107
|
rescue ActiveRecord::StaleObjectError
|
|
103
108
|
# Someone saved between open and submit — show the diff, reload fresh, retry.
|
|
104
109
|
stale_conflict!(@record, FIELDS)
|
|
105
|
-
@lock =
|
|
110
|
+
@lock = OpenLoam::RecordLocks.acquire(@record, by: current_actor) || OpenLoam::RecordLocks.active_lock(@record)
|
|
106
111
|
render :edit, status: :conflict
|
|
107
112
|
end
|
|
108
113
|
|
|
@@ -111,8 +116,8 @@ module Admin
|
|
|
111
116
|
def destroy
|
|
112
117
|
authorize!(policy_for(@record), :destroy?)
|
|
113
118
|
@record.soft_delete!
|
|
114
|
-
|
|
115
|
-
redirect_to [:admin, <%= class_name %>], notice: t("
|
|
119
|
+
OpenLoam::RecordLocks.release(@record, by: current_actor)
|
|
120
|
+
redirect_to [:admin, <%= class_name %>], notice: t("open_loam.flash.destroyed", name: <%= class_name %>.model_name.human)
|
|
116
121
|
end
|
|
117
122
|
|
|
118
123
|
# Restore looks through the deleted rows — the default scope hides them, so a
|
|
@@ -121,7 +126,7 @@ module Admin
|
|
|
121
126
|
@record = <%= class_name %>.with_deleted.find(params[:id])
|
|
122
127
|
authorize!(policy_for(@record), :update?)
|
|
123
128
|
@record.restore!
|
|
124
|
-
redirect_to [:deleted, :admin, <%= class_name %>], notice: t("
|
|
129
|
+
redirect_to [:deleted, :admin, <%= class_name %>], notice: t("open_loam.flash.restored", name: <%= class_name %>.model_name.human)
|
|
125
130
|
end
|
|
126
131
|
|
|
127
132
|
private
|
|
@@ -134,7 +139,7 @@ module Admin
|
|
|
134
139
|
# export so the CSV matches what the manager is looking at.
|
|
135
140
|
def index_scope
|
|
136
141
|
scope = <%= class_name %>.all
|
|
137
|
-
perspective =
|
|
142
|
+
perspective = OpenLoam::Perspectives.resolve("<%= class_name %>", user: current_actor, id: params[:perspective_id])
|
|
138
143
|
scope = perspective.apply(scope) if perspective
|
|
139
144
|
<% if searchable_attributes.any? -%>
|
|
140
145
|
scope = scope.search(params[:q])
|
|
@@ -147,9 +152,14 @@ module Admin
|
|
|
147
152
|
# against real columns (never interpolated from params — that would be SQL
|
|
148
153
|
# injection), and the direction is constrained to asc/desc. With no valid
|
|
149
154
|
# sort param, a perspective's own order is kept, else a stable default.
|
|
155
|
+
#
|
|
156
|
+
# It must also be a column the role may READ: ordering by a hidden field
|
|
157
|
+
# leaks its ordering, which is an inference oracle on a value the role
|
|
158
|
+
# cannot see. Same reasoning as OpenLoam::FieldAccessError on custom fields —
|
|
159
|
+
# ignored rather than raised, since the header is not rendered either.
|
|
150
160
|
def apply_sort(scope)
|
|
151
161
|
column = params[:sort].to_s
|
|
152
|
-
if <%= class_name %>.column_names.include?(column)
|
|
162
|
+
if <%= class_name %>.column_names.include?(column) && policy_for(<%= class_name %>.new).readable?(column)
|
|
153
163
|
dir = params[:dir].to_s.casecmp("asc").zero? ? :asc : :desc
|
|
154
164
|
scope.reorder(column => dir).order(id: dir)
|
|
155
165
|
elsif scope.order_values.empty?
|
|
@@ -160,13 +170,13 @@ module Admin
|
|
|
160
170
|
end
|
|
161
171
|
|
|
162
172
|
# A custom-field filter routed through the read-model index
|
|
163
|
-
# (
|
|
173
|
+
# (OpenLoam::CustomFieldIndex) — index-backed, not a JSON scan. An unknown field
|
|
164
174
|
# is ignored rather than raising.
|
|
165
175
|
def apply_custom_field_filter(scope)
|
|
166
176
|
return scope if params[:cf_field].blank?
|
|
167
177
|
|
|
168
|
-
scope.merge(
|
|
169
|
-
rescue
|
|
178
|
+
scope.merge(OpenLoam::CustomFieldIndex.filter(<%= class_name %>, params[:cf_field], params[:cf_op].presence || "eq", params[:cf_value]))
|
|
179
|
+
rescue OpenLoam::Error
|
|
170
180
|
scope
|
|
171
181
|
end
|
|
172
182
|
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
2
|
|
|
3
|
-
# Generated guardrail tests for <%= class_name %>. They prove the
|
|
3
|
+
# Generated guardrail tests for <%= class_name %>. They prove the OpenLoam
|
|
4
4
|
# invariants hold for THIS entity: tenant isolation, loud failure without
|
|
5
5
|
# context, audit-by-default, lifecycle events, membership-gated policies.
|
|
6
6
|
# Extend freely; never delete.
|
|
7
|
-
class <%= class_name %>
|
|
7
|
+
class <%= class_name %>OpenLoamTest < ActiveSupport::TestCase
|
|
8
8
|
setup do
|
|
9
|
-
@tenant_a =
|
|
10
|
-
@tenant_b =
|
|
9
|
+
@tenant_a = OpenLoam::Tenant.create!(name: "Tenant A", slug: "a-<%= file_name %>")
|
|
10
|
+
@tenant_b = OpenLoam::Tenant.create!(name: "Tenant B", slug: "b-<%= file_name %>")
|
|
11
11
|
@manager = User.create!(name: "Manager", email: "manager@example.test", password: "password")
|
|
12
12
|
@employee = User.create!(name: "Employee", email: "employee@example.test", password: "password")
|
|
13
13
|
|
|
14
14
|
with_tenant(@tenant_a) do
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
OpenLoam::Membership.create!(user: @manager, role: "manager")
|
|
16
|
+
OpenLoam::Membership.create!(user: @employee, role: "employee")
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -29,15 +29,15 @@ class <%= class_name %>LoamTest < ActiveSupport::TestCase
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
test "guardrail: touching the model with no tenant context raises" do
|
|
32
|
-
assert_raises(
|
|
33
|
-
assert_raises(
|
|
32
|
+
assert_raises(OpenLoam::MissingTenantError) { <%= class_name %>.count }
|
|
33
|
+
assert_raises(OpenLoam::MissingTenantError) { <%= class_name %>.new }
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
test "guardrail: a record cannot be written into a foreign tenant" do
|
|
37
37
|
record = with_tenant(@tenant_a) { <%= class_name %>.create!(<%= sample_attributes %>) }
|
|
38
38
|
|
|
39
39
|
with_tenant(@tenant_b) do
|
|
40
|
-
assert_raises(
|
|
40
|
+
assert_raises(OpenLoam::MissingTenantError) { record.update!(<%= sample_attributes(1) %>) }
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -45,7 +45,7 @@ class <%= class_name %>LoamTest < ActiveSupport::TestCase
|
|
|
45
45
|
with_tenant(@tenant_a, actor: @manager) do
|
|
46
46
|
record = <%= class_name %>.create!(<%= sample_attributes %>)
|
|
47
47
|
|
|
48
|
-
audit =
|
|
48
|
+
audit = OpenLoam::AuditRecord.find_by(
|
|
49
49
|
auditable_type: "<%= class_name %>", auditable_id: record.id, action: "create"
|
|
50
50
|
)
|
|
51
51
|
assert audit, "expected an audit record for the create"
|
|
@@ -56,7 +56,7 @@ class <%= class_name %>LoamTest < ActiveSupport::TestCase
|
|
|
56
56
|
|
|
57
57
|
test "lifecycle events are published with the tenant stamped" do
|
|
58
58
|
received = []
|
|
59
|
-
subscription =
|
|
59
|
+
subscription = OpenLoam::Events.subscribe("<%= domain %>.<%= singular_name %>.created") do |_name, payload|
|
|
60
60
|
received << payload
|
|
61
61
|
end
|
|
62
62
|
|
|
@@ -78,7 +78,7 @@ class <%= class_name %>LoamTest < ActiveSupport::TestCase
|
|
|
78
78
|
with_tenant(@tenant_a) do
|
|
79
79
|
assert_equal 0, <%= class_name %>.count, "a soft-deleted record is gone from ordinary queries"
|
|
80
80
|
assert_equal 1, <%= class_name %>.with_deleted.count, "but the row still exists"
|
|
81
|
-
assert
|
|
81
|
+
assert OpenLoam::AuditRecord.exists?(auditable_type: "<%= class_name %>", auditable_id: record_id, action: "soft_delete")
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
# with_deleted lifts the deleted_at filter but NOT the tenant filter.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
class Create<%= table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::VERSION::STRING.to_f %>]
|
|
2
2
|
def change
|
|
3
|
-
create_table :<%= table_name %><%=
|
|
4
|
-
t.references :tenant, null: false, foreign_key: { to_table: :
|
|
3
|
+
create_table :<%= table_name %><%= open_loam_id_option %> do |t|
|
|
4
|
+
t.references :tenant, null: false, foreign_key: { to_table: :open_loam_tenants }<%= open_loam_type_option %>
|
|
5
5
|
<% attributes.each do |attribute| -%>
|
|
6
6
|
<% if encrypted?(attribute) -%>
|
|
7
|
-
t.text :<%= attribute.name %> # encrypted at rest (
|
|
7
|
+
t.text :<%= attribute.name %> # encrypted at rest (OpenLoam::Encryptable) — text, since ciphertext outgrows varchar
|
|
8
8
|
<% else -%>
|
|
9
9
|
t.<%= attribute.type %> :<%= attribute.name %>
|
|
10
10
|
<% end -%>
|
|
@@ -14,10 +14,10 @@ class Create<%= table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecor
|
|
|
14
14
|
<% end -%>
|
|
15
15
|
t.json :custom_fields, null: false, default: {}
|
|
16
16
|
t.datetime :deleted_at
|
|
17
|
-
t.integer :lock_version, null: false, default: 0 # optimistic locking (
|
|
17
|
+
t.integer :lock_version, null: false, default: 0 # optimistic locking (OpenLoam::RecordLock)
|
|
18
18
|
t.timestamps
|
|
19
19
|
end
|
|
20
|
-
#
|
|
20
|
+
# OpenLoam::SoftDeletable filters `deleted_at IS NULL` on every query.
|
|
21
21
|
add_index :<%= table_name %>, :deleted_at
|
|
22
22
|
<% encrypt_searchable_names.each do |field| -%>
|
|
23
23
|
add_index :<%= table_name %>, :<%= field %>_hash
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# Tenant-scoped, audited, evented — by inheritance, not by remembering.
|
|
2
|
-
class <%= class_name %> <
|
|
3
|
-
include
|
|
4
|
-
include
|
|
5
|
-
include
|
|
6
|
-
include
|
|
7
|
-
include
|
|
8
|
-
include
|
|
9
|
-
include
|
|
2
|
+
class <%= class_name %> < OpenLoam::TenantRecord
|
|
3
|
+
include OpenLoam::Auditable
|
|
4
|
+
include OpenLoam::Eventful
|
|
5
|
+
include OpenLoam::CustomFields
|
|
6
|
+
include OpenLoam::Commentable
|
|
7
|
+
include OpenLoam::Attachable
|
|
8
|
+
include OpenLoam::Searchable
|
|
9
|
+
include OpenLoam::SoftDeletable
|
|
10
10
|
<% if encrypted_field_names.any? -%>
|
|
11
|
-
include
|
|
11
|
+
include OpenLoam::Encryptable
|
|
12
12
|
<% end -%>
|
|
13
13
|
|
|
14
14
|
event_domain :<%= domain %>
|
|
@@ -23,5 +23,5 @@ class <%= class_name %> < Loam::TenantRecord
|
|
|
23
23
|
<% end -%>
|
|
24
24
|
|
|
25
25
|
# Business logic goes here. Publish business events explicitly:
|
|
26
|
-
#
|
|
26
|
+
# OpenLoam::Events.publish("<%= domain %>.something.happened", id: id)
|
|
27
27
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<%% policy =
|
|
1
|
+
<%% policy = OpenLoam::Policy.for(@record) %>
|
|
2
2
|
|
|
3
3
|
<%%# Optimistic-locking conflict: what the user typed vs what is now saved. %>
|
|
4
4
|
<%% if @conflict.present? %>
|
|
@@ -36,25 +36,28 @@
|
|
|
36
36
|
</ul>
|
|
37
37
|
<%% end %>
|
|
38
38
|
|
|
39
|
+
<%%# Three states per field: writable (input), readable-only (shown, labelled
|
|
40
|
+
read-only), or neither (absent). There is no branch for the third case on
|
|
41
|
+
purpose — a field the role may not read is not rendered at all. %>
|
|
39
42
|
<% attributes.each do |attribute| -%>
|
|
40
43
|
<%% if policy.writable?(:<%= attribute.name %>) %>
|
|
41
44
|
<p>
|
|
42
45
|
<%%= f.label :<%= attribute.name %> %><br>
|
|
43
46
|
<%%= f.<%= form_field_helper(attribute) %> :<%= attribute.name %> %>
|
|
44
47
|
</p>
|
|
45
|
-
<%%
|
|
48
|
+
<%% elsif policy.readable?(:<%= attribute.name %>) %>
|
|
46
49
|
<p>
|
|
47
50
|
<%%= f.label :<%= attribute.name %> %>: <%%= @record.<%= attribute.name %> %>
|
|
48
|
-
<em><%%= t("
|
|
51
|
+
<em><%%= t("open_loam.form.read_only") %></em>
|
|
49
52
|
</p>
|
|
50
53
|
<%% end %>
|
|
51
54
|
<% end -%>
|
|
52
55
|
|
|
53
|
-
<%%= render "
|
|
56
|
+
<%%= render "open_loam/custom_fields/fields", record: @record, policy: policy, mode: :edit %>
|
|
54
57
|
|
|
55
58
|
<%% if policy.update? %>
|
|
56
59
|
<p>
|
|
57
|
-
<%%= f.label :files, t("
|
|
60
|
+
<%%= f.label :files, t("open_loam.form.attach_files") %><br>
|
|
58
61
|
<%%= f.file_field :files, multiple: true %>
|
|
59
62
|
</p>
|
|
60
63
|
<%% end %>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
<h1><%%= t("
|
|
1
|
+
<h1><%%= t("open_loam.actions.deleted_title", name: <%= class_name %>.model_name.human(count: 2)) %></h1>
|
|
2
2
|
|
|
3
|
-
<p><%%= link_to t("
|
|
3
|
+
<p><%%= link_to t("open_loam.actions.back"), [:admin, <%= class_name %>] %></p>
|
|
4
4
|
|
|
5
5
|
<%%# No Show/Edit here: these rows are hidden by the default scope, so a plain
|
|
6
6
|
find would 404. The one action a deleted record offers is Restore. %>
|
|
7
7
|
<table>
|
|
8
8
|
<thead>
|
|
9
9
|
<tr>
|
|
10
|
-
<th><%%= t("
|
|
10
|
+
<th><%%= t("open_loam.labels.id") %></th>
|
|
11
11
|
<% attributes.each do |attribute| -%>
|
|
12
12
|
<th><%%= <%= class_name %>.human_attribute_name("<%= attribute.name %>") %></th>
|
|
13
13
|
<% end -%>
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
<td><%%= record.<%= attribute.name %> %></td>
|
|
24
24
|
<% end -%>
|
|
25
25
|
<td><%%= record.deleted_at %></td>
|
|
26
|
-
<td><%%= button_to t("
|
|
26
|
+
<td><%%= button_to t("open_loam.actions.restore"), [:restore, :admin, record], method: :patch %></td>
|
|
27
27
|
</tr>
|
|
28
28
|
<%% end %>
|
|
29
29
|
</tbody>
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
<%%# Page links carry nothing but the page: the recycle bin has no filter box. %>
|
|
33
33
|
<p>
|
|
34
34
|
<%% if @page > 1 %>
|
|
35
|
-
<%%= link_to t("
|
|
35
|
+
<%%= link_to t("open_loam.pagination.previous"), polymorphic_path([:deleted, :admin, <%= class_name %>], page: @page - 1) %>
|
|
36
36
|
<%% end %>
|
|
37
|
-
<%%= t("
|
|
37
|
+
<%%= t("open_loam.pagination.page", page: @page) %>
|
|
38
38
|
<%% if @has_next %>
|
|
39
|
-
<%%= link_to t("
|
|
39
|
+
<%%= link_to t("open_loam.pagination.next"), polymorphic_path([:deleted, :admin, <%= class_name %>], page: @page + 1) %>
|
|
40
40
|
<%% end %>
|
|
41
41
|
</p>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<%%# One policy for the whole table: readable? keys off the actor's ROLE, not the
|
|
2
|
+
row, so building it per record would only add a membership query per row. %>
|
|
3
|
+
<%% policy = OpenLoam::Policy.for_model(<%= class_name %>, current_actor) %>
|
|
4
|
+
|
|
5
|
+
<h1><%%= <%= class_name %>.model_name.human(count: 2) %></h1>
|
|
6
|
+
|
|
7
|
+
<%% if @index_partial %>
|
|
8
|
+
<p style="color:#b00"><%%= t("open_loam.index.incomplete") %></p>
|
|
9
|
+
<%% end %>
|
|
10
|
+
|
|
11
|
+
<p>
|
|
12
|
+
<%%= link_to t("open_loam.actions.new", name: <%= class_name %>.model_name.human), new_polymorphic_path([:admin, <%= class_name %>]) %>
|
|
13
|
+
<%%= link_to t("open_loam.actions.deleted", name: <%= class_name %>.model_name.human(count: 2)), polymorphic_path([:deleted, :admin, <%= class_name %>]) %>
|
|
14
|
+
<%% if current_role == :manager %>
|
|
15
|
+
<%%= link_to t("open_loam.actions.export_csv"), url_for(action: :export, **current_index_params) %>
|
|
16
|
+
<%%= link_to t("open_loam.actions.import_csv"), new_admin_import_path(entity_type: "<%= class_name %>") %>
|
|
17
|
+
<%% end %>
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<%%# Saved views (OpenLoam::Perspectives): pick one to apply, or save the current one. %>
|
|
21
|
+
<%% if @perspectives.any? %>
|
|
22
|
+
<%%= form_with url: [:admin, <%= class_name %>], method: :get do %>
|
|
23
|
+
<%%= select_tag :perspective_id,
|
|
24
|
+
options_for_select([[t("open_loam.views.all", name: <%= class_name %>.model_name.human(count: 2)), "none"]] + @perspectives.map { |p| [p.name, p.id] }, @perspective&.id),
|
|
25
|
+
onchange: "this.form.submit()" %>
|
|
26
|
+
<%%= link_to t("open_loam.views.manage"), admin_perspectives_path(entity_type: "<%= class_name %>") %>
|
|
27
|
+
<%% end %>
|
|
28
|
+
<%% else %>
|
|
29
|
+
<p><%%= link_to t("open_loam.views.manage_saved"), admin_perspectives_path(entity_type: "<%= class_name %>") %></p>
|
|
30
|
+
<%% end %>
|
|
31
|
+
|
|
32
|
+
<%%= form_with url: admin_perspectives_path, method: :post do %>
|
|
33
|
+
<%%= hidden_field_tag :entity_type, "<%= class_name %>" %>
|
|
34
|
+
<%%= hidden_field_tag :q, params[:q] %>
|
|
35
|
+
<%%= text_field_tag :name, nil, placeholder: t("open_loam.views.name_placeholder") %>
|
|
36
|
+
<%%= submit_tag t("open_loam.views.save_current") %>
|
|
37
|
+
<%% end %>
|
|
38
|
+
<% if searchable_attributes.any? -%>
|
|
39
|
+
|
|
40
|
+
<%%= form_with url: [:admin, <%= class_name %>], method: :get do |f| %>
|
|
41
|
+
<%%= text_field_tag :q, params[:q], placeholder: t("open_loam.views.filter_placeholder", name: <%= class_name %>.model_name.human(count: 2)) %>
|
|
42
|
+
<%%= f.submit t("open_loam.actions.filter") %>
|
|
43
|
+
<%% end %>
|
|
44
|
+
<% end -%>
|
|
45
|
+
|
|
46
|
+
<%%# Bulk actions on selected rows (OpenLoam::Bulk). Zero selection = no-op; each
|
|
47
|
+
action is policy-checked per record server-side. %>
|
|
48
|
+
<%%= form_with url: url_for(action: :bulk), method: :post do %>
|
|
49
|
+
<p>
|
|
50
|
+
<%%= select_tag :bulk_action, options_for_select([[t("open_loam.bulk.delete_selected"), "soft_delete"], [t("open_loam.bulk.set_field"), "set_field"], [t("open_loam.bulk.export_selected"), "export"]]) %>
|
|
51
|
+
<%%= select_tag :field, options_for_select(%i[<%= field_names.join(" ") %>]) %>
|
|
52
|
+
<%%= text_field_tag :value, nil, placeholder: t("open_loam.bulk.new_value") %>
|
|
53
|
+
<%%= submit_tag t("open_loam.bulk.apply"), data: { turbo_confirm: t("open_loam.bulk.confirm") } %>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<table>
|
|
57
|
+
<thead>
|
|
58
|
+
<tr>
|
|
59
|
+
<th><input type="checkbox" onclick="document.querySelectorAll('.bulk-select').forEach(function(c){c.checked=this.checked}.bind(this))"></th>
|
|
60
|
+
<th><%%= t("open_loam.labels.id") %></th>
|
|
61
|
+
<% attributes.each do |attribute| -%>
|
|
62
|
+
<%% if policy.readable?(:<%= attribute.name %>) %><th><%%= sort_link("<%= attribute.name %>", <%= class_name %>.human_attribute_name("<%= attribute.name %>")) %></th><%% end %>
|
|
63
|
+
<% end -%>
|
|
64
|
+
<th></th>
|
|
65
|
+
</tr>
|
|
66
|
+
</thead>
|
|
67
|
+
<tbody>
|
|
68
|
+
<%% @records.each do |record| %>
|
|
69
|
+
<tr>
|
|
70
|
+
<td><%%= check_box_tag "ids[]", record.id, false, class: "bulk-select" %></td>
|
|
71
|
+
<td><%%= record.id %></td>
|
|
72
|
+
<% attributes.each do |attribute| -%>
|
|
73
|
+
<%% if policy.readable?(:<%= attribute.name %>) %><td><%%= record.<%= attribute.name %> %></td><%% end %>
|
|
74
|
+
<% end -%>
|
|
75
|
+
<td>
|
|
76
|
+
<%%= link_to t("open_loam.actions.show"), [:admin, record] %>
|
|
77
|
+
<%%= link_to t("open_loam.actions.edit"), edit_polymorphic_path([:admin, record]) %>
|
|
78
|
+
</td>
|
|
79
|
+
</tr>
|
|
80
|
+
<%% end %>
|
|
81
|
+
</tbody>
|
|
82
|
+
</table>
|
|
83
|
+
<%% end %>
|
|
84
|
+
|
|
85
|
+
<%%# Page links carry the full filter state, or page 2 would quietly drop it. %>
|
|
86
|
+
<p>
|
|
87
|
+
<%% if @page > 1 %>
|
|
88
|
+
<%%= link_to t("open_loam.pagination.previous"), polymorphic_path([:admin, <%= class_name %>], **current_index_params, page: @page - 1) %>
|
|
89
|
+
<%% end %>
|
|
90
|
+
<%%= t("open_loam.pagination.page", page: @page) %>
|
|
91
|
+
<%% if @has_next %>
|
|
92
|
+
<%%= link_to t("open_loam.pagination.next"), polymorphic_path([:admin, <%= class_name %>], **current_index_params, page: @page + 1) %>
|
|
93
|
+
<%% end %>
|
|
94
|
+
</p>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<%% policy = OpenLoam::Policy.for(@record) %>
|
|
2
|
+
|
|
3
|
+
<h1><%%= t("open_loam.actions.show_title", name: <%= class_name %>.model_name.human, id: @record.id) %></h1>
|
|
4
|
+
|
|
5
|
+
<% attributes.each do |attribute| -%>
|
|
6
|
+
<%% if policy.readable?(:<%= attribute.name %>) %>
|
|
7
|
+
<p><strong><%%= <%= class_name %>.human_attribute_name("<%= attribute.name %>") %>:</strong> <%%= @record.<%= attribute.name %> %></p>
|
|
8
|
+
<%% end %>
|
|
9
|
+
<% end -%>
|
|
10
|
+
|
|
11
|
+
<%%= render "open_loam/custom_fields/fields", record: @record, policy: policy, mode: :show %>
|
|
12
|
+
|
|
13
|
+
<%%# Computed cross-module blocks (OpenLoam::Enrichers) — no section when none registered. %>
|
|
14
|
+
<%% enrichments = OpenLoam::Enrichers.enrich(@record) %>
|
|
15
|
+
<%% if enrichments.any? %>
|
|
16
|
+
<h2><%%= t("open_loam.labels.enrichments") %></h2>
|
|
17
|
+
<dl>
|
|
18
|
+
<%% enrichments.each do |key, value| %>
|
|
19
|
+
<dt><strong><%%= key.humanize %></strong></dt>
|
|
20
|
+
<dd><%%= value %></dd>
|
|
21
|
+
<%% end %>
|
|
22
|
+
</dl>
|
|
23
|
+
<%% end %>
|
|
24
|
+
|
|
25
|
+
<p>
|
|
26
|
+
<%%= link_to t("open_loam.actions.edit"), edit_polymorphic_path([:admin, @record]) %>
|
|
27
|
+
<%%= link_to "History", admin_history_path(type: @record.class.name, record_id: @record.id) %>
|
|
28
|
+
<%% if @record.class.respond_to?(:open_loam_translatable_attributes) && @record.class.open_loam_translatable_attributes.any? && current_role == :manager %>
|
|
29
|
+
<%%= link_to t("open_loam.actions.translations"), admin_translations_path(translatable_type: @record.class.name, translatable_id: @record.id) %>
|
|
30
|
+
<%% end %>
|
|
31
|
+
<%%# Delete soft-deletes: the record moves to the recycle bin, not oblivion. %>
|
|
32
|
+
<%%= button_to t("open_loam.actions.destroy"), [:admin, @record], method: :delete if policy.destroy? %>
|
|
33
|
+
<%%= link_to t("open_loam.actions.back"), [:admin, <%= class_name %>] %>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
<%%= render "open_loam/attachments/attachments", record: @record %>
|
|
37
|
+
|
|
38
|
+
<%%= render "open_loam/comments/comments", record: @record %>
|