Skip to content

Commit

Permalink
fix(ui): prefill parameters for workflow submit form. Fixes argoproj#…
Browse files Browse the repository at this point in the history
…1214

Signed-off-by: Sairam Arunachalam <sair.aruna@gmail.com>
  • Loading branch information
sairam91 committed Oct 15, 2024
1 parent 7a33720 commit fc1c45d
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 4 deletions.
33 changes: 33 additions & 0 deletions ui/src/app/shared/get_workflow_params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Method to extract a key from query parameter. The query parameter will be of the following format
* ?parameters[key]=value.
* This method will extract the key from the query parameter.
* @param inputString
* @returns
*/
function extractKey(inputString: string): string | null {
// Use regular expression to match the key within square brackets
const match = inputString.match(/parameters\[(.*?)\]/);

// If a match is found, return the captured key
if (match) {
return match[1];
}

// If no match is found, return null or an empty string
return null; // Or return '';
}

export function getWorkflowParametersFromQuery(): {[key: string]: string} {
const queryParams = new URLSearchParams(location.search);

const parameters: {[key: string]: string} = {};
for (const [key, value] of queryParams.entries()) {
const q = extractKey(key);
if (q) {
parameters[q] = value;
}
}

return parameters;
}
2 changes: 1 addition & 1 deletion ui/src/app/workflows/components/submit-workflow-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const defaultTemplate: Template = {

export function SubmitWorkflowPanel(props: Props) {
const {navigation} = useContext(Context);
const [entrypoint, setEntrypoint] = useState(workflowEntrypoint);
const [entrypoint, setEntrypoint] = useState(props.entrypoint || workflowEntrypoint);
const [parameters, setParameters] = useState<Parameter[]>([]);
const [workflowParameters, setWorkflowParameters] = useState<Parameter[]>(JSON.parse(JSON.stringify(props.workflowParameters)));
const [labels, setLabels] = useState(['submit-from-ui=true']);
Expand Down
48 changes: 46 additions & 2 deletions ui/src/app/workflows/components/workflow-creator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import {Select} from 'argo-ui/src/components/select/select';
import * as React from 'react';
import {useEffect, useState} from 'react';

import {Workflow, WorkflowTemplate} from '../../../models';
import {Parameter, Workflow, WorkflowTemplate} from '../../../models';
import {Button} from '../../shared/components/button';
import {ErrorNotice} from '../../shared/components/error-notice';
import {ExampleManifests} from '../../shared/components/example-manifests';
import {UploadButton} from '../../shared/components/upload-button';
import {getWorkflowParametersFromQuery} from '../../shared/get_workflow_params';
import {exampleWorkflow} from '../../shared/examples';
import {services} from '../../shared/services';
import * as nsUtils from '../../shared/namespaces';
Expand All @@ -21,7 +22,8 @@ export function WorkflowCreator({namespace, onCreate}: {namespace: string; onCre
const [stage, setStage] = useState<Stage>('choose-method');
const [workflow, setWorkflow] = useState<Workflow>();
const [error, setError] = useState<Error>();

const queryParams = new URLSearchParams(location.search);
const template = queryParams.get('template');
useEffect(() => {
services.workflowTemplate
.list(namespace, [])
Expand Down Expand Up @@ -61,6 +63,48 @@ export function WorkflowCreator({namespace, onCreate}: {namespace: string; onCre
}
}, [workflowTemplate]);

useEffect(() => {
if (template != null && workflowTemplates) {
// Fetch matching template from the list of templates
const workflowTemplate = workflowTemplates.find(tmpl => tmpl.metadata.name === template);
// If we have a matching template set default values.
if (workflowTemplate) {
setWorkflowTemplate(workflowTemplate);

const templatePropertiesInQuery = getWorkflowParametersFromQuery();
// Get the user arguments from the query params
const updatedParams = workflowTemplate.spec.arguments.parameters.map(param => {
const queryValue = templatePropertiesInQuery[param.name];
const p: Parameter = {
name: param.name,
value: queryValue || param.value
};
return p;
});

workflowTemplate.spec.arguments.parameters = updatedParams;

setWorkflow({
metadata: {
generateName: workflowTemplate.metadata.name + '-',
namespace,
labels: {
'workflows.argoproj.io/workflow-template': workflowTemplate.metadata.name,
'submit-from-ui': 'true'
}
},
spec: {
entrypoint: workflowTemplate.spec.entrypoint,
arguments: {
...workflowTemplate.spec.arguments,
parameters: updatedParams
}
}
});
}
}
}, [template, workflowTemplates]);

return (
<>
{stage === 'choose-method' && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {WorkflowsToolbar} from '../workflows-toolbar/workflows-toolbar';
import './workflows-list.scss';
import useTimestamp, {TIMESTAMP_KEYS} from '../../../shared/use-timestamp';
import {TimestampSwitch} from '../../../shared/components/timestamp';
import {getWorkflowParametersFromQuery} from '../../../shared/get_workflow_params';

interface WorkflowListRenderOptions {
paginationLimit: number;
Expand Down Expand Up @@ -135,6 +136,18 @@ export function WorkflowsList({match, location, history}: RouteComponentProps<an
if (pagination.limit) {
params.append('limit', pagination.limit.toString());
}

// Add any workflow parameters to the query
const workflowProperties = getWorkflowParametersFromQuery();
console.log(workflowProperties);
Object.keys(workflowProperties).forEach(key => {
params.append(`parameters[${key}]`, workflowProperties[key]);
});

// Add the sidePanel query parameter if it exists
params.append('sidePanel', getSidePanel());
params.append('template', queryParams.get('template'));

history.push(historyUrl('workflows' + (nsUtils.getManagedNamespace() ? '' : '/{namespace}'), {namespace, extraSearchParams: params}));
}, [namespace, phases.toString(), labels.toString(), pagination.limit, pagination.offset]); // referential equality, so use values, not refs

Expand Down Expand Up @@ -330,7 +343,23 @@ export function WorkflowsList({match, location, history}: RouteComponentProps<an
)}
</div>
</div>
<SlidingPanel isShown={!!getSidePanel()} onClose={() => navigation.goto('.', {sidePanel: null})}>
<SlidingPanel
isShown={!!getSidePanel()}
onClose={() => {
// Remove any lingering query params
const qParams: {[key: string]: string | null} = {
sidePanel: null
};
// Remove any lingering query params
for (const key of queryParams.keys()) {
qParams[key] = null;
}
// Add back the pagination and namespace params.
qParams.limit = pagination.limit.toString();
qParams.offset = pagination.offset || null;
qParams.namespace = namespace;
navigation.goto('.', qParams);
}}>
{getSidePanel() === 'submit-new-workflow' && (
<WorkflowCreator
namespace={nsUtils.getNamespaceWithDefault(namespace)}
Expand Down

0 comments on commit fc1c45d

Please sign in to comment.