@qoretechnologies/reqraft 0.10.54 → 0.10.55-pr.115.g24a94bf

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 (292) 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_EXPRESSIONS.md +110 -0
  6. package/design/FORM_ENGINE_FIELD_MIGRATION.md +155 -1
  7. package/design/RENDER_EXPRESSION_TRANSPORT.md +76 -10
  8. package/design/SMART_EDITOR_UX.md +21 -0
  9. package/dist/components/dpqlEditor/DpqlEditor.d.ts.map +1 -1
  10. package/dist/components/dpqlEditor/DpqlEditor.js +3 -3
  11. package/dist/components/dpqlEditor/DpqlEditor.js.map +1 -1
  12. package/dist/components/dpqlEditor/dpqlHelpers.d.ts +6 -0
  13. package/dist/components/dpqlEditor/dpqlHelpers.d.ts.map +1 -1
  14. package/dist/components/dpqlEditor/dpqlHelpers.js +21 -2
  15. package/dist/components/dpqlEditor/dpqlHelpers.js.map +1 -1
  16. package/dist/components/dpqlEditor/dpqlProbe.d.ts +37 -0
  17. package/dist/components/dpqlEditor/dpqlProbe.d.ts.map +1 -0
  18. package/dist/components/dpqlEditor/dpqlProbe.js +203 -0
  19. package/dist/components/dpqlEditor/dpqlProbe.js.map +1 -0
  20. package/dist/components/dpqlEditor/dpqlTags.d.ts +8 -0
  21. package/dist/components/dpqlEditor/dpqlTags.d.ts.map +1 -1
  22. package/dist/components/dpqlEditor/dpqlTags.js +5 -1
  23. package/dist/components/dpqlEditor/dpqlTags.js.map +1 -1
  24. package/dist/components/dpqlEditor/index.d.ts +4 -0
  25. package/dist/components/dpqlEditor/index.d.ts.map +1 -1
  26. package/dist/components/dpqlEditor/index.js +5 -1
  27. package/dist/components/dpqlEditor/index.js.map +1 -1
  28. package/dist/components/dpqlEditor/types.d.ts +42 -2
  29. package/dist/components/dpqlEditor/types.d.ts.map +1 -1
  30. package/dist/components/dpqlEditor/types.js +0 -4
  31. package/dist/components/dpqlEditor/types.js.map +1 -1
  32. package/dist/components/dpqlEditor/useDpqlProbe.d.ts +4 -0
  33. package/dist/components/dpqlEditor/useDpqlProbe.d.ts.map +1 -0
  34. package/dist/components/dpqlEditor/useDpqlProbe.js +29 -0
  35. package/dist/components/dpqlEditor/useDpqlProbe.js.map +1 -0
  36. package/dist/components/dpqlEditor/useDpqlSession.d.ts +5 -2
  37. package/dist/components/dpqlEditor/useDpqlSession.d.ts.map +1 -1
  38. package/dist/components/dpqlEditor/useDpqlSession.js +8 -2
  39. package/dist/components/dpqlEditor/useDpqlSession.js.map +1 -1
  40. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  41. package/dist/components/form/engine/CompactRow.js +192 -45
  42. package/dist/components/form/engine/CompactRow.js.map +1 -1
  43. package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
  44. package/dist/components/form/engine/CompactToolbar.js +5 -2
  45. package/dist/components/form/engine/CompactToolbar.js.map +1 -1
  46. package/dist/components/form/engine/FormEngine.d.ts +160 -12
  47. package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
  48. package/dist/components/form/engine/FormEngine.js +380 -78
  49. package/dist/components/form/engine/FormEngine.js.map +1 -1
  50. package/dist/components/form/engine/FormFieldsSkeleton.d.ts +48 -0
  51. package/dist/components/form/engine/FormFieldsSkeleton.d.ts.map +1 -0
  52. package/dist/components/form/engine/FormFieldsSkeleton.js +38 -0
  53. package/dist/components/form/engine/FormFieldsSkeleton.js.map +1 -0
  54. package/dist/components/form/engine/OptionFieldMessages.d.ts +17 -2
  55. package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
  56. package/dist/components/form/engine/OptionFieldMessages.js +73 -12
  57. package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
  58. package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -1
  59. package/dist/components/form/engine/_structuredData/SchemaDataView.js +7 -1
  60. package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -1
  61. package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
  62. package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
  63. package/dist/components/form/engine/readFirst.d.ts +42 -1
  64. package/dist/components/form/engine/readFirst.d.ts.map +1 -1
  65. package/dist/components/form/engine/readFirst.js +74 -7
  66. package/dist/components/form/engine/readFirst.js.map +1 -1
  67. package/dist/components/form/engine/rendererTypes.d.ts +13 -0
  68. package/dist/components/form/engine/rendererTypes.d.ts.map +1 -1
  69. package/dist/components/form/engine/rendererTypes.js.map +1 -1
  70. package/dist/components/form/engine/rowMenuContext.d.ts +78 -0
  71. package/dist/components/form/engine/rowMenuContext.d.ts.map +1 -0
  72. package/dist/components/form/engine/rowMenuContext.js +103 -0
  73. package/dist/components/form/engine/rowMenuContext.js.map +1 -0
  74. package/dist/components/form/engine/typeChoices.d.ts +42 -0
  75. package/dist/components/form/engine/typeChoices.d.ts.map +1 -0
  76. package/dist/components/form/engine/typeChoices.js +31 -0
  77. package/dist/components/form/engine/typeChoices.js.map +1 -0
  78. package/dist/components/form/expressions/DpqlRendering.d.ts +26 -0
  79. package/dist/components/form/expressions/DpqlRendering.d.ts.map +1 -0
  80. package/dist/components/form/expressions/DpqlRendering.js +53 -0
  81. package/dist/components/form/expressions/DpqlRendering.js.map +1 -0
  82. package/dist/components/form/expressions/ExpressionField.d.ts +7 -1
  83. package/dist/components/form/expressions/ExpressionField.d.ts.map +1 -1
  84. package/dist/components/form/expressions/ExpressionField.js +203 -45
  85. package/dist/components/form/expressions/ExpressionField.js.map +1 -1
  86. package/dist/components/form/expressions/argumentPresence.d.ts +84 -0
  87. package/dist/components/form/expressions/argumentPresence.d.ts.map +1 -0
  88. package/dist/components/form/expressions/argumentPresence.js +217 -0
  89. package/dist/components/form/expressions/argumentPresence.js.map +1 -0
  90. package/dist/components/form/expressions/builder/argumentLabel.d.ts.map +1 -1
  91. package/dist/components/form/expressions/builder/argumentLabel.js +9 -4
  92. package/dist/components/form/expressions/builder/argumentLabel.js.map +1 -1
  93. package/dist/components/form/expressions/builder/index.d.ts +15 -2
  94. package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
  95. package/dist/components/form/expressions/builder/index.js +21 -65
  96. package/dist/components/form/expressions/builder/index.js.map +1 -1
  97. package/dist/components/form/expressions/builder/renderTemplate.d.ts +4 -1
  98. package/dist/components/form/expressions/builder/renderTemplate.d.ts.map +1 -1
  99. package/dist/components/form/expressions/builder/renderTemplate.js +10 -67
  100. package/dist/components/form/expressions/builder/renderTemplate.js.map +1 -1
  101. package/dist/components/form/expressions/dpqlMockLanguage.d.ts +76 -0
  102. package/dist/components/form/expressions/dpqlMockLanguage.d.ts.map +1 -0
  103. package/dist/components/form/expressions/dpqlMockLanguage.js +525 -0
  104. package/dist/components/form/expressions/dpqlMockLanguage.js.map +1 -0
  105. package/dist/components/form/expressions/dpqlMockLsp.d.ts +31 -2
  106. package/dist/components/form/expressions/dpqlMockLsp.d.ts.map +1 -1
  107. package/dist/components/form/expressions/dpqlMockLsp.js +86 -80
  108. package/dist/components/form/expressions/dpqlMockLsp.js.map +1 -1
  109. package/dist/components/form/expressions/mockExpressions.d.ts.map +1 -1
  110. package/dist/components/form/expressions/mockExpressions.js +8 -4
  111. package/dist/components/form/expressions/mockExpressions.js.map +1 -1
  112. package/dist/components/form/expressions/renderExpressionToText.d.ts +1 -1
  113. package/dist/components/form/expressions/renderExpressionToText.d.ts.map +1 -1
  114. package/dist/components/form/expressions/renderExpressionToText.js +95 -19
  115. package/dist/components/form/expressions/renderExpressionToText.js.map +1 -1
  116. package/dist/components/form/expressions/types.d.ts +7 -0
  117. package/dist/components/form/expressions/types.d.ts.map +1 -1
  118. package/dist/components/form/expressions/useRenderExpression.d.ts +7 -16
  119. package/dist/components/form/expressions/useRenderExpression.d.ts.map +1 -1
  120. package/dist/components/form/expressions/useRenderExpression.js +50 -126
  121. package/dist/components/form/expressions/useRenderExpression.js.map +1 -1
  122. package/dist/components/form/fields/Field.d.ts.map +1 -1
  123. package/dist/components/form/fields/Field.js +3 -1
  124. package/dist/components/form/fields/Field.js.map +1 -1
  125. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +11 -1
  126. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
  127. package/dist/components/form/fields/allowed-values/AllowedValues.js +14 -2
  128. package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
  129. package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
  130. package/dist/components/form/fields/auto/AutoFormField.js +91 -28
  131. package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
  132. package/dist/components/form/fields/date/Date.d.ts +1 -1
  133. package/dist/components/form/fields/date/Date.d.ts.map +1 -1
  134. package/dist/components/form/fields/date/Date.js +16 -2
  135. package/dist/components/form/fields/date/Date.js.map +1 -1
  136. package/dist/components/form/fields/long-string/LongString.d.ts.map +1 -1
  137. package/dist/components/form/fields/long-string/LongString.js +14 -2
  138. package/dist/components/form/fields/long-string/LongString.js.map +1 -1
  139. package/dist/components/form/fields/rich-text/RichText.d.ts +35 -2
  140. package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
  141. package/dist/components/form/fields/rich-text/RichText.js +153 -12
  142. package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
  143. package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts +2 -1
  144. package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts.map +1 -1
  145. package/dist/components/form/fields/template/ReadOnlyTemplateTag.js +3 -2
  146. package/dist/components/form/fields/template/ReadOnlyTemplateTag.js.map +1 -1
  147. package/dist/components/form/fields/template/TemplateField.d.ts +34 -2
  148. package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
  149. package/dist/components/form/fields/template/TemplateField.js +606 -58
  150. package/dist/components/form/fields/template/TemplateField.js.map +1 -1
  151. package/dist/components/form/index.d.ts +1 -0
  152. package/dist/components/form/index.d.ts.map +1 -1
  153. package/dist/components/form/index.js +1 -0
  154. package/dist/components/form/index.js.map +1 -1
  155. package/dist/components/smartEditor/SmartEditor.d.ts.map +1 -1
  156. package/dist/components/smartEditor/SmartEditor.js +29 -8
  157. package/dist/components/smartEditor/SmartEditor.js.map +1 -1
  158. package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts +8 -0
  159. package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts.map +1 -1
  160. package/dist/components/smartEditor/__fixtures__/mockLspServer.js +53 -10
  161. package/dist/components/smartEditor/__fixtures__/mockLspServer.js.map +1 -1
  162. package/dist/components/smartEditor/useLspSession.d.ts +5 -1
  163. package/dist/components/smartEditor/useLspSession.d.ts.map +1 -1
  164. package/dist/components/smartEditor/useLspSession.js +16 -2
  165. package/dist/components/smartEditor/useLspSession.js.map +1 -1
  166. package/dist/helpers/dpqlDetection.d.ts +58 -0
  167. package/dist/helpers/dpqlDetection.d.ts.map +1 -0
  168. package/dist/helpers/dpqlDetection.js +164 -0
  169. package/dist/helpers/dpqlDetection.js.map +1 -0
  170. package/dist/helpers/optionUiTypes.d.ts +19 -3
  171. package/dist/helpers/optionUiTypes.d.ts.map +1 -1
  172. package/dist/helpers/optionUiTypes.js +20 -1
  173. package/dist/helpers/optionUiTypes.js.map +1 -1
  174. package/dist/helpers/options.d.ts +37 -0
  175. package/dist/helpers/options.d.ts.map +1 -1
  176. package/dist/helpers/options.js +78 -1
  177. package/dist/helpers/options.js.map +1 -1
  178. package/dist/helpers/templateItems.d.ts +47 -0
  179. package/dist/helpers/templateItems.d.ts.map +1 -0
  180. package/dist/helpers/templateItems.js +88 -0
  181. package/dist/helpers/templateItems.js.map +1 -0
  182. package/dist/helpers/templateText.d.ts +37 -0
  183. package/dist/helpers/templateText.d.ts.map +1 -0
  184. package/dist/helpers/templateText.js +64 -0
  185. package/dist/helpers/templateText.js.map +1 -0
  186. package/dist/helpers/templates.d.ts +30 -12
  187. package/dist/helpers/templates.d.ts.map +1 -1
  188. package/dist/helpers/templates.js +91 -33
  189. package/dist/helpers/templates.js.map +1 -1
  190. package/dist/helpers/validations.d.ts +1 -1
  191. package/dist/helpers/validations.d.ts.map +1 -1
  192. package/dist/helpers/validations.js +68 -12
  193. package/dist/helpers/validations.js.map +1 -1
  194. package/dist/hooks/useArgSchema.d.ts +2 -1
  195. package/dist/hooks/useArgSchema.d.ts.map +1 -1
  196. package/dist/hooks/useFetch/useFetch.d.ts +3 -1
  197. package/dist/hooks/useFetch/useFetch.d.ts.map +1 -1
  198. package/dist/hooks/useFetch/useFetch.js +47 -9
  199. package/dist/hooks/useFetch/useFetch.js.map +1 -1
  200. package/dist/hooks/useTemplates.d.ts +20 -0
  201. package/dist/hooks/useTemplates.d.ts.map +1 -1
  202. package/dist/hooks/useTemplates.js +34 -2
  203. package/dist/hooks/useTemplates.js.map +1 -1
  204. package/dist/index.d.ts +2 -1
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +5 -1
  207. package/dist/index.js.map +1 -1
  208. package/dist/stories/storyNetwork.d.ts +36 -0
  209. package/dist/stories/storyNetwork.d.ts.map +1 -0
  210. package/dist/stories/storyNetwork.js +82 -0
  211. package/dist/stories/storyNetwork.js.map +1 -0
  212. package/dist/utils/fetch.d.ts +151 -1
  213. package/dist/utils/fetch.d.ts.map +1 -1
  214. package/dist/utils/fetch.js +256 -44
  215. package/dist/utils/fetch.js.map +1 -1
  216. package/dist/utils/lspClient.d.ts +6 -0
  217. package/dist/utils/lspClient.d.ts.map +1 -1
  218. package/dist/utils/lspClient.js +62 -11
  219. package/dist/utils/lspClient.js.map +1 -1
  220. package/dist/utils/websocket.d.ts +6 -0
  221. package/dist/utils/websocket.d.ts.map +1 -1
  222. package/dist/utils/websocket.js +15 -7
  223. package/dist/utils/websocket.js.map +1 -1
  224. package/package.json +2 -2
  225. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +3 -119
  226. package/src/components/dpqlEditor/DpqlEditor.tsx +5 -2
  227. package/src/components/dpqlEditor/dpqlHelpers.ts +20 -1
  228. package/src/components/dpqlEditor/dpqlProbe.ts +165 -0
  229. package/src/components/dpqlEditor/dpqlTags.ts +13 -0
  230. package/src/components/dpqlEditor/index.ts +4 -0
  231. package/src/components/dpqlEditor/types.ts +38 -2
  232. package/src/components/dpqlEditor/useDpqlProbe.ts +33 -0
  233. package/src/components/dpqlEditor/useDpqlSession.ts +20 -4
  234. package/src/components/form/engine/CompactRow.tsx +240 -51
  235. package/src/components/form/engine/CompactToolbar.tsx +10 -3
  236. package/src/components/form/engine/FormEngine.stories.tsx +431 -124
  237. package/src/components/form/engine/FormEngine.tsx +508 -90
  238. package/src/components/form/engine/FormFieldsSkeleton.tsx +76 -0
  239. package/src/components/form/engine/OptionFieldMessages.tsx +103 -12
  240. package/src/components/form/engine/_structuredData/SchemaDataView.tsx +11 -0
  241. package/src/components/form/engine/compactToolbarContext.ts +1 -1
  242. package/src/components/form/engine/readFirst.ts +86 -7
  243. package/src/components/form/engine/rendererTypes.ts +12 -0
  244. package/src/components/form/engine/rowMenuContext.ts +159 -0
  245. package/src/components/form/engine/typeChoices.ts +61 -0
  246. package/src/components/form/expressions/DpqlRendering.tsx +85 -0
  247. package/src/components/form/expressions/ExpressionField.stories.tsx +826 -48
  248. package/src/components/form/expressions/ExpressionField.tsx +266 -54
  249. package/src/components/form/expressions/argumentPresence.ts +213 -0
  250. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +31 -14
  251. package/src/components/form/expressions/builder/argumentLabel.tsx +10 -4
  252. package/src/components/form/expressions/builder/index.tsx +39 -81
  253. package/src/components/form/expressions/builder/renderTemplate.tsx +23 -56
  254. package/src/components/form/expressions/dpqlMockLanguage.ts +565 -0
  255. package/src/components/form/expressions/dpqlMockLsp.ts +109 -83
  256. package/src/components/form/expressions/mockExpressions.ts +8 -4
  257. package/src/components/form/expressions/renderExpressionToText.ts +112 -22
  258. package/src/components/form/expressions/types.ts +7 -0
  259. package/src/components/form/expressions/useRenderExpression.ts +43 -127
  260. package/src/components/form/fields/Field.tsx +3 -2
  261. package/src/components/form/fields/allowed-values/AllowedValues.tsx +13 -2
  262. package/src/components/form/fields/auto/AutoFormField.stories.tsx +85 -18
  263. package/src/components/form/fields/auto/AutoFormField.tsx +90 -20
  264. package/src/components/form/fields/date/Date.tsx +17 -1
  265. package/src/components/form/fields/long-string/LongString.tsx +15 -3
  266. package/src/components/form/fields/rich-text/RichText.tsx +235 -30
  267. package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +4 -2
  268. package/src/components/form/fields/template/TemplateField.stories.tsx +93 -14
  269. package/src/components/form/fields/template/TemplateField.tsx +825 -131
  270. package/src/components/form/index.tsx +1 -0
  271. package/src/components/log/Log.stories.tsx +2 -1
  272. package/src/components/smartEditor/SmartEditor.tsx +41 -9
  273. package/src/components/smartEditor/__fixtures__/mockLspServer.ts +52 -3
  274. package/src/components/smartEditor/useLspSession.ts +21 -3
  275. package/src/helpers/dpqlDetection.ts +209 -0
  276. package/src/helpers/optionUiTypes.ts +22 -0
  277. package/src/helpers/options.ts +70 -0
  278. package/src/helpers/templateItems.ts +81 -0
  279. package/src/helpers/templateText.ts +92 -0
  280. package/src/helpers/templates.ts +94 -41
  281. package/src/helpers/validations.ts +79 -24
  282. package/src/hooks/useFetch/useFetch.stories.tsx +6 -5
  283. package/src/hooks/useFetch/useFetch.tsx +53 -7
  284. package/src/hooks/useStorage/useStorage.stories.tsx +2 -1
  285. package/src/hooks/useTemplates.ts +41 -0
  286. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +2 -1
  287. package/src/index.tsx +14 -1
  288. package/src/stores/currentUser/currentUser.stories.tsx +2 -1
  289. package/src/stories/storyNetwork.ts +92 -0
  290. package/src/utils/fetch.ts +311 -21
  291. package/src/utils/lspClient.ts +68 -11
  292. package/src/utils/websocket.ts +20 -9
@@ -9,6 +9,7 @@ import { expect, fireEvent, fn, userEvent, waitFor, within } from 'storybook/tes
9
9
  import { useState } from 'react';
10
10
  import { sleep } from '../../../../../__tests__/utils';
11
11
  import { StoryMeta } from '../../../../types';
12
+ import { templateChipLabel } from '../../../../helpers/templateText';
12
13
  import { mockExpressions } from '../mockExpressions';
13
14
  import { IExpression } from '../types';
14
15
  import { ExpressionBuilder } from './index';
@@ -643,14 +644,38 @@ export const VariableArgumentsCanBeAdded: Story = {
643
644
  const CONCAT_OPERANDS = ['first', 'second', 'third'];
644
645
  const OPERAND_LITERALS = [...CONCAT_OPERANDS, 'plain', '$local:some-richtext'];
645
646
 
647
+ /**
648
+ * What an operand field holds. A text operand is edited in the chip editor
649
+ * (these stories offer templates), so it is read from the editable field; a
650
+ * template chip in it shows the name these stories' templates give the
651
+ * reference ("Richtext Template"), read back as the reference it names.
652
+ */
653
+ const readOperand = (field: HTMLElement): string => {
654
+ if (field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement) {
655
+ return field.value;
656
+ }
657
+ const shown = (field.textContent ?? '').replace(/\uFEFF/g, '').trim();
658
+ return (
659
+ OPERAND_LITERALS.find(
660
+ (literal) => literal === shown || templateChipLabel(localTemplates as never, literal) === shown
661
+ ) ?? shown
662
+ );
663
+ };
664
+
665
+ /** Every operand editor's text, in DOM order (no number or position inputs). */
666
+ const operandTexts = () =>
667
+ Array.from(
668
+ document.querySelectorAll<HTMLElement>('.expression textarea, .expression [contenteditable="true"]')
669
+ ).map(readOperand);
670
+
646
671
  /** Seeded operand values in DOM order — only the seeded ones, so stray fields don't count. */
647
672
  const operandValues = () =>
648
673
  Array.from(
649
- document.querySelectorAll<HTMLInputElement | HTMLTextAreaElement>(
650
- '.expression textarea, .expression input'
674
+ document.querySelectorAll<HTMLElement>(
675
+ '.expression textarea, .expression input, .expression [contenteditable="true"]'
651
676
  )
652
677
  )
653
- .map((field) => field.value)
678
+ .map(readOperand)
654
679
  .filter((value) => OPERAND_LITERALS.includes(value));
655
680
 
656
681
  const count = (selector: string) => document.querySelectorAll(selector).length;
@@ -698,7 +723,7 @@ export const ConcatExpression: Story = {
698
723
  docs: {
699
724
  description: {
700
725
  story:
701
- 'Renders a "concat" varargs expression with three string operands ("first", "second", "third"). By default each operand gets a drag grip and a "Move Argument" section in its ⋮ menu — opened and expanded here on the second operand to show "Move before / after / to start / to end" and, at three operands, a "Move to position" caption with a single "2nd" position dropdown beside it, opened to show 1st / 2nd / 3rd.',
726
+ 'Renders a "concat" varargs expression with three string operands ("first", "second", "third"), each edited in the chip editor a string field with templates now uses — a contenteditable box rather than a textarea, so a template reference in an operand reads as its name. By default each operand gets a drag grip and a "Move Argument" section in its ⋮ menu — opened and expanded here on the second operand to show "Move before / after / to start / to end" and, at three operands, a "Move to position" caption with a single "2nd" position dropdown beside it, opened to show 1st / 2nd / 3rd.',
702
727
  },
703
728
  },
704
729
  },
@@ -765,11 +790,7 @@ export const ReorderLongConcat: Story = {
765
790
  await fireEvent.keyDown(field, { key: 'Enter' });
766
791
  await waitFor(
767
792
  () =>
768
- expect(
769
- Array.from(
770
- document.querySelectorAll<HTMLTextAreaElement>('.expression textarea')
771
- ).map((t) => t.value)
772
- ).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'second', 'seventh']),
793
+ expect(operandTexts()).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'second', 'seventh']),
773
794
  { timeout: 10000 }
774
795
  );
775
796
 
@@ -780,11 +801,7 @@ export const ReorderLongConcat: Story = {
780
801
  await clickSelector('.expression-arg-move-to-7');
781
802
  await waitFor(
782
803
  () =>
783
- expect(
784
- Array.from(
785
- document.querySelectorAll<HTMLTextAreaElement>('.expression textarea')
786
- ).map((t) => t.value)
787
- ).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'second']),
804
+ expect(operandTexts()).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'second']),
788
805
  { timeout: 10000 }
789
806
  );
790
807
  expect(context.args.onChange).toHaveBeenLastCalledWith(
@@ -49,9 +49,15 @@ export const ExpressionBuilderArgumentLabel = ({
49
49
  ...types.getExactMatches(schema.ui_type),
50
50
  ...types.getAcceptedTypes(schema.ui_type),
51
51
  ]);
52
- const { isValid, reason } = arg.is_expression
53
- ? validateFieldWithResult('expression', arg, { expressions })
54
- : validateFieldWithResult(argumentType, arg.value, schema, !schema.required);
52
+ /* `arg` is optional — an operand the author has not filled in yet has no
53
+ entry at all, and a literal carried straight from a parse can be the null
54
+ literal itself. Both were dereferenced unguarded here, which took the whole
55
+ expression editor down to its error boundary rather than drawing an empty
56
+ argument. */
57
+ const { isValid, reason } =
58
+ arg?.is_expression ?
59
+ validateFieldWithResult('expression', arg, { expressions })
60
+ : validateFieldWithResult(argumentType, arg?.value, schema, !schema.required);
55
61
 
56
62
  return (
57
63
  <ReqoreP
@@ -94,7 +100,7 @@ export const ExpressionBuilderArgumentLabel = ({
94
100
  {!matchesType ? (
95
101
  <ReqoreIcon icon='ErrorWarningLine' color='warning' size='10px' margin='both' />
96
102
  ) : null}
97
- {(argumentType || (arg.is_expression && arg.value?.exp)) &&
103
+ {(argumentType || (arg?.is_expression && arg.value?.exp)) &&
98
104
  types.getTypeDisplayName(argumentType) !== types.getTypeDisplayName(schema.ui_type) &&
99
105
  !matchesTypeExactly ? (
100
106
  <>
@@ -25,6 +25,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
25
25
  import styled from 'styled-components';
26
26
  import { moveItem } from '../../../../helpers/common';
27
27
  import { areQorusTypesCompatible, getArgumentType } from '../../../../helpers/expressions';
28
+ import { addMissingExpressionArgs } from '../argumentPresence';
28
29
  import { findTemplate } from '../../../../helpers/templates';
29
30
  import { validateField, validateFieldWithResult } from '../../../../helpers/validations';
30
31
  import { IQorusTypeObject, useQorusTypes } from '../../../../hooks/useQorusTypes';
@@ -79,6 +80,18 @@ export interface IExpressionBuilderProps {
79
80
  expressions?: IExpressionSchema[];
80
81
  expressionsUrl?: string;
81
82
  serverHandled?: boolean;
83
+ /**
84
+ * SEAM (reqraft): the host's per-`ui_type` editors, forwarded to the operand
85
+ * fields below.
86
+ *
87
+ * Without them an operand whose type is one of the CONSUMER's own ui_types
88
+ * falls through `AutoFormField`'s switch to the literal "Unknown type!" tag.
89
+ * That is what an assertion's `Value` did the moment it was turned into an
90
+ * expression: the field is `test-reference`, an IDE ui_type whose editor the
91
+ * IDE registers through `componentOverrides`, and the builder rendered its
92
+ * operands without them.
93
+ */
94
+ componentOverrides?: Record<string, React.FC<any>>;
82
95
  size?: string;
83
96
  /**
84
97
  * SEAM (reqraft): extra hover actions prepended to each expression card —
@@ -132,6 +145,7 @@ export const Expression = ({
132
145
  expressionsUrl,
133
146
  serverHandled,
134
147
  extraActions,
148
+ componentOverrides,
135
149
  ...props
136
150
  }: IExpressionProps) => {
137
151
  const types = useQorusTypes();
@@ -267,62 +281,8 @@ export const Expression = ({
267
281
  );
268
282
 
269
283
  const addMissingArgs = useCallback(
270
- (expression: string, args: IExpression[] = []): IExpression[] => {
271
- const newArgs = [...args];
272
- // Check if this expression has variable arguments
273
- const selectedExpression = expressions.value?.find((exp) => exp.name === expression);
274
-
275
- // An operand slot with nothing in it yet: the schema's default value
276
- // when it has one, otherwise an envelope typed after the schema for
277
- // the editors that need a type to mount. `updateExp` leaves such a
278
- // slot behind for every catalogue argument the previous value had no
279
- // operand for (a fresh builder has none), so every branch below has
280
- // to fill them — an `undefined` operand that reaches the validator or
281
- // an operand editor is read for its `type` and crashes the builder.
282
- const isEmptySlot = (slot: IExpression | undefined, arg: IExpressionSchemaArg) =>
283
- slot === undefined || size(slot) === 0 || (arg.default_value && !('value' in slot));
284
- const emptySlot = (arg: IExpressionSchemaArg): IExpression =>
285
- arg.default_value
286
- ? { value: arg.default_value, type: arg.ui_type }
287
- : {
288
- type:
289
- arg.ui_type === 'richtext' || arg.ui_type === 'number' || arg.ui_type === 'bool'
290
- ? arg.ui_type
291
- : undefined,
292
- };
293
-
294
- if (selectedExpression.varargs) {
295
- if (selectedExpression.subtype === 2) {
296
- newArgs.push({
297
- is_expression: true,
298
- value: {
299
- args: [],
300
- },
301
- });
302
- } else {
303
- // Every operand follows the one schema argument; add slots up to
304
- // min_args and fill the empty ones.
305
- const [schema] = selectedExpression.args;
306
-
307
- newArgs.push(
308
- ...Array.from({ length: selectedExpression.min_args - 1 }, () => emptySlot(schema))
309
- );
310
- newArgs.forEach((slot, index) => {
311
- if (isEmptySlot(slot, schema)) {
312
- newArgs[index] = emptySlot(schema);
313
- }
314
- });
315
- }
316
- } else {
317
- selectedExpression.args.forEach((arg, index) => {
318
- if (isEmptySlot(newArgs[index], arg)) {
319
- newArgs[index] = emptySlot(arg);
320
- }
321
- });
322
- }
323
-
324
- return newArgs;
325
- },
284
+ (expression: string, args: IExpression[] = []): IExpression[] =>
285
+ addMissingExpressionArgs(expressions.value as never, expression, args as never) as never,
326
286
  [JSON.stringify(expressions.value)]
327
287
  );
328
288
 
@@ -511,13 +471,7 @@ export const Expression = ({
511
471
  );
512
472
 
513
473
  const updateArg = useCallback(
514
- (
515
- val: any,
516
- index: number = 0,
517
- type?: string,
518
- isFunction?: boolean,
519
- isRequired?: boolean
520
- ) => {
474
+ (val: any, index: number = 0, type?: string, isFunction?: boolean) => {
521
475
  const args = clone(value.value.args);
522
476
  const newVal = clone(val);
523
477
 
@@ -525,12 +479,18 @@ export const Expression = ({
525
479
  newVal.args = addMissingArgs(newVal.exp, newVal.args);
526
480
  }
527
481
 
482
+ /* `required` is NOT written here. It is a schema key — it describes the
483
+ catalogue's declaration of the argument, not the author's value, and
484
+ nothing reads it back off a stored argument (validation takes it from
485
+ the schema). Persisting it made a cleared argument indistinguishable
486
+ from real data: the value dropped out as `undefined`, `required: true`
487
+ stayed, and what was saved to the draft was `{type, required}` — an
488
+ argument DEFINITION sitting where its value should be. */
528
489
  args[index] = {
529
490
  ...args[index],
530
491
  value: newVal,
531
492
  type: !isFunction ? type || args[index]?.type : undefined,
532
493
  is_expression: isFunction,
533
- required: isRequired,
534
494
  };
535
495
 
536
496
  onValueChange(
@@ -776,16 +736,10 @@ export const Expression = ({
776
736
  const handleFirstParamChange = useCallback(
777
737
  (_name, value, type, isFunction) => {
778
738
  if (isFunction || (type !== 'any' && type !== 'auto')) {
779
- updateArg(
780
- value,
781
- 0,
782
- isFunction ? undefined : type,
783
- isFunction,
784
- selectedExpression?.args?.[0]?.required
785
- );
739
+ updateArg(value, 0, isFunction ? undefined : type, isFunction);
786
740
  }
787
741
  },
788
- [updateArg, JSON.stringify(selectedExpression)]
742
+ [updateArg]
789
743
  );
790
744
 
791
745
  const buildCustomTemplateItems = useCallback(
@@ -1062,7 +1016,9 @@ export const Expression = ({
1062
1016
  {confirmDialogData.children}
1063
1017
  </ConfirmUnsupportedTypeModal>
1064
1018
  )}
1065
- {showSummary && <ExpressionRenderTemplate exp={value} expressions={expressions.value} />}
1019
+ {showSummary && (
1020
+ <ExpressionRenderTemplate exp={value} expressions={expressions.value} templates={localTemplates} />
1021
+ )}
1066
1022
  {!selectedExpression && !serverExpression && !firstArgument?.value && level === 0 ? (
1067
1023
  <ReqoreMessage size='small' opaque={false} intent='info'>
1068
1024
  Select an operation to start building your expression
@@ -1102,6 +1058,7 @@ export const Expression = ({
1102
1058
  >
1103
1059
  <TemplateField
1104
1060
  component={auto}
1061
+ componentOverrides={componentOverrides}
1105
1062
  // SEAM (reqraft): an operand that becomes an expression mounts
1106
1063
  // its own builder through this TemplateField — hand the host's
1107
1064
  // actions on, or nesting silently drops them (the group
@@ -1223,6 +1180,7 @@ export const Expression = ({
1223
1180
  <TemplateField
1224
1181
  minimal
1225
1182
  component={auto}
1183
+ componentOverrides={componentOverrides}
1226
1184
  // SEAM (reqraft): same as the first operand above.
1227
1185
  extraActions={extraActions}
1228
1186
  noSoft
@@ -1257,13 +1215,7 @@ export const Expression = ({
1257
1215
  !!arg.default_value
1258
1216
  }
1259
1217
  onChange={((_name, value, type, isFunction) => {
1260
- updateArg(
1261
- value,
1262
- index + 1,
1263
- isFunction ? undefined : type,
1264
- isFunction,
1265
- arg.required
1266
- );
1218
+ updateArg(value, index + 1, isFunction ? undefined : type, isFunction);
1267
1219
  }) as any}
1268
1220
  fluid={phone}
1269
1221
  fixed={!phone}
@@ -1351,6 +1303,7 @@ export const ExpressionBuilder = ({
1351
1303
  expressionsUrl,
1352
1304
  serverHandled,
1353
1305
  extraActions,
1306
+ componentOverrides,
1354
1307
  reorder,
1355
1308
  }: IExpressionBuilderProps) => {
1356
1309
  const templates = useTemplates(!isChild, localTemplates);
@@ -1472,7 +1425,11 @@ export const ExpressionBuilder = ({
1472
1425
  >
1473
1426
  <ReqoreControlGroup vertical fluid size='normal' style={{ position: 'relative' }} wrap>
1474
1427
  {showSummary && (
1475
- <ExpressionRenderTemplate exp={value} expressions={_expressions.expressions} />
1428
+ <ExpressionRenderTemplate
1429
+ exp={value}
1430
+ expressions={_expressions.expressions}
1431
+ templates={localTemplates}
1432
+ />
1476
1433
  )}
1477
1434
  <StyledExpressionItemLabel
1478
1435
  as={ReqoreP}
@@ -1535,6 +1492,7 @@ export const ExpressionBuilder = ({
1535
1492
  id={level === 0 && index === 0 ? 'expression-builder' : undefined}
1536
1493
  serverHandled={serverHandled}
1537
1494
  extraActions={extraActions}
1495
+ componentOverrides={componentOverrides}
1538
1496
  reorder={reorder}
1539
1497
  />
1540
1498
  </ReqoreErrorBoundary>
@@ -1,75 +1,42 @@
1
1
  // SEAM (reqraft): the IDE rendered the readable expression via
2
- // `callBackendBasic('render-expression')` over the Creator WebSocket; here
3
- // the same server rendering arrives over the LSP (`dpql/renderExpression`,
4
- // via `useRenderExpression`), with a client-side approximation as fallback.
5
- //
6
- // Server path: the rendering is displayed through a read-only `DpqlEditor`,
7
- // which gives template-reference chips (the `$context:value` converter) AND
8
- // LSP-backed token colours (semantic tokens) — diagnostics are suppressed
9
- // because the rendering is human-readable text, not parseable DPQL. The
10
- // fallback path keeps the plain rich-text rendering plus an explicit
11
- // "Approximate" tag so the serving path is never ambiguous.
2
+ // `callBackendBasic('render-expression')` over the Creator WebSocket; here the
3
+ // same server rendering arrives over the LSP (`dpql/renderExpression`, via
4
+ // `useRenderExpression`) and is shown through `ExpressionRendering`, the one
5
+ // read-only rendering every expression surface shares — monospace, coloured by
6
+ // the language server, template references as chips.
12
7
  // The component name/shape is kept identical so `index.tsx`'s usage is
13
8
  // unchanged.
14
- import { ReqoreTag } from '@qoretechnologies/reqore';
15
- import { useAsyncRetry } from 'react-use';
16
- import { DpqlEditor } from '../../../dpqlEditor';
9
+ import { ReqoreMessage } from '@qoretechnologies/reqore';
10
+ import { IReqoreFormTemplates } from '@qoretechnologies/reqore/dist/components/Textarea';
17
11
  import { validateField } from '../../../../helpers/validations';
18
- import { RichTextFormField } from '../../fields/rich-text/RichText';
19
- import { useRenderExpression } from '../useRenderExpression';
12
+ import { ExpressionRendering } from '../DpqlRendering';
20
13
  import { IExpression, IExpressionSchema } from '../types';
21
14
 
22
- const noop = (): void => undefined;
23
-
24
15
  export interface IExpressionRenderTemplateProps {
25
16
  exp: IExpression;
26
17
  expressions: IExpressionSchema[];
18
+ /** The builder's template catalogue: a reference in it reads as its name. */
19
+ templates?: IReqoreFormTemplates;
27
20
  }
28
21
 
29
- export const ExpressionRenderTemplate = ({ exp, expressions }: IExpressionRenderTemplateProps) => {
30
- const { renderRich } = useRenderExpression();
31
-
32
- const isValid = validateField('expression', exp, { expressions });
33
-
34
- const renderTemplate = useAsyncRetry(async () => {
35
- if (!isValid) return null;
36
- return renderRich(exp.value, expressions);
37
- }, [JSON.stringify(exp), JSON.stringify(expressions)]);
38
-
39
- if (!isValid || !renderTemplate.value || !renderTemplate.value.server) {
22
+ export const ExpressionRenderTemplate = ({
23
+ exp,
24
+ expressions,
25
+ templates,
26
+ }: IExpressionRenderTemplateProps) => {
27
+ if (!validateField('expression', exp, { expressions })) {
40
28
  return (
41
- <>
42
- <RichTextFormField
43
- readOnly
44
- value={
45
- isValid
46
- ? renderTemplate.value?.text
47
- : 'Expression is invalid, unable to render summary'
48
- }
49
- flat
50
- panelProps={{ style: { flexGrow: 0, flexShrink: 0 } }}
51
- size='small'
52
- />
53
- {isValid && renderTemplate.value ? (
54
- <ReqoreTag
55
- size='small'
56
- minimal
57
- intent='muted'
58
- label='Approximate — server rendering unavailable'
59
- />
60
- ) : null}
61
- </>
29
+ <ReqoreMessage size='small' intent='muted' flat opaque={false}>
30
+ Expression is invalid, unable to render summary
31
+ </ReqoreMessage>
62
32
  );
63
33
  }
64
34
 
65
35
  return (
66
- <DpqlEditor
67
- value={renderTemplate.value.text}
68
- onChange={noop}
69
- readOnly
70
- showDiagnostics={false}
71
- enableHover={false}
72
- templateTagsUseIntent
36
+ <ExpressionRendering
37
+ expression={exp.value}
38
+ templates={templates}
39
+ data-testid='expression-explanation'
73
40
  />
74
41
  );
75
42
  };