@qoretechnologies/reqraft 0.10.36 → 0.10.37-pr.95.g4e65c57
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/dist/components/codeSize/index.d.ts +37 -0
- package/dist/components/codeSize/index.d.ts.map +1 -0
- package/dist/components/codeSize/index.js +87 -0
- package/dist/components/codeSize/index.js.map +1 -0
- package/dist/components/form/engine/CompactRow.d.ts +6 -1
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +259 -19
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts +20 -0
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +137 -24
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts +37 -0
- package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -0
- package/dist/components/form/engine/_structuredData/SchemaDataView.js +307 -0
- package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -0
- package/dist/components/form/engine/compactRowStyles.d.ts +13 -0
- package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowStyles.js +30 -5
- package/dist/components/form/engine/compactRowStyles.js.map +1 -1
- package/dist/components/form/engine/readFirst.d.ts +66 -1
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +175 -5
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/fields/array/ArrayAuto.d.ts.map +1 -1
- package/dist/components/form/fields/array/ArrayAuto.js +51 -21
- package/dist/components/form/fields/array/ArrayAuto.js.map +1 -1
- package/dist/components/form/fields/array/ArrayAutoField.d.ts.map +1 -1
- package/dist/components/form/fields/array/ArrayAutoField.js +42 -25
- package/dist/components/form/fields/array/ArrayAutoField.js.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts +4 -0
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +8 -1
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/dist/helpers/validations.d.ts +14 -0
- package/dist/helpers/validations.d.ts.map +1 -1
- package/dist/helpers/validations.js +58 -3
- package/dist/helpers/validations.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/codeSize/index.tsx +79 -0
- package/src/components/form/engine/CompactRow.tsx +313 -24
- package/src/components/form/engine/FormEngine.stories.tsx +487 -14
- package/src/components/form/engine/FormEngine.tsx +142 -8
- package/src/components/form/engine/_structuredData/SchemaDataView.stories.tsx +129 -0
- package/src/components/form/engine/_structuredData/SchemaDataView.tsx +594 -0
- package/src/components/form/engine/compactRowStyles.ts +44 -2
- package/src/components/form/engine/readFirst.ts +201 -5
- package/src/components/form/fields/array/ArrayAuto.tsx +35 -4
- package/src/components/form/fields/array/ArrayAutoField.stories.tsx +53 -0
- package/src/components/form/fields/array/ArrayAutoField.tsx +22 -4
- package/src/components/form/fields/auto/AutoFormField.tsx +11 -0
- package/src/helpers/validations.ts +59 -2
- package/src/index.tsx +1 -0
|
@@ -12,8 +12,14 @@ import {
|
|
|
12
12
|
import { IReqoreDropdownItem } from '@qoretechnologies/reqore/dist/components/Dropdown/list';
|
|
13
13
|
import { IReqorePanelAction } from '@qoretechnologies/reqore/dist/components/Panel';
|
|
14
14
|
import { resolveOptionActions } from './optionActions';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
IQorusFormField,
|
|
17
|
+
IQorusFormSchema,
|
|
18
|
+
TQorusForm,
|
|
19
|
+
TQorusFormFieldSchema,
|
|
20
|
+
} from '@qoretechnologies/ts-toolkit';
|
|
16
21
|
import flatten from 'lodash/flatten';
|
|
22
|
+
import isEqual from 'lodash/isEqual';
|
|
17
23
|
import size from 'lodash/size';
|
|
18
24
|
import React, { memo } from 'react';
|
|
19
25
|
import { useContextSelector } from 'use-context-selector';
|
|
@@ -26,6 +32,7 @@ import {
|
|
|
26
32
|
} from '../../../helpers/templates';
|
|
27
33
|
import { richtextToSegments } from '../../../helpers/common';
|
|
28
34
|
import { ReadOnlyTemplateTag } from '../fields/template/ReadOnlyTemplateTag';
|
|
35
|
+
import { ReqraftCodeSizeTag } from '../../codeSize';
|
|
29
36
|
import { Description } from '../../Description';
|
|
30
37
|
import { useMarkdownRenderer } from '../../Description/markdownRendererContext';
|
|
31
38
|
import { FocusedEditing } from '../../FocusedEditing';
|
|
@@ -39,6 +46,8 @@ import {
|
|
|
39
46
|
StyledColumn,
|
|
40
47
|
StyledEditCard,
|
|
41
48
|
StyledLabelBlock,
|
|
49
|
+
StyledAbsorbedField,
|
|
50
|
+
StyledAbsorbedLabel,
|
|
42
51
|
StyledLabelDesc,
|
|
43
52
|
StyledRowActions,
|
|
44
53
|
StyledRowInset,
|
|
@@ -47,6 +56,8 @@ import {
|
|
|
47
56
|
StyledStatusDot,
|
|
48
57
|
} from './compactRowStyles';
|
|
49
58
|
import { getShownSchemaMessages, getOptionFieldMessages } from './OptionFieldMessages';
|
|
59
|
+
import { SchemaDataView, canRenderWithSchema } from './_structuredData/SchemaDataView';
|
|
60
|
+
import { query } from '../../../utils/fetch';
|
|
50
61
|
import {
|
|
51
62
|
colorToCss,
|
|
52
63
|
formatBytes,
|
|
@@ -135,10 +146,16 @@ export const CompactRow = memo(
|
|
|
135
146
|
clustered = false,
|
|
136
147
|
clusterFirst = false,
|
|
137
148
|
clusterLast = false,
|
|
149
|
+
absorbedFields,
|
|
138
150
|
}: {
|
|
139
151
|
optionName: string;
|
|
140
152
|
optionField: IQorusFormField;
|
|
141
153
|
hidden?: boolean;
|
|
154
|
+
/** Siblings this row renders inside its own container instead of leaving
|
|
155
|
+
* them a row each — declared by the schema's `absorb_fields`. The pair it
|
|
156
|
+
* exists for is a code editor and its language: one decision, so one
|
|
157
|
+
* element. */
|
|
158
|
+
absorbedFields?: string[];
|
|
142
159
|
// Rendered inside a required-group cluster: leading status node + rail, and no
|
|
143
160
|
// per-row "one of" chip (the cluster header carries it). first/last trim the
|
|
144
161
|
// rail segment so it spans node-to-node, not past the end members.
|
|
@@ -149,6 +166,13 @@ export const CompactRow = memo(
|
|
|
149
166
|
const readOnly = useContextSelector(CompactRowContext, (v) => v.readOnly);
|
|
150
167
|
const commitMode = useContextSelector(CompactRowContext, (v) => v.commitMode);
|
|
151
168
|
const options = useContextSelector(CompactRowContext, (v) => v.options);
|
|
169
|
+
|
|
170
|
+
// An absorbed field keeps its own name — it is a different field, not a
|
|
171
|
+
// property of its host — so the label comes from its schema exactly as it
|
|
172
|
+
// would on its own row.
|
|
173
|
+
const getAbsorbedLabel = (absorbedName: string): string =>
|
|
174
|
+
(options?.[absorbedName] as { display_name?: string } | undefined)?.display_name ||
|
|
175
|
+
absorbedName;
|
|
152
176
|
const codePreviewRenderer = useContextSelector(CompactRowContext, (v) => v.codePreviewRenderer);
|
|
153
177
|
const markdownRenderer = useMarkdownRenderer();
|
|
154
178
|
const operators = useContextSelector(CompactRowContext, (v) => v.operators);
|
|
@@ -288,17 +312,32 @@ export const CompactRow = memo(
|
|
|
288
312
|
// see `showCodePreview` below. Keeps the row height fixed while making
|
|
289
313
|
// multi-line source readable without opening the full editor.
|
|
290
314
|
if (valueType === 'code-editor' && typeof field?.value === 'string') {
|
|
291
|
-
|
|
292
|
-
|
|
315
|
+
// An absorbed sibling has no row of its own, so a COLLAPSED host has to
|
|
316
|
+
// carry its value or it disappears from the form entirely when closed.
|
|
317
|
+
// It reads as a chip beside the size chip — "Qore · 62 lines" — which
|
|
318
|
+
// is the same summary the read-only interface pages already show.
|
|
293
319
|
return (
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
320
|
+
<ReqoreControlGroup gapSize='tiny' verticalAlign='center' wrap>
|
|
321
|
+
{(absorbedFields ?? []).map((absorbedName) => {
|
|
322
|
+
const absorbedValue = (
|
|
323
|
+
availableOptions?.[absorbedName] as IQorusFormField | undefined
|
|
324
|
+
)?.value;
|
|
325
|
+
if (absorbedValue === undefined || absorbedValue === null || absorbedValue === '') {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
return (
|
|
329
|
+
<ReqoreTag
|
|
330
|
+
key={absorbedName}
|
|
331
|
+
className='options-readfirst-absorbed-tag'
|
|
332
|
+
size='small'
|
|
333
|
+
minimal
|
|
334
|
+
label={String(absorbedValue)}
|
|
335
|
+
tooltip={getAbsorbedLabel(absorbedName)}
|
|
336
|
+
/>
|
|
337
|
+
);
|
|
338
|
+
})}
|
|
339
|
+
<ReqraftCodeSizeTag code={field.value} />
|
|
340
|
+
</ReqoreControlGroup>
|
|
302
341
|
);
|
|
303
342
|
}
|
|
304
343
|
|
|
@@ -592,6 +631,110 @@ export const CompactRow = memo(
|
|
|
592
631
|
return () => window.clearTimeout(id);
|
|
593
632
|
}, [isExpanded, optionName, autoFocusNameRef]);
|
|
594
633
|
|
|
634
|
+
// What the field held when it was opened — the baseline Cancel restores.
|
|
635
|
+
//
|
|
636
|
+
// Deliberately NOT `originalValue`, which is the whole form's load-time
|
|
637
|
+
// snapshot. That answers "undo every change ever made to this field", which
|
|
638
|
+
// is a different question from "forget what I just typed"; a Cancel sitting
|
|
639
|
+
// next to Done has to mean the second one, or it silently throws away edits
|
|
640
|
+
// the user made earlier and had already accepted.
|
|
641
|
+
//
|
|
642
|
+
// The dependency list is `isExpanded` alone on purpose: adding the value
|
|
643
|
+
// would re-take the snapshot on every keystroke, leaving nothing to cancel.
|
|
644
|
+
const editEntryValue = React.useRef<{ value: any; type?: string } | undefined>(undefined);
|
|
645
|
+
React.useEffect(() => {
|
|
646
|
+
if (isExpanded) {
|
|
647
|
+
editEntryValue.current = { value: optionField?.value, type: optionField?.type };
|
|
648
|
+
} else {
|
|
649
|
+
editEntryValue.current = undefined;
|
|
650
|
+
}
|
|
651
|
+
}, [isExpanded]);
|
|
652
|
+
|
|
653
|
+
// True while the open editor holds something other than what it opened with.
|
|
654
|
+
const editedSinceOpened =
|
|
655
|
+
isExpanded &&
|
|
656
|
+
!!editEntryValue.current &&
|
|
657
|
+
!isEqual(editEntryValue.current.value, optionField?.value);
|
|
658
|
+
|
|
659
|
+
// Discard whatever was typed since the field was opened and close it. Used
|
|
660
|
+
// by both the Cancel button and Escape, so the two cannot diverge.
|
|
661
|
+
const cancelEdit = React.useCallback(() => {
|
|
662
|
+
const snapshot = editEntryValue.current;
|
|
663
|
+
if (snapshot && !isEqual(snapshot.value, optionField?.value)) {
|
|
664
|
+
handleValueChange(optionName, snapshot.value, snapshot.type);
|
|
665
|
+
}
|
|
666
|
+
toggleExpandedOption(optionName);
|
|
667
|
+
}, [handleValueChange, optionField?.value, optionName, toggleExpandedOption]);
|
|
668
|
+
|
|
669
|
+
// The sub-schema describing this field's value, when it has one. A value the
|
|
670
|
+
// form knows the shape of is previewed THROUGH that shape (see
|
|
671
|
+
// `SchemaDataView`); only genuinely undescribed data falls through to the
|
|
672
|
+
// untyped data tree.
|
|
673
|
+
//
|
|
674
|
+
// The server does NOT inline that sub-schema. `encodeFieldsForUi()` registers
|
|
675
|
+
// it and sends an id string in its place, which the consumer fetches back —
|
|
676
|
+
// exactly what AutoFormField does to build the editor ("Some arg schemas are
|
|
677
|
+
// not provided as objects, but as strings so we need to fetch them"). A
|
|
678
|
+
// preview that understood only the inline object therefore fell through to
|
|
679
|
+
// the untyped tree for every field a real server describes: the schema view
|
|
680
|
+
// worked against hand-written story fixtures and nowhere else.
|
|
681
|
+
//
|
|
682
|
+
// Resolved here rather than beside the preview it feeds: the preview renders
|
|
683
|
+
// below an early return, so a hook placed there would run conditionally.
|
|
684
|
+
const rawArgSchema = (schema as { arg_schema?: IQorusFormSchema | string } | undefined)
|
|
685
|
+
?.arg_schema;
|
|
686
|
+
const argSchemaId = typeof rawArgSchema === 'string' ? rawArgSchema : undefined;
|
|
687
|
+
const [resolvedArgSchema, setResolvedArgSchema] = React.useState<IQorusFormSchema | undefined>(
|
|
688
|
+
undefined
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
// Only worth a request when there is a described value to preview: a row whose
|
|
692
|
+
// value is unset or scalar renders no inset, so fetching its schema would buy
|
|
693
|
+
// a round trip per row and show nothing. `query` caches GETs, so rows sharing
|
|
694
|
+
// an id (every row of one list) cost one request between them.
|
|
695
|
+
const valueLooksStructured =
|
|
696
|
+
!!optionField?.value && typeof optionField.value === 'object';
|
|
697
|
+
|
|
698
|
+
React.useEffect(() => {
|
|
699
|
+
if (!argSchemaId || !valueLooksStructured) {
|
|
700
|
+
return undefined;
|
|
701
|
+
}
|
|
702
|
+
let cancelled = false;
|
|
703
|
+
(async () => {
|
|
704
|
+
const response = await query<IQorusFormSchema>({
|
|
705
|
+
url: `dataprovider/arg_schemas/${argSchemaId}`,
|
|
706
|
+
method: 'GET',
|
|
707
|
+
});
|
|
708
|
+
// A failed fetch is not an error state here: the preview simply stays the
|
|
709
|
+
// untyped tree, which is what it was before the schema view existed.
|
|
710
|
+
if (!cancelled && response.ok) {
|
|
711
|
+
setResolvedArgSchema(response.data as IQorusFormSchema);
|
|
712
|
+
}
|
|
713
|
+
})();
|
|
714
|
+
return () => {
|
|
715
|
+
cancelled = true;
|
|
716
|
+
};
|
|
717
|
+
}, [argSchemaId, valueLooksStructured]);
|
|
718
|
+
|
|
719
|
+
const previewArgSchema =
|
|
720
|
+
argSchemaId ? resolvedArgSchema : (rawArgSchema as IQorusFormSchema | undefined);
|
|
721
|
+
const previewWithSchema = React.useMemo(
|
|
722
|
+
() => canRenderWithSchema(optionField?.value, previewArgSchema),
|
|
723
|
+
[optionField?.value, previewArgSchema]
|
|
724
|
+
);
|
|
725
|
+
|
|
726
|
+
// The form-load revert: back to the value the FORM was loaded with.
|
|
727
|
+
//
|
|
728
|
+
// In an open editor this is offered only when it would do something
|
|
729
|
+
// `cancelEditButton` does not — that is, when the field was already
|
|
730
|
+
// modified BEFORE it was opened, so "undo this edit" and "undo every edit"
|
|
731
|
+
// are different answers. On the usual path (open an untouched field, type,
|
|
732
|
+
// change your mind) the two are identical, and two buttons with the same
|
|
733
|
+
// effect and different names are worse than one.
|
|
734
|
+
//
|
|
735
|
+
// It is unconditional on the READ row, where it renders inline in the
|
|
736
|
+
// status-dot column — there is no edit in progress there to cancel, so the
|
|
737
|
+
// whole-field revert is the only undo that makes sense.
|
|
595
738
|
const revertButton =
|
|
596
739
|
changed ?
|
|
597
740
|
<ReqoreButton
|
|
@@ -673,6 +816,42 @@ export const CompactRow = memo(
|
|
|
673
816
|
/>
|
|
674
817
|
: null;
|
|
675
818
|
const isPassiveCloseAction = fixedAllowedValueOption || readOnly;
|
|
819
|
+
// Cancel — the counterpart to Done, and the answer to "how do I get out of
|
|
820
|
+
// here without keeping this". Done was the only way to leave an open field,
|
|
821
|
+
// so every way out committed: the check, clicking away, and Escape (which
|
|
822
|
+
// closed without discarding, so it committed too, silently).
|
|
823
|
+
//
|
|
824
|
+
// Shown only while there is something to discard. On an untouched field
|
|
825
|
+
// Cancel and Done would do exactly the same thing, and two buttons that
|
|
826
|
+
// differ in name but not in effect are worse than one.
|
|
827
|
+
//
|
|
828
|
+
// Not offered when the close action is passive (read-only, or a fixed
|
|
829
|
+
// choice) — nothing can have been typed, so there is nothing to cancel.
|
|
830
|
+
const cancelEditButton =
|
|
831
|
+
!isPassiveCloseAction && editedSinceOpened ?
|
|
832
|
+
<ReqoreButton
|
|
833
|
+
className='options-readfirst-cancel'
|
|
834
|
+
size='small'
|
|
835
|
+
flat
|
|
836
|
+
fixed
|
|
837
|
+
icon='CloseLine'
|
|
838
|
+
intent='warning'
|
|
839
|
+
// "Cancel edit", not "Cancel": a bare Cancel collides with the one
|
|
840
|
+
// in Reqore's confirmation modal, and this one is specifically about
|
|
841
|
+
// abandoning the edit rather than dismissing a dialog.
|
|
842
|
+
aria-label='Cancel edit'
|
|
843
|
+
tooltip='Cancel edit — discard the changes made since this field was opened'
|
|
844
|
+
onClick={(event: React.MouseEvent) => {
|
|
845
|
+
event.stopPropagation();
|
|
846
|
+
cancelEdit();
|
|
847
|
+
}}
|
|
848
|
+
/>
|
|
849
|
+
: null;
|
|
850
|
+
// See `revertButton` above for why this is conditional in the edit row.
|
|
851
|
+
const openedWithFormLoadValue =
|
|
852
|
+
!editEntryValue.current ||
|
|
853
|
+
isEqual(editEntryValue.current.value, originalValue.current?.[optionName]?.value);
|
|
854
|
+
const editRowRevertButton = openedWithFormLoadValue ? null : revertButton;
|
|
676
855
|
const closeExpandedFieldButton = (
|
|
677
856
|
<ReqoreButton
|
|
678
857
|
className='options-readfirst-done'
|
|
@@ -857,6 +1036,38 @@ export const CompactRow = memo(
|
|
|
857
1036
|
/>
|
|
858
1037
|
);
|
|
859
1038
|
|
|
1039
|
+
// The absorbed siblings' controls, rendered inside this row.
|
|
1040
|
+
//
|
|
1041
|
+
// Each keeps its own label so it is still identifiable — it is a different
|
|
1042
|
+
// field, not a property of this one — but it sits inside this row's
|
|
1043
|
+
// container, above the editor, so the pair reads as the single decision it
|
|
1044
|
+
// is. `renderOption` is the same function the row uses for its own editor,
|
|
1045
|
+
// so an absorbed field renders exactly as it would have on its own row.
|
|
1046
|
+
const absorbedNodes =
|
|
1047
|
+
absorbedFields?.length ?
|
|
1048
|
+
absorbedFields
|
|
1049
|
+
.map((absorbedName) => {
|
|
1050
|
+
const absorbedField = availableOptions?.[absorbedName] as IQorusFormField | undefined;
|
|
1051
|
+
if (!absorbedField) return null;
|
|
1052
|
+
return (
|
|
1053
|
+
<StyledAbsorbedField key={absorbedName} className='options-readfirst-absorbed'>
|
|
1054
|
+
<StyledAbsorbedLabel size='small' effect={{ opacity: 0.6 }}>
|
|
1055
|
+
{getAbsorbedLabel(absorbedName)}
|
|
1056
|
+
</StyledAbsorbedLabel>
|
|
1057
|
+
<div style={{ minWidth: 0, flex: 1 }}>
|
|
1058
|
+
{renderOption(absorbedName, absorbedField, 'small', true)}
|
|
1059
|
+
</div>
|
|
1060
|
+
</StyledAbsorbedField>
|
|
1061
|
+
);
|
|
1062
|
+
})
|
|
1063
|
+
.filter(Boolean)
|
|
1064
|
+
: null;
|
|
1065
|
+
|
|
1066
|
+
// Declared here rather than beside the hash rows below: the `isExpanded`
|
|
1067
|
+
// branch returns before that point, and its editor needs to know whether it is
|
|
1068
|
+
// holding code.
|
|
1069
|
+
const valueType = getValueType(optionField, schema);
|
|
1070
|
+
|
|
860
1071
|
if (isExpanded) {
|
|
861
1072
|
if (inlineEditable) {
|
|
862
1073
|
const collapse = () => toggleExpandedOption(optionName);
|
|
@@ -914,10 +1125,35 @@ export const CompactRow = memo(
|
|
|
914
1125
|
onKeyDown={(event) => {
|
|
915
1126
|
if (event.key === 'Escape') {
|
|
916
1127
|
event.stopPropagation();
|
|
917
|
-
collapse()
|
|
1128
|
+
// Escape discards. It used to call `collapse()`, which closed
|
|
1129
|
+
// the field and KEPT whatever had been typed — the one
|
|
1130
|
+
// keystroke every editor treats as "get me out of this
|
|
1131
|
+
// without saving" was the quietest way to commit.
|
|
1132
|
+
cancelEdit();
|
|
918
1133
|
}
|
|
919
1134
|
}}
|
|
920
1135
|
>
|
|
1136
|
+
{/* The size chip survives into the editor.
|
|
1137
|
+
|
|
1138
|
+
Opening a field replaces the whole value cell with its editor, which
|
|
1139
|
+
for every other type is right — the editor shows the value, so a
|
|
1140
|
+
summary of it above would say the same thing twice. Code is the
|
|
1141
|
+
exception: the chip counts lines and characters, which the editor
|
|
1142
|
+
does not show anywhere. Dropping it lost real information AND moved
|
|
1143
|
+
everything under it up by the height of a chip, so the editor
|
|
1144
|
+
appeared to jump as it opened.
|
|
1145
|
+
|
|
1146
|
+
It renders here, at the top of the value cell, which is exactly where
|
|
1147
|
+
it sits on the read row — so the switch moves nothing. */}
|
|
1148
|
+
{/* Absorbed siblings sit at the TOP of the value cell, above the
|
|
1149
|
+
editor they belong to — the language you are writing in is
|
|
1150
|
+
read before the code, not after it. */}
|
|
1151
|
+
{absorbedNodes}
|
|
1152
|
+
{valueType === 'code-editor' && typeof optionField?.value === 'string' ?
|
|
1153
|
+
<div className='options-readfirst-editing-summary'>
|
|
1154
|
+
<ReqraftCodeSizeTag code={optionField.value} />
|
|
1155
|
+
</div>
|
|
1156
|
+
: null}
|
|
921
1157
|
{renderOption(optionName, optionField, 'small', true)}
|
|
922
1158
|
</div>
|
|
923
1159
|
<StyledRowActions>
|
|
@@ -926,7 +1162,8 @@ export const CompactRow = memo(
|
|
|
926
1162
|
OptionFieldMessages strip below already says it — showing
|
|
927
1163
|
both was redundant. The tag stays on READ rows, where no
|
|
928
1164
|
message strip is visible. */}
|
|
929
|
-
{
|
|
1165
|
+
{editRowRevertButton}
|
|
1166
|
+
{cancelEditButton}
|
|
930
1167
|
{clearValueButton}
|
|
931
1168
|
{inlineOptionActions.map((action, index) =>
|
|
932
1169
|
renderInjectedOptionAction(action, index)
|
|
@@ -1113,6 +1350,10 @@ export const CompactRow = memo(
|
|
|
1113
1350
|
{closeExpandedFieldButton}
|
|
1114
1351
|
</ReqoreControlGroup>
|
|
1115
1352
|
</div>
|
|
1353
|
+
{/* Absorbed siblings render in the CARD form of an open field too,
|
|
1354
|
+
not only the inline row — which shape a field opens into depends
|
|
1355
|
+
on its type, and absorbing must not depend on that. */}
|
|
1356
|
+
{absorbedNodes}
|
|
1116
1357
|
{/* Same fullscreen focused-editing affordance as the classic cards —
|
|
1117
1358
|
the modal mounts when this option is focused. */}
|
|
1118
1359
|
<FocusedEditing
|
|
@@ -1146,7 +1387,6 @@ export const CompactRow = memo(
|
|
|
1146
1387
|
];
|
|
1147
1388
|
// A hash row reveals its sub-fields as read-only sub-rows under a "view
|
|
1148
1389
|
// more" disclosure; the row itself still expands the real editor on click.
|
|
1149
|
-
const valueType = getValueType(optionField, schema);
|
|
1150
1390
|
const hashEntries =
|
|
1151
1391
|
(
|
|
1152
1392
|
!hidden &&
|
|
@@ -1452,8 +1692,17 @@ export const CompactRow = memo(
|
|
|
1452
1692
|
copy that used to sit above the document was a second rendering of
|
|
1453
1693
|
the same text with the markers taken out (Qlip review, build #97).
|
|
1454
1694
|
Without a renderer there is no inset, and the prose IS the value —
|
|
1455
|
-
so the line stays, and `renderReadFirstValue` still produces it.
|
|
1456
|
-
|
|
1695
|
+
so the line stays, and `renderReadFirstValue` still produces it.
|
|
1696
|
+
|
|
1697
|
+
A schema-previewed value is the same situation. The summary is a
|
|
1698
|
+
flattened join of the item labels ("Default RBAC, Cookie") sitting
|
|
1699
|
+
directly above a preview that names every one of those items and
|
|
1700
|
+
its fields — the same facts twice, the shorter version first, which
|
|
1701
|
+
reads less like a summary than like a second, disagreeing answer.
|
|
1702
|
+
An UNDESCRIBED value keeps its summary: the data tree beneath it
|
|
1703
|
+
says nothing about what the value MEANS, so the summary is still
|
|
1704
|
+
the only line that does. */}
|
|
1705
|
+
{showMarkdownPreview || previewWithSchema ? null : (
|
|
1457
1706
|
<span className='options-readfirst-valuetext'>
|
|
1458
1707
|
{hidden || empty ? '—' : renderReadFirstValue(optionField, schema, formatted)}
|
|
1459
1708
|
</span>
|
|
@@ -1486,17 +1735,57 @@ export const CompactRow = memo(
|
|
|
1486
1735
|
onClick={(e) => e.stopPropagation()}
|
|
1487
1736
|
>
|
|
1488
1737
|
<ReqoreCollapsibleContent
|
|
1489
|
-
|
|
1738
|
+
// The schema view spends more height per datum than a data tree
|
|
1739
|
+
// does — a labelled row rather than a packed chip — but there is
|
|
1740
|
+
// far less of it to read, so it gets enough room to show a
|
|
1741
|
+
// couple of complete items instead of fading out mid-row. A tree
|
|
1742
|
+
// of unknown depth keeps the tighter cap.
|
|
1743
|
+
maxCollapsedHeight={previewWithSchema ? 140 : 96}
|
|
1490
1744
|
buttonProps={{ className: 'options-readfirst-viewmore' }}
|
|
1491
1745
|
>
|
|
1492
1746
|
<div className='options-readfirst-structured'>
|
|
1493
|
-
|
|
1494
|
-
value
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1747
|
+
{previewWithSchema ?
|
|
1748
|
+
// The form already knows this value's shape, names and
|
|
1749
|
+
// choices, so the preview says it rather than making the
|
|
1750
|
+
// reader decode it: "Scheme Type — Default RBAC", not a data
|
|
1751
|
+
// tree announcing "Object · 1 field" over `type: default`.
|
|
1752
|
+
<SchemaDataView
|
|
1753
|
+
value={optionField?.value}
|
|
1754
|
+
schema={previewArgSchema!}
|
|
1755
|
+
showTypes={showFieldTypes}
|
|
1756
|
+
colors={{
|
|
1757
|
+
key: cKey,
|
|
1758
|
+
muted: cMuted,
|
|
1759
|
+
// Deliberately stronger than `cDivider`. That tier is for
|
|
1760
|
+
// decorative hairlines between rows, where being nearly
|
|
1761
|
+
// invisible is the point. This rule is load-bearing — it
|
|
1762
|
+
// is the only thing saying which fields belong to which
|
|
1763
|
+
// numbered item — so it gets the muted tier at partial
|
|
1764
|
+
// alpha: quiet, but actually visible.
|
|
1765
|
+
border: `${cMuted}66`,
|
|
1766
|
+
// The identity accent for each item's heading.
|
|
1767
|
+
//
|
|
1768
|
+
// `custom1` first: BRAND_DESIGN §1 says apps may register
|
|
1769
|
+
// their own named intents and reference them like the
|
|
1770
|
+
// built-ins, and that is where a product's own accent
|
|
1771
|
+
// lives (qorus-ide registers its brand purple there).
|
|
1772
|
+
// Falling back to `info` keeps this working for a
|
|
1773
|
+
// consumer that registers nothing — the heading is
|
|
1774
|
+
// accented either way, just in the theme's own colour
|
|
1775
|
+
// rather than one this library picked.
|
|
1776
|
+
accent:
|
|
1777
|
+
(theme?.intents as Record<string, string> | undefined)?.custom1 || cInfo,
|
|
1778
|
+
}}
|
|
1779
|
+
onItemClick={() => activate()}
|
|
1780
|
+
/>
|
|
1781
|
+
: <StructuredDataView
|
|
1782
|
+
value={optionField?.value}
|
|
1783
|
+
collapsibleRoot={false}
|
|
1784
|
+
showTypes={showFieldTypes}
|
|
1785
|
+
defaultExpandDepth={2}
|
|
1786
|
+
onItemClick={() => activate()}
|
|
1787
|
+
/>
|
|
1788
|
+
}
|
|
1500
1789
|
</div>
|
|
1501
1790
|
</ReqoreCollapsibleContent>
|
|
1502
1791
|
</StyledRowInset>
|