[arvados-workbench2] created: 2.6.3-100-g5afc1f6e
git repository hosting
git at public.arvados.org
Mon Aug 28 19:20:11 UTC 2023
at 5afc1f6ee27b2135827d0f2976ed01ad0534ba62 (commit)
commit 5afc1f6ee27b2135827d0f2976ed01ad0534ba62
Author: Peter Amstutz <peter.amstutz at curii.com>
Date: Mon Aug 28 15:19:39 2023 -0400
20899: Add menu item to delete workflow record
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>
diff --git a/cypress/integration/workflow.spec.js b/cypress/integration/workflow.spec.js
index e1fa20a8..76ad3c63 100644
--- a/cypress/integration/workflow.spec.js
+++ b/cypress/integration/workflow.spec.js
@@ -234,4 +234,35 @@ describe('Registered workflow panel tests', function() {
});
});
});
+
+ it('can delete a workflow', function() {
+ cy.createResource(activeUser.token, "workflows", {workflow: {name: "Test wf"}})
+ .then(function(workflowResource) {
+ cy.loginAs(activeUser);
+ cy.goToPath(`/projects/${activeUser.user.uuid}`);
+ cy.get('[data-cy=project-panel] table tbody').contains(workflowResource.name).rightclick();
+ cy.get('[data-cy=context-menu]').contains('Delete Workflow').click();
+ cy.get('[data-cy=project-panel] table tbody').should('not.contain', workflowResource.name);
+ });
+ });
+
+ it('cannot delete readonly workflow', function() {
+ cy.createProject({
+ owningUser: adminUser,
+ targetUser: activeUser,
+ projectName: 'mySharedReadonlyProject',
+ canWrite: false,
+ });
+ cy.getAll('@mySharedReadonlyProject')
+ .then(function ([mySharedReadonlyProject]) {
+ cy.createResource(adminUser.token, "workflows", {workflow: {name: "Test wf", owner_uuid: mySharedReadonlyProject.uuid}})
+ .then(function(workflowResource) {
+ cy.loginAs(activeUser);
+ cy.goToPath(`/shared-with-me`);
+ cy.contains("mySharedReadonlyProject").click();
+ cy.get('[data-cy=project-panel] table tbody').contains(workflowResource.name).rightclick();
+ cy.get('[data-cy=context-menu]').should("not.contain", 'Delete Workflow');
+ });
+ });
+ });
});
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index fadd73e0..67ddf45d 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -36,12 +36,14 @@ let createdResources = [];
const containerLogFolderPrefix = 'log for container ';
-// Clean up on a 'before' hook to allow post-mortem analysis on individual tests.
-beforeEach(function () {
+// Clean up anything that was created. You can temporarily add
+// 'return' to the top if you need the resources to hang around to
+// debug a specific test.
+afterEach(function () {
if (createdResources.length === 0) {
return;
}
- cy.log(`Cleaning ${createdResources.length} previously created resource(s)`);
+ cy.log(`Cleaning ${createdResources.length} previously created resource(s).`);
createdResources.forEach(function({suffix, uuid}) {
// Don't fail when a resource isn't already there, some objects may have
// been removed, directly or indirectly, from the test that created them.
diff --git a/src/index.tsx b/src/index.tsx
index 9293dd74..7cc18783 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -62,7 +62,7 @@ import { linkActionSet } from 'views-components/context-menu/action-sets/link-ac
import { loadFileViewersConfig } from 'store/file-viewers/file-viewers-actions';
import { filterGroupAdminActionSet, frozenAdminActionSet, projectAdminActionSet } from 'views-components/context-menu/action-sets/project-admin-action-set';
import { permissionEditActionSet } from 'views-components/context-menu/action-sets/permission-edit-action-set';
-import { workflowActionSet } from 'views-components/context-menu/action-sets/workflow-action-set';
+import { workflowActionSet, readOnlyWorkflowActionSet } from 'views-components/context-menu/action-sets/workflow-action-set';
import { snackbarActions, SnackbarKind } from "store/snackbar/snackbar-actions";
import { openNotFoundDialog } from './store/not-found-panel/not-found-panel-action';
import { storeRedirects } from './common/redirect-to';
@@ -108,6 +108,7 @@ addMenuActionSet(ContextMenuKind.FROZEN_PROJECT, frozenActionSet);
addMenuActionSet(ContextMenuKind.FROZEN_PROJECT_ADMIN, frozenAdminActionSet);
addMenuActionSet(ContextMenuKind.FILTER_GROUP_ADMIN, filterGroupAdminActionSet);
addMenuActionSet(ContextMenuKind.PERMISSION_EDIT, permissionEditActionSet);
+addMenuActionSet(ContextMenuKind.READONLY_WORKFLOW, readOnlyWorkflowActionSet);
addMenuActionSet(ContextMenuKind.WORKFLOW, workflowActionSet);
addMenuActionSet(ContextMenuKind.SEARCH_RESULTS, searchResultsActionSet);
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index e659de8a..4abfb372 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -274,7 +274,7 @@ export const resourceUuidToContextMenuKind = (uuid: string, readonly = false) =>
case ResourceKind.LINK:
return ContextMenuKind.LINK;
case ResourceKind.WORKFLOW:
- return ContextMenuKind.WORKFLOW;
+ return isEditable ? ContextMenuKind.WORKFLOW : ContextMenuKind.READONLY_WORKFLOW;
default:
return;
}
diff --git a/src/store/resources/resources.ts b/src/store/resources/resources.ts
index 3f711404..e3fb2eb3 100644
--- a/src/store/resources/resources.ts
+++ b/src/store/resources/resources.ts
@@ -9,18 +9,17 @@ import { GroupResource } from "models/group";
export type ResourcesState = { [key: string]: Resource };
-export const getResourceWithEditableStatus = <T extends EditableResource & GroupResource>(id: string, userUuid?: string) =>
+export const getResourceWithEditableStatus = <T extends GroupResource & EditableResource>(id: string, userUuid?: string) =>
(state: ResourcesState): T | undefined => {
if (state[id] === undefined) { return; }
- const resource = JSON.parse(JSON.stringify(state[id] as T));
+ const resource = JSON.parse(JSON.stringify(state[id])) as T;
if (resource) {
- resource.isEditable = resource.canWrite;
-
- if (!resource.isEditable && state[resource.ownerUuid]) {
- const resourceOwner = JSON.parse(JSON.stringify(state[resource.ownerUuid] as T));
- resource.isEditable = resourceOwner.canWrite;
+ if (resource.canWrite === undefined) {
+ resource.isEditable = (state[resource.ownerUuid] as GroupResource)?.canWrite;
+ } else {
+ resource.isEditable = resource.canWrite;
}
}
diff --git a/src/store/workflow-panel/workflow-panel-actions.ts b/src/store/workflow-panel/workflow-panel-actions.ts
index 2c44fae4..94b35078 100644
--- a/src/store/workflow-panel/workflow-panel-actions.ts
+++ b/src/store/workflow-panel/workflow-panel-actions.ts
@@ -8,14 +8,14 @@ import { ServiceRepository } from 'services/services';
import { bindDataExplorerActions } from 'store/data-explorer/data-explorer-action';
import { propertiesActions } from 'store/properties/properties-actions';
import { getProperty } from 'store/properties/properties';
-import { navigateToRunProcess } from 'store/navigation/navigation-action';
+import { navigateToRunProcess, navigateTo } from 'store/navigation/navigation-action';
import {
goToStep,
runProcessPanelActions,
loadPresets,
getWorkflowRunnerSettings
} from 'store/run-process-panel/run-process-panel-actions';
-import { snackbarActions } from 'store/snackbar/snackbar-actions';
+import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
import { initialize } from 'redux-form';
import { RUN_PROCESS_BASIC_FORM } from 'views/run-process-panel/run-process-basic-form';
import { RUN_PROCESS_INPUTS_FORM } from 'views/run-process-panel/run-process-inputs-form';
@@ -117,3 +117,11 @@ export const getWorkflowDetails = (state: RootState) => {
const workflow = workflows.find(workflow => workflow.uuid === uuid);
return workflow || undefined;
};
+
+export const deleteWorkflow = (workflowUuid: string, ownerUuid: string) =>
+ async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+ dispatch<any>(navigateTo(ownerUuid));
+ dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...', kind: SnackbarKind.INFO }));
+ await services.workflowService.delete(workflowUuid);
+ dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
+ };
diff --git a/src/views-components/context-menu/action-sets/workflow-action-set.ts b/src/views-components/context-menu/action-sets/workflow-action-set.ts
index a5223d1d..1baf0422 100644
--- a/src/views-components/context-menu/action-sets/workflow-action-set.ts
+++ b/src/views-components/context-menu/action-sets/workflow-action-set.ts
@@ -3,19 +3,20 @@
// SPDX-License-Identifier: AGPL-3.0
import { ContextMenuActionSet } from "views-components/context-menu/context-menu-action-set";
-import { openRunProcess } from "store/workflow-panel/workflow-panel-actions";
+import { openRunProcess, deleteWorkflow } from "store/workflow-panel/workflow-panel-actions";
import {
DetailsIcon,
AdvancedIcon,
OpenIcon,
Link,
- StartIcon
+ StartIcon,
+ TrashIcon
} from "components/icon/icon";
import { copyToClipboardAction, openInNewTabAction } from "store/open-in-new-tab/open-in-new-tab.actions";
import { toggleDetailsPanel } from 'store/details-panel/details-panel-action';
import { openAdvancedTabDialog } from "store/advanced-tab/advanced-tab";
-export const workflowActionSet: ContextMenuActionSet = [[
+export const readOnlyWorkflowActionSet: ContextMenuActionSet = [[
{
icon: OpenIcon,
name: "Open in new tab",
@@ -50,5 +51,16 @@ export const workflowActionSet: ContextMenuActionSet = [[
execute: (dispatch, resource) => {
dispatch<any>(openRunProcess(resource.uuid, resource.ownerUuid, resource.name));
}
+ }
+]];
+
+export const workflowActionSet: ContextMenuActionSet = [[
+ ...readOnlyWorkflowActionSet[0],
+ {
+ icon: TrashIcon,
+ name: "Delete Workflow",
+ execute: (dispatch, resource) => {
+ dispatch<any>(deleteWorkflow(resource.uuid, resource.ownerUuid));
+ }
},
]];
diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx
index 81c1a51e..1b4610ef 100644
--- a/src/views-components/context-menu/context-menu.tsx
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -115,5 +115,6 @@ export enum ContextMenuKind {
PERMISSION_EDIT = "PermissionEdit",
LINK = "Link",
WORKFLOW = "Workflow",
+ READONLY_WORKFLOW = "ReadOnlyWorkflow",
SEARCH_RESULTS = "SearchResults"
}
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list