1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as React from "react";
6 import { Dispatch, compose } from "redux";
7 import { withDialog } from "~/store/dialog/with-dialog";
8 import { dialogActions } from "~/store/dialog/dialog-actions";
9 import { reduxForm, startSubmit, stopSubmit, InjectedFormProps, initialize, Field, WrappedFieldProps } from 'redux-form';
10 import { WithDialogProps } from '~/store/dialog/with-dialog';
11 import { FormDialog } from '~/components/form-dialog/form-dialog';
12 import { ProjectTreePicker } from '~/views-components/project-tree-picker/project-tree-picker';
13 import { MOVE_TO_VALIDATION } from '~/validators/validators';
14 import { Typography } from "@material-ui/core";
15 import { ResourceKind } from '~/models/resource';
16 import { ServiceRepository, getResourceService } from '~/services/services';
17 import { RootState } from '~/store/store';
18 import { getCommonResourceServiceError, CommonResourceServiceError } from "~/common/api/common-resource-service";
19 import { snackbarActions } from '../../store/snackbar/snackbar-actions';
21 export const MOVE_TO_DIALOG = 'moveToDialog';
23 export interface MoveToDialogResource {
30 export const openMoveToDialog = (resource: { name: string, uuid: string, kind: ResourceKind }) =>
31 (dispatch: Dispatch) => {
32 dispatch(initialize(MOVE_TO_DIALOG, resource));
33 dispatch(dialogActions.OPEN_DIALOG({ id: MOVE_TO_DIALOG, data: {} }));
36 export const moveResource = (resource: MoveToDialogResource) =>
37 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
38 const service = getResourceService(resource.kind, services);
39 dispatch(startSubmit(MOVE_TO_DIALOG));
42 const originalResource = await service.get(resource.uuid);
43 await service.update(resource.uuid, { ...originalResource, owner_uuid: resource.ownerUuid });
44 dispatch(dialogActions.CLOSE_DIALOG({ id: MOVE_TO_DIALOG }));
45 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Resource has been moved', hideDuration: 2000 }));
47 const error = getCommonResourceServiceError(e);
48 if (error === CommonResourceServiceError.UNIQUE_VIOLATION) {
49 dispatch(stopSubmit(MOVE_TO_DIALOG, { ownerUuid: 'A resource with the same name already exists in the target project' }));
51 dispatch(dialogActions.CLOSE_DIALOG({ id: MOVE_TO_DIALOG }));
52 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not move the resource.', hideDuration: 2000 }));
58 export const MoveToProjectDialog = compose(
59 withDialog(MOVE_TO_DIALOG),
60 reduxForm<MoveToDialogResource>({
62 onSubmit: (data, dispatch) => {
63 dispatch(moveResource(data));
66 )((props: WithDialogProps<string> & InjectedFormProps<MoveToDialogResource>) =>
69 formFields={MoveToDialogFields}
74 const MoveToDialogFields = () =>
78 validate={MOVE_TO_VALIDATION} />;
81 const Picker = (props: WrappedFieldProps) =>
82 <div style={{ height: '144px', display: 'flex', flexDirection: 'column' }}>
83 <ProjectTreePicker onChange={projectUuid => props.input.onChange(projectUuid)} />
84 {props.meta.dirty && props.meta.error &&
85 <Typography variant='caption' color='error'>