[arvados-workbench2] updated: 2.6.0-85-g2bd3f83d

git repository hosting git at public.arvados.org
Wed Sep 6 21:08:30 UTC 2023


Summary of changes:
 .../collection-panel-files.tsx                     |  1 -
 src/components/data-explorer/data-explorer.tsx     |  3 ++
 src/components/data-table/data-table.tsx           |  3 +-
 .../multiselect-toolbar/MultiselectToolbar.tsx     |  2 +-
 src/store/collections/collection-copy-actions.ts   | 56 ++++++++++++----------
 src/store/copy-dialog/copy-dialog.ts               |  3 +-
 src/store/workbench/workbench-actions.ts           | 51 +++++++++++++-------
 .../action-sets/collection-action-set.ts           |  2 +-
 .../data-explorer/data-explorer.tsx                | 33 ++++++-------
 src/views-components/dialog-copy/dialog-copy.tsx   | 55 +++++++++++----------
 .../dialog-forms/copy-collection-dialog.ts         | 16 +++----
 11 files changed, 126 insertions(+), 99 deletions(-)

       via  2bd3f83db9934198b658b7035a7be65017b754d9 (commit)
      from  23575ae95aab42c4c4d9c2b5ee0236fab004dccb (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 2bd3f83db9934198b658b7035a7be65017b754d9
Author: Lisa Knox <lisaknox83 at gmail.com>
Date:   Wed Sep 6 17:08:25 2023 -0400

    15768: collection copy works except dialog Arvados-DCO-1.1-Signed-off-by: Lisa Knox <lisa.knox at curii.com>

diff --git a/src/components/collection-panel-files/collection-panel-files.tsx b/src/components/collection-panel-files/collection-panel-files.tsx
index 95dd4d4c..0fe933f5 100644
--- a/src/components/collection-panel-files/collection-panel-files.tsx
+++ b/src/components/collection-panel-files/collection-panel-files.tsx
@@ -278,7 +278,6 @@ export const CollectionPanelFiles = withStyles(styles)(
                             }
 
                             pathPromise[key] = true;
-                            console.log(key);
 
                             return webdavClient.propfind(`c=${key}`, webDAVRequestConfig);
                         }
diff --git a/src/components/data-explorer/data-explorer.tsx b/src/components/data-explorer/data-explorer.tsx
index f0f30c81..91d7dc77 100644
--- a/src/components/data-explorer/data-explorer.tsx
+++ b/src/components/data-explorer/data-explorer.tsx
@@ -83,6 +83,7 @@ interface DataExplorerDataProps<T> {
     currentItemUuid: string;
     elementPath?: string;
     isMSToolbarVisible: boolean;
+    checkedList: TCheckedList;
 }
 
 interface DataExplorerActionProps<T> {
@@ -188,6 +189,7 @@ export const DataExplorer = withStyles(styles)(
                 elementPath,
                 toggleMSToolbar,
                 setCheckedListOnStore,
+                checkedList,
             } = this.props;
             return (
                 <Paper
@@ -288,6 +290,7 @@ export const DataExplorer = withStyles(styles)(
                                 currentRoute={paperKey}
                                 toggleMSToolbar={toggleMSToolbar}
                                 setCheckedListOnStore={setCheckedListOnStore}
+                                checkedList={checkedList}
                             />
                         </Grid>
                         <Grid
diff --git a/src/components/data-table/data-table.tsx b/src/components/data-table/data-table.tsx
index ae68a6bc..c82f2ce3 100644
--- a/src/components/data-table/data-table.tsx
+++ b/src/components/data-table/data-table.tsx
@@ -53,6 +53,7 @@ export interface DataTableDataProps<I> {
     currentRoute?: string;
     toggleMSToolbar: (isVisible: boolean) => void;
     setCheckedListOnStore: (checkedList: TCheckedList) => void;
+    checkedList: TCheckedList;
 }
 
 type CssRules =
@@ -141,7 +142,7 @@ export const DataTable = withStyles(styles)(
     class Component<T> extends React.Component<DataTableProps<T>> {
         state: DataTableState = {
             isSelected: false,
-            checkedList: {},
+            checkedList: this.props.checkedList,
         };
 
         componentDidMount(): void {
diff --git a/src/components/multiselect-toolbar/MultiselectToolbar.tsx b/src/components/multiselect-toolbar/MultiselectToolbar.tsx
index b726cfa0..8c36f60f 100644
--- a/src/components/multiselect-toolbar/MultiselectToolbar.tsx
+++ b/src/components/multiselect-toolbar/MultiselectToolbar.tsx
@@ -176,6 +176,7 @@ function selectActionsByKind(currentResourceKinds: Array<string>, filterSet: TMu
 
 function mapStateToProps(state: RootState) {
     const { isVisible, checkedList } = state.multiselect;
+    // console.log("checkedList", checkedList); //here
     return {
         isVisible: isVisible,
         checkedList: checkedList as TCheckedList,
@@ -201,7 +202,6 @@ function mapDispatchToProps(dispatch: Dispatch) {
                 default:
                     for (const kind in kindGroups) {
                         const action = findActionByName(selectedAction.name as string, kindToActionSet[kind]);
-                        console.log(action, kindGroups[kind]);
                         if (action) action.execute(dispatch, kindGroups[kind]);
                     }
                     break;
diff --git a/src/store/collections/collection-copy-actions.ts b/src/store/collections/collection-copy-actions.ts
index eb9c64fd..fe204aad 100644
--- a/src/store/collections/collection-copy-actions.ts
+++ b/src/store/collections/collection-copy-actions.ts
@@ -4,52 +4,56 @@
 
 import { Dispatch } from "redux";
 import { dialogActions } from "store/dialog/dialog-actions";
-import { FormErrors, initialize, startSubmit, stopSubmit } from 'redux-form';
-import { resetPickerProjectTree } from 'store/project-tree-picker/project-tree-picker-actions';
-import { RootState } from 'store/store';
-import { ServiceRepository } from 'services/services';
-import { getCommonResourceServiceError, CommonResourceServiceError } from 'services/common-service/common-resource-service';
-import { CopyFormDialogData } from 'store/copy-dialog/copy-dialog';
+import { FormErrors, initialize, startSubmit, stopSubmit } from "redux-form";
+import { resetPickerProjectTree } from "store/project-tree-picker/project-tree-picker-actions";
+import { RootState } from "store/store";
+import { ServiceRepository } from "services/services";
+import { getCommonResourceServiceError, CommonResourceServiceError } from "services/common-service/common-resource-service";
+import { CopyFormDialogData } from "store/copy-dialog/copy-dialog";
 import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions";
-import { initProjectsTreePicker } from 'store/tree-picker/tree-picker-actions';
+import { initProjectsTreePicker } from "store/tree-picker/tree-picker-actions";
 import { getResource } from "store/resources/resources";
 import { CollectionResource } from "models/collection";
 
-export const COLLECTION_COPY_FORM_NAME = 'collectionCopyFormName';
+export const COLLECTION_COPY_FORM_NAME = "collectionCopyFormName";
 
-export const openCollectionCopyDialog = (resource: { name: string, uuid: string }) =>
-    (dispatch: Dispatch) => {
-        dispatch<any>(resetPickerProjectTree());
-        dispatch<any>(initProjectsTreePicker(COLLECTION_COPY_FORM_NAME));
-        const initialData: CopyFormDialogData = { name: `Copy of: ${resource.name}`, ownerUuid: '', uuid: resource.uuid };
-        dispatch<any>(initialize(COLLECTION_COPY_FORM_NAME, initialData));
-        dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_COPY_FORM_NAME, data: {} }));
-    };
+export const openCollectionCopyDialog = (resource: { name: string; uuid: string; isSingle?: boolean }) => (dispatch: Dispatch) => {
+    dispatch<any>(resetPickerProjectTree());
+    dispatch<any>(initProjectsTreePicker(COLLECTION_COPY_FORM_NAME));
+    const initialData: CopyFormDialogData = { name: `Copy of: ${resource.name}`, ownerUuid: "", uuid: resource.uuid, isSingle: resource.isSingle };
+    dispatch<any>(initialize(COLLECTION_COPY_FORM_NAME, initialData));
+    dispatch(dialogActions.OPEN_DIALOG({ id: COLLECTION_COPY_FORM_NAME, data: {} }));
+};
 
-export const copyCollection = (resource: CopyFormDialogData) =>
-    async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+export const copyCollection =
+    (resource: CopyFormDialogData) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(startSubmit(COLLECTION_COPY_FORM_NAME));
         let collection = getResource<CollectionResource>(resource.uuid)(getState().resources);
         try {
             if (!collection) {
                 collection = await services.collectionService.get(resource.uuid);
             }
-            const collManifestText = await services.collectionService.get(resource.uuid, undefined, ['manifestText']);
+            const collManifestText = await services.collectionService.get(resource.uuid, undefined, ["manifestText"]);
             collection.manifestText = collManifestText.manifestText;
-            const {href, ...collectionRecord} = collection;
-            const newCollection = await services.collectionService.create({ ...collectionRecord, ownerUuid: resource.ownerUuid, name: resource.name });
+            const { href, ...collectionRecord } = collection;
+            const newCollection = await services.collectionService.create({
+                ...collectionRecord,
+                ownerUuid: resource.ownerUuid,
+                name: resource.name,
+            });
             dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_COPY_FORM_NAME }));
             return newCollection;
         } catch (e) {
             const error = getCommonResourceServiceError(e);
             if (error === CommonResourceServiceError.UNIQUE_NAME_VIOLATION) {
-                dispatch(stopSubmit(
-                    COLLECTION_COPY_FORM_NAME,
-                    { ownerUuid: 'A collection with the same name already exists in the target project.' } as FormErrors
-                ));
+                dispatch(
+                    stopSubmit(COLLECTION_COPY_FORM_NAME, {
+                        ownerUuid: "A collection with the same name already exists in the target project.",
+                    } as FormErrors)
+                );
             } else {
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_COPY_FORM_NAME }));
-                throw new Error('Could not copy the collection.');
+                throw new Error("Could not copy the collection.");
             }
             return;
         } finally {
diff --git a/src/store/copy-dialog/copy-dialog.ts b/src/store/copy-dialog/copy-dialog.ts
index 4450cfc6..af4d7ace 100644
--- a/src/store/copy-dialog/copy-dialog.ts
+++ b/src/store/copy-dialog/copy-dialog.ts
@@ -6,4 +6,5 @@ export interface CopyFormDialogData {
     name: string;
     uuid: string;
     ownerUuid: string;
-}
\ No newline at end of file
+    isSingle?: boolean;
+}
diff --git a/src/store/workbench/workbench-actions.ts b/src/store/workbench/workbench-actions.ts
index 0de438c5..e79df239 100644
--- a/src/store/workbench/workbench-actions.ts
+++ b/src/store/workbench/workbench-actions.ts
@@ -281,7 +281,6 @@ export const createProject = (data: projectCreateActions.ProjectCreateFormDialog
 export const moveProject =
     (data: MoveToFormDialogData, isSecondaryMove = false) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-        console.log(data);
         const checkedList = getState().multiselect.checkedList;
         const uuidsToMove: string[] = data.isSingle ? [data.uuid] : selectedToArray(checkedList);
 
@@ -427,28 +426,44 @@ export const createCollection = (data: collectionCreateActions.CollectionCreateF
 };
 
 export const copyCollection = (data: CopyFormDialogData) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
-    try {
-        const copyToProject = getResource(data.ownerUuid)(getState().resources);
-        const collection = await dispatch<any>(collectionCopyActions.copyCollection(data));
-        if (copyToProject && collection) {
-            dispatch<any>(reloadProjectMatchingUuid([copyToProject.uuid]));
+    const checkedList = getState().multiselect.checkedList;
+    const uuidsToCopy: string[] = data.isSingle ? [data.uuid] : selectedToArray(checkedList);
+
+    //if no items in checkedlist && no items passed in, default to normal context menu behavior
+    if (!uuidsToCopy.length) uuidsToCopy.push(data.uuid);
+
+    const collectionsToCopy: Resource[] = uuidsToCopy
+        .map(uuid => getResource(uuid)(getState().resources) as any)
+        .filter(resource => resource.kind === ResourceKind.COLLECTION);
+
+    for (const collection of collectionsToCopy) {
+        await copySingleCollection(collection as Resource & { name: string });
+    }
+
+    async function copySingleCollection(copyToProject: Resource & { name: string }) {
+        const newName = data.isSingle ? data.name : `Copy of: ${copyToProject.name}`;
+        try {
+            const collection = await dispatch<any>(collectionCopyActions.copyCollection({ ...copyToProject, name: newName }));
+            if (copyToProject && collection) {
+                await dispatch<any>(reloadProjectMatchingUuid([copyToProject.uuid]));
+                dispatch(
+                    snackbarActions.OPEN_SNACKBAR({
+                        message: "Collection has been copied.",
+                        hideDuration: 3000,
+                        kind: SnackbarKind.SUCCESS,
+                        link: collection.ownerUuid,
+                    })
+                );
+            }
+        } catch (e) {
             dispatch(
                 snackbarActions.OPEN_SNACKBAR({
-                    message: "Collection has been copied.",
-                    hideDuration: 3000,
-                    kind: SnackbarKind.SUCCESS,
-                    link: collection.ownerUuid,
+                    message: e.message,
+                    hideDuration: 2000,
+                    kind: SnackbarKind.ERROR,
                 })
             );
         }
-    } catch (e) {
-        dispatch(
-            snackbarActions.OPEN_SNACKBAR({
-                message: e.message,
-                hideDuration: 2000,
-                kind: SnackbarKind.ERROR,
-            })
-        );
     }
 };
 
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 f960571e..f1250582 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
@@ -66,7 +66,7 @@ const commonActionSet: ContextMenuActionSet = [
             icon: CopyIcon,
             name: "Make a copy",
             execute: (dispatch, resources) => {
-                resources.forEach(resource => dispatch<any>(openCollectionCopyDialog(resource))); //here
+                dispatch<any>(openCollectionCopyDialog(resources[0]));
             },
         },
         {
diff --git a/src/views-components/data-explorer/data-explorer.tsx b/src/views-components/data-explorer/data-explorer.tsx
index 871389d4..d885fd5a 100644
--- a/src/views-components/data-explorer/data-explorer.tsx
+++ b/src/views-components/data-explorer/data-explorer.tsx
@@ -2,17 +2,17 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import { connect } from 'react-redux';
-import { RootState } from 'store/store';
-import { DataExplorer as DataExplorerComponent } from 'components/data-explorer/data-explorer';
-import { getDataExplorer } from 'store/data-explorer/data-explorer-reducer';
-import { Dispatch } from 'redux';
-import { dataExplorerActions } from 'store/data-explorer/data-explorer-action';
-import { DataColumn } from 'components/data-table/data-column';
-import { DataColumns, TCheckedList } from 'components/data-table/data-table';
-import { DataTableFilters } from 'components/data-table-filters/data-table-filters-tree';
-import { LAST_REFRESH_TIMESTAMP } from 'components/refresh-button/refresh-button';
-import { toggleMSToolbar, setCheckedListOnStore } from 'store/multiselect/multiselect-actions';
+import { connect } from "react-redux";
+import { RootState } from "store/store";
+import { DataExplorer as DataExplorerComponent } from "components/data-explorer/data-explorer";
+import { getDataExplorer } from "store/data-explorer/data-explorer-reducer";
+import { Dispatch } from "redux";
+import { dataExplorerActions } from "store/data-explorer/data-explorer-action";
+import { DataColumn } from "components/data-table/data-column";
+import { DataColumns, TCheckedList } from "components/data-table/data-table";
+import { DataTableFilters } from "components/data-table-filters/data-table-filters-tree";
+import { LAST_REFRESH_TIMESTAMP } from "components/refresh-button/refresh-button";
+import { toggleMSToolbar, setCheckedListOnStore } from "store/multiselect/multiselect-actions";
 
 interface Props {
     id: string;
@@ -23,11 +23,11 @@ interface Props {
 }
 
 const mapStateToProps = (state: RootState, { id }: Props) => {
-    const progress = state.progressIndicator.find((p) => p.id === id);
+    const progress = state.progressIndicator.find(p => p.id === id);
     const dataExplorerState = getDataExplorer(state.dataExplorer, id);
-    const currentRoute = state.router.location ? state.router.location.pathname : '';
-    const currentRefresh = localStorage.getItem(LAST_REFRESH_TIMESTAMP) || '';
-    const currentItemUuid = currentRoute === '/workflows' ? state.properties.workflowPanelDetailsUuid : state.detailsPanel.resourceUuid;
+    const currentRoute = state.router.location ? state.router.location.pathname : "";
+    const currentRefresh = localStorage.getItem(LAST_REFRESH_TIMESTAMP) || "";
+    const currentItemUuid = currentRoute === "/workflows" ? state.properties.workflowPanelDetailsUuid : state.detailsPanel.resourceUuid;
     const isMSToolbarVisible = state.multiselect.isVisible;
     return {
         ...dataExplorerState,
@@ -37,10 +37,11 @@ const mapStateToProps = (state: RootState, { id }: Props) => {
         paperKey: currentRoute,
         currentItemUuid,
         isMSToolbarVisible,
+        checkedList: state.multiselect.checkedList,
     };
 };
 
-const mapDispatchToProps = (dispatchFn) => {
+const mapDispatchToProps = dispatchFn => {
     return (dispatch: Dispatch, { id, onRowClick, onRowDoubleClick, onContextMenu }: Props) => ({
         onSetColumns: (columns: DataColumns<any, any>) => {
             dispatch(dataExplorerActions.SET_COLUMNS({ id, columns }));
diff --git a/src/views-components/dialog-copy/dialog-copy.tsx b/src/views-components/dialog-copy/dialog-copy.tsx
index a3e30119..aa6b6784 100644
--- a/src/views-components/dialog-copy/dialog-copy.tsx
+++ b/src/views-components/dialog-copy/dialog-copy.tsx
@@ -3,37 +3,40 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from "react";
-import { memoize } from 'lodash/fp';
-import { InjectedFormProps, Field } from 'redux-form';
-import { WithDialogProps } from 'store/dialog/with-dialog';
-import { FormDialog } from 'components/form-dialog/form-dialog';
-import { ProjectTreePickerField } from 'views-components/projects-tree-picker/tree-picker-field';
-import { COPY_NAME_VALIDATION, COPY_FILE_VALIDATION } from 'validators/validators';
+import { memoize } from "lodash/fp";
+import { InjectedFormProps, Field } from "redux-form";
+import { WithDialogProps } from "store/dialog/with-dialog";
+import { FormDialog } from "components/form-dialog/form-dialog";
+import { ProjectTreePickerField } from "views-components/projects-tree-picker/tree-picker-field";
+import { COPY_NAME_VALIDATION, COPY_FILE_VALIDATION } from "validators/validators";
 import { TextField } from "components/text-field/text-field";
-import { CopyFormDialogData } from 'store/copy-dialog/copy-dialog';
-import { PickerIdProp } from 'store/tree-picker/picker-id';
+import { CopyFormDialogData } from "store/copy-dialog/copy-dialog";
+import { PickerIdProp } from "store/tree-picker/picker-id";
 
 type CopyFormDialogProps = WithDialogProps<string> & InjectedFormProps<CopyFormDialogData>;
 
-export const DialogCopy = (props: CopyFormDialogProps & PickerIdProp) =>
+export const DialogCopy = (props: CopyFormDialogProps & PickerIdProp) => (
     <FormDialog
-        dialogTitle='Make a copy'
+        dialogTitle="Make a copy"
         formFields={CopyDialogFields(props.pickerId)}
-        submitLabel='Copy'
+        submitLabel="Copy"
         {...props}
-    />;
+    />
+);
 
-const CopyDialogFields = memoize((pickerId: string) =>
-    () =>
-        <>
-            <Field
-                name='name'
-                component={TextField as any}
-                validate={COPY_NAME_VALIDATION}
-                label="Enter a new name for the copy" />
-            <Field
-                name="ownerUuid"
-                component={ProjectTreePickerField}
-                validate={COPY_FILE_VALIDATION}
-                pickerId={pickerId}/>
-        </>);
+const CopyDialogFields = memoize((pickerId: string) => () => (
+    <>
+        <Field
+            name="name"
+            component={TextField as any}
+            validate={COPY_NAME_VALIDATION}
+            label="Enter a new name for the copy"
+        />
+        <Field
+            name="ownerUuid"
+            component={ProjectTreePickerField}
+            validate={COPY_FILE_VALIDATION}
+            pickerId={pickerId}
+        />
+    </>
+));
diff --git a/src/views-components/dialog-forms/copy-collection-dialog.ts b/src/views-components/dialog-forms/copy-collection-dialog.ts
index a1c822cf..eb1f2615 100644
--- a/src/views-components/dialog-forms/copy-collection-dialog.ts
+++ b/src/views-components/dialog-forms/copy-collection-dialog.ts
@@ -4,12 +4,12 @@
 
 import { compose } from "redux";
 import { withDialog } from "store/dialog/with-dialog";
-import { reduxForm } from 'redux-form';
-import { COLLECTION_COPY_FORM_NAME } from 'store/collections/collection-copy-actions';
+import { reduxForm } from "redux-form";
+import { COLLECTION_COPY_FORM_NAME } from "store/collections/collection-copy-actions";
 import { DialogCopy } from "views-components/dialog-copy/dialog-copy";
-import { copyCollection } from 'store/workbench/workbench-actions';
-import { CopyFormDialogData } from 'store/copy-dialog/copy-dialog';
-import { pickerId } from 'store/tree-picker/picker-id';
+import { copyCollection } from "store/workbench/workbench-actions";
+import { CopyFormDialogData } from "store/copy-dialog/copy-dialog";
+import { pickerId } from "store/tree-picker/picker-id";
 
 export const CopyCollectionDialog = compose(
     withDialog(COLLECTION_COPY_FORM_NAME),
@@ -18,7 +18,7 @@ export const CopyCollectionDialog = compose(
         touchOnChange: true,
         onSubmit: (data, dispatch) => {
             dispatch(copyCollection(data));
-        }
+        },
     }),
-    pickerId(COLLECTION_COPY_FORM_NAME),
-)(DialogCopy);
\ No newline at end of file
+    pickerId(COLLECTION_COPY_FORM_NAME)
+)(DialogCopy);

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list