@qoretechnologies/reqraft 0.10.53 → 0.10.54-pr.115.g9bc96ed
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.
- package/.claude/CLAUDE.md +25 -0
- package/.tasks/INDEX.md +1 -0
- package/.tasks/STORY_NETWORK_ISOLATION.md +98 -0
- package/README.md +1 -1
- package/design/FORM_ENGINE_EXPRESSIONS.md +110 -0
- package/design/FORM_ENGINE_FIELD_MIGRATION.md +56 -1
- package/design/RENDER_EXPRESSION_TRANSPORT.md +76 -10
- package/design/SMART_EDITOR_UX.md +21 -0
- package/dist/components/dpqlEditor/DpqlEditor.d.ts.map +1 -1
- package/dist/components/dpqlEditor/DpqlEditor.js +3 -3
- package/dist/components/dpqlEditor/DpqlEditor.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts +6 -0
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.js +21 -2
- package/dist/components/dpqlEditor/dpqlHelpers.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlProbe.d.ts +37 -0
- package/dist/components/dpqlEditor/dpqlProbe.d.ts.map +1 -0
- package/dist/components/dpqlEditor/dpqlProbe.js +203 -0
- package/dist/components/dpqlEditor/dpqlProbe.js.map +1 -0
- package/dist/components/dpqlEditor/dpqlTags.d.ts +8 -0
- package/dist/components/dpqlEditor/dpqlTags.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlTags.js +5 -1
- package/dist/components/dpqlEditor/dpqlTags.js.map +1 -1
- package/dist/components/dpqlEditor/index.d.ts +4 -0
- package/dist/components/dpqlEditor/index.d.ts.map +1 -1
- package/dist/components/dpqlEditor/index.js +5 -1
- package/dist/components/dpqlEditor/index.js.map +1 -1
- package/dist/components/dpqlEditor/types.d.ts +42 -2
- package/dist/components/dpqlEditor/types.d.ts.map +1 -1
- package/dist/components/dpqlEditor/types.js +0 -4
- package/dist/components/dpqlEditor/types.js.map +1 -1
- package/dist/components/dpqlEditor/useDpqlProbe.d.ts +4 -0
- package/dist/components/dpqlEditor/useDpqlProbe.d.ts.map +1 -0
- package/dist/components/dpqlEditor/useDpqlProbe.js +29 -0
- package/dist/components/dpqlEditor/useDpqlProbe.js.map +1 -0
- package/dist/components/dpqlEditor/useDpqlSession.d.ts +5 -2
- package/dist/components/dpqlEditor/useDpqlSession.d.ts.map +1 -1
- package/dist/components/dpqlEditor/useDpqlSession.js +8 -2
- package/dist/components/dpqlEditor/useDpqlSession.js.map +1 -1
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +192 -45
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
- package/dist/components/form/engine/CompactToolbar.js +5 -2
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts +160 -12
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +376 -75
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/FormFieldsSkeleton.d.ts +48 -0
- package/dist/components/form/engine/FormFieldsSkeleton.d.ts.map +1 -0
- package/dist/components/form/engine/FormFieldsSkeleton.js +38 -0
- package/dist/components/form/engine/FormFieldsSkeleton.js.map +1 -0
- package/dist/components/form/engine/OptionFieldMessages.d.ts +17 -2
- package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
- package/dist/components/form/engine/OptionFieldMessages.js +61 -11
- package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.js +7 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
- package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.d.ts +42 -1
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +74 -7
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/engine/rendererTypes.d.ts +13 -0
- package/dist/components/form/engine/rendererTypes.d.ts.map +1 -1
- package/dist/components/form/engine/rendererTypes.js.map +1 -1
- package/dist/components/form/engine/rowMenuContext.d.ts +78 -0
- package/dist/components/form/engine/rowMenuContext.d.ts.map +1 -0
- package/dist/components/form/engine/rowMenuContext.js +103 -0
- package/dist/components/form/engine/rowMenuContext.js.map +1 -0
- package/dist/components/form/engine/typeChoices.d.ts +37 -0
- package/dist/components/form/engine/typeChoices.d.ts.map +1 -0
- package/dist/components/form/engine/typeChoices.js +25 -0
- package/dist/components/form/engine/typeChoices.js.map +1 -0
- package/dist/components/form/expressions/DpqlRendering.d.ts +26 -0
- package/dist/components/form/expressions/DpqlRendering.d.ts.map +1 -0
- package/dist/components/form/expressions/DpqlRendering.js +53 -0
- package/dist/components/form/expressions/DpqlRendering.js.map +1 -0
- package/dist/components/form/expressions/ExpressionField.d.ts +7 -1
- package/dist/components/form/expressions/ExpressionField.d.ts.map +1 -1
- package/dist/components/form/expressions/ExpressionField.js +202 -45
- package/dist/components/form/expressions/ExpressionField.js.map +1 -1
- package/dist/components/form/expressions/argumentPresence.d.ts +97 -0
- package/dist/components/form/expressions/argumentPresence.d.ts.map +1 -0
- package/dist/components/form/expressions/argumentPresence.js +203 -0
- package/dist/components/form/expressions/argumentPresence.js.map +1 -0
- package/dist/components/form/expressions/builder/argumentLabel.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/argumentLabel.js +9 -4
- package/dist/components/form/expressions/builder/argumentLabel.js.map +1 -1
- package/dist/components/form/expressions/builder/index.d.ts +15 -2
- package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/index.js +20 -58
- package/dist/components/form/expressions/builder/index.js.map +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.d.ts +4 -1
- package/dist/components/form/expressions/builder/renderTemplate.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.js +10 -67
- package/dist/components/form/expressions/builder/renderTemplate.js.map +1 -1
- package/dist/components/form/expressions/dpqlMockLanguage.d.ts +76 -0
- package/dist/components/form/expressions/dpqlMockLanguage.d.ts.map +1 -0
- package/dist/components/form/expressions/dpqlMockLanguage.js +525 -0
- package/dist/components/form/expressions/dpqlMockLanguage.js.map +1 -0
- package/dist/components/form/expressions/dpqlMockLsp.d.ts +31 -2
- package/dist/components/form/expressions/dpqlMockLsp.d.ts.map +1 -1
- package/dist/components/form/expressions/dpqlMockLsp.js +86 -80
- package/dist/components/form/expressions/dpqlMockLsp.js.map +1 -1
- package/dist/components/form/expressions/mockExpressions.d.ts.map +1 -1
- package/dist/components/form/expressions/mockExpressions.js +8 -4
- package/dist/components/form/expressions/mockExpressions.js.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.d.ts +1 -1
- package/dist/components/form/expressions/renderExpressionToText.d.ts.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.js +95 -19
- package/dist/components/form/expressions/renderExpressionToText.js.map +1 -1
- package/dist/components/form/expressions/types.d.ts +7 -0
- package/dist/components/form/expressions/types.d.ts.map +1 -1
- package/dist/components/form/expressions/useRenderExpression.d.ts +7 -16
- package/dist/components/form/expressions/useRenderExpression.d.ts.map +1 -1
- package/dist/components/form/expressions/useRenderExpression.js +50 -126
- package/dist/components/form/expressions/useRenderExpression.js.map +1 -1
- package/dist/components/form/fields/Field.d.ts.map +1 -1
- package/dist/components/form/fields/Field.js +3 -1
- package/dist/components/form/fields/Field.js.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +11 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.js +14 -2
- package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +32 -8
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/dist/components/form/fields/date/Date.d.ts +1 -1
- package/dist/components/form/fields/date/Date.d.ts.map +1 -1
- package/dist/components/form/fields/date/Date.js +16 -2
- package/dist/components/form/fields/date/Date.js.map +1 -1
- package/dist/components/form/fields/rich-text/RichText.d.ts +21 -1
- package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
- package/dist/components/form/fields/rich-text/RichText.js +140 -8
- package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts +2 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts.map +1 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js +3 -2
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js.map +1 -1
- package/dist/components/form/fields/template/TemplateField.d.ts +31 -1
- package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
- package/dist/components/form/fields/template/TemplateField.js +528 -50
- package/dist/components/form/fields/template/TemplateField.js.map +1 -1
- package/dist/components/form/index.d.ts +1 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +1 -0
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/smartEditor/SmartEditor.d.ts.map +1 -1
- package/dist/components/smartEditor/SmartEditor.js +29 -8
- package/dist/components/smartEditor/SmartEditor.js.map +1 -1
- package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts +8 -0
- package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts.map +1 -1
- package/dist/components/smartEditor/__fixtures__/mockLspServer.js +53 -10
- package/dist/components/smartEditor/__fixtures__/mockLspServer.js.map +1 -1
- package/dist/components/smartEditor/useLspSession.d.ts +5 -1
- package/dist/components/smartEditor/useLspSession.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspSession.js +16 -2
- package/dist/components/smartEditor/useLspSession.js.map +1 -1
- package/dist/helpers/dpqlDetection.d.ts +58 -0
- package/dist/helpers/dpqlDetection.d.ts.map +1 -0
- package/dist/helpers/dpqlDetection.js +164 -0
- package/dist/helpers/dpqlDetection.js.map +1 -0
- package/dist/helpers/optionUiTypes.d.ts +3 -3
- package/dist/helpers/options.d.ts +37 -0
- package/dist/helpers/options.d.ts.map +1 -1
- package/dist/helpers/options.js +78 -1
- package/dist/helpers/options.js.map +1 -1
- package/dist/helpers/templateItems.d.ts +47 -0
- package/dist/helpers/templateItems.d.ts.map +1 -0
- package/dist/helpers/templateItems.js +88 -0
- package/dist/helpers/templateItems.js.map +1 -0
- package/dist/helpers/templateText.d.ts +37 -0
- package/dist/helpers/templateText.d.ts.map +1 -0
- package/dist/helpers/templateText.js +64 -0
- package/dist/helpers/templateText.js.map +1 -0
- package/dist/helpers/templates.d.ts +19 -11
- package/dist/helpers/templates.d.ts.map +1 -1
- package/dist/helpers/templates.js +46 -29
- package/dist/helpers/templates.js.map +1 -1
- package/dist/helpers/validations.d.ts.map +1 -1
- package/dist/helpers/validations.js +56 -9
- package/dist/helpers/validations.js.map +1 -1
- package/dist/hooks/useArgSchema.d.ts +2 -1
- package/dist/hooks/useArgSchema.d.ts.map +1 -1
- package/dist/hooks/useFetch/useFetch.d.ts +3 -1
- package/dist/hooks/useFetch/useFetch.d.ts.map +1 -1
- package/dist/hooks/useFetch/useFetch.js +47 -9
- package/dist/hooks/useFetch/useFetch.js.map +1 -1
- package/dist/hooks/useTemplates.d.ts +20 -0
- package/dist/hooks/useTemplates.d.ts.map +1 -1
- package/dist/hooks/useTemplates.js +34 -2
- package/dist/hooks/useTemplates.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/stories/storyNetwork.d.ts +36 -0
- package/dist/stories/storyNetwork.d.ts.map +1 -0
- package/dist/stories/storyNetwork.js +82 -0
- package/dist/stories/storyNetwork.js.map +1 -0
- package/dist/utils/fetch.d.ts +151 -1
- package/dist/utils/fetch.d.ts.map +1 -1
- package/dist/utils/fetch.js +256 -44
- package/dist/utils/fetch.js.map +1 -1
- package/dist/utils/lspClient.d.ts +6 -0
- package/dist/utils/lspClient.d.ts.map +1 -1
- package/dist/utils/lspClient.js +62 -11
- package/dist/utils/lspClient.js.map +1 -1
- package/dist/utils/websocket.d.ts +6 -0
- package/dist/utils/websocket.d.ts.map +1 -1
- package/dist/utils/websocket.js +15 -7
- package/dist/utils/websocket.js.map +1 -1
- package/package.json +2 -2
- package/src/components/dpqlEditor/DpqlEditor.stories.tsx +3 -119
- package/src/components/dpqlEditor/DpqlEditor.tsx +5 -2
- package/src/components/dpqlEditor/dpqlHelpers.ts +20 -1
- package/src/components/dpqlEditor/dpqlProbe.ts +165 -0
- package/src/components/dpqlEditor/dpqlTags.ts +13 -0
- package/src/components/dpqlEditor/index.ts +4 -0
- package/src/components/dpqlEditor/types.ts +38 -2
- package/src/components/dpqlEditor/useDpqlProbe.ts +33 -0
- package/src/components/dpqlEditor/useDpqlSession.ts +20 -4
- package/src/components/form/engine/CompactRow.tsx +240 -51
- package/src/components/form/engine/CompactToolbar.tsx +10 -3
- package/src/components/form/engine/FormEngine.stories.tsx +423 -120
- package/src/components/form/engine/FormEngine.tsx +504 -87
- package/src/components/form/engine/FormFieldsSkeleton.tsx +76 -0
- package/src/components/form/engine/OptionFieldMessages.tsx +89 -11
- package/src/components/form/engine/_structuredData/SchemaDataView.tsx +11 -0
- package/src/components/form/engine/compactToolbarContext.ts +1 -1
- package/src/components/form/engine/readFirst.ts +86 -7
- package/src/components/form/engine/rendererTypes.ts +12 -0
- package/src/components/form/engine/rowMenuContext.ts +159 -0
- package/src/components/form/engine/typeChoices.ts +55 -0
- package/src/components/form/expressions/DpqlRendering.tsx +85 -0
- package/src/components/form/expressions/ExpressionField.stories.tsx +826 -48
- package/src/components/form/expressions/ExpressionField.tsx +265 -54
- package/src/components/form/expressions/argumentPresence.ts +200 -0
- package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +20 -4
- package/src/components/form/expressions/builder/argumentLabel.tsx +10 -4
- package/src/components/form/expressions/builder/index.tsx +39 -77
- package/src/components/form/expressions/builder/renderTemplate.tsx +23 -56
- package/src/components/form/expressions/dpqlMockLanguage.ts +565 -0
- package/src/components/form/expressions/dpqlMockLsp.ts +109 -83
- package/src/components/form/expressions/mockExpressions.ts +8 -4
- package/src/components/form/expressions/renderExpressionToText.ts +112 -22
- package/src/components/form/expressions/types.ts +7 -0
- package/src/components/form/expressions/useRenderExpression.ts +43 -127
- package/src/components/form/fields/Field.tsx +3 -2
- package/src/components/form/fields/allowed-values/AllowedValues.tsx +13 -2
- package/src/components/form/fields/auto/AutoFormField.stories.tsx +27 -20
- package/src/components/form/fields/auto/AutoFormField.tsx +33 -9
- package/src/components/form/fields/date/Date.tsx +17 -1
- package/src/components/form/fields/rich-text/RichText.tsx +199 -22
- package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +4 -2
- package/src/components/form/fields/template/TemplateField.stories.tsx +31 -9
- package/src/components/form/fields/template/TemplateField.tsx +714 -122
- package/src/components/form/index.tsx +1 -0
- package/src/components/log/Log.stories.tsx +2 -1
- package/src/components/smartEditor/SmartEditor.tsx +41 -9
- package/src/components/smartEditor/__fixtures__/mockLspServer.ts +52 -3
- package/src/components/smartEditor/useLspSession.ts +21 -3
- package/src/helpers/dpqlDetection.ts +209 -0
- package/src/helpers/options.ts +70 -0
- package/src/helpers/templateItems.ts +81 -0
- package/src/helpers/templateText.ts +92 -0
- package/src/helpers/templates.ts +47 -37
- package/src/helpers/validations.ts +59 -9
- package/src/hooks/useFetch/useFetch.stories.tsx +6 -5
- package/src/hooks/useFetch/useFetch.tsx +53 -7
- package/src/hooks/useStorage/useStorage.stories.tsx +2 -1
- package/src/hooks/useTemplates.ts +41 -0
- package/src/hooks/useWebSocket/useWebsocket.stories.tsx +2 -1
- package/src/index.tsx +14 -1
- package/src/stores/currentUser/currentUser.stories.tsx +2 -1
- package/src/stories/storyNetwork.ts +92 -0
- package/src/utils/fetch.ts +311 -21
- package/src/utils/lspClient.ts +68 -11
- package/src/utils/websocket.ts +20 -9
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
ReqoreTagGroup,
|
|
11
11
|
} from '@qoretechnologies/reqore';
|
|
12
12
|
import { IReqoreDropdownItem } from '@qoretechnologies/reqore/dist/components/Dropdown/list';
|
|
13
|
+
import { RowMenuContext, useRowMenuRegistry } from './rowMenuContext';
|
|
13
14
|
import { IReqorePanelAction } from '@qoretechnologies/reqore/dist/components/Panel';
|
|
14
15
|
import { resolveOptionActions } from './optionActions';
|
|
15
16
|
import {
|
|
@@ -28,8 +29,7 @@ import {
|
|
|
28
29
|
findTemplate,
|
|
29
30
|
getTemplateTagStyle,
|
|
30
31
|
isValueTemplate,
|
|
31
|
-
|
|
32
|
-
splitTemplateTokens,
|
|
32
|
+
templateTooltip,
|
|
33
33
|
TTemplateMeta,
|
|
34
34
|
} from '../../../helpers/templates';
|
|
35
35
|
import { getDefaultValue, richtextToSegments, richtextToString } from '../../../helpers/common';
|
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
findAllowedValueOption,
|
|
65
65
|
formatBytes,
|
|
66
66
|
formatOptionValue,
|
|
67
|
+
getAllowedValueIcon,
|
|
67
68
|
getAllowedValueImage,
|
|
68
69
|
getFileSize,
|
|
69
70
|
getHashEntries,
|
|
@@ -72,8 +73,11 @@ import {
|
|
|
72
73
|
isFixedCompactAllowedValueOption,
|
|
73
74
|
isOptionValueEmpty,
|
|
74
75
|
optionHasImages,
|
|
76
|
+
getExpressionAst,
|
|
75
77
|
} from './readFirst';
|
|
76
78
|
import { StructuredDataView } from './_structuredData/StructuredDataView';
|
|
79
|
+
import { DpqlRendering } from '../expressions/DpqlRendering';
|
|
80
|
+
import { TFieldWithOwnTemplates } from './rendererTypes';
|
|
77
81
|
|
|
78
82
|
/**
|
|
79
83
|
* Does this markdown value have more document in it than one row can show?
|
|
@@ -299,6 +303,39 @@ export const CompactRow = memo(
|
|
|
299
303
|
{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }
|
|
300
304
|
: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
|
|
301
305
|
|
|
306
|
+
/* A row has to SAY when its value is an expression.
|
|
307
|
+
|
|
308
|
+
Reported from the live IDE: an author accepted the *Use as expression*
|
|
309
|
+
offer on one field and not on the other, and the two rows read exactly
|
|
310
|
+
the same - `1 + 2` and `2 + 1`, both plain text - so there was no way
|
|
311
|
+
to tell which had been converted. The assertion then compared the
|
|
312
|
+
string `"1 + 2"` against the number `3` and the author had no way to
|
|
313
|
+
see why.
|
|
314
|
+
|
|
315
|
+
The same Σ the expression editor uses, so the mark means the same thing
|
|
316
|
+
wherever it appears. */
|
|
317
|
+
const withExpressionMarker = (rendered: React.ReactNode): React.ReactNode => {
|
|
318
|
+
if (!(field as { is_expression?: boolean })?.is_expression) {
|
|
319
|
+
return rendered;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return (
|
|
323
|
+
<span style={{ ...wrapStyle, gap: 4 }}>
|
|
324
|
+
<ReqoreIcon
|
|
325
|
+
icon='Functions'
|
|
326
|
+
size='tiny'
|
|
327
|
+
/* A stable hook: reqore renders every icon as a bare
|
|
328
|
+
`.reqore-icon`, so without this there is nothing to select the
|
|
329
|
+
mark by — in a test or in a consumer's stylesheet. */
|
|
330
|
+
className='reqraft-expression-marker'
|
|
331
|
+
style={{ flexShrink: 0, opacity: 0.7 }}
|
|
332
|
+
tooltip='This value is an expression'
|
|
333
|
+
/>
|
|
334
|
+
{rendered}
|
|
335
|
+
</span>
|
|
336
|
+
);
|
|
337
|
+
};
|
|
338
|
+
|
|
302
339
|
if (valueType === 'rgbcolor') {
|
|
303
340
|
const swatch = colorToCss(field?.value);
|
|
304
341
|
return (
|
|
@@ -351,6 +388,52 @@ export const CompactRow = memo(
|
|
|
351
388
|
);
|
|
352
389
|
}
|
|
353
390
|
|
|
391
|
+
// A test's cases read as CHIPS here, the same as the names in the table
|
|
392
|
+
// this row opens (`CasesTable`, qorus-ide). `test-cases` is a
|
|
393
|
+
// renderer-only ui_type, so it reached none of the branches above and
|
|
394
|
+
// fell through to the generic summary, which flattens the array of case
|
|
395
|
+
// hashes to a comma-joined string — "case_1, resolved_expected_values".
|
|
396
|
+
// A case name is an identifier the author types into `$.` references and
|
|
397
|
+
// skip conditions, and a chip is how the rest of the product writes an
|
|
398
|
+
// identifier down; the table already agreed, so the collapsed row was the
|
|
399
|
+
// only surface still printing them as prose.
|
|
400
|
+
//
|
|
401
|
+
// `intent` is a FILL, which is what a tag is — the hazard the other
|
|
402
|
+
// branches warn about is only ever using an intent as a TEXT colour.
|
|
403
|
+
//
|
|
404
|
+
// Falls through to the plain summary unless EVERY entry yields a name: a
|
|
405
|
+
// partly-chipped row would read as though the unnamed cases were missing.
|
|
406
|
+
if (valueType === 'test-cases' && Array.isArray(field?.value)) {
|
|
407
|
+
const caseNames = (field.value as unknown[]).map((item) => {
|
|
408
|
+
const name = (item as { name?: unknown } | null | undefined)?.name;
|
|
409
|
+
return typeof name === 'string' ? name.trim() : '';
|
|
410
|
+
});
|
|
411
|
+
if (caseNames.length > 0 && caseNames.every((name) => name !== '')) {
|
|
412
|
+
return (
|
|
413
|
+
<ReqoreControlGroup
|
|
414
|
+
gapSize='tiny'
|
|
415
|
+
verticalAlign='center'
|
|
416
|
+
// An editable row is ONE line: further chips clip with the row
|
|
417
|
+
// instead of growing it. A read-only row is the only rendering
|
|
418
|
+
// the value gets, so it wraps and shows every case.
|
|
419
|
+
wrap={full}
|
|
420
|
+
style={full ? undefined : { minWidth: 0, overflow: 'hidden' }}
|
|
421
|
+
>
|
|
422
|
+
{caseNames.map((name, index) => (
|
|
423
|
+
<ReqoreTag
|
|
424
|
+
key={`${name}-${index}`}
|
|
425
|
+
className='options-readfirst-case-tag'
|
|
426
|
+
size='small'
|
|
427
|
+
minimal
|
|
428
|
+
intent='info'
|
|
429
|
+
label={name}
|
|
430
|
+
/>
|
|
431
|
+
))}
|
|
432
|
+
</ReqoreControlGroup>
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
354
437
|
// Code-editor read summary: replace the truncated string with a chip
|
|
355
438
|
// showing line count + character count. The actual code renders below
|
|
356
439
|
// the row as a monospace `<pre>` inside a `ReqoreCollapsibleContent` —
|
|
@@ -418,15 +501,40 @@ export const CompactRow = memo(
|
|
|
418
501
|
);
|
|
419
502
|
}
|
|
420
503
|
|
|
504
|
+
// The same, for an option whose mark is an ICON rather than a logo. Only
|
|
505
|
+
// images were drawn here, so a list whose entries are told apart by their
|
|
506
|
+
// icon — every interface kind is a bare word, `Service`, `Job`, `Qog` —
|
|
507
|
+
// showed the mark while choosing and lost it the moment the row went
|
|
508
|
+
// read-only, which is where a reader spends most of their time.
|
|
509
|
+
const allowedIcon = getAllowedValueIcon(field?.value, schema);
|
|
510
|
+
if (allowedIcon) {
|
|
511
|
+
return (
|
|
512
|
+
<span style={wrapStyle}>
|
|
513
|
+
<ReqoreIcon icon={allowedIcon as any} size='16px' style={{ flexShrink: 0 }} />
|
|
514
|
+
<span style={textStyle}>{formatted}</span>
|
|
515
|
+
</span>
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
421
519
|
// Template value ($local:…): the read-only template picker — the SAME chip
|
|
422
520
|
// TemplateField renders when disabled, so a template reads identically here
|
|
423
521
|
// and in the editor (qorus-ide intent scheme: info / qorus purple).
|
|
522
|
+
//
|
|
523
|
+
// A field may also declare templates OF ITS OWN, and a value drawn from
|
|
524
|
+
// that list is just as much a template even when it does not look like
|
|
525
|
+
// `$name:key` — `isValueTemplate` is a guess at the shape of the built-in
|
|
526
|
+
// grammar, and a host's own grammar (a Qorus test's `$.order.id`) fails it.
|
|
527
|
+
// Asking the field's list whether it CONTAINS the value settles it without
|
|
528
|
+
// guessing at syntax, and hands back the entry whose label the chip prints,
|
|
529
|
+
// so a reference reads as the name it was chosen by here as well as in the
|
|
530
|
+
// editor rather than as a raw path.
|
|
531
|
+
const ownTemplates = (schema as TFieldWithOwnTemplates | undefined)?.templates ?? templates;
|
|
424
532
|
if (
|
|
425
533
|
typeof field?.value === 'string' &&
|
|
426
534
|
!(field as { is_expression?: boolean }).is_expression &&
|
|
427
|
-
isValueTemplate(field.value)
|
|
535
|
+
(isValueTemplate(field.value) || !!findTemplate(ownTemplates ?? {}, field.value))
|
|
428
536
|
) {
|
|
429
|
-
return <ReadOnlyTemplateTag value={field.value} templates={
|
|
537
|
+
return <ReadOnlyTemplateTag value={field.value} templates={ownTemplates} size='small' />;
|
|
430
538
|
}
|
|
431
539
|
|
|
432
540
|
// A LIST whose elements are rich-text envelopes is a list of strings, so it
|
|
@@ -465,7 +573,9 @@ export const CompactRow = memo(
|
|
|
465
573
|
style={{ fontSize: 'inherit' }}
|
|
466
574
|
icon='ExchangeDollarLine'
|
|
467
575
|
label={segment.text || segment.value}
|
|
468
|
-
|
|
576
|
+
// The same card the chosen-template chip shows: what the
|
|
577
|
+
// value IS, not the reference that names it.
|
|
578
|
+
tooltip={templateTooltip(templates, segment.value)}
|
|
469
579
|
{...getTemplateTagStyle(
|
|
470
580
|
(templates ? findTemplate(templates, segment.value || '') : undefined)
|
|
471
581
|
?.metadata as TTemplateMeta | undefined
|
|
@@ -480,50 +590,20 @@ export const CompactRow = memo(
|
|
|
480
590
|
}
|
|
481
591
|
}
|
|
482
592
|
|
|
483
|
-
// An expression
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
// Unconditionally: a surface with no catalogue (the Automation Hub
|
|
490
|
-
// template preview never fetches one) still shows the reference's own
|
|
491
|
-
// path, which is the point — a conditional chip is no chip at all
|
|
492
|
-
// exactly where the raw token looks worst.
|
|
593
|
+
// An expression reads as DPQL wherever it is shown without being edited:
|
|
594
|
+
// the same rendering its Explain panel and Preview use — monospace,
|
|
595
|
+
// coloured by the language server, template references as chips — so a
|
|
596
|
+
// collapsed row and the editor it opens never disagree about what the
|
|
597
|
+
// value looks like. See `DpqlRendering`.
|
|
493
598
|
if ((field as { is_expression?: boolean })?.is_expression && formatted) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
: segment
|
|
599
|
+
return withExpressionMarker(
|
|
600
|
+
<span style={{ minWidth: 0, flex: '1 1 auto', ...(full ? {} : { overflow: 'hidden' }) }}>
|
|
601
|
+
<DpqlRendering text={formatted} templates={ownTemplates} />
|
|
602
|
+
</span>
|
|
499
603
|
);
|
|
500
|
-
|
|
501
|
-
if (named.some((segment) => segment.kind === 'token')) {
|
|
502
|
-
return (
|
|
503
|
-
<span style={{ ...wrapStyle, gap: 4, overflow: 'hidden' }}>
|
|
504
|
-
{named.map((segment, index) =>
|
|
505
|
-
segment.kind === 'token' ?
|
|
506
|
-
<ReqoreTag
|
|
507
|
-
key={index}
|
|
508
|
-
size='tiny'
|
|
509
|
-
// Inherit the row's font size so the chip shares a baseline
|
|
510
|
-
// with the text around it — see the richtext branch above.
|
|
511
|
-
style={{ fontSize: 'inherit' }}
|
|
512
|
-
icon='ExchangeDollarLine'
|
|
513
|
-
label={segment.label}
|
|
514
|
-
tooltip={segment.text}
|
|
515
|
-
{...getTemplateTagStyle(segment.item?.metadata as TTemplateMeta | undefined)}
|
|
516
|
-
/>
|
|
517
|
-
: <span key={index} style={{ whiteSpace: full ? 'pre-wrap' : 'pre' }}>
|
|
518
|
-
{segment.text}
|
|
519
|
-
</span>
|
|
520
|
-
)}
|
|
521
|
-
</span>
|
|
522
|
-
);
|
|
523
|
-
}
|
|
524
604
|
}
|
|
525
605
|
|
|
526
|
-
return full ? <span style={textStyle}>{formatted}</span> : formatted;
|
|
606
|
+
return withExpressionMarker(full ? <span style={textStyle}>{formatted}</span> : formatted);
|
|
527
607
|
};
|
|
528
608
|
|
|
529
609
|
const schema = options?.[optionName];
|
|
@@ -627,8 +707,23 @@ export const CompactRow = memo(
|
|
|
627
707
|
const changed = !hidden && !readOnly && hasOptionChanged(optionField?.value, optionName);
|
|
628
708
|
// "Has a value" = set to anything non-empty. Drives the edit-row Clear
|
|
629
709
|
// button and the cluster node's filled state (see `memberSet`).
|
|
710
|
+
/* "Is there anything to clear?" — this predicate has exactly one job, and
|
|
711
|
+
both of its uses are the Clear-value button.
|
|
712
|
+
|
|
713
|
+
An empty list is not a value. `[]` is neither `undefined`, `null` nor `''`,
|
|
714
|
+
so a field whose last item had just been removed went on offering to clear
|
|
715
|
+
it, and the confirmation asked whether to clear nothing. A test's cases
|
|
716
|
+
table is where this shows: delete the last case and a red clear-all sat
|
|
717
|
+
above an empty table, guarding a no-op.
|
|
718
|
+
|
|
719
|
+
Deliberately arrays only. An empty hash is arguable — "present but empty"
|
|
720
|
+
can be a real state for a hash — and nothing has demonstrated the same
|
|
721
|
+
defect there, so widening this predicate would be a guess. */
|
|
630
722
|
const hasValue =
|
|
631
|
-
optionField?.value !== undefined &&
|
|
723
|
+
optionField?.value !== undefined &&
|
|
724
|
+
optionField?.value !== null &&
|
|
725
|
+
optionField?.value !== '' &&
|
|
726
|
+
!(Array.isArray(optionField.value) && optionField.value.length === 0);
|
|
632
727
|
// Required-group membership shows a PERSISTENT chip on every member: amber
|
|
633
728
|
// "One of" while the group is unmet (tap → flash siblings), then a muted-green
|
|
634
729
|
// resolution once satisfied — "Covers" on the field that satisfied it,
|
|
@@ -705,7 +800,7 @@ export const CompactRow = memo(
|
|
|
705
800
|
: (schema?.ui_type as string) || (schema?.type as string)) ?? '';
|
|
706
801
|
// Scalars edit in place inside the row; complex fields (tall or nested
|
|
707
802
|
// editors) still open the expanded card below.
|
|
708
|
-
const
|
|
803
|
+
const inlineEditableNow =
|
|
709
804
|
!readOnly &&
|
|
710
805
|
!schema?.arg_schema &&
|
|
711
806
|
!(operators && size(operators)) &&
|
|
@@ -715,6 +810,43 @@ export const CompactRow = memo(
|
|
|
715
810
|
!optionHasImages(schema) &&
|
|
716
811
|
!COMPACT_COMPLEX_TYPES.has(editType);
|
|
717
812
|
|
|
813
|
+
/* Which of the two editors a row gets is settled when the row OPENS.
|
|
814
|
+
*
|
|
815
|
+
* Every term above reads the VALUE or a schema derived from it, so the
|
|
816
|
+
* answer can change while the author is inside the control — and the two
|
|
817
|
+
* branches are different subtrees, so a changed answer does not restyle
|
|
818
|
+
* the editor, it unmounts one and mounts the other. Everything the old one
|
|
819
|
+
* held goes with it: what was typed, the caret, and any state the editor
|
|
820
|
+
* keeps about how it was entered.
|
|
821
|
+
*
|
|
822
|
+
* `is_expression` is the term that actually fires, and it fires on the one
|
|
823
|
+
* interaction that exists to keep the author where they are: accepting
|
|
824
|
+
* "Use as expression" is the moment the value becomes an expression, and
|
|
825
|
+
* the expression shell opens on its Text view precisely because the author
|
|
826
|
+
* has just written the expression as text. The remount discarded that and
|
|
827
|
+
* dropped them into the visual builder, so the sentence they had typed was
|
|
828
|
+
* nowhere on screen. Clicking Text then appeared to work and bounced back,
|
|
829
|
+
* because the next value change remounted the row again.
|
|
830
|
+
*
|
|
831
|
+
* So the row keeps the editor it opened with for as long as it is open,
|
|
832
|
+
* and asks the question again when it is next opened — the same trade
|
|
833
|
+
* `editEntryValue` above makes for a different reason, and the one
|
|
834
|
+
* qorus-ide's `referenceEditorLatch` makes for this exact one. A field that
|
|
835
|
+
* already holds an expression when it is opened still gets the card; it is
|
|
836
|
+
* only a field that BECOMES one under the author that stays put.
|
|
837
|
+
*
|
|
838
|
+
* Held in a ref and settled during render rather than in an effect: an
|
|
839
|
+
* effect lands one render late, and one render late is a visible flash of
|
|
840
|
+
* the wrong editor — which is the thing being fixed.
|
|
841
|
+
*/
|
|
842
|
+
const inlineEditableLatch = React.useRef<boolean | undefined>(undefined);
|
|
843
|
+
if (!isExpanded) {
|
|
844
|
+
inlineEditableLatch.current = undefined;
|
|
845
|
+
} else if (inlineEditableLatch.current === undefined) {
|
|
846
|
+
inlineEditableLatch.current = inlineEditableNow;
|
|
847
|
+
}
|
|
848
|
+
const inlineEditable = isExpanded ? !!inlineEditableLatch.current : inlineEditableNow;
|
|
849
|
+
|
|
718
850
|
// Auto-focus the editor's first input when a field is opened, so you can type
|
|
719
851
|
// straight away (matches the prototype's tap-to-edit feel).
|
|
720
852
|
const editorRef = React.useRef<HTMLDivElement>(null);
|
|
@@ -1061,6 +1193,19 @@ export const CompactRow = memo(
|
|
|
1061
1193
|
// stacks children flush, and the class rule that used to carry a 4px gap
|
|
1062
1194
|
// never reached this element at all — which is why two messages read as one
|
|
1063
1195
|
// two-tone block with no space between them.
|
|
1196
|
+
/* A message is PROSE, so it is drawn by the host's prose renderer.
|
|
1197
|
+
|
|
1198
|
+
`markdownRendererContext` says this package renders markdown "in exactly
|
|
1199
|
+
one place — a field's description". That was one place short: a schema
|
|
1200
|
+
message is written by the same author, in the same dialect, and it landed
|
|
1201
|
+
here as a raw string. A Qorus warning reading "Give that step a **Fixture
|
|
1202
|
+
Output**" showed the asterisks, and every reference inside it stayed a raw
|
|
1203
|
+
`$.` path where the editor two lines above renders it as a named chip.
|
|
1204
|
+
|
|
1205
|
+
`compact` for the same reason the row inset asks for it: this is a strip
|
|
1206
|
+
inside a row, never a page, and markdown authored as a document opens with
|
|
1207
|
+
a heading that would outgrow the field label above it. Without a host
|
|
1208
|
+
renderer the string is drawn as it always was. */
|
|
1064
1209
|
const renderInfoStrip = (m: TInfoMsg, index: number) => (
|
|
1065
1210
|
<ReqoreMessage
|
|
1066
1211
|
key={`${m.content}-${index}`}
|
|
@@ -1071,7 +1216,9 @@ export const CompactRow = memo(
|
|
|
1071
1216
|
title={m.title}
|
|
1072
1217
|
style={{ marginBottom: 8 }}
|
|
1073
1218
|
>
|
|
1074
|
-
{m.content
|
|
1219
|
+
{markdownRenderer && typeof m.content === 'string' ?
|
|
1220
|
+
markdownRenderer({ value: m.content, compact: true })
|
|
1221
|
+
: m.content}
|
|
1075
1222
|
</ReqoreMessage>
|
|
1076
1223
|
);
|
|
1077
1224
|
const reasonColor = (intent?: string) =>
|
|
@@ -1108,6 +1255,9 @@ export const CompactRow = memo(
|
|
|
1108
1255
|
}
|
|
1109
1256
|
: {};
|
|
1110
1257
|
|
|
1258
|
+
// Items the EDITOR inside this row published — see `rowMenuContext`.
|
|
1259
|
+
const { rowMenu, items: editorMenuItems } = useRowMenuRegistry();
|
|
1260
|
+
|
|
1111
1261
|
// Secondary edit actions tuck into a "More" (⋮) menu so the card header stays
|
|
1112
1262
|
// calm: Fullscreen always, plus Remove field for a removable option. Rendered
|
|
1113
1263
|
// just before the Done ✓ in both expanded layouts.
|
|
@@ -1144,6 +1294,10 @@ export const CompactRow = memo(
|
|
|
1144
1294
|
// wholesale on touch) land here — this row already has a menu, so they
|
|
1145
1295
|
// reuse it rather than adding a second one beside it.
|
|
1146
1296
|
...injectedOptionActionMenuItems,
|
|
1297
|
+
// ...and for the same reason, so do the editor's own actions. Without
|
|
1298
|
+
// this an editor with affordances of its own had to draw a second ⋮
|
|
1299
|
+
// inside the value cell, beside this one.
|
|
1300
|
+
...editorMenuItems,
|
|
1147
1301
|
]}
|
|
1148
1302
|
/>
|
|
1149
1303
|
);
|
|
@@ -1316,7 +1470,13 @@ export const CompactRow = memo(
|
|
|
1316
1470
|
editor they belong to — the language you are writing in is
|
|
1317
1471
|
read before the code, not after it. */}
|
|
1318
1472
|
{absorbedNodes}
|
|
1319
|
-
{
|
|
1473
|
+
{/* The editor may publish into THIS row's ⋮ — see `rowMenuContext`.
|
|
1474
|
+
Only the editors rendered in the row are given the channel: the
|
|
1475
|
+
fullscreen modal below has no row menu on screen, so an editor
|
|
1476
|
+
there keeps drawing its own control. */}
|
|
1477
|
+
<RowMenuContext.Provider value={rowMenu}>
|
|
1478
|
+
{renderOption(optionName, optionField, 'small', true)}
|
|
1479
|
+
</RowMenuContext.Provider>
|
|
1320
1480
|
</div>
|
|
1321
1481
|
<StyledRowActions>
|
|
1322
1482
|
{draftChip}
|
|
@@ -1556,7 +1716,9 @@ export const CompactRow = memo(
|
|
|
1556
1716
|
longDescriptionShownByDefault
|
|
1557
1717
|
/>
|
|
1558
1718
|
: null}
|
|
1559
|
-
{
|
|
1719
|
+
<RowMenuContext.Provider value={rowMenu}>
|
|
1720
|
+
{renderOption(optionName, optionField)}
|
|
1721
|
+
</RowMenuContext.Provider>
|
|
1560
1722
|
</FocusedEditing>
|
|
1561
1723
|
</div>
|
|
1562
1724
|
</StyledEditCard>
|
|
@@ -1596,11 +1758,21 @@ export const CompactRow = memo(
|
|
|
1596
1758
|
];
|
|
1597
1759
|
// A hash row reveals its sub-fields as read-only sub-rows under a "view
|
|
1598
1760
|
// more" disclosure; the row itself still expands the real editor on click.
|
|
1761
|
+
/* An EXPRESSION is not a hash, whatever shape it is stored in.
|
|
1762
|
+
|
|
1763
|
+
`{is_expression: true, value: {exp, args}}` is hash-shaped, so a field
|
|
1764
|
+
holding one earned the structured inset and the row printed the syntax
|
|
1765
|
+
tree — `is_expression true / value / exp + / args 1 2` — directly under a
|
|
1766
|
+
summary line that already read `1 + 2`. The AST is how an expression is
|
|
1767
|
+
STORED, not what it is; the row's line is the whole value, and the
|
|
1768
|
+
expression editor is where its parts are looked at. Same exclusion, and
|
|
1769
|
+
for the same reason, as `schema-definition` beside it. */
|
|
1599
1770
|
const hashEntries =
|
|
1600
1771
|
(
|
|
1601
1772
|
!hidden &&
|
|
1602
1773
|
(valueType === 'hash' || valueType === 'free-hash') &&
|
|
1603
|
-
(schema as { ui_type?: string } | undefined)?.ui_type !== 'schema-definition'
|
|
1774
|
+
(schema as { ui_type?: string } | undefined)?.ui_type !== 'schema-definition' &&
|
|
1775
|
+
getExpressionAst(optionField) === undefined
|
|
1604
1776
|
) ?
|
|
1605
1777
|
getHashEntries(optionField, schema)
|
|
1606
1778
|
: [];
|
|
@@ -1647,6 +1819,22 @@ export const CompactRow = memo(
|
|
|
1647
1819
|
valueType === 'richtext' &&
|
|
1648
1820
|
Array.isArray(optionField?.value) &&
|
|
1649
1821
|
richtextToSegments(optionField.value as never).some((segment) => segment.kind === 'tag');
|
|
1822
|
+
/* The same pair, for a value that IS one template rather than prose with
|
|
1823
|
+
templates embedded in it. `showsTemplateChips` above closed the richtext
|
|
1824
|
+
case and left this one open: a chosen reference renders as
|
|
1825
|
+
`ReadOnlyTemplateTag`, which carries its own popover, while the row went
|
|
1826
|
+
on setting a native `title` holding the raw reference. Hovering fired
|
|
1827
|
+
both — two tooltips in two places, and the one that says something useful
|
|
1828
|
+
is not the one a screenshot captures. */
|
|
1829
|
+
const showsTemplateTag =
|
|
1830
|
+
!hidden &&
|
|
1831
|
+
typeof optionField?.value === 'string' &&
|
|
1832
|
+
!(optionField as { is_expression?: boolean } | undefined)?.is_expression &&
|
|
1833
|
+
(isValueTemplate(optionField.value) ||
|
|
1834
|
+
!!findTemplate(
|
|
1835
|
+
(schema as TFieldWithOwnTemplates | undefined)?.templates ?? templates ?? {},
|
|
1836
|
+
optionField.value
|
|
1837
|
+
));
|
|
1650
1838
|
// Markdown reads the same way for the same reason: the row itself can only
|
|
1651
1839
|
// show a line of text, and for markdown that line is the SOURCE — the reader
|
|
1652
1840
|
// gets `## ` and `**` where the point of the value is what it looks like
|
|
@@ -1960,6 +2148,7 @@ export const CompactRow = memo(
|
|
|
1960
2148
|
!showCodePreview &&
|
|
1961
2149
|
!showMarkdownPreview &&
|
|
1962
2150
|
!showsTemplateChips &&
|
|
2151
|
+
!showsTemplateTag &&
|
|
1963
2152
|
typeof formatted === 'string'
|
|
1964
2153
|
) ?
|
|
1965
2154
|
formatted
|
|
@@ -140,7 +140,10 @@ export const CompactToolbar = memo((reqoreProps: Partial<IReqoreControlGroupProp
|
|
|
140
140
|
const cWarning = intents.warning || '#d17c29';
|
|
141
141
|
const cText = (theme.text?.color as string) || '#e8e8e8';
|
|
142
142
|
const cTrack = `${cText}1f`;
|
|
143
|
-
|
|
143
|
+
// The GREEN run is what is done, not merely what has a value: a field that is
|
|
144
|
+
// set but flagged belongs to the amber run, and counting it twice pushed that
|
|
145
|
+
// run off the end of the track.
|
|
146
|
+
const setPct = completion.total ? (completion.done / completion.total) * 100 : 0;
|
|
144
147
|
const attentionPct = completion.total ? (attentionCount / completion.total) * 100 : 0;
|
|
145
148
|
|
|
146
149
|
return (
|
|
@@ -155,10 +158,14 @@ export const CompactToolbar = memo((reqoreProps: Partial<IReqoreControlGroupProp
|
|
|
155
158
|
<StyledCompletionLine>
|
|
156
159
|
<StyledSummary
|
|
157
160
|
className='options-readfirst-status'
|
|
158
|
-
$color={invalidCount ? cWarning : cSuccess}
|
|
161
|
+
$color={invalidCount || attentionCount ? cWarning : cSuccess}
|
|
159
162
|
style={{ fontWeight: 600 }}
|
|
160
163
|
>
|
|
161
|
-
{
|
|
164
|
+
{/* "Ready" is a claim about the whole form, so anything the form
|
|
165
|
+
is asking for withdraws it — a value that fails validation and
|
|
166
|
+
a field the host has flagged alike. Saying Ready beside
|
|
167
|
+
"1 need attention" made the word mean nothing. */}
|
|
168
|
+
{invalidCount || attentionCount ? 'Draft' : 'Ready'}
|
|
162
169
|
</StyledSummary>
|
|
163
170
|
<StyledSummary style={{ opacity: 0.5 }}>
|
|
164
171
|
· {completion.set}/{completion.total} set
|