Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions workspaces/orchestrator/.changeset/tall-games-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-orchestrator': patch
---

prepopulate Execute Workflow form from URL query params
46 changes: 46 additions & 0 deletions workspaces/orchestrator/docs/user-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,52 @@ Workflows can also be invoked from Backstage software templates using the `orche
- Monitor workflow execution status
- View workflow results and outputs

### Execute Workflow Form Prepopulation

The Execute Workflow page supports prepopulating form fields from URL query parameters. When the workflow schema defines input fields, any query parameter whose name matches a schema property path will be used to prepopulate the corresponding form field.

**Path format**

- For flat schemas, use the property name directly: `?language=English&name=John`
- For nested (multi-step) schemas, use dot notation: `?firstStep.fooTheFirst=test` or `?provideInputs.language=English`
- For fields inside `oneOf` or `anyOf` branches, use the same dot notation: `?mode.alphaValue=test`

**Schema support**

The prepopulation logic supports the full JSON Schema draft-07 spec, including:

- Fields defined via `$ref` in `$defs` or `definitions`
- `oneOf` and `anyOf` — the correct branch is resolved from the provided data
- Array fields — use comma-separated values: `?tags=foo,bar,baz`
- Type coercion for numbers, integers, and booleans

**Schema constraints**

For fields with `enum` constraints in the schema, the query param value must match one of the allowed values. Case-insensitive matching is supported (e.g. `?language=english` maps to `English` when the enum is `['English', 'Spanish']`). Values that do not match any enum option are ignored and will not prepopulate the field.

Query parameters that do not match any schema property path are ignored and will not be merged into the form.

**Reserved parameters**

The following query parameters are reserved for navigation and are not used for form prepopulation:

- `targetEntity` — Used to associate the workflow run with a catalog entity
- `instanceId` — Used when re-running or viewing a specific workflow instance

**Examples**

```
/orchestrator/workflows/yamlgreet/execute?targetEntity=default:component:my-app&language=English&name=alice
```

In this example, `targetEntity` is excluded (reserved), while `language` and `name` prepopulate the form when those fields exist in the workflow schema.

```
/orchestrator/workflows/my-workflow/execute?language=English&mode.alphaValue=prefilled&tags=a,b,c
```

This example prepopulates a flat field (`language`), a nested field inside an `oneOf` branch (`mode.alphaValue`), and an array field (`tags`).

### Entity Integration

- Workflow tabs on entity pages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"@red-hat-developer-hub/backstage-plugin-orchestrator-form-react": "workspace:^",
"axios": "^1.11.0",
"json-schema": "^0.4.0",
"json-schema-library": "^9.0.0",
"lodash": "^4.17.21",
"luxon": "^3.7.2",
"react-use": "^17.4.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
import { getErrorObject } from '../../utils/ErrorUtils';
import { BaseOrchestratorPage } from '../ui/BaseOrchestratorPage';
import MissingSchemaNotice from './MissingSchemaNotice';
import { mergeQueryParamsIntoFormData } from './queryParamsToFormData';
import { getSchemaUpdater } from './schemaUpdater';

export const ExecuteWorkflowPage = () => {
Expand All @@ -67,6 +68,7 @@ export const ExecuteWorkflowPage = () => {
const [isExecuting, setIsExecuting] = useState(false);
const [updateError, setUpdateError] = useState<Error>();
const [instanceId] = useQueryParamState<string>(QUERY_PARAM_INSTANCE_ID);

const navigate = useNavigate();
const instanceLink = useRouteRef(workflowInstanceRouteRef);
const entityInstanceLink = useRouteRef(entityInstanceRouteRef);
Expand Down Expand Up @@ -96,7 +98,13 @@ export const ExecuteWorkflowPage = () => {
[schema],
);

const initialFormData = value?.data ?? {};
const initialFormData = useMemo(() => {
const baseData = value?.data ?? {};
if (!schema) {
return baseData;
}
return mergeQueryParamsIntoFormData(schema, searchParams, baseData);
}, [schema, value?.data, searchParams]);
const {
value: workflowName,
loading: workflowNameLoading,
Expand Down
Loading
Loading