ecoportal-api-graphql 1.3.5 → 1.3.9
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/.ai-assistance/bridge/CLAUDE.md +338 -0
- data/.ai-assistance/bridge/archive/.gitkeep +0 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +29 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +18 -0
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +42 -0
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +115 -0
- data/.ai-assistance/bridge/context/gemini-review-prompt.txt +48 -0
- data/.ai-assistance/bridge/context/gemini-review-response.md +104 -0
- data/.ai-assistance/bridge/context/project.md +42 -0
- data/.ai-assistance/bridge/inbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/.gitkeep +0 -0
- data/.ai-assistance/bridge/outbox/request-for-standards-discovery.md +48 -0
- data/.ai-assistance/bridge/queue/.gitkeep +1 -0
- data/.ai-assistance/capabilities/CLAUDE.md +27 -0
- data/.ai-assistance/capabilities/assumptions-log.md +80 -0
- data/.ai-assistance/capabilities/code.md +47 -0
- data/.ai-assistance/capabilities/connectors.md +37 -0
- data/.ai-assistance/capabilities/cowork.md +55 -0
- data/.ai-assistance/code/OVERVIEW.md +155 -0
- data/.ai-assistance/code/data_fields.md +242 -0
- data/.ai-assistance/code/dependencies.md +151 -0
- data/.ai-assistance/code/diff_as_input.md +234 -0
- data/.ai-assistance/code/diff_service_deep_dive.md +192 -0
- data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +55 -0
- data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +181 -0
- data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +192 -0
- data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +147 -0
- data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +277 -0
- data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +200 -0
- data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +228 -0
- data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +197 -0
- data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +243 -0
- data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +196 -0
- data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +132 -0
- data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +187 -0
- data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +236 -0
- data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +183 -0
- data/.ai-assistance/code/ecoportal_schema_reference.md +240 -0
- data/.ai-assistance/code/graphql_domain_knowledge.md +230 -0
- data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +71 -0
- data/.ai-assistance/code/refactoring/opportunities.md +251 -0
- data/.ai-assistance/code/schema_analysis.md +321 -0
- data/.ai-assistance/code/search_filters.md +868 -0
- data/.ai-assistance/code/spec_coverage.md +73 -0
- data/.ai-assistance/code/workflow-command-guide.md +438 -0
- data/.ai-assistance/code/workflow-space.md +353 -0
- data/.ai-assistance/conventions/CLAUDE.md +30 -0
- data/.ai-assistance/conventions/code-working-tree-protocol.md +199 -0
- data/.ai-assistance/conventions/gitignore-rules.md +42 -0
- data/.ai-assistance/conventions/permission-guidance.md +120 -0
- data/.ai-assistance/integrations/README.md +70 -0
- data/.ai-assistance/integrations/gitkraken-mcp.md +107 -0
- data/.ai-assistance/integrations/gitlab-mcp.md +123 -0
- data/.ai-assistance/integrations/local-git.md +60 -0
- data/.ai-assistance/local_paths.example.md +17 -0
- data/.ai-assistance/projects/TODO.md +97 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +168 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +60 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +267 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +53 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +102 -0
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +139 -0
- data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +93 -0
- data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +244 -0
- data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +266 -0
- data/.ai-assistance/projects/eco-helpers-compat/TODO.md +86 -0
- data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +101 -0
- data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +177 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +161 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +125 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +126 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +256 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +122 -0
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +148 -0
- data/.ai-assistance/projects/page-model/DECISIONS.md +245 -0
- data/.ai-assistance/projects/page-model/TODO.md +190 -0
- data/.ai-assistance/projects/search-filter-builder/INTENT.md +107 -0
- data/.ai-assistance/projects/search-filter-builder/TODO.md +131 -0
- data/.ai-assistance/projects/template-maintenance/DESIGN.md +134 -0
- data/.ai-assistance/projects/workflow-space/TODO.md +213 -0
- data/.ai-assistance/reinstall-claude-desktop-windows.md +136 -0
- data/.ai-assistance/scripts/CLAUDE.md +150 -0
- data/.ai-assistance/scripts/bridge-init.sh +86 -0
- data/.ai-assistance/scripts/bridge-status.sh +44 -0
- data/.ai-assistance/scripts/capabilities-check.ts +104 -0
- data/.ai-assistance/scripts/check-outbox.sh +43 -0
- data/.ai-assistance/scripts/dep_graph.rb +91 -0
- data/.ai-assistance/scripts/lock-acquire.sh +103 -0
- data/.ai-assistance/scripts/lock-multi.sh +124 -0
- data/.ai-assistance/scripts/lock-queue.sh +94 -0
- data/.ai-assistance/scripts/setup-mcps.test.ts +188 -0
- data/.ai-assistance/scripts/setup-mcps.ts +234 -0
- data/.ai-assistance/scripts/task-complete.ts +74 -0
- data/.ai-assistance/scripts/task-create.ts +75 -0
- data/.ai-assistance/scripts/task-read.ts +125 -0
- data/.ai-assistance/scripts/token-logger.js +220 -0
- data/.ai-assistance/scripts/token-report.ts +158 -0
- data/.ai-assistance/scripts/token-session-start.js +66 -0
- data/.ai-assistance/skills/ai-instructions/SKILL.md +48 -0
- data/.ai-assistance/skills/code-specs/SKILL.md +69 -0
- data/.ai-assistance/skills/corporate-policies/SKILL.md +201 -0
- data/.ai-assistance/skills/dep-graph/SKILL.md +139 -0
- data/.ai-assistance/skills/ep-ai-manager/SKILL.md +417 -0
- data/.ai-assistance/skills/gemini-assist/SKILL.md +63 -0
- data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +205 -0
- data/.ai-assistance/skills/gemini-assist/gemini_ask.py +1 -0
- data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +240 -0
- data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +25 -0
- data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +261 -0
- data/.ai-assistance/skills/project-cycle/SKILL.md +177 -0
- data/.ai-assistance/skills/refactor/SKILL.md +62 -0
- data/.ai-assistance/skills/rubocop/SKILL.md +93 -0
- data/.ai-assistance/skills/ruby-scripting/SKILL.md +215 -0
- data/.ai-assistance/skills/spec-generation/SKILL.md +72 -0
- data/.ai-assistance/standards-version.json +21 -0
- data/.ai-assistance/token-budget.json +32 -0
- data/.ai-assistance/version.json +39 -0
- data/.claude/settings.json +146 -0
- data/.env.example +18 -0
- data/.gitattributes +15 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +121 -97
- data/CHANGELOG.md +673 -477
- data/CLAUDE.md +232 -0
- data/Gemfile +30 -6
- data/Rakefile +90 -38
- data/docs/worklog.md +574 -0
- data/ecoportal-api-graphql.gemspec +40 -40
- data/lib/ecoportal/api/common/graphql/CLAUDE.md +36 -0
- data/lib/ecoportal/api/common/graphql/client.rb +1 -1
- data/lib/ecoportal/api/common/graphql/http_client.rb +35 -3
- data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +28 -0
- data/lib/ecoportal/api/common/graphql/model/as_input.rb +8 -5
- data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +3 -1
- data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +31 -23
- data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +54 -1
- data/lib/ecoportal/api/graphql/CLAUDE.md +37 -0
- data/lib/ecoportal/api/graphql/base/CLAUDE.md +50 -0
- data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -0
- data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -0
- data/lib/ecoportal/api/graphql/base/force/binding.rb +19 -0
- data/lib/ecoportal/api/graphql/base/force/binding_collection.rb +62 -0
- data/lib/ecoportal/api/graphql/base/force/collection.rb +47 -0
- data/lib/ecoportal/api/graphql/base/force.rb +65 -0
- data/lib/ecoportal/api/graphql/base/kickstand/job.rb +17 -0
- data/lib/ecoportal/api/graphql/base/kickstand/workflow.rb +18 -0
- data/lib/ecoportal/api/graphql/base/kickstand.rb +13 -0
- data/lib/ecoportal/api/graphql/base/page/basic.rb +38 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +112 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +28 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +54 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +25 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/gauge.rb +19 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/number.rb +20 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +35 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/select.rb +41 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -0
- data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -0
- data/lib/ecoportal/api/graphql/base/page/data_field.rb +137 -12
- data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +68 -14
- data/lib/ecoportal/api/graphql/base/page/phased.rb +1 -0
- data/lib/ecoportal/api/graphql/base/page/section.rb +36 -0
- data/lib/ecoportal/api/graphql/base/page/section_collection.rb +79 -0
- data/lib/ecoportal/api/graphql/base/page.rb +2 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/action_type_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/callback_type.rb +28 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_change.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_change_message.rb +15 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_es_change.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/command_interface.rb +36 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/email_config.rb +18 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/escalation_level.rb +19 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/in_system_config.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/mailbox_field_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/create_page.rb +21 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/people_field_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/register_field.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/task_config_selection.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/time_delay_config.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/trigger_interface.rb +26 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/triggers/conditional_logic.rb +17 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow/user_selection.rb +16 -0
- data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -0
- data/lib/ecoportal/api/graphql/base/preset_view.rb +17 -0
- data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -0
- data/lib/ecoportal/api/graphql/base/register.rb +18 -0
- data/lib/ecoportal/api/graphql/base.rb +11 -0
- data/lib/ecoportal/api/graphql/builder/CLAUDE.md +65 -0
- data/lib/ecoportal/api/graphql/builder/kickstand.rb +73 -0
- data/lib/ecoportal/api/graphql/builder/page.rb +210 -41
- data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -0
- data/lib/ecoportal/api/graphql/builder/register.rb +27 -19
- data/lib/ecoportal/api/graphql/builder/template.rb +80 -0
- data/lib/ecoportal/api/graphql/builder.rb +2 -0
- data/lib/ecoportal/api/graphql/compat/filter_translator.rb +107 -0
- data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -0
- data/lib/ecoportal/api/graphql/compat/pages.rb +212 -0
- data/lib/ecoportal/api/graphql/compat/registers.rb +84 -0
- data/lib/ecoportal/api/graphql/compat/response.rb +35 -0
- data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -0
- data/lib/ecoportal/api/graphql/compat/stage_collection.rb +70 -0
- data/lib/ecoportal/api/graphql/compat/stage_view.rb +76 -0
- data/lib/ecoportal/api/graphql/compat.rb +17 -0
- data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -0
- data/lib/ecoportal/api/graphql/concerns/deprecation.rb +20 -0
- data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +21 -28
- data/lib/ecoportal/api/graphql/concerns/page_compat.rb +51 -0
- data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -0
- data/lib/ecoportal/api/graphql/concerns.rb +4 -0
- data/lib/ecoportal/api/graphql/connection/page.rb +11 -0
- data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +13 -0
- data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -0
- data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -0
- data/lib/ecoportal/api/graphql/connection.rb +4 -0
- data/lib/ecoportal/api/graphql/file_upload/client.rb +181 -0
- data/lib/ecoportal/api/graphql/file_upload.rb +10 -0
- data/lib/ecoportal/api/graphql/fragment/action.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/action_category.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/force.rb +30 -0
- data/lib/ecoportal/api/graphql/fragment/location_draft.rb +2 -2
- data/lib/ecoportal/api/graphql/fragment/location_node.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/locations_error.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment/page.rb +85 -0
- data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +395 -0
- data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -0
- data/lib/ecoportal/api/graphql/fragment/pages_workflow.rb +172 -0
- data/lib/ecoportal/api/graphql/fragment/pagination.rb +1 -1
- data/lib/ecoportal/api/graphql/fragment.rb +37 -27
- data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +25 -0
- data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -0
- data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -0
- data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -0
- data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -0
- data/lib/ecoportal/api/graphql/input/page/update.rb +140 -0
- data/lib/ecoportal/api/graphql/input/page.rb +26 -0
- data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -0
- data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -0
- data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -0
- data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -0
- data/lib/ecoportal/api/graphql/input/register/create.rb +18 -0
- data/lib/ecoportal/api/graphql/input/register/update.rb +15 -0
- data/lib/ecoportal/api/graphql/input/register.rb +13 -0
- data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -0
- data/lib/ecoportal/api/graphql/input/search_conf.rb +367 -0
- data/lib/ecoportal/api/graphql/input/variable_binding.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_gauge_field_stop.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +19 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_gauge_field_stop.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_field_config.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_select_field_option.rb +17 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -0
- data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -0
- data/lib/ecoportal/api/graphql/input.rb +8 -0
- data/lib/ecoportal/api/graphql/interface/base_page.rb +100 -58
- data/lib/ecoportal/api/graphql/interface/location_structure/nodes.rb +27 -28
- data/lib/ecoportal/api/graphql/logic/base_model.rb +2 -0
- data/lib/ecoportal/api/graphql/logic/base_query.rb +45 -2
- data/lib/ecoportal/api/graphql/logic/input.rb +15 -0
- data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -0
- data/lib/ecoportal/api/graphql/model/organization.rb +65 -55
- data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -0
- data/lib/ecoportal/api/graphql/model/page/phased.rb +82 -20
- data/lib/ecoportal/api/graphql/model/page.rb +1 -0
- data/lib/ecoportal/api/graphql/model/page_union.rb +21 -0
- data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -0
- data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -0
- data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -0
- data/lib/ecoportal/api/graphql/model/register.rb +10 -0
- data/lib/ecoportal/api/graphql/model.rb +8 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_jobs.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_workflows.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/fail_job.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/start_job.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/kickstand.rb +18 -0
- data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +2 -2
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +2 -2
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +3 -3
- data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -0
- data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +69 -0
- data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +51 -0
- data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/page/update_variable_bindings.rb +44 -0
- data/lib/ecoportal/api/graphql/mutation/page.rb +28 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -0
- data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -0
- data/lib/ecoportal/api/graphql/mutation/register.rb +14 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -0
- data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -0
- data/lib/ecoportal/api/graphql/mutation/template/create.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -0
- data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template/publish.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/unpublish.rb +39 -0
- data/lib/ecoportal/api/graphql/mutation/template/update.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +43 -0
- data/lib/ecoportal/api/graphql/mutation/template.rb +18 -0
- data/lib/ecoportal/api/graphql/mutation.rb +8 -0
- data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -0
- data/lib/ecoportal/api/graphql/payload/execute_workflow_commands.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/force_commands.rb +31 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +36 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/job.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/kickstand/workflow.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/kickstand.rb +15 -0
- data/lib/ecoportal/api/graphql/payload/location_structure/draft/create.rb +33 -34
- data/lib/ecoportal/api/graphql/payload/ok_payload.rb +21 -0
- data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/draft.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page/update_variable_bindings.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/page.rb +19 -0
- data/lib/ecoportal/api/graphql/payload/preset_view.rb +11 -0
- data/lib/ecoportal/api/graphql/payload/register.rb +11 -0
- data/lib/ecoportal/api/graphql/payload/template/create.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/publish.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/unpublish.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/update.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template/update_information.rb +13 -0
- data/lib/ecoportal/api/graphql/payload/template.rb +18 -0
- data/lib/ecoportal/api/graphql/payload.rb +11 -0
- data/lib/ecoportal/api/graphql/query/action.rb +1 -1
- data/lib/ecoportal/api/graphql/query/action_categories.rb +1 -1
- data/lib/ecoportal/api/graphql/query/actions.rb +2 -2
- data/lib/ecoportal/api/graphql/query/contractor_entities.rb +1 -1
- data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -0
- data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +2 -2
- data/lib/ecoportal/api/graphql/query/location_structure.rb +1 -1
- data/lib/ecoportal/api/graphql/query/location_structures.rb +1 -1
- data/lib/ecoportal/api/graphql/query/page.rb +45 -0
- data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -0
- data/lib/ecoportal/api/graphql/query/page_with_forces.rb +43 -0
- data/lib/ecoportal/api/graphql/query/pages.rb +59 -0
- data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +59 -0
- data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -0
- data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -0
- data/lib/ecoportal/api/graphql/query/templates.rb +53 -0
- data/lib/ecoportal/api/graphql/query.rb +11 -0
- data/lib/ecoportal/api/graphql.rb +60 -2
- data/lib/ecoportal/api/graphql_version.rb +5 -5
- data/scripts/auto-worker-scheduler.sh +386 -0
- data/tests/contractor_entity_create.rb +19 -19
- data/tests/contractor_entity_udpate.rb +20 -20
- data/tests/dump_page_model.rb +74 -0
- data/tests/loc_structure_get.rb +1 -2
- data/tests/loc_structure_update.rb +51 -51
- data/tests/loc_structures_get.rb +15 -15
- metadata +436 -5
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# EcoPortal Search and Filters
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Two Search Modalities
|
|
6
|
+
|
|
7
|
+
### 1. Org Search — `currentOrganization { pages(...) }`
|
|
8
|
+
|
|
9
|
+
**Data source:** PostgreSQL/MongoDB — full DB render
|
|
10
|
+
**Returns:** `PageUnion` (BasicPage | PhasedPage) — complete data
|
|
11
|
+
**Performance:** ~3 seconds per page (API-layer assembly)
|
|
12
|
+
**Supports archived:** Yes (via `searchConf` state filter)
|
|
13
|
+
**Has field IDs:** Yes — use for pre-update fetch
|
|
14
|
+
**patchVer:** Yes — required for mutations
|
|
15
|
+
|
|
16
|
+
Use when you need full field data to build mutation inputs.
|
|
17
|
+
|
|
18
|
+
**Arguments:**
|
|
19
|
+
- `searchConf: Search` — filter/sort/query
|
|
20
|
+
- `templatesOnly: Boolean` — restrict to templates
|
|
21
|
+
- `showHiddenData: Boolean` — include hidden fields
|
|
22
|
+
- `first/last/after/before` — cursor pagination
|
|
23
|
+
|
|
24
|
+
**Key `searchConf` filter for register-scoping within org search:**
|
|
25
|
+
```json
|
|
26
|
+
{ "operation": "register_filter", "params": { "ids": ["REGISTER_ID"] } }
|
|
27
|
+
```
|
|
28
|
+
This scopes the org search to a register without switching to `previewPages`.
|
|
29
|
+
|
|
30
|
+
### 2. Register Search — `currentOrganization { register(id:) { previewPages(...) } }`
|
|
31
|
+
|
|
32
|
+
**Data source:** Elasticsearch — search index snapshot
|
|
33
|
+
**Returns:** `PreviewPage` — metadata only (id, name, state, locations, dataFields as previews)
|
|
34
|
+
**Performance:** Sub-second (ES-powered)
|
|
35
|
+
**Supports archived:** Yes — `includeArchived: Boolean` parameter (default false)
|
|
36
|
+
**Has field IDs:** NO — cannot build mutation inputs from this
|
|
37
|
+
**patchVer:** NO
|
|
38
|
+
|
|
39
|
+
Use for fast metadata lookup (find page IDs, check existence, list pages).
|
|
40
|
+
|
|
41
|
+
**Additional arguments:**
|
|
42
|
+
- `presetViewId: ID` — apply a register PageView preset configuration
|
|
43
|
+
- `searchConf: Search`
|
|
44
|
+
- `includeArchived: Boolean`
|
|
45
|
+
|
|
46
|
+
**Field name:** `previewPages` (not `pages`) — common confusion point.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## SearchConf Structure
|
|
51
|
+
|
|
52
|
+
`searchConf` is a `Hash` type (`Search` in the schema) — NOT a typed GraphQL input.
|
|
53
|
+
Engineering has backend classes but they are not exposed as GraphQL types.
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"filters": [ <filter_object>, ... ],
|
|
58
|
+
"sorters": { "key": "created_at", "direction": "asc" },
|
|
59
|
+
"query": "optional full-text search string"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Note on sorters:** Can be a single object OR an array. Key field is `key` (not `fieldName`).
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Filter Operations
|
|
68
|
+
|
|
69
|
+
**ALL operation names are snake_case strings.** If CamelCase is used (e.g. `ExactFilter`),
|
|
70
|
+
the server returns NO error AND NO results — completely silent failure. This is one of
|
|
71
|
+
the hardest bugs for customers to diagnose.
|
|
72
|
+
|
|
73
|
+
**`filters` should always be an Array.** The server normalises a single object to an
|
|
74
|
+
array internally, but always use array form for consistency.
|
|
75
|
+
|
|
76
|
+
### `exact_filter`
|
|
77
|
+
|
|
78
|
+
Equality match on a field.
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{ "operation": "exact_filter", "params": { "key": "external_id", "value": "EXT-001" } }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Common keys: `external_id`, `state`, `creator_id`, `template_id`
|
|
85
|
+
|
|
86
|
+
### `date_filter`
|
|
87
|
+
|
|
88
|
+
Date range filter.
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"operation": "date_filter",
|
|
93
|
+
"params": {
|
|
94
|
+
"key": "updated_at",
|
|
95
|
+
"gte": "2025-01-01T00:00:00Z",
|
|
96
|
+
"lte": "2025-12-31T23:59:59Z",
|
|
97
|
+
"time_zone": "UTC"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`gte` = lower bound, `lte` = upper bound. Both optional.
|
|
103
|
+
|
|
104
|
+
**v2 format note:** APIv2 used `lbound`/`ubound` instead of `gte`/`lte`. The
|
|
105
|
+
eco-helpers compat layer translates these automatically.
|
|
106
|
+
|
|
107
|
+
### `register_filter`
|
|
108
|
+
|
|
109
|
+
Scope org search to specific registers (org search only — not applicable to `previewPages`).
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{ "operation": "register_filter", "params": { "ids": ["REGISTER_ID"] } }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `and_filter`
|
|
116
|
+
|
|
117
|
+
Explicit AND group (top-level `filters` array is already implicit AND).
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"operation": "and_filter",
|
|
122
|
+
"params": {
|
|
123
|
+
"filters": [
|
|
124
|
+
{ "operation": "exact_filter", "params": { "key": "external_id", "value": "X" } },
|
|
125
|
+
{ "operation": "date_filter", "params": { "key": "updated_at", "gte": "..." } }
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `or_filter`
|
|
132
|
+
|
|
133
|
+
OR group.
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"operation": "or_filter",
|
|
138
|
+
"params": {
|
|
139
|
+
"filters": [
|
|
140
|
+
{ "operation": "exact_filter", "params": { "key": "external_id", "value": "A" } },
|
|
141
|
+
{ "operation": "exact_filter", "params": { "key": "external_id", "value": "B" } }
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### `tag_filter` (v2 pass-through)
|
|
148
|
+
|
|
149
|
+
Filter by location tags. Used by APIv2 eco-helpers scripts. Passes through to the ES
|
|
150
|
+
backend unchanged. Same ES backend as GraphQL register search.
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"type": "tag_filter",
|
|
155
|
+
"tags": ["Auckland", "Wellington"],
|
|
156
|
+
"mode": "any",
|
|
157
|
+
"negate": false,
|
|
158
|
+
"key": "tags"
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## SearchConf Builder (Gem)
|
|
165
|
+
|
|
166
|
+
The gem provides `Input::SearchConf` for building filters programmatically:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
# Find by externalId
|
|
170
|
+
conf = SearchConf.new.filter(SearchConf::Exact.new(:external_id, 'EXT-001'))
|
|
171
|
+
|
|
172
|
+
# Register-scoped date range
|
|
173
|
+
conf = SearchConf.new
|
|
174
|
+
.filter(SearchConf::Register.new('REG_ID'))
|
|
175
|
+
.filter(SearchConf::DateRange.new(:updated_at, gte: '2025-01-01', time_zone: 'UTC'))
|
|
176
|
+
.sort(:created_at, :asc)
|
|
177
|
+
|
|
178
|
+
# OR filter (multiple externalIds)
|
|
179
|
+
conf = SearchConf.new.filter(
|
|
180
|
+
SearchConf::Or.new(
|
|
181
|
+
SearchConf::Exact.new(:external_id, 'EXT-001'),
|
|
182
|
+
SearchConf::Exact.new(:external_id, 'EXT-002')
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Parametrize (same search, different value)
|
|
187
|
+
base = SearchConf.new.filter(SearchConf::Exact.new(:external_id, 'X'))
|
|
188
|
+
copy = base.with(external_id: 'Y') # original unchanged
|
|
189
|
+
|
|
190
|
+
# Use with queries
|
|
191
|
+
org.pages(searchConf: conf.to_h, first: 10)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Filter classes:** `SearchConf::Exact`, `SearchConf::DateRange`, `SearchConf::Register`,
|
|
195
|
+
`SearchConf::And`, `SearchConf::Or`
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Known Filterable Field Keys (confirmed from production queries)
|
|
200
|
+
|
|
201
|
+
| key | Type | Operations |
|
|
202
|
+
|-----|------|------------|
|
|
203
|
+
| `external_id` | string | `exact_filter` |
|
|
204
|
+
| `updated_at` | datetime | `date_filter` |
|
|
205
|
+
| `created_at` | datetime | `date_filter` (likely) |
|
|
206
|
+
| `state` | enum | `exact_filter` (key: active/archived/draft) |
|
|
207
|
+
| `location_ids` | ID array | likely `in_filter` or similar |
|
|
208
|
+
| `creator_id` | ID | `exact_filter` |
|
|
209
|
+
| `template_id` | ID | `exact_filter` |
|
|
210
|
+
|
|
211
|
+
**Note:** The `fieldName` convention in some Confluence docs uses this same key concept.
|
|
212
|
+
The keys are snake_case corresponding to indexed ES document fields — NOT necessarily
|
|
213
|
+
the GraphQL field names.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Future: Fluent DSL (Planned)
|
|
218
|
+
|
|
219
|
+
A more ergonomic API using Ruby's `&` (AND) and `|` (OR) operators is planned:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
Search[:external_id].eq('EXT-001') & Search.in_register('REG_ID')
|
|
223
|
+
Search[:state].is(:active) | Search[:state].is(:draft)
|
|
224
|
+
(Search[:state].is(:active) | Search[:state].is(:draft)) & Search.in_register('REG_ID')
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
This is operator-based (familiar to Arel/Sequel users), avoids ambiguity in chaining,
|
|
228
|
+
and will support AI-assisted filter generation. See `search-filter-builder/` project.
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# EcoPortal Data Fields
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Data fields are the form inputs within a page. Each field is an INSTANCE of a field
|
|
8
|
+
definition from the template. Field instances have:
|
|
9
|
+
- A MongoDB ObjectId (`id`) assigned on page creation — NOT predictable from template
|
|
10
|
+
- The field type (`__typename` in GraphQL)
|
|
11
|
+
- Label (the question/field name shown to users)
|
|
12
|
+
- Value(s) — the user's response
|
|
13
|
+
- `ref` — the ES index key (Field ID / System ID future)
|
|
14
|
+
- `deindex: Boolean` — if true, field is excluded from Elasticsearch index
|
|
15
|
+
- Linked field configuration (cross-reference from another register)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## All Field Types (`DataFieldUnion`)
|
|
20
|
+
|
|
21
|
+
The GraphQL `DataFieldUnion` has 20+ concrete types:
|
|
22
|
+
|
|
23
|
+
| GraphQL type | eco-helpers type | Description |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `PlainText` | `:plain_text` | Single or multi-line text |
|
|
26
|
+
| `RichText` | `:rich_text` | HTML rich text editor |
|
|
27
|
+
| `Date` | `:date` | Date/datetime picker |
|
|
28
|
+
| `Number` | `:number` | Numeric input |
|
|
29
|
+
| `Gauge` | `:gauge` | Numeric with min/max (risk matrix output) |
|
|
30
|
+
| `Select` | `:select` | Single or multi-select dropdown |
|
|
31
|
+
| `Checklist` | `:checklist` | Checkbox list (each item: label + checked) |
|
|
32
|
+
| `Signature` | `:signature` | Digital signature capture |
|
|
33
|
+
| `TagField` | `:tag_field` | Location tag selector |
|
|
34
|
+
| `People` | `:people` | Person selector (linked to PersonMember) |
|
|
35
|
+
| `ContractorEntities` | `:contractor_entities` | Contractor selector |
|
|
36
|
+
| `CrossReference` | `:cross_reference` | Reference to pages in another register |
|
|
37
|
+
| `Geo` | `:geo` | Geographic coordinates + address |
|
|
38
|
+
| `ImageGallery` | `:image_gallery` | Image upload gallery |
|
|
39
|
+
| `File` | `:file` | File attachment |
|
|
40
|
+
| `Mailbox` | `:mailbox` | Email inbox linked to the field |
|
|
41
|
+
| `ActionsList` | `:actions_list` | Embedded actions list |
|
|
42
|
+
| `Law` | `:law` | Legal obligation snippets |
|
|
43
|
+
| `AiSummary` | `:ai_summary` | AI-generated summary field |
|
|
44
|
+
| `EmbeddedStructure` | `:embedded_structure` | Embedded reporting structure |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## DataFieldInput Structure
|
|
49
|
+
|
|
50
|
+
When updating or adding field values, each field uses a typed input within `DataFieldInput`:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"plainText": { "id": "FIELD_ID", "value": "Job description text" },
|
|
55
|
+
"richText": { "id": "FIELD_ID", "content": "<p>HTML content</p>" },
|
|
56
|
+
"date": { "id": "FIELD_ID", "value": "2024-11-25T08:30:00+13:00" },
|
|
57
|
+
"number": { "id": "FIELD_ID", "value": 42.5 },
|
|
58
|
+
"gauge": { "id": "FIELD_ID", "value": 14.0 },
|
|
59
|
+
"select": { "id": "FIELD_ID", "options": [{ "id": "OPT_ID", "selected": true }] },
|
|
60
|
+
"people": { "id": "FIELD_ID", "peopleIds": ["PERSON_ID_1", "PERSON_ID_2"] },
|
|
61
|
+
"geo": { "id": "FIELD_ID", "address": "...", "coordinates": { "lat": -36.86, "lon": 174.76 } },
|
|
62
|
+
"checklist": { "id": "FIELD_ID", "items": [{ "id": "ITEM_ID", "checked": true }] },
|
|
63
|
+
"locationField": { "id": "FIELD_ID", "locationIds": ["LOC_ID"] }
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Only ONE field type key is used per `DataFieldInput` object.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## DataFieldOneToManyInput
|
|
72
|
+
|
|
73
|
+
Used in both `createPageFromTemplate` and `updatePage`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"additions": [<DataFieldInput>, ...],
|
|
78
|
+
"updates": [<DataFieldInput>, ...],
|
|
79
|
+
"deletions": ["FIELD_ID_TO_DELETE", ...]
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- **`updates`** — change values of existing fields (require their current `id`)
|
|
84
|
+
- **`additions`** — add new field data (for fields that exist in template but have no instance data yet)
|
|
85
|
+
- **`deletions`** — remove field instances
|
|
86
|
+
|
|
87
|
+
**For `createFromTemplate`:** Use `updates` — the `buildFromTemplate` response gives
|
|
88
|
+
instance field IDs, and `updates` sets their values on creation.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Field Access in the Gem
|
|
93
|
+
|
|
94
|
+
### Getting fields from a page
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
page = graphql.pages.get(page_id) # fetches CommonPageUnion with $fields: true
|
|
98
|
+
|
|
99
|
+
# As DataField::Collection
|
|
100
|
+
fields = page.components # or page.field_collection
|
|
101
|
+
|
|
102
|
+
# Filter by type
|
|
103
|
+
plain_texts = fields.get_by_type(:plain_text)
|
|
104
|
+
selects = fields.get_by_type('Select')
|
|
105
|
+
|
|
106
|
+
# Find by label
|
|
107
|
+
field = fields.get_by_name('Summary')
|
|
108
|
+
|
|
109
|
+
# Access raw docs (v2 compat)
|
|
110
|
+
fields.doc # → [raw_hash, ...]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Modifying fields
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
# PlainText
|
|
117
|
+
field = page.components.get_by_name('Summary')
|
|
118
|
+
field.value = 'New summary text'
|
|
119
|
+
|
|
120
|
+
# Select — by option name, value, or id
|
|
121
|
+
field = page.components.get_by_name('Status')
|
|
122
|
+
field.select_option('Active') # deselects all others
|
|
123
|
+
|
|
124
|
+
# People
|
|
125
|
+
field = page.components.get_by_name('Assigned To')
|
|
126
|
+
field.people_ids = ['person_id_1', 'person_id_2']
|
|
127
|
+
|
|
128
|
+
# Date (ISO8601 string)
|
|
129
|
+
field = page.components.get_by_name('Due Date')
|
|
130
|
+
field.value = '2025-06-30T09:00:00+12:00'
|
|
131
|
+
|
|
132
|
+
# Checklist
|
|
133
|
+
field = page.components.get_by_name('Checklist')
|
|
134
|
+
field.check('Step A')
|
|
135
|
+
field.check('Step B', checked: false)
|
|
136
|
+
|
|
137
|
+
# Rich text (HTML)
|
|
138
|
+
field = page.components.get_by_name('Description')
|
|
139
|
+
field.content = '<p>Updated description</p>'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Adding a new field (additions)
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
# When a field exists in the template but has no data in this instance:
|
|
146
|
+
draft = graphql.pages.get_new(template_id)
|
|
147
|
+
draft.components.add(id: 'f1_from_draft', type: 'PlainText') { |f| f.value = 'X' }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Stage-Level Field Access
|
|
153
|
+
|
|
154
|
+
For PhasedPage, fields are within stages → sections → fields:
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
# Get stage by name
|
|
158
|
+
stage = page.stages['Risk Assessment']
|
|
159
|
+
|
|
160
|
+
# Stage sections
|
|
161
|
+
stage.sections.each do |section|
|
|
162
|
+
puts "Section: #{section.heading}"
|
|
163
|
+
section.components.each { |f| puts " Field: #{f.label}" }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# All fields in stage (flat)
|
|
167
|
+
stage.components.get_by_name('Hazard Description').value = 'Exposure to...'
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Field Visibility: deindex and Hidden
|
|
173
|
+
|
|
174
|
+
- `deindex: Boolean` — if true, field value is NOT sent to Elasticsearch. Used for
|
|
175
|
+
sensitive data. Affects: search, filters, analytics, exports.
|
|
176
|
+
- Fields can be hidden (template configuration). `showHiddenData: true` in queries
|
|
177
|
+
includes hidden fields in the response.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Field Reference (ref) — ES Index Key
|
|
182
|
+
|
|
183
|
+
The `ref` property identifies a field in the search index (ES). It is:
|
|
184
|
+
- Composed of: `<type_shorthand>.<hash_of_label>`
|
|
185
|
+
- Used in: sorters (`key:` field), filters, chart configurations, linked field config
|
|
186
|
+
- Different from the MongoDB instance `id`
|
|
187
|
+
- Breaks if the field label changes (hash of label changes)
|
|
188
|
+
|
|
189
|
+
**Formula:** `Ecoportal::API::Common::Content::StringDigest` in `ecoportal-api-v2`
|
|
190
|
+
|
|
191
|
+
**Examples:**
|
|
192
|
+
- Plain text field "Job Number": `plain_text.job_nu` (approximate hash)
|
|
193
|
+
- Date field "Due Date": `date.due_da`
|
|
194
|
+
|
|
195
|
+
**Known issue:** If a field was added via a tech script without copying from the template,
|
|
196
|
+
its `ref` may be unique per instance rather than consistent across all instances of the
|
|
197
|
+
same template. This causes analytics issues (missing data, duplicate columns in exports).
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# EcoPortal Stages and Sections
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Stage Lifecycle
|
|
6
|
+
|
|
7
|
+
### Stage States (`StageStateEnum`)
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
pending → inprogress → complete
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- **`pending`** — Stage not yet started. No fill-in task exists yet.
|
|
14
|
+
- **`inprogress`** — Stage is active. A fill-in task (`CompletePage`) exists and is
|
|
15
|
+
assigned to someone (per workflow rules). The assignee can enter data.
|
|
16
|
+
- **`complete`** — All required tasks are done. Stage is locked.
|
|
17
|
+
|
|
18
|
+
**Transition triggers:**
|
|
19
|
+
- `pending → inprogress`: Previous stage completes (its task is done/signed off)
|
|
20
|
+
- `inprogress → complete`: Fill-in task completed, OR review task signed off (if review configured)
|
|
21
|
+
|
|
22
|
+
### Active vs Started
|
|
23
|
+
|
|
24
|
+
- `active: Boolean` — Stage is currently active for input (the "current" stage)
|
|
25
|
+
- `started: Boolean` — Stage has had at least some input (includes all past stages)
|
|
26
|
+
|
|
27
|
+
For a PhasedPage: typically ONE stage is `active` at a time. Previous stages are
|
|
28
|
+
`started` but not `active`. Future stages are neither.
|
|
29
|
+
|
|
30
|
+
### Stage-Specific Submit
|
|
31
|
+
|
|
32
|
+
When submitting a stage via GraphQL, ALWAYS include `stageId`:
|
|
33
|
+
|
|
34
|
+
```graphql
|
|
35
|
+
mutation SubmitStage($input: UpdatePageInput!) {
|
|
36
|
+
updatePage(input: $input) {
|
|
37
|
+
item { ...PhasedPageFields }
|
|
38
|
+
errors { details fullMessages }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"input": {
|
|
46
|
+
"id": "PAGE_ID",
|
|
47
|
+
"patchVer": 5,
|
|
48
|
+
"stageId": "STAGE_ID",
|
|
49
|
+
"submit": true,
|
|
50
|
+
"dataFields": {
|
|
51
|
+
"updates": [
|
|
52
|
+
{ "plainText": { "id": "FIELD_ID", "value": "Final value" } }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Without `stageId`, the submit may not correctly associate with the right stage and
|
|
60
|
+
may not trigger the expected task assignments in the next stage.
|
|
61
|
+
|
|
62
|
+
**Why a stage is mandatory (verified — Oscar, 2026-06-30):** stage tasks, and the
|
|
63
|
+
permissions granted through them, are **stage-scoped**. A people field can grant the user
|
|
64
|
+
attached to it permission to *only the stage where they were attached* — so a save / submit /
|
|
65
|
+
sign-off MUST be executed against that specific stage as the target. The web/mobile front-ends
|
|
66
|
+
always operate within a stage for this reason. Inferring a "current/active" stage from the
|
|
67
|
+
page is therefore not just unreliable, it is semantically wrong: on a multi-stage page it may
|
|
68
|
+
name a different stage than the one the work was done on. The submit must carry the stage the
|
|
69
|
+
caller actually worked on. ⇒ **submit / sign_off without a target stage is invalid.**
|
|
70
|
+
|
|
71
|
+
### Gem enforcement & stageId resolution (compat layer)
|
|
72
|
+
|
|
73
|
+
The gem treats "a submit must name its stage" as a hard invariant:
|
|
74
|
+
|
|
75
|
+
- `Input::Page::Update.from_model` **raises** (`ArgumentError`) when `submit: true` or a stage
|
|
76
|
+
`task` is requested with no `stage_id`. This replaced a silent failure: the operation hash's
|
|
77
|
+
nil-guard used to *drop* a nil `stageId`, so a stage-less submit went out unnoticed (the
|
|
78
|
+
act-gov TOOCS bug, 2026-06-30). A plain field update / publish needs no stage and is exempt.
|
|
79
|
+
- `Compat::Pages#compat_stage_id` resolves the target most-explicit-first:
|
|
80
|
+
1. **pinned** — `submit!(stage_id:)` / `sign_off!(stage_id:)` from the script;
|
|
81
|
+
2. **active** — `page._compat_active_stage_id`, recorded when a `Compat::StageView` is taken
|
|
82
|
+
over the page (`pages.get(id, stage_id:)` or eco-helpers `OozeRedirect#stage`). This is the
|
|
83
|
+
reliable source on the OozeSamples path, where the base loop enqueues and updates the FULL
|
|
84
|
+
page (first-wins by id — the StageView is never the queued object), so the chosen stage must
|
|
85
|
+
live on the page itself;
|
|
86
|
+
3. **current** — `Phased#current_stage_id` server-state inference (`state=='inprogress'` /
|
|
87
|
+
`active==true`). Last resort only, and guarded: if it yields nil the `from_model` guard fires.
|
|
88
|
+
|
|
89
|
+
So the canonical way to submit a specific stage from a script is to work *through a stage view*
|
|
90
|
+
(`with_stage` → `stage()` → `StageView`), which records the stage; the later `target.submit!`
|
|
91
|
+
then resolves to it automatically.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Stage Permissions
|
|
96
|
+
|
|
97
|
+
Each stage can have restricted access:
|
|
98
|
+
- **User group restrictions** — only members of specified groups can edit the stage
|
|
99
|
+
- **People field access** — if a stage has a people field configured to "grant stage access",
|
|
100
|
+
the people assigned to that field get editing access to that stage only
|
|
101
|
+
|
|
102
|
+
**Key insight:** The configuration enum on a people field determines access scope:
|
|
103
|
+
- `stage_only` — grant access only to the stage where the people field is embedded
|
|
104
|
+
- `page_wide` — grant access to the entire page
|
|
105
|
+
|
|
106
|
+
**GraphQL behaviour:** If a user doesn't have access to a stage, the stage is simply
|
|
107
|
+
ABSENT from the response (`stages`, `stagesIndex`, `activeStages`). No error is thrown.
|
|
108
|
+
This is different from APIv2 which returned explicit access errors per stage.
|
|
109
|
+
|
|
110
|
+
**Scripting implication:** Scripts should check whether an expected stage is present
|
|
111
|
+
in the response rather than catching errors. If a stage is missing, the authenticated
|
|
112
|
+
user may not have access to it.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Section Types (HasSectionsInterface)
|
|
117
|
+
|
|
118
|
+
Both BasicPage (directly) and Stage (within PhasedPage) implement `HasSectionsInterface`.
|
|
119
|
+
|
|
120
|
+
### `ContentSection`
|
|
121
|
+
|
|
122
|
+
Standard section — one column of fields:
|
|
123
|
+
```graphql
|
|
124
|
+
fragment on ContentSection {
|
|
125
|
+
id
|
|
126
|
+
heading
|
|
127
|
+
dataFields { ...dataField }
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `SplitSection`
|
|
132
|
+
|
|
133
|
+
Two-column section (left + right panels):
|
|
134
|
+
```graphql
|
|
135
|
+
fragment on SplitSection {
|
|
136
|
+
id
|
|
137
|
+
heading
|
|
138
|
+
leftDataFields { ...dataField }
|
|
139
|
+
rightDataFields { ...dataField }
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
When accessing a split section's fields, always merge left + right:
|
|
144
|
+
```ruby
|
|
145
|
+
section.components # → DataField::Collection merging left + right
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Stage-Level Field Access (PhasedPage)
|
|
151
|
+
|
|
152
|
+
In GraphQL, all stage data is returned in one request via `CommonPageUnion`.
|
|
153
|
+
The response has stages → sections → fields.
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
# Gem access pattern
|
|
157
|
+
page = graphql.pages.get(page_id)
|
|
158
|
+
|
|
159
|
+
# All stages
|
|
160
|
+
page.stages # → StageCollection
|
|
161
|
+
page.stages['Risk Assessment'] # → Stage (by name or ID)
|
|
162
|
+
page.stages.ordered # → [Stage, ...] sorted by ordering
|
|
163
|
+
|
|
164
|
+
# Stage contents
|
|
165
|
+
stage = page.stages['Risk Assessment']
|
|
166
|
+
stage.sections # → SectionCollection
|
|
167
|
+
stage.components # → DataField::Collection (all fields in stage)
|
|
168
|
+
stage.sections.get_by_type(:content_section)
|
|
169
|
+
stage.sections.get_by_heading('Details')
|
|
170
|
+
|
|
171
|
+
# Field access in a stage
|
|
172
|
+
stage.components.get_by_name('Hazard Description').value = 'Exposure to...'
|
|
173
|
+
stage.components.get_by_type(:select).find { |f| f.label == 'Risk Level' }.select_option('High')
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## APIv2 vs GraphQL Stage Rendering Comparison
|
|
179
|
+
|
|
180
|
+
| Concern | APIv2 | GraphQL |
|
|
181
|
+
|---------|-------|---------|
|
|
182
|
+
| Request count for PhasedPage | One per stage | One for entire page |
|
|
183
|
+
| Stage data isolation | Strict — each request scoped to one stage | Full page returned, client filters |
|
|
184
|
+
| Stage-specific mutations | Via stage_id on URL | Via `stageId:` in `UpdatePageInput` |
|
|
185
|
+
| Permission handling | Access error per forbidden stage | Forbidden stages absent from response |
|
|
186
|
+
| Template stages | Full render | Full render |
|
|
187
|
+
|
|
188
|
+
**Compat layer approach:**
|
|
189
|
+
`graphql.pages.get(page_id, stage_id: 's1')` returns a `StageView` — a client-side
|
|
190
|
+
wrapper that shows only the specified stage's sections and components, while delegating
|
|
191
|
+
all other page accessors (id, name, patchVer, as_update, etc.) to the full page.
|
|
192
|
+
This matches what v2 scripts expect from a per-stage fetch.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## StageIndex (Lightweight Stage Summary)
|
|
197
|
+
|
|
198
|
+
For displaying workflow progress without loading full stage content:
|
|
199
|
+
|
|
200
|
+
```graphql
|
|
201
|
+
fragment PhasedPageFields on PhasedPage {
|
|
202
|
+
stagesIndex {
|
|
203
|
+
id
|
|
204
|
+
name
|
|
205
|
+
ordering
|
|
206
|
+
state
|
|
207
|
+
started
|
|
208
|
+
hasCompleteTask
|
|
209
|
+
hasReviewTask
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`hasCompleteTask` — whether a fill-in task is configured for this stage
|
|
215
|
+
`hasReviewTask` — whether a review/sign-off task is configured for this stage
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Task Types on Stages
|
|
220
|
+
|
|
221
|
+
| Task type | GraphQL type | Trigger | When complete |
|
|
222
|
+
|-----------|-------------|---------|---------------|
|
|
223
|
+
| Fill-in | `CompletePage` | Stage becomes active | Moves to review (if configured) or completes stage |
|
|
224
|
+
| Review/sign-off | `ReviewPage` | Fill-in task completed | Completes stage → activates next stage |
|
|
225
|
+
|
|
226
|
+
Task fields: `id`, `complete`, `completedAt`, `completedBy`, `due`, `overdue`, `users`
|
|
227
|
+
|
|
228
|
+
**Stage close-out sequence:**
|
|
229
|
+
1. Fill-in task assigned to user(s) (per workflow rules)
|
|
230
|
+
2. User submits: `updatePage(stageId:, submit: true)` triggers `CompletePage` completion
|
|
231
|
+
3. If review configured: `ReviewPage` task created and assigned
|
|
232
|
+
4. Review approved: stage state → `complete`, next stage activated
|
|
233
|
+
5. Next fill-in task created per workflow rules
|
|
234
|
+
|
|
235
|
+
**Scripting a stage submit:**
|
|
236
|
+
```ruby
|
|
237
|
+
input = Input::Page::Update.from_model(page,
|
|
238
|
+
stage_id: 'STAGE_ID',
|
|
239
|
+
submit: true
|
|
240
|
+
)
|
|
241
|
+
# Input will include stageId + submit even if no page/field changes
|
|
242
|
+
Builder::Page.new(client).update(input: input)
|
|
243
|
+
```
|