From d460edbafc385ed78b612f3ee99d43a325a6e2da Mon Sep 17 00:00:00 2001 From: Hazem Nureldin Date: Mon, 14 Sep 2026 11:41:31 +0100 Subject: [PATCH] feat(forms): support schema-driven template parameter autofill from URL --- .../lib/components/SubmissionForm.tsx | 7 ++- .../lib/utils/workflowRelayUtils.ts | 51 ++++++++++++++++++- .../components/template/SubmissionForm.tsx | 5 +- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/frontend/relay-workflows-lib/lib/components/SubmissionForm.tsx b/frontend/relay-workflows-lib/lib/components/SubmissionForm.tsx index 93c3c4b3e..a41ab4d7a 100644 --- a/frontend/relay-workflows-lib/lib/components/SubmissionForm.tsx +++ b/frontend/relay-workflows-lib/lib/components/SubmissionForm.tsx @@ -52,21 +52,24 @@ const SubmissionForm = ({ workflowId?: string; }) => { const data = useFragment(SubmissionFormFragment, template); + const repositoryUrl = data.repository ?? templateSourceToLink(data.templateSource); const reusedParameterData = useFragment( SubmissionFormParametersFragment, prepopulatedParameters, ); + const [searchParams] = useSearchParams(); + const parametersSchema = data.arguments as JsonSchema; + const autofilledParameters = mergeParameters( reusedParameterData, searchParams, + parametersSchema, ); - const parametersSchema = data.arguments as JsonSchema; - const overriddenKeys = Array.from(new Set(searchParams.keys())).filter( (key) => { return parametersSchema.properties && key in parametersSchema.properties; diff --git a/frontend/relay-workflows-lib/lib/utils/workflowRelayUtils.ts b/frontend/relay-workflows-lib/lib/utils/workflowRelayUtils.ts index 95226850a..8534b7451 100644 --- a/frontend/relay-workflows-lib/lib/utils/workflowRelayUtils.ts +++ b/frontend/relay-workflows-lib/lib/utils/workflowRelayUtils.ts @@ -10,6 +10,7 @@ import { } from "../graphql/__generated__/WorkflowTasksFragment.graphql"; import { JSONObject } from "workflows-lib"; import { SubmissionFormParametersFragment$data } from "../components/__generated__/SubmissionFormParametersFragment.graphql"; +import { JsonSchema } from "@jsonforms/core"; export function updateSearchParamsWithTaskIds( updatedTaskIds: string[], @@ -95,8 +96,56 @@ export function useFetchedTasks( export function mergeParameters( reusedParameterData: SubmissionFormParametersFragment$data | null | undefined, searchParams: URLSearchParams, + parametersSchema?: JsonSchema, ) { - const searchParameterData = Object.fromEntries(searchParams.entries()); + const searchParameterData: JSONObject = {}; + if (!parametersSchema) { + return { + ...reusedParameterData?.parameters, + ...Object.fromEntries(searchParams.entries()), + } as JSONObject; + } + + for (const [key, value] of searchParams.entries()) { + const propertySchema = parametersSchema.properties?.[key]; + + // Ignore URL parameters that do not exist in the template schema. + if (!propertySchema || typeof propertySchema === "boolean") { + continue; + } + + if (propertySchema.type === "array" || propertySchema.type === "object") { + try { + const parsedValue: unknown = JSON.parse(value); + + const hasExpectedType = + (propertySchema.type === "array" && Array.isArray(parsedValue)) || + (propertySchema.type === "object" && + parsedValue !== null && + typeof parsedValue === "object" && + !Array.isArray(parsedValue)); + + if (!hasExpectedType) { + console.warn( + `Ignoring URL parameter "${key}": expected ${propertySchema.type}.`, + ); + continue; + } + + // Argo workflow parameters are passed as strings. + searchParameterData[key] = parsedValue as JSONObject[keyof JSONObject]; + } catch { + console.warn( + `Ignoring URL parameter "${key}": value is not valid JSON.`, + ); + } + + continue; + } + // Preserve existing behaviour for flat parameters. + searchParameterData[key] = value; + } + return { ...reusedParameterData?.parameters, ...searchParameterData, diff --git a/frontend/workflows-lib/lib/components/template/SubmissionForm.tsx b/frontend/workflows-lib/lib/components/template/SubmissionForm.tsx index f1157ecb4..1f29d50bd 100644 --- a/frontend/workflows-lib/lib/components/template/SubmissionForm.tsx +++ b/frontend/workflows-lib/lib/components/template/SubmissionForm.tsx @@ -2,6 +2,7 @@ import { materialCells } from "@jsonforms/material-renderers"; import { JsonSchema, UISchemaElement, createAjv } from "@jsonforms/core"; import { JsonForms } from "@jsonforms/react"; import React, { useState } from "react"; + import { Box, Divider, @@ -44,7 +45,9 @@ const TemplateSubmissionForm: React.FC = ({ const theme = useTheme(); const validator = createAjv({ useDefaults: true, coerceTypes: true }); - const [parameters, setParameters] = useState(prepopulatedParameters ?? {}); + const [parameters, setParameters] = useState( + prepopulatedParameters ?? {}, + ); const [errors, setErrors] = useState([]); const [submitted, setSubmitted] = useState(false);