[ARVADOS-WORKBENCH2] created: 1.2.0-320-g8805314

Git user git at public.curoverse.com
Fri Sep 7 09:50:44 EDT 2018


        at  8805314e7327cda30d455d0c05075ee37f3a490e (commit)


commit 8805314e7327cda30d455d0c05075ee37f3a490e
Author: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>
Date:   Fri Sep 7 15:50:24 2018 +0200

    14096-move-to-process
    
    Feature #14096
    
    Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk at contractors.roche.com>

diff --git a/src/index.tsx b/src/index.tsx
index a921b47..8ab089a 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -35,6 +35,7 @@ import { ServiceRepository } from '~/services/services';
 import { initWebSocket } from '~/websocket/websocket';
 import { Config } from '~/common/config';
 import { addRouteChangeHandlers } from './routes/route-change-handlers';
+import { processResourceActionSet } from './views-components/context-menu/action-sets/process-resource-action-set';
 
 const getBuildNumber = () => "BN-" + (process.env.REACT_APP_BUILD_NUMBER || "dev");
 const getGitCommit = () => "GIT-" + (process.env.REACT_APP_GIT_COMMIT || "latest").substr(0, 7);
@@ -53,6 +54,7 @@ addMenuActionSet(ContextMenuKind.COLLECTION_FILES_ITEM, collectionFilesItemActio
 addMenuActionSet(ContextMenuKind.COLLECTION, collectionActionSet);
 addMenuActionSet(ContextMenuKind.COLLECTION_RESOURCE, collectionResourceActionSet);
 addMenuActionSet(ContextMenuKind.PROCESS, processActionSet);
+addMenuActionSet(ContextMenuKind.PROCESS_RESOURCE, processResourceActionSet);
 addMenuActionSet(ContextMenuKind.TRASH, trashActionSet);
 
 fetchConfig()
diff --git a/src/routes/routes.ts b/src/routes/routes.ts
index f108e0b..29941b4 100644
--- a/src/routes/routes.ts
+++ b/src/routes/routes.ts
@@ -25,6 +25,8 @@ export const getResourceUrl = (uuid: string) => {
             return getProjectUrl(uuid);
         case ResourceKind.COLLECTION:
             return getCollectionUrl(uuid);
+        case ResourceKind.PROCESS:
+            return getProcessUrl(uuid);
         default:
             return undefined;
     }
diff --git a/src/services/common-service/common-resource-service.ts b/src/services/common-service/common-resource-service.ts
index 7b36b71..abc856f 100644
--- a/src/services/common-service/common-resource-service.ts
+++ b/src/services/common-service/common-resource-service.ts
@@ -32,6 +32,7 @@ export interface Errors {
 export enum CommonResourceServiceError {
     UNIQUE_VIOLATION = 'UniqueViolation',
     OWNERSHIP_CYCLE = 'OwnershipCycle',
+    MODIFYING_CONTAINER_REQUEST_FINAL_STATE = 'ModifyingFinalState',
     UNKNOWN = 'Unknown',
     NONE = 'None'
 }
@@ -121,6 +122,8 @@ export const getCommonResourceServiceError = (errorResponse: any) => {
                 return CommonResourceServiceError.UNIQUE_VIOLATION;
             case /ownership cycle/.test(error):
                 return CommonResourceServiceError.OWNERSHIP_CYCLE;
+            case /Mounts cannot be modified in state 'Final'/.test(error):
+                return CommonResourceServiceError.MODIFYING_CONTAINER_REQUEST_FINAL_STATE;
             default:
                 return CommonResourceServiceError.UNKNOWN;
         }
diff --git a/src/store/context-menu/context-menu-actions.ts b/src/store/context-menu/context-menu-actions.ts
index bb404b8..eabf41a 100644
--- a/src/store/context-menu/context-menu-actions.ts
+++ b/src/store/context-menu/context-menu-actions.ts
@@ -88,7 +88,7 @@ export const openProcessContextMenu = (event: React.MouseEvent<HTMLElement>) =>
     (dispatch: Dispatch, getState: () => RootState) => {
         const { location } = getState().router;
         const pathname = location ? location.pathname : '';
-        const match = matchProcessRoute(pathname); 
+        const match = matchProcessRoute(pathname);
         const uuid = match ? match.params.id : '';
         const resource = {
             uuid,
@@ -108,6 +108,8 @@ export const resourceKindToContextMenuKind = (uuid: string) => {
             return ContextMenuKind.PROJECT;
         case ResourceKind.COLLECTION:
             return ContextMenuKind.COLLECTION_RESOURCE;
+        case ResourceKind.PROCESS:
+            return ContextMenuKind.PROCESS_RESOURCE;
         case ResourceKind.USER:
             return ContextMenuKind.ROOT_PROJECT;
         default:
diff --git a/src/store/processes/process-move-actions.ts b/src/store/processes/process-move-actions.ts
new file mode 100644
index 0000000..d59cdca
--- /dev/null
+++ b/src/store/processes/process-move-actions.ts
@@ -0,0 +1,57 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from "redux";
+import { dialogActions } from "~/store/dialog/dialog-actions";
+import { startSubmit, stopSubmit, initialize } from 'redux-form';
+import { ServiceRepository } from '~/services/services';
+import { RootState } from '~/store/store';
+import { getCommonResourceServiceError, CommonResourceServiceError } from "~/services/common-service/common-resource-service";
+import { snackbarActions } from '~/store/snackbar/snackbar-actions';
+import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
+import { resetPickerProjectTree } from '~/store/project-tree-picker/project-tree-picker-actions';
+import { projectPanelActions } from '~/store/project-panel/project-panel-action';
+import { getProcess, getProcessStatus, ProcessStatus } from '~/store/processes/process';
+
+export const PROCESS_MOVE_FORM_NAME = 'processMoveFormName';
+
+export const openMoveProcessDialog = (resource: { name: string, uuid: string }) =>
+    (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const process = getProcess(resource.uuid)(getState().resources);
+        if (process) {
+            const processStatus = getProcessStatus(process);
+            if (processStatus === ProcessStatus.DRAFT) {
+                dispatch<any>(resetPickerProjectTree());
+                dispatch(initialize(PROCESS_MOVE_FORM_NAME, resource));
+                dispatch(dialogActions.OPEN_DIALOG({ id: PROCESS_MOVE_FORM_NAME, data: {} }));
+            } else {
+                dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'You can move only draft processes.', hideDuration: 2000 }));
+            }
+        }
+    };
+
+export const moveProcess = (resource: MoveToFormDialogData) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(startSubmit(PROCESS_MOVE_FORM_NAME));
+        try {
+            const process = await services.containerRequestService.get(resource.uuid);
+            await services.containerRequestService.update(resource.uuid, { ...process, ownerUuid: resource.ownerUuid });
+            dispatch(projectPanelActions.REQUEST_ITEMS());
+            dispatch(dialogActions.CLOSE_DIALOG({ id: PROCESS_MOVE_FORM_NAME }));
+            dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Process has been moved', hideDuration: 2000 }));
+            return process;
+        } catch (e) {
+            const error = getCommonResourceServiceError(e);
+            if (error === CommonResourceServiceError.UNIQUE_VIOLATION) {
+                dispatch(stopSubmit(PROCESS_MOVE_FORM_NAME, { ownerUuid: 'A process with the same name already exists in the target project.' }));
+            } else if (error === CommonResourceServiceError.MODIFYING_CONTAINER_REQUEST_FINAL_STATE) {
+                dispatch(stopSubmit(PROCESS_MOVE_FORM_NAME, { ownerUuid: 'You can move only uncommitted process.' }));
+            }
+            else {
+                dispatch(dialogActions.CLOSE_DIALOG({ id: PROCESS_MOVE_FORM_NAME }));
+                dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not move the process.', hideDuration: 2000 }));
+            }
+            return;
+        }
+    };
\ No newline at end of file
diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts
index 036f4a3..cb65c24 100644
--- a/src/store/workbench/workbench-actions.ts
+++ b/src/store/workbench/workbench-actions.ts
@@ -29,6 +29,7 @@ import * as collectionCopyActions from '~/store/collections/collection-copy-acti
 import * as collectionUpdateActions from '~/store/collections/collection-update-actions';
 import * as collectionMoveActions from '~/store/collections/collection-move-actions';
 import * as processesActions from '../processes/processes-actions';
+import * as processMoveActions from '~/store/processes/process-move-actions';
 import { trashPanelColumns } from "~/views/trash-panel/trash-panel";
 import { loadTrashPanel, trashPanelActions } from "~/store/trash-panel/trash-panel-action";
 import { initProcessLogsPanel } from '../process-logs-panel/process-logs-panel-actions';
@@ -191,7 +192,19 @@ export const loadProcess = (uuid: string) =>
         await dispatch<any>(activateSidePanelTreeItem(process.containerRequest.ownerUuid));
         dispatch<any>(setProcessBreadcrumbs(uuid));
         dispatch(loadDetailsPanel(uuid));
-        
+
+    };
+
+export const moveProcess = (data: MoveToFormDialogData) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        try {
+            const process = await dispatch<any>(processMoveActions.moveProcess(data));
+            dispatch<any>(updateResources([process]));
+            dispatch<any>(reloadProjectMatchingUuid([process.ownerUuid]));
+            dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Process has been moved.', hideDuration: 2000 }));
+        } catch (e) {
+            dispatch(snackbarActions.OPEN_SNACKBAR({ message: e.message, hideDuration: 2000 }));
+        }
     };
 
 export const loadProcessLog = (uuid: string) =>
diff --git a/src/views-components/context-menu/action-sets/process-action-set.ts b/src/views-components/context-menu/action-sets/process-action-set.ts
index 2897455..3a824ec 100644
--- a/src/views-components/context-menu/action-sets/process-action-set.ts
+++ b/src/views-components/context-menu/action-sets/process-action-set.ts
@@ -11,6 +11,7 @@ import {
 } from "~/components/icon/icon";
 import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
 import { navigateToProcessLogs } from '~/store/navigation/navigation-action';
+import { openMoveProcessDialog } from '~/store/processes/process-move-actions';
 
 export const processActionSet: ContextMenuActionSet = [[
     {
@@ -30,9 +31,7 @@ export const processActionSet: ContextMenuActionSet = [[
     {
         icon: MoveToIcon,
         name: "Move to",
-        execute: (dispatch, resource) => {
-            // add code
-        }
+        execute: (dispatch, resource) => dispatch<any>(openMoveProcessDialog(resource))
     },
     {
         component: ToggleFavoriteAction,
diff --git a/src/views-components/context-menu/action-sets/process-resource-action-set.ts b/src/views-components/context-menu/action-sets/process-resource-action-set.ts
new file mode 100644
index 0000000..64e30f7
--- /dev/null
+++ b/src/views-components/context-menu/action-sets/process-resource-action-set.ts
@@ -0,0 +1,61 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { ContextMenuActionSet } from "../context-menu-action-set";
+import { ToggleFavoriteAction } from "../actions/favorite-action";
+import { toggleFavorite } from "~/store/favorites/favorites-actions";
+import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, RemoveIcon } from "~/components/icon/icon";
+import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action";
+import { openMoveProcessDialog } from '~/store/processes/process-move-actions';
+
+export const processResourceActionSet: ContextMenuActionSet = [[
+    {
+        icon: RenameIcon,
+        name: "Edit process",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: ShareIcon,
+        name: "Share",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: MoveToIcon,
+        name: "Move to",
+        execute: (dispatch, resource) => dispatch<any>(openMoveProcessDialog(resource))
+    },
+    {
+        component: ToggleFavoriteAction,
+        execute: (dispatch, resource) => {
+            dispatch<any>(toggleFavorite(resource)).then(() => {
+                dispatch<any>(favoritePanelActions.REQUEST_ITEMS());
+            });
+        }
+    },
+    {
+        icon: CopyIcon,
+        name: "Copy to project",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: DetailsIcon,
+        name: "View details",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    },
+    {
+        icon: RemoveIcon,
+        name: "Remove",
+        execute: (dispatch, resource) => {
+            // add code
+        }
+    }
+]];
diff --git a/src/views-components/context-menu/context-menu.tsx b/src/views-components/context-menu/context-menu.tsx
index a545b2b..d5c82be 100644
--- a/src/views-components/context-menu/context-menu.tsx
+++ b/src/views-components/context-menu/context-menu.tsx
@@ -65,5 +65,6 @@ export enum ContextMenuKind {
     COLLECTION = 'Collection',
     COLLECTION_RESOURCE = 'CollectionResource',
     PROCESS = "Process",
+    PROCESS_RESOURCE = 'ProcessResource',
     PROCESS_LOGS = "ProcessLogs"
 }
diff --git a/src/views-components/dialog-forms/move-process-dialog.ts b/src/views-components/dialog-forms/move-process-dialog.ts
new file mode 100644
index 0000000..baea34b
--- /dev/null
+++ b/src/views-components/dialog-forms/move-process-dialog.ts
@@ -0,0 +1,21 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { compose } from 'redux';
+import { withDialog } from "~/store/dialog/with-dialog";
+import { reduxForm } from 'redux-form';
+import { PROCESS_MOVE_FORM_NAME } from '~/store/processes/process-move-actions';
+import { MoveToFormDialogData } from '~/store/move-to-dialog/move-to-dialog';
+import { DialogMoveTo } from '~/views-components/dialog-move/dialog-move-to';
+import { moveProcess } from '~/store/workbench/workbench-actions';
+
+export const MoveProcessDialog = compose(
+    withDialog(PROCESS_MOVE_FORM_NAME),
+    reduxForm<MoveToFormDialogData>({
+        form: PROCESS_MOVE_FORM_NAME,
+        onSubmit: (data, dispatch) => {
+            dispatch(moveProcess(data));
+        }
+    })
+)(DialogMoveTo);
\ No newline at end of file
diff --git a/src/views/workbench/workbench.tsx b/src/views/workbench/workbench.tsx
index 3c28108..f202b69 100644
--- a/src/views/workbench/workbench.tsx
+++ b/src/views/workbench/workbench.tsx
@@ -34,11 +34,11 @@ import { CreateCollectionDialog } from '~/views-components/dialog-forms/create-c
 import { CopyCollectionDialog } from '~/views-components/dialog-forms/copy-collection-dialog';
 import { UpdateCollectionDialog } from '~/views-components/dialog-forms/update-collection-dialog';
 import { UpdateProjectDialog } from '~/views-components/dialog-forms/update-project-dialog';
+import { MoveProcessDialog } from '~/views-components/dialog-forms/move-process-dialog';
 import { MoveProjectDialog } from '~/views-components/dialog-forms/move-project-dialog';
 import { MoveCollectionDialog } from '~/views-components/dialog-forms/move-collection-dialog';
 import { FilesUploadCollectionDialog } from '~/views-components/dialog-forms/files-upload-collection-dialog';
 import { PartialCopyCollectionDialog } from '~/views-components/dialog-forms/partial-copy-collection-dialog';
-
 import { TrashPanel } from "~/views/trash-panel/trash-panel";
 
 const APP_BAR_HEIGHT = 100;
@@ -189,6 +189,7 @@ export const Workbench = withStyles(styles)(
                         <FilesUploadCollectionDialog />
                         <UpdateProjectDialog />
                         <MoveCollectionDialog />
+                        <MoveProcessDialog />
                         <MoveProjectDialog />
                         <CurrentTokenDialog
                             currentToken={this.props.currentToken}

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list