ecoportal-api-graphql 1.3.13 → 1.3.16
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 +87 -0
- data/lib/ecoportal/api/common/graphql/client.rb +0 -2
- data/lib/ecoportal/api/common/graphql/http_client.rb +6 -0
- data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -17
- data/lib/ecoportal/api/graphql/base/file_container.rb +14 -14
- data/lib/ecoportal/api/graphql/base/location_classification_type.rb +15 -15
- data/lib/ecoportal/api/graphql/base/location_structure.rb +27 -27
- data/lib/ecoportal/api/graphql/base/organization.rb +15 -15
- data/lib/ecoportal/api/graphql/base/page/task.rb +24 -0
- data/lib/ecoportal/api/graphql/base/page.rb +17 -16
- data/lib/ecoportal/api/graphql/base/template.rb +35 -0
- data/lib/ecoportal/api/graphql/base.rb +37 -35
- data/lib/ecoportal/api/graphql/builder/contractor_entity.rb +41 -41
- data/lib/ecoportal/api/graphql/compat/response.rb +35 -35
- data/lib/ecoportal/api/graphql/connection/action.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/action_category.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/contractor_entity.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/person_member.rb +11 -11
- data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -11
- data/lib/ecoportal/api/graphql/connection.rb +17 -17
- data/lib/ecoportal/api/graphql/file_upload/client.rb +21 -10
- data/lib/ecoportal/api/graphql/fragment/field_configuration.rb +38 -0
- data/lib/ecoportal/api/graphql/fragment/force.rb +14 -10
- data/lib/ecoportal/api/graphql/fragment/location_node.rb +26 -26
- data/lib/ecoportal/api/graphql/fragment/page_task.rb +39 -0
- data/lib/ecoportal/api/graphql/fragment/template.rb +51 -0
- data/lib/ecoportal/api/graphql/fragment.rb +3 -0
- data/lib/ecoportal/api/graphql/input/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -16
- data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -21
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -28
- data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -23
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -24
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -20
- data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -18
- data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -251
- data/lib/ecoportal/api/graphql/input.rb +24 -24
- data/lib/ecoportal/api/graphql/logic/connection.rb +34 -34
- data/lib/ecoportal/api/graphql/model/page/task.rb +16 -0
- data/lib/ecoportal/api/graphql/model/page.rb +16 -15
- data/lib/ecoportal/api/graphql/model/person_member.rb +15 -15
- data/lib/ecoportal/api/graphql/model/template.rb +15 -0
- data/lib/ecoportal/api/graphql/model.rb +32 -30
- data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -45
- data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +7 -7
- data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +8 -7
- data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +38 -40
- data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +34 -35
- data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -35
- data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -36
- data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -40
- data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -13
- data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -46
- data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/mutation.rb +20 -20
- data/lib/ecoportal/api/graphql/payload/contractor_entity.rb +14 -14
- data/lib/ecoportal/api/graphql/payload/ok_payload.rb +36 -21
- data/lib/ecoportal/api/graphql/payload/page/draft.rb +26 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -13
- data/lib/ecoportal/api/graphql/payload/page/review_task_batch.rb +23 -0
- data/lib/ecoportal/api/graphql/payload/page.rb +20 -19
- data/lib/ecoportal/api/graphql/payload/preset_view.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/register.rb +15 -11
- data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +1 -1
- data/lib/ecoportal/api/graphql/payload/template/update_information.rb +1 -1
- data/lib/ecoportal/api/graphql/payload.rb +23 -23
- data/lib/ecoportal/api/graphql/query/location_structures.rb +57 -57
- data/lib/ecoportal/api/graphql/query/page.rb +45 -45
- data/lib/ecoportal/api/graphql/query/page_with_forces.rb +9 -3
- data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +9 -3
- data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -78
- data/lib/ecoportal/api/graphql/query.rb +27 -27
- data/lib/ecoportal/api/graphql.rb +9 -5
- data/lib/ecoportal/api/graphql_version.rb +1 -1
- metadata +9 -180
- data/.ai-assistance/bridge/CLAUDE.md +0 -338
- data/.ai-assistance/bridge/archive/.gitkeep +0 -0
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.inbox.md +0 -29
- data/.ai-assistance/bridge/archive/oscar-a1b2c3d-gitlab-mcp-doc-update.outbox.md +0 -18
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.inbox.md +0 -42
- data/.ai-assistance/bridge/archive/oscar-c912c25-gemini-design-review.outbox.md +0 -115
- data/.ai-assistance/bridge/context/gemini-review-prompt.txt +0 -48
- data/.ai-assistance/bridge/context/gemini-review-response.md +0 -104
- data/.ai-assistance/bridge/context/project.md +0 -42
- 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 +0 -48
- data/.ai-assistance/bridge/queue/.gitkeep +0 -1
- data/.ai-assistance/capabilities/CLAUDE.md +0 -27
- data/.ai-assistance/capabilities/assumptions-log.md +0 -80
- data/.ai-assistance/capabilities/code.md +0 -47
- data/.ai-assistance/capabilities/connectors.md +0 -37
- data/.ai-assistance/capabilities/cowork.md +0 -55
- data/.ai-assistance/code/OVERVIEW.md +0 -155
- data/.ai-assistance/code/data_fields.md +0 -242
- data/.ai-assistance/code/dependencies.md +0 -151
- data/.ai-assistance/code/diff_as_input.md +0 -234
- data/.ai-assistance/code/diff_pairing_engine.md +0 -243
- data/.ai-assistance/code/diff_service_deep_dive.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/00_overview_and_index.md +0 -55
- data/.ai-assistance/code/ecoPortal_architecture/01_terminology_dictionary.md +0 -181
- data/.ai-assistance/code/ecoPortal_architecture/02_data_model.md +0 -192
- data/.ai-assistance/code/ecoPortal_architecture/03_api_layers.md +0 -147
- data/.ai-assistance/code/ecoPortal_architecture/04_graphql_queries_mutations.md +0 -277
- data/.ai-assistance/code/ecoPortal_architecture/05_page_workflows.md +0 -200
- data/.ai-assistance/code/ecoPortal_architecture/06_search_and_filters.md +0 -228
- data/.ai-assistance/code/ecoPortal_architecture/07_data_fields.md +0 -197
- data/.ai-assistance/code/ecoPortal_architecture/08_stages_sections.md +0 -243
- data/.ai-assistance/code/ecoPortal_architecture/09_people_contractors_locations.md +0 -196
- data/.ai-assistance/code/ecoPortal_architecture/10_forces_workflow_builder.md +0 -132
- data/.ai-assistance/code/ecoPortal_architecture/11_integration_gems.md +0 -187
- data/.ai-assistance/code/ecoPortal_architecture/12_ai_documentation_sources_gaps.md +0 -236
- data/.ai-assistance/code/ecoPortal_architecture/13_ai_infrastructure.md +0 -183
- data/.ai-assistance/code/ecoportal_schema_reference.md +0 -240
- data/.ai-assistance/code/filter_contract_matrix.md +0 -177
- data/.ai-assistance/code/graphql_domain_knowledge.md +0 -240
- data/.ai-assistance/code/refactoring/datafield-readwrite-shape-asymmetry.md +0 -71
- data/.ai-assistance/code/refactoring/opportunities.md +0 -251
- data/.ai-assistance/code/schema_analysis.md +0 -321
- data/.ai-assistance/code/search_filters.md +0 -868
- data/.ai-assistance/code/spec_coverage.md +0 -73
- data/.ai-assistance/code/template_diff_pairing_domain.md +0 -175
- data/.ai-assistance/code/workflow-command-guide.md +0 -466
- data/.ai-assistance/code/workflow-space.md +0 -353
- data/.ai-assistance/conventions/CLAUDE.md +0 -30
- data/.ai-assistance/conventions/code-working-tree-protocol.md +0 -199
- data/.ai-assistance/conventions/gitignore-rules.md +0 -42
- data/.ai-assistance/conventions/permission-guidance.md +0 -120
- data/.ai-assistance/integrations/README.md +0 -70
- data/.ai-assistance/integrations/gitkraken-mcp.md +0 -107
- data/.ai-assistance/integrations/gitlab-mcp.md +0 -123
- data/.ai-assistance/integrations/local-git.md +0 -60
- data/.ai-assistance/local_paths.example.md +0 -17
- data/.ai-assistance/projects/TODO.md +0 -118
- data/.ai-assistance/projects/api-v2-to-graphql-migration/DECISIONS.md +0 -168
- data/.ai-assistance/projects/api-v2-to-graphql-migration/INTENT.md +0 -60
- data/.ai-assistance/projects/api-v2-to-graphql-migration/TODO.md +0 -267
- data/.ai-assistance/projects/api-v2-to-graphql-migration/UPSTREAM.md +0 -53
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/csv-template-pipeline-design.md +0 -102
- data/.ai-assistance/projects/api-v2-to-graphql-migration/notes/cutover-usecase-gap-audit.md +0 -139
- data/.ai-assistance/projects/compat-layer-audit/COMPAT_AUDIT.md +0 -244
- data/.ai-assistance/projects/dynamic-model-generation/INTENT.md +0 -93
- data/.ai-assistance/projects/eco-helpers-compat/INTENT.md +0 -244
- data/.ai-assistance/projects/eco-helpers-compat/MIGRATION_GUIDE.md +0 -266
- data/.ai-assistance/projects/eco-helpers-compat/TODO.md +0 -86
- data/.ai-assistance/projects/ecoportal-api-v2-doublemodel-review/INTENT.md +0 -101
- data/.ai-assistance/projects/graphql-agent/GAP_ANALYSIS.md +0 -177
- data/.ai-assistance/projects/ooze-graphql-native-migration/DECISIONS.md +0 -161
- data/.ai-assistance/projects/ooze-graphql-native-migration/INTENT.md +0 -125
- data/.ai-assistance/projects/ooze-graphql-native-migration/INVENTORY.md +0 -136
- data/.ai-assistance/projects/ooze-graphql-native-migration/RISKS.md +0 -126
- data/.ai-assistance/projects/ooze-graphql-native-migration/TODO.md +0 -261
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-06-30-cutover-workflow-deep-review.md +0 -122
- data/.ai-assistance/projects/ooze-graphql-native-migration/analysis/2026-07-01-forces-via-workflow-commands-miss-rca.md +0 -148
- data/.ai-assistance/projects/page-model/DECISIONS.md +0 -245
- data/.ai-assistance/projects/page-model/TODO.md +0 -190
- data/.ai-assistance/projects/qa-services-delivery/DECISIONS.md +0 -93
- data/.ai-assistance/projects/qa-services-delivery/INTENT.md +0 -76
- data/.ai-assistance/projects/qa-services-delivery/PHASE3-SCOPE.md +0 -115
- data/.ai-assistance/projects/qa-services-delivery/ROADMAP.md +0 -99
- data/.ai-assistance/projects/qa-services-delivery/TODO.md +0 -81
- data/.ai-assistance/projects/search-filter-builder/INTENT.md +0 -107
- data/.ai-assistance/projects/search-filter-builder/TODO.md +0 -131
- data/.ai-assistance/projects/template-automatic-build-maintenance/INTENT.md +0 -87
- data/.ai-assistance/projects/template-automatic-build-maintenance/TODO.md +0 -108
- data/.ai-assistance/projects/template-diff-deploy/INTENT.md +0 -12
- data/.ai-assistance/projects/template-diff-deploy/TODO.md +0 -9
- data/.ai-assistance/projects/template-maintenance/DESIGN.md +0 -134
- data/.ai-assistance/projects/template-maintenance/PHASE0-FINDINGS.md +0 -93
- data/.ai-assistance/projects/template-maintenance/README.md +0 -14
- data/.ai-assistance/projects/template-model-logic/CATEGORY_CATALOG.md +0 -236
- data/.ai-assistance/projects/template-model-logic/CLASSIFICATION_SPIKE.md +0 -243
- data/.ai-assistance/projects/template-model-logic/DESIGN_NOTE.md +0 -154
- data/.ai-assistance/projects/workflow-space/TODO.md +0 -213
- data/.ai-assistance/reinstall-claude-desktop-windows.md +0 -136
- data/.ai-assistance/scripts/CLAUDE.md +0 -150
- data/.ai-assistance/scripts/bridge-inbox-check.sh +0 -75
- data/.ai-assistance/scripts/bridge-init.sh +0 -86
- data/.ai-assistance/scripts/bridge-status.sh +0 -44
- data/.ai-assistance/scripts/capabilities-check.ts +0 -104
- data/.ai-assistance/scripts/check-outbox.sh +0 -43
- data/.ai-assistance/scripts/dep_graph.rb +0 -91
- data/.ai-assistance/scripts/lock-acquire.sh +0 -103
- data/.ai-assistance/scripts/lock-multi.sh +0 -124
- data/.ai-assistance/scripts/lock-queue.sh +0 -94
- data/.ai-assistance/scripts/setup-mcps.test.ts +0 -188
- data/.ai-assistance/scripts/setup-mcps.ts +0 -234
- data/.ai-assistance/scripts/task-complete.ts +0 -74
- data/.ai-assistance/scripts/task-create.ts +0 -75
- data/.ai-assistance/scripts/task-read.ts +0 -125
- data/.ai-assistance/scripts/token-logger.js +0 -220
- data/.ai-assistance/scripts/token-report.ts +0 -158
- data/.ai-assistance/scripts/token-session-start.js +0 -66
- data/.ai-assistance/skills/ai-instructions/SKILL.md +0 -48
- data/.ai-assistance/skills/code-specs/SKILL.md +0 -69
- data/.ai-assistance/skills/corporate-policies/SKILL.md +0 -201
- data/.ai-assistance/skills/dep-graph/SKILL.md +0 -139
- data/.ai-assistance/skills/ep-ai-manager/SKILL.md +0 -417
- data/.ai-assistance/skills/gemini-assist/SKILL.md +0 -63
- data/.ai-assistance/skills/gemini-assist/gemini-mcp-server.js +0 -205
- data/.ai-assistance/skills/gemini-assist/gemini_ask.py +0 -1
- data/.ai-assistance/skills/gemini-assist/gemini_ask.rb +0 -240
- data/.ai-assistance/skills/gemini-assist/prompts/cycle_end_review.txt +0 -25
- data/.ai-assistance/skills/graphql-schema-analysis/SKILL.md +0 -261
- data/.ai-assistance/skills/procedural-memory/SKILL.md +0 -319
- data/.ai-assistance/skills/project-cycle/SKILL.md +0 -177
- data/.ai-assistance/skills/project-self-docs/SKILL.md +0 -181
- data/.ai-assistance/skills/project-self-docs/scripts/self_docs_scan.py +0 -378
- data/.ai-assistance/skills/refactor/SKILL.md +0 -62
- data/.ai-assistance/skills/rubocop/SKILL.md +0 -93
- data/.ai-assistance/skills/ruby-scripting/SKILL.md +0 -215
- data/.ai-assistance/skills/spec-generation/SKILL.md +0 -72
- data/.ai-assistance/standards-version.json +0 -22
- data/.ai-assistance/token-budget.json +0 -32
- data/.ai-assistance/version.json +0 -39
- data/.claude/settings.json +0 -150
- data/.env.example +0 -18
- data/.gitattributes +0 -15
- data/.gitignore +0 -37
- data/.gitlab-ci.yml +0 -45
- data/.markdownlint.json +0 -4
- data/.rspec +0 -3
- data/.rubocop.yml +0 -121
- data/.ruby-version +0 -1
- data/.yardopts +0 -10
- data/CLAUDE.md +0 -243
- data/Gemfile +0 -30
- data/Rakefile +0 -90
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/bin/setup.ps1 +0 -6
- data/docs/self-docs/ARCHITECTURE.md +0 -88
- data/docs/self-docs/CHANGES.jsonl +0 -12
- data/docs/self-docs/COMPLIANCE.md +0 -79
- data/docs/self-docs/CONVENTIONS.md +0 -74
- data/docs/self-docs/INTEGRATIONS.md +0 -65
- data/docs/self-docs/OPERATIONS.md +0 -76
- data/docs/self-docs/OVERVIEW.md +0 -64
- data/docs/self-docs/STATUS.md +0 -73
- data/docs/self-docs/self-docs-index.json +0 -51
- data/docs/worklog.md +0 -977
- data/ecoportal-api-graphql.gemspec +0 -40
- data/scripts/auto-worker-scheduler.sh +0 -386
- data/tests/actions_get.rb +0 -7
- data/tests/contractor_entities_get.rb +0 -20
- data/tests/contractor_entity_create.rb +0 -19
- data/tests/contractor_entity_udpate.rb +0 -20
- data/tests/dump_page_model.rb +0 -74
- data/tests/dump_template_model.rb +0 -90
- data/tests/loc_structure_get.rb +0 -10
- data/tests/loc_structure_update.rb +0 -51
- data/tests/loc_structures_get.rb +0 -15
- data/tests/local_libs.rb +0 -20
- data/tests/validate_queries.rb +0 -127
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
# EcoPortal GraphQL Queries and Mutations
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## Query Root (`currentOrganization`)
|
|
6
|
-
|
|
7
|
-
All queries nest under `currentOrganization`. There is no top-level resource query —
|
|
8
|
-
everything is scoped to the authenticated user's organisation.
|
|
9
|
-
|
|
10
|
-
```graphql
|
|
11
|
-
{
|
|
12
|
-
currentOrganization {
|
|
13
|
-
id
|
|
14
|
-
# All other queries go here
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Page Queries
|
|
22
|
-
|
|
23
|
-
### `page(id: ID!)` → `PageUnion`
|
|
24
|
-
|
|
25
|
-
Fetches a single page by ID. Returns `BasicPage | PhasedPage`.
|
|
26
|
-
|
|
27
|
-
```graphql
|
|
28
|
-
query GetPage($id: ID!) {
|
|
29
|
-
currentOrganization {
|
|
30
|
-
page(id: $id) {
|
|
31
|
-
...PageFields # core metadata
|
|
32
|
-
...PhasedPageFields # stage index (if phased)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
**Gem class:** `Query::Page`
|
|
39
|
-
**For compat (full data):** Use `...CommonPageUnion` fragment (includes all field data).
|
|
40
|
-
|
|
41
|
-
### `pages(...)` → `PageUnionConnection`
|
|
42
|
-
|
|
43
|
-
Org-wide paginated page search. Returns full `PageUnion` from DB.
|
|
44
|
-
|
|
45
|
-
**Arguments:**
|
|
46
|
-
- `searchConf: Search` — filter/sort/query configuration
|
|
47
|
-
- `templatesOnly: Boolean` — restrict to templates only
|
|
48
|
-
- `showHiddenData: Boolean` — include hidden fields
|
|
49
|
-
- `after/before/first/last` — cursor pagination
|
|
50
|
-
|
|
51
|
-
**Performance note:** ~3 seconds per page on render (DB-backed). Avoid large result sets.
|
|
52
|
-
|
|
53
|
-
```graphql
|
|
54
|
-
query OrgSearchPages($searchConf: Search, $first: Int, $after: String) {
|
|
55
|
-
currentOrganization {
|
|
56
|
-
pages(searchConf: $searchConf, first: $first, after: $after) {
|
|
57
|
-
totalCount
|
|
58
|
-
pageInfo { hasNextPage endCursor }
|
|
59
|
-
nodes { ...PageFields }
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**Gem class:** `Query::Pages`
|
|
66
|
-
|
|
67
|
-
### `templates(...)` → `PageConnection`
|
|
68
|
-
|
|
69
|
-
Lists templates (pages with `templatesOnly: true`). Same arguments as `pages`.
|
|
70
|
-
|
|
71
|
-
**Gem class:** `Query::Templates`
|
|
72
|
-
|
|
73
|
-
### `register(id:) { previewPages(...) }` → `PreviewPageConnection`
|
|
74
|
-
|
|
75
|
-
ES-backed fast register search. Returns `PreviewPage` — metadata only, no field IDs.
|
|
76
|
-
|
|
77
|
-
**Arguments on `previewPages`:**
|
|
78
|
-
- `searchConf: Search`
|
|
79
|
-
- `includeArchived: Boolean` (default false)
|
|
80
|
-
- `presetViewId: ID` — apply a register PageView preset
|
|
81
|
-
|
|
82
|
-
**Performance:** Sub-second (Elasticsearch). Use for metadata lookup.
|
|
83
|
-
**Limitation:** No `patchVer`, no field IDs. Cannot be used for mutation input building.
|
|
84
|
-
|
|
85
|
-
```graphql
|
|
86
|
-
query RegisterSearch($registerId: ID!, $search: Search, $includeArchived: Boolean) {
|
|
87
|
-
currentOrganization {
|
|
88
|
-
register(id: $registerId) {
|
|
89
|
-
previewPages(searchConf: $search, includeArchived: $includeArchived) {
|
|
90
|
-
totalCount
|
|
91
|
-
pageInfo { hasNextPage endCursor }
|
|
92
|
-
nodes { id uid name state archived externalId createdAt { dateTime } }
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
**Gem class:** `Query::RegisterPreviewPages`
|
|
100
|
-
|
|
101
|
-
### `pageDelta(deltaInput: [DeltaInput!]!, searchConf: Search)` → `[DeltaResult!]!`
|
|
102
|
-
|
|
103
|
-
Cache-invalidation query. Given a list of `{ id, deltaAt }` pairs, returns which pages
|
|
104
|
-
have changed since the given timestamp.
|
|
105
|
-
|
|
106
|
-
**`DeltaResult`:** `{ id: ID!, delta: DeltaEnum! }` where `DeltaEnum = UPDATED | NOT_FOUND | NEW`
|
|
107
|
-
|
|
108
|
-
**Gem class:** `Query::PageDelta`
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## Page Mutations
|
|
113
|
-
|
|
114
|
-
### `buildPageFromTemplate(input: BuildFromTemplateInput!)` → `BuildFromTemplatePayload`
|
|
115
|
-
|
|
116
|
-
**Step (a) of the 2-step create sequence.** Builds a draft without persisting it.
|
|
117
|
-
Returns a `PageUnion` with server-assigned field IDs (the template's field IDs mapped
|
|
118
|
-
to new instance IDs). Use these IDs to populate `dataFields.updates` in `createFromTemplate`.
|
|
119
|
-
|
|
120
|
-
```graphql
|
|
121
|
-
mutation BuildPage($input: BuildFromTemplateInput!) {
|
|
122
|
-
buildPageFromTemplate(input: $input) {
|
|
123
|
-
errors { details fullMessages }
|
|
124
|
-
item { ...CommonPageUnion }
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
**Variables:** `{ templateId: "...", showHiddenData: true }`
|
|
130
|
-
|
|
131
|
-
### `createPageFromTemplate(input: CreateFromTemplateInput!)` → `CreateFromTemplatePayload`
|
|
132
|
-
|
|
133
|
-
**Step (b) of the 2-step create sequence.** Creates the page from a filled draft.
|
|
134
|
-
|
|
135
|
-
**Key `CreateFromTemplateInput` fields:**
|
|
136
|
-
- `templateId: ID!`
|
|
137
|
-
- `dataFields: DataFieldOneToManyInput!` — field values to set on creation
|
|
138
|
-
- `page: PageInput` — page-level fields (name, state, locations, etc.)
|
|
139
|
-
- `showHiddenData: Boolean`
|
|
140
|
-
- `stageId: ID` — target stage
|
|
141
|
-
- `submit: Boolean` — submit immediately
|
|
142
|
-
- `draft: Boolean` — create as draft
|
|
143
|
-
|
|
144
|
-
### `updatePage(input: UpdatePageInput!)` → `UpdatePagePayload`
|
|
145
|
-
|
|
146
|
-
Updates an existing page.
|
|
147
|
-
|
|
148
|
-
**Key `UpdatePageInput` fields:**
|
|
149
|
-
- `id: ID!`
|
|
150
|
-
- `patchVer: Int` — **MUST match current page patchVer**
|
|
151
|
-
- `page: PageInput` — page-level fields to change
|
|
152
|
-
- `dataFields: DataFieldOneToManyInput` — field updates and/or additions
|
|
153
|
-
- `stageId: ID` — target specific stage (required for stage submit/close-out)
|
|
154
|
-
- `submit: Boolean` — submit the stage (triggers task assignment server-side)
|
|
155
|
-
- `publish: Boolean` — publish a draft page
|
|
156
|
-
- `showHiddenData: Boolean`
|
|
157
|
-
|
|
158
|
-
**DataFieldOneToManyInput:**
|
|
159
|
-
```json
|
|
160
|
-
{
|
|
161
|
-
"updates": [{ "plainText": { "id": "FIELD_ID", "value": "..." } }],
|
|
162
|
-
"additions": [{ "date": { "id": "NEW_ID", "value": "..." } }],
|
|
163
|
-
"deletions": ["FIELD_ID_TO_DELETE"]
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### `archivePage(input: ArchivePageInput!)` / `unarchivePage(...)` → payload with `item: PageUnion`
|
|
168
|
-
|
|
169
|
-
Archive/unarchive a page.
|
|
170
|
-
|
|
171
|
-
**Production pattern (compound mutation):**
|
|
172
|
-
When a page has a unique `externalId`, archive the externalId first to prevent conflicts
|
|
173
|
-
on future re-creation, then archive:
|
|
174
|
-
|
|
175
|
-
```graphql
|
|
176
|
-
mutation ArchivePage($id: ID!, $blank_external_id: Boolean = true) {
|
|
177
|
-
updatePage(input: { id: $id, page: { externalId: null } })
|
|
178
|
-
@include(if: $blank_external_id) {
|
|
179
|
-
item { id externalId }
|
|
180
|
-
}
|
|
181
|
-
archivePage(input: { id: $id }) {
|
|
182
|
-
item { id archived }
|
|
183
|
-
errors { details fullMessages }
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
This compound mutation (two in one request) was designed for stateless middleware
|
|
189
|
-
clients that cannot sequence separate HTTP calls.
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
## Fragments
|
|
194
|
-
|
|
195
|
-
### `PageFields` (on `BasePageInterface`)
|
|
196
|
-
|
|
197
|
-
Core metadata fragment — always include `__typename` for `PageUnion` dispatch.
|
|
198
|
-
|
|
199
|
-
Fields: `__typename id name uid icon patchVer state archived archivedAt draft externalId
|
|
200
|
-
timeZone otherTags taskPriority sourceTemplateId createdAt updatedAt creatorName locations { ...LocationNode }`
|
|
201
|
-
|
|
202
|
-
**Gem:** `Fragment::PageFields` in `fragment/page.rb`
|
|
203
|
-
|
|
204
|
-
### `BasicPageFields` (on `BasicPage`)
|
|
205
|
-
|
|
206
|
-
Sections available directly on BasicPage:
|
|
207
|
-
```graphql
|
|
208
|
-
fragment BasicPageFields on BasicPage {
|
|
209
|
-
sections { __typename ... on ContentSection { id heading } ... on SplitSection { id heading } }
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
**Gem:** `Fragment::BasicPageFields`
|
|
214
|
-
|
|
215
|
-
### `PhasedPageFields` (on `PhasedPage`)
|
|
216
|
-
|
|
217
|
-
Stage index for phased pages (lightweight — no data fields):
|
|
218
|
-
```graphql
|
|
219
|
-
fragment PhasedPageFields on PhasedPage {
|
|
220
|
-
stagesIndex { id name ordering state started hasCompleteTask hasReviewTask }
|
|
221
|
-
currentStage { id name ordering state }
|
|
222
|
-
activeStages { id name ordering }
|
|
223
|
-
}
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
**Gem:** `Fragment::PhasedPageFields`
|
|
227
|
-
|
|
228
|
-
### `CommonPageUnion` (on `PageUnion`) — THE STANDARD FRAGMENT
|
|
229
|
-
|
|
230
|
-
The comprehensive fragment covering all customer integration patterns.
|
|
231
|
-
Located in `Fragment::Pages` (sub-namespace, accessed via `fragment.pages.assemble(:CommonPageUnion)`).
|
|
232
|
-
|
|
233
|
-
**Boolean variables controlling payload:**
|
|
234
|
-
|
|
235
|
-
| Variable | Purpose |
|
|
236
|
-
|---|---|
|
|
237
|
-
| `$content` | Include field values, stage completion info, files, people |
|
|
238
|
-
| `$only_content` | Exclude structural/config — content values only |
|
|
239
|
-
| `$fields` | Include field definitions (labels, types, options — needed for mutation input building) |
|
|
240
|
-
|
|
241
|
-
**Three use cases:**
|
|
242
|
-
1. **Build from template** — `$fields: true, $content: false` → get field structure + IDs
|
|
243
|
-
2. **Fetch before update** — `$content: true, $fields: true` → current values + IDs for mutation
|
|
244
|
-
3. **Verify after create/update** — `$content: true, $only_content: true` → confirm result
|
|
245
|
-
|
|
246
|
-
**Fragment source:** `lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb`
|
|
247
|
-
**Documented in:** Jira API Docs space (Confluence APIDOCS)
|
|
248
|
-
|
|
249
|
-
### `LocationNode` (on `LocationNodeInterface`)
|
|
250
|
-
|
|
251
|
-
Location node fragment with ancestors and classifications. Automatically assembled
|
|
252
|
-
when `...LocationNode` appears in a query via the recursive `assemble_fragments` mechanism.
|
|
253
|
-
|
|
254
|
-
---
|
|
255
|
-
|
|
256
|
-
## Fragment Assembly (How It Works)
|
|
257
|
-
|
|
258
|
-
The gem scans query strings for `...FragmentName` spreads and assembles the needed
|
|
259
|
-
fragment definitions RECURSIVELY. A fragment that references another fragment
|
|
260
|
-
(e.g. `PageFields → ...LocationNode`) is resolved automatically.
|
|
261
|
-
|
|
262
|
-
Sub-namespaces (`Fragment::Pages`) are registered via `Fragment.register_namespace(Pages)`
|
|
263
|
-
so `Fragment.assemble(:CommonPageUnion)` finds it.
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
## Other Key Queries
|
|
268
|
-
|
|
269
|
-
### `contractorEntities(...)` → `ContractorEntityConnection`
|
|
270
|
-
### `actionCategories(...)` → `ActionCategoryConnection`
|
|
271
|
-
### `action(id:)` → `Action`
|
|
272
|
-
### `actions(...)` → `ActionConnection`
|
|
273
|
-
### `locationStructure(id:)` → `LocationStructure`
|
|
274
|
-
### `locationStructures(...)` → `LocationStructureConnection`
|
|
275
|
-
### `registers(...)` → register list
|
|
276
|
-
### `personMembers(...)` → `PersonMemberConnection`
|
|
277
|
-
### `pageDelta(...)` → cache invalidation
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
# EcoPortal Page Workflows
|
|
2
|
-
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## The 2-Step Create Sequence
|
|
6
|
-
|
|
7
|
-
Creating a page from a template ALWAYS requires two steps because MongoDB assigns field
|
|
8
|
-
IDs at creation time — the client must know these IDs to populate field values.
|
|
9
|
-
|
|
10
|
-
### Step A: Build from Template
|
|
11
|
-
|
|
12
|
-
```ruby
|
|
13
|
-
# GraphQL
|
|
14
|
-
payload = Mutation::Page::BuildFromTemplate.new(client).query(
|
|
15
|
-
input: { templateId: template_id, showHiddenData: true }
|
|
16
|
-
) do
|
|
17
|
-
item { spread :CommonPageUnion }
|
|
18
|
-
end
|
|
19
|
-
draft = payload.item
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
This returns a `PageUnion` with:
|
|
23
|
-
- All field definitions for the template (labels, types, options)
|
|
24
|
-
- Server-assigned field IDs (instance IDs, NOT template field IDs)
|
|
25
|
-
- Default values where configured
|
|
26
|
-
- Stage structure (for PhasedPage)
|
|
27
|
-
|
|
28
|
-
**Important:** The returned page is NOT persisted yet.
|
|
29
|
-
|
|
30
|
-
### Step B: Fill and Create
|
|
31
|
-
|
|
32
|
-
```ruby
|
|
33
|
-
# Modify fields using the instance field IDs from the draft
|
|
34
|
-
draft.components.get_by_name('Job Number').value = 'JOB-001'
|
|
35
|
-
draft.components.get_by_type(:select).find { |f| f.label == 'Status' }.select_option('Active')
|
|
36
|
-
|
|
37
|
-
# Build field updates from dirty fields
|
|
38
|
-
field_updates = draft.data_fields_updates # → [DataFieldInput, ...]
|
|
39
|
-
|
|
40
|
-
# Create the page
|
|
41
|
-
payload = Mutation::Page::CreateFromTemplate.new(client).query(
|
|
42
|
-
input: {
|
|
43
|
-
templateId: template_id,
|
|
44
|
-
dataFields: { updates: field_updates }, # uses instance field IDs from draft
|
|
45
|
-
page: { externalId: 'EXT-001', name: 'My Record' }
|
|
46
|
-
}
|
|
47
|
-
)
|
|
48
|
-
ref = Compat::PageReference.new(payload.item)
|
|
49
|
-
# ref.page_id → the created page's ID
|
|
50
|
-
# ref.active_stage_id → ID of the first active stage
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## The 2-Step Update Sequence
|
|
56
|
-
|
|
57
|
-
Updating a page ALWAYS requires fetching first to get:
|
|
58
|
-
1. `patchVer` — required for optimistic concurrency
|
|
59
|
-
2. Current field IDs — for building `dataFields.updates`
|
|
60
|
-
3. Current field values — for computing changes
|
|
61
|
-
|
|
62
|
-
### Step A: Fetch Current Page
|
|
63
|
-
|
|
64
|
-
```ruby
|
|
65
|
-
page = Query::Page.new(client).query(id: page_id) do
|
|
66
|
-
spread :CommonPageUnion
|
|
67
|
-
end
|
|
68
|
-
# OR via compat layer:
|
|
69
|
-
page = graphql.pages.get(page_id)
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Step B: Modify and Update
|
|
73
|
-
|
|
74
|
-
```ruby
|
|
75
|
-
# Modify page-level fields
|
|
76
|
-
page.name = 'Updated Name'
|
|
77
|
-
page.external_id = 'NEW-EXT-001'
|
|
78
|
-
|
|
79
|
-
# Modify data fields
|
|
80
|
-
page.components.get_by_name('Summary').value = 'Updated summary'
|
|
81
|
-
|
|
82
|
-
# Send update
|
|
83
|
-
input = Input::Page::Update.from_model(page)
|
|
84
|
-
# input[:patchVer] — injected automatically from page.patchVer
|
|
85
|
-
# input[:page] — page-level changes
|
|
86
|
-
# input[:dataFields] — field-level changes
|
|
87
|
-
payload = Builder::Page.new(client).update(input: input)
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**Why patchVer matters:** If two scripts update the same page concurrently, the second
|
|
91
|
-
update will fail with a stale-patchVer error. Re-fetch the page to get the new patchVer.
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## Stage Submit / Close-Out Sequence
|
|
96
|
-
|
|
97
|
-
When a stage needs to be submitted (triggering task assignment on the next stage):
|
|
98
|
-
|
|
99
|
-
```ruby
|
|
100
|
-
# Fetch page with full stage data
|
|
101
|
-
page = graphql.pages.get(page_id)
|
|
102
|
-
|
|
103
|
-
# Get stage view for the specific stage
|
|
104
|
-
stage_view = graphql.pages.get(page_id, stage_id: 's1_id')
|
|
105
|
-
# stage_view.sections, stage_view.components → filtered to this stage only
|
|
106
|
-
|
|
107
|
-
# Fill in field data for this stage
|
|
108
|
-
stage_view.components.get_by_name('Risk Level').select_option('High')
|
|
109
|
-
|
|
110
|
-
# Submit the stage
|
|
111
|
-
input = Input::Page::Update.from_model(
|
|
112
|
-
stage_view,
|
|
113
|
-
stage_id: 's1_id',
|
|
114
|
-
submit: true
|
|
115
|
-
)
|
|
116
|
-
payload = Builder::Page.new(client).update(input: input)
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
**What `submit: true` triggers server-side:**
|
|
120
|
-
- Stage state changes to `complete`
|
|
121
|
-
- Next fill-in task (`CompletePage`) is created and assigned per workflow rules
|
|
122
|
-
- Or if review is configured: `ReviewPage` task is created
|
|
123
|
-
- People fields scoped to the next stage may generate access grants
|
|
124
|
-
|
|
125
|
-
**Important:** Without `stageId`, the server may not correctly associate the submit
|
|
126
|
-
with the right stage. Always include `stageId` when submitting a specific stage.
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## Archive Sequence
|
|
131
|
-
|
|
132
|
-
Standard archive (no externalId concern):
|
|
133
|
-
```ruby
|
|
134
|
-
payload = Builder::Page.new(client).archive(input: { id: page_id })
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
With externalId blanking (production pattern for deduplication safety):
|
|
138
|
-
```graphql
|
|
139
|
-
mutation ArchivePage($id: ID!, $blank_external_id: Boolean = true) {
|
|
140
|
-
updatePage(input: { id: $id, page: { externalId: null } })
|
|
141
|
-
@include(if: $blank_external_id) {
|
|
142
|
-
item { id }
|
|
143
|
-
}
|
|
144
|
-
archivePage(input: { id: $id }) {
|
|
145
|
-
item { id archived }
|
|
146
|
-
errors { details fullMessages }
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## Find-Before-Create (Deduplication Pattern)
|
|
154
|
-
|
|
155
|
-
To prevent creating duplicate pages based on a unique identifier:
|
|
156
|
-
|
|
157
|
-
```ruby
|
|
158
|
-
# Step 1: Search for existing page
|
|
159
|
-
conf = SearchConf.new
|
|
160
|
-
.filter(SearchConf::Register.new(register_id))
|
|
161
|
-
.filter(SearchConf::Exact.new(:external_id, 'EXT-001'))
|
|
162
|
-
|
|
163
|
-
result = org.pages(searchConf: conf.to_h, first: 1)
|
|
164
|
-
existing = result.nodes.first
|
|
165
|
-
|
|
166
|
-
if existing
|
|
167
|
-
# Page exists — update it
|
|
168
|
-
page = graphql.pages.get(existing.id)
|
|
169
|
-
# ... modify and update
|
|
170
|
-
else
|
|
171
|
-
# Page doesn't exist — create it
|
|
172
|
-
draft = graphql.pages.get_new(template_id)
|
|
173
|
-
# ... fill and create
|
|
174
|
-
end
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
**Why org search (not register search):** Register search (`previewPages`) is ES-backed
|
|
178
|
-
and fast, but returns `PreviewPage` without field IDs or `patchVer`. For update workflows,
|
|
179
|
-
always use org search (`pages`) with `register_filter` to get the full page.
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## Simulate / Dry Run Mode (eco-helpers Pattern)
|
|
184
|
-
|
|
185
|
-
eco-helpers scripts support a dry-run mode where changes are computed but not sent:
|
|
186
|
-
|
|
187
|
-
```ruby
|
|
188
|
-
# In eco-helpers, dirty? checks for pending changes
|
|
189
|
-
if dirty?(page)
|
|
190
|
-
if simulate?
|
|
191
|
-
puts "Would update: #{pages.get_body(page).inspect}"
|
|
192
|
-
else
|
|
193
|
-
pages.update(page)
|
|
194
|
-
page.consolidate! # reset dirty tracking
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
The `get_body(page)` method returns `page.as_update` — the computed change diff.
|
|
200
|
-
`consolidate!` resets the `original_doc` baseline so the page is no longer dirty.
|
|
@@ -1,228 +0,0 @@
|
|
|
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.
|