Skip to content

Commit

Permalink
fix: add query string to workflow detail page(#11371) (#11373)
Browse files Browse the repository at this point in the history
  • Loading branch information
toyamagu-2021 committed Jul 22, 2023
1 parent 5b31ca1 commit 5cb75d9
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 46 deletions.
11 changes: 9 additions & 2 deletions ui/src/app/shared/services/workflows-service.ts
Expand Up @@ -67,8 +67,8 @@ export const WorkflowsService = {
return requests.get(`api/v1/workflows/${namespace}/${name}`).then(res => res.body as Workflow);
},

getArchived(namespace: string, name: string) {
return requests.get(`api/v1/archived-workflows/?name=${name}&namespace=${namespace}`).then(res => res.body as models.Workflow);
getArchived(namespace: string, uid: string) {
return requests.get(`api/v1/archived-workflows/${uid}?namespace=${namespace}`).then(res => res.body as models.Workflow);
},

watch(query: {
Expand Down Expand Up @@ -129,6 +129,13 @@ export const WorkflowsService = {
.then(res => res.body as Workflow);
},

resubmitArchived(uid: string, namespace: string, opts?: ResubmitOpts) {
return requests
.put(`api/v1/archived-workflows/${uid}/resubmit`)
.send({namespace, ...opts})
.then(res => res.body as Workflow);
},

suspend(name: string, namespace: string) {
return requests.put(`api/v1/workflows/${namespace}/${name}/suspend`).then(res => res.body as Workflow);
},
Expand Down
16 changes: 12 additions & 4 deletions ui/src/app/workflows/components/resubmit-workflow-panel.tsx
Expand Up @@ -9,6 +9,7 @@ import {Utils} from '../../shared/utils';

interface Props {
workflow: Workflow;
isArchived: boolean;
}

interface State {
Expand Down Expand Up @@ -98,9 +99,16 @@ export class ResubmitWorkflowPanel extends React.Component<Props, State> {
memoized: this.state.memoized
};

services.workflows
.resubmit(this.props.workflow.metadata.name, this.props.workflow.metadata.namespace, opts)
.then((submitted: Workflow) => (document.location.href = uiUrl(`workflows/${submitted.metadata.namespace}/${submitted.metadata.name}`)))
.catch(error => this.setState({error, isSubmitting: false}));
if (!this.props.isArchived) {
services.workflows
.resubmit(this.props.workflow.metadata.name, this.props.workflow.metadata.namespace, opts)
.then((submitted: Workflow) => (document.location.href = uiUrl(`workflows/${submitted.metadata.namespace}/${submitted.metadata.name}`)))
.catch(error => this.setState({error, isSubmitting: false}));
} else {
services.workflows
.resubmitArchived(this.props.workflow.metadata.uid, this.props.workflow.metadata.namespace, opts)
.then((submitted: Workflow) => (document.location.href = uiUrl(`workflows/${submitted.metadata.namespace}/${submitted.metadata.name}`)))
.catch(error => this.setState({error, isSubmitting: false}));
}
}
}
Expand Up @@ -3,7 +3,7 @@ import * as classNames from 'classnames';
import * as React from 'react';
import {useContext, useEffect, useRef, useState} from 'react';
import {RouteComponentProps} from 'react-router';
import {ArtifactRepository, execSpec, isArchivedWorkflow, Link, NodeStatus, Parameter, Workflow} from '../../../../models';
import {archivalStatus, ArtifactRepository, execSpec, isArchivedWorkflow, isWorkflowInCluster, Link, NodeStatus, Parameter, Workflow} from '../../../../models';
import {ANNOTATION_KEY_POD_NAME_VERSION} from '../../../shared/annotations';
import {artifactRepoHasLocation, findArtifact} from '../../../shared/artifacts';
import {uiUrl} from '../../../shared/base';
Expand Down Expand Up @@ -93,10 +93,9 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
const queryParams = new URLSearchParams(location.search);

const [namespace] = useState(match.params.namespace);
const [isWfInDB, setIsWfInDB] = useState(false);
const [isWfInCluster, setIsWfInCluster] = useState(false);
const [name, setName] = useState(match.params.name);
const [tab, setTab] = useState(queryParams.get('tab') || 'workflow');
const [uid, setUid] = useState(queryParams.get('uid') || '');
const [nodeId, setNodeId] = useState(queryParams.get('nodeId'));
const [nodePanelView, setNodePanelView] = useState(queryParams.get('nodePanelView'));
const [sidePanel, setSidePanel] = useState(queryParams.get('sidePanel'));
Expand All @@ -120,6 +119,7 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<

useEffect(
useQueryParams(history, p => {
setUid(p.get('uid'));
setTab(p.get('tab') || 'workflow');
setNodeId(p.get('nodeId'));
setNodePanelView(p.get('nodePanelView'));
Expand Down Expand Up @@ -158,8 +158,8 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
}, [workflow, selectedArtifact]);

useEffect(() => {
history.push(historyUrl('workflows/{namespace}/{name}', {namespace, name, tab, nodeId, nodePanelView, sidePanel}));
}, [namespace, name, tab, nodeId, nodePanelView, sidePanel]);
history.push(historyUrl('workflows/{namespace}/{name}', {namespace, name, tab, nodeId, nodePanelView, sidePanel, uid}));
}, [namespace, name, tab, nodeId, nodePanelView, sidePanel, uid]);

useEffect(() => {
services.info
Expand Down Expand Up @@ -187,24 +187,14 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
action: () => {
if (workflowOperation.title === 'DELETE') {
popup
.confirm('Confirm', () => <DeleteCheck isWfInDB={isWfInDB} isWfInCluster={isWfInCluster} />)
.confirm('Confirm', () => <DeleteCheck isWfInDB={isArchivedWorkflow(workflow)} isWfInCluster={isWorkflowInCluster(workflow)} />)
.then(yes => {
if (yes) {
if (isWfInCluster) {
services.workflows
.delete(workflow.metadata.name, workflow.metadata.namespace)
.then(() => {
setIsWfInCluster(false);
})
.catch(setError);
if (isWorkflowInCluster(workflow)) {
services.workflows.delete(workflow.metadata.name, workflow.metadata.namespace).catch(setError);
}
if (isWfInDB && (globalDeleteArchived || !isWfInCluster)) {
services.workflows
.deleteArchived(workflow.metadata.uid, workflow.metadata.namespace)
.then(() => {
setIsWfInDB(false);
})
.catch(setError);
if (isArchivedWorkflow(workflow) && (globalDeleteArchived || !isWorkflowInCluster(workflow))) {
services.workflows.deleteArchived(workflow.metadata.uid, workflow.metadata.namespace).catch(setError);
}
navigation.goto(uiUrl(`workflows/${workflow.metadata.namespace}`));
// TODO: This is a temporary workaround so that the list of workflows
Expand Down Expand Up @@ -352,49 +342,76 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
);
};
useEffect(() => {
if (!isWorkflowInCluster(workflow)) {
return;
}
const retryWatch = new RetryWatch<Workflow>(
() => services.workflows.watch({name, namespace}),
() => {
setIsWfInCluster(true);
setError(null);
},
e => {
if (e.type === 'DELETED') {
setUid(e.object.metadata.uid);
setError(new Error('Workflow gone'));
setIsWfInCluster(false);
if (e.object.metadata.labels[archivalStatus]) {
e.object.metadata.labels[archivalStatus] = 'Persisted';
}
setWorkflow(e.object);
} else {
if (hasArtifactGCError(e.object.status.conditions)) {
setError(new Error('Artifact garbage collection failed'));
}
setWorkflow(e.object);
setIsWfInCluster(true);
}
},
err => {
setError(err);
setIsWfInCluster(false);
}
);
retryWatch.start();
return () => retryWatch.stop();
}, [namespace, name]);
}, [namespace, name, isWorkflowInCluster(workflow)]);

// Get workflow
useEffect(() => {
if (!workflow && !isWfInCluster) {
services.workflows
.getArchived(namespace, name)
const getWf = async () => {
let archivedWf: Workflow;
if (uid !== '') {
await services.workflows
.getArchived(namespace, uid)
.then(wf => {
setError(null);
archivedWf = wf;
})
.catch(err => {
if (err.status !== 404) {
setError(err);
}
});
}
await services.workflows
.get(namespace, name)
.then(wf => {
setError(null);
setWorkflow(wf);
setIsWfInDB(true);
// If we find live workflow which has same uid, we use live workflow.
if (!archivedWf || archivedWf.metadata.uid === wf.metadata.uid) {
setWorkflow(wf);
setUid(wf.metadata.uid);
} else {
setWorkflow(archivedWf);
}
})
.catch(newErr => {
if (newErr.status !== 404) {
setError(newErr);
.catch(err => {
if (archivedWf) {
setWorkflow(archivedWf);
} else {
setError(err);
}
});
}
}, [namespace, name, isWfInCluster]);
};
getWf();
}, [namespace, name, uid]);

const openLink = (link: Link) => {
const object = {
Expand Down Expand Up @@ -563,7 +580,7 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
{parsedSidePanel.type === 'events' && <EventsPanel namespace={namespace} kind='Pod' name={podName} />}
{parsedSidePanel.type === 'share' && <WidgetGallery namespace={namespace} name={name} />}
{parsedSidePanel.type === 'yaml' && <WorkflowYamlViewer workflow={workflow} selectedNode={selectedNode} />}
{parsedSidePanel.type === 'resubmit' && <ResubmitWorkflowPanel workflow={workflow} />}
{parsedSidePanel.type === 'resubmit' && <ResubmitWorkflowPanel workflow={workflow} isArchived={isArchivedWorkflow(workflow)} />}
{!parsedSidePanel}
</SlidingPanel>
)}
Expand Down
Expand Up @@ -50,7 +50,12 @@ export class WorkflowsRow extends React.Component<WorkflowsRowProps, WorkflowRow
/>
<PhaseIcon value={wf.status.phase} />
</div>
<Link to={uiUrl(`workflows/${wf.metadata.namespace}/${wf.metadata.name}`)} className='small-11 row'>
<Link
to={{
pathname: uiUrl(`workflows/${wf.metadata.namespace}/${wf.metadata.name}`),
search: `?uid=${wf.metadata.uid}`
}}
className='small-11 row'>
<div className='columns small-2'>
{(wf.metadata.annotations && wf.metadata.annotations[ANNOTATION_TITLE]) || wf.metadata.name}
{wf.metadata.annotations && wf.metadata.annotations[ANNOTATION_DESCRIPTION] ? <p>{wf.metadata.annotations[ANNOTATION_DESCRIPTION]}</p> : null}
Expand Down
@@ -1,6 +1,6 @@
import {NotificationType} from 'argo-ui';
import * as React from 'react';
import {archivalStatus, Workflow} from '../../../../models';
import {isArchivedWorkflow, isWorkflowInCluster, Workflow} from '../../../../models';
import {Consumer} from '../../../shared/context';
import {services} from '../../../shared/services';
import * as Actions from '../../../shared/workflow-operations-map';
Expand Down Expand Up @@ -60,7 +60,7 @@ export class WorkflowsToolbar extends React.Component<WorkflowsToolbarProps, {}>
this.props.selectedWorkflows.forEach((wf: Workflow) => {
if (title === 'DELETE') {
// The ones without archivalStatus label or with 'Archived' labels are the live workflows.
if (!wf.metadata.labels.hasOwnProperty(archivalStatus) || wf.metadata.labels[archivalStatus] === 'Archived') {
if (isWorkflowInCluster(wf)) {
promises.push(
services.workflows.delete(wf.metadata.name, wf.metadata.namespace).catch(reason =>
ctx.notifications.show({
Expand All @@ -70,7 +70,7 @@ export class WorkflowsToolbar extends React.Component<WorkflowsToolbarProps, {}>
)
);
}
if (deleteArchived && (wf.metadata.labels[archivalStatus] === 'Archived' || wf.metadata.labels[archivalStatus] === 'Persisted')) {
if (deleteArchived && isArchivedWorkflow(wf)) {
promises.push(
services.workflows.deleteArchived(wf.metadata.uid, wf.metadata.namespace).catch(reason =>
ctx.notifications.show({
Expand Down
10 changes: 10 additions & 0 deletions ui/src/models/workflows.ts
Expand Up @@ -541,7 +541,17 @@ export const execSpec = (w: Workflow) => Object.assign({}, w.status.storedWorkfl

export const archivalStatus = 'workflows.argoproj.io/workflow-archiving-status';

export function isWorkflowInCluster(wf: Workflow): boolean {
if (!wf) {
return false;
}
return !wf.metadata.labels[archivalStatus] || wf.metadata.labels[archivalStatus] === 'Pending' || wf.metadata.labels[archivalStatus] === 'Archived';
}

export function isArchivedWorkflow(wf: Workflow): boolean {
if (!wf) {
return false;
}
return wf.metadata.labels && (wf.metadata.labels[archivalStatus] === 'Archived' || wf.metadata.labels[archivalStatus] === 'Persisted');
}

Expand Down

0 comments on commit 5cb75d9

Please sign in to comment.