@qoretechnologies/reqraft 0.10.53 → 0.10.54-pr.115.gaf0d7a7

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 (291) 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 +97 -0
  87. package/dist/components/form/expressions/argumentPresence.d.ts.map +1 -0
  88. package/dist/components/form/expressions/argumentPresence.js +203 -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 +20 -58
  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 +604 -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 +19 -11
  187. package/dist/helpers/templates.d.ts.map +1 -1
  188. package/dist/helpers/templates.js +46 -29
  189. package/dist/helpers/templates.js.map +1 -1
  190. package/dist/helpers/validations.d.ts.map +1 -1
  191. package/dist/helpers/validations.js +56 -9
  192. package/dist/helpers/validations.js.map +1 -1
  193. package/dist/hooks/useArgSchema.d.ts +2 -1
  194. package/dist/hooks/useArgSchema.d.ts.map +1 -1
  195. package/dist/hooks/useFetch/useFetch.d.ts +3 -1
  196. package/dist/hooks/useFetch/useFetch.d.ts.map +1 -1
  197. package/dist/hooks/useFetch/useFetch.js +47 -9
  198. package/dist/hooks/useFetch/useFetch.js.map +1 -1
  199. package/dist/hooks/useTemplates.d.ts +20 -0
  200. package/dist/hooks/useTemplates.d.ts.map +1 -1
  201. package/dist/hooks/useTemplates.js +34 -2
  202. package/dist/hooks/useTemplates.js.map +1 -1
  203. package/dist/index.d.ts +2 -1
  204. package/dist/index.d.ts.map +1 -1
  205. package/dist/index.js +5 -1
  206. package/dist/index.js.map +1 -1
  207. package/dist/stories/storyNetwork.d.ts +36 -0
  208. package/dist/stories/storyNetwork.d.ts.map +1 -0
  209. package/dist/stories/storyNetwork.js +82 -0
  210. package/dist/stories/storyNetwork.js.map +1 -0
  211. package/dist/utils/fetch.d.ts +151 -1
  212. package/dist/utils/fetch.d.ts.map +1 -1
  213. package/dist/utils/fetch.js +256 -44
  214. package/dist/utils/fetch.js.map +1 -1
  215. package/dist/utils/lspClient.d.ts +6 -0
  216. package/dist/utils/lspClient.d.ts.map +1 -1
  217. package/dist/utils/lspClient.js +62 -11
  218. package/dist/utils/lspClient.js.map +1 -1
  219. package/dist/utils/websocket.d.ts +6 -0
  220. package/dist/utils/websocket.d.ts.map +1 -1
  221. package/dist/utils/websocket.js +15 -7
  222. package/dist/utils/websocket.js.map +1 -1
  223. package/package.json +2 -2
  224. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +3 -119
  225. package/src/components/dpqlEditor/DpqlEditor.tsx +5 -2
  226. package/src/components/dpqlEditor/dpqlHelpers.ts +20 -1
  227. package/src/components/dpqlEditor/dpqlProbe.ts +165 -0
  228. package/src/components/dpqlEditor/dpqlTags.ts +13 -0
  229. package/src/components/dpqlEditor/index.ts +4 -0
  230. package/src/components/dpqlEditor/types.ts +38 -2
  231. package/src/components/dpqlEditor/useDpqlProbe.ts +33 -0
  232. package/src/components/dpqlEditor/useDpqlSession.ts +20 -4
  233. package/src/components/form/engine/CompactRow.tsx +240 -51
  234. package/src/components/form/engine/CompactToolbar.tsx +10 -3
  235. package/src/components/form/engine/FormEngine.stories.tsx +431 -124
  236. package/src/components/form/engine/FormEngine.tsx +508 -90
  237. package/src/components/form/engine/FormFieldsSkeleton.tsx +76 -0
  238. package/src/components/form/engine/OptionFieldMessages.tsx +103 -12
  239. package/src/components/form/engine/_structuredData/SchemaDataView.tsx +11 -0
  240. package/src/components/form/engine/compactToolbarContext.ts +1 -1
  241. package/src/components/form/engine/readFirst.ts +86 -7
  242. package/src/components/form/engine/rendererTypes.ts +12 -0
  243. package/src/components/form/engine/rowMenuContext.ts +159 -0
  244. package/src/components/form/engine/typeChoices.ts +61 -0
  245. package/src/components/form/expressions/DpqlRendering.tsx +85 -0
  246. package/src/components/form/expressions/ExpressionField.stories.tsx +826 -48
  247. package/src/components/form/expressions/ExpressionField.tsx +266 -54
  248. package/src/components/form/expressions/argumentPresence.ts +200 -0
  249. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +31 -14
  250. package/src/components/form/expressions/builder/argumentLabel.tsx +10 -4
  251. package/src/components/form/expressions/builder/index.tsx +39 -77
  252. package/src/components/form/expressions/builder/renderTemplate.tsx +23 -56
  253. package/src/components/form/expressions/dpqlMockLanguage.ts +565 -0
  254. package/src/components/form/expressions/dpqlMockLsp.ts +109 -83
  255. package/src/components/form/expressions/mockExpressions.ts +8 -4
  256. package/src/components/form/expressions/renderExpressionToText.ts +112 -22
  257. package/src/components/form/expressions/types.ts +7 -0
  258. package/src/components/form/expressions/useRenderExpression.ts +43 -127
  259. package/src/components/form/fields/Field.tsx +3 -2
  260. package/src/components/form/fields/allowed-values/AllowedValues.tsx +13 -2
  261. package/src/components/form/fields/auto/AutoFormField.stories.tsx +85 -18
  262. package/src/components/form/fields/auto/AutoFormField.tsx +90 -20
  263. package/src/components/form/fields/date/Date.tsx +17 -1
  264. package/src/components/form/fields/long-string/LongString.tsx +15 -3
  265. package/src/components/form/fields/rich-text/RichText.tsx +235 -30
  266. package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +4 -2
  267. package/src/components/form/fields/template/TemplateField.stories.tsx +93 -14
  268. package/src/components/form/fields/template/TemplateField.tsx +823 -129
  269. package/src/components/form/index.tsx +1 -0
  270. package/src/components/log/Log.stories.tsx +2 -1
  271. package/src/components/smartEditor/SmartEditor.tsx +41 -9
  272. package/src/components/smartEditor/__fixtures__/mockLspServer.ts +52 -3
  273. package/src/components/smartEditor/useLspSession.ts +21 -3
  274. package/src/helpers/dpqlDetection.ts +209 -0
  275. package/src/helpers/optionUiTypes.ts +22 -0
  276. package/src/helpers/options.ts +70 -0
  277. package/src/helpers/templateItems.ts +81 -0
  278. package/src/helpers/templateText.ts +92 -0
  279. package/src/helpers/templates.ts +47 -37
  280. package/src/helpers/validations.ts +59 -9
  281. package/src/hooks/useFetch/useFetch.stories.tsx +6 -5
  282. package/src/hooks/useFetch/useFetch.tsx +53 -7
  283. package/src/hooks/useStorage/useStorage.stories.tsx +2 -1
  284. package/src/hooks/useTemplates.ts +41 -0
  285. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +2 -1
  286. package/src/index.tsx +14 -1
  287. package/src/stores/currentUser/currentUser.stories.tsx +2 -1
  288. package/src/stories/storyNetwork.ts +92 -0
  289. package/src/utils/fetch.ts +311 -21
  290. package/src/utils/lspClient.ts +68 -11
  291. 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';
@@ -610,14 +611,38 @@ export const VariableArgumentsCanBeAdded: Story = {
610
611
  const CONCAT_OPERANDS = ['first', 'second', 'third'];
611
612
  const OPERAND_LITERALS = [...CONCAT_OPERANDS, 'plain', '$local:some-richtext'];
612
613
 
614
+ /**
615
+ * What an operand field holds. A text operand is edited in the chip editor
616
+ * (these stories offer templates), so it is read from the editable field; a
617
+ * template chip in it shows the name these stories' templates give the
618
+ * reference ("Richtext Template"), read back as the reference it names.
619
+ */
620
+ const readOperand = (field: HTMLElement): string => {
621
+ if (field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement) {
622
+ return field.value;
623
+ }
624
+ const shown = (field.textContent ?? '').replace(/\uFEFF/g, '').trim();
625
+ return (
626
+ OPERAND_LITERALS.find(
627
+ (literal) => literal === shown || templateChipLabel(localTemplates as never, literal) === shown
628
+ ) ?? shown
629
+ );
630
+ };
631
+
632
+ /** Every operand editor's text, in DOM order (no number or position inputs). */
633
+ const operandTexts = () =>
634
+ Array.from(
635
+ document.querySelectorAll<HTMLElement>('.expression textarea, .expression [contenteditable="true"]')
636
+ ).map(readOperand);
637
+
613
638
  /** Seeded operand values in DOM order — only the seeded ones, so stray fields don't count. */
614
639
  const operandValues = () =>
615
640
  Array.from(
616
- document.querySelectorAll<HTMLInputElement | HTMLTextAreaElement>(
617
- '.expression textarea, .expression input'
641
+ document.querySelectorAll<HTMLElement>(
642
+ '.expression textarea, .expression input, .expression [contenteditable="true"]'
618
643
  )
619
644
  )
620
- .map((field) => field.value)
645
+ .map(readOperand)
621
646
  .filter((value) => OPERAND_LITERALS.includes(value));
622
647
 
623
648
  const count = (selector: string) => document.querySelectorAll(selector).length;
@@ -665,7 +690,7 @@ export const ConcatExpression: Story = {
665
690
  docs: {
666
691
  description: {
667
692
  story:
668
- '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.',
693
+ '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.',
669
694
  },
670
695
  },
671
696
  },
@@ -732,11 +757,7 @@ export const ReorderLongConcat: Story = {
732
757
  await fireEvent.keyDown(field, { key: 'Enter' });
733
758
  await waitFor(
734
759
  () =>
735
- expect(
736
- Array.from(
737
- document.querySelectorAll<HTMLTextAreaElement>('.expression textarea')
738
- ).map((t) => t.value)
739
- ).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'second', 'seventh']),
760
+ expect(operandTexts()).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'second', 'seventh']),
740
761
  { timeout: 10000 }
741
762
  );
742
763
 
@@ -747,11 +768,7 @@ export const ReorderLongConcat: Story = {
747
768
  await clickSelector('.expression-arg-move-to-7');
748
769
  await waitFor(
749
770
  () =>
750
- expect(
751
- Array.from(
752
- document.querySelectorAll<HTMLTextAreaElement>('.expression textarea')
753
- ).map((t) => t.value)
754
- ).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'second']),
771
+ expect(operandTexts()).toEqual(['first', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'second']),
755
772
  { timeout: 10000 }
756
773
  );
757
774
  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
  <>
@@ -24,6 +24,7 @@ import React, { useCallback, useMemo, useRef, useState } from 'react';
24
24
  import styled from 'styled-components';
25
25
  import { moveItem } from '../../../../helpers/common';
26
26
  import { areQorusTypesCompatible, getArgumentType } from '../../../../helpers/expressions';
27
+ import { addMissingExpressionArgs } from '../argumentPresence';
27
28
  import { findTemplate } from '../../../../helpers/templates';
28
29
  import { validateField, validateFieldWithResult } from '../../../../helpers/validations';
29
30
  import { IQorusTypeObject, useQorusTypes } from '../../../../hooks/useQorusTypes';
@@ -76,6 +77,18 @@ export interface IExpressionBuilderProps {
76
77
  expressions?: IExpressionSchema[];
77
78
  expressionsUrl?: string;
78
79
  serverHandled?: boolean;
80
+ /**
81
+ * SEAM (reqraft): the host's per-`ui_type` editors, forwarded to the operand
82
+ * fields below.
83
+ *
84
+ * Without them an operand whose type is one of the CONSUMER's own ui_types
85
+ * falls through `AutoFormField`'s switch to the literal "Unknown type!" tag.
86
+ * That is what an assertion's `Value` did the moment it was turned into an
87
+ * expression: the field is `test-reference`, an IDE ui_type whose editor the
88
+ * IDE registers through `componentOverrides`, and the builder rendered its
89
+ * operands without them.
90
+ */
91
+ componentOverrides?: Record<string, React.FC<any>>;
79
92
  size?: string;
80
93
  /**
81
94
  * SEAM (reqraft): extra hover actions prepended to each expression card —
@@ -129,6 +142,7 @@ export const Expression = ({
129
142
  expressionsUrl,
130
143
  serverHandled,
131
144
  extraActions,
145
+ componentOverrides,
132
146
  ...props
133
147
  }: IExpressionProps) => {
134
148
  const types = useQorusTypes();
@@ -264,58 +278,8 @@ export const Expression = ({
264
278
  );
265
279
 
266
280
  const addMissingArgs = useCallback(
267
- (expression: string, args: IExpression[] = []): IExpression[] => {
268
- const newArgs = [...args];
269
- // Check if this expression has variable arguments
270
- const selectedExpression = expressions.value?.find((exp) => exp.name === expression);
271
-
272
- if (selectedExpression.varargs) {
273
- if (selectedExpression.subtype === 2) {
274
- newArgs.push({
275
- is_expression: true,
276
- value: {
277
- args: [],
278
- },
279
- });
280
- } else {
281
- // Add the number of arguments equal to min_args - 1
282
- newArgs.push(
283
- ...Array.from({ length: selectedExpression.min_args - 1 }, () => ({
284
- type:
285
- selectedExpression.args[0].ui_type === 'richtext' ||
286
- selectedExpression.args[0].ui_type === 'number'
287
- ? selectedExpression.args[0].ui_type
288
- : undefined,
289
- }))
290
- );
291
- }
292
- } else {
293
- // Check if any of the arguments have a default value
294
- selectedExpression.args.forEach((arg, index) => {
295
- if (
296
- newArgs[index] === undefined ||
297
- size(newArgs[index]) === 0 ||
298
- (arg.default_value && 'value' in newArgs[index] === false)
299
- ) {
300
- if (arg.default_value) {
301
- newArgs[index] = {
302
- value: arg.default_value,
303
- type: arg.ui_type,
304
- };
305
- } else {
306
- newArgs[index] = {
307
- type:
308
- arg.ui_type === 'richtext' || arg.ui_type === 'number' || arg.ui_type === 'bool'
309
- ? arg.ui_type
310
- : undefined,
311
- };
312
- }
313
- }
314
- });
315
- }
316
-
317
- return newArgs;
318
- },
281
+ (expression: string, args: IExpression[] = []): IExpression[] =>
282
+ addMissingExpressionArgs(expressions.value as never, expression, args as never) as never,
319
283
  [JSON.stringify(expressions.value)]
320
284
  );
321
285
 
@@ -501,13 +465,7 @@ export const Expression = ({
501
465
  );
502
466
 
503
467
  const updateArg = useCallback(
504
- (
505
- val: any,
506
- index: number = 0,
507
- type?: string,
508
- isFunction?: boolean,
509
- isRequired?: boolean
510
- ) => {
468
+ (val: any, index: number = 0, type?: string, isFunction?: boolean) => {
511
469
  const args = clone(value.value.args);
512
470
  const newVal = clone(val);
513
471
 
@@ -515,12 +473,18 @@ export const Expression = ({
515
473
  newVal.args = addMissingArgs(newVal.exp, newVal.args);
516
474
  }
517
475
 
476
+ /* `required` is NOT written here. It is a schema key — it describes the
477
+ catalogue's declaration of the argument, not the author's value, and
478
+ nothing reads it back off a stored argument (validation takes it from
479
+ the schema). Persisting it made a cleared argument indistinguishable
480
+ from real data: the value dropped out as `undefined`, `required: true`
481
+ stayed, and what was saved to the draft was `{type, required}` — an
482
+ argument DEFINITION sitting where its value should be. */
518
483
  args[index] = {
519
484
  ...args[index],
520
485
  value: newVal,
521
486
  type: !isFunction ? type || args[index]?.type : undefined,
522
487
  is_expression: isFunction,
523
- required: isRequired,
524
488
  };
525
489
 
526
490
  onValueChange(
@@ -683,16 +647,10 @@ export const Expression = ({
683
647
  const handleFirstParamChange = useCallback(
684
648
  (_name, value, type, isFunction) => {
685
649
  if (isFunction || (type !== 'any' && type !== 'auto')) {
686
- updateArg(
687
- value,
688
- 0,
689
- isFunction ? undefined : type,
690
- isFunction,
691
- selectedExpression?.args?.[0]?.required
692
- );
650
+ updateArg(value, 0, isFunction ? undefined : type, isFunction);
693
651
  }
694
652
  },
695
- [updateArg, JSON.stringify(selectedExpression)]
653
+ [updateArg]
696
654
  );
697
655
 
698
656
  const buildCustomTemplateItems = useCallback(
@@ -978,7 +936,9 @@ export const Expression = ({
978
936
  {confirmDialogData.children}
979
937
  </ConfirmUnsupportedTypeModal>
980
938
  )}
981
- {showSummary && <ExpressionRenderTemplate exp={value} expressions={expressions.value} />}
939
+ {showSummary && (
940
+ <ExpressionRenderTemplate exp={value} expressions={expressions.value} templates={localTemplates} />
941
+ )}
982
942
  {!selectedExpression && !serverExpression && !firstArgument?.value && level === 0 ? (
983
943
  <ReqoreMessage size='small' opaque={false} intent='info'>
984
944
  Select an operation to start building your expression
@@ -1013,6 +973,7 @@ export const Expression = ({
1013
973
  >
1014
974
  <TemplateField
1015
975
  component={auto}
976
+ componentOverrides={componentOverrides}
1016
977
  // SEAM (reqraft): an operand that becomes an expression mounts
1017
978
  // its own builder through this TemplateField — hand the host's
1018
979
  // actions on, or nesting silently drops them (the group
@@ -1132,6 +1093,7 @@ export const Expression = ({
1132
1093
  <TemplateField
1133
1094
  minimal
1134
1095
  component={auto}
1096
+ componentOverrides={componentOverrides}
1135
1097
  // SEAM (reqraft): same as the first operand above.
1136
1098
  extraActions={extraActions}
1137
1099
  noSoft
@@ -1166,13 +1128,7 @@ export const Expression = ({
1166
1128
  !!arg.default_value
1167
1129
  }
1168
1130
  onChange={((_name, value, type, isFunction) => {
1169
- updateArg(
1170
- value,
1171
- index + 1,
1172
- isFunction ? undefined : type,
1173
- isFunction,
1174
- arg.required
1175
- );
1131
+ updateArg(value, index + 1, isFunction ? undefined : type, isFunction);
1176
1132
  }) as any}
1177
1133
  fluid={false}
1178
1134
  fixed={true}
@@ -1248,6 +1204,7 @@ export const ExpressionBuilder = ({
1248
1204
  expressionsUrl,
1249
1205
  serverHandled,
1250
1206
  extraActions,
1207
+ componentOverrides,
1251
1208
  reorder,
1252
1209
  }: IExpressionBuilderProps) => {
1253
1210
  const templates = useTemplates(!isChild, localTemplates);
@@ -1369,7 +1326,11 @@ export const ExpressionBuilder = ({
1369
1326
  >
1370
1327
  <ReqoreControlGroup vertical fluid size='normal' style={{ position: 'relative' }} wrap>
1371
1328
  {showSummary && (
1372
- <ExpressionRenderTemplate exp={value} expressions={_expressions.expressions} />
1329
+ <ExpressionRenderTemplate
1330
+ exp={value}
1331
+ expressions={_expressions.expressions}
1332
+ templates={localTemplates}
1333
+ />
1373
1334
  )}
1374
1335
  <StyledExpressionItemLabel
1375
1336
  as={ReqoreP}
@@ -1432,6 +1393,7 @@ export const ExpressionBuilder = ({
1432
1393
  id={level === 0 && index === 0 ? 'expression-builder' : undefined}
1433
1394
  serverHandled={serverHandled}
1434
1395
  extraActions={extraActions}
1396
+ componentOverrides={componentOverrides}
1435
1397
  reorder={reorder}
1436
1398
  />
1437
1399
  </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
  };