[ARVADOS-WORKBENCH2] updated: 2.3.2-1-g6b368635

Git user git at public.arvados.org
Thu Dec 16 13:49:53 UTC 2021


Summary of changes:
 cypress/integration/collection.spec.js             | 80 ++++++++++++++++++++++
 cypress/integration/favorites.spec.js              |  3 +-
 src/store/collections/collection-copy-actions.ts   | 12 +++-
 src/store/collections/collection-move-actions.ts   |  8 ++-
 .../collections/collection-partial-copy-actions.ts |  8 +--
 .../action-sets/collection-files-action-set.ts     | 13 ++--
 .../projects-tree-picker/projects-tree-picker.tsx  | 14 ++--
 src/views-components/snackbar/snackbar.tsx         |  6 +-
 src/views/project-panel/project-panel.tsx          |  2 +-
 9 files changed, 124 insertions(+), 22 deletions(-)

       via  6b368635bf1a768e89237c011de76a4230dc9d6d (commit)
      from  d0df6414bef82439ff46836f059632250d2de3c2 (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 6b368635bf1a768e89237c011de76a4230dc9d6d
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Wed Dec 15 19:32:01 2021 -0300

    Merge branch '18584-collection-copy-fix'. Closes #18584.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/cypress/integration/collection.spec.js b/cypress/integration/collection.spec.js
index eb06a06c..bd211b1a 100644
--- a/cypress/integration/collection.spec.js
+++ b/cypress/integration/collection.spec.js
@@ -595,6 +595,86 @@ describe('Collection panel tests', function () {
         })
     });
 
+    it('moves a collection to a different project', function () {
+        const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
+        const projName = `Test Project ${Math.floor(Math.random() * 999999)}`;
+        const fileName = `Test_File_${Math.floor(Math.random() * 999999)}`;
+
+        cy.createCollection(adminUser.token, {
+            name: collName,
+            owner_uuid: activeUser.user.uuid,
+            manifest_text: `. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:${fileName}\n`,
+        }).as('testCollection');
+        cy.createGroup(adminUser.token, {
+            name: projName,
+            group_class: 'project',
+            owner_uuid: activeUser.user.uuid,
+        }).as('testProject');
+
+        cy.getAll('@testCollection', '@testProject')
+            .then(function ([testCollection, testProject]) {
+                cy.loginAs(activeUser);
+                cy.goToPath(`/collections/${testCollection.uuid}`);
+                cy.get('[data-cy=collection-files-panel]').should('contain', fileName);
+                cy.get('[data-cy=collection-info-panel]')
+                    .should('not.contain', projName)
+                    .and('not.contain', testProject.uuid);
+                cy.get('[data-cy=collection-panel-options-btn]').click();
+                cy.get('[data-cy=context-menu]').contains('Move to').click();
+                cy.get('[data-cy=form-dialog]')
+                    .should('contain', 'Move to')
+                    .within(() => {
+                        cy.get('[data-cy=projects-tree-home-tree-picker]')
+                            .find('i')
+                            .click();
+                        cy.get('[data-cy=projects-tree-home-tree-picker]')
+                            .contains(projName)
+                            .click();
+                    });
+                cy.get('[data-cy=form-submit-btn]').click();
+                cy.get('[data-cy=snackbar]')
+                    .contains('Collection has been moved')
+                cy.get('[data-cy=collection-info-panel]')
+                    .contains(projName).and('contain', testProject.uuid);
+                // Double check that the collection is in the project
+                cy.goToPath(`/projects/${testProject.uuid}`);
+                cy.get('[data-cy=project-panel]').should('contain', collName);
+            });
+    });
+
+    it('makes a copy of an existing collection', function() {
+        const collName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
+        const copyName = `Copy of: ${collName}`;
+
+        cy.createCollection(adminUser.token, {
+            name: collName,
+            owner_uuid: activeUser.user.uuid,
+            manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:some-file\n",
+        }).as('collection').then(function () {
+            cy.loginAs(activeUser)
+            cy.goToPath(`/collections/${this.collection.uuid}`);
+            cy.get('[data-cy=collection-files-panel]')
+                .should('contain', 'some-file');
+            cy.get('[data-cy=collection-panel-options-btn]').click();
+            cy.get('[data-cy=context-menu]').contains('Make a copy').click();
+            cy.get('[data-cy=form-dialog]')
+                .should('contain', 'Make a copy')
+                .within(() => {
+                    cy.get('[data-cy=projects-tree-home-tree-picker]')
+                        .contains('Projects')
+                        .click();
+                    cy.get('[data-cy=form-submit-btn]').click();
+                });
+            cy.get('[data-cy=snackbar]')
+                .contains('Collection has been copied.')
+            cy.get('[data-cy=snackbar-goto-action]').click();
+            cy.get('[data-cy=project-panel]')
+                .contains(copyName).click();
+            cy.get('[data-cy=collection-files-panel]')
+                .should('contain', 'some-file');
+        });
+    });
+
     it('uses the collection version browser to view a previous version', function () {
         const colName = `Test Collection ${Math.floor(Math.random() * 999999)}`;
 
diff --git a/cypress/integration/favorites.spec.js b/cypress/integration/favorites.spec.js
index 13a2c467..9bc90ebd 100644
--- a/cypress/integration/favorites.spec.js
+++ b/cypress/integration/favorites.spec.js
@@ -44,7 +44,8 @@ describe('Favorites tests', function () {
         });
     });
 
-    it('can copy selected into the collection', () => {
+    // Disabled while addressing #18587
+    it.skip('can copy selected into the collection', () => {
         cy.createCollection(adminUser.token, {
             name: `Test source collection ${Math.floor(Math.random() * 999999)}`,
             manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
diff --git a/src/store/collections/collection-copy-actions.ts b/src/store/collections/collection-copy-actions.ts
index 9d812783..eb9c64fd 100644
--- a/src/store/collections/collection-copy-actions.ts
+++ b/src/store/collections/collection-copy-actions.ts
@@ -12,6 +12,8 @@ import { getCommonResourceServiceError, CommonResourceServiceError } from 'servi
 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 { getResource } from "store/resources/resources";
+import { CollectionResource } from "models/collection";
 
 export const COLLECTION_COPY_FORM_NAME = 'collectionCopyFormName';
 
@@ -27,9 +29,15 @@ export const openCollectionCopyDialog = (resource: { name: string, uuid: string
 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 {
-            const collection = await services.collectionService.get(resource.uuid);
-            const newCollection = await services.collectionService.create({ ...collection, ownerUuid: resource.ownerUuid, name: resource.name });
+            if (!collection) {
+                collection = await services.collectionService.get(resource.uuid);
+            }
+            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 });
             dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_COPY_FORM_NAME }));
             return newCollection;
         } catch (e) {
diff --git a/src/store/collections/collection-move-actions.ts b/src/store/collections/collection-move-actions.ts
index d056b6e5..929f1612 100644
--- a/src/store/collections/collection-move-actions.ts
+++ b/src/store/collections/collection-move-actions.ts
@@ -14,6 +14,8 @@ import { MoveToFormDialogData } from 'store/move-to-dialog/move-to-dialog';
 import { resetPickerProjectTree } from 'store/project-tree-picker/project-tree-picker-actions';
 import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions";
 import { initProjectsTreePicker } from 'store/tree-picker/tree-picker-actions';
+import { getResource } from "store/resources/resources";
+import { CollectionResource } from "models/collection";
 
 export const COLLECTION_MOVE_FORM_NAME = 'collectionMoveFormName';
 
@@ -28,13 +30,17 @@ export const openMoveCollectionDialog = (resource: { name: string, uuid: string
 export const moveCollection = (resource: MoveToFormDialogData) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(startSubmit(COLLECTION_MOVE_FORM_NAME));
+        let cachedCollection = getResource<CollectionResource>(resource.uuid)(getState().resources);
         try {
             dispatch(progressIndicatorActions.START_WORKING(COLLECTION_MOVE_FORM_NAME));
+            if (!cachedCollection) {
+                cachedCollection = await services.collectionService.get(resource.uuid);
+            }
             const collection = await services.collectionService.update(resource.uuid, { ownerUuid: resource.ownerUuid });
             dispatch(projectPanelActions.REQUEST_ITEMS());
             dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_MOVE_FORM_NAME }));
             dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_MOVE_FORM_NAME));
-            return collection;
+            return {...cachedCollection, ...collection};
         } catch (e) {
             const error = getCommonResourceServiceError(e);
             if (error === CommonResourceServiceError.UNIQUE_NAME_VIOLATION) {
diff --git a/src/store/collections/collection-partial-copy-actions.ts b/src/store/collections/collection-partial-copy-actions.ts
index d898c500..9f478d74 100644
--- a/src/store/collections/collection-partial-copy-actions.ts
+++ b/src/store/collections/collection-partial-copy-actions.ts
@@ -52,13 +52,13 @@ export const copyCollectionPartial = ({ name, description, projectUuid }: Collec
         if (currentCollection) {
             try {
                 dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));
-                const collection = await services.collectionService.get(currentCollection.uuid);
+                const collectionManifestText = await services.collectionService.get(currentCollection.uuid, undefined, ['manifestText']);
                 const collectionCopy = {
                     name,
                     description,
                     ownerUuid: projectUuid,
                     uuid: undefined,
-                    manifestText: collection.manifestText,
+                    manifestText: collectionManifestText.manifestText,
                 };
                 const newCollection = await services.collectionService.create(collectionCopy);
                 const copiedFiles = await services.collectionService.files(newCollection.uuid);
@@ -67,7 +67,7 @@ export const copyCollectionPartial = ({ name, description, projectUuid }: Collec
                     return !paths.find(path => path.indexOf(file.replace(newCollection.uuid, '')) > -1);
                 });
                 await services.collectionService.deleteFiles(
-                    '',
+                    newCollection.uuid,
                     filesToDelete
                 );
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
@@ -135,7 +135,7 @@ export const copyCollectionPartialToSelectedCollection = ({ collectionUuid }: Co
                 });
                 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);
+                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)));
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION }));
diff --git a/src/views-components/context-menu/action-sets/collection-files-action-set.ts b/src/views-components/context-menu/action-sets/collection-files-action-set.ts
index 3aeec4c0..59a5f368 100644
--- a/src/views-components/context-menu/action-sets/collection-files-action-set.ts
+++ b/src/views-components/context-menu/action-sets/collection-files-action-set.ts
@@ -26,12 +26,13 @@ export const readOnlyCollectionFilesActionSet: ContextMenuActionSet = [[
             dispatch<any>(openCollectionPartialCopyDialog());
         }
     },
-    {
-        name: "Copy selected into the collection",
-        execute: dispatch => {
-            dispatch<any>(openCollectionPartialCopyToSelectedCollectionDialog());
-        }
-    }
+    // Disabled while addressing #18587
+    // {
+    //     name: "Copy selected into the collection",
+    //     execute: dispatch => {
+    //         dispatch<any>(openCollectionPartialCopyToSelectedCollectionDialog());
+    //     }
+    // }
 ]];
 
 export const collectionFilesActionSet: ContextMenuActionSet = readOnlyCollectionFilesActionSet.concat([[
diff --git a/src/views-components/projects-tree-picker/projects-tree-picker.tsx b/src/views-components/projects-tree-picker/projects-tree-picker.tsx
index 2f3ea611..ee8ce1d5 100644
--- a/src/views-components/projects-tree-picker/projects-tree-picker.tsx
+++ b/src/views-components/projects-tree-picker/projects-tree-picker.tsx
@@ -31,11 +31,17 @@ export const ProjectsTreePicker = ({ pickerId, ...props }: ProjectsTreePickerPro
         disableActivation
     };
     return <div>
-        <HomeTreePicker pickerId={home} {...p} />
-        <SharedTreePicker pickerId={shared} {...p} />
-        <PublicFavoritesTreePicker pickerId={publicFavorites} {...p} />
+        <div data-cy="projects-tree-home-tree-picker">
+            <HomeTreePicker pickerId={home} {...p} />
+        </div>
+        <div data-cy="projects-tree-shared-tree-picker">
+            <SharedTreePicker pickerId={shared} {...p} />
+        </div>
+        <div data-cy="projects-tree-public-favourites-tree-picker">
+            <PublicFavoritesTreePicker pickerId={publicFavorites} {...p} />
+        </div>
         <div data-cy="projects-tree-favourites-tree-picker">
-            <FavoritesTreePicker pickerId={favorites} {...p} />  
+            <FavoritesTreePicker pickerId={favorites} {...p} />
         </div>
     </div>;
 };
diff --git a/src/views-components/snackbar/snackbar.tsx b/src/views-components/snackbar/snackbar.tsx
index 2a63a31a..a33b6968 100644
--- a/src/views-components/snackbar/snackbar.tsx
+++ b/src/views-components/snackbar/snackbar.tsx
@@ -116,7 +116,7 @@ export const Snackbar = withStyles(styles)(connect(mapStateToProps, mapDispatchT
                 onExited={props.onExited}
                 anchorOrigin={props.anchorOrigin}
                 autoHideDuration={props.autoHideDuration}>
-                <SnackbarContent
+                <div data-cy="snackbar"><SnackbarContent
                     className={classNames(cssClass)}
                     aria-describedby="client-snackbar"
                     message={
@@ -126,7 +126,7 @@ export const Snackbar = withStyles(styles)(connect(mapStateToProps, mapDispatchT
                         </span>
                     }
                     action={actions(props)}
-                />
+                /></div>
             </MaterialSnackbar>
         );
     }
@@ -151,7 +151,7 @@ const actions = (props: SnackbarProps) => {
                 color="inherit"
                 className={classes.linkButton}
                 onClick={() => onClick(link)}>
-                Go To
+                <span data-cy='snackbar-goto-action'>Go To</span>
             </Button>
         );
     }
diff --git a/src/views/project-panel/project-panel.tsx b/src/views/project-panel/project-panel.tsx
index 67264511..eaf48d14 100644
--- a/src/views/project-panel/project-panel.tsx
+++ b/src/views/project-panel/project-panel.tsx
@@ -147,7 +147,7 @@ export const ProjectPanel = withStyles(styles)(
         class extends React.Component<ProjectPanelProps> {
             render() {
                 const { classes } = this.props;
-                return <div className={classes.root}>
+                return <div data-cy='project-panel' className={classes.root}>
                     <DataExplorer
                         id={PROJECT_PANEL_ID}
                         onRowClick={this.handleRowClick}

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list