@qoretechnologies/reqraft 0.10.55-pr.124.g77dd26c → 0.10.55

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 (375) hide show
  1. package/.claude/CLAUDE.md +25 -0
  2. package/.tasks/INDEX.md +1 -0
  3. package/.tasks/STORY_NETWORK_ISOLATION.md +98 -0
  4. package/README.md +1 -1
  5. package/design/FORM_ENGINE_COMPACT.md +34 -0
  6. package/design/FORM_ENGINE_EXPRESSIONS.md +110 -0
  7. package/design/FORM_ENGINE_FIELD_MIGRATION.md +155 -1
  8. package/design/IDE_INTEGRATION.md +13 -0
  9. package/design/RENDER_EXPRESSION_TRANSPORT.md +76 -10
  10. package/design/SELECT_DIALOG_FLOOR.md +86 -0
  11. package/design/SMART_EDITOR_UX.md +21 -0
  12. package/design/UNAVAILABLE_ALLOWED_VALUES.md +226 -0
  13. package/dist/components/composer/Composer.d.ts +8 -3
  14. package/dist/components/composer/Composer.d.ts.map +1 -1
  15. package/dist/components/composer/Composer.js.map +1 -1
  16. package/dist/components/dpqlEditor/DpqlEditor.d.ts.map +1 -1
  17. package/dist/components/dpqlEditor/DpqlEditor.js +3 -3
  18. package/dist/components/dpqlEditor/DpqlEditor.js.map +1 -1
  19. package/dist/components/dpqlEditor/dpqlHelpers.d.ts +6 -0
  20. package/dist/components/dpqlEditor/dpqlHelpers.d.ts.map +1 -1
  21. package/dist/components/dpqlEditor/dpqlHelpers.js +21 -2
  22. package/dist/components/dpqlEditor/dpqlHelpers.js.map +1 -1
  23. package/dist/components/dpqlEditor/dpqlProbe.d.ts +37 -0
  24. package/dist/components/dpqlEditor/dpqlProbe.d.ts.map +1 -0
  25. package/dist/components/dpqlEditor/dpqlProbe.js +203 -0
  26. package/dist/components/dpqlEditor/dpqlProbe.js.map +1 -0
  27. package/dist/components/dpqlEditor/dpqlTags.d.ts +8 -0
  28. package/dist/components/dpqlEditor/dpqlTags.d.ts.map +1 -1
  29. package/dist/components/dpqlEditor/dpqlTags.js +5 -1
  30. package/dist/components/dpqlEditor/dpqlTags.js.map +1 -1
  31. package/dist/components/dpqlEditor/index.d.ts +4 -0
  32. package/dist/components/dpqlEditor/index.d.ts.map +1 -1
  33. package/dist/components/dpqlEditor/index.js +5 -1
  34. package/dist/components/dpqlEditor/index.js.map +1 -1
  35. package/dist/components/dpqlEditor/types.d.ts +42 -2
  36. package/dist/components/dpqlEditor/types.d.ts.map +1 -1
  37. package/dist/components/dpqlEditor/types.js +0 -4
  38. package/dist/components/dpqlEditor/types.js.map +1 -1
  39. package/dist/components/dpqlEditor/useDpqlProbe.d.ts +4 -0
  40. package/dist/components/dpqlEditor/useDpqlProbe.d.ts.map +1 -0
  41. package/dist/components/dpqlEditor/useDpqlProbe.js +29 -0
  42. package/dist/components/dpqlEditor/useDpqlProbe.js.map +1 -0
  43. package/dist/components/dpqlEditor/useDpqlSession.d.ts +5 -2
  44. package/dist/components/dpqlEditor/useDpqlSession.d.ts.map +1 -1
  45. package/dist/components/dpqlEditor/useDpqlSession.js +8 -2
  46. package/dist/components/dpqlEditor/useDpqlSession.js.map +1 -1
  47. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  48. package/dist/components/form/engine/CompactRow.js +414 -128
  49. package/dist/components/form/engine/CompactRow.js.map +1 -1
  50. package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
  51. package/dist/components/form/engine/CompactToolbar.js +5 -2
  52. package/dist/components/form/engine/CompactToolbar.js.map +1 -1
  53. package/dist/components/form/engine/FormEngine.d.ts +273 -22
  54. package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
  55. package/dist/components/form/engine/FormEngine.js +669 -192
  56. package/dist/components/form/engine/FormEngine.js.map +1 -1
  57. package/dist/components/form/engine/FormFieldsSkeleton.d.ts +48 -0
  58. package/dist/components/form/engine/FormFieldsSkeleton.d.ts.map +1 -0
  59. package/dist/components/form/engine/FormFieldsSkeleton.js +41 -0
  60. package/dist/components/form/engine/FormFieldsSkeleton.js.map +1 -0
  61. package/dist/components/form/engine/OptionFieldMessages.d.ts +108 -2
  62. package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
  63. package/dist/components/form/engine/OptionFieldMessages.js +203 -13
  64. package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
  65. package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -1
  66. package/dist/components/form/engine/_structuredData/SchemaDataView.js +68 -5
  67. package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -1
  68. package/dist/components/form/engine/compactRowContext.d.ts +15 -1
  69. package/dist/components/form/engine/compactRowContext.d.ts.map +1 -1
  70. package/dist/components/form/engine/compactRowContext.js.map +1 -1
  71. package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
  72. package/dist/components/form/engine/compactRowStyles.js +55 -29
  73. package/dist/components/form/engine/compactRowStyles.js.map +1 -1
  74. package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
  75. package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
  76. package/dist/components/form/engine/optionActions.d.ts +37 -1
  77. package/dist/components/form/engine/optionActions.d.ts.map +1 -1
  78. package/dist/components/form/engine/optionActions.js +71 -1
  79. package/dist/components/form/engine/optionActions.js.map +1 -1
  80. package/dist/components/form/engine/optionsContext.d.ts +22 -0
  81. package/dist/components/form/engine/optionsContext.d.ts.map +1 -0
  82. package/dist/components/form/engine/optionsContext.js +20 -0
  83. package/dist/components/form/engine/optionsContext.js.map +1 -0
  84. package/dist/components/form/engine/readFirst.d.ts +42 -1
  85. package/dist/components/form/engine/readFirst.d.ts.map +1 -1
  86. package/dist/components/form/engine/readFirst.js +76 -8
  87. package/dist/components/form/engine/readFirst.js.map +1 -1
  88. package/dist/components/form/engine/rendererTypes.d.ts +42 -3
  89. package/dist/components/form/engine/rendererTypes.d.ts.map +1 -1
  90. package/dist/components/form/engine/rendererTypes.js +3 -1
  91. package/dist/components/form/engine/rendererTypes.js.map +1 -1
  92. package/dist/components/form/engine/rowFocus.d.ts +30 -0
  93. package/dist/components/form/engine/rowFocus.d.ts.map +1 -0
  94. package/dist/components/form/engine/rowFocus.js +93 -0
  95. package/dist/components/form/engine/rowFocus.js.map +1 -0
  96. package/dist/components/form/engine/rowMenuContext.d.ts +78 -0
  97. package/dist/components/form/engine/rowMenuContext.d.ts.map +1 -0
  98. package/dist/components/form/engine/rowMenuContext.js +103 -0
  99. package/dist/components/form/engine/rowMenuContext.js.map +1 -0
  100. package/dist/components/form/engine/rowOpenPicker.d.ts +27 -0
  101. package/dist/components/form/engine/rowOpenPicker.d.ts.map +1 -0
  102. package/dist/components/form/engine/rowOpenPicker.js +30 -0
  103. package/dist/components/form/engine/rowOpenPicker.js.map +1 -0
  104. package/dist/components/form/engine/typeChoices.d.ts +42 -0
  105. package/dist/components/form/engine/typeChoices.d.ts.map +1 -0
  106. package/dist/components/form/engine/typeChoices.js +33 -0
  107. package/dist/components/form/engine/typeChoices.js.map +1 -0
  108. package/dist/components/form/expressions/DpqlRendering.d.ts +26 -0
  109. package/dist/components/form/expressions/DpqlRendering.d.ts.map +1 -0
  110. package/dist/components/form/expressions/DpqlRendering.js +53 -0
  111. package/dist/components/form/expressions/DpqlRendering.js.map +1 -0
  112. package/dist/components/form/expressions/ExpressionField.d.ts +7 -1
  113. package/dist/components/form/expressions/ExpressionField.d.ts.map +1 -1
  114. package/dist/components/form/expressions/ExpressionField.js +203 -45
  115. package/dist/components/form/expressions/ExpressionField.js.map +1 -1
  116. package/dist/components/form/expressions/argumentPresence.d.ts +84 -0
  117. package/dist/components/form/expressions/argumentPresence.d.ts.map +1 -0
  118. package/dist/components/form/expressions/argumentPresence.js +217 -0
  119. package/dist/components/form/expressions/argumentPresence.js.map +1 -0
  120. package/dist/components/form/expressions/builder/argumentLabel.d.ts.map +1 -1
  121. package/dist/components/form/expressions/builder/argumentLabel.js +9 -4
  122. package/dist/components/form/expressions/builder/argumentLabel.js.map +1 -1
  123. package/dist/components/form/expressions/builder/index.d.ts +15 -2
  124. package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
  125. package/dist/components/form/expressions/builder/index.js +21 -65
  126. package/dist/components/form/expressions/builder/index.js.map +1 -1
  127. package/dist/components/form/expressions/builder/renderTemplate.d.ts +4 -1
  128. package/dist/components/form/expressions/builder/renderTemplate.d.ts.map +1 -1
  129. package/dist/components/form/expressions/builder/renderTemplate.js +10 -67
  130. package/dist/components/form/expressions/builder/renderTemplate.js.map +1 -1
  131. package/dist/components/form/expressions/mockExpressions.d.ts.map +1 -1
  132. package/dist/components/form/expressions/mockExpressions.js +8 -4
  133. package/dist/components/form/expressions/mockExpressions.js.map +1 -1
  134. package/dist/components/form/expressions/renderExpressionToText.d.ts +1 -1
  135. package/dist/components/form/expressions/renderExpressionToText.d.ts.map +1 -1
  136. package/dist/components/form/expressions/renderExpressionToText.js +95 -19
  137. package/dist/components/form/expressions/renderExpressionToText.js.map +1 -1
  138. package/dist/components/form/expressions/types.d.ts +17 -2
  139. package/dist/components/form/expressions/types.d.ts.map +1 -1
  140. package/dist/components/form/expressions/useExpressions.d.ts.map +1 -1
  141. package/dist/components/form/expressions/useExpressions.js +5 -2
  142. package/dist/components/form/expressions/useExpressions.js.map +1 -1
  143. package/dist/components/form/expressions/useRenderExpression.d.ts +7 -16
  144. package/dist/components/form/expressions/useRenderExpression.d.ts.map +1 -1
  145. package/dist/components/form/expressions/useRenderExpression.js +50 -126
  146. package/dist/components/form/expressions/useRenderExpression.js.map +1 -1
  147. package/dist/components/form/fields/Field.d.ts +21 -0
  148. package/dist/components/form/fields/Field.d.ts.map +1 -1
  149. package/dist/components/form/fields/Field.js +54 -8
  150. package/dist/components/form/fields/Field.js.map +1 -1
  151. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +11 -1
  152. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
  153. package/dist/components/form/fields/allowed-values/AllowedValues.js +52 -8
  154. package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
  155. package/dist/components/form/fields/auto/AutoFormField.d.ts +7 -1
  156. package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
  157. package/dist/components/form/fields/auto/AutoFormField.js +91 -28
  158. package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
  159. package/dist/components/form/fields/date/Date.d.ts +1 -1
  160. package/dist/components/form/fields/date/Date.d.ts.map +1 -1
  161. package/dist/components/form/fields/date/Date.js +16 -2
  162. package/dist/components/form/fields/date/Date.js.map +1 -1
  163. package/dist/components/form/fields/long-string/LongString.d.ts.map +1 -1
  164. package/dist/components/form/fields/long-string/LongString.js +14 -2
  165. package/dist/components/form/fields/long-string/LongString.js.map +1 -1
  166. package/dist/components/form/fields/multi-select/MultiSelectFormField.d.ts.map +1 -1
  167. package/dist/components/form/fields/multi-select/MultiSelectFormField.js +50 -4
  168. package/dist/components/form/fields/multi-select/MultiSelectFormField.js.map +1 -1
  169. package/dist/components/form/fields/number/Number.d.ts +12 -1
  170. package/dist/components/form/fields/number/Number.d.ts.map +1 -1
  171. package/dist/components/form/fields/number/Number.js +6 -3
  172. package/dist/components/form/fields/number/Number.js.map +1 -1
  173. package/dist/components/form/fields/rich-text/RichText.d.ts +47 -2
  174. package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
  175. package/dist/components/form/fields/rich-text/RichText.js +153 -12
  176. package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
  177. package/dist/components/form/fields/select/Select.d.ts.map +1 -1
  178. package/dist/components/form/fields/select/Select.js +120 -20
  179. package/dist/components/form/fields/select/Select.js.map +1 -1
  180. package/dist/components/form/fields/select/SelectCollection.d.ts +166 -9
  181. package/dist/components/form/fields/select/SelectCollection.d.ts.map +1 -1
  182. package/dist/components/form/fields/select/SelectCollection.js +200 -7
  183. package/dist/components/form/fields/select/SelectCollection.js.map +1 -1
  184. package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts +2 -1
  185. package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts.map +1 -1
  186. package/dist/components/form/fields/template/ReadOnlyTemplateTag.js +3 -2
  187. package/dist/components/form/fields/template/ReadOnlyTemplateTag.js.map +1 -1
  188. package/dist/components/form/fields/template/TemplateField.d.ts +34 -2
  189. package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
  190. package/dist/components/form/fields/template/TemplateField.js +606 -58
  191. package/dist/components/form/fields/template/TemplateField.js.map +1 -1
  192. package/dist/components/form/fields/template/TemplateText.d.ts +36 -0
  193. package/dist/components/form/fields/template/TemplateText.d.ts.map +1 -0
  194. package/dist/components/form/fields/template/TemplateText.js +80 -0
  195. package/dist/components/form/fields/template/TemplateText.js.map +1 -0
  196. package/dist/components/form/index.d.ts +2 -0
  197. package/dist/components/form/index.d.ts.map +1 -1
  198. package/dist/components/form/index.js +4 -0
  199. package/dist/components/form/index.js.map +1 -1
  200. package/dist/components/smartEditor/SmartEditor.d.ts.map +1 -1
  201. package/dist/components/smartEditor/SmartEditor.js +29 -8
  202. package/dist/components/smartEditor/SmartEditor.js.map +1 -1
  203. package/dist/components/smartEditor/useLspSession.d.ts +5 -1
  204. package/dist/components/smartEditor/useLspSession.d.ts.map +1 -1
  205. package/dist/components/smartEditor/useLspSession.js +16 -2
  206. package/dist/components/smartEditor/useLspSession.js.map +1 -1
  207. package/dist/components/supportTicket/TicketReplyBox.d.ts +8 -4
  208. package/dist/components/supportTicket/TicketReplyBox.d.ts.map +1 -1
  209. package/dist/components/supportTicket/TicketReplyBox.js.map +1 -1
  210. package/dist/helpers/common.d.ts.map +1 -1
  211. package/dist/helpers/common.js +7 -3
  212. package/dist/helpers/common.js.map +1 -1
  213. package/dist/helpers/dpqlDetection.d.ts +58 -0
  214. package/dist/helpers/dpqlDetection.d.ts.map +1 -0
  215. package/dist/helpers/dpqlDetection.js +164 -0
  216. package/dist/helpers/dpqlDetection.js.map +1 -0
  217. package/dist/helpers/optionUiTypes.d.ts +31 -3
  218. package/dist/helpers/optionUiTypes.d.ts.map +1 -1
  219. package/dist/helpers/optionUiTypes.js +36 -1
  220. package/dist/helpers/optionUiTypes.js.map +1 -1
  221. package/dist/helpers/options.d.ts +57 -0
  222. package/dist/helpers/options.d.ts.map +1 -1
  223. package/dist/helpers/options.js +97 -1
  224. package/dist/helpers/options.js.map +1 -1
  225. package/dist/helpers/templateItems.d.ts +47 -0
  226. package/dist/helpers/templateItems.d.ts.map +1 -0
  227. package/dist/helpers/templateItems.js +88 -0
  228. package/dist/helpers/templateItems.js.map +1 -0
  229. package/dist/helpers/templateText.d.ts +80 -0
  230. package/dist/helpers/templateText.d.ts.map +1 -0
  231. package/dist/helpers/templateText.js +291 -0
  232. package/dist/helpers/templateText.js.map +1 -0
  233. package/dist/helpers/templates.d.ts +30 -12
  234. package/dist/helpers/templates.d.ts.map +1 -1
  235. package/dist/helpers/templates.js +91 -33
  236. package/dist/helpers/templates.js.map +1 -1
  237. package/dist/helpers/validations.d.ts +35 -8
  238. package/dist/helpers/validations.d.ts.map +1 -1
  239. package/dist/helpers/validations.js +162 -25
  240. package/dist/helpers/validations.js.map +1 -1
  241. package/dist/hooks/useArgSchema.d.ts +2 -1
  242. package/dist/hooks/useArgSchema.d.ts.map +1 -1
  243. package/dist/hooks/useFetch/useFetch.d.ts +3 -1
  244. package/dist/hooks/useFetch/useFetch.d.ts.map +1 -1
  245. package/dist/hooks/useFetch/useFetch.js +47 -9
  246. package/dist/hooks/useFetch/useFetch.js.map +1 -1
  247. package/dist/hooks/useTemplates.d.ts +20 -0
  248. package/dist/hooks/useTemplates.d.ts.map +1 -1
  249. package/dist/hooks/useTemplates.js +34 -2
  250. package/dist/hooks/useTemplates.js.map +1 -1
  251. package/dist/index.d.ts +2 -1
  252. package/dist/index.d.ts.map +1 -1
  253. package/dist/index.js +5 -1
  254. package/dist/index.js.map +1 -1
  255. package/dist/utils/fetch.d.ts +151 -1
  256. package/dist/utils/fetch.d.ts.map +1 -1
  257. package/dist/utils/fetch.js +256 -44
  258. package/dist/utils/fetch.js.map +1 -1
  259. package/dist/utils/lspClient.d.ts +6 -0
  260. package/dist/utils/lspClient.d.ts.map +1 -1
  261. package/dist/utils/lspClient.js +62 -11
  262. package/dist/utils/lspClient.js.map +1 -1
  263. package/dist/utils/websocket.d.ts +6 -0
  264. package/dist/utils/websocket.d.ts.map +1 -1
  265. package/dist/utils/websocket.js +15 -7
  266. package/dist/utils/websocket.js.map +1 -1
  267. package/package.json +10 -6
  268. package/src/components/composer/Composer.tsx +7 -2
  269. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +3 -119
  270. package/src/components/dpqlEditor/DpqlEditor.tsx +5 -2
  271. package/src/components/dpqlEditor/dpqlHelpers.ts +20 -1
  272. package/src/components/dpqlEditor/dpqlProbe.ts +165 -0
  273. package/src/components/dpqlEditor/dpqlTags.ts +13 -0
  274. package/src/components/dpqlEditor/index.ts +4 -0
  275. package/src/components/dpqlEditor/types.ts +38 -2
  276. package/src/components/dpqlEditor/useDpqlProbe.ts +33 -0
  277. package/src/components/dpqlEditor/useDpqlSession.ts +20 -4
  278. package/src/components/form/engine/CompactRow.tsx +487 -160
  279. package/src/components/form/engine/CompactToolbar.tsx +10 -3
  280. package/src/components/form/engine/FormEngine.stories.tsx +1269 -211
  281. package/src/components/form/engine/FormEngine.tsx +922 -270
  282. package/src/components/form/engine/FormEngineStickyHeaders.stories.tsx +331 -0
  283. package/src/components/form/engine/FormFieldsSkeleton.tsx +77 -0
  284. package/src/components/form/engine/OptionFieldMessages.tsx +300 -14
  285. package/src/components/form/engine/_structuredData/SchemaDataView.tsx +94 -3
  286. package/src/components/form/engine/compactRowContext.ts +15 -6
  287. package/src/components/form/engine/compactRowStyles.ts +56 -2
  288. package/src/components/form/engine/compactToolbarContext.ts +1 -1
  289. package/src/components/form/engine/optionActions.ts +89 -1
  290. package/src/components/form/engine/optionsContext.ts +24 -0
  291. package/src/components/form/engine/readFirst.ts +88 -8
  292. package/src/components/form/engine/rendererTypes.ts +48 -4
  293. package/src/components/form/engine/rowFocus.ts +101 -0
  294. package/src/components/form/engine/rowMenuContext.ts +159 -0
  295. package/src/components/form/engine/rowOpenPicker.ts +27 -0
  296. package/src/components/form/engine/typeChoices.ts +63 -0
  297. package/src/components/form/expressions/DpqlRendering.tsx +85 -0
  298. package/src/components/form/expressions/ExpressionField.stories.tsx +826 -48
  299. package/src/components/form/expressions/ExpressionField.tsx +269 -55
  300. package/src/components/form/expressions/argumentPresence.ts +213 -0
  301. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +38 -21
  302. package/src/components/form/expressions/builder/argumentLabel.tsx +10 -4
  303. package/src/components/form/expressions/builder/index.tsx +39 -81
  304. package/src/components/form/expressions/builder/renderTemplate.tsx +23 -56
  305. package/src/components/form/expressions/dpqlMockLanguage.ts +565 -0
  306. package/src/components/form/expressions/dpqlMockLsp.ts +109 -83
  307. package/src/components/form/expressions/mockExpressions.ts +8 -4
  308. package/src/components/form/expressions/renderExpressionToText.ts +112 -22
  309. package/src/components/form/expressions/types.ts +17 -2
  310. package/src/components/form/expressions/useExpressions.ts +5 -1
  311. package/src/components/form/expressions/useRenderExpression.ts +43 -127
  312. package/src/components/form/fields/Field.tsx +102 -20
  313. package/src/components/form/fields/allowed-values/AllowedValues.tsx +106 -44
  314. package/src/components/form/fields/auto/AutoFormField.stories.tsx +85 -18
  315. package/src/components/form/fields/auto/AutoFormField.tsx +97 -21
  316. package/src/components/form/fields/date/Date.tsx +17 -1
  317. package/src/components/form/fields/long-string/LongString.tsx +15 -3
  318. package/src/components/form/fields/multi-select/MultiSelectFormField.tsx +65 -6
  319. package/src/components/form/fields/number/Number.tsx +25 -0
  320. package/src/components/form/fields/rich-text/RichText.tsx +248 -30
  321. package/src/components/form/fields/select/Select.stories.tsx +392 -0
  322. package/src/components/form/fields/select/Select.tsx +164 -27
  323. package/src/components/form/fields/select/SelectCollection.tsx +350 -6
  324. package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +4 -2
  325. package/src/components/form/fields/template/TemplateField.stories.tsx +93 -14
  326. package/src/components/form/fields/template/TemplateField.tsx +825 -131
  327. package/src/components/form/fields/template/TemplateText.tsx +115 -0
  328. package/src/components/form/index.tsx +4 -0
  329. package/src/components/log/Log.stories.tsx +2 -1
  330. package/src/components/searchFilterBar/SearchFilterBar.stories.tsx +3 -3
  331. package/src/components/smartEditor/SmartEditor.tsx +41 -9
  332. package/src/components/smartEditor/__fixtures__/mockLspServer.ts +52 -3
  333. package/src/components/smartEditor/useLspSession.ts +21 -3
  334. package/src/components/supportTicket/TicketReplyBox.tsx +8 -4
  335. package/src/components/ticketThread/TicketThread.stories.tsx +1 -0
  336. package/src/helpers/common.ts +7 -3
  337. package/src/helpers/dpqlDetection.ts +209 -0
  338. package/src/helpers/optionUiTypes.ts +38 -0
  339. package/src/helpers/options.ts +96 -0
  340. package/src/helpers/templateItems.ts +81 -0
  341. package/src/helpers/templateText.ts +350 -0
  342. package/src/helpers/templates.ts +94 -41
  343. package/src/helpers/validations.ts +203 -51
  344. package/src/hooks/useFetch/useFetch.stories.tsx +6 -5
  345. package/src/hooks/useFetch/useFetch.tsx +53 -7
  346. package/src/hooks/useStorage/useStorage.stories.tsx +2 -1
  347. package/src/hooks/useTemplates.ts +41 -0
  348. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +2 -1
  349. package/src/index.tsx +14 -1
  350. package/src/stores/currentUser/currentUser.stories.tsx +2 -1
  351. package/src/stories/storyNetwork.ts +92 -0
  352. package/src/utils/fetch.ts +311 -21
  353. package/src/utils/lspClient.ts +68 -11
  354. package/src/utils/websocket.ts +20 -9
  355. package/dist/components/form/engine/__fixtures__/basicFormOptions.d.ts +0 -73
  356. package/dist/components/form/engine/__fixtures__/basicFormOptions.d.ts.map +0 -1
  357. package/dist/components/form/engine/__fixtures__/basicFormOptions.js +0 -317
  358. package/dist/components/form/engine/__fixtures__/basicFormOptions.js.map +0 -1
  359. package/dist/components/form/engine/__fixtures__/fieldChromeOptions.d.ts +0 -41
  360. package/dist/components/form/engine/__fixtures__/fieldChromeOptions.d.ts.map +0 -1
  361. package/dist/components/form/engine/__fixtures__/fieldChromeOptions.js +0 -45
  362. package/dist/components/form/engine/__fixtures__/fieldChromeOptions.js.map +0 -1
  363. package/dist/components/form/expressions/dpqlMockLsp.d.ts +0 -3
  364. package/dist/components/form/expressions/dpqlMockLsp.d.ts.map +0 -1
  365. package/dist/components/form/expressions/dpqlMockLsp.js +0 -91
  366. package/dist/components/form/expressions/dpqlMockLsp.js.map +0 -1
  367. package/dist/components/form/fields/template/__fixtures__/longExampleValue.d.ts +0 -2
  368. package/dist/components/form/fields/template/__fixtures__/longExampleValue.d.ts.map +0 -1
  369. package/dist/components/form/fields/template/__fixtures__/longExampleValue.js +0 -9
  370. package/dist/components/form/fields/template/__fixtures__/longExampleValue.js.map +0 -1
  371. package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts +0 -55
  372. package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts.map +0 -1
  373. package/dist/components/smartEditor/__fixtures__/mockLspServer.js +0 -126
  374. package/dist/components/smartEditor/__fixtures__/mockLspServer.js.map +0 -1
  375. package/dist/stories/Data/fileFieldArgSchema.json +0 -86
@@ -1,4 +1,5 @@
1
1
  import { modalStore } from '@qoretechnologies/reqore';
2
+ import { TReqoreTooltipProp } from '@qoretechnologies/reqore/dist/types/global';
2
3
  import { IReqoreFormTemplates } from '@qoretechnologies/reqore/dist/components/Textarea';
3
4
  import {
4
5
  TReqoreDropdownItem,
@@ -20,6 +21,24 @@ import { areQorusTypesCompatible } from './expressions';
20
21
  */
21
22
  export const TEMPLATE_EXAMPLE_PREVIEW_LENGTH = 150;
22
23
 
24
+ /**
25
+ * How template picker entries are ordered: by the label a reader actually sees.
26
+ *
27
+ * The server sends groups and their items in whatever order it assembled them —
28
+ * for the test vocabulary that is step order, for an app's actions it is the
29
+ * connector's own. Neither is an order a reader can predict, and a picker
30
+ * holding 29 items is navigated by looking for a NAME.
31
+ *
32
+ * `localeCompare` with `numeric` so `item2` sorts before `item10`, and
33
+ * `sensitivity: 'base'` so case and accents do not split otherwise-adjacent
34
+ * neighbours.
35
+ */
36
+ const byLabel = (a: { label?: unknown }, b: { label?: unknown }): number =>
37
+ String(a?.label ?? '').localeCompare(String(b?.label ?? ''), undefined, {
38
+ numeric: true,
39
+ sensitivity: 'base',
40
+ });
41
+
23
42
  /**
24
43
  * Shared template string utilities.
25
44
  * Used by both validations and TemplateField.
@@ -106,9 +125,42 @@ const matchesTemplateValue = (item: TReqoreDropdownItem, value: string): boolean
106
125
  /** Splits `$data:{a.b.c}` into its key (`$data`) and inner path (`a.b.c`). */
107
126
  const TEMPLATE_TOKEN_PATH = /^(\$[A-Za-z_][\w-]*):\{(.*)\}$/;
108
127
 
128
+ /**
129
+ * The KEY-LESS spelling — `$.create.status`, `$._case.mode`, `$.order[0].sku`.
130
+ *
131
+ * A host may name its own references without a key and without braces: a Qorus
132
+ * test reads what a step captured as `$.create`, and that is the whole token.
133
+ * The path is captured WITH its leading `.`, so a prefix comparison is between
134
+ * two strings of the same shape and `$.create` still ends at a path boundary
135
+ * inside `$.create.status`.
136
+ *
137
+ * Deliberately strict — a root segment, then any number of further `.field`
138
+ * steps and `[0]` indices, and nothing else — so it cannot claim a keyed token
139
+ * (which carries a `:`) or a bare `$word`.
140
+ */
141
+ const KEYLESS_TOKEN_PATH = /^\$((?:\.[A-Za-z_][\w-]*|\[\d+\])+)$/;
142
+
143
+ /**
144
+ * "No key" is a key of its own.
145
+ *
146
+ * `findTemplateByPath` refuses to name a value from an item under a different
147
+ * key, and the key-less grammar has to take part in that rule rather than sit
148
+ * outside it: a `$data:{create.status}` item must not name `$.create.status`,
149
+ * and a `$.create` item must not name `$data:{create.status}`. Every keyed
150
+ * token's key begins with `$`, so the empty string can never collide with one.
151
+ */
152
+ const NO_TOKEN_KEY = '';
153
+
109
154
  const getTokenPath = (value?: unknown): { key: string; path: string } | undefined => {
110
- const match = typeof value === 'string' ? TEMPLATE_TOKEN_PATH.exec(value) : null;
111
- return match ? { key: match[1], path: match[2] } : undefined;
155
+ if (typeof value !== 'string') {
156
+ return undefined;
157
+ }
158
+ const keyed = TEMPLATE_TOKEN_PATH.exec(value);
159
+ if (keyed) {
160
+ return { key: keyed[1], path: keyed[2] };
161
+ }
162
+ const keyless = KEYLESS_TOKEN_PATH.exec(value);
163
+ return keyless ? { key: NO_TOKEN_KEY, path: keyless[1] } : undefined;
112
164
  };
113
165
 
114
166
  /**
@@ -124,7 +176,12 @@ const getTokenPath = (value?: unknown): { key: string; path: string } | undefine
124
176
  *
125
177
  * The match must break at a path boundary (`.` or `[`) so `choicesOther` is
126
178
  * never named after `choices`, and the token keys must agree so a `$config:`
127
- * item never names a `$data:` value.
179
+ * item never names a `$data:` value — "no key" included, so the key-less
180
+ * grammar and the keyed one never name each other's references.
181
+ *
182
+ * Both grammars arrive here: `$data:{create.choices[0]}` and the key-less
183
+ * `$.create.status` are the same question asked in two spellings, and a
184
+ * catalogue written in either one names the walks its author took past it.
128
185
  */
129
186
  export const findTemplateByPath = (
130
187
  templates: IReqoreFormTemplates,
@@ -239,9 +296,14 @@ export const resolveTemplateLabel = (
239
296
  * never fetches one), and there the raw token is the only thing left to show.
240
297
  * Showing it as `$data:{…}` renders a value as code; showing the path renders
241
298
  * it as a name, which is the honest floor.
299
+ *
300
+ * Only a BRACED wrapper is stripped, because only a braced wrapper is one.
301
+ * A key-less `$._case.mode` stripped of its `$` reads as `._case.mode`, which
302
+ * is neither the reference nor a name for it; with nothing to call it, the
303
+ * reference as written is the honest answer.
242
304
  */
243
305
  export const getTemplateReferencePath = (value: string): string =>
244
- getTokenPath(value)?.path ?? value;
306
+ (typeof value === 'string' ? TEMPLATE_TOKEN_PATH.exec(value)?.[2] : undefined) ?? value;
245
307
 
246
308
  /**
247
309
  * The best available name for a reference, for a surface that must show
@@ -258,43 +320,34 @@ export const describeTemplateReference = (
258
320
  return resolved.item ? resolved : { label: getTemplateReferencePath(value) };
259
321
  };
260
322
 
261
- const EMBEDDED_TEMPLATE_TOKEN = new RegExp(TEMPLATE_TOKEN_SOURCE, 'g');
262
-
263
- export type TTemplateTextSegment =
264
- | { kind: 'text'; text: string }
265
- | { kind: 'token'; text: string };
266
-
267
323
  /**
268
- * Splits prose that embeds template tokens into its literal and token parts —
269
- * `trim("$data:{…}")` becomes `trim("`, the token, `")`. Used to chip the
270
- * references inside a rendered expression instead of printing them raw.
324
+ * What a chosen template's hover should say.
325
+ *
326
+ * The reference itself — `$._case.title`, `$data:{dc_ai_reply.choices[0]…}` —
327
+ * is an implementation detail of the grammar, and it was what every template
328
+ * chip put in its tooltip. An author hovering a chip wants to know WHAT VALUE
329
+ * this is, and the catalogue already carries that: the entry's `description`
330
+ * is the prose the picker lists it under, written from the schema that declares
331
+ * it, with its type appended.
332
+ *
333
+ * So the hover reads as a small card — the value's name as the title, its
334
+ * description as the body — and the path stays where it is genuinely needed:
335
+ * the field's own help, which teaches the grammar with a worked example, and
336
+ * the picker, for the walks no list can hold.
337
+ *
338
+ * Falls back to the resolved label (itself the stripped path when the catalogue
339
+ * explains nothing), because a surface with no catalogue must still say what
340
+ * the value is rather than nothing at all.
271
341
  */
272
- export const splitTemplateTokens = (text?: string): TTemplateTextSegment[] => {
273
- if (!text) {
274
- return [];
275
- }
276
-
277
- const segments: TTemplateTextSegment[] = [];
278
- let lastIndex = 0;
279
-
280
- // A fresh regex per call: a shared /g instance carries `lastIndex` between
281
- // calls and would skip tokens on the second string it is given.
282
- const pattern = new RegExp(EMBEDDED_TEMPLATE_TOKEN.source, 'g');
283
- let match: RegExpExecArray | null;
284
-
285
- while ((match = pattern.exec(text)) !== null) {
286
- if (match.index > lastIndex) {
287
- segments.push({ kind: 'text', text: text.slice(lastIndex, match.index) });
288
- }
289
- segments.push({ kind: 'token', text: match[0] });
290
- lastIndex = match.index + match[0].length;
291
- }
292
-
293
- if (lastIndex < text.length) {
294
- segments.push({ kind: 'text', text: text.slice(lastIndex) });
295
- }
296
-
297
- return segments;
342
+ export const templateTooltip = (
343
+ templates: IReqoreFormTemplates | undefined,
344
+ value: string
345
+ ): TReqoreTooltipProp => {
346
+ const { label, item } = describeTemplateReference(templates, value);
347
+ const description = (item as { description?: unknown } | undefined)?.description;
348
+ return typeof description === 'string' && description.trim() ?
349
+ { title: label, content: description, maxWidth: '360px' }
350
+ : label || value;
298
351
  };
299
352
 
300
353
  // Ported verbatim from qorus-ide `helpers/functions.tsx` (FIELD_STACK_REPORT
@@ -506,7 +559,7 @@ export const buildTemplates = (
506
559
 
507
560
  return item;
508
561
  }
509
- );
562
+ ).sort(byLabel);
510
563
 
511
564
  return {
512
565
  items: Object.values(templates).map(
@@ -544,6 +597,6 @@ export const buildTemplates = (
544
597
  data_role
545
598
  ),
546
599
  })
547
- ),
600
+ ).sort(byLabel),
548
601
  } as IReqoreFormTemplates;
549
602
  };
@@ -75,6 +75,24 @@ interface IFieldValidationProps {
75
75
  * mapped onto the corresponding `has_to_be_*` flags. */
76
76
  rules?: string[];
77
77
  validation_regex?: string;
78
+ /**
79
+ * The inclusive bounds a numeric field accepts — read only by the `int`, `float`
80
+ * and `number` validators.
81
+ *
82
+ * Declared here rather than imported because ts-toolkit still does not carry them:
83
+ * 0.5.82 added the allowed-value and message members reqraft was waiting on, but
84
+ * `IQorusFormFieldSchemaBase` has no numeric bound. These two collapse into the
85
+ * imported type once it does — unlike the allowed-value shapes, which stay local
86
+ * for a reason of their own.
87
+ *
88
+ * The server declares a bound only where that same bound is already enforced on the
89
+ * write (`MetaFieldInfo::min_value`), so refusing a value here turns an error the
90
+ * author would otherwise meet on save into one they meet while the field is still on
91
+ * screen. It never enforces the bound, and it never refuses a value the server would
92
+ * have accepted.
93
+ */
94
+ min_value?: number;
95
+ max_value?: number;
78
96
  required_groups?: string[];
79
97
  optionSchema?: IQorusFormSchema;
80
98
  /** The sibling option VALUES, for required-group and dependency checks.
@@ -174,6 +192,41 @@ const withContext = (result: IValidationResult, context?: string): IValidationRe
174
192
  const resultFromBoolean = (isValid: boolean, reason: string): IValidationResult =>
175
193
  isValid ? validResult() : invalidResult(reason);
176
194
 
195
+ /**
196
+ * Whether the value is a number at all — the check the `number` and `float` cases both
197
+ * make before any bound is read. Shared because the two differ only in the wording of
198
+ * the refusal, and a predicate that drifted between them would leave one of the pair
199
+ * accepting what the other refuses.
200
+ */
201
+ const isNumericValue = (value: any): boolean =>
202
+ !isNaN(value) && (getTypeFromValue(value) === 'float' || getTypeFromValue(value) === 'int');
203
+
204
+ /**
205
+ * The schema-declared range for a value that is already the right kind of number.
206
+ *
207
+ * Both bounds are inclusive and either may stand alone — the server declares only the
208
+ * side it can point at an enforcing line for, so a count with a floor and no ceiling
209
+ * arrives with `min_value` alone. A bound that is not a finite number is ignored rather
210
+ * than treated as zero: a schema that says nothing must not refuse everything.
211
+ *
212
+ * Kept out of the type checks above it so the reason a value is refused says which
213
+ * thing is wrong — "must be a whole number" and "must be at least 1" are different
214
+ * corrections, and collapsing them into one message makes the author guess.
215
+ */
216
+ const checkNumericBounds = (value: any, field?: IFieldValidationProps): IValidationResult => {
217
+ const num = Number(value);
218
+ const min = field?.min_value;
219
+ const max = field?.max_value;
220
+
221
+ if (typeof min === 'number' && Number.isFinite(min) && num < min) {
222
+ return invalidResult(`Value must be ${min} or more`);
223
+ }
224
+ if (typeof max === 'number' && Number.isFinite(max) && num > max) {
225
+ return invalidResult(`Value must be ${max} or less`);
226
+ }
227
+ return validResult();
228
+ };
229
+
177
230
  const isRichTextWithoutValue = (value: any): boolean => {
178
231
  return (
179
232
  value === undefined ||
@@ -574,21 +627,21 @@ export const _validateField = (
574
627
  return valid ? validResult() : invalidResult(undefined, reasons);
575
628
  }
576
629
  case 'number': {
577
- return resultFromBoolean(
578
- !isNaN(value) && (getTypeFromValue(value) === 'float' || getTypeFromValue(value) === 'int'),
579
- 'Value must be a number'
580
- );
630
+ if (!isNumericValue(value)) {
631
+ return invalidResult('Value must be a number');
632
+ }
633
+ return checkNumericBounds(value, field);
581
634
  }
582
635
  case 'int':
583
- return resultFromBoolean(
584
- !Number.isNaN(value) && getTypeFromValue(value) === 'int',
585
- 'Value must be an integer'
586
- );
636
+ if (!(!Number.isNaN(value) && getTypeFromValue(value) === 'int')) {
637
+ return invalidResult('Value must be an integer');
638
+ }
639
+ return checkNumericBounds(value, field);
587
640
  case 'float':
588
- return resultFromBoolean(
589
- !isNaN(value) && (getTypeFromValue(value) === 'float' || getTypeFromValue(value) === 'int'),
590
- 'Value must be a float'
591
- );
641
+ if (!isNumericValue(value)) {
642
+ return invalidResult('Value must be a float');
643
+ }
644
+ return checkNumericBounds(value, field);
592
645
  case 'select-array':
593
646
  case 'multi-select':
594
647
  case 'array':
@@ -1064,14 +1117,39 @@ export const _validateField = (
1064
1117
  }
1065
1118
  }
1066
1119
 
1067
- if (parsedData) {
1068
- return withContext(
1069
- validateFieldWithResult(getTypeFromValue(parsedData), value),
1070
- 'Auto-detected type is invalid'
1071
- );
1120
+ /* A FALSY value is not an ABSENT one. `null`, `0`, `false` and `""` are
1121
+ all values an author may hold in an `auto`/`any` field — a test
1122
+ assertion expecting a count of zero, a flag that is off, or a blank
1123
+ string — and the truthiness gate that used to stand here refused every
1124
+ one of them as *"Value is empty"*. It surfaced on an assertion's
1125
+ Expected Value holding `null`: opening it reported *"Value for argument
1126
+ 1 ("any") is invalid: Value is empty"* on the value the author had
1127
+ deliberately chosen. Only `undefined` is actually empty.
1128
+
1129
+ `null` and `""` are answered here rather than delegated, for two
1130
+ different reasons: `getTypeFromValue(null)` answers `auto`, which would
1131
+ re-enter this very branch, and the `string` validator rejects `""`
1132
+ because that is the rule for a REQUIRED text field — a different
1133
+ question from whether an untyped field may hold a blank string. */
1134
+ if (parsedData === undefined) {
1135
+ return invalidResult('Value is empty');
1072
1136
  }
1073
1137
 
1074
- return invalidResult('Value is empty');
1138
+ if (parsedData === null || parsedData === '') {
1139
+ return validResult();
1140
+ }
1141
+
1142
+ /* Validate what was PARSED, against the type detected from the same
1143
+ parse. Validating the raw `value` instead made the two disagree
1144
+ whenever parsing changed the shape: typing `1` into an `auto` field
1145
+ parsed to the number 1, detected `int`, and then validated the STRING
1146
+ "1" against it — "Value must be an integer", on a value that is one.
1147
+ The author saw their field go invalid on the first character they
1148
+ typed. */
1149
+ return withContext(
1150
+ validateFieldWithResult(getTypeFromValue(parsedData), parsedData),
1151
+ 'Auto-detected type is invalid'
1152
+ );
1075
1153
  }
1076
1154
  case 'processor': {
1077
1155
  if (!value || !value['processor-input-type'] || !value['processor-output-type']) {
@@ -1295,6 +1373,22 @@ export const _validateField = (
1295
1373
  continue;
1296
1374
  }
1297
1375
 
1376
+ /* An option whose dependencies are not fulfilled is not part of this
1377
+ object, so it cannot make the object invalid.
1378
+
1379
+ The form already takes that view — it HIDES such an option — and
1380
+ the two disagreeing is a trap with no way out of it: a test whose
1381
+ subject moved from a versioned kind to a service keeps the
1382
+ `subject_iface_version` it no longer has a field for, and Submit
1383
+ goes dead naming an option that is nowhere on screen. Nulling the
1384
+ value does not help either, because a null is still a value the
1385
+ loop reaches.
1386
+
1387
+ A REQUIRED option with unfulfilled dependencies is unaffected:
1388
+ `getUnresolvedRequiredOptions` above reports it as `dependency`
1389
+ before this loop runs, and it is the only owner of that question.
1390
+ This branch was therefore only ever able to fail an option the
1391
+ author could not see and did not need. */
1298
1392
  if (
1299
1393
  (optionSchema?.[option] as TQorusFormFieldSchema)?.depends_on &&
1300
1394
  !hasAllDependenciesFullfilled(
@@ -1303,7 +1397,7 @@ export const _validateField = (
1303
1397
  optionSchema
1304
1398
  )
1305
1399
  ) {
1306
- return invalidResult(`Option ${option} dependencies are not fulfilled`);
1400
+ continue;
1307
1401
  }
1308
1402
 
1309
1403
  const optionResult =
@@ -1512,6 +1606,31 @@ export const _validateField = (
1512
1606
  const argDefinition = expressionDefinition.varargs
1513
1607
  ? expressionDefinition.args[0]
1514
1608
  : expressionDefinition.args[index];
1609
+ /* The argument's name for the message.
1610
+
1611
+ `display_name` is what a catalogue MAY carry; the served one carries
1612
+ `name`, so every message about an argument read "argument 1
1613
+ ("undefined") is invalid" and named a field that does not exist. */
1614
+ const argLabel =
1615
+ argDefinition?.display_name ?? argDefinition?.name ?? `argument ${index + 1}`;
1616
+
1617
+ /* An explicit null is a VALUE, and DPQL says so: `null` is a literal
1618
+ that parses, serializes and round-trips like any other.
1619
+
1620
+ Treated as a missing one, it made "this returns no value"
1621
+ unsayable. Typing `null` into the text editor produces the literal
1622
+ expression `{exp: "value", args: [null]}`; the visual view then
1623
+ called it invalid and refused to render a summary, and a raw null
1624
+ argument crashed the validator outright on `argValue.type`. Reported
1625
+ from the live IDE by an author with no other way to assert that a
1626
+ service method returns nothing.
1627
+
1628
+ Only an EXPLICIT null counts. An argument that is simply absent, or
1629
+ an envelope holding `undefined`, is still missing — which is the
1630
+ distinction the author is making when they write it. */
1631
+ if (argValue === null || (isObject(argValue) && (argValue as any).value === null)) {
1632
+ continue;
1633
+ }
1515
1634
 
1516
1635
  if (!argValue?.value && !argDefinition?.required) {
1517
1636
  continue;
@@ -1526,30 +1645,34 @@ export const _validateField = (
1526
1645
  if (!result.isValid) {
1527
1646
  return withContext(
1528
1647
  result,
1529
- `Sub-expression for argument ${index + 1} ("${argDefinition?.display_name}") is invalid`
1648
+ `Sub-expression for argument ${index + 1} ("${argLabel}") is invalid`
1530
1649
  );
1531
1650
  }
1532
1651
 
1533
1652
  continue;
1534
1653
  }
1535
1654
 
1536
- // A slot with no operand at all is a missing value, not a crash:
1537
- // judge it as an empty value of the type the catalogue expects.
1538
- const result = validateFieldWithResult(
1539
- argValue?.type ?? argDefinition?.ui_type,
1540
- argValue?.value,
1541
- {
1542
- expressions,
1543
- allowed_values: argDefinition?.allowed_values,
1544
- element_allowed_values: argDefinition?.element_allowed_values,
1545
- has_to_have_value: argDefinition?.required,
1546
- }
1547
- );
1655
+ /* A slot with no operand at all is judged as what it is — a missing
1656
+ value — rather than read for a `type` it does not have.
1657
+
1658
+ An operand that HOLDS something is judged by the envelope's own type,
1659
+ or — when the envelope carries none (a raw parse operand widened
1660
+ without a `ui_type`, a slot reset by a type change) — by the type the
1661
+ catalogue declares. Without that fallback `_validateField` refuses it
1662
+ for "Missing type" however right the value is. */
1663
+ const operandType =
1664
+ argValue?.type ?? (argValue?.value === undefined ? undefined : argDefinition?.ui_type);
1665
+ const result = validateFieldWithResult(operandType, argValue?.value, {
1666
+ expressions,
1667
+ allowed_values: argDefinition?.allowed_values,
1668
+ element_allowed_values: argDefinition?.element_allowed_values,
1669
+ has_to_have_value: argDefinition?.required,
1670
+ });
1548
1671
 
1549
1672
  if (!result.isValid) {
1550
1673
  return withContext(
1551
1674
  result,
1552
- `Value for argument ${index + 1} ("${argDefinition?.display_name}") is invalid`
1675
+ `Value for argument ${index + 1} ("${argLabel}") is invalid`
1553
1676
  );
1554
1677
  }
1555
1678
  }
@@ -1818,19 +1941,28 @@ export const getUnresolvedRequiredOptions = (
1818
1941
  /**
1819
1942
  * Split a dependency entry into the sibling it names and how its value is compared.
1820
1943
  *
1821
- * Three forms: `name` (the sibling must simply have a value), `name=value` (it must
1822
- * have exactly that value) and `name!=value` (it must have a value, and not that
1823
- * one). The negative form is what lets a field say it applies to every variant of a
1824
- * record but one — spelling that as an `any-of` list of every other variant is both
1825
- * unreadable in the "Depends on" lock and silently wrong the moment a variant is
1826
- * added.
1944
+ * Four forms: `name` (the sibling must simply have a value), `!name` (it must have
1945
+ * none), `name=value` (it must have exactly that value) and `name!=value` (it must
1946
+ * have a value, and not that one). The negative comparison is what lets a field say
1947
+ * it applies to every variant of a record but one — spelling that as an `any-of`
1948
+ * list of every other variant is both unreadable in the "Depends on" lock and
1949
+ * silently wrong the moment a variant is added.
1827
1950
  *
1828
1951
  * `!=` deliberately requires the sibling to be answered: "not X" is a statement about
1829
1952
  * an answer, so an unanswered sibling does not satisfy it and the field stays locked.
1953
+ *
1954
+ * `!name` is the form that statement cannot make. Two options that exclude one
1955
+ * another (a converter that reads NodeSet2 and one that writes OpenAPI 3) each
1956
+ * apply only while the OTHER has not been answered at all, and `name!=value` cannot
1957
+ * say that: it requires an answer. Being a predicate like any other, it composes
1958
+ * with the AND of the top-level entries and the OR of a nested list for free.
1959
+ *
1960
+ * `!` binds to the whole entry, so `!name` never carries a value; `!=` is checked
1961
+ * first, which is what keeps `name!=value` from being read as a leading `!`.
1830
1962
  */
1831
1963
  export const parseDependency = (
1832
1964
  dependency: string
1833
- ): { name: string; op?: '=' | '!='; value?: string } => {
1965
+ ): { name: string; op?: '=' | '!=' | '!'; value?: string } => {
1834
1966
  const neqIdx = dependency.indexOf('!=');
1835
1967
  if (neqIdx !== -1) {
1836
1968
  return {
@@ -1849,9 +1981,25 @@ export const parseDependency = (
1849
1981
  };
1850
1982
  }
1851
1983
 
1984
+ if (dependency.startsWith('!')) {
1985
+ return { name: dependency.substring(1), op: '!' };
1986
+ }
1987
+
1852
1988
  return { name: dependency };
1853
1989
  };
1854
1990
 
1991
+ /** Whether the named sibling currently holds a value this form accepts. */
1992
+ const siblingHasValue = (
1993
+ name: string,
1994
+ options: TQorusForm,
1995
+ optionsSchema?: IQorusFormSchema
1996
+ ): boolean =>
1997
+ validateField(options?.[name]?.type, options?.[name]?.value, {
1998
+ ...(optionsSchema?.[name] as unknown as IFieldValidationProps),
1999
+ options,
2000
+ optionSchema: optionsSchema,
2001
+ });
2002
+
1855
2003
  /** Whether one dependency entry holds against the current form values. */
1856
2004
  const isDependencyFulfilled = (
1857
2005
  dependency: string,
@@ -1860,6 +2008,15 @@ const isDependencyFulfilled = (
1860
2008
  ): boolean => {
1861
2009
  const { name, op, value } = parseDependency(dependency);
1862
2010
 
2011
+ if (op === '!') {
2012
+ // "Has no value" is true of a field the form has not materialized at all —
2013
+ // there is nothing there to be the value. So an absent sibling satisfies
2014
+ // this, exactly as it satisfies the bare form below: neither has an answer
2015
+ // to judge, and a mutual exclusion that locked both halves until one of
2016
+ // them was added would offer the author no way in.
2017
+ return !options?.[name] || !siblingHasValue(name, options, optionsSchema);
2018
+ }
2019
+
1863
2020
  if (op) {
1864
2021
  const optValue = options?.[name]?.value;
1865
2022
  if (optValue == null) {
@@ -1868,17 +2025,12 @@ const isDependencyFulfilled = (
1868
2025
  return op === '=' ? String(optValue) === value : String(optValue) !== value;
1869
2026
  }
1870
2027
 
1871
- return options?.[name]
1872
- ? validateField(options[name].type, options[name].value, {
1873
- ...(optionsSchema?.[name] as unknown as IFieldValidationProps),
1874
- options,
1875
- optionSchema: optionsSchema,
1876
- })
1877
- : true;
2028
+ return options?.[name] ? siblingHasValue(name, options, optionsSchema) : true;
1878
2029
  };
1879
2030
 
1880
2031
  export const hasAllDependenciesFullfilled = (
1881
- dependencies: string[] | string[][],
2032
+ /** Every entry must hold; a nested list is an ANY of its entries. Mixed freely. */
2033
+ dependencies: ReadonlyArray<string | readonly string[]>,
1882
2034
  options: TQorusForm,
1883
2035
  optionsSchema?: IQorusFormSchema
1884
2036
  ): boolean => {
@@ -1886,20 +2038,20 @@ export const hasAllDependenciesFullfilled = (
1886
2038
  return true;
1887
2039
  }
1888
2040
 
1889
- return dependencies.every((dependency: string | string[]) => {
2041
+ return dependencies.every((dependency) => {
1890
2042
  // A nested list is an ANY. It used to look each entry up as a whole form-field
1891
2043
  // name, so a `name=value` entry inside one found no field and returned `true`
1892
2044
  // unconditionally — the any-of group was satisfied by anything at all, while
1893
2045
  // CompactRow's lock rendered those same entries as real comparisons. Both halves
1894
2046
  // now go through one parser, so the grammar cannot mean two things.
1895
2047
  if (isArray(dependency)) {
1896
- return (dependency as string[]).some((dep) =>
2048
+ return (dependency as readonly string[]).some((dep) =>
1897
2049
  isDependencyFulfilled(dep, options, optionsSchema)
1898
2050
  );
1899
2051
  }
1900
2052
 
1901
2053
  return isString(dependency)
1902
- ? isDependencyFulfilled(dependency as string, options, optionsSchema)
2054
+ ? isDependencyFulfilled(dependency, options, optionsSchema)
1903
2055
  : true;
1904
2056
  });
1905
2057
  };
@@ -1,6 +1,7 @@
1
1
  import { ReqoreSpinner, ReqoreTree } from '@qoretechnologies/reqore';
2
2
  import { StoryObj } from '@storybook/react-vite';
3
3
  import { testsWaitForText } from '../../../__tests__/utils';
4
+ import { storyApiUrl } from '../../stories/storyNetwork';
4
5
  import { StoryMeta } from '../../types';
5
6
  import { useFetch } from './useFetch';
6
7
 
@@ -44,7 +45,7 @@ export const Get: Story = {
44
45
  mockData: [
45
46
  {
46
47
  // An array of mock objects which will add in every story
47
- url: 'https://hq.qoretechnologies.com:8092/api/latest/public/info',
48
+ url: storyApiUrl('public/info'),
48
49
  method: 'GET',
49
50
  status: 200,
50
51
  delay: 200,
@@ -81,7 +82,7 @@ export const Put: Story = {
81
82
  mockData: [
82
83
  {
83
84
  // An array of mock objects which will add in every story
84
- url: 'https://hq.qoretechnologies.com:8092/api/latest/public/info',
85
+ url: storyApiUrl('public/info'),
85
86
  method: 'PUT',
86
87
  status: 200,
87
88
  response: {
@@ -109,7 +110,7 @@ export const Post: Story = {
109
110
  mockData: [
110
111
  {
111
112
  // An array of mock objects which will add in every story
112
- url: 'https://hq.qoretechnologies.com:8092/api/latest/public/info',
113
+ url: storyApiUrl('public/info'),
113
114
  method: 'POST',
114
115
  status: 200,
115
116
  response: {
@@ -137,7 +138,7 @@ export const Del: Story = {
137
138
  mockData: [
138
139
  {
139
140
  // An array of mock objects which will add in every story
140
- url: 'https://hq.qoretechnologies.com:8092/api/latest/public/info',
141
+ url: storyApiUrl('public/info'),
141
142
  method: 'DELETE',
142
143
  status: 200,
143
144
  response: {
@@ -165,7 +166,7 @@ export const Error409: Story = {
165
166
  mockData: [
166
167
  {
167
168
  // An array of mock objects which will add in every story
168
- url: 'https://hq.qoretechnologies.com:8092/api/latest/public/info',
169
+ url: storyApiUrl('public/info'),
169
170
  method: 'POST',
170
171
  status: 409,
171
172
  response: {