Skip to content

Commit e16baff

Browse files
feat(orchestrator-form-react): allow conditional omitFromWorkflowInput (#2245)
1 parent db243d1 commit e16baff

4 files changed

Lines changed: 120 additions & 5 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-orchestrator-form-react': patch
3+
---
4+
5+
Allow `omitFromWorkflowInput` to be conditional using the same expression
6+
format as `ui:hidden` so fields can be omitted based on form data.

workspaces/orchestrator/docs/orchestratorFormWidgets.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,47 @@ Hidden fields (regardless of hiding method):
976976

977977
If all inputs within a multi-step form's step are marked with `ui:hidden` (either statically or dynamically), the entire step will be automatically hidden from the stepper navigation. The step and its hidden fields will still be processed during form submission.
978978

979+
## Omitting Fields from Workflow Input
980+
981+
Use `omitFromWorkflowInput` to exclude fields from the **execution payload** while
982+
keeping them in form state (and therefore still visible in the review step).
983+
984+
The property supports the same formats as `ui:hidden`:
985+
986+
### Static Omit
987+
988+
```json
989+
{
990+
"secret": {
991+
"type": "string",
992+
"title": "Secret",
993+
"omitFromWorkflowInput": true
994+
}
995+
}
996+
```
997+
998+
### Conditional Omit
999+
1000+
```json
1001+
{
1002+
"mode": {
1003+
"type": "string",
1004+
"enum": ["simple", "advanced"]
1005+
},
1006+
"advancedSecret": {
1007+
"type": "string",
1008+
"title": "Advanced Secret",
1009+
"omitFromWorkflowInput": {
1010+
"when": "mode",
1011+
"is": "advanced"
1012+
}
1013+
}
1014+
}
1015+
```
1016+
1017+
Supported condition patterns are identical to `ui:hidden` (e.g., `when/is`,
1018+
`when/isNot`, `when/isEmpty`, `allOf`, `anyOf`).
1019+
9791020
## Customization
9801021

9811022
The recommended approach for introducing customizations or other modifications is to contribute directly to [the library on GitHub](https://github.com/redhat-developer/rhdh-plugins/tree/main/workspaces/orchestrator/plugins/orchestrator-form-widgets).

workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/pruneFormData.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,5 +784,56 @@ describe('pruneFormData', () => {
784784
});
785785
expect(result.step).not.toHaveProperty('secret');
786786
});
787+
788+
it('should remove properties when omitFromWorkflowInput condition matches', () => {
789+
const schema: JSONSchema7 = {
790+
type: 'object',
791+
properties: {
792+
mode: { type: 'string' },
793+
conditional: {
794+
type: 'string',
795+
omitFromWorkflowInput: {
796+
when: 'mode',
797+
is: 'advanced',
798+
},
799+
} as JSONSchema7,
800+
},
801+
};
802+
803+
const formData = {
804+
mode: 'advanced',
805+
conditional: 'omit',
806+
};
807+
808+
const result = omitFromWorkflowInput(formData, schema);
809+
810+
expect(result).toEqual({ mode: 'advanced' });
811+
expect(result).not.toHaveProperty('conditional');
812+
});
813+
814+
it('should keep properties when omitFromWorkflowInput condition does not match', () => {
815+
const schema: JSONSchema7 = {
816+
type: 'object',
817+
properties: {
818+
mode: { type: 'string' },
819+
conditional: {
820+
type: 'string',
821+
omitFromWorkflowInput: {
822+
when: 'mode',
823+
is: 'advanced',
824+
},
825+
} as JSONSchema7,
826+
},
827+
};
828+
829+
const formData = {
830+
mode: 'simple',
831+
conditional: 'keep',
832+
};
833+
834+
const result = omitFromWorkflowInput(formData, schema);
835+
836+
expect(result).toEqual({ mode: 'simple', conditional: 'keep' });
837+
});
787838
});
788839
});

workspaces/orchestrator/plugins/orchestrator-form-react/src/utils/pruneFormData.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ import { JsonObject, JsonValue } from '@backstage/types';
1818

1919
import type { JSONSchema7 } from 'json-schema';
2020

21+
import { HiddenCondition } from '../types/HiddenCondition';
22+
import { evaluateHiddenCondition } from './evaluateHiddenCondition';
23+
2124
type WorkflowInputSchema = JSONSchema7 & {
22-
omitFromWorkflowInput?: boolean;
25+
omitFromWorkflowInput?: HiddenCondition;
2326
};
2427

2528
/**
@@ -44,8 +47,18 @@ function resolveSchema(
4447
return schema;
4548
}
4649

47-
function shouldOmitFromWorkflowInput(schema: JSONSchema7): boolean {
48-
return (schema as WorkflowInputSchema).omitFromWorkflowInput === true;
50+
function shouldOmitFromWorkflowInput(
51+
schema: JSONSchema7,
52+
rootFormData: JsonObject,
53+
): boolean {
54+
const omitFlag = (schema as WorkflowInputSchema).omitFromWorkflowInput;
55+
if (omitFlag === undefined) {
56+
return false;
57+
}
58+
if (typeof omitFlag === 'boolean') {
59+
return omitFlag;
60+
}
61+
return evaluateHiddenCondition(omitFlag, rootFormData);
4962
}
5063

5164
/**
@@ -321,8 +334,10 @@ export function omitFromWorkflowInput(
321334
formData: JsonObject,
322335
schema: JSONSchema7,
323336
rootSchema?: JSONSchema7,
337+
rootFormData?: JsonObject,
324338
): JsonObject {
325339
const root = rootSchema || schema;
340+
const rootData = rootFormData || formData;
326341
const filtered: JsonObject = {};
327342

328343
for (const [key, value] of Object.entries(formData)) {
@@ -335,7 +350,7 @@ export function omitFromWorkflowInput(
335350
}
336351

337352
propSchema = resolveSchema(propSchema as JSONSchema7, root);
338-
if (shouldOmitFromWorkflowInput(propSchema)) {
353+
if (shouldOmitFromWorkflowInput(propSchema, rootData)) {
339354
continue;
340355
}
341356

@@ -349,6 +364,7 @@ export function omitFromWorkflowInput(
349364
value as JsonObject,
350365
propSchema as JSONSchema7,
351366
root,
367+
rootData,
352368
);
353369
continue;
354370
}
@@ -359,7 +375,7 @@ export function omitFromWorkflowInput(
359375
? resolveSchema(propSchema.items as JSONSchema7, root)
360376
: undefined;
361377

362-
if (itemsSchema && shouldOmitFromWorkflowInput(itemsSchema)) {
378+
if (itemsSchema && shouldOmitFromWorkflowInput(itemsSchema, rootData)) {
363379
continue;
364380
}
365381

@@ -374,6 +390,7 @@ export function omitFromWorkflowInput(
374390
item as JsonObject,
375391
itemsSchema as JSONSchema7,
376392
root,
393+
rootData,
377394
);
378395
}
379396
return item as JsonValue;

0 commit comments

Comments
 (0)