ecoportal-api-graphql 1.3.5 → 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.
Files changed (434) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +934 -477
  3. data/lib/ecoportal/api/common/graphql/CLAUDE.md +36 -0
  4. data/lib/ecoportal/api/common/graphql/client.rb +1 -1
  5. data/lib/ecoportal/api/common/graphql/http_client.rb +195 -145
  6. data/lib/ecoportal/api/common/graphql/model/CLAUDE.md +28 -0
  7. data/lib/ecoportal/api/common/graphql/model/as_input.rb +8 -5
  8. data/lib/ecoportal/api/common/graphql/model/diffable/classic_diff_service.rb +3 -1
  9. data/lib/ecoportal/api/common/graphql/model/diffable/diff_service.rb +31 -23
  10. data/lib/ecoportal/api/common/graphql/model/diffable/hash_diff_nesting.rb +54 -1
  11. data/lib/ecoportal/api/common/graphql/model/diffable.rb +54 -54
  12. data/lib/ecoportal/api/graphql/CLAUDE.md +37 -0
  13. data/lib/ecoportal/api/graphql/base/CLAUDE.md +50 -0
  14. data/lib/ecoportal/api/graphql/base/action.rb +43 -43
  15. data/lib/ecoportal/api/graphql/base/ai_summary_version.rb +17 -0
  16. data/lib/ecoportal/api/graphql/base/contractor_entity/member_changes.rb +67 -67
  17. data/lib/ecoportal/api/graphql/base/delta_result.rb +16 -0
  18. data/lib/ecoportal/api/graphql/base/file_container.rb +14 -14
  19. data/lib/ecoportal/api/graphql/base/force/binding.rb +19 -0
  20. data/lib/ecoportal/api/graphql/base/force/binding_collection.rb +62 -0
  21. data/lib/ecoportal/api/graphql/base/force/collection.rb +47 -0
  22. data/lib/ecoportal/api/graphql/base/force.rb +65 -0
  23. data/lib/ecoportal/api/graphql/base/kickstand/job.rb +17 -0
  24. data/lib/ecoportal/api/graphql/base/kickstand/workflow.rb +18 -0
  25. data/lib/ecoportal/api/graphql/base/kickstand.rb +13 -0
  26. data/lib/ecoportal/api/graphql/base/location_classification_type.rb +15 -15
  27. data/lib/ecoportal/api/graphql/base/location_structure.rb +27 -27
  28. data/lib/ecoportal/api/graphql/base/organization.rb +15 -15
  29. data/lib/ecoportal/api/graphql/base/page/basic.rb +38 -0
  30. data/lib/ecoportal/api/graphql/base/page/data_field/actions_list.rb +9 -0
  31. data/lib/ecoportal/api/graphql/base/page/data_field/ai_summary.rb +18 -0
  32. data/lib/ecoportal/api/graphql/base/page/data_field/checklist.rb +29 -0
  33. data/lib/ecoportal/api/graphql/base/page/data_field/collection.rb +119 -0
  34. data/lib/ecoportal/api/graphql/base/page/data_field/contractor_entities.rb +28 -0
  35. data/lib/ecoportal/api/graphql/base/page/data_field/cross_reference.rb +54 -0
  36. data/lib/ecoportal/api/graphql/base/page/data_field/date_field.rb +23 -0
  37. data/lib/ecoportal/api/graphql/base/page/data_field/file_field.rb +25 -0
  38. data/lib/ecoportal/api/graphql/base/page/data_field/gauge.rb +19 -0
  39. data/lib/ecoportal/api/graphql/base/page/data_field/geo.rb +24 -0
  40. data/lib/ecoportal/api/graphql/base/page/data_field/image_gallery.rb +24 -0
  41. data/lib/ecoportal/api/graphql/base/page/data_field/law.rb +8 -0
  42. data/lib/ecoportal/api/graphql/base/page/data_field/mailbox.rb +9 -0
  43. data/lib/ecoportal/api/graphql/base/page/data_field/number.rb +20 -0
  44. data/lib/ecoportal/api/graphql/base/page/data_field/people.rb +35 -0
  45. data/lib/ecoportal/api/graphql/base/page/data_field/plain_text.rb +17 -0
  46. data/lib/ecoportal/api/graphql/base/page/data_field/rich_text.rb +26 -0
  47. data/lib/ecoportal/api/graphql/base/page/data_field/select.rb +41 -0
  48. data/lib/ecoportal/api/graphql/base/page/data_field/signature.rb +9 -0
  49. data/lib/ecoportal/api/graphql/base/page/data_field/smart_fill.rb +17 -0
  50. data/lib/ecoportal/api/graphql/base/page/data_field/table.rb +9 -0
  51. data/lib/ecoportal/api/graphql/base/page/data_field/tag_field.rb +21 -0
  52. data/lib/ecoportal/api/graphql/base/page/data_field.rb +137 -12
  53. data/lib/ecoportal/api/graphql/base/page/phased/stage.rb +68 -14
  54. data/lib/ecoportal/api/graphql/base/page/phased.rb +1 -0
  55. data/lib/ecoportal/api/graphql/base/page/section.rb +36 -0
  56. data/lib/ecoportal/api/graphql/base/page/section_collection.rb +85 -0
  57. data/lib/ecoportal/api/graphql/base/page/task.rb +24 -0
  58. data/lib/ecoportal/api/graphql/base/page.rb +17 -14
  59. data/lib/ecoportal/api/graphql/base/pages_workflow/action_type_selection.rb +17 -0
  60. data/lib/ecoportal/api/graphql/base/pages_workflow/callback_type.rb +28 -0
  61. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change.rb +17 -0
  62. data/lib/ecoportal/api/graphql/base/pages_workflow/command_change_message.rb +15 -0
  63. data/lib/ecoportal/api/graphql/base/pages_workflow/command_es_change.rb +17 -0
  64. data/lib/ecoportal/api/graphql/base/pages_workflow/command_interface.rb +36 -0
  65. data/lib/ecoportal/api/graphql/base/pages_workflow/email_config.rb +18 -0
  66. data/lib/ecoportal/api/graphql/base/pages_workflow/escalation_level.rb +19 -0
  67. data/lib/ecoportal/api/graphql/base/pages_workflow/in_system_config.rb +16 -0
  68. data/lib/ecoportal/api/graphql/base/pages_workflow/mailbox_field_selection.rb +17 -0
  69. data/lib/ecoportal/api/graphql/base/pages_workflow/operation_interface.rb +39 -0
  70. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/assign_to.rb +27 -0
  71. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/create_page.rb +21 -0
  72. data/lib/ecoportal/api/graphql/base/pages_workflow/operations/send_notification.rb +30 -0
  73. data/lib/ecoportal/api/graphql/base/pages_workflow/people_field_selection.rb +17 -0
  74. data/lib/ecoportal/api/graphql/base/pages_workflow/recipient_config.rb +34 -0
  75. data/lib/ecoportal/api/graphql/base/pages_workflow/register_field.rb +17 -0
  76. data/lib/ecoportal/api/graphql/base/pages_workflow/task_config_selection.rb +17 -0
  77. data/lib/ecoportal/api/graphql/base/pages_workflow/time_delay_config.rb +16 -0
  78. data/lib/ecoportal/api/graphql/base/pages_workflow/trigger_interface.rb +26 -0
  79. data/lib/ecoportal/api/graphql/base/pages_workflow/triggers/conditional_logic.rb +17 -0
  80. data/lib/ecoportal/api/graphql/base/pages_workflow/user_selection.rb +16 -0
  81. data/lib/ecoportal/api/graphql/base/pages_workflow.rb +35 -0
  82. data/lib/ecoportal/api/graphql/base/preset_view.rb +17 -0
  83. data/lib/ecoportal/api/graphql/base/preview_page.rb +23 -0
  84. data/lib/ecoportal/api/graphql/base/register.rb +18 -0
  85. data/lib/ecoportal/api/graphql/base/template.rb +35 -0
  86. data/lib/ecoportal/api/graphql/base.rb +37 -24
  87. data/lib/ecoportal/api/graphql/builder/CLAUDE.md +65 -0
  88. data/lib/ecoportal/api/graphql/builder/contractor_entity.rb +41 -41
  89. data/lib/ecoportal/api/graphql/builder/kickstand.rb +73 -0
  90. data/lib/ecoportal/api/graphql/builder/page.rb +210 -41
  91. data/lib/ecoportal/api/graphql/builder/register/preset_view.rb +84 -0
  92. data/lib/ecoportal/api/graphql/builder/register.rb +27 -19
  93. data/lib/ecoportal/api/graphql/builder/template.rb +80 -0
  94. data/lib/ecoportal/api/graphql/builder/template_builder.rb +174 -0
  95. data/lib/ecoportal/api/graphql/builder.rb +17 -14
  96. data/lib/ecoportal/api/graphql/compat/filter_translator.rb +142 -0
  97. data/lib/ecoportal/api/graphql/compat/page_reference.rb +23 -0
  98. data/lib/ecoportal/api/graphql/compat/pages.rb +212 -0
  99. data/lib/ecoportal/api/graphql/compat/registers.rb +84 -0
  100. data/lib/ecoportal/api/graphql/compat/response.rb +35 -0
  101. data/lib/ecoportal/api/graphql/compat/search_results.rb +33 -0
  102. data/lib/ecoportal/api/graphql/compat/stage_collection.rb +70 -0
  103. data/lib/ecoportal/api/graphql/compat/stage_view.rb +76 -0
  104. data/lib/ecoportal/api/graphql/compat.rb +17 -0
  105. data/lib/ecoportal/api/graphql/concerns/data_field_access.rb +71 -0
  106. data/lib/ecoportal/api/graphql/concerns/deprecation.rb +20 -0
  107. data/lib/ecoportal/api/graphql/concerns/fragment_definitions.rb +21 -28
  108. data/lib/ecoportal/api/graphql/concerns/page_compat.rb +51 -0
  109. data/lib/ecoportal/api/graphql/concerns/snake_camel_access.rb +60 -0
  110. data/lib/ecoportal/api/graphql/concerns.rb +14 -10
  111. data/lib/ecoportal/api/graphql/connection/action.rb +11 -11
  112. data/lib/ecoportal/api/graphql/connection/action_category.rb +11 -11
  113. data/lib/ecoportal/api/graphql/connection/contractor_entity.rb +11 -11
  114. data/lib/ecoportal/api/graphql/connection/page.rb +11 -0
  115. data/lib/ecoportal/api/graphql/connection/pages_workflow_command.rb +13 -0
  116. data/lib/ecoportal/api/graphql/connection/person_member.rb +11 -11
  117. data/lib/ecoportal/api/graphql/connection/preset_view.rb +11 -0
  118. data/lib/ecoportal/api/graphql/connection/preview_page.rb +11 -0
  119. data/lib/ecoportal/api/graphql/connection.rb +17 -13
  120. data/lib/ecoportal/api/graphql/diff/change.rb +59 -0
  121. data/lib/ecoportal/api/graphql/diff/command_synthesizer.rb +329 -0
  122. data/lib/ecoportal/api/graphql/diff/cross_object_diff.rb +165 -0
  123. data/lib/ecoportal/api/graphql/diff/deploy.rb +121 -0
  124. data/lib/ecoportal/api/graphql/diff/id_resolver.rb +64 -0
  125. data/lib/ecoportal/api/graphql/diff/pairing/candidate.rb +32 -0
  126. data/lib/ecoportal/api/graphql/diff/pairing/engine.rb +173 -0
  127. data/lib/ecoportal/api/graphql/diff/pairing/ledger.rb +119 -0
  128. data/lib/ecoportal/api/graphql/diff/pairing/signals.rb +104 -0
  129. data/lib/ecoportal/api/graphql/diff/strategy.rb +113 -0
  130. data/lib/ecoportal/api/graphql/diff/version_diff.rb +332 -0
  131. data/lib/ecoportal/api/graphql/diff.rb +34 -0
  132. data/lib/ecoportal/api/graphql/file_upload/client.rb +192 -0
  133. data/lib/ecoportal/api/graphql/file_upload.rb +10 -0
  134. data/lib/ecoportal/api/graphql/fragment/action.rb +1 -1
  135. data/lib/ecoportal/api/graphql/fragment/action_category.rb +1 -1
  136. data/lib/ecoportal/api/graphql/fragment/contractor_entity.rb +1 -1
  137. data/lib/ecoportal/api/graphql/fragment/field_configuration.rb +38 -0
  138. data/lib/ecoportal/api/graphql/fragment/force.rb +34 -0
  139. data/lib/ecoportal/api/graphql/fragment/location_draft.rb +53 -53
  140. data/lib/ecoportal/api/graphql/fragment/location_node.rb +26 -26
  141. data/lib/ecoportal/api/graphql/fragment/locations_error.rb +1 -1
  142. data/lib/ecoportal/api/graphql/fragment/page.rb +85 -0
  143. data/lib/ecoportal/api/graphql/fragment/page_task.rb +39 -0
  144. data/lib/ecoportal/api/graphql/fragment/pages/common_page_union.rb +396 -0
  145. data/lib/ecoportal/api/graphql/fragment/pages.rb +15 -0
  146. data/lib/ecoportal/api/graphql/fragment/pages_workflow.rb +172 -0
  147. data/lib/ecoportal/api/graphql/fragment/pagination.rb +1 -1
  148. data/lib/ecoportal/api/graphql/fragment/template.rb +51 -0
  149. data/lib/ecoportal/api/graphql/fragment.rb +40 -27
  150. data/lib/ecoportal/api/graphql/input/action/update.rb +14 -14
  151. data/lib/ecoportal/api/graphql/input/contractor_entity/update.rb +41 -16
  152. data/lib/ecoportal/api/graphql/input/contractor_entity.rb +14 -14
  153. data/lib/ecoportal/api/graphql/input/delta_input.rb +16 -0
  154. data/lib/ecoportal/api/graphql/input/location_structure/apply_commands.rb +47 -47
  155. data/lib/ecoportal/api/graphql/input/location_structure/draft/add_commands.rb +49 -49
  156. data/lib/ecoportal/api/graphql/input/location_structure/update_command.rb +27 -27
  157. data/lib/ecoportal/api/graphql/input/page/archive.rb +14 -0
  158. data/lib/ecoportal/api/graphql/input/page/build_from_template.rb +13 -0
  159. data/lib/ecoportal/api/graphql/input/page/create_draft.rb +13 -0
  160. data/lib/ecoportal/api/graphql/input/page/create_from_template.rb +18 -0
  161. data/lib/ecoportal/api/graphql/input/page/delete_draft.rb +13 -0
  162. data/lib/ecoportal/api/graphql/input/page/publish_draft.rb +13 -0
  163. data/lib/ecoportal/api/graphql/input/page/review_task.rb +14 -0
  164. data/lib/ecoportal/api/graphql/input/page/unarchive.rb +14 -0
  165. data/lib/ecoportal/api/graphql/input/page/update.rb +140 -0
  166. data/lib/ecoportal/api/graphql/input/page.rb +26 -0
  167. data/lib/ecoportal/api/graphql/input/preset_view/create.rb +18 -0
  168. data/lib/ecoportal/api/graphql/input/preset_view/permission.rb +16 -0
  169. data/lib/ecoportal/api/graphql/input/preset_view/update.rb +16 -0
  170. data/lib/ecoportal/api/graphql/input/preset_view.rb +14 -0
  171. data/lib/ecoportal/api/graphql/input/register/create.rb +18 -0
  172. data/lib/ecoportal/api/graphql/input/register/update.rb +15 -0
  173. data/lib/ecoportal/api/graphql/input/register.rb +13 -0
  174. data/lib/ecoportal/api/graphql/input/search_conf/ai_generator.rb +234 -0
  175. data/lib/ecoportal/api/graphql/input/search_conf.rb +436 -0
  176. data/lib/ecoportal/api/graphql/input/variable_binding.rb +20 -0
  177. data/lib/ecoportal/api/graphql/input/workflow_command/add_action_tag.rb +18 -0
  178. data/lib/ecoportal/api/graphql/input/workflow_command/add_binding.rb +18 -0
  179. data/lib/ecoportal/api/graphql/input/workflow_command/add_comment_tagging_user_group.rb +18 -0
  180. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_direct_strategy_user.rb +18 -0
  181. data/lib/ecoportal/api/graphql/input/workflow_command/add_default_strategy.rb +18 -0
  182. data/lib/ecoportal/api/graphql/input/workflow_command/add_direct_strategy_user.rb +18 -0
  183. data/lib/ecoportal/api/graphql/input/workflow_command/add_field.rb +27 -0
  184. data/lib/ecoportal/api/graphql/input/workflow_command/add_force.rb +18 -0
  185. data/lib/ecoportal/api/graphql/input/workflow_command/add_gauge_field_stop.rb +19 -0
  186. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_field_config.rb +23 -0
  187. data/lib/ecoportal/api/graphql/input/workflow_command/add_linked_helper.rb +18 -0
  188. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation.rb +18 -0
  189. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_direct_strategy_user.rb +18 -0
  190. data/lib/ecoportal/api/graphql/input/workflow_command/add_operation_strategy.rb +18 -0
  191. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_action_type.rb +18 -0
  192. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_filter.rb +18 -0
  193. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_people_field.rb +18 -0
  194. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_task_config.rb +18 -0
  195. data/lib/ecoportal/api/graphql/input/workflow_command/add_recipient_user.rb +18 -0
  196. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback.rb +23 -0
  197. data/lib/ecoportal/api/graphql/input/workflow_command/add_scheduled_callback_action.rb +18 -0
  198. data/lib/ecoportal/api/graphql/input/workflow_command/add_section.rb +18 -0
  199. data/lib/ecoportal/api/graphql/input/workflow_command/add_select_field_option.rb +19 -0
  200. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage.rb +18 -0
  201. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_section.rb +18 -0
  202. data/lib/ecoportal/api/graphql/input/workflow_command/add_stage_tag.rb +18 -0
  203. data/lib/ecoportal/api/graphql/input/workflow_command/add_strategy.rb +18 -0
  204. data/lib/ecoportal/api/graphql/input/workflow_command/add_task.rb +18 -0
  205. data/lib/ecoportal/api/graphql/input/workflow_command/add_task_assignment_user_group.rb +18 -0
  206. data/lib/ecoportal/api/graphql/input/workflow_command/add_workflow_callback.rb +18 -0
  207. data/lib/ecoportal/api/graphql/input/workflow_command/collapse_section.rb +18 -0
  208. data/lib/ecoportal/api/graphql/input/workflow_command/edit_binding.rb +18 -0
  209. data/lib/ecoportal/api/graphql/input/workflow_command/edit_creator_permissions.rb +18 -0
  210. data/lib/ecoportal/api/graphql/input/workflow_command/edit_default_strategy.rb +18 -0
  211. data/lib/ecoportal/api/graphql/input/workflow_command/edit_field_configuration.rb +21 -0
  212. data/lib/ecoportal/api/graphql/input/workflow_command/edit_force.rb +18 -0
  213. data/lib/ecoportal/api/graphql/input/workflow_command/edit_gauge_field_stop.rb +19 -0
  214. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_field_config.rb +19 -0
  215. data/lib/ecoportal/api/graphql/input/workflow_command/edit_linked_helper.rb +18 -0
  216. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation.rb +18 -0
  217. data/lib/ecoportal/api/graphql/input/workflow_command/edit_operation_strategy.rb +18 -0
  218. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page.rb +28 -0
  219. data/lib/ecoportal/api/graphql/input/workflow_command/edit_page_creator_permissions.rb +18 -0
  220. data/lib/ecoportal/api/graphql/input/workflow_command/edit_reminder.rb +18 -0
  221. data/lib/ecoportal/api/graphql/input/workflow_command/edit_required_sign_offs.rb +18 -0
  222. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_comment_tagging.rb +18 -0
  223. data/lib/ecoportal/api/graphql/input/workflow_command/edit_restrict_task_assignment.rb +18 -0
  224. data/lib/ecoportal/api/graphql/input/workflow_command/edit_scheduled_callback.rb +22 -0
  225. data/lib/ecoportal/api/graphql/input/workflow_command/edit_section_header.rb +18 -0
  226. data/lib/ecoportal/api/graphql/input/workflow_command/edit_select_field_option.rb +19 -0
  227. data/lib/ecoportal/api/graphql/input/workflow_command/edit_stage.rb +18 -0
  228. data/lib/ecoportal/api/graphql/input/workflow_command/edit_strategy.rb +18 -0
  229. data/lib/ecoportal/api/graphql/input/workflow_command/edit_task_due.rb +18 -0
  230. data/lib/ecoportal/api/graphql/input/workflow_command/edit_trigger.rb +18 -0
  231. data/lib/ecoportal/api/graphql/input/workflow_command/expand_section.rb +18 -0
  232. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/contractor_entities.rb +24 -0
  233. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/cross_reference.rb +23 -0
  234. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/date.rb +20 -0
  235. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/gauge.rb +20 -0
  236. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/image_gallery.rb +20 -0
  237. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/location_field.rb +24 -0
  238. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/people.rb +24 -0
  239. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/plain_text.rb +20 -0
  240. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/rich_text.rb +20 -0
  241. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/select.rb +20 -0
  242. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/signature.rb +20 -0
  243. data/lib/ecoportal/api/graphql/input/workflow_command/field_config/table.rb +25 -0
  244. data/lib/ecoportal/api/graphql/input/workflow_command/move_field.rb +18 -0
  245. data/lib/ecoportal/api/graphql/input/workflow_command/move_stage.rb +18 -0
  246. data/lib/ecoportal/api/graphql/input/workflow_command/remove_action_tag.rb +18 -0
  247. data/lib/ecoportal/api/graphql/input/workflow_command/remove_binding.rb +18 -0
  248. data/lib/ecoportal/api/graphql/input/workflow_command/remove_callback.rb +18 -0
  249. data/lib/ecoportal/api/graphql/input/workflow_command/remove_comment_tagging_user_group.rb +18 -0
  250. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_direct_strategy_user.rb +18 -0
  251. data/lib/ecoportal/api/graphql/input/workflow_command/remove_default_strategy.rb +18 -0
  252. data/lib/ecoportal/api/graphql/input/workflow_command/remove_direct_strategy_user.rb +18 -0
  253. data/lib/ecoportal/api/graphql/input/workflow_command/remove_field.rb +18 -0
  254. data/lib/ecoportal/api/graphql/input/workflow_command/remove_force.rb +18 -0
  255. data/lib/ecoportal/api/graphql/input/workflow_command/remove_gauge_field_stop.rb +17 -0
  256. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_field_config.rb +17 -0
  257. data/lib/ecoportal/api/graphql/input/workflow_command/remove_linked_helper.rb +18 -0
  258. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation.rb +18 -0
  259. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_direct_strategy_user.rb +18 -0
  260. data/lib/ecoportal/api/graphql/input/workflow_command/remove_operation_strategy.rb +18 -0
  261. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_action_type.rb +18 -0
  262. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_filter.rb +18 -0
  263. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_people_field.rb +18 -0
  264. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_task_config.rb +18 -0
  265. data/lib/ecoportal/api/graphql/input/workflow_command/remove_recipient_user.rb +18 -0
  266. data/lib/ecoportal/api/graphql/input/workflow_command/remove_scheduled_callback.rb +18 -0
  267. data/lib/ecoportal/api/graphql/input/workflow_command/remove_section.rb +18 -0
  268. data/lib/ecoportal/api/graphql/input/workflow_command/remove_select_field_option.rb +17 -0
  269. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage.rb +18 -0
  270. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_section.rb +18 -0
  271. data/lib/ecoportal/api/graphql/input/workflow_command/remove_stage_tag.rb +18 -0
  272. data/lib/ecoportal/api/graphql/input/workflow_command/remove_strategy.rb +18 -0
  273. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task.rb +18 -0
  274. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_assignment_user_group.rb +18 -0
  275. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_due.rb +18 -0
  276. data/lib/ecoportal/api/graphql/input/workflow_command/remove_task_priority_level.rb +18 -0
  277. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_forces.rb +18 -0
  278. data/lib/ecoportal/api/graphql/input/workflow_command/reorder_section.rb +18 -0
  279. data/lib/ecoportal/api/graphql/input/workflow_command.rb +251 -0
  280. data/lib/ecoportal/api/graphql/input.rb +24 -16
  281. data/lib/ecoportal/api/graphql/interface/base_page.rb +100 -58
  282. data/lib/ecoportal/api/graphql/interface/location_structure/command.rb +30 -30
  283. data/lib/ecoportal/api/graphql/interface/location_structure/nodes.rb +27 -28
  284. data/lib/ecoportal/api/graphql/logic/base_model.rb +2 -0
  285. data/lib/ecoportal/api/graphql/logic/base_query.rb +45 -2
  286. data/lib/ecoportal/api/graphql/logic/connection.rb +34 -34
  287. data/lib/ecoportal/api/graphql/logic/input.rb +26 -11
  288. data/lib/ecoportal/api/graphql/model/ai_summary_version.rb +10 -0
  289. data/lib/ecoportal/api/graphql/model/organization.rb +65 -55
  290. data/lib/ecoportal/api/graphql/model/page/basic.rb +14 -0
  291. data/lib/ecoportal/api/graphql/model/page/phased.rb +82 -20
  292. data/lib/ecoportal/api/graphql/model/page/task.rb +16 -0
  293. data/lib/ecoportal/api/graphql/model/page.rb +16 -14
  294. data/lib/ecoportal/api/graphql/model/page_union.rb +21 -0
  295. data/lib/ecoportal/api/graphql/model/pages_workflow.rb +20 -0
  296. data/lib/ecoportal/api/graphql/model/person_member.rb +15 -15
  297. data/lib/ecoportal/api/graphql/model/preset_view.rb +10 -0
  298. data/lib/ecoportal/api/graphql/model/preview_page.rb +10 -0
  299. data/lib/ecoportal/api/graphql/model/register.rb +10 -0
  300. data/lib/ecoportal/api/graphql/model/template.rb +15 -0
  301. data/lib/ecoportal/api/graphql/model.rb +32 -22
  302. data/lib/ecoportal/api/graphql/mutation/action/archive.rb +1 -1
  303. data/lib/ecoportal/api/graphql/mutation/action/create.rb +1 -1
  304. data/lib/ecoportal/api/graphql/mutation/action/update.rb +1 -1
  305. data/lib/ecoportal/api/graphql/mutation/ai_summary/generate.rb +45 -0
  306. data/lib/ecoportal/api/graphql/mutation/ai_summary/submit_feedback.rb +40 -0
  307. data/lib/ecoportal/api/graphql/mutation/ai_summary.rb +13 -0
  308. data/lib/ecoportal/api/graphql/mutation/contractor_entity/create.rb +1 -1
  309. data/lib/ecoportal/api/graphql/mutation/contractor_entity/destroy.rb +1 -1
  310. data/lib/ecoportal/api/graphql/mutation/contractor_entity/update.rb +1 -1
  311. data/lib/ecoportal/api/graphql/mutation/contractor_entity.rb +14 -14
  312. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_jobs.rb +43 -0
  313. data/lib/ecoportal/api/graphql/mutation/kickstand/bulk_update_workflows.rb +43 -0
  314. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_job.rb +39 -0
  315. data/lib/ecoportal/api/graphql/mutation/kickstand/fail_workflow.rb +39 -0
  316. data/lib/ecoportal/api/graphql/mutation/kickstand/start_job.rb +39 -0
  317. data/lib/ecoportal/api/graphql/mutation/kickstand/start_workflow.rb +39 -0
  318. data/lib/ecoportal/api/graphql/mutation/kickstand/stop_workflow.rb +39 -0
  319. data/lib/ecoportal/api/graphql/mutation/kickstand.rb +18 -0
  320. data/lib/ecoportal/api/graphql/mutation/location_structure/apply_commands.rb +3 -3
  321. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/add_commands.rb +2 -2
  322. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/create.rb +2 -2
  323. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/drop_bad_commands.rb +3 -3
  324. data/lib/ecoportal/api/graphql/mutation/location_structure/draft/publish.rb +3 -3
  325. data/lib/ecoportal/api/graphql/mutation/page/approve_review_task.rb +40 -0
  326. data/lib/ecoportal/api/graphql/mutation/page/archive.rb +40 -0
  327. data/lib/ecoportal/api/graphql/mutation/page/batch_update_review_task.rb +38 -0
  328. data/lib/ecoportal/api/graphql/mutation/page/build_from_template.rb +50 -0
  329. data/lib/ecoportal/api/graphql/mutation/page/create_draft.rb +38 -0
  330. data/lib/ecoportal/api/graphql/mutation/page/create_from_template.rb +43 -0
  331. data/lib/ecoportal/api/graphql/mutation/page/delete_draft.rb +38 -0
  332. data/lib/ecoportal/api/graphql/mutation/page/execute_force_commands.rb +69 -0
  333. data/lib/ecoportal/api/graphql/mutation/page/execute_workflow_commands.rb +52 -0
  334. data/lib/ecoportal/api/graphql/mutation/page/publish_draft.rb +38 -0
  335. data/lib/ecoportal/api/graphql/mutation/page/reject_review_task.rb +40 -0
  336. data/lib/ecoportal/api/graphql/mutation/page/restart_review_task.rb +40 -0
  337. data/lib/ecoportal/api/graphql/mutation/page/unarchive.rb +40 -0
  338. data/lib/ecoportal/api/graphql/mutation/page/undo_review_task.rb +40 -0
  339. data/lib/ecoportal/api/graphql/mutation/page/update.rb +40 -0
  340. data/lib/ecoportal/api/graphql/mutation/page/update_variable_bindings.rb +44 -0
  341. data/lib/ecoportal/api/graphql/mutation/page.rb +28 -0
  342. data/lib/ecoportal/api/graphql/mutation/preset_view/create.rb +35 -0
  343. data/lib/ecoportal/api/graphql/mutation/preset_view/destroy.rb +34 -0
  344. data/lib/ecoportal/api/graphql/mutation/preset_view/permission.rb +37 -0
  345. data/lib/ecoportal/api/graphql/mutation/preset_view/update.rb +35 -0
  346. data/lib/ecoportal/api/graphql/mutation/preset_view.rb +15 -0
  347. data/lib/ecoportal/api/graphql/mutation/register/create.rb +35 -0
  348. data/lib/ecoportal/api/graphql/mutation/register/destroy.rb +35 -0
  349. data/lib/ecoportal/api/graphql/mutation/register/update.rb +35 -0
  350. data/lib/ecoportal/api/graphql/mutation/register.rb +14 -0
  351. data/lib/ecoportal/api/graphql/mutation/smart_fill/generate.rb +36 -0
  352. data/lib/ecoportal/api/graphql/mutation/smart_fill/submit_feedback.rb +40 -0
  353. data/lib/ecoportal/api/graphql/mutation/smart_fill.rb +13 -0
  354. data/lib/ecoportal/api/graphql/mutation/template/create.rb +39 -0
  355. data/lib/ecoportal/api/graphql/mutation/template/create_related_page.rb +46 -0
  356. data/lib/ecoportal/api/graphql/mutation/template/destroy_related_page.rb +43 -0
  357. data/lib/ecoportal/api/graphql/mutation/template/publish.rb +39 -0
  358. data/lib/ecoportal/api/graphql/mutation/template/unpublish.rb +39 -0
  359. data/lib/ecoportal/api/graphql/mutation/template/update.rb +43 -0
  360. data/lib/ecoportal/api/graphql/mutation/template/update_information.rb +43 -0
  361. data/lib/ecoportal/api/graphql/mutation/template.rb +18 -0
  362. data/lib/ecoportal/api/graphql/mutation.rb +20 -12
  363. data/lib/ecoportal/api/graphql/payload/ai_summary_generate.rb +12 -0
  364. data/lib/ecoportal/api/graphql/payload/contractor_entity.rb +14 -14
  365. data/lib/ecoportal/api/graphql/payload/execute_workflow_commands.rb +36 -0
  366. data/lib/ecoportal/api/graphql/payload/force_commands.rb +31 -0
  367. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_jobs.rb +36 -0
  368. data/lib/ecoportal/api/graphql/payload/kickstand/bulk_update_workflows.rb +36 -0
  369. data/lib/ecoportal/api/graphql/payload/kickstand/job.rb +13 -0
  370. data/lib/ecoportal/api/graphql/payload/kickstand/workflow.rb +13 -0
  371. data/lib/ecoportal/api/graphql/payload/kickstand.rb +15 -0
  372. data/lib/ecoportal/api/graphql/payload/location_structure/draft/create.rb +33 -34
  373. data/lib/ecoportal/api/graphql/payload/ok_payload.rb +36 -0
  374. data/lib/ecoportal/api/graphql/payload/page/archive.rb +13 -0
  375. data/lib/ecoportal/api/graphql/payload/page/build_from_template.rb +13 -0
  376. data/lib/ecoportal/api/graphql/payload/page/create_from_template.rb +13 -0
  377. data/lib/ecoportal/api/graphql/payload/page/draft.rb +26 -0
  378. data/lib/ecoportal/api/graphql/payload/page/review_task.rb +13 -0
  379. data/lib/ecoportal/api/graphql/payload/page/review_task_batch.rb +23 -0
  380. data/lib/ecoportal/api/graphql/payload/page/unarchive.rb +13 -0
  381. data/lib/ecoportal/api/graphql/payload/page/update.rb +13 -0
  382. data/lib/ecoportal/api/graphql/payload/page/update_variable_bindings.rb +13 -0
  383. data/lib/ecoportal/api/graphql/payload/page.rb +20 -0
  384. data/lib/ecoportal/api/graphql/payload/preset_view.rb +15 -0
  385. data/lib/ecoportal/api/graphql/payload/register.rb +15 -0
  386. data/lib/ecoportal/api/graphql/payload/template/create.rb +13 -0
  387. data/lib/ecoportal/api/graphql/payload/template/create_related_page.rb +13 -0
  388. data/lib/ecoportal/api/graphql/payload/template/destroy_related_page.rb +13 -0
  389. data/lib/ecoportal/api/graphql/payload/template/publish.rb +13 -0
  390. data/lib/ecoportal/api/graphql/payload/template/unpublish.rb +13 -0
  391. data/lib/ecoportal/api/graphql/payload/template/update.rb +13 -0
  392. data/lib/ecoportal/api/graphql/payload/template/update_information.rb +13 -0
  393. data/lib/ecoportal/api/graphql/payload/template.rb +18 -0
  394. data/lib/ecoportal/api/graphql/payload.rb +23 -12
  395. data/lib/ecoportal/api/graphql/query/action.rb +1 -1
  396. data/lib/ecoportal/api/graphql/query/action_categories.rb +1 -1
  397. data/lib/ecoportal/api/graphql/query/actions.rb +2 -2
  398. data/lib/ecoportal/api/graphql/query/contractor_entities.rb +1 -1
  399. data/lib/ecoportal/api/graphql/query/file_upload_signature.rb +76 -0
  400. data/lib/ecoportal/api/graphql/query/location_structure/draft.rb +62 -62
  401. data/lib/ecoportal/api/graphql/query/location_structure.rb +61 -61
  402. data/lib/ecoportal/api/graphql/query/location_structures.rb +57 -57
  403. data/lib/ecoportal/api/graphql/query/page.rb +45 -0
  404. data/lib/ecoportal/api/graphql/query/page_delta.rb +47 -0
  405. data/lib/ecoportal/api/graphql/query/page_with_forces.rb +49 -0
  406. data/lib/ecoportal/api/graphql/query/pages.rb +59 -0
  407. data/lib/ecoportal/api/graphql/query/pages_workflow_commands.rb +65 -0
  408. data/lib/ecoportal/api/graphql/query/register_preset_views.rb +78 -0
  409. data/lib/ecoportal/api/graphql/query/register_preview_pages.rb +83 -0
  410. data/lib/ecoportal/api/graphql/query/templates.rb +53 -0
  411. data/lib/ecoportal/api/graphql/query.rb +27 -16
  412. data/lib/ecoportal/api/graphql.rb +143 -80
  413. data/lib/ecoportal/api/graphql_version.rb +5 -5
  414. metadata +333 -25
  415. data/.gitignore +0 -24
  416. data/.markdownlint.json +0 -4
  417. data/.rspec +0 -3
  418. data/.rubocop.yml +0 -97
  419. data/.ruby-version +0 -1
  420. data/.yardopts +0 -10
  421. data/Gemfile +0 -6
  422. data/Rakefile +0 -38
  423. data/bin/console +0 -14
  424. data/bin/setup +0 -8
  425. data/bin/setup.ps1 +0 -6
  426. data/ecoportal-api-graphql.gemspec +0 -40
  427. data/tests/actions_get.rb +0 -7
  428. data/tests/contractor_entities_get.rb +0 -20
  429. data/tests/contractor_entity_create.rb +0 -19
  430. data/tests/contractor_entity_udpate.rb +0 -20
  431. data/tests/loc_structure_get.rb +0 -11
  432. data/tests/loc_structure_update.rb +0 -51
  433. data/tests/loc_structures_get.rb +0 -15
  434. data/tests/local_libs.rb +0 -20
@@ -0,0 +1,80 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Builder
5
+ class Template
6
+ attr_reader :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ def create(commands:, &block)
13
+ createMutation.query(commands: commands, &block)
14
+ end
15
+
16
+ def update(model, commands:, patch_ver: model.patchVer, &block)
17
+ updateMutation.query(id: model.id, patch_ver: patch_ver, commands: commands, &block)
18
+ end
19
+
20
+ def publish(id:, &block)
21
+ publishMutation.query(id: id, &block)
22
+ end
23
+
24
+ def unpublish(id:, &block)
25
+ unpublishMutation.query(id: id, &block)
26
+ end
27
+
28
+ def update_information(id:, **kargs, &block)
29
+ updateInformationMutation.query(id: id, **kargs, &block)
30
+ end
31
+
32
+ def create_related_page(template_id:, title:, register_id:, patch_ver:, filters: nil, &block)
33
+ createRelatedPageMutation.query(
34
+ template_id: template_id,
35
+ title: title,
36
+ register_id: register_id,
37
+ patch_ver: patch_ver,
38
+ filters: filters,
39
+ &block
40
+ )
41
+ end
42
+
43
+ def destroy_related_page(template_id:, id:, patch_ver:, &block)
44
+ destroyRelatedPageMutation.query(template_id: template_id, id: id, patch_ver: patch_ver, &block)
45
+ end
46
+
47
+ private
48
+
49
+ def createMutation
50
+ Mutation::Template::Create.new(client)
51
+ end
52
+
53
+ def updateMutation
54
+ Mutation::Template::Update.new(client)
55
+ end
56
+
57
+ def publishMutation
58
+ Mutation::Template::Publish.new(client)
59
+ end
60
+
61
+ def unpublishMutation
62
+ Mutation::Template::Unpublish.new(client)
63
+ end
64
+
65
+ def updateInformationMutation
66
+ Mutation::Template::UpdateInformation.new(client)
67
+ end
68
+
69
+ def createRelatedPageMutation
70
+ Mutation::Template::CreateRelatedPage.new(client)
71
+ end
72
+
73
+ def destroyRelatedPageMutation
74
+ Mutation::Template::DestroyRelatedPage.new(client)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,174 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Builder
5
+ # Build-from-scratch emitter for a template/workflow: turns a DECLARATIVE spec
6
+ # (stages -> sections -> fields -> options / config / gauge-stops) into an ordered batch of
7
+ # built `WorkflowCommand` hashes, ready for `Builder::Template#create(commands:)` /
8
+ # `#update(model, commands:)` (which wrap `executeWorkflowCommands`).
9
+ #
10
+ # This is the gem-level, reusable BUILD emitter (previously a one-off in eco-helpers samples).
11
+ # It shares ONE emission layer with the DIFF-DEPLOY pipeline: both produce an ordered
12
+ # `WorkflowCommand` batch, and both use the SAME `placeholderId` id-threading primitive that
13
+ # `Diff::CommandSynthesizer` uses — a newly-created node is addressed by a client-chosen
14
+ # `placeholderId`, and every later command in the same batch that references it substitutes
15
+ # that placeholder (the server has not assigned real ids yet). Here every node is brand new,
16
+ # so the whole batch is threaded through placeholders.
17
+ #
18
+ # SPEC SHAPE (all keys optional unless noted; only VALID command inputs are emitted):
19
+ #
20
+ # {
21
+ # stages: [
22
+ # { name: 'Report', ordering: 0, sections: [ # addStage(name, ordering)
23
+ # { layout: 'ONE_COLUMN', fields: [ # addSection(layout) + addStageSection
24
+ # { field_type: 'PlainText', label: 'Description', column: 0,
25
+ # description: 'ID:token' }, # addField (+ editFieldConfiguration for description)
26
+ # { field_type: 'Select', label: 'Severity',
27
+ # options: [ { label: 'Low', weight: 0 }, ... ], # addSelectFieldOption
28
+ # config: { select: { multiple: false } } }, # editFieldConfiguration(byType:)
29
+ # { field_type: 'Gauge', label: 'Risk',
30
+ # stops: [ { threshold: 0, color: '#0f0' }, ... ], # addGaugeFieldStop
31
+ # config: { gauge: { max: 100.0 } } }
32
+ # ] }
33
+ # ] }
34
+ # ]
35
+ # }
36
+ #
37
+ # ORDER — addStage -> addSection -> addStageSection -> addField -> (addSelectFieldOption |
38
+ # addGaugeFieldStop | editFieldConfiguration). This is the dependency-safe order the workflow
39
+ # command bus expects; placeholderId resolution makes the intra-batch references valid.
40
+ #
41
+ # SAFETY — only keys present in each command input's VALID_KEYS are emitted (the input classes
42
+ # slice + compact). A spec key with no corresponding command input is dropped, not fabricated.
43
+ # `field_type` shape and per-type config (`byType`) are NOT invented: config is passed through
44
+ # under its byType sub-hash exactly as given (the caller supplies confirmed byType keys), and
45
+ # is emitted only for a field that carries one.
46
+ class TemplateBuilder
47
+ # @param spec [Hash] the declarative template spec (see class doc). String or symbol keys.
48
+ def initialize(spec)
49
+ @spec = symbolize(spec || {})
50
+ @commands = []
51
+ @counter = 0
52
+ @built = false
53
+ end
54
+
55
+ # Ordered Array of built command hashes ({ commandKey => input }), placeholder-threaded.
56
+ def commands
57
+ return @commands if @built
58
+
59
+ @built = true
60
+ build_all
61
+ end
62
+
63
+ # Ready to hand to `Builder::Template#create(commands: builder.to_commands)`.
64
+ alias_method :to_commands, :commands
65
+
66
+ def to_h
67
+ { commands: commands }
68
+ end
69
+
70
+ private
71
+
72
+ def build_all
73
+ Array(@spec[:stages]).each_with_index { |stage, idx| emit_stage(stage, idx) }
74
+ @commands
75
+ end
76
+
77
+ def emit_stage(stage, index)
78
+ stage_ph = placeholder(:stg)
79
+ add(:addStage, name: stage[:name], ordering: stage.fetch(:ordering, index), placeholderId: stage_ph)
80
+ Array(stage[:sections]).each { |section| emit_section(section, stage_ph) }
81
+ end
82
+
83
+ def emit_section(section, stage_ph)
84
+ section_ph = placeholder(:sec)
85
+ add(:addSection, layout: section[:layout], placeholderId: section_ph)
86
+ # Attach the freshly-created section to its (freshly-created) stage.
87
+ add(:addStageSection, stageId: stage_ph, sectionId: section_ph)
88
+ emit_section_heading(section, section_ph)
89
+ Array(section[:fields]).each { |field| emit_field(field, stage_ph, section_ph) }
90
+ end
91
+
92
+ # A section's heading is not an addSection input; set it via editSectionHeader after create.
93
+ def emit_section_heading(section, section_ph)
94
+ heading = section[:heading]
95
+ return if heading.nil?
96
+
97
+ add(:editSectionHeader, sectionId: section_ph, header: heading)
98
+ end
99
+
100
+ def emit_field(field, stage_ph, section_ph)
101
+ field_ph = placeholder(:fld)
102
+ add(:addField,
103
+ fieldType: field[:field_type] || field[:fieldType],
104
+ label: field[:label],
105
+ stageId: stage_ph,
106
+ sectionId: section_ph,
107
+ column: field[:column],
108
+ placeholderId: field_ph)
109
+ emit_description(field, field_ph)
110
+ emit_options(field, field_ph)
111
+ emit_stops(field, field_ph)
112
+ emit_config(field, field_ph)
113
+ end
114
+
115
+ # A field's `description` is NOT an addField input (the schema's WorkflowAddFieldInput has
116
+ # no `description` key — VERIFIED against the 20260605 dump). It is a top-level key of
117
+ # editFieldConfiguration, so we persist it with a follow-up editFieldConfiguration
118
+ # addressed to the freshly-created field placeholder. Emitted only when supplied. This is
119
+ # the seam the CSV/hidden-field identity token rides on. NOTE: `required` has no schema
120
+ # input key at all, so it is intentionally NOT emitted (a spec `required:` is ignored).
121
+ def emit_description(field, field_ph)
122
+ description = field[:description]
123
+ return if description.nil?
124
+
125
+ add(:editFieldConfiguration, data_field_id: field_ph, description: description)
126
+ end
127
+
128
+ def emit_options(field, field_ph)
129
+ Array(field[:options]).each do |opt|
130
+ add(:addSelectFieldOption, data_field_id: field_ph, label: opt[:label], weight: opt[:weight])
131
+ end
132
+ end
133
+
134
+ def emit_stops(field, field_ph)
135
+ Array(field[:stops]).each do |stop|
136
+ add(:addGaugeFieldStop, data_field_id: field_ph, threshold: stop[:threshold], color: stop[:color])
137
+ end
138
+ end
139
+
140
+ # Per-type field configuration passed through under its byType sub-hash exactly as supplied
141
+ # (e.g. { select: { multiple: true } }, { gauge: { max: 100.0 } }). Emitted only when
142
+ # present; keys are validated/sliced by the EditFieldConfiguration input, never fabricated.
143
+ def emit_config(field, field_ph)
144
+ config = field[:config]
145
+ return if config.nil? || config.empty?
146
+
147
+ add(:editFieldConfiguration, data_field_id: field_ph, byType: symbolize(config))
148
+ end
149
+
150
+ # Build one command and append it. Reuses the SAME builder the diff synthesizer uses, so
151
+ # BUILD and DIFF-DEPLOY emit through one layer.
152
+ def add(command_key, **kwargs)
153
+ @commands << Ecoportal::API::GraphQL::Input::WorkflowCommand.build(command_key, **kwargs)
154
+ end
155
+
156
+ # A deterministic client-chosen placeholderId — the id-threading primitive shared with the
157
+ # diff synthesizer. Prefix marks the node kind for readability of the emitted batch.
158
+ def placeholder(prefix)
159
+ @counter += 1
160
+ "ph_#{prefix}_#{@counter}"
161
+ end
162
+
163
+ def symbolize(value)
164
+ case value
165
+ when Hash then value.each_with_object({}) { |(k, v), h| h[k.to_sym] = symbolize(v) }
166
+ when Array then value.map { |e| symbolize(e) }
167
+ else value
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
@@ -1,14 +1,17 @@
1
- module Ecoportal
2
- module API
3
- class GraphQL
4
- module Builder
5
- end
6
- end
7
- end
8
- end
9
-
10
- require_relative 'builder/location_structure'
11
- require_relative 'builder/action'
12
- require_relative 'builder/contractor_entity'
13
- require_relative 'builder/register'
14
- require_relative 'builder/page'
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Builder
5
+ end
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative 'builder/location_structure'
11
+ require_relative 'builder/action'
12
+ require_relative 'builder/contractor_entity'
13
+ require_relative 'builder/register'
14
+ require_relative 'builder/page'
15
+ require_relative 'builder/kickstand'
16
+ require_relative 'builder/template'
17
+ require_relative 'builder/template_builder'
@@ -0,0 +1,142 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Compat
5
+ # Translates v2-style filter hashes to GraphQL-compatible filter hashes.
6
+ # Extracted from Compat::Registers so any part of the compat layer can use it.
7
+ #
8
+ # SearchConf filter objects (respond_to :to_h, not a Hash) are passed through —
9
+ # callers may also pass already-translated hashes or SearchConf instances directly.
10
+ #
11
+ # v2 → GraphQL translation table:
12
+ # date_filter lbound/ubound → gte/lte; Date FIELD (key 'date.zXXXX') →
13
+ # range_date_filter + membranes.date path; system date → date_filter
14
+ # text_filter {query, key} → match_filter {key, value} (partial text)
15
+ # options_filter Select FIELD (key 'select_str.zXXXX') → has_any_filter
16
+ # {key, path, field_key: 'selected', values} (doesnt_have_any_filter to
17
+ # exclude); system option key → one_of_filter/none_of_filter {key, values}
18
+ # tag_filter passed through (same ES backend, same format)
19
+ # register_filter passed through
20
+ # and_filter / or_filter passed through
21
+ # Operation/param shapes per .ai-assistance/code/search_filters.md.
22
+ class FilterTranslator
23
+ class << self
24
+ def to_graphql(filter)
25
+ return filter if filter.respond_to?(:to_h) && !filter.is_a?(Hash)
26
+ return filter unless filter.is_a?(Hash)
27
+
28
+ case filter['type'] || filter[:type]
29
+ when 'date_filter'
30
+ translate_date_filter(filter)
31
+ when 'text_filter'
32
+ translate_text_filter(filter)
33
+ when 'exact_filter', 'is_filter'
34
+ translate_exact_filter(filter)
35
+ when 'options_filter'
36
+ translate_options_filter(filter)
37
+ else
38
+ filter
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # v2 exact_filter {query/value, key} → GraphQL is_filter (whole-value equality).
45
+ # For a register/page field there is NO `exact_filter` operation — `is_filter` is the
46
+ # exact one: it matches the field's `.exact` keyword subfield (backend
47
+ # NewEp::Es::Filters::Pages::IsFilter → ExactFilter on `membranes.<type>.exact`),
48
+ # whereas match_filter/contains_filter hit the analyzed `.value` and miss exact SKUs.
49
+ # A register FIELD key ('plain_text.zXXXX') needs the nested membranes.<type> path;
50
+ # a SYSTEM key (external_id/id/state/creator_id/source) must NOT carry a path — the
51
+ # backend routes it to Global::ExactFilter which joins [@path,@key] into the term key,
52
+ # so a spurious 'membranes.external_id' yields term 'membranes.external_id.external_id'
53
+ # → 0 results (proof: pages/is_filter.rb:36-55 passes path: @path to Global::ExactFilter;
54
+ # global/exact_filter.rb:18 builds the term as [@path, @key].compact.join(".")).
55
+ # CAVEAT: case-insensitive and only the first 64 chars are significant (values are
56
+ # lowercased + truncated at index time). No case-sensitive/>64-char exact exists.
57
+ def translate_exact_filter(filter)
58
+ key = filter['key'] || filter[:key]
59
+ path = filter['path'] || filter[:path]
60
+ path ||= membrane_path_for(key) if membrane_field?(key)
61
+ value = filter['value'] || filter[:value] || filter['query'] || filter[:query]
62
+ { operation: 'is_filter', params: { key: key, path: path, value: value }.compact }
63
+ end
64
+
65
+ # Derive the ES nested path from a field key: `plain_text.zXXXX` → `membranes.plain_text`.
66
+ def membrane_path_for(key)
67
+ prefix = key.to_s.split('.').first
68
+ prefix.empty? ? nil : "membranes.#{prefix}"
69
+ end
70
+
71
+ # A register FIELD key carries a `<type>.<hash>` shape (e.g. 'date.zab1bddc3',
72
+ # 'select_str.z223beb6d'); system/top-level keys (created_at, id, external_id) have
73
+ # no field-type prefix. Field filters need the nested membranes.<type> path (and,
74
+ # for options, a field_key), which system filters do not.
75
+ def membrane_field?(key)
76
+ key.to_s.include?('.')
77
+ end
78
+
79
+ # v2 text_filter {query, key} → GraphQL match_filter (partial/full-text on key).
80
+ def translate_text_filter(filter)
81
+ {
82
+ operation: 'match_filter',
83
+ params: {
84
+ key: filter['key'] || filter[:key],
85
+ value: filter['query'] || filter[:query] || filter['value'] || filter[:value]
86
+ }
87
+ }
88
+ end
89
+
90
+ # v2 options_filter {chosen, key, mode} → GraphQL.
91
+ # A register Select FIELD (key like 'select_str.zXXXX') filters via
92
+ # has_any_filter / doesnt_have_any_filter over its nested path
93
+ # (membranes.select_str) with field_key 'selected' and the chosen option ids as
94
+ # `values` (backend NewEp::Es::Filters::Pages::*::HasAnyFilter). A system/top-level
95
+ # option key (e.g. 'id') keeps one_of_filter / none_of_filter with {key, values}.
96
+ def translate_options_filter(filter)
97
+ key = filter['key'] || filter[:key]
98
+ values = Array(filter['chosen'] || filter[:chosen])
99
+ exclude = exclude_mode?(filter)
100
+
101
+ unless membrane_field?(key)
102
+ op = exclude ? 'none_of_filter' : 'one_of_filter'
103
+ return { operation: op, params: { key: key, values: values } }
104
+ end
105
+
106
+ op = exclude ? 'doesnt_have_any_filter' : 'has_any_filter'
107
+ path = filter['path'] || filter[:path] || membrane_path_for(key)
108
+ field_key = filter['field_key'] || filter[:field_key] || 'selected'
109
+ { operation: op, params: { key: key, path: path, field_key: field_key, values: values } }
110
+ end
111
+
112
+ # v2 date_filter → GraphQL. A register Date FIELD (key like 'date.zXXXX') filters
113
+ # via range_date_filter on its nested path (membranes.date); a system/top-level date
114
+ # (created_at/updated_at) uses date_filter. Both share range params (gte/lte/time_zone)
115
+ # — range_date_filter additionally carries `path` (backend BaseRangeDateFilter < DateFilter).
116
+ def translate_date_filter(filter)
117
+ key = filter['key'] || filter[:key]
118
+ field = membrane_field?(key)
119
+ path = filter['path'] || filter[:path]
120
+ path ||= membrane_path_for(key) if field
121
+
122
+ params = { key: key, time_zone: filter['time_zone'] || filter[:time_zone] || 'UTC' }
123
+ params[:path] = path if path
124
+ lbound = filter['lbound'] || filter[:lbound]
125
+ ubound = filter['ubound'] || filter[:ubound]
126
+ params[:gte] = lbound if lbound
127
+ params[:lte] = ubound if ubound
128
+
129
+ { operation: field ? 'range_date_filter' : 'date_filter', params: params }
130
+ end
131
+
132
+ # "exclude" style modes map to the negative filter operation.
133
+ def exclude_mode?(filter)
134
+ mode = (filter['mode'] || filter[:mode]).to_s.downcase
135
+ %w[none exclude not not_in].include?(mode)
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,23 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Compat
5
+ # Returned by Compat::Pages#create — mirrors the v2 reference object.
6
+ # Scripts access .page_id and .active_stage_id after page creation.
7
+ class PageReference
8
+ attr_reader :page_id, :active_stage_id, :page
9
+
10
+ def initialize(page)
11
+ @page = page
12
+ @page_id = page.id
13
+ @active_stage_id = page.respond_to?(:current_stage_id) ? page.current_stage_id : nil
14
+ end
15
+
16
+ def success?
17
+ !@page_id.nil?
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,212 @@
1
+ module Ecoportal
2
+ module API
3
+ class GraphQL
4
+ module Compat
5
+ # v2-compatible pages API backed by GraphQL.
6
+ # Exposes the same interface as ecoportal-api-v2's pages object so that
7
+ # existing eco-helpers scripts work without modification.
8
+ #
9
+ # Key difference from v2:
10
+ # - get_new / create is a 2-step GraphQL workflow (build then create)
11
+ # - update requires patchVer — must always fetch the page first
12
+ # - search is via the GraphQL org search (register_filter + searchConf)
13
+ class Pages
14
+ def initialize(client)
15
+ @client = client
16
+ end
17
+
18
+ # Fetch a page by ID with full data — metadata, stages, sections, data fields.
19
+ # When stage_id is provided, wraps the result in a StageView that filters
20
+ # sections and components to that stage only — matching v2 per-stage behaviour.
21
+ def get(id, stage_id: nil)
22
+ page = Query::Page.new(@client).query(id: id) do
23
+ spread :CommonPageUnion
24
+ end
25
+ stage_id ? StageView.new(page, stage_id) : page
26
+ end
27
+
28
+ # Build a draft page from a template.
29
+ # Returns the built PageUnion with server-assigned field IDs and structure.
30
+ # This is step (a) of the 2-step creation sequence:
31
+ # (a) get_new → inspect/modify field values → (b) create
32
+ def get_new(template_id)
33
+ mutation = Mutation::Page::BuildFromTemplate.new(@client)
34
+ payload = mutation.query(input: { templateId: template_id, showHiddenData: true }) do
35
+ clientMutationId
36
+ errors {
37
+ details
38
+ fullMessages
39
+ }
40
+ item { spread :CommonPageUnion }
41
+ end
42
+ # Record the source template on the built draft: the read fragment does not fetch
43
+ # sourceTemplateId, and a built draft carries a (real) patchVer, so without this
44
+ # marker the dry-run can neither detect the draft nor recover its templateId — it
45
+ # would mis-preview a CREATE as an UPDATE. See #new_draft? / #create_body.
46
+ payload.item&.tap do |draft|
47
+ draft._compat_source_template_id = template_id if draft.respond_to?(:_compat_source_template_id=)
48
+ end
49
+ end
50
+
51
+ # Create a page from a filled draft.
52
+ # Serialises any modified data fields from the draft into dataFields.updates.
53
+ # Returns a PageReference with .page_id and .active_stage_id.
54
+ def create(page, from: nil)
55
+ template_id = source_template_id(page, from)
56
+ field_updates = page.respond_to?(:data_fields_updates) ? page.data_fields_updates : []
57
+
58
+ # dataFields is a required (non-null) field on CreateFromTemplateInput — always
59
+ # send it, with an empty updates list when the draft has no field changes.
60
+ input = { templateId: template_id, showHiddenData: true, dataFields: { updates: field_updates } }
61
+
62
+ mutation = Mutation::Page::CreateFromTemplate.new(@client)
63
+ payload = mutation.query(input: input)
64
+ resp = Response.new(payload)
65
+ return PageReference.new(payload.item) if resp.success?
66
+
67
+ resp
68
+ end
69
+
70
+ # Update a page. Builds the mutation input from the page model diff.
71
+ # Returns a Compat::Response with .success? and .status.
72
+ # Returns nil (no-op) if there are no changes.
73
+ #
74
+ # When called with no explicit operation (the base eco-helpers update_ooze path does
75
+ # `pages.update(page)`), any captured submit!/sign_off! intent on the page is folded in
76
+ # so the SINGLE updatePage carries both the dirty fields and the submit.
77
+ def update(page, **kargs)
78
+ kargs = compat_submit_kargs(page) if kargs.empty?
79
+ input = Input::Page::Update.from_model(page, **kargs)
80
+ return nil if input.nil?
81
+
82
+ payload = Builder::Page.new(@client).update(input: input)
83
+ Response.new(payload)
84
+ end
85
+
86
+ # Returns the pending changes on a page wrapped under the 'page' key.
87
+ # v2 equivalent: DocHelpers#get_body(doc, level: 'page') → { 'page' => {...} }.
88
+ # eco-helpers' OozeBaseCase reads patch_doc(ooze)['page'] (display_patch /
89
+ # backup_patch! / dirty?), so the body must be wrapped to match the v2 contract —
90
+ # otherwise ['page'] is always nil → diff never prints and "No changes to update"
91
+ # misfires.
92
+ #
93
+ # CRITICAL: the body is the SAME input #update/#create would send — NOT page.as_update.
94
+ # On a phased page, as_update only carries page-SCALAR changes; data-field edits
95
+ # (the bulk of what scripts do — set/select/add-reference) live in data_fields_updates
96
+ # and are invisible to as_update. Reading as_update here made the dry-run blind to
97
+ # every field change: toocs coded a Breakdown Agency reference yet the preview showed
98
+ # "No changes to update", while a real run (made dirty by submit!) DID patch it. Build
99
+ # the faithful body via the Input serialisers so the dry-run shows exactly what will be
100
+ # written. nil when there is genuinely nothing to send (and no submit/sign-off pending).
101
+ def get_body(page)
102
+ { 'page' => patch_body(page) }
103
+ end
104
+
105
+ # Cursor-paginated iteration over pages matching searchConf.
106
+ # Yields full PageUnion objects (with patchVer and field IDs).
107
+ # Required for update workflows — register search returns PreviewPage only.
108
+ #
109
+ # Usage:
110
+ # api.pages.each(searchConf: SearchConf[:state].is(:active).to_h, first: 50) do |page|
111
+ # # page is a Model::Page::Basic or Model::Page::Phased
112
+ # end
113
+ def each(search_conf: {}, first: 50, &block)
114
+ Query::Pages.new(@client).each(searchConf: search_conf, first: first, &block)
115
+ end
116
+
117
+ private
118
+
119
+ # The faithful "what will be sent" body for dry-run display / backup / dirty checks.
120
+ # - update path: the full UpdatePageInput (folds any captured submit!/sign_off!),
121
+ # which — unlike page.as_update — INCLUDES dataFields.updates (field edits).
122
+ # - create path: a never-saved draft has no patchVer; preview the
123
+ # CreateFromTemplateInput instead (matches #create's payload).
124
+ # Returns nil when there is nothing to send and no operation is pending.
125
+ def patch_body(page)
126
+ return create_body(page) if new_draft?(page)
127
+
128
+ Input::Page::Update.from_model(page, **compat_submit_kargs(page))
129
+ end
130
+
131
+ # Is this a never-saved CREATE draft (vs a persisted page to UPDATE)?
132
+ # A draft built via get_new/buildPageFromTemplate is marked with
133
+ # _compat_source_template_id — the authoritative signal, because such a draft DOES
134
+ # carry a server-assigned patchVer (so patchVer-nil alone misclassifies it as an
135
+ # update, the cans-upsert dry-run mislabel). patchVer-nil remains a fallback for any
136
+ # other unsaved model.
137
+ def new_draft?(page)
138
+ return true if page.respond_to?(:_compat_source_template_id) && page._compat_source_template_id
139
+
140
+ !page.respond_to?(:patchVer) || page.patchVer.nil?
141
+ end
142
+
143
+ # CreateFromTemplateInput preview — mirrors #create's payload (templateId + the
144
+ # field updates serialised from the draft). Uses the SAME templateId resolution as
145
+ # the live #create, so the dry-run can't diverge from what gets sent.
146
+ def create_body(page, from: nil)
147
+ template_id = source_template_id(page, from)
148
+ updates = page.respond_to?(:data_fields_updates) ? page.data_fields_updates : []
149
+ return nil if updates.empty? && template_id.nil?
150
+
151
+ { templateId: template_id, dataFields: { updates: updates } }
152
+ end
153
+
154
+ # Resolve the source template id for a create, most-explicit first:
155
+ # 1. explicit `from:` (the caller passed it)
156
+ # 2. the get_new marker `_compat_source_template_id` — the read fragment does NOT
157
+ # fetch sourceTemplateId, and eco-helpers' Creatable passes `draft.template_id`
158
+ # which is nil on a GraphQL draft, so this marker is what actually carries it
159
+ # 3. a doc-provided `sourceTemplateId` (if the page happens to have one)
160
+ # Shared by the live #create AND the dry-run #create_body so they cannot diverge —
161
+ # they DID: the preview showed the marker's id while #create sent nil, and the server
162
+ # rejected `templateId: null` on a live cans-upsert create.
163
+ def source_template_id(page, from = nil)
164
+ return from if from
165
+ return page._compat_source_template_id if page.respond_to?(:_compat_source_template_id) && page._compat_source_template_id
166
+
167
+ page.respond_to?(:sourceTemplateId) ? page.sourceTemplateId : nil
168
+ end
169
+
170
+ # Translates a page's captured submit!/sign_off! intent (flags set by eco-helpers'
171
+ # OozeRedirect::FieldPatches) into update kwargs. Returns {} when nothing is pending.
172
+ # sign_off implies submit (a not-yet-submitted stage submits + approves inline);
173
+ # submit!(force: true) maps to forcedComplete (admin/superuser: skips required-field check).
174
+ def compat_submit_kargs(page)
175
+ if compat_flag(page, :_compat_sign_off?)
176
+ { submit: true, stage_id: compat_stage_id(page, :_compat_sign_off_stage_id),
177
+ complete_page_task: { sign_off: true } }
178
+ elsif compat_flag(page, :_compat_submit?)
179
+ force = compat_flag(page, :_compat_submit_force?)
180
+ { submit: true, stage_id: compat_stage_id(page, :_compat_submit_stage_id),
181
+ complete_page_task: force ? { forced_complete: true } : true }
182
+ else
183
+ {}
184
+ end
185
+ end
186
+
187
+ def compat_flag(page, name)
188
+ page.respond_to?(name) && page.public_send(name)
189
+ end
190
+
191
+ # Resolve the target stage for a submit/sign-off, most-explicit first:
192
+ # 1. pinned — the script passed submit!(stage_id:)/sign_off!(stage_id:)
193
+ # 2. active — the stage last viewed via a StageView (the stage the work was
194
+ # done on; set by Compat::StageView). This is the reliable source
195
+ # for the OozeSamples path, where the queued object is the full page.
196
+ # 3. current — server-state inference (state=='inprogress'/active==true). Last
197
+ # resort only: it guesses, and on a multi-stage page may name the
198
+ # WRONG stage — so the from_model guard still rejects a nil result.
199
+ def compat_stage_id(page, pinned_name)
200
+ pinned = compat_flag(page, pinned_name)
201
+ return pinned if pinned
202
+
203
+ active = compat_flag(page, :_compat_active_stage_id)
204
+ return active if active
205
+
206
+ page.respond_to?(:current_stage_id) ? page.current_stage_id : nil
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end