20031: Add collection partial move/copy to new/existing collection
authorStephen Smith <stephen@curii.com>
Mon, 10 Apr 2023 19:16:39 +0000 (15:16 -0400)
committerStephen Smith <stephen@curii.com>
Mon, 10 Apr 2023 19:16:39 +0000 (15:16 -0400)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

15 files changed:
cypress/integration/collection.spec.js
src/store/collection-panel/collection-panel-files/collection-panel-files-state.ts
src/store/collections/collection-partial-copy-actions.ts
src/store/collections/collection-partial-move-actions.ts [new file with mode: 0644]
src/views-components/context-menu/action-sets/collection-files-action-set.ts
src/views-components/dialog-copy/dialog-collection-partial-copy-to-existing-collection.tsx [moved from src/views-components/dialog-copy/dialog-partial-copy-to-collection.tsx with 76% similarity]
src/views-components/dialog-copy/dialog-collection-partial-copy-to-new-collection.tsx [moved from src/views-components/dialog-copy/dialog-collection-partial-copy.tsx with 68% similarity]
src/views-components/dialog-forms/partial-copy-collection-dialog.ts [deleted file]
src/views-components/dialog-forms/partial-copy-to-existing-collection-dialog.ts [moved from src/views-components/dialog-forms/partial-copy-to-collection-dialog.ts with 54% similarity]
src/views-components/dialog-forms/partial-copy-to-new-collection-dialog.ts [new file with mode: 0644]
src/views-components/dialog-forms/partial-move-to-existing-collection-dialog.ts [new file with mode: 0644]
src/views-components/dialog-forms/partial-move-to-new-collection-dialog.ts [new file with mode: 0644]
src/views-components/dialog-move/dialog-collection-partial-move-to-existing-collection.tsx [new file with mode: 0644]
src/views-components/dialog-move/dialog-collection-partial-move-to-new-collection.tsx [new file with mode: 0644]
src/views/workbench/workbench.tsx

index 1a66600c8a8e6b995f0bb71696e9382a56e7b56f..977a28c2ff8712974de0380c4e0d8f656a390389 100644 (file)
@@ -922,7 +922,7 @@ describe('Collection panel tests', function () {
                 });
 
                 cy.get('[data-cy=collection-files-panel-options-btn]').click();
-                cy.get('[data-cy=context-menu]').contains('Create a new collection with selected').click();
+                cy.get('[data-cy=context-menu]').contains('Copy selected into new collection').click();
 
                 cy.get('[data-cy=form-dialog]').contains('Projects').click();
 
index 0044a66d84b201dca481a1028a54a9d9604106a1..405e7eac093040a8bbfd80ce7f3f5700d1b0c456 100644 (file)
@@ -40,5 +40,8 @@ export const filterCollectionFilesBySelection = (tree: CollectionPanelFilesState
     const allFiles = getNodeDescendants('')(tree).map(node => node.value);
     const selectedDirectories = allFiles.filter(file => file.selected === selected && file.type === CollectionFileType.DIRECTORY);
     const selectedFiles = allFiles.filter(file => file.selected === selected && !selectedDirectories.some(dir => dir.id === file.path));
-    return [...selectedDirectories, ...selectedFiles];
+    return [...selectedDirectories, ...selectedFiles]
+        .filter((value, index, array) => (
+            array.indexOf(value) === index
+        ));
 };
index a0c4e4e490d3476bea7ef247d076c6b23a269289..73d117c26cc8da2a5fd12e0633b688c6cc0768c7 100644 (file)
@@ -3,7 +3,6 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import { Dispatch } from 'redux';
-import { difference } from "lodash";
 import { RootState } from 'store/store';
 import { FormErrors, initialize, startSubmit, stopSubmit } from 'redux-form';
 import { resetPickerProjectTree } from 'store/project-tree-picker/project-tree-picker-actions';
@@ -14,21 +13,22 @@ import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
 import { getCommonResourceServiceError, CommonResourceServiceError } from 'services/common-service/common-resource-service';
 import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions";
 import { initProjectsTreePicker } from "store/tree-picker/tree-picker-actions";
+import { updateResources } from 'store/resources/resources-actions';
 
 export const COLLECTION_PARTIAL_COPY_FORM_NAME = 'COLLECTION_PARTIAL_COPY_DIALOG';
 export const COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION = 'COLLECTION_PARTIAL_COPY_TO_SELECTED_DIALOG';
 
-export interface CollectionPartialCopyFormData {
+export interface CollectionPartialCopyToNewCollectionFormData {
     name: string;
     description: string;
     projectUuid: string;
 }
 
-export interface CollectionPartialCopyToSelectedCollectionFormData {
+export interface CollectionPartialCopyToExistingCollectionFormData {
     collectionUuid: string;
 }
 
-export const openCollectionPartialCopyDialog = () =>
+export const openCollectionPartialCopyToNewCollectionDialog = () =>
     (dispatch: Dispatch, getState: () => RootState) => {
         const currentCollection = getState().collectionPanel.item;
         if (currentCollection) {
@@ -44,7 +44,7 @@ export const openCollectionPartialCopyDialog = () =>
         }
     };
 
-export const copyCollectionPartial = ({ name, description, projectUuid }: CollectionPartialCopyFormData) =>
+export const copyCollectionPartialToNewCollection = ({ name, description, projectUuid }: CollectionPartialCopyToNewCollectionFormData) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(startSubmit(COLLECTION_PARTIAL_COPY_FORM_NAME));
         const state = getState();
@@ -93,7 +93,7 @@ export const copyCollectionPartial = ({ name, description, projectUuid }: Collec
         }
     };
 
-export const openCollectionPartialCopyToSelectedCollectionDialog = () =>
+export const openCollectionPartialCopyToExistingCollectionDialog = () =>
     (dispatch: Dispatch, getState: () => RootState) => {
         const currentCollection = getState().collectionPanel.item;
         if (currentCollection) {
@@ -107,37 +107,24 @@ export const openCollectionPartialCopyToSelectedCollectionDialog = () =>
         }
     };
 
-export const copyCollectionPartialToSelectedCollection = ({ collectionUuid }: CollectionPartialCopyToSelectedCollectionFormData) =>
+export const copyCollectionPartialToExistingCollection = ({ collectionUuid }: CollectionPartialCopyToExistingCollectionFormData) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        dispatch(startSubmit(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
         const state = getState();
-        const currentCollection = state.collectionPanel.item;
-
-        if (currentCollection && !currentCollection.manifestText) {
-            const fetchedCurrentCollection = await services.collectionService.get(currentCollection.uuid, undefined, ['manifestText']);
-            currentCollection.manifestText = fetchedCurrentCollection.manifestText;
-            currentCollection.unsignedManifestText = fetchedCurrentCollection.unsignedManifestText;
-        }
+        // Get current collection
+        const sourceCollection = state.collectionPanel.item;
 
-        if (currentCollection) {
+        if (sourceCollection) {
             try {
+                dispatch(startSubmit(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
                 dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
-                const selectedCollection = await services.collectionService.get(collectionUuid);
-                const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, false).map(file => file.id);
-                const pathsToRemove = paths.filter(path => {
-                    const a = path.split('/');
-                    const fileExistsInSelectedCollection = selectedCollection.manifestText.includes(a[1]);
-                    if (fileExistsInSelectedCollection) {
-                        return path;
-                    } else {
-                        return null;
-                    }
-                });
-                const diffPathToRemove = difference(paths, pathsToRemove);
-                await services.collectionService.deleteFiles(selectedCollection.uuid, pathsToRemove.map(path => path.replace(currentCollection.uuid, collectionUuid)));
-                const collectionWithDeletedFiles = await services.collectionService.get(collectionUuid, undefined, ['uuid', 'manifestText']);
-                await services.collectionService.update(collectionUuid, { manifestText: `${collectionWithDeletedFiles.manifestText}${(currentCollection.manifestText ? currentCollection.manifestText : currentCollection.unsignedManifestText) || ''}` });
-                await services.collectionService.deleteFiles(collectionWithDeletedFiles.uuid, diffPathToRemove.map(path => path.replace(currentCollection.uuid, collectionUuid)));
+                // Get selected files
+                const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, true)
+                    .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
+
+                // Copy files
+                const updatedCollection = await services.collectionService.copyFiles(sourceCollection.portableDataHash, paths, collectionUuid, '/', false);
+                dispatch(updateResources([updatedCollection]));
+
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION }));
                 dispatch(snackbarActions.OPEN_SNACKBAR({
                     message: 'Files has been copied to selected collection.',
@@ -154,4 +141,4 @@ export const copyCollectionPartialToSelectedCollection = ({ collectionUuid }: Co
                 dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION));
             }
         }
-    };
\ No newline at end of file
+    };
diff --git a/src/store/collections/collection-partial-move-actions.ts b/src/store/collections/collection-partial-move-actions.ts
new file mode 100644 (file)
index 0000000..19cac52
--- /dev/null
@@ -0,0 +1,140 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { Dispatch } from "redux";
+import { initialize, startSubmit } from "redux-form";
+import { CommonResourceServiceError, getCommonResourceServiceError } from "services/common-service/common-resource-service";
+import { ServiceRepository } from "services/services";
+import { filterCollectionFilesBySelection } from "store/collection-panel/collection-panel-files/collection-panel-files-state";
+import { dialogActions } from "store/dialog/dialog-actions";
+import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions";
+import { resetPickerProjectTree } from "store/project-tree-picker/project-tree-picker-actions";
+import { updateResources } from "store/resources/resources-actions";
+import { SnackbarKind, snackbarActions } from "store/snackbar/snackbar-actions";
+import { RootState } from "store/store";
+import { initProjectsTreePicker } from "store/tree-picker/tree-picker-actions";
+
+export const COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION = 'COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION_DIALOG';
+export const COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION = 'COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION_DIALOG';
+
+export interface CollectionPartialMoveToNewCollectionFormData {
+    name: string;
+    description: string;
+    projectUuid: string;
+}
+
+export interface CollectionPartialMoveToExistingCollectionFormData {
+    collectionUuid: string;
+}
+
+export const openCollectionPartialMoveToNewCollectionDialog = () =>
+    (dispatch: Dispatch, getState: () => RootState) => {
+        const currentCollection = getState().collectionPanel.item;
+        if (currentCollection) {
+            const initialData = {
+                name: `Files moved from: ${currentCollection.name}`,
+                description: currentCollection.description,
+                projectUuid: undefined
+            };
+            dispatch(initialize(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION, initialData));
+            dispatch<any>(resetPickerProjectTree());
+            dispatch<any>(initProjectsTreePicker(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION));
+            dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION, data: {} }));
+        }
+    };
+
+export const moveCollectionPartialToNewCollection = ({ name, description, projectUuid }: CollectionPartialMoveToNewCollectionFormData) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const state = getState();
+        // Get current collection
+        const sourceCollection = state.collectionPanel.item;
+
+        if (sourceCollection) {
+            try {
+                dispatch(startSubmit(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION));
+                dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION));
+
+                // Create new collection
+                const newCollection = await services.collectionService.create({
+                    name,
+                    description,
+                    ownerUuid: projectUuid,
+                    uuid: undefined,
+                });
+
+                // Get selected files
+                const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, true)
+                    .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
+
+                // Move files
+                const updatedCollection = await services.collectionService.moveFiles(sourceCollection.uuid, sourceCollection.portableDataHash, paths, newCollection.uuid, '/', false);
+                dispatch(updateResources([updatedCollection]));
+
+                dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION }));
+                dispatch(snackbarActions.OPEN_SNACKBAR({
+                    message: 'Files have been moved to selected collection.',
+                    hideDuration: 2000,
+                    kind: SnackbarKind.SUCCESS
+                }));
+                dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION));
+            } catch (e) {
+                const error = getCommonResourceServiceError(e);
+                if (error === CommonResourceServiceError.UNKNOWN) {
+                    dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION }));
+                    dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not move files to selected collection', hideDuration: 2000, kind: SnackbarKind.ERROR }));
+                }
+                dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION));
+            }
+        }
+    };
+
+export const openCollectionPartialMoveToExistingCollectionDialog = () =>
+    (dispatch: Dispatch, getState: () => RootState) => {
+        const currentCollection = getState().collectionPanel.item;
+        if (currentCollection) {
+            const initialData = {
+                collectionUuid: ''
+            };
+            dispatch(initialize(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION, initialData));
+            dispatch<any>(resetPickerProjectTree());
+            dispatch<any>(initProjectsTreePicker(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION));
+            dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION, data: {} }));
+        }
+    };
+
+export const moveCollectionPartialToExistingCollection = ({ collectionUuid }: CollectionPartialMoveToExistingCollectionFormData) =>
+    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const state = getState();
+        // Get current collection
+        const sourceCollection = state.collectionPanel.item;
+
+        if (sourceCollection) {
+            try {
+                dispatch(startSubmit(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION));
+                dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION));
+                // Get selected files
+                const paths = filterCollectionFilesBySelection(state.collectionPanelFiles, true)
+                    .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
+
+                // Move files
+                const updatedCollection = await services.collectionService.moveFiles(sourceCollection.uuid, sourceCollection.portableDataHash, paths, collectionUuid, '/', false);
+                dispatch(updateResources([updatedCollection]));
+
+                dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION }));
+                dispatch(snackbarActions.OPEN_SNACKBAR({
+                    message: 'Files have been moved to selected collection.',
+                    hideDuration: 2000,
+                    kind: SnackbarKind.SUCCESS
+                }));
+                dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION));
+            } catch (e) {
+                const error = getCommonResourceServiceError(e);
+                if (error === CommonResourceServiceError.UNKNOWN) {
+                    dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION }));
+                    dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not copy this files to selected collection', hideDuration: 2000, kind: SnackbarKind.ERROR }));
+                }
+                dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION));
+            }
+        }
+    };
index f34f286840c362dbc29d9cea96428df3d7da38cc..3e6e1a201a9b48b528b911ae427b9a5511ef33cf 100644 (file)
@@ -5,10 +5,10 @@
 import { ContextMenuActionSet } from "views-components/context-menu/context-menu-action-set";
 import { collectionPanelFilesAction, openMultipleFilesRemoveDialog } from "store/collection-panel/collection-panel-files/collection-panel-files-actions";
 import {
-    openCollectionPartialCopyDialog,
-    // Disabled while addressing #18587
-    // openCollectionPartialCopyToSelectedCollectionDialog
+    openCollectionPartialCopyToNewCollectionDialog,
+    openCollectionPartialCopyToExistingCollectionDialog
 } from 'store/collections/collection-partial-copy-actions';
+import { openCollectionPartialMoveToExistingCollectionDialog, openCollectionPartialMoveToNewCollectionDialog } from "store/collections/collection-partial-move-actions";
 
 // These action sets are used on the multi-select actions button.
 export const readOnlyCollectionFilesActionSet: ContextMenuActionSet = [[
@@ -25,18 +25,17 @@ export const readOnlyCollectionFilesActionSet: ContextMenuActionSet = [[
         }
     },
     {
-        name: "Create a new collection with selected",
+        name: "Copy selected into new collection",
         execute: dispatch => {
-            dispatch<any>(openCollectionPartialCopyDialog());
+            dispatch<any>(openCollectionPartialCopyToNewCollectionDialog());
         }
     },
-    // Disabled while addressing #18587
-    // {
-    //     name: "Copy selected into the collection",
-    //     execute: dispatch => {
-    //         dispatch<any>(openCollectionPartialCopyToSelectedCollectionDialog());
-    //     }
-    // }
+    {
+        name: "Copy selected into existing collection",
+        execute: dispatch => {
+            dispatch<any>(openCollectionPartialCopyToExistingCollectionDialog());
+        }
+    }
 ]];
 
 export const collectionFilesActionSet: ContextMenuActionSet = readOnlyCollectionFilesActionSet.concat([[
@@ -46,4 +45,16 @@ export const collectionFilesActionSet: ContextMenuActionSet = readOnlyCollection
             dispatch(openMultipleFilesRemoveDialog());
         }
     },
+    {
+        name: "Move selected into new collection",
+        execute: dispatch => {
+            dispatch<any>(openCollectionPartialMoveToNewCollectionDialog());
+        }
+    },
+    {
+        name: "Move selected into existing collection",
+        execute: dispatch => {
+            dispatch<any>(openCollectionPartialMoveToExistingCollectionDialog());
+        }
+    }
 ]]);
similarity index 76%
rename from src/views-components/dialog-copy/dialog-partial-copy-to-collection.tsx
rename to src/views-components/dialog-copy/dialog-collection-partial-copy-to-existing-collection.tsx
index 4e9dde6a12bc2ef56e1fafa1cf34d73329e660d8..1af9dfeecf84faddc0b5c3496987b3a8b6bc695d 100644 (file)
@@ -7,21 +7,21 @@ import { memoize } from "lodash/fp";
 import { FormDialog } from 'components/form-dialog/form-dialog';
 import { WithDialogProps } from 'store/dialog/with-dialog';
 import { InjectedFormProps } from 'redux-form';
-import { CollectionPartialCopyToSelectedCollectionFormData } from 'store/collections/collection-partial-copy-actions';
+import { CollectionPartialCopyToExistingCollectionFormData } from 'store/collections/collection-partial-copy-actions';
 import { PickerIdProp } from "store/tree-picker/picker-id";
 import { CollectionPickerField } from 'views-components/form-fields/collection-form-fields';
 
-type DialogCollectionPartialCopyProps = WithDialogProps<string> & InjectedFormProps<CollectionPartialCopyToSelectedCollectionFormData>;
+type DialogCollectionPartialCopyProps = WithDialogProps<string> & InjectedFormProps<CollectionPartialCopyToExistingCollectionFormData>;
 
-export const DialogCollectionPartialCopyToSelectedCollection = (props: DialogCollectionPartialCopyProps & PickerIdProp) =>
+export const DialogCollectionPartialCopyToExistingCollection = (props: DialogCollectionPartialCopyProps & PickerIdProp) =>
     <FormDialog
-        dialogTitle='Choose collection'
+        dialogTitle='Copy to existing collection'
         formFields={CollectionPartialCopyFields(props.pickerId)}
         submitLabel='Copy files'
         {...props}
     />;
 
-export const CollectionPartialCopyFields = memoize(
+const CollectionPartialCopyFields = memoize(
     (pickerId: string) =>
         () =>
             <>
similarity index 68%
rename from src/views-components/dialog-copy/dialog-collection-partial-copy.tsx
rename to src/views-components/dialog-copy/dialog-collection-partial-copy-to-new-collection.tsx
index 3c584e4f51452381d56296e753ad182123af82f2..6b5a7759e5ccfbbfcac7ffc119d4a415ede7472b 100644 (file)
@@ -8,20 +8,20 @@ import { FormDialog } from 'components/form-dialog/form-dialog';
 import { CollectionNameField, CollectionDescriptionField, CollectionProjectPickerField } from 'views-components/form-fields/collection-form-fields';
 import { WithDialogProps } from 'store/dialog/with-dialog';
 import { InjectedFormProps } from 'redux-form';
-import { CollectionPartialCopyFormData } from 'store/collections/collection-partial-copy-actions';
+import { CollectionPartialCopyToNewCollectionFormData } from 'store/collections/collection-partial-copy-actions';
 import { PickerIdProp } from "store/tree-picker/picker-id";
 
-type DialogCollectionPartialCopyProps = WithDialogProps<string> & InjectedFormProps<CollectionPartialCopyFormData>;
+type DialogCollectionPartialCopyProps = WithDialogProps<string> & InjectedFormProps<CollectionPartialCopyToNewCollectionFormData>;
 
-export const DialogCollectionPartialCopy = (props: DialogCollectionPartialCopyProps & PickerIdProp) =>
+export const DialogCollectionPartialCopyToNewCollection = (props: DialogCollectionPartialCopyProps & PickerIdProp) =>
     <FormDialog
-        dialogTitle='Create a collection'
+        dialogTitle='Copy to new collection'
         formFields={CollectionPartialCopyFields(props.pickerId)}
-        submitLabel='Create collection'
+        submitLabel='Create collection'
         {...props}
     />;
 
-export const CollectionPartialCopyFields = memoize(
+const CollectionPartialCopyFields = memoize(
     (pickerId: string) =>
         () =>
             <>
diff --git a/src/views-components/dialog-forms/partial-copy-collection-dialog.ts b/src/views-components/dialog-forms/partial-copy-collection-dialog.ts
deleted file mode 100644 (file)
index 3630ffb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import { compose } from "redux";
-import { reduxForm } from 'redux-form';
-import { withDialog, } from 'store/dialog/with-dialog';
-import { CollectionPartialCopyFormData, copyCollectionPartial, COLLECTION_PARTIAL_COPY_FORM_NAME } from 'store/collections/collection-partial-copy-actions';
-import { DialogCollectionPartialCopy } from "views-components/dialog-copy/dialog-collection-partial-copy";
-import { pickerId } from "store/tree-picker/picker-id";
-
-
-export const PartialCopyCollectionDialog = compose(
-    withDialog(COLLECTION_PARTIAL_COPY_FORM_NAME),
-    reduxForm<CollectionPartialCopyFormData>({
-        form: COLLECTION_PARTIAL_COPY_FORM_NAME,
-        onSubmit: (data, dispatch) => {
-            dispatch(copyCollectionPartial(data));
-        }
-    }),
-    pickerId(COLLECTION_PARTIAL_COPY_FORM_NAME),
-)(DialogCollectionPartialCopy);
\ No newline at end of file
similarity index 54%
rename from src/views-components/dialog-forms/partial-copy-to-collection-dialog.ts
rename to src/views-components/dialog-forms/partial-copy-to-existing-collection-dialog.ts
index d7b33929b70e340b1a0ec1f24d3ae3b415ae0c84..8fe57f2dc367d89925e4ed538a377e5b5d1beee7 100644 (file)
@@ -5,17 +5,17 @@
 import { compose } from "redux";
 import { reduxForm } from 'redux-form';
 import { withDialog, } from 'store/dialog/with-dialog';
-import { CollectionPartialCopyToSelectedCollectionFormData, copyCollectionPartialToSelectedCollection, COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION } from 'store/collections/collection-partial-copy-actions';
-import { DialogCollectionPartialCopyToSelectedCollection } from "views-components/dialog-copy/dialog-partial-copy-to-collection";
+import { CollectionPartialCopyToExistingCollectionFormData, copyCollectionPartialToExistingCollection, COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION } from 'store/collections/collection-partial-copy-actions';
+import { DialogCollectionPartialCopyToExistingCollection } from "views-components/dialog-copy/dialog-collection-partial-copy-to-existing-collection";
 import { pickerId } from "store/tree-picker/picker-id";
 
-export const PartialCopyToCollectionDialog = compose(
+export const PartialCopyToExistingCollectionDialog = compose(
     withDialog(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION),
-    reduxForm<CollectionPartialCopyToSelectedCollectionFormData>({
+    reduxForm<CollectionPartialCopyToExistingCollectionFormData>({
         form: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION,
         onSubmit: (data, dispatch) => {
-            dispatch(copyCollectionPartialToSelectedCollection(data));
+            dispatch(copyCollectionPartialToExistingCollection(data));
         }
     }),
     pickerId(COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION),
-)(DialogCollectionPartialCopyToSelectedCollection);
\ No newline at end of file
+)(DialogCollectionPartialCopyToExistingCollection);
diff --git a/src/views-components/dialog-forms/partial-copy-to-new-collection-dialog.ts b/src/views-components/dialog-forms/partial-copy-to-new-collection-dialog.ts
new file mode 100644 (file)
index 0000000..40bb147
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { compose } from "redux";
+import { reduxForm } from 'redux-form';
+import { withDialog, } from 'store/dialog/with-dialog';
+import { CollectionPartialCopyToNewCollectionFormData, copyCollectionPartialToNewCollection, COLLECTION_PARTIAL_COPY_FORM_NAME } from 'store/collections/collection-partial-copy-actions';
+import { DialogCollectionPartialCopyToNewCollection } from "views-components/dialog-copy/dialog-collection-partial-copy-to-new-collection";
+import { pickerId } from "store/tree-picker/picker-id";
+
+export const PartialCopyToNewCollectionDialog = compose(
+    withDialog(COLLECTION_PARTIAL_COPY_FORM_NAME),
+    reduxForm<CollectionPartialCopyToNewCollectionFormData>({
+        form: COLLECTION_PARTIAL_COPY_FORM_NAME,
+        onSubmit: (data, dispatch) => {
+            dispatch(copyCollectionPartialToNewCollection(data));
+        }
+    }),
+    pickerId(COLLECTION_PARTIAL_COPY_FORM_NAME),
+)(DialogCollectionPartialCopyToNewCollection);
diff --git a/src/views-components/dialog-forms/partial-move-to-existing-collection-dialog.ts b/src/views-components/dialog-forms/partial-move-to-existing-collection-dialog.ts
new file mode 100644 (file)
index 0000000..cb18a66
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { compose } from "redux";
+import { reduxForm } from 'redux-form';
+import { withDialog, } from 'store/dialog/with-dialog';
+import { COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION, CollectionPartialMoveToExistingCollectionFormData, moveCollectionPartialToExistingCollection } from "store/collections/collection-partial-move-actions";
+import { DialogCollectionPartialMoveToExistingCollection } from "views-components/dialog-move/dialog-collection-partial-move-to-existing-collection";
+import { pickerId } from "store/tree-picker/picker-id";
+
+export const PartialMoveToExistingCollectionDialog = compose(
+    withDialog(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION),
+    reduxForm<CollectionPartialMoveToExistingCollectionFormData>({
+        form: COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION,
+        onSubmit: (data, dispatch) => {
+            dispatch(moveCollectionPartialToExistingCollection(data));
+        }
+    }),
+    pickerId(COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION),
+)(DialogCollectionPartialMoveToExistingCollection);
diff --git a/src/views-components/dialog-forms/partial-move-to-new-collection-dialog.ts b/src/views-components/dialog-forms/partial-move-to-new-collection-dialog.ts
new file mode 100644 (file)
index 0000000..d7251c8
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import { compose } from "redux";
+import { reduxForm } from 'redux-form';
+import { withDialog, } from 'store/dialog/with-dialog';
+import { COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION, CollectionPartialMoveToNewCollectionFormData, moveCollectionPartialToNewCollection } from "store/collections/collection-partial-move-actions";
+import { DialogCollectionPartialMoveToNewCollection } from "views-components/dialog-move/dialog-collection-partial-move-to-new-collection";
+import { pickerId } from "store/tree-picker/picker-id";
+
+export const PartialMoveToNewCollectionDialog = compose(
+    withDialog(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION),
+    reduxForm<CollectionPartialMoveToNewCollectionFormData>({
+        form: COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION,
+        onSubmit: (data, dispatch) => {
+            dispatch(moveCollectionPartialToNewCollection(data));
+        }
+    }),
+    pickerId(COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION),
+)(DialogCollectionPartialMoveToNewCollection);
diff --git a/src/views-components/dialog-move/dialog-collection-partial-move-to-existing-collection.tsx b/src/views-components/dialog-move/dialog-collection-partial-move-to-existing-collection.tsx
new file mode 100644 (file)
index 0000000..e808103
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from "react";
+import { memoize } from "lodash/fp";
+import { FormDialog } from 'components/form-dialog/form-dialog';
+import { WithDialogProps } from 'store/dialog/with-dialog';
+import { InjectedFormProps } from 'redux-form';
+import { CollectionPartialMoveToExistingCollectionFormData } from "store/collections/collection-partial-move-actions";
+import { PickerIdProp } from "store/tree-picker/picker-id";
+import { CollectionPickerField } from 'views-components/form-fields/collection-form-fields';
+
+type DialogCollectionPartialMoveProps = WithDialogProps<string> & InjectedFormProps<CollectionPartialMoveToExistingCollectionFormData>;
+
+export const DialogCollectionPartialMoveToExistingCollection = (props: DialogCollectionPartialMoveProps & PickerIdProp) =>
+    <FormDialog
+        dialogTitle='Move to existing collection'
+        formFields={CollectionPartialMoveFields(props.pickerId)}
+        submitLabel='Move files'
+        {...props}
+    />;
+
+const CollectionPartialMoveFields = memoize(
+    (pickerId: string) =>
+        () =>
+            <>
+                <CollectionPickerField {...{ pickerId }}/>
+            </>);
diff --git a/src/views-components/dialog-move/dialog-collection-partial-move-to-new-collection.tsx b/src/views-components/dialog-move/dialog-collection-partial-move-to-new-collection.tsx
new file mode 100644 (file)
index 0000000..a33f377
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from "react";
+import { memoize } from "lodash/fp";
+import { FormDialog } from 'components/form-dialog/form-dialog';
+import { CollectionNameField, CollectionDescriptionField, CollectionProjectPickerField } from 'views-components/form-fields/collection-form-fields';
+import { WithDialogProps } from 'store/dialog/with-dialog';
+import { InjectedFormProps } from 'redux-form';
+import { CollectionPartialMoveToNewCollectionFormData } from "store/collections/collection-partial-move-actions";
+import { PickerIdProp } from "store/tree-picker/picker-id";
+
+type DialogCollectionPartialMoveProps = WithDialogProps<string> & InjectedFormProps<CollectionPartialMoveToNewCollectionFormData>;
+
+export const DialogCollectionPartialMoveToNewCollection = (props: DialogCollectionPartialMoveProps & PickerIdProp) =>
+    <FormDialog
+        dialogTitle='Move to new collection'
+        formFields={CollectionPartialMoveFields(props.pickerId)}
+        submitLabel='Create collection'
+        {...props}
+    />;
+
+const CollectionPartialMoveFields = memoize(
+    (pickerId: string) =>
+        () =>
+            <>
+                <CollectionNameField />
+                <CollectionDescriptionField />
+                <CollectionProjectPickerField {...{ pickerId }} />
+            </>);
index d549c52935136d42c6fb295b71269a5750a04c4a..5b1fff39b9bcefedf2a9fb354f54affa67d79a31 100644 (file)
@@ -32,7 +32,10 @@ import { MoveProcessDialog } from 'views-components/dialog-forms/move-process-di
 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 { PartialCopyToNewCollectionDialog } from 'views-components/dialog-forms/partial-copy-to-new-collection-dialog';
+import { PartialCopyToExistingCollectionDialog } from 'views-components/dialog-forms/partial-copy-to-existing-collection-dialog';
+import { PartialMoveToNewCollectionDialog } from 'views-components/dialog-forms/partial-move-to-new-collection-dialog';
+import { PartialMoveToExistingCollectionDialog } from 'views-components/dialog-forms/partial-move-to-existing-collection-dialog';
 import { RemoveProcessDialog } from 'views-components/process-remove-dialog/process-remove-dialog';
 import { MainContentBar } from 'views-components/main-content-bar/main-content-bar';
 import { Grid } from '@material-ui/core';
@@ -88,7 +91,6 @@ import { GroupAttributesDialog } from 'views-components/groups-dialog/attributes
 import { GroupDetailsPanel } from 'views/group-details-panel/group-details-panel';
 import { RemoveGroupMemberDialog } from 'views-components/groups-dialog/member-remove-dialog';
 import { GroupMemberAttributesDialog } from 'views-components/groups-dialog/member-attributes-dialog';
-import { PartialCopyToCollectionDialog } from 'views-components/dialog-forms/partial-copy-to-collection-dialog';
 import { PublicFavoritePanel } from 'views/public-favorites-panel/public-favorites-panel';
 import { LinkAccountPanel } from 'views/link-account-panel/link-account-panel';
 import { FedLogin } from './fed-login';
@@ -264,8 +266,10 @@ export const WorkbenchPanel =
             <MoveProjectDialog />
             <MultipleFilesRemoveDialog />
             <PublicKeyDialog />
-            <PartialCopyCollectionDialog />
-            <PartialCopyToCollectionDialog />
+            <PartialCopyToNewCollectionDialog />
+            <PartialCopyToExistingCollectionDialog />
+            <PartialMoveToNewCollectionDialog />
+            <PartialMoveToExistingCollectionDialog />
             <ProcessInputDialog />
             <RestoreCollectionVersionDialog />
             <RemoveApiClientAuthorizationDialog />