f2dc551b1077296e5af73e05c759e228428c0bda
[arvados-workbench2.git] / src / store / collection-panel / collection-panel-files / collection-panel-files-actions.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { default as unionize, ofType, UnionOf } from "unionize";
6 import { Dispatch } from "redux";
7 import { CollectionFilesTree, CollectionFileType } from "~/models/collection-file";
8 import { ServiceRepository } from "~/services/services";
9 import { RootState } from "../../store";
10 import { snackbarActions } from "../../snackbar/snackbar-actions";
11 import { dialogActions } from '../../dialog/dialog-actions';
12 import { getNodeValue } from "~/models/tree";
13 import { filterCollectionFilesBySelection } from './collection-panel-files-state';
14 import { startSubmit, initialize, SubmissionError, stopSubmit } from 'redux-form';
15 import { loadProjectTreePickerProjects } from '../../../views-components/project-tree-picker/project-tree-picker';
16 import { getCommonResourceServiceError, CommonResourceServiceError } from "~/common/api/common-resource-service";
17
18 export const collectionPanelFilesAction = unionize({
19     SET_COLLECTION_FILES: ofType<CollectionFilesTree>(),
20     TOGGLE_COLLECTION_FILE_COLLAPSE: ofType<{ id: string }>(),
21     TOGGLE_COLLECTION_FILE_SELECTION: ofType<{ id: string }>(),
22     SELECT_ALL_COLLECTION_FILES: ofType<{}>(),
23     UNSELECT_ALL_COLLECTION_FILES: ofType<{}>(),
24 }, { tag: 'type', value: 'payload' });
25
26 export type CollectionPanelFilesAction = UnionOf<typeof collectionPanelFilesAction>;
27
28 export const loadCollectionFiles = (uuid: string) =>
29     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
30         const files = await services.collectionService.files(uuid);
31         dispatch(collectionPanelFilesAction.SET_COLLECTION_FILES(files));
32     };
33
34 export const removeCollectionFiles = (filePaths: string[]) =>
35     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
36         const currentCollection = getState().collectionPanel.item;
37         if (currentCollection) {
38             dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
39             await services.collectionService.deleteFiles(currentCollection.uuid, filePaths);
40             dispatch<any>(loadCollectionFiles(currentCollection.uuid));
41             dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000 }));
42         }
43     };
44
45 export const removeCollectionsSelectedFiles = () =>
46     (dispatch: Dispatch, getState: () => RootState) => {
47         const paths = filterCollectionFilesBySelection(getState().collectionPanelFiles, true).map(file => file.id);
48         dispatch<any>(removeCollectionFiles(paths));
49     };
50
51 export const FILE_REMOVE_DIALOG = 'fileRemoveDialog';
52
53 export const openFileRemoveDialog = (filePath: string) =>
54     (dispatch: Dispatch, getState: () => RootState) => {
55         const file = getNodeValue(filePath)(getState().collectionPanelFiles);
56         if (file) {
57             const title = file.type === CollectionFileType.DIRECTORY
58                 ? 'Removing directory'
59                 : 'Removing file';
60             const text = file.type === CollectionFileType.DIRECTORY
61                 ? 'Are you sure you want to remove this directory?'
62                 : 'Are you sure you want to remove this file?';
63
64             dispatch(dialogActions.OPEN_DIALOG({
65                 id: FILE_REMOVE_DIALOG,
66                 data: {
67                     title,
68                     text,
69                     confirmButtonLabel: 'Remove',
70                     filePath
71                 }
72             }));
73         }
74     };
75
76 export const MULTIPLE_FILES_REMOVE_DIALOG = 'multipleFilesRemoveDialog';
77
78 export const openMultipleFilesRemoveDialog = () =>
79     dialogActions.OPEN_DIALOG({
80         id: MULTIPLE_FILES_REMOVE_DIALOG,
81         data: {
82             title: 'Removing files',
83             text: 'Are you sure you want to remove selected files?',
84             confirmButtonLabel: 'Remove'
85         }
86     });
87
88 export const COLLECTION_PARTIAL_COPY = 'COLLECTION_PARTIAL_COPY';
89
90 export interface CollectionPartialCopyFormData {
91     name: string;
92     description: string;
93     projectUuid: string;
94 }
95
96 export const openCollectionPartialCopyDialog = () =>
97     (dispatch: Dispatch, getState: () => RootState) => {
98         const currentCollection = getState().collectionPanel.item;
99         if (currentCollection) {
100             const initialData = {
101                 name: currentCollection.name,
102                 description: currentCollection.description,
103                 projectUuid: ''
104             };
105             dispatch(initialize(COLLECTION_PARTIAL_COPY, initialData));
106             dispatch<any>(loadProjectTreePickerProjects(''));
107             dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_PARTIAL_COPY, data: {} }));
108         }
109     };
110
111 export const doCollectionPartialCopy = ({ name, description, projectUuid }: CollectionPartialCopyFormData) =>
112     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
113         dispatch(startSubmit(COLLECTION_PARTIAL_COPY));
114         const state = getState();
115         const currentCollection = state.collectionPanel.item;
116         if (currentCollection) {
117             try {
118                 const collection = await services.collectionService.get(currentCollection.uuid);
119                 const collectionCopy = {
120                     ...collection,
121                     name,
122                     description,
123                     ownerUuid: projectUuid,
124                     uuid: undefined
125                 };
126                 const newCollection = await services.collectionService.create(collectionCopy);
127                 const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, false).map(file => file.id);
128                 await services.collectionService.deleteFiles(newCollection.uuid, paths);
129                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY }));
130                 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'New collection created.', hideDuration: 2000 }));
131             } catch (e) {
132                 if (getCommonResourceServiceError(e) === CommonResourceServiceError.UNIQUE_VIOLATION) {
133                     dispatch(stopSubmit(COLLECTION_PARTIAL_COPY, { name: 'Collection with this name already exists.' }));
134                 }
135             }
136         }
137     };
138