diff --git a/ui/src/app/shared/services/archived-workflows-service.ts b/ui/src/app/shared/services/archived-workflows-service.ts
deleted file mode 100644
index ecda26a10c27..000000000000
--- a/ui/src/app/shared/services/archived-workflows-service.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import * as models from '../../../models';
-import {Pagination} from '../pagination';
-import {Utils} from '../utils';
-import requests from './requests';
-export const ArchivedWorkflowsService = {
- list(namespace: string, name: string, namePrefix: string, phases: string[], labels: string[], minStartedAt: Date, maxStartedAt: Date, pagination: Pagination) {
- if (namespace === '') {
- return requests
- .get(`api/v1/archived-workflows?${Utils.queryParams({name, namePrefix, phases, labels, minStartedAt, maxStartedAt, pagination}).join('&')}`)
- .then(res => res.body as models.WorkflowList);
- } else {
- return requests
- .get(`api/v1/archived-workflows?namespace=${namespace}&${Utils.queryParams({name, namePrefix, phases, labels, minStartedAt, maxStartedAt, pagination}).join('&')}`)
- .then(res => res.body as models.WorkflowList);
- }
- },
-
- get(uid: string, namespace: string) {
- if (namespace === '') {
- return requests.get(`api/v1/archived-workflows/${uid}`).then(res => res.body as models.Workflow);
- } else {
- return requests.get(`api/v1/archived-workflows/${uid}?namespace=${namespace}`).then(res => res.body as models.Workflow);
- }
- },
-
- delete(uid: string, namespace: string) {
- if (namespace === '') {
- return requests.delete(`api/v1/archived-workflows/${uid}`);
- } else {
- return requests.delete(`api/v1/archived-workflows/${uid}?namespace=${namespace}`);
- }
- },
-
- listLabelKeys(namespace: string) {
- if (namespace === '') {
- return requests.get(`api/v1/archived-workflows-label-keys`).then(res => res.body as models.Labels);
- } else {
- return requests.get(`api/v1/archived-workflows-label-keys?namespace=${namespace}`).then(res => res.body as models.Labels);
- }
- },
-
- async listLabelValues(key: string, namespace: string): Promise
{
- let url = `api/v1/archived-workflows-label-values?listOptions.labelSelector=${key}`;
- if (namespace !== '') {
- url += `&namespace=${namespace}`;
- }
- return (await requests.get(url)).body as models.Labels;
- },
-
- resubmit(uid: string, namespace: string) {
- return requests
- .put(`api/v1/archived-workflows/${uid}/resubmit`)
- .send({namespace})
- .then(res => res.body as models.Workflow);
- },
-
- retry(uid: string, namespace: string) {
- return requests
- .put(`api/v1/archived-workflows/${uid}/retry`)
- .send({namespace})
- .then(res => res.body as models.Workflow);
- }
-};
diff --git a/ui/src/app/shared/services/index.ts b/ui/src/app/shared/services/index.ts
index d44e7364be1c..29e9b1326ea5 100644
--- a/ui/src/app/shared/services/index.ts
+++ b/ui/src/app/shared/services/index.ts
@@ -1,4 +1,3 @@
-import {ArchivedWorkflowsService} from './archived-workflows-service';
import {ClusterWorkflowTemplateService} from './cluster-workflow-template-service';
import {CronWorkflowService} from './cron-workflow-service';
import {EventService} from './event-service';
@@ -16,7 +15,6 @@ interface Services {
workflows: typeof WorkflowsService;
workflowTemplate: typeof WorkflowTemplateService;
clusterWorkflowTemplate: typeof ClusterWorkflowTemplateService;
- archivedWorkflows: typeof ArchivedWorkflowsService;
cronWorkflows: typeof CronWorkflowService;
}
@@ -28,6 +26,5 @@ export const services: Services = {
event: EventService,
eventSource: EventSourceService,
sensor: SensorService,
- archivedWorkflows: ArchivedWorkflowsService,
cronWorkflows: CronWorkflowService
};
diff --git a/ui/src/app/shared/services/workflows-service.ts b/ui/src/app/shared/services/workflows-service.ts
index 9900a10920fa..df70d6d60171 100644
--- a/ui/src/app/shared/services/workflows-service.ts
+++ b/ui/src/app/shared/services/workflows-service.ts
@@ -66,6 +66,10 @@ 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);
+ },
+
watch(query: {
namespace?: string;
name?: string;
@@ -151,6 +155,14 @@ export const WorkflowsService = {
return requests.delete(`api/v1/workflows/${namespace}/${name}`).then(res => res.body as WorkflowDeleteResponse);
},
+ deleteArchived(uid: string, namespace: string): Promise {
+ if (namespace === '') {
+ return requests.delete(`api/v1/archived-workflows/${uid}`).then(res => res.body as WorkflowDeleteResponse);
+ } else {
+ return requests.delete(`api/v1/archived-workflows/${uid}?namespace=${namespace}`).then(res => res.body as WorkflowDeleteResponse);
+ }
+ },
+
submit(kind: string, name: string, namespace: string, submitOptions?: SubmitOpts) {
return requests
.post(`api/v1/workflows/${namespace}/submit`)
diff --git a/ui/src/app/shared/workflow-operations-map.ts b/ui/src/app/shared/workflow-operations-map.tsx
similarity index 100%
rename from ui/src/app/shared/workflow-operations-map.ts
rename to ui/src/app/shared/workflow-operations-map.tsx
diff --git a/ui/src/app/workflows/components/workflow-details/workflow-details.tsx b/ui/src/app/workflows/components/workflow-details/workflow-details.tsx
index f61bdce5011d..e13d1e771df0 100644
--- a/ui/src/app/workflows/components/workflow-details/workflow-details.tsx
+++ b/ui/src/app/workflows/components/workflow-details/workflow-details.tsx
@@ -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, Link, NodeStatus, Parameter, Workflow} from '../../../../models';
+import {ArtifactRepository, execSpec, isArchivedWorkflow, 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';
@@ -51,12 +51,49 @@ const INITIAL_SIDE_PANEL_WIDTH = 570;
const ANIMATION_MS = 200;
const ANIMATION_BUFFER_MS = 20;
+// This is used instead of React state since the state update is async and there's a delay for parent
+// component to render with the updated state.
+let globalDeleteArchived = false;
+
+const DeleteCheck = (props: {isWfInDB: boolean; isWfInCluster: boolean}) => {
+ // The local states are created intentionally so that the checkbox works as expected
+ const [da, sda] = useState(false);
+ if (props.isWfInDB && props.isWfInCluster) {
+ return (
+ <>
+ Are you sure you want to delete this workflow?
+
+ {
+ sda(!da);
+ globalDeleteArchived = !globalDeleteArchived;
+ }}
+ id='delete-check'
+ />
+
+
+ >
+ );
+ } else {
+ return (
+ <>
+ Are you sure you want to delete this workflow?
+ >
+ );
+ }
+};
+
export const WorkflowDetails = ({history, location, match}: RouteComponentProps) => {
// boiler-plate
const {navigation, popup} = useContext(Context);
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 [nodeId, setNodeId] = useState(queryParams.get('nodeId'));
@@ -147,20 +184,45 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
title: workflowOperation.title.charAt(0).toUpperCase() + workflowOperation.title.slice(1),
iconClassName: workflowOperation.iconClassName,
action: () => {
- popup.confirm('Confirm', `Are you sure you want to ${workflowOperation.title.toLowerCase()} this workflow?`).then(yes => {
- if (yes) {
- workflowOperation
- .action(workflow)
- .then((wf: Workflow) => {
- if (workflowOperation.title === 'DELETE') {
- navigation.goto(uiUrl(`workflows/${workflow.metadata.namespace}`));
- } else {
- setName(wf.metadata.name);
+ if (workflowOperation.title === 'DELETE') {
+ popup
+ .confirm('Confirm', () => )
+ .then(yes => {
+ if (yes) {
+ if (isWfInCluster) {
+ services.workflows
+ .delete(workflow.metadata.name, workflow.metadata.namespace)
+ .then(() => {
+ setIsWfInCluster(false);
+ })
+ .catch(setError);
+ }
+ if (isWfInDB && (globalDeleteArchived || !isWfInCluster)) {
+ services.workflows
+ .deleteArchived(workflow.metadata.uid, workflow.metadata.namespace)
+ .then(() => {
+ setIsWfInDB(false);
+ })
+ .catch(setError);
}
- })
- .catch(setError);
- }
- });
+ navigation.goto(uiUrl(`workflows/${workflow.metadata.namespace}`));
+ // TODO: This is a temporary workaround so that the list of workflows
+ // is correctly displayed. Workflow list page needs to be more responsive.
+ window.location.reload();
+ }
+ });
+ } else {
+ popup.confirm('Confirm', `Are you sure you want to ${workflowOperation.title.toLowerCase()} this workflow?`).then(yes => {
+ if (yes) {
+ workflowOperation
+ .action(workflow)
+ .then((wf: Workflow) => {
+ setName(wf.metadata.name);
+ })
+ .catch(setError);
+ }
+ });
+ }
}
};
});
@@ -277,7 +339,7 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
)}
Artifacts
-
+