From: Michal Klobukowski Date: Mon, 20 Aug 2018 15:27:08 +0000 (+0200) Subject: Implement resource moving X-Git-Tag: 1.3.0~141^2~9 X-Git-Url: https://git.arvados.org/arvados-workbench2.git/commitdiff_plain/8c0a8c26b37118e6e516da2cfaa19b26b8f1e5eb Implement resource moving Feature #13831 Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski --- diff --git a/src/services/services.ts b/src/services/services.ts index 1fa35fca..c2615a34 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -14,6 +14,7 @@ import { CollectionFilesService } from "./collection-files-service/collection-fi import { KeepService } from "./keep-service/keep-service"; import { WebDAV } from "../common/webdav"; import { Config } from "../common/config"; +import { ResourceKind } from '~/models/resource'; export type ServiceRepository = ReturnType; @@ -49,3 +50,14 @@ export const createServices = (config: Config) => { }; }; +export const getResourceService = (resourceKind: ResourceKind, serviceRepository: ServiceRepository) => { + switch (resourceKind) { + case ResourceKind.PROJECT: + return serviceRepository.projectService; + case ResourceKind.COLLECTION: + return serviceRepository.collectionService; + default: + return undefined; + } +}; + diff --git a/src/views-components/context-menu/action-sets/collection-action-set.ts b/src/views-components/context-menu/action-sets/collection-action-set.ts index 9c07fb05..bbe6f5f6 100644 --- a/src/views-components/context-menu/action-sets/collection-action-set.ts +++ b/src/views-components/context-menu/action-sets/collection-action-set.ts @@ -9,6 +9,7 @@ import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, ProvenanceGra import { openUpdater } from "~/store/collections/updater/collection-updater-action"; import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action"; import { openMoveToDialog } from "../../move-to-dialog/move-to-dialog"; +import { ResourceKind } from "~/models/resource"; export const collectionActionSet: ContextMenuActionSet = [[ { @@ -28,7 +29,11 @@ export const collectionActionSet: ContextMenuActionSet = [[ { icon: MoveToIcon, name: "Move to", - execute: dispatch => dispatch(openMoveToDialog()) + execute: (dispatch, resource) => dispatch(openMoveToDialog({ + name: resource.name, + uuid: resource.uuid, + kind: ResourceKind.COLLECTION + })) }, { component: ToggleFavoriteAction, diff --git a/src/views-components/context-menu/action-sets/collection-resource-action-set.ts b/src/views-components/context-menu/action-sets/collection-resource-action-set.ts index 337ca2ff..24c1bf15 100644 --- a/src/views-components/context-menu/action-sets/collection-resource-action-set.ts +++ b/src/views-components/context-menu/action-sets/collection-resource-action-set.ts @@ -9,6 +9,7 @@ import { RenameIcon, ShareIcon, MoveToIcon, CopyIcon, DetailsIcon, RemoveIcon } import { openUpdater } from "~/store/collections/updater/collection-updater-action"; import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action"; import { openMoveToDialog } from "../../move-to-dialog/move-to-dialog"; +import { ResourceKind } from '~/models/resource'; export const collectionResourceActionSet: ContextMenuActionSet = [[ { @@ -28,7 +29,11 @@ export const collectionResourceActionSet: ContextMenuActionSet = [[ { icon: MoveToIcon, name: "Move to", - execute: dispatch => dispatch(openMoveToDialog()) + execute: (dispatch, resource) => dispatch(openMoveToDialog({ + name: resource.name, + uuid: resource.uuid, + kind: ResourceKind.COLLECTION + })) }, { component: ToggleFavoriteAction, diff --git a/src/views-components/context-menu/action-sets/project-action-set.ts b/src/views-components/context-menu/action-sets/project-action-set.ts index efba4578..e5c401a9 100644 --- a/src/views-components/context-menu/action-sets/project-action-set.ts +++ b/src/views-components/context-menu/action-sets/project-action-set.ts @@ -12,6 +12,7 @@ import { toggleFavorite } from "~/store/favorites/favorites-actions"; import { favoritePanelActions } from "~/store/favorite-panel/favorite-panel-action"; import { openMoveToDialog } from "../../move-to-dialog/move-to-dialog"; import { PROJECT_CREATE_DIALOG } from "../../dialog-create/dialog-project-create"; +import { ResourceKind } from '~/models/resource'; export const projectActionSet: ContextMenuActionSet = [[ { @@ -41,6 +42,10 @@ export const projectActionSet: ContextMenuActionSet = [[ { icon: MoveToIcon, name: "Move to", - execute: dispatch => dispatch(openMoveToDialog()) + execute: (dispatch, resource) => dispatch(openMoveToDialog({ + name: resource.name, + uuid: resource.uuid, + kind: ResourceKind.PROJECT + })) }, ]]; diff --git a/src/views-components/move-to-dialog/move-to-dialog.tsx b/src/views-components/move-to-dialog/move-to-dialog.tsx index 59396625..d7c66bc4 100644 --- a/src/views-components/move-to-dialog/move-to-dialog.tsx +++ b/src/views-components/move-to-dialog/move-to-dialog.tsx @@ -2,26 +2,87 @@ // // SPDX-License-Identifier: AGPL-3.0 +import * as React from "react"; import { Dispatch, compose } from "redux"; -import { withDialog } from "../../store/dialog/with-dialog"; -import { dialogActions } from "../../store/dialog/dialog-actions"; -import { MoveToDialog } from "../../components/move-to-dialog/move-to-dialog"; -import { reduxForm, startSubmit, stopSubmit } from "redux-form"; +import { withDialog } from "~/store/dialog/with-dialog"; +import { dialogActions } from "~/store/dialog/dialog-actions"; +import { reduxForm, startSubmit, stopSubmit, InjectedFormProps, initialize, Field, WrappedFieldProps } from 'redux-form'; +import { WithDialogProps } from '~/store/dialog/with-dialog'; +import { FormDialog } from '~/components/form-dialog/form-dialog'; +import { ProjectTreePicker } from '~/views-components/project-tree-picker/project-tree-picker'; +import { MOVE_TO_VALIDATION } from '~/validators/validators'; +import { Typography } from "@material-ui/core"; +import { ResourceKind } from '~/models/resource'; +import { ServiceRepository, getResourceService } from '~/services/services'; +import { RootState } from '~/store/store'; +import { getCommonResourceServiceError, CommonResourceServiceError } from "~/common/api/common-resource-service"; +import { snackbarActions } from '../../store/snackbar/snackbar-actions'; export const MOVE_TO_DIALOG = 'moveToDialog'; -export const openMoveToDialog = () => +export interface MoveToDialogResource { + name: string; + uuid: string; + ownerUuid: string; + kind: ResourceKind; +} + +export const openMoveToDialog = (resource: { name: string, uuid: string, kind: ResourceKind }) => (dispatch: Dispatch) => { + dispatch(initialize(MOVE_TO_DIALOG, resource)); dispatch(dialogActions.OPEN_DIALOG({ id: MOVE_TO_DIALOG, data: {} })); }; +export const moveResource = (resource: MoveToDialogResource) => + async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { + const service = getResourceService(resource.kind, services); + dispatch(startSubmit(MOVE_TO_DIALOG)); + if (service) { + try { + const originalResource = await service.get(resource.uuid); + await service.update(resource.uuid, { ...originalResource, owner_uuid: resource.ownerUuid }); + dispatch(dialogActions.CLOSE_DIALOG({ id: MOVE_TO_DIALOG })); + dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Resource has been moved', hideDuration: 2000 })); + } catch (e) { + const error = getCommonResourceServiceError(e); + if (error === CommonResourceServiceError.UNIQUE_VIOLATION) { + dispatch(stopSubmit(MOVE_TO_DIALOG, { ownerUuid: 'A resource with the same name already exists in the target project' })); + } else { + dispatch(dialogActions.CLOSE_DIALOG({ id: MOVE_TO_DIALOG })); + dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not move the resource.', hideDuration: 2000 })); + } + } + } + }; + export const MoveToProjectDialog = compose( withDialog(MOVE_TO_DIALOG), - reduxForm({ + reduxForm({ form: MOVE_TO_DIALOG, onSubmit: (data, dispatch) => { - dispatch(startSubmit(MOVE_TO_DIALOG)); - setTimeout(() => dispatch(stopSubmit(MOVE_TO_DIALOG, { name: 'Invalid path' })), 2000); + dispatch(moveResource(data)); } }) -)(MoveToDialog); +)((props: WithDialogProps & InjectedFormProps) => + ); + +const MoveToDialogFields = () => + ; + + +const Picker = (props: WrappedFieldProps) => +
+ props.input.onChange(projectUuid)} /> + {props.meta.dirty && props.meta.error && + + {props.meta.error} + } +
;