@qoretechnologies/reqraft 0.10.61 → 0.10.62-pr.137.g86641aa

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 (101) hide show
  1. package/dist/components/dpqlEditor/DpqlEditor.d.ts.map +1 -1
  2. package/dist/components/dpqlEditor/DpqlEditor.js +8 -3
  3. package/dist/components/dpqlEditor/DpqlEditor.js.map +1 -1
  4. package/dist/components/dpqlEditor/types.d.ts +5 -0
  5. package/dist/components/dpqlEditor/types.d.ts.map +1 -1
  6. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  7. package/dist/components/form/engine/CompactRow.js +17 -8
  8. package/dist/components/form/engine/CompactRow.js.map +1 -1
  9. package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
  10. package/dist/components/form/engine/FormEngine.js +65 -15
  11. package/dist/components/form/engine/FormEngine.js.map +1 -1
  12. package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
  13. package/dist/components/form/engine/OptionFieldMessages.js +12 -1
  14. package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
  15. package/dist/components/form/engine/compactRowContext.d.ts +2 -0
  16. package/dist/components/form/engine/compactRowContext.d.ts.map +1 -1
  17. package/dist/components/form/engine/compactRowContext.js.map +1 -1
  18. package/dist/components/form/engine/readFirst.d.ts.map +1 -1
  19. package/dist/components/form/engine/readFirst.js +5 -1
  20. package/dist/components/form/engine/readFirst.js.map +1 -1
  21. package/dist/components/form/expressions/ExpressionField.d.ts +21 -1
  22. package/dist/components/form/expressions/ExpressionField.d.ts.map +1 -1
  23. package/dist/components/form/expressions/ExpressionField.js +72 -14
  24. package/dist/components/form/expressions/ExpressionField.js.map +1 -1
  25. package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
  26. package/dist/components/form/expressions/builder/index.js +16 -3
  27. package/dist/components/form/expressions/builder/index.js.map +1 -1
  28. package/dist/components/form/expressions/expressionOperands.d.ts +16 -0
  29. package/dist/components/form/expressions/expressionOperands.d.ts.map +1 -0
  30. package/dist/components/form/expressions/expressionOperands.js +97 -0
  31. package/dist/components/form/expressions/expressionOperands.js.map +1 -0
  32. package/dist/components/form/expressions/mockExpressions.d.ts.map +1 -1
  33. package/dist/components/form/expressions/mockExpressions.js +15 -0
  34. package/dist/components/form/expressions/mockExpressions.js.map +1 -1
  35. package/dist/components/form/expressions/renderExpressionToText.d.ts +2 -0
  36. package/dist/components/form/expressions/renderExpressionToText.d.ts.map +1 -1
  37. package/dist/components/form/expressions/renderExpressionToText.js +24 -5
  38. package/dist/components/form/expressions/renderExpressionToText.js.map +1 -1
  39. package/dist/components/form/expressions/textOfExpression.d.ts +18 -0
  40. package/dist/components/form/expressions/textOfExpression.d.ts.map +1 -0
  41. package/dist/components/form/expressions/textOfExpression.js +37 -0
  42. package/dist/components/form/expressions/textOfExpression.js.map +1 -0
  43. package/dist/components/form/expressions/useRenderExpression.d.ts.map +1 -1
  44. package/dist/components/form/expressions/useRenderExpression.js +7 -7
  45. package/dist/components/form/expressions/useRenderExpression.js.map +1 -1
  46. package/dist/components/form/fields/rich-text/RichText.d.ts +8 -1
  47. package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
  48. package/dist/components/form/fields/rich-text/RichText.js +10 -10
  49. package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
  50. package/dist/components/form/fields/template/TemplateField.d.ts +6 -0
  51. package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
  52. package/dist/components/form/fields/template/TemplateField.js +280 -55
  53. package/dist/components/form/fields/template/TemplateField.js.map +1 -1
  54. package/dist/components/form/fields/template/writtenAsText.d.ts +57 -0
  55. package/dist/components/form/fields/template/writtenAsText.d.ts.map +1 -0
  56. package/dist/components/form/fields/template/writtenAsText.js +203 -0
  57. package/dist/components/form/fields/template/writtenAsText.js.map +1 -0
  58. package/dist/components/form/index.d.ts +2 -0
  59. package/dist/components/form/index.d.ts.map +1 -1
  60. package/dist/components/form/index.js +7 -1
  61. package/dist/components/form/index.js.map +1 -1
  62. package/dist/components/smartEditor/useLspSession.d.ts +6 -0
  63. package/dist/components/smartEditor/useLspSession.d.ts.map +1 -1
  64. package/dist/components/smartEditor/useLspSession.js +7 -6
  65. package/dist/components/smartEditor/useLspSession.js.map +1 -1
  66. package/dist/helpers/templates.d.ts +18 -0
  67. package/dist/helpers/templates.d.ts.map +1 -1
  68. package/dist/helpers/templates.js +30 -1
  69. package/dist/helpers/templates.js.map +1 -1
  70. package/dist/helpers/validations.d.ts.map +1 -1
  71. package/dist/helpers/validations.js +98 -18
  72. package/dist/helpers/validations.js.map +1 -1
  73. package/package.json +1 -1
  74. package/src/components/dpqlEditor/DpqlEditor.tsx +11 -18
  75. package/src/components/dpqlEditor/types.ts +5 -0
  76. package/src/components/form/engine/CompactRow.tsx +31 -10
  77. package/src/components/form/engine/FormEngine.stories.tsx +656 -18
  78. package/src/components/form/engine/FormEngine.tsx +64 -22
  79. package/src/components/form/engine/FormEngineRemote.stories.tsx +5 -0
  80. package/src/components/form/engine/OptionFieldMessages.tsx +12 -1
  81. package/src/components/form/engine/compactRowContext.ts +2 -0
  82. package/src/components/form/engine/readFirst.ts +7 -1
  83. package/src/components/form/expressions/ExpressionField.stories.tsx +57 -9
  84. package/src/components/form/expressions/ExpressionField.tsx +179 -60
  85. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +8 -1
  86. package/src/components/form/expressions/builder/index.tsx +16 -3
  87. package/src/components/form/expressions/dpqlMockLanguage.ts +7 -2
  88. package/src/components/form/expressions/expressionOperands.ts +74 -0
  89. package/src/components/form/expressions/mockExpressions.ts +16 -4
  90. package/src/components/form/expressions/renderExpressionToText.ts +26 -9
  91. package/src/components/form/expressions/textOfExpression.ts +39 -0
  92. package/src/components/form/expressions/useRenderExpression.ts +9 -1
  93. package/src/components/form/fields/number/Number.stories.tsx +8 -7
  94. package/src/components/form/fields/rich-text/RichText.tsx +18 -10
  95. package/src/components/form/fields/template/TemplateField.stories.tsx +486 -18
  96. package/src/components/form/fields/template/TemplateField.tsx +506 -62
  97. package/src/components/form/fields/template/writtenAsText.ts +217 -0
  98. package/src/components/form/index.tsx +6 -0
  99. package/src/components/smartEditor/useLspSession.ts +15 -10
  100. package/src/helpers/templates.ts +35 -0
  101. package/src/helpers/validations.ts +83 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqraft",
3
- "version": "0.10.61",
3
+ "version": "0.10.62-pr.137.g86641aa",
4
4
  "description": "ReQraft is a collection of React components and hooks that are used across Qore Technologies' products made using the ReQore component library from Qore.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -12,14 +12,7 @@
12
12
  // There is intentionally no client-side "Templates" button — it would
13
13
  // duplicate what the server already returns on `$`.
14
14
 
15
- import {
16
- forwardRef,
17
- useEffect,
18
- useImperativeHandle,
19
- useMemo,
20
- useRef,
21
- useState,
22
- } from 'react';
15
+ import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
23
16
  import { SmartEditor } from '../smartEditor/SmartEditor';
24
17
  import { ISlateConverter, ISlateElement } from '../smartEditor/types';
25
18
  import { dpqlSlateConverter, richtextResponseToSlate } from './dpqlHelpers';
@@ -58,6 +51,7 @@ export const DpqlEditor = forwardRef<IDpqlEditorRef, IDpqlEditorProps>(
58
51
  fields,
59
52
  alertPayloadContext = false,
60
53
  fsmContext,
54
+ onUnavailable,
61
55
  },
62
56
  ref
63
57
  ) => {
@@ -79,12 +73,8 @@ export const DpqlEditor = forwardRef<IDpqlEditorRef, IDpqlEditorProps>(
79
73
  // reuse it without another roundtrip. `null` until the first
80
74
  // response arrives (or when the request errored — caller falls
81
75
  // back to the client-side regex parser via `dpqlSlateConverter`).
82
- const [serverParsedNodes, setServerParsedNodes] = useState<
83
- ISlateElement[] | null
84
- >(null);
85
- const [serverParsedFor, setServerParsedFor] = useState<string | null>(
86
- null
87
- );
76
+ const [serverParsedNodes, setServerParsedNodes] = useState<ISlateElement[] | null>(null);
77
+ const [serverParsedFor, setServerParsedFor] = useState<string | null>(null);
88
78
  const [isParsing, setIsParsing] = useState(false);
89
79
  // Tracks the most recent in-flight request so a slow response
90
80
  // can't overwrite a newer one (the user typed faster than the
@@ -163,10 +153,7 @@ export const DpqlEditor = forwardRef<IDpqlEditorRef, IDpqlEditorProps>(
163
153
  return {
164
154
  ...dpqlSlateConverter,
165
155
  toSlateNodes: (text: string) => {
166
- if (
167
- text === serverParsedFor &&
168
- serverParsedNodes
169
- ) {
156
+ if (text === serverParsedFor && serverParsedNodes) {
170
157
  return serverParsedNodes;
171
158
  }
172
159
  return dpqlSlateConverter.toSlateNodes(text);
@@ -174,6 +161,12 @@ export const DpqlEditor = forwardRef<IDpqlEditorRef, IDpqlEditorProps>(
174
161
  };
175
162
  }, [useServerParse, serverParsedFor, serverParsedNodes]);
176
163
 
164
+ // no language server to talk to: said once, for the host to show what works without one
165
+ const unavailable = dpql.session.isUnavailable;
166
+ useEffect(() => {
167
+ if (unavailable) onUnavailable?.();
168
+ }, [unavailable]);
169
+
177
170
  const tagRenderer = useMemo(
178
171
  () => makeDpqlTagRenderer(dpql.fieldMeta, { templateTagsUseIntent, templates }),
179
172
  [dpql.fieldMeta, templateTagsUseIntent, templates]
@@ -114,6 +114,11 @@ export interface IDpqlEditorProps {
114
114
  templates?: IReqoreFormTemplates;
115
115
  /** Called when the editor loses focus. */
116
116
  onBlur?: () => void;
117
+ /**
118
+ * Called once when there is no language server to talk to (connecting failed): the editor can show the
119
+ * text but not parse, serialize or complete it, so a host that needs those offers what works without it.
120
+ */
121
+ onUnavailable?: () => void;
117
122
  /**
118
123
  * Opt-in to server-driven plain-text → Slate parsing via the LSP's
119
124
  * `dpql/toRichtext` custom method. When `true`, the editor calls
@@ -166,6 +166,9 @@ export const richtextItemText = (item: unknown): string | undefined =>
166
166
  richtextToString((item as { value?: Parameters<typeof richtextToString>[0] }).value)
167
167
  : undefined;
168
168
 
169
+ /** The status boxes by name, as their headers say them. */
170
+ const BOX_NAMES = { attention: 'Needs attention', set: 'Set', optional: 'Optional' } as const;
171
+
169
172
  export const CompactRow = memo(
170
173
  ({
171
174
  optionName,
@@ -210,6 +213,8 @@ export const CompactRow = memo(
210
213
  const isExpanded = useContextSelector(CompactRowContext, (v) =>
211
214
  v.expandedOptions.includes(optionName)
212
215
  );
216
+ // the box this open field moves to when it is closed, when that is not the one it is shown in
217
+ const movesTo = useContextSelector(CompactRowContext, (v) => v.heldOptions?.[optionName]);
213
218
  const isHighlighted = useContextSelector(CompactRowContext, (v) =>
214
219
  v.highlightedOptions.includes(optionName)
215
220
  );
@@ -222,10 +227,7 @@ export const CompactRow = memo(
222
227
  );
223
228
  const setFocusedEditing = useContextSelector(CompactRowContext, (v) => v.setFocusedEditing);
224
229
  const readRowHeights = useContextSelector(CompactRowContext, (v) => v.readRowHeights);
225
- const onReadOnlyActivate = useContextSelector(
226
- CompactRowContext,
227
- (v) => v.onReadOnlyActivate
228
- );
230
+ const onReadOnlyActivate = useContextSelector(CompactRowContext, (v) => v.onReadOnlyActivate);
229
231
 
230
232
  /**
231
233
  * The floor recorded when a row is opened lasts until the author changes
@@ -401,7 +403,11 @@ export const CompactRow = memo(
401
403
  );
402
404
  }
403
405
 
404
- if (valueType === 'bool' || valueType === 'boolean') {
406
+ // a yes/no holding a template reads as the template, below, not as Yes (qorus#646)
407
+ if (
408
+ (valueType === 'bool' || valueType === 'boolean') &&
409
+ !(typeof field?.value === 'string' && isValueTemplate(field.value))
410
+ ) {
405
411
  const truthy = field?.value === true || field?.value === 'true';
406
412
  return (
407
413
  <ReqoreTag
@@ -1245,6 +1251,7 @@ export const CompactRow = memo(
1245
1251
  const panelMessages = schemaMessages;
1246
1252
  const inlineMessages: TInfoMsg[] = [
1247
1253
  ...fieldMessages,
1254
+
1248
1255
  ...(infoActive && schema?.default_value_desc ?
1249
1256
  [
1250
1257
  {
@@ -1587,6 +1594,18 @@ export const CompactRow = memo(
1587
1594
  {renderOption(optionName, optionField, 'small', true)}
1588
1595
  </RowMenuContext.Provider>
1589
1596
  </RowOpenPickerContext.Provider>
1597
+ {/* Why a value already right is still in this box: an open field stays where it was opened
1598
+ (moving it would take the focus), and says where it goes when it is closed. */}
1599
+ {movesTo ?
1600
+ <ReqoreP
1601
+ size='small'
1602
+ className='options-readfirst-moves-to'
1603
+ intent={movesTo === 'attention' ? 'warning' : 'success'}
1604
+ style={{ marginTop: 4 }}
1605
+ >
1606
+ {`Moves to "${BOX_NAMES[movesTo]}" when you close it (✓)`}
1607
+ </ReqoreP>
1608
+ : null}
1590
1609
  </div>
1591
1610
  <StyledRowActions>
1592
1611
  {draftChip}
@@ -1674,9 +1693,12 @@ export const CompactRow = memo(
1674
1693
  $border={schemaIntentColor ? `${schemaIntentColor}66` : `${cInfo}66`}
1675
1694
  >
1676
1695
  <div
1696
+ className='options-readfirst-card-header'
1677
1697
  style={{
1678
1698
  display: 'flex',
1679
- alignItems: 'flex-start',
1699
+ // a heading of one line is centred on the card's actions; one with a description or tags under
1700
+ // its name lines up by its top (David's review of qorus#646: the name sat above the buttons)
1701
+ alignItems: schema?.short_desc || cardTags.length ? 'flex-start' : 'center',
1680
1702
  justifyContent: 'space-between',
1681
1703
  gap: 12,
1682
1704
  }}
@@ -1893,9 +1915,7 @@ export const CompactRow = memo(
1893
1915
  !Array.isArray(optionField.value) &&
1894
1916
  !isExpression;
1895
1917
  const hashEntries =
1896
- !hidden && (isPlainHashType || isObjectValuedType) ?
1897
- getHashEntries(optionField, schema)
1898
- : [];
1918
+ !hidden && (isPlainHashType || isObjectValuedType) ? getHashEntries(optionField, schema) : [];
1899
1919
  // A LIST OF HASHES/objects gets the same expandable structured preview a hash
1900
1920
  // does — the flat "N items" summary can't convey object contents (and must
1901
1921
  // never print "[object Object]"). StructuredDataView unwraps each item's
@@ -2231,7 +2251,8 @@ export const CompactRow = memo(
2231
2251
  tabIndex={actsOnClick ? 0 : undefined}
2232
2252
  aria-label={
2233
2253
  readOnlyIsAWayIn ? `Edit ${label}`
2234
- : readOnly ? undefined
2254
+ : readOnly ?
2255
+ undefined
2235
2256
  : label
2236
2257
  }
2237
2258
  className={`readfirst-row options-readfirst-value${readOnly ? ' readfirst-row-read' : ''}${readOnlyIsAWayIn ? ' readfirst-row-way-in' : ''}${hidden ? ' readfirst-row-hidden' : ''}${fieldDisabled ? ' readfirst-row-disabled' : ''}${isHighlighted ? ' readfirst-row-group-highlight' : ''}${isFlashed ? ' readfirst-row-flash' : ''}${showLabelDesc ? ' readfirst-row-info-open' : ''}${panelMessages.length || showStructuredPreview || showCodePreview || showMarkdownPreview || showLongTextInset ? ' readfirst-row-tall' : ''}${clusterBlockClass ? ' ' + clusterBlockClass : ''}`}