@qoretechnologies/reqraft 0.10.57 → 0.10.58-pr.129.g4b46b32

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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.summarize = exports.buildVariantGroups = void 0;
4
4
  var readFirst_1 = require("../readFirst");
5
5
  var templates_1 = require("../../../../helpers/templates");
6
+ var validations_1 = require("../../../../helpers/validations");
6
7
  // Default (basic-fixture) invalid set — overridable via config.
7
8
  var DEFAULT_INVALID = {
8
9
  optionWithInvalidValue: 'Text value is empty',
@@ -67,8 +68,11 @@ function buildVariantGroups(options, values, config) {
67
68
  var empty = (0, readFirst_1.isOptionValueEmpty)(field === null || field === void 0 ? void 0 : field.value);
68
69
  var ownGroups = (schema === null || schema === void 0 ? void 0 : schema.required_groups) || [];
69
70
  // Member of a one-of group that nobody has satisfied yet.
70
- var inUnmetGroup = ownGroups.some(function (k) { return reqGroups[k] && !reqGroups[k].satisfied; });
71
- var required = !!(schema === null || schema === void 0 ? void 0 : schema.required);
71
+ // A field locked by an unmet `depends_on` does not apply yet, so it is
72
+ // neither required nor part of an unmet group — the engine's rule.
73
+ var locked = !!(schema === null || schema === void 0 ? void 0 : schema.depends_on) && !(0, validations_1.hasAllDependenciesFullfilled)(schema.depends_on, values, options);
74
+ var inUnmetGroup = !locked && ownGroups.some(function (k) { return reqGroups[k] && !reqGroups[k].satisfied; });
75
+ var required = !locked && !!(schema === null || schema === void 0 ? void 0 : schema.required);
72
76
  var status;
73
77
  var reason;
74
78
  if (invalidReasons[name]) {
@@ -99,7 +103,8 @@ function buildVariantGroups(options, values, config) {
99
103
  label: (schema === null || schema === void 0 ? void 0 : schema.display_name) || name,
100
104
  shortDesc: schema === null || schema === void 0 ? void 0 : schema.short_desc,
101
105
  longDesc: schema === null || schema === void 0 ? void 0 : schema.desc,
102
- required: required || ownGroups.length > 0,
106
+ // The asterisk still marks it: it is required once it applies.
107
+ required: !!(schema === null || schema === void 0 ? void 0 : schema.required) || ownGroups.length > 0,
103
108
  readOnly: !!(schema === null || schema === void 0 ? void 0 : schema.readonly),
104
109
  status: status,
105
110
  reason: reason,
@@ -1 +1 @@
1
- {"version":3,"file":"variantModel.js","sourceRoot":"","sources":["../../../../../src/components/form/engine/variants/variantModel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"variantModel.js","sourceRoot":"","sources":["../../../../../src/components/form/engine/variants/variantModel.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqraft",
3
- "version": "0.10.57",
3
+ "version": "0.10.58-pr.129.g4b46b32",
4
4
  "description": "ReQraft is a collection of React components and hooks that are used across Qore Technologies' products made using the ReQore component library from Qore.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -75,7 +75,7 @@ const StyledMeter = styled.div<{
75
75
  background: ${({ $att_c }) => $att_c};
76
76
  }
77
77
  `;
78
- // One shared text size for the whole summary line, so "Draft", "1/6 set" and
78
+ // One shared text size for the whole summary line, so "Incomplete", "1/6 set" and
79
79
  // "N need attention" all read at the same scale (no chips, no size jumps).
80
80
  const StyledSummary = styled.span<{ $color?: string }>`
81
81
  font-size: 13px;
@@ -164,8 +164,13 @@ export const CompactToolbar = memo((reqoreProps: Partial<IReqoreControlGroupProp
164
164
  {/* "Ready" is a claim about the whole form, so anything the form
165
165
  is asking for withdraws it — a value that fails validation and
166
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'}
167
+ "1 need attention" made the word mean nothing.
168
+
169
+ The other state is "Incomplete", not "Draft": it is about
170
+ what the form still lacks, and a form nobody has touched can
171
+ lack things. "Draft" means unsaved changes and belongs to the
172
+ batched mode's per-row chip alone. */}
173
+ {invalidCount || attentionCount ? 'Incomplete' : 'Ready'}
169
174
  </StyledSummary>
170
175
  <StyledSummary style={{ opacity: 0.5 }}>
171
176
  · {completion.set}/{completion.total} set
@@ -2153,6 +2153,114 @@ export const CompactWithholdsFieldsWithUnmetDependencies: Story = {
2153
2153
  },
2154
2154
  };
2155
2155
 
2156
+ /** A check whose kind decides which of the rest apply — the guided check's shape. */
2157
+ const lockedRequiredCheckOptions = {
2158
+ kind: {
2159
+ type: 'string',
2160
+ ui_type: 'string',
2161
+ display_name: 'Kind',
2162
+ short_desc: 'What the check compares',
2163
+ preselected: true,
2164
+ allowed_values: [
2165
+ { value: { type: 'string', value: 'equals' }, display_name: 'Equals' },
2166
+ { value: { type: 'string', value: 'between' }, display_name: 'Between' },
2167
+ { value: { type: 'string', value: 'exists' }, display_name: 'Exists' },
2168
+ ],
2169
+ },
2170
+ expected: {
2171
+ type: 'string',
2172
+ ui_type: 'string',
2173
+ display_name: 'Expected value',
2174
+ short_desc: 'Applies once a kind is picked',
2175
+ required: true,
2176
+ depends_on: ['kind'],
2177
+ },
2178
+ min: {
2179
+ type: 'int',
2180
+ ui_type: 'int',
2181
+ display_name: 'Minimum',
2182
+ short_desc: 'Applies to Between alone',
2183
+ required: true,
2184
+ depends_on: ['kind=between'],
2185
+ },
2186
+ max: {
2187
+ type: 'int',
2188
+ ui_type: 'int',
2189
+ display_name: 'Maximum',
2190
+ short_desc: 'Applies to Between alone',
2191
+ required: true,
2192
+ depends_on: ['kind=between'],
2193
+ },
2194
+ } as IOptionsSchema;
2195
+
2196
+ export const CompactLockedRequiredNeedsNoAttention: Story = {
2197
+ parameters: {
2198
+ docs: {
2199
+ description: {
2200
+ story:
2201
+ 'Renders a check whose Expected value, Minimum and Maximum are required but locked until a kind is picked. A locked field is not listed under "Needs attention": the author can do nothing with it yet. Each stays on the form, locked, among the optional fields, saying what unlocks it. With no kind picked, nothing needs attention and the header reads Ready: the locked fields do not apply yet.',
2202
+ },
2203
+ },
2204
+ },
2205
+ args: {
2206
+ compact: true,
2207
+ minColumnWidth: '300px',
2208
+ options: lockedRequiredCheckOptions,
2209
+ value: {} as IOptions,
2210
+ },
2211
+ play: async () => {
2212
+ await _testsWaitForText('Expected value');
2213
+ await waitFor(
2214
+ () =>
2215
+ expect(
2216
+ document.querySelector(
2217
+ '.readfirst-row[data-field="expected"] .options-readfirst-lock-deps'
2218
+ )
2219
+ ).toBeTruthy(),
2220
+ { timeout: 10000 }
2221
+ );
2222
+ await expect(document.querySelector('[data-field="min"]')).toBeTruthy();
2223
+ await expect(document.querySelector('[data-field="max"]')).toBeTruthy();
2224
+ await _testsWaitForTextToNotExist('Needs attention');
2225
+ // Nothing the author can fill in is missing, so the form is Ready — the
2226
+ // locked fields do not apply until a kind is picked.
2227
+ await _testsWaitForText('Ready');
2228
+ await _testsWaitForTextToNotExist('Incomplete');
2229
+ },
2230
+ };
2231
+
2232
+ export const CompactUnlockedRequiredNeedsAttention: Story = {
2233
+ parameters: {
2234
+ docs: {
2235
+ description: {
2236
+ story:
2237
+ 'Renders the same check with the kind set to Between. Every field that kind unlocks is required and empty, so Expected value, Minimum and Maximum are all listed under "Needs attention" and the header reads Incomplete (never Draft: nothing has been changed).',
2238
+ },
2239
+ },
2240
+ },
2241
+ args: {
2242
+ compact: true,
2243
+ minColumnWidth: '300px',
2244
+ options: lockedRequiredCheckOptions,
2245
+ value: { kind: { type: 'string', value: 'between' } } as IOptions,
2246
+ },
2247
+ play: async () => {
2248
+ await _testsWaitForText('Needs attention');
2249
+ await _testsWaitForText('Incomplete');
2250
+ await _testsWaitForTextToNotExist('Draft');
2251
+ const attention = [...document.querySelectorAll('.options-readfirst-group')].find((group) =>
2252
+ (group.textContent || '').startsWith('Needs attention')
2253
+ );
2254
+ await expect(attention).toBeTruthy();
2255
+ for (const field of ['expected', 'min', 'max']) {
2256
+ await waitFor(
2257
+ () => expect(attention!.querySelector(`[data-field="${field}"]`)).toBeTruthy(),
2258
+ { timeout: 10000 }
2259
+ );
2260
+ }
2261
+ },
2262
+ };
2263
+
2156
2264
  export const CompactConditionalMessage: Story = {
2157
2265
  parameters: {
2158
2266
  docs: {
@@ -2616,6 +2724,21 @@ const _expandOptionalBox = async () => {
2616
2724
  }
2617
2725
  };
2618
2726
 
2727
+ /**
2728
+ * Put one row of the Optional box on screen: open the box, and its "N more
2729
+ * optional fields" fold if the row is behind it. A required field locked by an
2730
+ * unmet dependency waits here rather than under "Needs attention", and a box
2731
+ * that shows its preselected rows folds the rest.
2732
+ */
2733
+ const _revealOptionalRow = async (field: string) => {
2734
+ await _expandOptionalBox();
2735
+ const row = () => document.querySelector(`.readfirst-row[data-field="${field}"]`);
2736
+ if (!row()) {
2737
+ await _testsClickButton({ selector: '.options-readfirst-more' });
2738
+ }
2739
+ await waitFor(() => expect(row()).toBeTruthy(), { timeout: 10000 });
2740
+ };
2741
+
2619
2742
  // CompactSchema plus one optional (non-preselected) field, to exercise the
2620
2743
  // "Fields" menu add / select-all / reset actions.
2621
2744
  const CompactFieldsMenuSchema: Record<string, TCompactField> = {
@@ -2785,9 +2908,10 @@ export const CompactReadOnly: Story = {
2785
2908
  },
2786
2909
  play: async () => {
2787
2910
  await _testsWaitForText('order-fulfilment');
2788
- // Nothing that reports progress: no meter, no Draft/Ready, no boxes.
2911
+ // Nothing that reports progress: no meter, no Incomplete/Ready, no boxes.
2789
2912
  expect(document.querySelector('.options-readfirst-completion')).toBeNull();
2790
2913
  expect(document.querySelector('.options-readfirst-group')).toBeNull();
2914
+ await _testsWaitForTextToNotExist('Incomplete');
2791
2915
  await _testsWaitForTextToNotExist('Draft');
2792
2916
  await _testsWaitForTextToNotExist('Needs attention');
2793
2917
  await _testsWaitForTextToNotExist('Optional');
@@ -2924,9 +3048,10 @@ export const CompactBasic: Story = {
2924
3048
  value: basicFormValue,
2925
3049
  },
2926
3050
  play: async () => {
2927
- // Unresolved required/invalid fields → the header shows the Draft badge
2928
- // (the IDE restyled-hero convention).
2929
- await _testsWaitForText('Draft');
3051
+ // Unresolved required/invalid fields → the header says Incomplete. Never
3052
+ // "Draft": nobody has changed this form, and Draft means unsaved changes.
3053
+ await _testsWaitForText('Incomplete');
3054
+ await _testsWaitForTextToNotExist('Draft');
2930
3055
  // Several asserted/clicked fields (Disabled option, …) are empty optionals in
2931
3056
  // the collapsed Optional box — open it so they're on screen.
2932
3057
  await _expandOptionalBox();
@@ -2955,7 +3080,9 @@ export const CompactBasic: Story = {
2955
3080
  ).toBeFalsy();
2956
3081
 
2957
3082
  // Dependency locks are navigable: the lock's popover lists the blockers
2958
- // with their state; clicking one scrolls to + flashes it.
3083
+ // with their state; clicking one scrolls to + flashes it. The locked row is
3084
+ // required, but locked it needs no attention, so it waits in Optional.
3085
+ await _revealOptionalRow('optionWithShortDescription');
2959
3086
  const depLock = document.querySelector(
2960
3087
  '.readfirst-row[data-field="optionWithShortDescription"] .options-readfirst-lock-deps'
2961
3088
  ) as HTMLElement;
@@ -3612,7 +3739,7 @@ export const CompactSensitive: Story = {
3612
3739
  };
3613
3740
 
3614
3741
  // `rules: ['valid_identifier']` flows from the schema into validation: a bad
3615
- // identifier marks the form invalid (banner + Draft badge).
3742
+ // identifier marks the form invalid (banner + Incomplete status).
3616
3743
  export const CompactValidIdentifierRule: Story = {
3617
3744
  parameters: {
3618
3745
  docs: {
@@ -3641,7 +3768,7 @@ export const CompactValidIdentifierRule: Story = {
3641
3768
  await _testsWaitForText('1-bad-identifier');
3642
3769
  // The rules-driven validation marks the form as needing attention — the
3643
3770
  // dedicated "Needs attention" box (and the header link) signal it.
3644
- await _testsWaitForText('Draft');
3771
+ await _testsWaitForText('Incomplete');
3645
3772
  await _testsWaitForText('Needs attention');
3646
3773
  },
3647
3774
  };
@@ -5801,12 +5928,12 @@ export const CompactRequiredGroups: Story = {
5801
5928
  value: {} as IOptions,
5802
5929
  },
5803
5930
  play: async () => {
5804
- // All three members show the required placeholder + the Draft badge. The two
5931
+ // All three members show the required placeholder + the Incomplete status. The two
5805
5932
  // contiguous members (byHost/byFile in Connection) cluster into a rail, which
5806
5933
  // carries the grouping in place of a chip; only the lone member (byUrl in
5807
5934
  // General) keeps a "One of" chip — so exactly one chip, not three.
5808
5935
  await _testsWaitForTextsCount('—', undefined, 3);
5809
- await _testsWaitForText('Draft');
5936
+ await _testsWaitForText('Incomplete');
5810
5937
  await _testsWaitForTextsCount('One of', undefined, 1);
5811
5938
 
5812
5939
  // The chip is a ReqoreDropdown listing the siblings; selecting one flashes
@@ -5861,7 +5988,7 @@ export const CompactRequiredGroups: Story = {
5861
5988
  await _testsClickButton({ selector: '.options-readfirst-done' });
5862
5989
  await _testsWaitForText('https://example.com');
5863
5990
 
5864
- // One fulfilled member satisfies the group → the badge flips to Ready and the
5991
+ // One fulfilled member satisfies the group → the status flips to Ready and the
5865
5992
  // Once satisfied: the filled member keeps a "Covers" chip; the empty siblings
5866
5993
  // show their "Covered by 'By URL'" note INLINE (not a chip), and no "One of"
5867
5994
  // remains. So exactly one required-group chip stays (the coverer's).
@@ -6468,7 +6595,9 @@ export const CompactShowcase: Story = {
6468
6595
  await expect(document.querySelectorAll('.options-readfirst-info-panel').length).toBeGreaterThan(
6469
6596
  0
6470
6597
  );
6471
- // The unmet-dependency hint surfaces on the dependent field's row.
6598
+ // The unmet-dependency hint surfaces on the dependent field's row — locked,
6599
+ // so in the Optional box rather than under "Needs attention".
6600
+ await _revealOptionalRow('optionWithShortDescription');
6472
6601
  await _testsWaitForText(
6473
6602
  'This field is disabled because some dependencies are not fulfilled: "basicOption"'
6474
6603
  );
@@ -2324,10 +2324,13 @@ const FormEngineImpl = ({
2324
2324
 
2325
2325
  const isOptionValid = useCallback(
2326
2326
  (optionName: string, type: TQorusType, optionValue: any) => {
2327
+ const isEmpty = optionValue === undefined || optionValue === '';
2328
+ // An empty field locked by an unmet `depends_on` does not apply, so it is
2329
+ // not missing — the same rule the read-first status follows.
2327
2330
  if (
2328
- !options?.[optionName]?.required &&
2329
- !options?.[optionName]?.required_groups &&
2330
- (optionValue === undefined || optionValue === '')
2331
+ isEmpty &&
2332
+ ((!options?.[optionName]?.required && !options?.[optionName]?.required_groups) ||
2333
+ dependencyLockedNames.includes(optionName))
2331
2334
  ) {
2332
2335
  return true;
2333
2336
  }
@@ -2342,7 +2345,12 @@ const FormEngineImpl = ({
2342
2345
  isFunction: (availableOptions?.[optionName] as { is_expression?: boolean })?.is_expression,
2343
2346
  } as any);
2344
2347
  },
2345
- [JSON.stringify(options), JSON.stringify(availableOptions), JSON.stringify(localValue.fields)]
2348
+ [
2349
+ JSON.stringify(options),
2350
+ JSON.stringify(availableOptions),
2351
+ JSON.stringify(localValue.fields),
2352
+ dependencyLockedNames,
2353
+ ]
2346
2354
  );
2347
2355
 
2348
2356
  const getValidityData = useCallback((): IFormValidityData => {
@@ -2366,7 +2374,17 @@ const FormEngineImpl = ({
2366
2374
 
2367
2375
  let validation: IValidationResult;
2368
2376
 
2369
- if (!isRequired && !hasRequiredGroups && isEmpty) {
2377
+ /* A required field locked by an unmet `depends_on` does not apply
2378
+ while it is locked: it is not in "Needs attention", and an empty one
2379
+ does not make the form incomplete either. Otherwise a check whose
2380
+ kind is Equals could never be saved, because Minimum — required for
2381
+ Between alone — is empty; and a form whose only gaps are fields
2382
+ nobody can fill in would say Incomplete with nothing to act on. A
2383
+ locked field that still HOLDS a value is validated as before. */
2384
+ if (
2385
+ isEmpty &&
2386
+ ((!isRequired && !hasRequiredGroups) || dependencyLockedNames.includes(optionName))
2387
+ ) {
2370
2388
  validation = { isValid: true, reasons: [] };
2371
2389
  } else {
2372
2390
  validation = validateFieldWithResult(getType(type), optionValue, {
@@ -2404,6 +2422,7 @@ const FormEngineImpl = ({
2404
2422
  JSON.stringify(options),
2405
2423
  JSON.stringify(operators),
2406
2424
  JSON.stringify(localValue.fields),
2425
+ dependencyLockedNames,
2407
2426
  ]);
2408
2427
 
2409
2428
  const validityData = useMemo(() => getValidityData(), [getValidityData]);
@@ -2487,7 +2506,14 @@ const FormEngineImpl = ({
2487
2506
  // sub-form it summarises said 0/3 set.
2488
2507
  const empty = isOptionValueEmpty(value) || isUnsetSchemaHash(value, schema);
2489
2508
  const reqGroups = (schema?.required_groups as string[] | undefined) || [];
2490
- const required = !!(schema?.required || reqGroups.length);
2509
+ // Required only while it applies. A field locked by an unmet `depends_on`
2510
+ // renders disabled with what unlocks it; nothing the author can do to it
2511
+ // is a next step — the next step is the field it depends on, which carries
2512
+ // its own status. Counting it here put a guided check's locked Path /
2513
+ // Minimum / Maximum under "Needs attention" before its kind was even
2514
+ // picked. The moment the dependency holds, it is required again.
2515
+ const required =
2516
+ !dependencyLockedNames.includes(name) && !!(schema?.required || reqGroups.length);
2491
2517
  const covered =
2492
2518
  empty &&
2493
2519
  reqGroups.some((g) => {
@@ -2512,11 +2538,15 @@ const FormEngineImpl = ({
2512
2538
  isOptionValid,
2513
2539
  requiredGroupsInfo,
2514
2540
  schemaMsgIntent,
2541
+ dependencyLockedNames,
2515
2542
  ]
2516
2543
  );
2517
2544
  const getOptionBucket = useCallback(
2518
2545
  (name: string, hidden = false): 'attention' | 'set' | 'optional' => {
2519
- if (!hidden) {
2546
+ // A locked one-of member cannot be the one that satisfies its group, so it
2547
+ // does not travel with the group into "Needs attention"; its own status
2548
+ // (not required while locked) decides its box.
2549
+ if (!hidden && !dependencyLockedNames.includes(name)) {
2520
2550
  const reqGroups = (options?.[name]?.required_groups as string[] | undefined) || [];
2521
2551
  if (reqGroups.length) {
2522
2552
  return reqGroups.some((g) => !requiredGroupsInfo.satisfiedBy[g]) ? 'attention' : 'set';
@@ -2524,7 +2554,7 @@ const FormEngineImpl = ({
2524
2554
  }
2525
2555
  return getReadFirstBucket(getOptionStatus(name, hidden));
2526
2556
  },
2527
- [JSON.stringify(options), requiredGroupsInfo, getOptionStatus]
2557
+ [JSON.stringify(options), requiredGroupsInfo, getOptionStatus, dependencyLockedNames]
2528
2558
  );
2529
2559
  // How many fields are in the "Needs attention" box — drives the header link.
2530
2560
  const readFirstAttentionCount = useMemo(
@@ -358,6 +358,9 @@ export const getOptionFieldMessages = ({
358
358
  }: IOptionFieldMessagesProps): IReqoreTagProps[] => {
359
359
  const optionSchema = schema[name];
360
360
  const result: IReqoreTagProps[] = [];
361
+ const locked =
362
+ !!optionSchema?.depends_on &&
363
+ !hasAllDependenciesFullfilled(optionSchema.depends_on, allOptions, schema);
361
364
 
362
365
  if (option.value || option.value === false || option.value === 0 || option.value === null) {
363
366
  /* A concrete type the VALUE carries beats an untyped schema.
@@ -392,7 +395,9 @@ export const getOptionFieldMessages = ({
392
395
  });
393
396
  }
394
397
  } else {
395
- if (optionSchema?.required && !untouched) {
398
+ // A locked field is not asked for: the dependency message below says what
399
+ // unlocks it, and until then there is nothing to fill in.
400
+ if (optionSchema?.required && !untouched && !locked) {
396
401
  result.push({ label: 'This field is required', intent: 'danger' });
397
402
  }
398
403
 
@@ -413,10 +418,7 @@ export const getOptionFieldMessages = ({
413
418
  }
414
419
  }
415
420
 
416
- if (
417
- optionSchema?.depends_on &&
418
- !hasAllDependenciesFullfilled(optionSchema.depends_on, allOptions, schema)
419
- ) {
421
+ if (locked) {
420
422
  const dependsOn = describeDependencies(optionSchema.depends_on, schema);
421
423
 
422
424
  result.push({
@@ -112,7 +112,9 @@ const Meter = ({ form }: { form: TVariantForm }) => {
112
112
  color: (s.attention ? c.warning : c.success) as never,
113
113
  }}
114
114
  >
115
- {s.attention ? 'Draft' : 'Ready'}
115
+ {/* What the form lacks, not whether it has unsaved changes:
116
+ "Draft" is the batched mode's per-row chip alone. */}
117
+ {s.attention ? 'Incomplete' : 'Ready'}
116
118
  </ReqoreP>
117
119
  <span>
118
120
  {s.set} of {s.total} set
@@ -20,6 +20,7 @@ import {
20
20
  isOptionValueEmpty,
21
21
  } from '../readFirst';
22
22
  import { isValueTemplate } from '../../../../helpers/templates';
23
+ import { hasAllDependenciesFullfilled } from '../../../../helpers/validations';
23
24
 
24
25
  export type TVariantStatus =
25
26
  | 'set' // has a valid value
@@ -153,8 +154,13 @@ export function buildVariantGroups(
153
154
  const empty = isOptionValueEmpty(field?.value);
154
155
  const ownGroups: string[] = schema?.required_groups || [];
155
156
  // Member of a one-of group that nobody has satisfied yet.
156
- const inUnmetGroup = ownGroups.some((k) => reqGroups[k] && !reqGroups[k].satisfied);
157
- const required = !!schema?.required;
157
+ // A field locked by an unmet `depends_on` does not apply yet, so it is
158
+ // neither required nor part of an unmet group — the engine's rule.
159
+ const locked =
160
+ !!schema?.depends_on && !hasAllDependenciesFullfilled(schema.depends_on, values, options);
161
+ const inUnmetGroup =
162
+ !locked && ownGroups.some((k) => reqGroups[k] && !reqGroups[k].satisfied);
163
+ const required = !locked && !!schema?.required;
158
164
 
159
165
  let status: TVariantStatus;
160
166
  let reason: string | undefined;
@@ -183,7 +189,8 @@ export function buildVariantGroups(
183
189
  label: (schema?.display_name as string) || name,
184
190
  shortDesc: schema?.short_desc,
185
191
  longDesc: schema?.desc,
186
- required: required || ownGroups.length > 0,
192
+ // The asterisk still marks it: it is required once it applies.
193
+ required: !!schema?.required || ownGroups.length > 0,
187
194
  readOnly: !!schema?.readonly,
188
195
  status,
189
196
  reason,