diff --git a/ui/src/cluster-workflow-templates/cluster-workflow-template-details.tsx b/ui/src/cluster-workflow-templates/cluster-workflow-template-details.tsx
index 9a3b6a96904f..74e7000930de 100644
--- a/ui/src/cluster-workflow-templates/cluster-workflow-template-details.tsx
+++ b/ui/src/cluster-workflow-templates/cluster-workflow-template-details.tsx
@@ -150,6 +150,7 @@ export function ClusterWorkflowTemplateDetails({history, location, match}: Route
entrypoint={template.spec.entrypoint}
templates={template.spec.templates || []}
workflowParameters={template.spec.arguments.parameters || []}
+ history={history}
/>
)}
diff --git a/ui/src/shared/get_workflow_params.test.ts b/ui/src/shared/get_workflow_params.test.ts
new file mode 100644
index 000000000000..e0542d143d2f
--- /dev/null
+++ b/ui/src/shared/get_workflow_params.test.ts
@@ -0,0 +1,38 @@
+import {createBrowserHistory} from 'history';
+
+import {getWorkflowParametersFromQuery} from './get_workflow_params';
+
+describe('get_workflow_params', () => {
+ it('should return an empty object when there are no query parameters', () => {
+ const history = createBrowserHistory();
+ const result = getWorkflowParametersFromQuery(history);
+ expect(result).toEqual({});
+ });
+
+ it('should return the parameters provided in the URL', () => {
+ const history = createBrowserHistory();
+ history.location.search = '?parameters[key1]=value1¶meters[key2]=value2';
+ const result = getWorkflowParametersFromQuery(history);
+ expect(result).toEqual({
+ key1: 'value1',
+ key2: 'value2'
+ });
+ });
+
+ it('should not return any key value pairs which are not in parameters query ', () => {
+ const history = createBrowserHistory();
+ history.location.search = '?retryparameters[key1]=value1&retryparameters[key2]=value2';
+ const result = getWorkflowParametersFromQuery(history);
+ expect(result).toEqual({});
+ });
+
+ it('should only return the parameters provided in the URL', () => {
+ const history = createBrowserHistory();
+ history.location.search = '?parameters[key1]=value1¶meters[key2]=value2&test=123';
+ const result = getWorkflowParametersFromQuery(history);
+ expect(result).toEqual({
+ key1: 'value1',
+ key2: 'value2'
+ });
+ });
+});
diff --git a/ui/src/shared/get_workflow_params.ts b/ui/src/shared/get_workflow_params.ts
new file mode 100644
index 000000000000..9df9a15325d8
--- /dev/null
+++ b/ui/src/shared/get_workflow_params.ts
@@ -0,0 +1,30 @@
+import {History} from 'history';
+
+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 '';
+}
+/**
+ * Returns the workflow parameters from the query parameters.
+ */
+export function getWorkflowParametersFromQuery(history: History): {[key: string]: string} {
+ const queryParams = new URLSearchParams(history.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;
+}
diff --git a/ui/src/shared/history.ts b/ui/src/shared/history.ts
index 87736e32a28d..3295c08d5c0a 100644
--- a/ui/src/shared/history.ts
+++ b/ui/src/shared/history.ts
@@ -6,8 +6,7 @@ import * as nsUtils from './namespaces';
* Only "truthy" values are put into the query parameters. I.e. "falsey" values include null, undefined, false, "", 0.
*/
export function historyUrl(path: string, params: {[key: string]: any}) {
- const queryParams: string[] = [];
- let extraSearchParams: URLSearchParams;
+ const queryParams = new URLSearchParams();
Object.entries(params)
.filter(([, v]) => v !== null)
.forEach(([k, v]) => {
@@ -15,14 +14,14 @@ export function historyUrl(path: string, params: {[key: string]: any}) {
if (path.includes(searchValue)) {
path = path.replace(searchValue, v != null ? v : '');
} else if (k === 'extraSearchParams') {
- extraSearchParams = v;
+ (v as URLSearchParams).forEach((value, key) => queryParams.set(key, value));
} else if (v) {
- queryParams.push(k + '=' + v);
+ queryParams.set(k, v);
}
if (k === 'namespace') {
nsUtils.setCurrentNamespace(v);
}
});
- const extraString = extraSearchParams ? '&' + extraSearchParams.toString() : '';
- return uiUrl(path.replace(/{[^}]*}/g, '')) + '?' + queryParams.join('&') + extraString;
+
+ return uiUrl(path.replace(/{[^}]*}/g, '')) + '?' + queryParams.toString();
}
diff --git a/ui/src/workflow-templates/workflow-template-details.tsx b/ui/src/workflow-templates/workflow-template-details.tsx
index 8a8d869c3050..782ffa5006ee 100644
--- a/ui/src/workflow-templates/workflow-template-details.tsx
+++ b/ui/src/workflow-templates/workflow-template-details.tsx
@@ -145,6 +145,7 @@ export function WorkflowTemplateDetails({history, location, match}: RouteCompone
entrypoint={template.spec.entrypoint}
templates={template.spec.templates || []}
workflowParameters={template.spec.arguments.parameters || []}
+ history={history}
/>
)}
{sidePanel === 'share' && }
diff --git a/ui/src/workflows/components/submit-workflow-panel.tsx b/ui/src/workflows/components/submit-workflow-panel.tsx
index 8b93d3b53b3e..02a3d8103c85 100644
--- a/ui/src/workflows/components/submit-workflow-panel.tsx
+++ b/ui/src/workflows/components/submit-workflow-panel.tsx
@@ -1,11 +1,13 @@
import {Select} from 'argo-ui/src/components/select/select';
-import React, {useContext, useMemo, useState} from 'react';
+import {History} from 'history';
+import React, {useContext, useEffect, useMemo, useState} from 'react';
import {uiUrl} from '../../shared/base';
import {ErrorNotice} from '../../shared/components/error-notice';
import {getValueFromParameter, ParametersInput} from '../../shared/components/parameters-input';
import {TagsInput} from '../../shared/components/tags-input/tags-input';
import {Context} from '../../shared/context';
+import {getWorkflowParametersFromQuery} from '../../shared/get_workflow_params';
import {Parameter, Template} from '../../shared/models';
import {services} from '../../shared/services';
@@ -16,6 +18,7 @@ interface Props {
entrypoint: string;
templates: Template[];
workflowParameters: Parameter[];
+ history: History;
}
const workflowEntrypoint = '';
@@ -28,13 +31,23 @@ 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([]);
const [workflowParameters, setWorkflowParameters] = useState(JSON.parse(JSON.stringify(props.workflowParameters)));
const [labels, setLabels] = useState(['submit-from-ui=true']);
const [error, setError] = useState();
const [isSubmitting, setIsSubmitting] = useState(false);
+ useEffect(() => {
+ const templatePropertiesInQuery = getWorkflowParametersFromQuery(props.history);
+ // Get the user arguments from the query params
+ const updatedParams = workflowParameters.map(param => ({
+ name: param.name,
+ value: templatePropertiesInQuery[param.name] || param.value
+ }));
+ setWorkflowParameters(updatedParams);
+ }, [props.history, setWorkflowParameters]);
+
const templates = useMemo(() => {
return [defaultTemplate].concat(props.templates);
}, [props.templates]);
diff --git a/ui/src/workflows/components/workflow-creator.tsx b/ui/src/workflows/components/workflow-creator.tsx
index a5e6c6e0e319..ff6e70da3393 100644
--- a/ui/src/workflows/components/workflow-creator.tsx
+++ b/ui/src/workflows/components/workflow-creator.tsx
@@ -1,4 +1,5 @@
import {Select} from 'argo-ui/src/components/select/select';
+import {History} from 'history';
import * as React from 'react';
import {useEffect, useState} from 'react';
@@ -15,7 +16,7 @@ import {WorkflowEditor} from './workflow-editor';
type Stage = 'choose-method' | 'submit-workflow' | 'full-editor';
-export function WorkflowCreator({namespace, onCreate}: {namespace: string; onCreate: (workflow: Workflow) => void}) {
+export function WorkflowCreator({namespace, onCreate, history}: {namespace: string; onCreate: (workflow: Workflow) => void; history: History}) {
const [workflowTemplates, setWorkflowTemplates] = useState();
const [workflowTemplate, setWorkflowTemplate] = useState();
const [stage, setStage] = useState('choose-method');
@@ -61,6 +62,12 @@ export function WorkflowCreator({namespace, onCreate}: {namespace: string; onCre
}
}, [workflowTemplate]);
+ useEffect(() => {
+ const queryParams = new URLSearchParams(history.location.search);
+ const template = queryParams.get('template');
+ setWorkflowTemplate((workflowTemplates || []).find(tpl => tpl.metadata.name === template));
+ }, [workflowTemplates, setWorkflowTemplate, history]);
+
return (
<>
{stage === 'choose-method' && (
@@ -92,6 +99,7 @@ export function WorkflowCreator({namespace, onCreate}: {namespace: string; onCre
entrypoint={workflowTemplate.spec.entrypoint}
templates={workflowTemplate.spec.templates || []}
workflowParameters={workflowTemplate.spec.arguments.parameters || []}
+ history={history}
/>
setStage('full-editor')}>
Edit using full workflow options
diff --git a/ui/src/workflows/components/workflows-list/workflows-list.tsx b/ui/src/workflows/components/workflows-list/workflows-list.tsx
index 92876713a7ff..00d57401547a 100644
--- a/ui/src/workflows/components/workflows-list/workflows-list.tsx
+++ b/ui/src/workflows/components/workflows-list/workflows-list.tsx
@@ -135,7 +135,7 @@ export function WorkflowsList({match, location, history}: RouteComponentProps params.append('phase', phase));
labels?.forEach(label => params.append('label', label));
if (pagination.offset) {
@@ -346,10 +346,26 @@ export function WorkflowsList({match, location, history}: RouteComponentProps
- navigation.goto('.', {sidePanel: null})}>
+ {
+ 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' && (
navigation.goto(uiUrl(`workflows/${wf.metadata.namespace}/${wf.metadata.name}`))}
/>
)}