@qoretechnologies/reqraft 0.10.47-pr.108.gf8e602d → 0.10.47
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/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +81 -34
- 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 +2 -4
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +139 -112
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowStyles.js +5 -2
- package/dist/components/form/engine/compactRowStyles.js.map +1 -1
- package/package.json +1 -1
- package/src/components/form/engine/CompactRow.tsx +140 -63
- package/src/components/form/engine/CompactToolbar.tsx +16 -14
- package/src/components/form/engine/FormEngine.stories.tsx +290 -69
- package/src/components/form/engine/FormEngine.tsx +226 -184
- package/src/components/form/engine/compactRowStyles.ts +32 -0
- package/src/components/form/fields/template/TemplateField.stories.tsx +1 -1
|
@@ -964,9 +964,7 @@ export const CompactRowCancelEdit: Story = {
|
|
|
964
964
|
const row = canvasElement.querySelector<HTMLElement>('[data-field="cookie_name"]');
|
|
965
965
|
expect(row).toBeTruthy();
|
|
966
966
|
fireEvent.click(row!);
|
|
967
|
-
await waitFor(() =>
|
|
968
|
-
expect(canvasElement.querySelector('.readfirst-row-editing')).toBeTruthy()
|
|
969
|
-
);
|
|
967
|
+
await waitFor(() => expect(canvasElement.querySelector('.readfirst-row-editing')).toBeTruthy());
|
|
970
968
|
|
|
971
969
|
// An untouched field offers no Cancel — it would do exactly what Done does.
|
|
972
970
|
expect(canvasElement.querySelector('.options-readfirst-cancel')).toBeNull();
|
|
@@ -1051,9 +1049,7 @@ export const CompactRowAbsorbsLanguage: Story = {
|
|
|
1051
1049
|
|
|
1052
1050
|
// Opening the host renders the language control inside its container.
|
|
1053
1051
|
fireEvent.click(sourceRow as HTMLElement);
|
|
1054
|
-
await waitFor(() =>
|
|
1055
|
-
expect(canvasElement.querySelector('.readfirst-row-editing')).toBeTruthy()
|
|
1056
|
-
);
|
|
1052
|
+
await waitFor(() => expect(canvasElement.querySelector('.readfirst-row-editing')).toBeTruthy());
|
|
1057
1053
|
await waitFor(() =>
|
|
1058
1054
|
expect(canvasElement.querySelector('.options-readfirst-absorbed')).toBeTruthy()
|
|
1059
1055
|
);
|
|
@@ -1078,9 +1074,7 @@ export const CompactRowCancelEditAffordance: Story = {
|
|
|
1078
1074
|
const row = canvasElement.querySelector<HTMLElement>('[data-field="cookie_name"]');
|
|
1079
1075
|
expect(row).toBeTruthy();
|
|
1080
1076
|
fireEvent.click(row!);
|
|
1081
|
-
await waitFor(() =>
|
|
1082
|
-
expect(canvasElement.querySelector('.readfirst-row-editing')).toBeTruthy()
|
|
1083
|
-
);
|
|
1077
|
+
await waitFor(() => expect(canvasElement.querySelector('.readfirst-row-editing')).toBeTruthy());
|
|
1084
1078
|
|
|
1085
1079
|
const input = canvasElement.querySelector<HTMLInputElement>(
|
|
1086
1080
|
'[data-field="cookie_name"] input, [data-field="cookie_name"] textarea'
|
|
@@ -1169,7 +1163,7 @@ export const CompactRowCodeEditorMessage: Story = {
|
|
|
1169
1163
|
docs: {
|
|
1170
1164
|
description: {
|
|
1171
1165
|
story:
|
|
1172
|
-
|
|
1166
|
+
'A schema `messages` entry on a code-editor field. Every other field surfaces its messages on the collapsed row; a code field draws a preview in the same cell, and the message has to survive beside it — a diagnostic the reader only finds by opening the field is not reported. Qorus puts source-validation results here, so an invalid service is called out on the row rather than at save time.',
|
|
1173
1167
|
},
|
|
1174
1168
|
},
|
|
1175
1169
|
},
|
|
@@ -1268,7 +1262,7 @@ export const CompactRowMessageWhileEditing: Story = {
|
|
|
1268
1262
|
docs: {
|
|
1269
1263
|
description: {
|
|
1270
1264
|
story:
|
|
1271
|
-
|
|
1265
|
+
'The same message, with the row OPEN. A schema message is guidance about the value, so the moment it matters most is while the value is being edited — and a validation diagnostic is useless anywhere else: it names a line the author can only fix with the editor in front of them. Qorus opens the Source Code row on arrival, so a message that only survives on the collapsed row was never seen at all.',
|
|
1272
1266
|
},
|
|
1273
1267
|
},
|
|
1274
1268
|
},
|
|
@@ -1474,7 +1468,7 @@ export const NestedOptionInheritsRenderPropFromAncestorCompact: Story = {
|
|
|
1474
1468
|
docs: {
|
|
1475
1469
|
description: {
|
|
1476
1470
|
story:
|
|
1477
|
-
|
|
1471
|
+
'Renders the NestedOptionInheritsRenderPropFromAncestor schema with compact=true — the compact renderer previews the list-of-hash rows through their arg_schema, naming each method, rather than printing [object Object].',
|
|
1478
1472
|
},
|
|
1479
1473
|
},
|
|
1480
1474
|
},
|
|
@@ -1774,7 +1768,7 @@ export const CompactWithholdsFieldsWithUnmetDependencies: Story = {
|
|
|
1774
1768
|
docs: {
|
|
1775
1769
|
description: {
|
|
1776
1770
|
story:
|
|
1777
|
-
|
|
1771
|
+
'A field whose `depends_on` is not fulfilled is not offered as an addable one. The scheme here is Permissive, so the two cookie-only fields are absent from the Optional box entirely — only the field that depends on nothing is offered. Setting the scheme to Cookie brings them back (and flashes them). Before this, they were listed, and clicking one opened a row that said it was disabled: an affordance leading nowhere.',
|
|
1778
1772
|
},
|
|
1779
1773
|
},
|
|
1780
1774
|
},
|
|
@@ -1821,10 +1815,9 @@ export const CompactWithholdsFieldsWithUnmetDependencies: Story = {
|
|
|
1821
1815
|
// The independent field IS offered — without this the two absences below
|
|
1822
1816
|
// would also be explained by an Optional box that never opened.
|
|
1823
1817
|
await _testsWaitForText('Note');
|
|
1824
|
-
await waitFor(
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
);
|
|
1818
|
+
await waitFor(() => expect(document.querySelector('[data-field="note"]')).toBeTruthy(), {
|
|
1819
|
+
timeout: 10000,
|
|
1820
|
+
});
|
|
1828
1821
|
|
|
1829
1822
|
await waitFor(
|
|
1830
1823
|
() => {
|
|
@@ -2457,7 +2450,7 @@ export const CompactReadOnly: Story = {
|
|
|
2457
2450
|
docs: {
|
|
2458
2451
|
description: {
|
|
2459
2452
|
story:
|
|
2460
|
-
'Renders the Compact fixture with readOnly enabled —
|
|
2453
|
+
'Renders the Compact fixture with readOnly enabled — no completion meter, no Needs attention / Set / Optional boxes and no required asterisks; every set field is one flat list of inert rows: nothing is a button, a click opens nothing, and a value that does not fit its line wraps instead of being cut.',
|
|
2461
2454
|
},
|
|
2462
2455
|
},
|
|
2463
2456
|
chromatic: { disable: true },
|
|
@@ -2468,14 +2461,35 @@ export const CompactReadOnly: Story = {
|
|
|
2468
2461
|
},
|
|
2469
2462
|
play: async () => {
|
|
2470
2463
|
await _testsWaitForText('order-fulfilment');
|
|
2471
|
-
//
|
|
2464
|
+
// Nothing that reports progress: no meter, no Draft/Ready, no boxes.
|
|
2465
|
+
expect(document.querySelector('.options-readfirst-completion')).toBeNull();
|
|
2466
|
+
expect(document.querySelector('.options-readfirst-group')).toBeNull();
|
|
2472
2467
|
await _testsWaitForTextToNotExist('Draft');
|
|
2473
|
-
|
|
2474
|
-
|
|
2468
|
+
await _testsWaitForTextToNotExist('Needs attention');
|
|
2469
|
+
await _testsWaitForTextToNotExist('Optional');
|
|
2470
|
+
// A required field nobody set is listed, unset, with no amber dot.
|
|
2471
|
+
await _testsWaitForText('Description');
|
|
2472
|
+
expect(
|
|
2473
|
+
document.querySelector(
|
|
2474
|
+
'.readfirst-row[data-field="description"] .options-readfirst-statusdot-slot > *'
|
|
2475
|
+
)
|
|
2476
|
+
).toBeNull();
|
|
2477
|
+
// Rows are not controls: no button role, and a click opens nothing — not
|
|
2478
|
+
// an editor, not a view.
|
|
2479
|
+
expect(document.querySelector('.readfirst-row[role="button"]')).toBeNull();
|
|
2475
2480
|
await _testsClickText('order-fulfilment');
|
|
2476
|
-
await
|
|
2477
|
-
await
|
|
2478
|
-
|
|
2481
|
+
await _testsClickText('Python');
|
|
2482
|
+
await sleep(400);
|
|
2483
|
+
expect(
|
|
2484
|
+
document.querySelector(
|
|
2485
|
+
'.options-readfirst-inline, .options-readfirst-card, .options-readfirst-done'
|
|
2486
|
+
)
|
|
2487
|
+
).toBeNull();
|
|
2488
|
+
expect(
|
|
2489
|
+
document.querySelector(
|
|
2490
|
+
'.options-readfirst-read input, .options-readfirst-read textarea, .options-readfirst-read select, .options-readfirst-read [contenteditable]'
|
|
2491
|
+
)
|
|
2492
|
+
).toBeNull();
|
|
2479
2493
|
},
|
|
2480
2494
|
};
|
|
2481
2495
|
|
|
@@ -2658,18 +2672,18 @@ export const CompactBasic: Story = {
|
|
|
2658
2672
|
},
|
|
2659
2673
|
};
|
|
2660
2674
|
|
|
2661
|
-
// Read-only richtext + template
|
|
2662
|
-
//
|
|
2663
|
-
//
|
|
2664
|
-
//
|
|
2665
|
-
// (
|
|
2666
|
-
// show as a readonly richtext or a readonly template picker".
|
|
2675
|
+
// Read-only richtext + template. A read-only form mounts no editing surface at
|
|
2676
|
+
// all: a richtext value reads as its text with its template chips (an earlier
|
|
2677
|
+
// fix had left a Slate instance mounted with contenteditable="false", which is
|
|
2678
|
+
// still an editor wearing a lock), and a field whose value is a template
|
|
2679
|
+
// ($local:…) reads as the resolved-name chip. Regression cover for the review
|
|
2680
|
+
// note "this should show as a readonly richtext or a readonly template picker".
|
|
2667
2681
|
export const CompactReadOnlyRichText: Story = {
|
|
2668
2682
|
parameters: {
|
|
2669
2683
|
docs: {
|
|
2670
2684
|
description: {
|
|
2671
2685
|
story:
|
|
2672
|
-
'Renders the CompactBasic fixture with readOnly enabled —
|
|
2686
|
+
'Renders the CompactBasic fixture with readOnly enabled — the Rich Text row reads as its text with its template chip and mounts no editor, the Template row reads as a chip showing the resolved template name (never the raw $local reference), and clicking either opens nothing.',
|
|
2673
2687
|
},
|
|
2674
2688
|
},
|
|
2675
2689
|
chromatic: { disable: true },
|
|
@@ -2677,45 +2691,243 @@ export const CompactReadOnlyRichText: Story = {
|
|
|
2677
2691
|
args: {
|
|
2678
2692
|
...CompactBasic.args,
|
|
2679
2693
|
readOnly: true,
|
|
2680
|
-
expandMode: 'multi' as const,
|
|
2681
2694
|
},
|
|
2682
2695
|
play: async () => {
|
|
2683
2696
|
await _testsWaitForText('Rich Text option');
|
|
2684
|
-
|
|
2685
|
-
//
|
|
2686
|
-
|
|
2687
|
-
|
|
2697
|
+
// Editor verdicts stay in the editor: the fixture's invalid value and its
|
|
2698
|
+
// dependency-locked field print no "fix this" hint in a read view.
|
|
2699
|
+
await _testsWaitForTextToNotExist('Text value is empty');
|
|
2700
|
+
await _testsWaitForTextToNotExist('dependencies are not fulfilled');
|
|
2701
|
+
|
|
2702
|
+
const row = (name: string) => document.querySelector(`.readfirst-row[data-field="${name}"]`);
|
|
2703
|
+
// Richtext: the text and its chip, no Slate.
|
|
2704
|
+
expect(row('richTextOption')?.textContent).toContain('This is a rich text option');
|
|
2705
|
+
expect(row('richTextOption')?.querySelector('.reqore-tag')?.textContent).toContain(
|
|
2706
|
+
'Richtext Template'
|
|
2707
|
+
);
|
|
2708
|
+
// Template: the resolved-name chip. The raw value is tooltip-only
|
|
2709
|
+
// (portalled, not in the tag), so the visible label is the resolved name.
|
|
2710
|
+
const tag = row('templateOption')?.querySelector('.reqore-tag');
|
|
2711
|
+
expect(tag?.textContent).toContain('Test (local)');
|
|
2712
|
+
expect(tag?.textContent).not.toContain('$local:test');
|
|
2713
|
+
|
|
2714
|
+
// Clicking either opens nothing.
|
|
2688
2715
|
await _testsClickText('Rich Text option');
|
|
2689
|
-
await
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2716
|
+
await _testsClickText('Template option');
|
|
2717
|
+
await sleep(400);
|
|
2718
|
+
expect(
|
|
2719
|
+
document.querySelector(
|
|
2720
|
+
'.options-readfirst-card, .options-readfirst-inline, .options-readfirst-done'
|
|
2721
|
+
)
|
|
2722
|
+
).toBeNull();
|
|
2723
|
+
expect(
|
|
2724
|
+
document.querySelector(
|
|
2725
|
+
'.options-readfirst-read [contenteditable], .options-readfirst-read input, .options-readfirst-read textarea'
|
|
2726
|
+
)
|
|
2727
|
+
).toBeNull();
|
|
2728
|
+
},
|
|
2729
|
+
};
|
|
2730
|
+
|
|
2731
|
+
// Read mode as a fact sheet. Every kind of value the engine can hold, set,
|
|
2732
|
+
// plus one optional field nobody set (`notes`) and one required field nobody
|
|
2733
|
+
// set (`owner`): the first must not appear at all, the second appears unset
|
|
2734
|
+
// with no amber. Every value is drawn in full in the row itself; nothing on
|
|
2735
|
+
// the page is a control.
|
|
2736
|
+
const ReadModeSchema: Record<string, TCompactField> = {
|
|
2737
|
+
id: {
|
|
2738
|
+
type: 'string',
|
|
2739
|
+
ui_type: 'string',
|
|
2740
|
+
display_name: 'ID',
|
|
2741
|
+
short_desc: 'Assigned by Qorus when the schema is created',
|
|
2742
|
+
desc: 'The identifier is allocated by the server and is what every reference to this schema uses. It never changes, even when the schema is renamed.',
|
|
2743
|
+
required: true,
|
|
2744
|
+
preselected: true,
|
|
2745
|
+
readonly: true,
|
|
2746
|
+
group: 'identity',
|
|
2747
|
+
},
|
|
2748
|
+
audience: {
|
|
2749
|
+
type: 'string',
|
|
2750
|
+
ui_type: 'string',
|
|
2751
|
+
display_name: 'Who can call this',
|
|
2752
|
+
short_desc: 'Which callers the gateway admits',
|
|
2753
|
+
required: true,
|
|
2754
|
+
preselected: true,
|
|
2755
|
+
group: 'identity',
|
|
2756
|
+
allowed_values: [
|
|
2757
|
+
{
|
|
2758
|
+
value: { type: 'string', value: 'anyone' },
|
|
2759
|
+
display_name: 'Anyone',
|
|
2760
|
+
short_desc: 'No credentials are checked.',
|
|
2696
2761
|
},
|
|
2697
|
-
{
|
|
2698
|
-
|
|
2762
|
+
{
|
|
2763
|
+
value: { type: 'string', value: 'authenticated' },
|
|
2764
|
+
display_name: 'Authenticated users',
|
|
2765
|
+
desc: 'Callers must present a valid token; the gateway rejects anonymous requests before they reach the handler.',
|
|
2766
|
+
},
|
|
2767
|
+
],
|
|
2768
|
+
},
|
|
2769
|
+
summary: {
|
|
2770
|
+
type: 'string',
|
|
2771
|
+
ui_type: 'long-string',
|
|
2772
|
+
display_name: 'Summary',
|
|
2773
|
+
short_desc: 'What this API is for',
|
|
2774
|
+
preselected: true,
|
|
2775
|
+
group: 'identity',
|
|
2776
|
+
},
|
|
2777
|
+
owner: {
|
|
2778
|
+
type: 'string',
|
|
2779
|
+
ui_type: 'string',
|
|
2780
|
+
display_name: 'Owner',
|
|
2781
|
+
short_desc: 'The team that answers for this API',
|
|
2782
|
+
required: true,
|
|
2783
|
+
preselected: true,
|
|
2784
|
+
group: 'identity',
|
|
2785
|
+
},
|
|
2786
|
+
handler: {
|
|
2787
|
+
type: 'string',
|
|
2788
|
+
ui_type: 'code-editor',
|
|
2789
|
+
display_name: 'Handler',
|
|
2790
|
+
short_desc: 'Runs on every call',
|
|
2791
|
+
preselected: true,
|
|
2792
|
+
group: 'behaviour',
|
|
2793
|
+
},
|
|
2794
|
+
retry: {
|
|
2795
|
+
type: 'hash',
|
|
2796
|
+
ui_type: 'hash',
|
|
2797
|
+
display_name: 'Retry policy',
|
|
2798
|
+
preselected: true,
|
|
2799
|
+
group: 'behaviour',
|
|
2800
|
+
arg_schema: {
|
|
2801
|
+
attempts: { type: 'number', ui_type: 'number', display_name: 'Attempts' },
|
|
2802
|
+
backoff: {
|
|
2803
|
+
type: 'string',
|
|
2804
|
+
ui_type: 'string',
|
|
2805
|
+
display_name: 'Backoff',
|
|
2806
|
+
allowed_values: [
|
|
2807
|
+
{ value: { type: 'string', value: 'exponential' }, display_name: 'Exponential' },
|
|
2808
|
+
{ value: { type: 'string', value: 'fixed' }, display_name: 'Fixed' },
|
|
2809
|
+
],
|
|
2810
|
+
},
|
|
2811
|
+
},
|
|
2812
|
+
},
|
|
2813
|
+
tags: {
|
|
2814
|
+
type: 'list',
|
|
2815
|
+
ui_type: 'list',
|
|
2816
|
+
display_name: 'Tags',
|
|
2817
|
+
preselected: true,
|
|
2818
|
+
group: 'behaviour',
|
|
2819
|
+
},
|
|
2820
|
+
enabled: {
|
|
2821
|
+
type: 'bool',
|
|
2822
|
+
ui_type: 'bool',
|
|
2823
|
+
display_name: 'Enabled',
|
|
2824
|
+
preselected: true,
|
|
2825
|
+
group: 'behaviour',
|
|
2826
|
+
},
|
|
2827
|
+
notes: {
|
|
2828
|
+
type: 'string',
|
|
2829
|
+
ui_type: 'string',
|
|
2830
|
+
display_name: 'Notes',
|
|
2831
|
+
short_desc: 'Free-form notes',
|
|
2832
|
+
group: 'behaviour',
|
|
2833
|
+
},
|
|
2834
|
+
};
|
|
2699
2835
|
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2836
|
+
const ReadModeValue: IOptions = {
|
|
2837
|
+
id: { type: 'string', value: 'api-schema-7f3c' },
|
|
2838
|
+
audience: { type: 'string', value: 'authenticated' },
|
|
2839
|
+
summary: {
|
|
2840
|
+
type: 'string',
|
|
2841
|
+
value:
|
|
2842
|
+
'Customer master data for the storefront: the record of who a customer is, where they are billed and where they are shipped, kept once and read by every channel.\n\nEvery operation is idempotent; clients retry freely. A write carries the revision it was based on, and a stale revision is refused rather than merged, so two channels editing the same customer cannot silently overwrite each other.\n\nResponses are cached at the edge for sixty seconds, so a write is visible to readers within a minute — the "eventually" in eventually consistent is short here, but it is not zero.',
|
|
2843
|
+
},
|
|
2844
|
+
handler: {
|
|
2845
|
+
type: 'string',
|
|
2846
|
+
value:
|
|
2847
|
+
'# Reject calls without a tenant header before they reach the service.\nif (!ctx.headers["x-tenant"]) {\n return { status: 400, body: { error: "tenant required" } };\n}\n\nconst customer = await store.get(ctx.params.id);\nif (!customer) {\n return { status: 404 };\n}\n\nreturn { status: 200, body: customer };',
|
|
2848
|
+
},
|
|
2849
|
+
retry: { type: 'hash', value: { attempts: 3, backoff: 'exponential' } },
|
|
2850
|
+
tags: { type: 'list', value: ['customers', 'public'] },
|
|
2851
|
+
enabled: { type: 'bool', value: true },
|
|
2852
|
+
};
|
|
2853
|
+
|
|
2854
|
+
export const CompactReadOnlyValues: Story = {
|
|
2855
|
+
parameters: {
|
|
2856
|
+
docs: {
|
|
2857
|
+
description: {
|
|
2858
|
+
story:
|
|
2859
|
+
'Read-only as a fact sheet, not a disabled editor: no completion meter, no Needs attention / Set / Optional boxes, no required asterisks; an optional field nobody set is not listed, a required one nobody set reads as unset without the amber; every value is drawn in full in its row — long text wrapped under a Show more cap, the whole code block, every field of the hash, the chosen option with its description — and no row is a control: nothing is a button, and a click opens nothing.',
|
|
2716
2860
|
},
|
|
2717
|
-
|
|
2861
|
+
},
|
|
2862
|
+
chromatic: { disable: true },
|
|
2863
|
+
},
|
|
2864
|
+
args: {
|
|
2865
|
+
compact: true,
|
|
2866
|
+
minColumnWidth: '300px',
|
|
2867
|
+
options: ReadModeSchema,
|
|
2868
|
+
value: ReadModeValue,
|
|
2869
|
+
groups: {
|
|
2870
|
+
identity: { icon: 'IdCardLine', subtitle: 'What this is and who may use it', sort: 0 },
|
|
2871
|
+
behaviour: { icon: 'FlashlightLine', sort: 1 },
|
|
2872
|
+
},
|
|
2873
|
+
readOnly: true,
|
|
2874
|
+
},
|
|
2875
|
+
play: async () => {
|
|
2876
|
+
await _testsWaitForText('api-schema-7f3c');
|
|
2877
|
+
// No progress, no boxes, no offers.
|
|
2878
|
+
expect(document.querySelector('.options-readfirst-completion')).toBeNull();
|
|
2879
|
+
expect(document.querySelector('.options-readfirst-group')).toBeNull();
|
|
2880
|
+
await _testsWaitForTextToNotExist('Needs attention');
|
|
2881
|
+
await _testsWaitForTextToNotExist('Optional');
|
|
2882
|
+
// An optional field nobody set is not listed at all…
|
|
2883
|
+
await _testsWaitForTextToNotExist('Notes');
|
|
2884
|
+
// …a required one nobody set is, as unset, with no amber dot.
|
|
2885
|
+
await _testsWaitForText('Owner');
|
|
2886
|
+
expect(
|
|
2887
|
+
document.querySelector(
|
|
2888
|
+
'.readfirst-row[data-field="owner"] .options-readfirst-statusdot-slot > *'
|
|
2889
|
+
)
|
|
2890
|
+
).toBeNull();
|
|
2891
|
+
|
|
2892
|
+
const row = (name: string) =>
|
|
2893
|
+
document.querySelector(`.readfirst-row[data-field="${name}"]`) as HTMLElement;
|
|
2894
|
+
// A choice reads as the option and what it means — not a select.
|
|
2895
|
+
expect(row('audience').textContent).toContain('Authenticated users');
|
|
2896
|
+
expect(row('audience').textContent).toContain('Callers must present a valid token');
|
|
2897
|
+
// A server-set id reads as the value — no lock, no disabled input.
|
|
2898
|
+
expect(row('id').textContent).toContain('api-schema-7f3c');
|
|
2899
|
+
expect(row('id').querySelector('.options-readfirst-locked')).toBeNull();
|
|
2900
|
+
// Long text is drawn in full under the row, capped by Show more.
|
|
2901
|
+
expect(row('summary').querySelector('.options-readfirst-text')?.textContent).toContain(
|
|
2902
|
+
'but it is not zero.'
|
|
2718
2903
|
);
|
|
2904
|
+
await waitFor(() =>
|
|
2905
|
+
expect(row('summary').querySelector('.options-readfirst-viewmore')).toBeTruthy()
|
|
2906
|
+
);
|
|
2907
|
+
// Code is the whole block.
|
|
2908
|
+
expect(row('handler').querySelector('.options-readfirst-code')?.textContent).toContain(
|
|
2909
|
+
'return { status: 200, body: customer };'
|
|
2910
|
+
);
|
|
2911
|
+
// A hash is every field, by name.
|
|
2912
|
+
expect(row('retry').textContent).toMatch(/Attempts/);
|
|
2913
|
+
expect(row('retry').textContent).toMatch(/Exponential|exponential/);
|
|
2914
|
+
|
|
2915
|
+
// Nothing is a control: no row is a button, a click opens nothing, and
|
|
2916
|
+
// there is no editor anywhere in the list.
|
|
2917
|
+
expect(document.querySelector('.readfirst-row[role="button"]')).toBeNull();
|
|
2918
|
+
await _testsClickText('Who can call this');
|
|
2919
|
+
await _testsClickText('Handler');
|
|
2920
|
+
await sleep(400);
|
|
2921
|
+
expect(
|
|
2922
|
+
document.querySelector(
|
|
2923
|
+
'.options-readfirst-inline, .options-readfirst-card, .options-readfirst-done'
|
|
2924
|
+
)
|
|
2925
|
+
).toBeNull();
|
|
2926
|
+
expect(
|
|
2927
|
+
document.querySelector(
|
|
2928
|
+
'.options-readfirst-read input, .options-readfirst-read textarea, .options-readfirst-read select, .options-readfirst-read [contenteditable]'
|
|
2929
|
+
)
|
|
2930
|
+
).toBeNull();
|
|
2719
2931
|
},
|
|
2720
2932
|
};
|
|
2721
2933
|
|
|
@@ -6297,11 +6509,21 @@ const RichtextMultilineTemplateValue: IOptions = {
|
|
|
6297
6509
|
type: 'paragraph',
|
|
6298
6510
|
children: [
|
|
6299
6511
|
{ text: 'Alert: ' },
|
|
6300
|
-
{
|
|
6512
|
+
{
|
|
6513
|
+
type: 'tag',
|
|
6514
|
+
value: '$fsminput:alert_code',
|
|
6515
|
+
label: 'alert_code',
|
|
6516
|
+
children: [{ text: '' }],
|
|
6517
|
+
},
|
|
6301
6518
|
{ text: '\nSeverity: ' },
|
|
6302
6519
|
{ type: 'tag', value: '$fsminput:severity', label: 'severity', children: [{ text: '' }] },
|
|
6303
6520
|
{ text: '\nRule: ' },
|
|
6304
|
-
{
|
|
6521
|
+
{
|
|
6522
|
+
type: 'tag',
|
|
6523
|
+
value: '$fsminput:rule_name',
|
|
6524
|
+
label: 'rule_name',
|
|
6525
|
+
children: [{ text: '' }],
|
|
6526
|
+
},
|
|
6305
6527
|
],
|
|
6306
6528
|
},
|
|
6307
6529
|
],
|
|
@@ -6329,7 +6551,8 @@ export const CompactReadFirstRichtextMultilineTemplate: Story = {
|
|
|
6329
6551
|
const proseSpans = Array.from(canvasElement.querySelectorAll('span')).filter(
|
|
6330
6552
|
// the collapsed newline leaves the segment with a leading space
|
|
6331
6553
|
(element) =>
|
|
6332
|
-
element.children.length === 0 &&
|
|
6554
|
+
element.children.length === 0 &&
|
|
6555
|
+
/^\s*(Alert|Severity|Rule):/.test(element.textContent || '')
|
|
6333
6556
|
) as HTMLElement[];
|
|
6334
6557
|
await expect(proseSpans.length).toBe(3);
|
|
6335
6558
|
|
|
@@ -6701,9 +6924,7 @@ export const CompactListOfHashReadsInSchemaWordsMobile: Story = {
|
|
|
6701
6924
|
|
|
6702
6925
|
// The narrow branch is actually engaged — otherwise this is the desktop
|
|
6703
6926
|
// story with a border round it, and it would pass while proving nothing.
|
|
6704
|
-
await waitFor(() =>
|
|
6705
|
-
expect(canvasElement.querySelector('.readfirst-narrow')).toBeTruthy()
|
|
6706
|
-
);
|
|
6927
|
+
await waitFor(() => expect(canvasElement.querySelector('.readfirst-narrow')).toBeTruthy());
|
|
6707
6928
|
|
|
6708
6929
|
const preview = await waitFor(() => {
|
|
6709
6930
|
const element = canvasElement.querySelector('.schema-data-view');
|
|
@@ -6908,7 +7129,7 @@ export const CompactChosenCollapsedBoxes: Story = {
|
|
|
6908
7129
|
docs: {
|
|
6909
7130
|
description: {
|
|
6910
7131
|
story:
|
|
6911
|
-
|
|
7132
|
+
"Renders a compact form with `compactCollapsedGroups={['set', 'optional']}` — the Set and Optional boxes start collapsed while Needs attention stays open, and typing a search query forces every box open (a collapsed panel unmounts its content, so a match inside one would be unreachable); clearing the query collapses them again.",
|
|
6912
7133
|
},
|
|
6913
7134
|
},
|
|
6914
7135
|
},
|