[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