1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import { Dispatch } from 'redux';
6 import { RootState } from 'store/store';
7 import { FormErrors, initialize, startSubmit, stopSubmit } from 'redux-form';
8 import { resetPickerProjectTree } from 'store/project-tree-picker/project-tree-picker-actions';
9 import { dialogActions } from 'store/dialog/dialog-actions';
10 import { ServiceRepository } from 'services/services';
11 import { filterCollectionFilesBySelection } from '../collection-panel/collection-panel-files/collection-panel-files-state';
12 import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
13 import { getCommonResourceServiceError, CommonResourceServiceError } from 'services/common-service/common-resource-service';
14 import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions";
15 import { initProjectsTreePicker } from "store/tree-picker/tree-picker-actions";
16 import { updateResources } from 'store/resources/resources-actions';
17 import { navigateTo } from 'store/navigation/navigation-action';
19 export const COLLECTION_PARTIAL_COPY_FORM_NAME = 'COLLECTION_PARTIAL_COPY_DIALOG';
20 export const COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION = 'COLLECTION_PARTIAL_COPY_TO_SELECTED_DIALOG';
21 export const COLLECTION_PARTIAL_COPY_TO_SEPARATE_COLLECTIONS = 'COLLECTION_PARTIAL_COPY_TO_SEPARATE_DIALOG';
23 export interface CollectionPartialCopyToNewCollectionFormData {
29 export interface CollectionPartialCopyToExistingCollectionFormData {
30 destination: {uuid: string, path?: string};
33 export interface CollectionPartialCopyToSeparateCollectionsFormData {
38 export const openCollectionPartialCopyToNewCollectionDialog = () =>
39 (dispatch: Dispatch, getState: () => RootState) => {
40 const currentCollection = getState().collectionPanel.item;
41 if (currentCollection) {
43 name: `Files extracted from: ${currentCollection.name}`,
44 description: currentCollection.description,
45 projectUuid: undefined
47 dispatch(initialize(COLLECTION_PARTIAL_COPY_FORM_NAME, initialData));
48 dispatch<any>(resetPickerProjectTree());
49 dispatch<any>(initProjectsTreePicker(COLLECTION_PARTIAL_COPY_FORM_NAME));
50 dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME, data: {} }));
54 export const copyCollectionPartialToNewCollection = ({ name, description, projectUuid }: CollectionPartialCopyToNewCollectionFormData) =>
55 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
56 const state = getState();
57 // Get current collection
58 const sourceCollection = state.collectionPanel.item;
60 if (sourceCollection) {
62 dispatch(startSubmit(COLLECTION_PARTIAL_COPY_FORM_NAME));
63 dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));
66 const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, true)
67 .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
70 const updatedCollection = await services.collectionService.copyFiles(
71 sourceCollection.portableDataHash,
76 ownerUuid: projectUuid,
82 dispatch(updateResources([updatedCollection]));
83 dispatch<any>(navigateTo(updatedCollection.uuid))
85 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
86 dispatch(snackbarActions.OPEN_SNACKBAR({
87 message: 'New collection created.',
89 kind: SnackbarKind.SUCCESS
91 dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));
93 const error = getCommonResourceServiceError(e);
94 if (error === CommonResourceServiceError.UNIQUE_NAME_VIOLATION) {
95 dispatch(stopSubmit(COLLECTION_PARTIAL_COPY_FORM_NAME, { name: 'Collection with this name already exists.' } as FormErrors));
96 } else if (error === CommonResourceServiceError.UNKNOWN) {
97 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
98 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not create a copy of collection', hideDuration: 2000, kind: SnackbarKind.ERROR }));
100 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
101 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Collection has been copied but may contain incorrect files.', hideDuration: 2000, kind: SnackbarKind.ERROR }));
103 dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));
108 export const openCollectionPartialCopyToExistingCollectionDialog = () =>
109 (dispatch: Dispatch, getState: () => RootState) => {
110 const currentCollection = getState().collectionPanel.item;
111 if (currentCollection) {
112 const initialData = {
113 destination: {uuid: '', destinationPath: ''}
115 dispatch(initialize(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION, initialData));
116 dispatch<any>(resetPickerProjectTree());
117 dispatch<any>(initProjectsTreePicker(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
118 dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION, data: {} }));
122 export const copyCollectionPartialToExistingCollection = ({ destination }: CollectionPartialCopyToExistingCollectionFormData) =>
123 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
124 const state = getState();
125 // Get current collection
126 const sourceCollection = state.collectionPanel.item;
128 if (sourceCollection && destination.uuid) {
130 dispatch(startSubmit(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
131 dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
132 // Get selected files
133 const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, true)
134 .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
137 const updatedCollection = await services.collectionService.copyFiles(sourceCollection.portableDataHash, paths, {uuid: destination.uuid}, destination.path || '/', false);
138 dispatch(updateResources([updatedCollection]));
140 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION }));
141 dispatch(snackbarActions.OPEN_SNACKBAR({
142 message: 'Files has been copied to selected collection.',
144 kind: SnackbarKind.SUCCESS
146 dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
148 const error = getCommonResourceServiceError(e);
149 if (error === CommonResourceServiceError.UNKNOWN) {
150 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION }));
151 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not copy this files to selected collection', hideDuration: 2000, kind: SnackbarKind.ERROR }));
153 dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
158 export const openCollectionPartialCopyToSeparateCollectionsDialog = () =>
159 (dispatch: Dispatch, getState: () => RootState) => {
160 const currentCollection = getState().collectionPanel.item;
161 if (currentCollection) {
162 const initialData = {
163 name: currentCollection.name,
164 projectUuid: undefined
166 dispatch(initialize(COLLECTION_PARTIAL_COPY_TO_SEPARATE_COLLECTIONS, initialData));
167 dispatch<any>(resetPickerProjectTree());
168 dispatch<any>(initProjectsTreePicker(COLLECTION_PARTIAL_COPY_TO_SEPARATE_COLLECTIONS));
169 dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SEPARATE_COLLECTIONS, data: {} }));
173 export const copyCollectionPartialToSeparateCollections = ({ name, projectUuid }: CollectionPartialCopyToSeparateCollectionsFormData) =>
174 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
175 const state = getState();
176 // Get current collection
177 const sourceCollection = state.collectionPanel.item;
179 if (sourceCollection) {
181 dispatch(startSubmit(COLLECTION_PARTIAL_COPY_FORM_NAME));
182 dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));
184 // Get selected files
185 const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, true)
186 .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
189 const collections = await Promise.all(paths.map((path) =>
190 services.collectionService.copyFiles(
191 sourceCollection.portableDataHash,
194 name: `File split from collection ${name}${path}`,
195 ownerUuid: projectUuid,
202 dispatch(updateResources(collections));
204 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
205 dispatch(snackbarActions.OPEN_SNACKBAR({
206 message: 'New collections created.',
208 kind: SnackbarKind.SUCCESS
210 dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));
212 const error = getCommonResourceServiceError(e);
213 console.log(e, error);
214 if (error === CommonResourceServiceError.UNIQUE_NAME_VIOLATION) {
215 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Collection from one or more files already exists', hideDuration: 2000, kind: SnackbarKind.ERROR }));
216 } else if (error === CommonResourceServiceError.UNKNOWN) {
217 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
218 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not create a copy of collection', hideDuration: 2000, kind: SnackbarKind.ERROR }));
220 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
221 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Collection has been copied but may contain incorrect files.', hideDuration: 2000, kind: SnackbarKind.ERROR }));
223 dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));