ecoportal-api-graphql 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +793 -14
  3. data/LICENSE +21 -21
  4. data/README.gem.md +53 -0
  5. data/lib/ecoportal/api/common/graphql/auth_service.rb +115 -115
  6. data/lib/ecoportal/api/common/graphql/class_helpers.rb +46 -46
  7. data/lib/ecoportal/api/common/graphql/client.rb +107 -69
  8. data/lib/ecoportal/api/common/graphql/hash_helpers.rb +105 -105
  9. data/lib/ecoportal/api/common/graphql/http_client.rb +124 -8
  10. data/lib/ecoportal/api/common/graphql/model/as_input.rb +54 -54
  11. data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +49 -49
  12. data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +188 -188
  13. data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff.rb +55 -55
  14. data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +295 -295
  15. data/lib/ecoportal/api/common/graphql/model/diffable/leaf_diff_service.rb +1 -1
  16. data/lib/ecoportal/api/common/graphql/model.rb +17 -17
  17. data/lib/ecoportal/api/common/graphql/patches.rb +1 -1
  18. data/lib/ecoportal/api/common/graphql/query_integration.rb +45 -45
  19. data/lib/ecoportal/api/common/graphql.rb +16 -16
  20. data/lib/ecoportal/api/common.graphql.rb +8 -8
  21. data/lib/ecoportal/api/graphql/base/action_category.rb +15 -15
  22. data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +1 -1
  23. data/lib/ecoportal/api/graphql/base/contractor_entity.rb +24 -24
  24. data/lib/ecoportal/api/graphql/base/date_time.rb +12 -12
  25. data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -16
  26. data/lib/ecoportal/api/graphql/base/field.rb +12 -12
  27. data/lib/ecoportal/api/graphql/base/file_attachment.rb +15 -15
  28. data/lib/ecoportal/api/graphql/base/location_node.rb +14 -14
  29. data/lib/ecoportal/api/graphql/base/location_structure/draft/structure.rb +37 -37
  30. data/lib/ecoportal/api/graphql/base/location_structure/draft.rb +93 -93
  31. data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -9
  32. data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -18
  33. data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -29
  34. data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +1 -1
  35. data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +1 -1
  36. data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -23
  37. data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -24
  38. data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +160 -12
  39. data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -8
  40. data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -9
  41. data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -17
  42. data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -26
  43. data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -9
  44. data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -17
  45. data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -9
  46. data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -21
  47. data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +51 -0
  48. data/lib/ecoportal/api/graphql/base/page/phased.rb +15 -15
  49. data/lib/ecoportal/api/graphql/base/page/section.rb +48 -48
  50. data/lib/ecoportal/api/graphql/base/page_info.rb +12 -12
  51. data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -39
  52. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -27
  53. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -30
  54. data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -34
  55. data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -35
  56. data/lib/ecoportal/api/graphql/base/person_member.rb +22 -22
  57. data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -23
  58. data/lib/ecoportal/api/graphql/base/register.rb +1 -1
  59. data/lib/ecoportal/api/graphql/base/resource.rb +13 -13
  60. data/lib/ecoportal/api/graphql/base/temp_image.rb +28 -0
  61. data/lib/ecoportal/api/graphql/base/template/change_log_entry.rb +118 -0
  62. data/lib/ecoportal/api/graphql/base/template.rb +2 -0
  63. data/lib/ecoportal/api/graphql/base.rb +1 -0
  64. data/lib/ecoportal/api/graphql/builder/action.rb +41 -41
  65. data/lib/ecoportal/api/graphql/builder/location_structure/draft.rb +64 -64
  66. data/lib/ecoportal/api/graphql/builder/location_structure.rb +40 -40
  67. data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -84
  68. data/lib/ecoportal/api/graphql/builder/register.rb +49 -49
  69. data/lib/ecoportal/api/graphql/builder/template.rb +37 -4
  70. data/lib/ecoportal/api/graphql/builder/template_builder.rb +21 -2
  71. data/lib/ecoportal/api/graphql/compat/filter_translator.rb +1 -1
  72. data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -23
  73. data/lib/ecoportal/api/graphql/compat/registers.rb +84 -84
  74. data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -33
  75. data/lib/ecoportal/api/graphql/compat.rb +17 -17
  76. data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -71
  77. data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +68 -68
  78. data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -60
  79. data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -11
  80. data/lib/ecoportal/api/graphql/connection/template_change_log.rb +19 -0
  81. data/lib/ecoportal/api/graphql/connection.rb +1 -0
  82. data/lib/ecoportal/api/graphql/diff/change.rb +7 -2
  83. data/lib/ecoportal/api/graphql/diff/command_synthesizer.rb +19 -1
  84. data/lib/ecoportal/api/graphql/diff/version_diff.rb +13 -6
  85. data/lib/ecoportal/api/graphql/error/locations_error/fetch_nested.rb +51 -51
  86. data/lib/ecoportal/api/graphql/error/locations_error.rb +28 -28
  87. data/lib/ecoportal/api/graphql/error/locations_validation_error.rb +20 -20
  88. data/lib/ecoportal/api/graphql/error/validation_errors.rb +28 -28
  89. data/lib/ecoportal/api/graphql/error.rb +12 -12
  90. data/lib/ecoportal/api/graphql/file_upload/client.rb +140 -35
  91. data/lib/ecoportal/api/graphql/file_upload.rb +10 -10
  92. data/lib/ecoportal/api/graphql/fragment/action.rb +65 -65
  93. data/lib/ecoportal/api/graphql/fragment/action_category.rb +17 -17
  94. data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +20 -20
  95. data/lib/ecoportal/api/graphql/fragment/locations_error.rb +19 -19
  96. data/lib/ecoportal/api/graphql/fragment/page.rb +1 -0
  97. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +10 -3
  98. data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -15
  99. data/lib/ecoportal/api/graphql/fragment/pagination.rb +17 -17
  100. data/lib/ecoportal/api/graphql/fragment/permissions.rb +0 -2
  101. data/lib/ecoportal/api/graphql/fragment/template_change_log.rb +102 -0
  102. data/lib/ecoportal/api/graphql/fragment.rb +1 -0
  103. data/lib/ecoportal/api/graphql/helpers/locations_tree.rb +41 -41
  104. data/lib/ecoportal/api/graphql/helpers.rb +10 -10
  105. data/lib/ecoportal/api/graphql/input/action/archive.rb +14 -14
  106. data/lib/ecoportal/api/graphql/input/action/create.rb +13 -13
  107. data/lib/ecoportal/api/graphql/input/action.rb +14 -14
  108. data/lib/ecoportal/api/graphql/input/contractor_entity/create.rb +14 -14
  109. data/lib/ecoportal/api/graphql/input/contractor_entity/destroy.rb +13 -13
  110. data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -16
  111. data/lib/ecoportal/api/graphql/input/id_diff.rb +11 -11
  112. data/lib/ecoportal/api/graphql/input/location_structure/archive_command.rb +13 -13
  113. data/lib/ecoportal/api/graphql/input/location_structure/delete_command.rb +13 -13
  114. data/lib/ecoportal/api/graphql/input/location_structure/draft/create.rb +15 -15
  115. data/lib/ecoportal/api/graphql/input/location_structure/draft/delete.rb +15 -15
  116. data/lib/ecoportal/api/graphql/input/location_structure/draft/drop_bad_commands.rb +16 -16
  117. data/lib/ecoportal/api/graphql/input/location_structure/draft/publish.rb +16 -16
  118. data/lib/ecoportal/api/graphql/input/location_structure/draft.rb +19 -19
  119. data/lib/ecoportal/api/graphql/input/location_structure/insert_command.rb +21 -13
  120. data/lib/ecoportal/api/graphql/input/location_structure/move_command.rb +14 -14
  121. data/lib/ecoportal/api/graphql/input/location_structure/reorder_command.rb +13 -13
  122. data/lib/ecoportal/api/graphql/input/location_structure/unarchive_command.rb +13 -13
  123. data/lib/ecoportal/api/graphql/input/location_structure.rb +20 -20
  124. data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -14
  125. data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -13
  126. data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -13
  127. data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -18
  128. data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -13
  129. data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -13
  130. data/lib/ecoportal/api/graphql/input/page/review_task.rb +27 -14
  131. data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -14
  132. data/lib/ecoportal/api/graphql/input/page/update.rb +109 -6
  133. data/lib/ecoportal/api/graphql/input/page.rb +26 -26
  134. data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -18
  135. data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -16
  136. data/lib/ecoportal/api/graphql/input/preset_view/update.rb +1 -1
  137. data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -14
  138. data/lib/ecoportal/api/graphql/input/register/create.rb +18 -18
  139. data/lib/ecoportal/api/graphql/input/register/update.rb +15 -15
  140. data/lib/ecoportal/api/graphql/input/register.rb +13 -13
  141. data/lib/ecoportal/api/graphql/input/search.rb +13 -13
  142. data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -234
  143. data/lib/ecoportal/api/graphql/input/search_conf.rb +1 -1
  144. data/lib/ecoportal/api/graphql/input/search_filter.rb +12 -12
  145. data/lib/ecoportal/api/graphql/input/search_sorter.rb +11 -11
  146. data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -18
  147. data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -18
  148. data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -18
  149. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -18
  150. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -18
  151. data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -18
  152. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +10 -9
  153. data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -18
  154. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -23
  155. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -18
  156. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -18
  157. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -18
  158. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -18
  159. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -18
  160. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -18
  161. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -18
  162. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -18
  163. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -18
  164. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -23
  165. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -18
  166. data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -18
  167. data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +25 -19
  168. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -18
  169. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -18
  170. data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -18
  171. data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -18
  172. data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -18
  173. data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -18
  174. data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -18
  175. data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -18
  176. data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -18
  177. data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -18
  178. data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +7 -2
  179. data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +21 -18
  180. data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -19
  181. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -19
  182. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -18
  183. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -18
  184. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -18
  185. data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -18
  186. data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -18
  187. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -18
  188. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -18
  189. data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -22
  190. data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -18
  191. data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +23 -19
  192. data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -18
  193. data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -18
  194. data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -18
  195. data/lib/ecoportal/api/graphql/input/workflow_command/edit_template_basic_settings.rb +7 -2
  196. data/lib/ecoportal/api/graphql/input/workflow_command/edit_template_container_uid.rb +1 -1
  197. data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -18
  198. data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -18
  199. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +28 -24
  200. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +8 -2
  201. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -20
  202. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -24
  203. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +8 -2
  204. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -20
  205. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -25
  206. data/lib/ecoportal/api/graphql/input/workflow_command/manage_copy_page_configuration.rb +47 -0
  207. data/lib/ecoportal/api/graphql/input/workflow_command/move_section_to_stage.rb +33 -0
  208. data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -18
  209. data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -18
  210. data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -18
  211. data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -18
  212. data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -18
  213. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -18
  214. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -18
  215. data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -18
  216. data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -18
  217. data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -18
  218. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -18
  219. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -18
  220. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -18
  221. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -18
  222. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -18
  223. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -18
  224. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -18
  225. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -18
  226. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -18
  227. data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -18
  228. data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -18
  229. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -18
  230. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -18
  231. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -18
  232. data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -18
  233. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -18
  234. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -18
  235. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -18
  236. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -18
  237. data/lib/ecoportal/api/graphql/input/workflow_command.rb +5 -0
  238. data/lib/ecoportal/api/graphql/interface/base_page.rb +14 -0
  239. data/lib/ecoportal/api/graphql/interface/location_structure/node.rb +43 -43
  240. data/lib/ecoportal/api/graphql/interface/location_structure.rb +14 -14
  241. data/lib/ecoportal/api/graphql/interface.rb +11 -11
  242. data/lib/ecoportal/api/graphql/logic/base_model.rb +15 -15
  243. data/lib/ecoportal/api/graphql/logic/base_query.rb +260 -193
  244. data/lib/ecoportal/api/graphql/logic/mutation.rb +59 -59
  245. data/lib/ecoportal/api/graphql/logic/payload.rb +42 -42
  246. data/lib/ecoportal/api/graphql/logic/query.rb +23 -23
  247. data/lib/ecoportal/api/graphql/logic/query_array.rb +30 -30
  248. data/lib/ecoportal/api/graphql/logic/query_connection.rb +48 -48
  249. data/lib/ecoportal/api/graphql/logic.rb +18 -18
  250. data/lib/ecoportal/api/graphql/model/account.rb +15 -15
  251. data/lib/ecoportal/api/graphql/model/action.rb +22 -22
  252. data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -10
  253. data/lib/ecoportal/api/graphql/model/contractor_entity.rb +12 -12
  254. data/lib/ecoportal/api/graphql/model/field.rb +10 -10
  255. data/lib/ecoportal/api/graphql/model/file_attachment.rb +10 -10
  256. data/lib/ecoportal/api/graphql/model/file_container.rb +11 -11
  257. data/lib/ecoportal/api/graphql/model/location_node.rb +14 -14
  258. data/lib/ecoportal/api/graphql/model/location_structure/draft/structure.rb +15 -15
  259. data/lib/ecoportal/api/graphql/model/location_structure/draft.rb +15 -15
  260. data/lib/ecoportal/api/graphql/model/location_structure.rb +16 -16
  261. data/lib/ecoportal/api/graphql/model/organization.rb +9 -0
  262. data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -14
  263. data/lib/ecoportal/api/graphql/model/page/data_field.rb +12 -12
  264. data/lib/ecoportal/api/graphql/model/page/phased/stage.rb +14 -14
  265. data/lib/ecoportal/api/graphql/model/page/phased.rb +17 -0
  266. data/lib/ecoportal/api/graphql/model/page/section.rb +12 -12
  267. data/lib/ecoportal/api/graphql/model/page_union.rb +21 -21
  268. data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -20
  269. data/lib/ecoportal/api/graphql/model/permissions.rb +6 -0
  270. data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -10
  271. data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -10
  272. data/lib/ecoportal/api/graphql/model/register.rb +10 -10
  273. data/lib/ecoportal/api/graphql/model/resource.rb +13 -13
  274. data/lib/ecoportal/api/graphql/model/temp_image.rb +10 -0
  275. data/lib/ecoportal/api/graphql/model/template/binding.rb +60 -0
  276. data/lib/ecoportal/api/graphql/model/template/change_log_entry.rb +19 -0
  277. data/lib/ecoportal/api/graphql/model/template/command_grouper.rb +107 -0
  278. data/lib/ecoportal/api/graphql/model/template/command_normalizer.rb +116 -0
  279. data/lib/ecoportal/api/graphql/model/template/command_synthesis.rb +262 -0
  280. data/lib/ecoportal/api/graphql/model/template/field.rb +68 -0
  281. data/lib/ecoportal/api/graphql/model/template/force.rb +65 -0
  282. data/lib/ecoportal/api/graphql/model/template/helper.rb +32 -0
  283. data/lib/ecoportal/api/graphql/model/template/instance.rb +202 -0
  284. data/lib/ecoportal/api/graphql/model/template/node.rb +78 -0
  285. data/lib/ecoportal/api/graphql/model/template/option.rb +49 -0
  286. data/lib/ecoportal/api/graphql/model/template/read.rb +164 -0
  287. data/lib/ecoportal/api/graphql/model/template/section.rb +82 -0
  288. data/lib/ecoportal/api/graphql/model/template/stage.rb +49 -0
  289. data/lib/ecoportal/api/graphql/model/template/staged_executor.rb +236 -0
  290. data/lib/ecoportal/api/graphql/model/template.rb +37 -1
  291. data/lib/ecoportal/api/graphql/model/user.rb +14 -14
  292. data/lib/ecoportal/api/graphql/model.rb +1 -0
  293. data/lib/ecoportal/api/graphql/mutation/action/archive.rb +41 -41
  294. data/lib/ecoportal/api/graphql/mutation/action/create.rb +40 -40
  295. data/lib/ecoportal/api/graphql/mutation/action/update.rb +40 -40
  296. data/lib/ecoportal/api/graphql/mutation/action.rb +14 -14
  297. data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +1 -1
  298. data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +1 -1
  299. data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -13
  300. data/lib/ecoportal/api/graphql/mutation/contractor_entity/create.rb +40 -40
  301. data/lib/ecoportal/api/graphql/mutation/contractor_entity/destroy.rb +40 -40
  302. data/lib/ecoportal/api/graphql/mutation/contractor_entity/update.rb +40 -40
  303. data/lib/ecoportal/api/graphql/mutation/file_container/upload.rb +11 -4
  304. data/lib/ecoportal/api/graphql/mutation/image/upload.rb +88 -0
  305. data/lib/ecoportal/api/graphql/mutation/image.rb +14 -0
  306. data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +54 -54
  307. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +55 -55
  308. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +54 -54
  309. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/delete.rb +43 -43
  310. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +56 -56
  311. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +66 -66
  312. data/lib/ecoportal/api/graphql/mutation/location_structure/draft.rb +18 -18
  313. data/lib/ecoportal/api/graphql/mutation/location_structure.rb +13 -13
  314. data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +1 -1
  315. data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -40
  316. data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +1 -1
  317. data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -50
  318. data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +1 -1
  319. data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -43
  320. data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +1 -1
  321. data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +1 -1
  322. data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +1 -1
  323. data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +1 -1
  324. data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -40
  325. data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +1 -1
  326. data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -40
  327. data/lib/ecoportal/api/graphql/mutation/page.rb +28 -28
  328. data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -35
  329. data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +1 -1
  330. data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -37
  331. data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -35
  332. data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -15
  333. data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -35
  334. data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +1 -1
  335. data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -35
  336. data/lib/ecoportal/api/graphql/mutation/register.rb +14 -14
  337. data/lib/ecoportal/api/graphql/mutation/template/create.rb +35 -3
  338. data/lib/ecoportal/api/graphql/mutation/template/update.rb +4 -2
  339. data/lib/ecoportal/api/graphql/mutation.rb +1 -0
  340. data/lib/ecoportal/api/graphql/payload/action/archive.rb +13 -13
  341. data/lib/ecoportal/api/graphql/payload/action/create.rb +13 -13
  342. data/lib/ecoportal/api/graphql/payload/action/update.rb +13 -13
  343. data/lib/ecoportal/api/graphql/payload/action.rb +14 -14
  344. data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -12
  345. data/lib/ecoportal/api/graphql/payload/contractor_entity/create.rb +13 -13
  346. data/lib/ecoportal/api/graphql/payload/contractor_entity/destroy.rb +12 -12
  347. data/lib/ecoportal/api/graphql/payload/contractor_entity/update.rb +12 -12
  348. data/lib/ecoportal/api/graphql/payload/images_upload.rb +14 -0
  349. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +2 -2
  350. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +2 -2
  351. data/lib/ecoportal/api/graphql/payload/location_structure/apply_commands.rb +51 -51
  352. data/lib/ecoportal/api/graphql/payload/location_structure/command_execution_result.rb +50 -50
  353. data/lib/ecoportal/api/graphql/payload/location_structure/draft/add_commands.rb +30 -30
  354. data/lib/ecoportal/api/graphql/payload/location_structure/draft/delete.rb +30 -30
  355. data/lib/ecoportal/api/graphql/payload/location_structure/draft/drop_bad_commands.rb +43 -43
  356. data/lib/ecoportal/api/graphql/payload/location_structure/draft/publish.rb +63 -63
  357. data/lib/ecoportal/api/graphql/payload/location_structure/draft.rb +18 -18
  358. data/lib/ecoportal/api/graphql/payload/location_structure.rb +14 -14
  359. data/lib/ecoportal/api/graphql/payload/ok_payload.rb +1 -1
  360. data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -13
  361. data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -13
  362. data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -13
  363. data/lib/ecoportal/api/graphql/payload/page/draft.rb +1 -1
  364. data/lib/ecoportal/api/graphql/payload/page/review_task.rb +1 -1
  365. data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -13
  366. data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -13
  367. data/lib/ecoportal/api/graphql/payload/preset_view.rb +1 -1
  368. data/lib/ecoportal/api/graphql/payload/register.rb +1 -1
  369. data/lib/ecoportal/api/graphql/payload.rb +1 -0
  370. data/lib/ecoportal/api/graphql/query/action.rb +33 -33
  371. data/lib/ecoportal/api/graphql/query/action_categories.rb +53 -53
  372. data/lib/ecoportal/api/graphql/query/actions.rb +43 -43
  373. data/lib/ecoportal/api/graphql/query/contractor_entities.rb +53 -53
  374. data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -76
  375. data/lib/ecoportal/api/graphql/query/location_classifications.rb +39 -39
  376. data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -47
  377. data/lib/ecoportal/api/graphql/query/pages.rb +59 -59
  378. data/lib/ecoportal/api/graphql/query/permissions.rb +1 -1
  379. data/lib/ecoportal/api/graphql/query/person_members.rb +76 -0
  380. data/lib/ecoportal/api/graphql/query/register_preset_views.rb +1 -1
  381. data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -83
  382. data/lib/ecoportal/api/graphql/query/template_change_log.rb +118 -0
  383. data/lib/ecoportal/api/graphql/query/templates.rb +53 -53
  384. data/lib/ecoportal/api/graphql/query.rb +2 -0
  385. data/lib/ecoportal/api/graphql_version.rb +1 -1
  386. data/lib/ecoportal/api-graphql.rb +10 -10
  387. metadata +45 -9
  388. data/README.md +0 -24
  389. data/lib/ecoportal/api/common/graphql/CLAUDE.md +0 -36
  390. data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +0 -28
  391. data/lib/ecoportal/api/graphql/CLAUDE.md +0 -37
  392. data/lib/ecoportal/api/graphql/base/CLAUDE.md +0 -50
  393. data/lib/ecoportal/api/graphql/builder/CLAUDE.md +0 -65
@@ -24,6 +24,8 @@ module Ecoportal
24
24
  embedded = super
25
25
  # Share the page's canonical field objects with each stage, so mutations made
26
26
  # via stage.components reach the page's data_fields_updates (phased write-path).
27
+ # NOTE: no manual `page` back-ref injection — Stage#page resolves the owning page
28
+ # via the DoubleModel's native `root` reference (page -> stages collection -> stage).
27
29
  fc = field_collection
28
30
  Array(embedded).each do |st|
29
31
  st.page_field_collection = fc if st.respond_to?(:page_field_collection=)
@@ -31,6 +33,21 @@ module Ecoportal
31
33
  Compat::StageCollection.new(embedded)
32
34
  end
33
35
 
36
+ # Page-level compiled tag set (client-side build of the backend-only
37
+ # "compiled_tags"), per the domain formula:
38
+ #
39
+ # Page.all_tags = Unique(⋃ all stages' all_tags)
40
+ #
41
+ # De-duplicated Array of tag strings across every stage. A phased page with no
42
+ # stages falls back to the page-level components (baseTags + otherTags +
43
+ # location_ids), matching the basic-page behaviour on Interface::BasePage.
44
+ def all_tags
45
+ stgs = Array(stages)
46
+ return super if stgs.empty?
47
+
48
+ stgs.flat_map(&:all_tags).compact.uniq
49
+ end
50
+
34
51
  # v2 compatible: ID of the stage with state == 'inprogress', or nil
35
52
  def current_stage_id
36
53
  raw = doc['stagesIndex'] || doc['stages']
@@ -1,12 +1,12 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Model
5
- module Page
6
- class Section < Base::Page::Section
7
- end
8
- end
9
- end
10
- end
11
- end
12
- end
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ module Page
6
+ class Section < Base::Page::Section
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,21 +1,21 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Model
5
- # Factory class — dispatches on __typename to the correct concrete page class.
6
- # Must be a Class (not a Module): v2's resolve_class matches `when Class`, so a
7
- # Module target falls through to "Unknown class". `self.new` is overridden to
8
- # return the concrete page instance instead of a PageUnion instance.
9
- class PageUnion
10
- def self.new(doc, **opts)
11
- case doc&.fetch('__typename', nil)
12
- when 'BasicPage' then Page::Basic.new(doc, **opts)
13
- when 'PhasedPage' then Page::Phased.new(doc, **opts)
14
- else Interface::BasePage.new(doc, **opts)
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ # Factory class — dispatches on __typename to the correct concrete page class.
6
+ # Must be a Class (not a Module): v2's resolve_class matches `when Class`, so a
7
+ # Module target falls through to "Unknown class". `self.new` is overridden to
8
+ # return the concrete page instance instead of a PageUnion instance.
9
+ class PageUnion
10
+ def self.new(doc, **opts)
11
+ case doc&.fetch('__typename', nil)
12
+ when 'BasicPage' then Page::Basic.new(doc, **opts)
13
+ when 'PhasedPage' then Page::Phased.new(doc, **opts)
14
+ else Interface::BasePage.new(doc, **opts)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,20 +1,20 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Model
5
- class PagesWorkflow < Base::PagesWorkflow
6
- SCHEMA_VERSION = '20260605'.freeze
7
-
8
- class_resolver :command_connection_class,
9
- 'Ecoportal::API::GraphQL::Connection::PagesWorkflowCommand'
10
-
11
- class_resolver :operation_class,
12
- 'Ecoportal::API::GraphQL::Base::PagesWorkflow::OperationUnion'
13
-
14
- class_resolver :trigger_class,
15
- 'Ecoportal::API::GraphQL::Base::PagesWorkflow::TriggerUnion'
16
- end
17
- end
18
- end
19
- end
20
- end
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ class PagesWorkflow < Base::PagesWorkflow
6
+ SCHEMA_VERSION = '20260605'.freeze
7
+
8
+ class_resolver :command_connection_class,
9
+ 'Ecoportal::API::GraphQL::Connection::PagesWorkflowCommand'
10
+
11
+ class_resolver :operation_class,
12
+ 'Ecoportal::API::GraphQL::Base::PagesWorkflow::OperationUnion'
13
+
14
+ class_resolver :trigger_class,
15
+ 'Ecoportal::API::GraphQL::Base::PagesWorkflow::TriggerUnion'
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -108,6 +108,9 @@ module Ecoportal
108
108
  klass: "Ecoportal::API::GraphQL::Model::AuthorizationResult", nullable: true
109
109
  embeds_one :pageCanUseDrafts,
110
110
  klass: "Ecoportal::API::GraphQL::Model::AuthorizationResult", nullable: true
111
+ # DEPRECATED (20260929): removed from the live schema by the smart-assistant
112
+ # consolidation; no longer selected by Fragment::Permissions, so always nil. Kept so
113
+ # callers get nil instead of NoMethodError.
111
114
  embeds_one :pageSmartAssistantCanChat,
112
115
  klass: "Ecoportal::API::GraphQL::Model::AuthorizationResult", nullable: true
113
116
  embeds_one :personSchemaCanAccessManager,
@@ -120,6 +123,9 @@ module Ecoportal
120
123
  klass: "Ecoportal::API::GraphQL::Model::AuthorizationResult", nullable: true
121
124
  embeds_one :publicTemplatesCanManage,
122
125
  klass: "Ecoportal::API::GraphQL::Model::AuthorizationResult", nullable: true
126
+ # DEPRECATED (20260929): removed from the live schema by the smart-assistant
127
+ # consolidation; no longer selected by Fragment::Permissions, so always nil. Kept so
128
+ # callers get nil instead of NoMethodError.
123
129
  embeds_one :registerAssistantCanChat,
124
130
  klass: "Ecoportal::API::GraphQL::Model::AuthorizationResult", nullable: true
125
131
  embeds_one :registerCanAccessRegisterTools,
@@ -1,10 +1,10 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Model
5
- class PresetView < Base::PresetView
6
- end
7
- end
8
- end
9
- end
10
- end
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ class PresetView < Base::PresetView
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,10 +1,10 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Model
5
- class PreviewPage < Base::PreviewPage
6
- end
7
- end
8
- end
9
- end
10
- end
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ class PreviewPage < Base::PreviewPage
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,10 +1,10 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Model
5
- class Register < Base::Register
6
- end
7
- end
8
- end
9
- end
10
- end
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ class Register < Base::Register
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,13 +1,13 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Model
5
- class Resource < Base::Resource
6
- embeds_one :page, klass: 'Ecoportal::API::GraphQL::Model::Page::Phased', read_only: true # PageUnion
7
- embeds_one :field, klass: 'Ecoportal::API::GraphQL::Model::Field', read_only: true
8
- # embeds_many :stages, klass: 'Ecoportal::API::GraphQL::Model::SimpleStage'
9
- end
10
- end
11
- end
12
- end
13
- end
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ class Resource < Base::Resource
6
+ embeds_one :page, klass: 'Ecoportal::API::GraphQL::Model::Page::Phased', read_only: true # PageUnion
7
+ embeds_one :field, klass: 'Ecoportal::API::GraphQL::Model::Field', read_only: true
8
+ # embeds_many :stages, klass: 'Ecoportal::API::GraphQL::Model::SimpleStage'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ class TempImage < Base::TempImage
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,60 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ module Template
6
+ # A force binding — `addBinding`/`editBinding`'s `referenceId` is the field (or field
7
+ # placeholder) the binding points at. `reference_id=` accepts either a raw id/String
8
+ # OR a `Field` (or any object answering `#ref`) so a caller can write
9
+ # `binding.reference_id = some_field` and let the SAME just-created-or-real-id
10
+ # resolution `Field#ref` already does apply here automatically — no separate
11
+ # "resolve the field id" step for the caller to remember.
12
+ class Binding
13
+ include Node
14
+
15
+ PLACEHOLDER_PREFIX = 'bnd'.freeze
16
+
17
+ BINDING_TYPE = 'field'.freeze
18
+
19
+ attr_reader :template, :force, :type
20
+ attr_accessor :name
21
+
22
+ def initialize(template:, force:, id: nil, name: nil, reference_id: nil, type: BINDING_TYPE)
23
+ @template = template
24
+ @force = force
25
+ @id = id
26
+ @name = name
27
+ @type = type
28
+ self.reference_id = reference_id
29
+ @snapshot = snapshot_attrs.freeze
30
+ end
31
+
32
+ attr_writer :reference_id
33
+
34
+ # Resolved at read time: the referenced node's own `#ref` when it is one (a `Field`
35
+ # or anything else in this tree), otherwise the raw value as given.
36
+ def reference_id
37
+ @reference_id.respond_to?(:ref) ? @reference_id.ref : @reference_id
38
+ end
39
+
40
+ def dirty?
41
+ !removed? && !new? && snapshot_attrs != @snapshot
42
+ end
43
+
44
+ def changed_attributes
45
+ return {} if new? || removed?
46
+
47
+ snapshot_attrs.each_with_object({}) { |(k, v), h| h[k] = v if v != @snapshot[k] }
48
+ end
49
+
50
+ private
51
+
52
+ def snapshot_attrs
53
+ { name: name, reference_id: reference_id }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,19 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ module Template
6
+ # Concrete read model for one entry of a template's change log. Adds the relational
7
+ # embed on top of the interface fields modelled in `Base::Template::ChangeLogEntry`
8
+ # (which is where the platform caveats are documented — read them before using this).
9
+ class ChangeLogEntry < Base::Template::ChangeLogEntry
10
+ # `owner` is a `UserType` (id / name / email) — WHO made the change. Resolved
11
+ # server-side from `owner_id` via RecordLoader, so it is nil for system-originated
12
+ # commands with no user. Prefer `owner&.name` over `ownerId` for reporting.
13
+ embeds_one :owner, klass: Model::User, nullable: true
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,107 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ module Template
6
+ # Groups an ordered command batch into chunks no larger than `chunk_size`, never
7
+ # splitting a placeholder-minting command away from any OTHER command in the SAME
8
+ # batch that references that placeholder (a `placeholderId` is only valid within the
9
+ # ONE `executeWorkflowCommands`/`updatePageTemplate` call that mints it —
10
+ # `18_template_editor_save_path.md` section B.1). Connected components (union-find
11
+ # over "which commands share a placeholder token") are packed into chunks in
12
+ # first-appearance order, so a chunk boundary only ever falls BETWEEN independent
13
+ # groups, never inside one.
14
+ module CommandGrouper
15
+ PLACEHOLDER_RE = /\Aph_/
16
+
17
+ class << self
18
+ # @param commands [Array<Hash>] built command hashes (`{ commandKey => input }`).
19
+ # @param chunk_size [Integer]
20
+ # @return [Array<Array<Hash>>] ordered chunks.
21
+ def chunk(commands, chunk_size)
22
+ slice_groups(group(commands), chunk_size)
23
+ end
24
+
25
+ # Every `ph_...` token referenced ANYWHERE in `commands` (minted or referenced).
26
+ # Public: `StagedExecutor`'s stale-placeholder guard uses this directly.
27
+ def tokens_in(commands)
28
+ commands.flat_map { |c| placeholder_tokens(c) }.uniq
29
+ end
30
+
31
+ private
32
+
33
+ def group(commands)
34
+ parent = {}
35
+ find = find_proc(parent)
36
+ token_owner = {}
37
+
38
+ commands.each_index do |i|
39
+ find.call(i)
40
+ placeholder_tokens(commands[i]).each do |tok|
41
+ token_owner.key?(tok) ? union(parent, find, i, token_owner[tok]) : (token_owner[tok] = i)
42
+ end
43
+ end
44
+
45
+ buckets = Hash.new { |h, k| h[k] = [] }
46
+ commands.each_index { |i| buckets[find.call(i)] << commands[i] }
47
+ buckets.values
48
+ end
49
+
50
+ def find_proc(parent)
51
+ find = nil
52
+ find = lambda do |x|
53
+ parent[x] ||= x
54
+ parent[x] = find.call(parent[x]) unless parent[x] == x
55
+ parent[x]
56
+ end
57
+ end
58
+
59
+ def union(parent, find, idx_a, idx_b)
60
+ root_a = find.call(idx_a)
61
+ root_b = find.call(idx_b)
62
+ parent[root_a] = root_b unless root_a == root_b
63
+ end
64
+
65
+ def slice_groups(groups, chunk_size)
66
+ chunks = []
67
+ current = []
68
+ groups.each do |members|
69
+ guard_group_size!(members, chunk_size)
70
+ if current.size + members.size > chunk_size
71
+ chunks << current
72
+ current = []
73
+ end
74
+ current.concat(members)
75
+ end
76
+ chunks << current unless current.empty?
77
+ chunks
78
+ end
79
+
80
+ def guard_group_size!(members, chunk_size)
81
+ return if members.size <= chunk_size
82
+
83
+ tally = members.map { |c| c.keys.first }.tally
84
+ raise "CommandGrouper: a placeholder-connected group of #{members.size} commands " \
85
+ "exceeds chunk_size (#{chunk_size}) and cannot be split without breaking a " \
86
+ "same-batch placeholder reference. Key tally: #{tally}"
87
+ end
88
+
89
+ def placeholder_tokens(command)
90
+ command.values.flat_map { |v| scan(v) }
91
+ end
92
+
93
+ def scan(value)
94
+ case value
95
+ when String then PLACEHOLDER_RE.match?(value) ? [value] : []
96
+ when Hash then value.values.flat_map { |v| scan(v) }
97
+ when Array then value.flat_map { |v| scan(v) }
98
+ else []
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,116 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Model
5
+ module Template
6
+ # Normalises an ordered batch of built `WorkflowCommand` hashes
7
+ # (`[{ commandKey => { ...input } }, ...]`) so that batches produced by DIFFERENT
8
+ # emitters -- each of which mints its own placeholder/id tokens (`Builder::
9
+ # TemplateBuilder`'s `ph_stg_1`, `Diff::CommandSynthesizer`'s `ph_stg_0`,
10
+ # `CommandSynthesis`'s `ph_stg_1`, a self-version replay's real server ids, the downstream
11
+ # writers' caller-chosen tokens) -- can be compared for STRUCTURAL equivalence.
12
+ #
13
+ # Two normalisations, both pure (no mutation of the input):
14
+ #
15
+ # 1. REFERENCE-TOKEN POSITIONING. Every value carried under a key this class
16
+ # recognises as an id/placeholder REFERENCE (see `REFERENCE_KEYS`) is replaced
17
+ # by a positional token `"ph_<n>"`, assigned in FIRST-APPEARANCE order across
18
+ # the whole ordered batch (scanning left to right, top to bottom, depth-first
19
+ # within each command's own Hash). The SAME source value always maps to the
20
+ # SAME token wherever it recurs (so a mint-then-reference pair, e.g. `addStage`'s
21
+ # `placeholderId` and a later `addStageSection`'s `stageId`, stays linked). Only
22
+ # the KEY decides whether a String is a reference -- literal content
23
+ # (`label`/`name`/`value`/`script`/`url`/...) is never touched, so a coincidental
24
+ # value match with a real id never causes a false substitution.
25
+ # 2. KEY ORDER + correlation stripping. Each command's own input Hash (and any
26
+ # nested Hash, e.g. `byType`) is recursively re-sorted by key so two batches that
27
+ # differ only in the Hash literal's construction order compare equal, and any
28
+ # `CORRELATION_KEYS` entry (never part of the compared shape) is dropped.
29
+ #
30
+ # Two normalised batches are STRUCTURALLY EQUIVALENT iff `Normalizer.normalize(a) ==
31
+ # Normalizer.normalize(b)` -- byte-identical once serialised (`to_json`), per the
32
+ # DSL-08 acceptance test.
33
+ class CommandNormalizer
34
+ # Keys whose String value addresses a node (mint or reference), across every
35
+ # `WorkflowCommand` input class this repo ships plus the downstream writers' own commands
36
+ # (`placeholderId`/`stageId`/`sectionId`/`dataFieldId`/`data_field_id`/`optionId`/
37
+ # `forceId`/`referenceId`/`anchorId`/`id`) -- verified against every `VALID_KEYS`
38
+ # list under `lib/ecoportal/api/graphql/input/workflow_command/`. Deliberately a
39
+ # CLOSED, named set (not "every String") so a literal content String (a label, a
40
+ # script, a URL) is never mistaken for a reference.
41
+ REFERENCE_KEYS = %i[
42
+ placeholderId stageId sectionId dataFieldId data_field_id optionId
43
+ forceId referenceId anchorId id
44
+ ].freeze
45
+
46
+ # Fields that exist only for request bookkeeping, never part of the compared shape.
47
+ CORRELATION_KEYS = %i[clientMutationId correlationId].freeze
48
+
49
+ # @param commands [Array<Hash>] an ordered batch, each a single-key Hash
50
+ # (`{ commandKey => { ...input } }`).
51
+ # @return [Array<Hash>] the same batch, reference tokens repositioned, keys sorted,
52
+ # correlation-only keys dropped. Deterministic and comparable with `==`.
53
+ def self.normalize(commands)
54
+ new.normalize(commands)
55
+ end
56
+
57
+ def normalize(commands)
58
+ @tokens = {}
59
+ @next_index = 0
60
+ Array(commands).map { |command| normalize_command(command) }
61
+ end
62
+
63
+ private
64
+
65
+ def normalize_command(command)
66
+ command_key = command.keys.first
67
+ body = command[command_key]
68
+ { command_key => deep_sort(normalize_hash(body)) }
69
+ end
70
+
71
+ def normalize_hash(hash)
72
+ hash.each_with_object({}) do |(key, value), out|
73
+ next if CORRELATION_KEYS.include?(key.to_sym)
74
+
75
+ out[key] = normalize_value(key, value)
76
+ end
77
+ end
78
+
79
+ def normalize_value(key, value)
80
+ case value
81
+ when Hash then normalize_hash(value)
82
+ when Array then value.map { |element| normalize_value(key, element) }
83
+ when String then reference_key?(key) ? token_for(value) : value
84
+ else value
85
+ end
86
+ end
87
+
88
+ def reference_key?(key)
89
+ REFERENCE_KEYS.include?(key.to_sym)
90
+ end
91
+
92
+ # The SAME source value (whatever token/id format the emitter minted) always maps
93
+ # to the SAME positional token -- first appearance decides the number.
94
+ def token_for(raw_value)
95
+ @tokens[raw_value] ||= begin
96
+ @next_index += 1
97
+ "ph_#{@next_index}"
98
+ end
99
+ end
100
+
101
+ # Recursively re-sorts every Hash (top-level input and any nested sub-hash, e.g.
102
+ # `byType`) by key, so construction-order differences never cause a false mismatch.
103
+ # Arrays keep their own order (option/command ORDER is part of what is compared).
104
+ def deep_sort(value)
105
+ case value
106
+ when Hash then value.map { |k, v| [k, deep_sort(v)] }.sort_by { |(k, _)| k.to_s }.to_h
107
+ when Array then value.map { |element| deep_sort(element) }
108
+ else value
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end