ecoportal-api-graphql 1.3.17 → 2.2.1

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.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +763 -11
  3. data/lib/ecoportal/api/common/graphql/http_client.rb +85 -2
  4. data/lib/ecoportal/api/common/graphql/model/diffable/leaf_diff_service.rb +97 -0
  5. data/lib/ecoportal/api/common/graphql/model/diffable.rb +1 -0
  6. data/lib/ecoportal/api/graphql/base/action.rb +1 -1
  7. data/lib/ecoportal/api/graphql/base/action_event.rb +23 -0
  8. data/lib/ecoportal/api/graphql/base/action_event_page.rb +16 -0
  9. data/lib/ecoportal/api/graphql/base/activity.rb +38 -0
  10. data/lib/ecoportal/api/graphql/base/activity_log.rb +38 -0
  11. data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +12 -7
  12. data/lib/ecoportal/api/graphql/base/auth_log.rb +24 -0
  13. data/lib/ecoportal/api/graphql/base/authorization_result.rb +20 -0
  14. data/lib/ecoportal/api/graphql/base/contractor_entity/member_changes.rb +17 -5
  15. data/lib/ecoportal/api/graphql/base/file_container.rb +12 -4
  16. data/lib/ecoportal/api/graphql/base/location_classification_type.rb +2 -0
  17. data/lib/ecoportal/api/graphql/base/location_structure.rb +3 -0
  18. data/lib/ecoportal/api/graphql/base/minimal_dashboard.rb +25 -0
  19. data/lib/ecoportal/api/graphql/base/organization.rb +2 -0
  20. data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +25 -2
  21. data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +46 -7
  22. data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +5 -2
  23. data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +50 -12
  24. data/lib/ecoportal/api/graphql/base/page/data_field.rb +12 -18
  25. data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +51 -0
  26. data/lib/ecoportal/api/graphql/base/permissions.rb +15 -0
  27. data/lib/ecoportal/api/graphql/base/person_member_changelog.rb +23 -0
  28. data/lib/ecoportal/api/graphql/base/preset_view.rb +135 -0
  29. data/lib/ecoportal/api/graphql/base/register.rb +5 -0
  30. data/lib/ecoportal/api/graphql/base/template/change_log_entry.rb +118 -0
  31. data/lib/ecoportal/api/graphql/base/template.rb +2 -0
  32. data/lib/ecoportal/api/graphql/base.rb +9 -0
  33. data/lib/ecoportal/api/graphql/builder/contractor_entity.rb +10 -0
  34. data/lib/ecoportal/api/graphql/builder/page.rb +0 -16
  35. data/lib/ecoportal/api/graphql/builder/template.rb +46 -0
  36. data/lib/ecoportal/api/graphql/builder/template_builder.rb +21 -2
  37. data/lib/ecoportal/api/graphql/compat/pages.rb +7 -2
  38. data/lib/ecoportal/api/graphql/compat/response.rb +14 -0
  39. data/lib/ecoportal/api/graphql/concerns/threadable.rb +58 -0
  40. data/lib/ecoportal/api/graphql/concerns.rb +1 -0
  41. data/lib/ecoportal/api/graphql/connection/action.rb +1 -1
  42. data/lib/ecoportal/api/graphql/connection/action_category.rb +1 -1
  43. data/lib/ecoportal/api/graphql/connection/activity.rb +11 -0
  44. data/lib/ecoportal/api/graphql/connection/activity_log.rb +11 -0
  45. data/lib/ecoportal/api/graphql/connection/auth_log.rb +11 -0
  46. data/lib/ecoportal/api/graphql/connection/contractor_entity.rb +1 -1
  47. data/lib/ecoportal/api/graphql/connection/minimal_dashboard.rb +11 -0
  48. data/lib/ecoportal/api/graphql/connection/page.rb +1 -1
  49. data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +1 -1
  50. data/lib/ecoportal/api/graphql/connection/person_member.rb +1 -1
  51. data/lib/ecoportal/api/graphql/connection/person_member_changelog.rb +11 -0
  52. data/lib/ecoportal/api/graphql/connection/preview_page.rb +1 -1
  53. data/lib/ecoportal/api/graphql/connection/template_change_log.rb +19 -0
  54. data/lib/ecoportal/api/graphql/connection.rb +6 -0
  55. data/lib/ecoportal/api/graphql/diff/change.rb +7 -2
  56. data/lib/ecoportal/api/graphql/diff/command_synthesizer.rb +19 -1
  57. data/lib/ecoportal/api/graphql/diff/pairing/signals.rb +21 -1
  58. data/lib/ecoportal/api/graphql/diff/version_diff.rb +13 -6
  59. data/lib/ecoportal/api/graphql/file_upload/client.rb +198 -139
  60. data/lib/ecoportal/api/graphql/fragment/activity.rb +84 -0
  61. data/lib/ecoportal/api/graphql/fragment/activity_log.rb +75 -0
  62. data/lib/ecoportal/api/graphql/fragment/auth_log.rb +29 -0
  63. data/lib/ecoportal/api/graphql/fragment/authorization_result.rb +14 -0
  64. data/lib/ecoportal/api/graphql/fragment/location_node.rb +1 -0
  65. data/lib/ecoportal/api/graphql/fragment/minimal_dashboard.rb +31 -0
  66. data/lib/ecoportal/api/graphql/fragment/page.rb +1 -0
  67. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +23 -0
  68. data/lib/ecoportal/api/graphql/fragment/permissions.rb +96 -0
  69. data/lib/ecoportal/api/graphql/fragment/person_member_changelog.rb +33 -0
  70. data/lib/ecoportal/api/graphql/fragment/template_change_log.rb +102 -0
  71. data/lib/ecoportal/api/graphql/fragment.rb +8 -0
  72. data/lib/ecoportal/api/graphql/input/action/update.rb +12 -0
  73. data/lib/ecoportal/api/graphql/input/contractor_entity/manager_settings.rb +20 -0
  74. data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +6 -27
  75. data/lib/ecoportal/api/graphql/input/contractor_entity.rb +1 -0
  76. data/lib/ecoportal/api/graphql/input/date_range.rb +16 -0
  77. data/lib/ecoportal/api/graphql/input/location_structure/apply_commands.rb +2 -2
  78. data/lib/ecoportal/api/graphql/input/location_structure/draft/add_commands.rb +2 -2
  79. data/lib/ecoportal/api/graphql/input/location_structure/insert_command.rb +8 -0
  80. data/lib/ecoportal/api/graphql/input/location_structure/update_command.rb +6 -2
  81. data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -1
  82. data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -1
  83. data/lib/ecoportal/api/graphql/input/workflow_command/add_checklist_field_item.rb +19 -0
  84. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +10 -9
  85. data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +11 -5
  86. data/lib/ecoportal/api/graphql/input/workflow_command/add_smart_fill_config.rb +23 -0
  87. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +3 -2
  88. data/lib/ecoportal/api/graphql/input/workflow_command/add_viewable_field.rb +45 -0
  89. data/lib/ecoportal/api/graphql/input/workflow_command/archive_public_config.rb +19 -0
  90. data/lib/ecoportal/api/graphql/input/workflow_command/create_public_config.rb +19 -0
  91. data/lib/ecoportal/api/graphql/input/workflow_command/edit_checklist_field_item.rb +19 -0
  92. data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +17 -2
  93. data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +5 -2
  94. data/lib/ecoportal/api/graphql/input/workflow_command/edit_public_config.rb +19 -0
  95. data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +6 -2
  96. data/lib/ecoportal/api/graphql/input/workflow_command/edit_smart_fill_config.rb +21 -0
  97. data/lib/ecoportal/api/graphql/input/workflow_command/edit_template_advanced_settings.rb +19 -0
  98. data/lib/ecoportal/api/graphql/input/workflow_command/edit_template_basic_settings.rb +32 -0
  99. data/lib/ecoportal/api/graphql/input/workflow_command/edit_template_container_uid.rb +45 -0
  100. data/lib/ecoportal/api/graphql/input/workflow_command/{edit_page_creator_permissions.rb → edit_template_creator_permissions.rb} +3 -2
  101. data/lib/ecoportal/api/graphql/input/workflow_command/edit_template_descriptions.rb +19 -0
  102. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/action_list.rb +31 -0
  103. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +6 -2
  104. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +9 -1
  105. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +15 -2
  106. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/file.rb +21 -0
  107. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +3 -2
  108. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +27 -3
  109. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +9 -2
  110. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +3 -2
  111. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +3 -2
  112. data/lib/ecoportal/api/graphql/input/workflow_command/manage_copy_page_configuration.rb +47 -0
  113. data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +3 -2
  114. data/lib/ecoportal/api/graphql/input/workflow_command/move_section_to_stage.rb +33 -0
  115. data/lib/ecoportal/api/graphql/input/workflow_command/move_viewable_field.rb +33 -0
  116. data/lib/ecoportal/api/graphql/input/workflow_command/remove_checklist_field_item.rb +19 -0
  117. data/lib/ecoportal/api/graphql/input/workflow_command/remove_smart_fill_config.rb +19 -0
  118. data/lib/ecoportal/api/graphql/input/workflow_command/remove_viewable_field.rb +21 -0
  119. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +3 -2
  120. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +3 -2
  121. data/lib/ecoportal/api/graphql/input/workflow_command.rb +48 -5
  122. data/lib/ecoportal/api/graphql/input.rb +1 -0
  123. data/lib/ecoportal/api/graphql/interface/base_page.rb +50 -3
  124. data/lib/ecoportal/api/graphql/interface/location_structure/command.rb +2 -1
  125. data/lib/ecoportal/api/graphql/logic/base_query.rb +72 -5
  126. data/lib/ecoportal/api/graphql/logic/connection.rb +17 -0
  127. data/lib/ecoportal/api/graphql/logic/input.rb +127 -0
  128. data/lib/ecoportal/api/graphql/model/action_event.rb +14 -0
  129. data/lib/ecoportal/api/graphql/model/action_event_page.rb +10 -0
  130. data/lib/ecoportal/api/graphql/model/activity.rb +14 -0
  131. data/lib/ecoportal/api/graphql/model/activity_log.rb +31 -0
  132. data/lib/ecoportal/api/graphql/model/auth_log.rb +11 -0
  133. data/lib/ecoportal/api/graphql/model/authorization_result.rb +12 -0
  134. data/lib/ecoportal/api/graphql/model/minimal_dashboard.rb +14 -0
  135. data/lib/ecoportal/api/graphql/model/organization.rb +36 -0
  136. data/lib/ecoportal/api/graphql/model/page/phased.rb +17 -0
  137. data/lib/ecoportal/api/graphql/model/permissions.rb +185 -0
  138. data/lib/ecoportal/api/graphql/model/person_member.rb +7 -0
  139. data/lib/ecoportal/api/graphql/model/person_member_changelog.rb +15 -0
  140. data/lib/ecoportal/api/graphql/model/template/change_log_entry.rb +19 -0
  141. data/lib/ecoportal/api/graphql/model/template.rb +4 -1
  142. data/lib/ecoportal/api/graphql/model.rb +9 -0
  143. data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +20 -10
  144. data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +25 -10
  145. data/lib/ecoportal/api/graphql/mutation/contractor_entity/update_manager_settings.rb +37 -0
  146. data/lib/ecoportal/api/graphql/mutation/contractor_entity.rb +1 -0
  147. data/lib/ecoportal/api/graphql/mutation/file_container/upload.rb +78 -0
  148. data/lib/ecoportal/api/graphql/mutation/file_container.rb +15 -0
  149. data/lib/ecoportal/api/graphql/mutation/template/update_related_page.rb +79 -0
  150. data/lib/ecoportal/api/graphql/mutation/template.rb +1 -0
  151. data/lib/ecoportal/api/graphql/mutation.rb +1 -1
  152. data/lib/ecoportal/api/graphql/payload/contractor_entity/manager_settings.rb +20 -0
  153. data/lib/ecoportal/api/graphql/payload/contractor_entity.rb +1 -0
  154. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +2 -2
  155. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +2 -2
  156. data/lib/ecoportal/api/graphql/payload/template/update_related_page.rb +15 -0
  157. data/lib/ecoportal/api/graphql/payload/template.rb +1 -0
  158. data/lib/ecoportal/api/graphql/payload/upload.rb +12 -0
  159. data/lib/ecoportal/api/graphql/payload.rb +1 -0
  160. data/lib/ecoportal/api/graphql/query/activity_logs.rb +78 -0
  161. data/lib/ecoportal/api/graphql/query/auth_logs.rb +51 -0
  162. data/lib/ecoportal/api/graphql/query/dashboard_search.rb +57 -0
  163. data/lib/ecoportal/api/graphql/query/location_structure.rb +2 -0
  164. data/lib/ecoportal/api/graphql/query/location_structures.rb +2 -0
  165. data/lib/ecoportal/api/graphql/query/page.rb +6 -1
  166. data/lib/ecoportal/api/graphql/query/page_activities.rb +56 -0
  167. data/lib/ecoportal/api/graphql/query/permissions.rb +35 -0
  168. data/lib/ecoportal/api/graphql/query/person_member_changelogs.rb +53 -0
  169. data/lib/ecoportal/api/graphql/query/person_members.rb +76 -0
  170. data/lib/ecoportal/api/graphql/query/template_change_log.rb +118 -0
  171. data/lib/ecoportal/api/graphql/query.rb +8 -0
  172. data/lib/ecoportal/api/graphql_version.rb +1 -1
  173. metadata +83 -14
  174. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +0 -28
  175. data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +0 -36
  176. data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +0 -40
  177. data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +0 -13
@@ -61,6 +61,7 @@ module Ecoportal
61
61
  fragment stageAttrs on Stage {
62
62
  id @skip(if: $only_content)
63
63
  name
64
+ tags
64
65
  ...sectionsFragment
65
66
  active
66
67
  started
@@ -85,6 +86,7 @@ module Ecoportal
85
86
  name
86
87
  uid
87
88
  locations { ...locationNode }
89
+ baseTags @include(if: $content)
88
90
  otherTags @include(if: $content)
89
91
  timeZone
90
92
  updatedAt { dateTime }
@@ -92,6 +94,16 @@ module Ecoportal
92
94
  creator { name email }
93
95
  state
94
96
  archived
97
+ # Cross-version template identity. `template` is non-null only on template pages
98
+ # (`BasePageInterface.template: Template`), so this stays nil for records.
99
+ # `templateContainerUid` is the SERIES key: many versions may carry the same uid,
100
+ # but only one may be published (`active: true`) per organization at a time —
101
+ # publishing another with the same uid unpublishes the incumbent. See
102
+ # the repo's internal docs.
103
+ template @skip(if: $only_content) {
104
+ templateContainerUid
105
+ active
106
+ }
95
107
  }
96
108
 
97
109
  fragment sectionsFragment on Stage {
@@ -119,6 +131,16 @@ module Ecoportal
119
131
  __typename
120
132
  id @skip(if: $only_content)
121
133
  label
134
+ # Field-configuration `description` (the hidden per-field note). Read-only from
135
+ # here — the ONLY writer is the `editFieldConfiguration` workflow command
136
+ # (`WorkflowEditFieldConfigurationInput.description`); `DataFieldInput` and its
137
+ # per-type members carry no description, so `updatePage` cannot set it.
138
+ #
139
+ # Integrations use it as a pseudo external-id on fields (we do so on templates;
140
+ # customers do so on page instances — confirmed working on instances with a
141
+ # non-superuser service account, 2026-07-31). Fetched by default so those
142
+ # integrations can read it back.
143
+ description @skip(if: $only_content)
122
144
  genomeSignature @skip(if: $only_content)
123
145
  deindex @include(if: $content)
124
146
  linkedFieldConfig @skip(if: $only_content) {
@@ -232,6 +254,7 @@ module Ecoportal
232
254
  fragment fileField on File {
233
255
  required @skip(if: $only_content)
234
256
  items @include(if: $content) {
257
+ id
235
258
  fileContainer { ...fileContainerAttrs }
236
259
  }
237
260
  }
@@ -0,0 +1,96 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ class Fragment
5
+ # Selects every canXXX permission on the Permissions type, spreading :AuthorizationResult
6
+ # ({ value message }) for each. Requires the :AuthorizationResult fragment to be assembled
7
+ # alongside (Fragment.assemble(:Permissions, :AuthorizationResult)).
8
+ fragment :Permissions, <<~GRAPHQL
9
+ fragment Permissions on Permissions {
10
+ actionCanCreateStandalone { ...AuthorizationResult }
11
+ actionCanIndex { ...AuthorizationResult }
12
+ alertNotificationCanAccessBroadcastNotifications { ...AuthorizationResult }
13
+ alertNotificationCanCreate { ...AuthorizationResult }
14
+ alertNotificationCanIndex { ...AuthorizationResult }
15
+ canAccessAdminTools { ...AuthorizationResult }
16
+ canAccessPeopleManager { ...AuthorizationResult }
17
+ canDeleteActionCategories { ...AuthorizationResult }
18
+ canIndex { ...AuthorizationResult }
19
+ canListAttachablePersonMembers { ...AuthorizationResult }
20
+ canManageActionCategories { ...AuthorizationResult }
21
+ canManageStandaloneActionsPermissions { ...AuthorizationResult }
22
+ canResetActionsCounter { ...AuthorizationResult }
23
+ canUpload { ...AuthorizationResult }
24
+ contractorEntityCanAccessContractorManager { ...AuthorizationResult }
25
+ contractorEntityCanAttach { ...AuthorizationResult }
26
+ contractorEntityCanCreate { ...AuthorizationResult }
27
+ contractorEntityCanDestroy { ...AuthorizationResult }
28
+ contractorEntityCanEdit { ...AuthorizationResult }
29
+ contractorEntityCanEditLinkedUsers { ...AuthorizationResult }
30
+ contractorEntityCanIndex { ...AuthorizationResult }
31
+ contractorEntityCanManageParentContractors { ...AuthorizationResult }
32
+ contractorEntityCanManageSubcontractors { ...AuthorizationResult }
33
+ crossReferenceReportsCanIndex { ...AuthorizationResult }
34
+ dashboardCanManage { ...AuthorizationResult }
35
+ dataSetsCanIndex { ...AuthorizationResult }
36
+ dataSpaceCanShow { ...AuthorizationResult }
37
+ dataViewsCanIndex { ...AuthorizationResult }
38
+ emailReportCanConfigureSmartReport { ...AuthorizationResult }
39
+ filesCanIndex { ...AuthorizationResult }
40
+ filesCanUpload { ...AuthorizationResult }
41
+ generatedPageFilterCanCreate { ...AuthorizationResult }
42
+ generatedPageFilterCanUseSmartQuery { ...AuthorizationResult }
43
+ hasFileAbilityToDownload { ...AuthorizationResult }
44
+ locationClassificationsCanCreate { ...AuthorizationResult }
45
+ locationClassificationsCanUpdate { ...AuthorizationResult }
46
+ locationStructuresCanAccess { ...AuthorizationResult }
47
+ locationStructuresCanAdministrate { ...AuthorizationResult }
48
+ locationStructuresCanAiGenerateStructure { ...AuthorizationResult }
49
+ locationStructuresCanCreate { ...AuthorizationResult }
50
+ locationStructuresCanManage { ...AuthorizationResult }
51
+ locationStructuresCanManageSftpIntegration { ...AuthorizationResult }
52
+ locationStructuresCanPublish { ...AuthorizationResult }
53
+ locationStructuresCanRead { ...AuthorizationResult }
54
+ locationStructuresCanScheduleUpdate { ...AuthorizationResult }
55
+ locationStructuresCanUpdate { ...AuthorizationResult }
56
+ organizationCanViewSettings { ...AuthorizationResult }
57
+ pageAiSummaryCanAccess { ...AuthorizationResult }
58
+ pageCanListDrafts { ...AuthorizationResult }
59
+ pageCanRestore { ...AuthorizationResult }
60
+ pageCanUseDrafts { ...AuthorizationResult }
61
+ personSchemaCanAccessManager { ...AuthorizationResult }
62
+ publicTemplatesCanCopyLink { ...AuthorizationResult }
63
+ publicTemplatesCanIndex { ...AuthorizationResult }
64
+ publicTemplatesCanListEntries { ...AuthorizationResult }
65
+ publicTemplatesCanManage { ...AuthorizationResult }
66
+ registerCanAccessRegisterTools { ...AuthorizationResult }
67
+ registerCanCreate { ...AuthorizationResult }
68
+ registerCanLimitTemplates { ...AuthorizationResult }
69
+ scimIntegrationCanAddCodeHooks { ...AuthorizationResult }
70
+ scimIntegrationCanCreate { ...AuthorizationResult }
71
+ scimIntegrationCanDestroy { ...AuthorizationResult }
72
+ scimIntegrationCanGenerateApiKey { ...AuthorizationResult }
73
+ scimIntegrationCanIndex { ...AuthorizationResult }
74
+ scimIntegrationCanShow { ...AuthorizationResult }
75
+ scimIntegrationCanShowLogs { ...AuthorizationResult }
76
+ scimIntegrationCanUpdate { ...AuthorizationResult }
77
+ spatialCanUpdateLocationNodeGeojson { ...AuthorizationResult }
78
+ structuresCanIndex { ...AuthorizationResult }
79
+ templateCanRestore { ...AuthorizationResult }
80
+ userAccessLogsCanShow { ...AuthorizationResult }
81
+ userCanAccessAdminArea { ...AuthorizationResult }
82
+ userCanAccessPageCreationTools { ...AuthorizationResult }
83
+ visitorLogCanAdminCheckIn { ...AuthorizationResult }
84
+ visitorLogCanEdit { ...AuthorizationResult }
85
+ visitorLogCanManage { ...AuthorizationResult }
86
+ visitorLogCanShow { ...AuthorizationResult }
87
+ visitorManagementCanAccessVisitorManager { ...AuthorizationResult }
88
+ visitorManagementCanIndex { ...AuthorizationResult }
89
+ webhooksCanManageSubscriptions { ...AuthorizationResult }
90
+ webhooksCanViewSubscriptions { ...AuthorizationResult }
91
+ }
92
+ GRAPHQL
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,33 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ class Fragment
5
+ fragment :PersonMemberChangelog, <<~GRAPHQL
6
+ fragment PersonMemberChangelog on PersonMemberChangelog {
7
+ id
8
+ operation
9
+ accountOperation
10
+ personMemberId
11
+ apiKeyPrefix
12
+ changedByApi
13
+ humanReadableDifferences
14
+ createdAt {
15
+ dateTime
16
+ timeZone
17
+ }
18
+ personMember {
19
+ id
20
+ name
21
+ email
22
+ }
23
+ user {
24
+ id
25
+ email
26
+ name
27
+ }
28
+ }
29
+ GRAPHQL
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,102 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ class Fragment
5
+ # Node selection for a TEMPLATE change-log entry — `template { commands { nodes } }`.
6
+ #
7
+ # The type condition is the INTERFACE `PagesWorkflowCommandInterface`
8
+ # (`app/graphql/types/pages/interfaces/workflow_command_interface.rb`, graphql_name set
9
+ # explicitly there). Spreading a fragment on an interface at an interface-typed location
10
+ # is legal; selecting a CONCRETE type's field (e.g. `changes`, `changeMessages`) is not,
11
+ # unless wrapped in an inline fragment. Everything below is therefore an interface field,
12
+ # plus `__typename` so callers can branch on the concrete command class.
13
+ #
14
+ # Deliberately NOT selected, and why:
15
+ # - `stage: StageType` and `task: TaskInterface` — object subtrees; `stageId`/`stageName`
16
+ # and `taskId`/`taskType` already answer "which stage / which task" as scalars, and
17
+ # both resolvers do an extra RecordLoader/EmbeddedObjectLoader round trip. Select them
18
+ # explicitly with a custom connection block if you need the full objects.
19
+ # - the concrete-type extras (`changes { field from to }`, `changeMessages`) — see
20
+ # `Fragment :PagesWorkflowCommandFields` in `fragment/pages_workflow.rb`, which already
21
+ # models them for the workflow-builder side of the same interface.
22
+ #
23
+ # See `Base::Template::ChangeLogEntry` for the two access caveats (nil-when-unpermitted,
24
+ # TEMPLATE_BUILDER-only) and the forces watermark blind spot.
25
+ fragment :TemplateChangeLogEntry, <<~GRAPHQL
26
+ fragment TemplateChangeLogEntry on PagesWorkflowCommandInterface {
27
+ __typename
28
+ id
29
+ commandAction
30
+ patchVer
31
+ createdAt {
32
+ dateTime
33
+ timeZone
34
+ }
35
+ updatedAt {
36
+ dateTime
37
+ timeZone
38
+ }
39
+ ownerId
40
+ owner {
41
+ id
42
+ name
43
+ email
44
+ }
45
+ stageId
46
+ stageName
47
+ taskId
48
+ taskType
49
+ targetedResourceId
50
+ targetedResourceName
51
+ targetedResourceType
52
+ }
53
+ GRAPHQL
54
+
55
+ # DETAIL selection — the same entry PLUS what actually changed.
56
+ #
57
+ # Opt in to this only when you need it: it costs three inline fragments and their
58
+ # sub-selections on every node. `Query::TemplateChangeLog.detail_block` and
59
+ # `api.template.change_log(detail: true)` both use it; the light
60
+ # `:TemplateChangeLogEntry` above stays the default so "who changed this, and when"
61
+ # does not pay for per-type detail.
62
+ #
63
+ # ★ The three concrete types report changes DIFFERENTLY, verified against the backend
64
+ # (2026-08-20) — this is why one flat shape cannot describe them:
65
+ # - `PagesWorkflowCommandChange.changes: [ChangeType!]!` — `ChangeType` is
66
+ # `{ field: String!, from: String, to: String }` (`app/graphql/types/change_type.rb`),
67
+ # i.e. before/after as STRINGS. This is the common case.
68
+ # - `PagesWorkflowCommandChangeMessage.changeMessages` — pre-rendered human strings, no
69
+ # field/from/to at all.
70
+ # - `PagesWorkflowCommandEsChange.changes: [StoredEsFilterChangeType!]!` where `from`/`to`
71
+ # are `StoredEsFilterType` OBJECTS, not strings
72
+ # (`app/graphql/types/stored_es_filter_change_type.rb`). Only `field` is selected here,
73
+ # deliberately: naming which filter changed is useful, and `StoredEsFilterType`'s own
74
+ # shape has not been verified, so selecting into it would be a guess. An ES-change entry
75
+ # therefore tells you WHICH filter moved, not its before/after.
76
+ # (Reached via `WorkflowCallbacks::EditTrigger` — see the interface's `resolve_type`.)
77
+ #
78
+ # So branch on `__typename` (or ask `entry.detail_kind`) before reading `changes`.
79
+ fragment :TemplateChangeLogEntryDetail, <<~GRAPHQL
80
+ fragment TemplateChangeLogEntryDetail on PagesWorkflowCommandInterface {
81
+ ...TemplateChangeLogEntry
82
+ ... on PagesWorkflowCommandChange {
83
+ changes {
84
+ field
85
+ from
86
+ to
87
+ }
88
+ }
89
+ ... on PagesWorkflowCommandChangeMessage {
90
+ changeMessages
91
+ }
92
+ ... on PagesWorkflowCommandEsChange {
93
+ changes {
94
+ field
95
+ }
96
+ }
97
+ }
98
+ GRAPHQL
99
+ end
100
+ end
101
+ end
102
+ end
@@ -35,6 +35,14 @@ require_relative 'fragment/page'
35
35
  require_relative 'fragment/pages'
36
36
  require_relative 'fragment/force'
37
37
  require_relative 'fragment/pages_workflow'
38
+ require_relative 'fragment/authorization_result'
39
+ require_relative 'fragment/permissions'
40
+ require_relative 'fragment/activity'
41
+ require_relative 'fragment/activity_log'
42
+ require_relative 'fragment/auth_log'
43
+ require_relative 'fragment/person_member_changelog'
44
+ require_relative 'fragment/minimal_dashboard'
38
45
  require_relative 'fragment/field_configuration'
39
46
  require_relative 'fragment/page_task'
40
47
  require_relative 'fragment/template'
48
+ require_relative 'fragment/template_change_log'
@@ -4,8 +4,20 @@ module Ecoportal
4
4
  module Input
5
5
  module Action
6
6
  class Update < Ecoportal::API::GraphQL::Base::Action
7
+ extend Logic::Input::FullArrayFields
8
+
7
9
  passthrough :clientMutationId
8
10
  passthrough :updateMode
11
+
12
+ # Base::Action is `root!`, so its own `as_update` never emits its array fields — an
13
+ # unaugmented Action::Update produced nothing for changed id-lists. The macro gives it
14
+ # emission, reading the full current array directly from doc vs original_doc.
15
+ #
16
+ # Schema (live introspection 20260605, UpdateActionInput): these are plain `[ID!]`,
17
+ # NOT IdDiffInput — the server expects the COMPLETE array, not additions/removals
18
+ # deltas. Hence `full_array_fields`, not `id_diff_fields` (contrast ContractorEntity,
19
+ # whose associatedPeopleIds/leadContractorIds ARE IdDiffInput).
20
+ full_array_fields :assignedPersonMemberIds, :locationIds, :fileContainerIds
9
21
  end
10
22
  end
11
23
  end
@@ -0,0 +1,20 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Input
5
+ module ContractorEntity
6
+ # Input for the `updateContractorManagerSettings` mutation (2026-07 schema;
7
+ # renamed from the removed `updateCmAutoApprovalsSettings` / CmAutoApprovalsSettingsInput,
8
+ # which this gem never modelled).
9
+ #
10
+ # `cmAutoApprovalsSettings` is a required AutoApprovalsInput
11
+ # ({ enabled:, approvalConditions: }); pass it as a Hash.
12
+ class ManagerSettings < Logic::Input
13
+ passthrough :cmAutoApprovalsSettings
14
+ passboolean :allowContractorAdminsToAddAdmins
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -4,35 +4,14 @@ module Ecoportal
4
4
  module Input
5
5
  module ContractorEntity
6
6
  class Update < Input::ContractorEntity::Create
7
- passthrough :clientMutationId
8
- class_resolver :id_diff_input, "Ecoportal::API::GraphQL::Input::IdDiff"
9
- embeds_one :associatedPeopleIds, klass: :id_diff_input
10
- embeds_one :leadContractorIds, klass: :id_diff_input
11
-
12
- ID_DIFF_FIELDS = %i[associatedPeopleIds leadContractorIds].freeze
13
-
14
- class << self
15
- # Overrides Logic::Input.from_model to reshape array fields into
16
- # IdDiffInput format: { additions: [...], removals: [...] }
17
- # Array fields are stripped from the flat diff, so we compare
18
- # doc vs original_doc directly rather than relying on the diff hash.
19
- def from_model(model, **kargs)
20
- diff = Logic::Input.from_model(model, **kargs)
7
+ extend Logic::Input::IdDiffFields
21
8
 
22
- ID_DIFF_FIELDS.each do |field|
23
- key = field.to_s
24
- current = Array(model.doc[key])
25
- original = Array(model.original_doc[key])
26
- next if current == original
27
-
28
- diff ||= {}
29
- diff[:id] ||= model.id
30
- diff[field] = { additions: current - original, removals: original - current }
31
- end
9
+ passthrough :clientMutationId
32
10
 
33
- diff
34
- end
35
- end
11
+ # `associatedPeopleIds` / `leadContractorIds` are exposed on UpdateContractorEntityInput
12
+ # as IdDiffInput { additions:, removals: }. The macro installs a `from_model` that
13
+ # computes each delta directly from the read model's doc vs original_doc arrays.
14
+ id_diff_fields :associatedPeopleIds, :leadContractorIds
36
15
  end
37
16
  end
38
17
  end
@@ -12,3 +12,4 @@ end
12
12
  require_relative 'contractor_entity/create'
13
13
  require_relative 'contractor_entity/destroy'
14
14
  require_relative 'contractor_entity/update'
15
+ require_relative 'contractor_entity/manager_settings'
@@ -0,0 +1,16 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Input
5
+ # DateRange input for filtering time-bounded queries (e.g. the
6
+ # `dateFilter` arg of `activityLogs`).
7
+ # from: ISO8601DateTime
8
+ # to: ISO8601DateTime
9
+ # Pass as: { from: '2026-07-01T00:00:00Z', to: '2026-07-14T00:00:00Z' }
10
+ class DateRange < Logic::BaseModel
11
+ passthrough :from, :to
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -33,8 +33,8 @@ module Ecoportal
33
33
  Input::LocationStructure::InsertCommand.new
34
34
  when :update
35
35
  Input::LocationStructure::UpdateCommand.new
36
- when :reoder
37
- Input::LocationStructure::ReoderCommand.new
36
+ when :reorder
37
+ Input::LocationStructure::ReorderCommand.new
38
38
  else
39
39
  raise "Unknown command type: '#{type}'"
40
40
  end
@@ -34,8 +34,8 @@ module Ecoportal
34
34
  Input::LocationStructure::InsertCommand.new
35
35
  when :update
36
36
  Input::LocationStructure::UpdateCommand.new
37
- when :reoder
38
- Input::LocationStructure::ReoderCommand.new
37
+ when :reorder
38
+ Input::LocationStructure::ReorderCommand.new
39
39
  else
40
40
  raise "Unknown command type: '#{type}'"
41
41
  end
@@ -3,7 +3,15 @@ module Ecoportal
3
3
  class GraphQL
4
4
  module Input
5
5
  module LocationStructure
6
+ # Backend evidence (app/graphql/types/inputs/locations/insert_input.rb:7-12, verified
7
+ # against C:\docker\ecoPortal_master): `name` is `required: true` -- without it, every
8
+ # insert is rejected by the backend. `keywords` ([String], optional) was also missing.
9
+ # Both are declared here, on InsertCommand only, NOT on the shared MoveCommand parent --
10
+ # a plain move has no `name`/`keywords` in the backend input, so putting them on the
11
+ # parent would give ReorderCommand's sibling MoveCommand a field the backend does not
12
+ # accept (the mirror image of this bug).
6
13
  class InsertCommand < Input::LocationStructure::MoveCommand
14
+ passthrough :name, :keywords
7
15
  passthrough :classificationIds
8
16
  end
9
17
  end
@@ -8,14 +8,18 @@ module Ecoportal
8
8
  passthrough :name, :newName
9
9
  passthrough :classificationIds, :newClassificationIds
10
10
 
11
+ # Effective name: the new value if one was set, otherwise the
12
+ # current value stored under +name+.
11
13
  def name
12
- super if newName.nil?
14
+ return doc["name"] if newName.nil?
13
15
 
14
16
  newName
15
17
  end
16
18
 
19
+ # Effective classification ids: the new value if one was set,
20
+ # otherwise the current value stored under +classificationIds+.
17
21
  def classificationIds
18
- super if newClassificationIds.empty?
22
+ return doc["classificationIds"] if newClassificationIds.nil? || newClassificationIds.empty?
19
23
 
20
24
  newClassificationIds
21
25
  end
@@ -3,9 +3,22 @@ module Ecoportal
3
3
  class GraphQL
4
4
  module Input
5
5
  class Page
6
+ # Shared input for the five review-task mutations (approve/reject/restart/undo,
7
+ # plus batch_update, which does not go through this shape at all).
8
+ #
9
+ # Backend evidence (app/graphql/mutations/tasks/review_pages/, verified against
10
+ # C:\docker\ecoPortal_master -- the gem's stored introspection snapshot, dated
11
+ # 2026-07-30, is stale on this point):
12
+ # approve.rb / reject.rb : id, notes
13
+ # restart.rb : id, notes, approve (Boolean, default false)
14
+ # undo_review.rb : id only
15
+ # None of the four accept `stageId` or `comment` -- both were unknown arguments the
16
+ # backend would reject, so no caller passing them could ever have succeeded.
17
+ # `notes` replaces the old (wrong) `comment`; `approve` is added for restart and is
18
+ # simply omitted (passthrough) for the other three, which never populate it.
6
19
  class ReviewTask < Logic::Input
7
20
  passkey :id
8
- passthrough :stageId, :comment
21
+ passthrough :notes, :approve
9
22
  end
10
23
  end
11
24
  end
@@ -7,7 +7,22 @@ module Ecoportal
7
7
  passkey :id
8
8
  passthrough :name, :sorter
9
9
  passboolean :preview
10
- passarray :fieldConfigs
10
+ # NOT a list: `UpdatePresetViewInput.fieldConfigs` is a (required)
11
+ # `FieldConfigurationOneToManyInput` — `{ additions:, deletions:, updates: }`.
12
+ # Only `CreatePresetViewInput` takes the plain `[FieldConfigurationInput!]!`.
13
+ passthrough :fieldConfigs
14
+
15
+ class << self
16
+ # The read model (Base::PresetView) exposes the collection as the
17
+ # `fieldConfigurations` LIST; this input takes it as the `fieldConfigs`
18
+ # one-to-many OBJECT. Base::PresetView owns the rename + reshape, so this
19
+ # explicit-converter seam (`as_input(target_class:)`, or a direct
20
+ # `.from_model`) stays in step with the implicit `model.as_input` one.
21
+ # The reshape is idempotent, so applying it on both is harmless.
22
+ def from_model(model, **kargs)
23
+ Base::PresetView.build_update_input(model, super)
24
+ end
25
+ end
11
26
  end
12
27
  end
13
28
  end
@@ -0,0 +1,19 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Input
5
+ class WorkflowCommand
6
+ # 20260713: add an item to a checklist field.
7
+ module AddChecklistFieldItem
8
+ SCHEMA_VERSION = '20260713'.freeze
9
+ VALID_KEYS = %i[dataFieldId placeholderId label weight].freeze
10
+
11
+ def self.build(**kwargs)
12
+ kwargs.slice(*VALID_KEYS).compact
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -5,15 +5,16 @@ module Ecoportal
5
5
  class WorkflowCommand
6
6
  module AddField
7
7
  SCHEMA_VERSION = '20260605'.freeze
8
- # VERIFIED against the live schema dump (WorkflowAddFieldInput, 20260605): the create
9
- # command accepts ONLY these keys. There is NO `description` and NO `required` field on
10
- # WorkflowAddFieldInput. `description` is instead a top-level key of
11
- # WorkflowEditFieldConfigurationInput, so a field's description is persisted via a
12
- # follow-up editFieldConfiguration command (see Builder::TemplateBuilder /
13
- # Diff::CommandSynthesizer). `required` has NO input key anywhere in the schema (not on
14
- # AddField, not on editFieldConfiguration top-level or any byType sub-input) and so
15
- # cannot be persisted through the workflow command bus at all — callers must treat it as
16
- # a read-only/unsupported attribute. Do NOT add these keys here (the server rejects them).
8
+ # VERIFIED against the backend source (WorkflowAddFieldInput, checked 20260828): the
9
+ # create command accepts ONLY these keys. There is NO `description` and NO `required`
10
+ # field on WorkflowAddFieldInput itself. Both are instead top-level keys of
11
+ # WorkflowEditFieldConfigurationInput (see edit_field_configuration.rb), so a field's
12
+ # description and required-ness are persisted via a follow-up editFieldConfiguration
13
+ # command (see Builder::TemplateBuilder / Diff::CommandSynthesizer). `required` IS
14
+ # persistable through the workflow command bus — via editFieldConfiguration's
15
+ # top-level `required` argument — it is simply not part of AddField. Do NOT add
16
+ # `description` or `required` to this builder's own keys (the server rejects them on
17
+ # AddField); route them through EditFieldConfiguration instead.
17
18
  VALID_KEYS = %i[placeholderId fieldType label stageId sectionId column].freeze
18
19
 
19
20
  def self.build(**kwargs)
@@ -4,12 +4,18 @@ module Ecoportal
4
4
  module Input
5
5
  class WorkflowCommand
6
6
  module AddSelectFieldOption
7
- SCHEMA_VERSION = '20260605'.freeze
8
- VALID_KEYS = %i[dataFieldId placeholderId label weight].freeze
7
+ SCHEMA_VERSION = '20260828'.freeze
8
+ # 20260828: added `value`, which the backend's AddSelectFieldOptionInput declares as
9
+ # `required: true` (schema authority: backend source, not the stale 2026-07-30
10
+ # introspection dump). This builder previously dropped it via kwargs.slice, so every
11
+ # call built by this class was rejected by the server for a missing required
12
+ # argument. `value` is always sent as a String, even for numeric select fields (an
13
+ # integral value is stored as an Integer by the server).
14
+ VALID_KEYS = %i[dataFieldId placeholderId label value weight].freeze
9
15
 
10
- def self.build(data_field_id:, label:, **kwargs)
11
- { dataFieldId: data_field_id, label: label }.
12
- merge(kwargs.slice(*VALID_KEYS - %i[dataFieldId label]).compact)
16
+ def self.build(data_field_id:, label:, value:, **kwargs)
17
+ { dataFieldId: data_field_id, label: label, value: value }.
18
+ merge(kwargs.slice(*VALID_KEYS - %i[dataFieldId label value]).compact)
13
19
  end
14
20
  end
15
21
  end
@@ -0,0 +1,23 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Input
5
+ class WorkflowCommand
6
+ # 20260713: smart-fill (AI) configuration extracted from the field-config inputs
7
+ # into its own add/edit/remove command family. `fieldConfigurations` accepts an array
8
+ # of pre-built WorkflowSmartFillFieldConfigurationInput hashes.
9
+ module AddSmartFillConfig
10
+ SCHEMA_VERSION = '20260713'.freeze
11
+ VALID_KEYS = %i[
12
+ dataFieldId triggerType instructions editEnabled textFormat limitLength fieldConfigurations
13
+ ].freeze
14
+
15
+ def self.build(**kwargs)
16
+ kwargs.slice(*VALID_KEYS).compact
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -4,8 +4,9 @@ module Ecoportal
4
4
  module Input
5
5
  class WorkflowCommand
6
6
  module AddStage
7
- SCHEMA_VERSION = '20260605'.freeze
8
- VALID_KEYS = %i[placeholderId name ordering].freeze
7
+ SCHEMA_VERSION = '20260713'.freeze
8
+ # 20260713: gained `tags` (create a stage already tagged, rather than adding stage tags after).
9
+ VALID_KEYS = %i[placeholderId name ordering tags].freeze
9
10
 
10
11
  def self.build(**kwargs)
11
12
  kwargs.slice(*VALID_KEYS).compact