[arvados-workbench2] created: 2.4.0-363-g9123f234

git repository hosting git at public.arvados.org
Fri Dec 9 20:15:30 UTC 2022


        at  9123f234b9b8240cbcd8570421d87fe3af6b97e4 (commit)


commit 9123f234b9b8240cbcd8570421d87fe3af6b97e4
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Fri Dec 9 21:15:04 2022 +0100

    19691: Adds tests.
    
    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 74506aea..06436d1d 100644
--- a/cypress/integration/collection.spec.js
+++ b/cypress/integration/collection.spec.js
@@ -75,6 +75,55 @@ describe('Collection panel tests', function () {
         });
     });
 
+    it('attempts to use a preexisting name creating or updating a collection', function() {
+        const name = `Test collection ${Math.floor(Math.random() * 999999)}`;
+        cy.createCollection(adminUser.token, {
+            name: name,
+            owner_uuid: activeUser.user.uuid,
+            manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
+        });
+        cy.loginAs(activeUser);
+        cy.goToPath(`/projects/${activeUser.user.uuid}`);
+        cy.get('[data-cy=breadcrumb-first]').should('contain', 'Projects');
+        cy.get('[data-cy=breadcrumb-last]').should('not.exist');
+        // Attempt to create new collection with a duplicate name
+        cy.get('[data-cy=side-panel-button]').click();
+        cy.get('[data-cy=side-panel-new-collection]').click();
+        cy.get('[data-cy=form-dialog]')
+            .should('contain', 'New collection')
+            .within(() => {
+                cy.get('[data-cy=name-field]').within(() => {
+                    cy.get('input').type(name);
+                });
+                cy.get('[data-cy=form-submit-btn]').click();
+            });
+        // Error message should display, allowing editing the name
+        cy.get('[data-cy=form-dialog]').should('exist')
+            .and('contain', 'Collection with the same name already exists')
+            .within(() => {
+                cy.get('[data-cy=name-field]').within(() => {
+                    cy.get('input').type(' renamed');
+                });
+                cy.get('[data-cy=form-submit-btn]').click();
+            });
+        cy.get('[data-cy=form-dialog]').should('not.exist');
+        // Attempt to rename the collection with the duplicate name
+        cy.get('[data-cy=collection-panel-options-btn]').click();
+        cy.get('[data-cy=context-menu]').contains('Edit collection').click();
+        cy.get('[data-cy=form-dialog]')
+            .should('contain', 'Edit Collection')
+            .within(() => {
+                cy.get('[data-cy=name-field]').within(() => {
+                    cy.get('input')
+                        .type('{selectall}{backspace}')
+                        .type(name);
+                });
+                cy.get('[data-cy=form-submit-btn]').click();
+            });
+        cy.get('[data-cy=form-dialog]').should('exist')
+            .and('contain', 'Collection with the same name already exists');
+    });
+
     it('uses the property editor (from edit dialog) with vocabulary terms', function () {
         cy.createCollection(adminUser.token, {
             name: `Test collection ${Math.floor(Math.random() * 999999)}`,
diff --git a/cypress/integration/project.spec.js b/cypress/integration/project.spec.js
index 93e4257b..bbb3571a 100644
--- a/cypress/integration/project.spec.js
+++ b/cypress/integration/project.spec.js
@@ -158,6 +158,38 @@ describe('Project tests', function() {
         cy.get('[data-cy=breadcrumb-last]').should('contain', subProjName);
     });
 
+    it('attempts to use a preexisting name creating a project', function() {
+        const name = `Test project ${Math.floor(Math.random() * 999999)}`;
+        cy.createGroup(activeUser.token, {
+            name: name,
+            group_class: 'project',
+        });
+        cy.loginAs(activeUser);
+        cy.goToPath(`/projects/${activeUser.user.uuid}`);
+
+        // Attempt to create new collection with a duplicate name
+        cy.get('[data-cy=side-panel-button]').click();
+        cy.get('[data-cy=side-panel-new-project]').click();
+        cy.get('[data-cy=form-dialog]')
+            .should('contain', 'New Project')
+            .within(() => {
+                cy.get('[data-cy=name-field]').within(() => {
+                    cy.get('input').type(name);
+                });
+                cy.get('[data-cy=form-submit-btn]').click();
+            });
+        // Error message should display, allowing editing the name
+        cy.get('[data-cy=form-dialog]').should('exist')
+            .and('contain', 'Project with the same name already exists')
+            .within(() => {
+                cy.get('[data-cy=name-field]').within(() => {
+                    cy.get('input').type(' renamed');
+                });
+                cy.get('[data-cy=form-submit-btn]').click();
+            });
+        cy.get('[data-cy=form-dialog]').should('not.exist');
+    });
+
     it('navigates to the parent project after trashing the one being displayed', function() {
         cy.createGroup(activeUser.token, {
             name: `Test root project ${Math.floor(Math.random() * 999999)}`,
@@ -313,12 +345,12 @@ describe('Project tests', function() {
     });
 
     describe('Frozen projects', () => {
-        beforeEach(() => {  
+        beforeEach(() => {
             cy.createGroup(activeUser.token, {
                 name: `Main project ${Math.floor(Math.random() * 999999)}`,
                 group_class: 'project',
             }).as('mainProject');
-    
+
             cy.createGroup(adminUser.token, {
                 name: `Admin project ${Math.floor(Math.random() * 999999)}`,
                 group_class: 'project',
@@ -337,7 +369,7 @@ describe('Project tests', function() {
                     name: `Main collection ${Math.floor(Math.random() * 999999)}`,
                     owner_uuid: mainProject.uuid,
                     manifest_text: "./subdir 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo\n. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
-                }).as('mainCollection');        
+                }).as('mainCollection');
             });
         });
 
@@ -398,7 +430,7 @@ describe('Project tests', function() {
                 cy.get('[data-cy=context-menu]').contains('Unfreeze').click();
 
                 cy.get('main').contains(adminProject.name).rightclick();
-                
+
                 cy.get('[data-cy=context-menu]').contains('Freeze').should('exist');
             });
         });

commit 6ffe67b266e94bb69098e46b102833c845288dba
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Fri Dec 9 17:20:07 2022 +0100

    19691: Show unknown errors on project & collection creation dialogs.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/src/store/collections/collection-create-actions.ts b/src/store/collections/collection-create-actions.ts
index 92e773c9..939ae9f9 100644
--- a/src/store/collections/collection-create-actions.ts
+++ b/src/store/collections/collection-create-actions.ts
@@ -68,11 +68,11 @@ export const createCollection = (data: CollectionCreateFormDialogData) =>
             const error = getCommonResourceServiceError(e);
             if (error === CommonResourceServiceError.UNIQUE_NAME_VIOLATION) {
                 dispatch(stopSubmit(COLLECTION_CREATE_FORM_NAME, { name: 'Collection with the same name already exists.' } as FormErrors));
-            } else if (error === CommonResourceServiceError.NONE) {
+            } else {
                 dispatch(stopSubmit(COLLECTION_CREATE_FORM_NAME));
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_CREATE_FORM_NAME }));
                 dispatch(snackbarActions.OPEN_SNACKBAR({
-                    message: 'Collection has not been created.',
+                    message: e.errors.join(''),
                     hideDuration: 2000,
                     kind: SnackbarKind.ERROR
                 }));
diff --git a/src/store/projects/project-create-actions.ts b/src/store/projects/project-create-actions.ts
index ddf5064e..e70ff0f6 100644
--- a/src/store/projects/project-create-actions.ts
+++ b/src/store/projects/project-create-actions.ts
@@ -20,6 +20,8 @@ import { ServiceRepository } from 'services/services';
 import { matchProjectRoute, matchRunProcessRoute } from 'routes/routes';
 import { RouterState } from "react-router-redux";
 import { GroupClass } from "models/group";
+import { snackbarActions, SnackbarKind } from "store/snackbar/snackbar-actions";
+import { progressIndicatorActions } from "store/progress-indicator/progress-indicator-actions";
 
 export interface ProjectCreateFormDialogData {
     ownerUuid: string;
@@ -65,6 +67,7 @@ export const createProject = (project: Partial<ProjectResource>) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(startSubmit(PROJECT_CREATE_FORM_NAME));
         try {
+            dispatch(progressIndicatorActions.START_WORKING(PROJECT_CREATE_FORM_NAME));
             const newProject = await services.projectService.create(project, false);
             dispatch(dialogActions.CLOSE_DIALOG({ id: PROJECT_CREATE_FORM_NAME }));
             dispatch(reset(PROJECT_CREATE_FORM_NAME));
@@ -73,7 +76,17 @@ export const createProject = (project: Partial<ProjectResource>) =>
             const error = getCommonResourceServiceError(e);
             if (error === CommonResourceServiceError.UNIQUE_NAME_VIOLATION) {
                 dispatch(stopSubmit(PROJECT_CREATE_FORM_NAME, { name: 'Project with the same name already exists.' } as FormErrors));
+            } else {
+                dispatch(stopSubmit(PROJECT_CREATE_FORM_NAME));
+                dispatch(dialogActions.CLOSE_DIALOG({ id: PROJECT_CREATE_FORM_NAME }));
+                dispatch(snackbarActions.OPEN_SNACKBAR({
+                    message: e.errors.join(''),
+                    hideDuration: 2000,
+                    kind: SnackbarKind.ERROR
+                }));
             }
             return undefined;
+        } finally {
+            dispatch(progressIndicatorActions.STOP_WORKING(PROJECT_CREATE_FORM_NAME));
         }
     };

commit 78a93ff46e7e9a38b9865fa743c88e1008adc81e
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Fri Dec 9 17:00:31 2022 +0100

    19691: Avoid showing generic errors on collection & project create dialogs.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/src/store/collections/collection-create-actions.ts b/src/store/collections/collection-create-actions.ts
index 17fecc1e..92e773c9 100644
--- a/src/store/collections/collection-create-actions.ts
+++ b/src/store/collections/collection-create-actions.ts
@@ -59,7 +59,7 @@ export const createCollection = (data: CollectionCreateFormDialogData) =>
         let newCollection: CollectionResource | undefined;
         try {
             dispatch(progressIndicatorActions.START_WORKING(COLLECTION_CREATE_FORM_NAME));
-            newCollection = await services.collectionService.create(data);
+            newCollection = await services.collectionService.create(data, false);
             await dispatch<any>(uploadCollectionFiles(newCollection.uuid));
             dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_CREATE_FORM_NAME }));
             dispatch(reset(COLLECTION_CREATE_FORM_NAME));
diff --git a/src/store/projects/project-create-actions.ts b/src/store/projects/project-create-actions.ts
index 23eaf7a4..ddf5064e 100644
--- a/src/store/projects/project-create-actions.ts
+++ b/src/store/projects/project-create-actions.ts
@@ -65,7 +65,7 @@ export const createProject = (project: Partial<ProjectResource>) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(startSubmit(PROJECT_CREATE_FORM_NAME));
         try {
-            const newProject = await services.projectService.create(project);
+            const newProject = await services.projectService.create(project, false);
             dispatch(dialogActions.CLOSE_DIALOG({ id: PROJECT_CREATE_FORM_NAME }));
             dispatch(reset(PROJECT_CREATE_FORM_NAME));
             return newProject;

commit 16d7bc7663c99f73f8f129d60021e6f3ebaec2a4
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Fri Dec 9 17:00:07 2022 +0100

    19691: Passes showErrors param on service layer's create method.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/src/services/collection-service/collection-service.ts b/src/services/collection-service/collection-service.ts
index c1d57802..d08e7899 100644
--- a/src/services/collection-service/collection-service.ts
+++ b/src/services/collection-service/collection-service.ts
@@ -35,8 +35,8 @@ export class CollectionService extends TrashableResourceService<CollectionResour
         return super.get(uuid, showErrors, selectParam, session);
     }
 
-    create(data?: Partial<CollectionResource>) {
-        return super.create({ ...data, preserveVersion: true });
+    create(data?: Partial<CollectionResource>, showErrors?: boolean) {
+        return super.create({ ...data, preserveVersion: true }, showErrors);
     }
 
     update(uuid: string, data: Partial<CollectionResource>, showErrors?: boolean) {
diff --git a/src/services/common-service/common-resource-service.ts b/src/services/common-service/common-resource-service.ts
index ce66aa37..d9be8dae 100644
--- a/src/services/common-service/common-resource-service.ts
+++ b/src/services/common-service/common-resource-service.ts
@@ -26,7 +26,7 @@ export class CommonResourceService<T extends Resource> extends CommonService<T>
         ]));
     }
 
-    create(data?: Partial<T>) {
+    create(data?: Partial<T>, showErrors?: boolean) {
         let payload: any;
         if (data !== undefined) {
             this.readOnlyFields.forEach( field => delete data[field] );
@@ -34,7 +34,7 @@ export class CommonResourceService<T extends Resource> extends CommonService<T>
                 [this.resourceType.slice(0, -1)]: CommonService.mapKeys(snakeCase)(data),
             };
         }
-        return super.create(payload);
+        return super.create(payload, showErrors);
     }
 
     update(uuid: string, data: Partial<T>, showErrors?: boolean, select?: string[]) {
diff --git a/src/services/project-service/project-service.ts b/src/services/project-service/project-service.ts
index 07b083fd..442a6ab9 100644
--- a/src/services/project-service/project-service.ts
+++ b/src/services/project-service/project-service.ts
@@ -9,9 +9,9 @@ import { ListArguments } from "services/common-service/common-service";
 import { FilterBuilder, joinFilters } from "services/api/filter-builder";
 export class ProjectService extends GroupsService<ProjectResource> {
 
-    create(data: Partial<ProjectResource>) {
+    create(data: Partial<ProjectResource>, showErrors?: boolean) {
         const projectData = { ...data, groupClass: GroupClass.PROJECT };
-        return super.create(projectData);
+        return super.create(projectData, showErrors);
     }
 
     list(args: ListArguments = {}) {

commit 5c1132153fa250f46de7954c8faeb456b96fe830
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Fri Dec 9 16:46:11 2022 +0100

    19691: Avoid showing generic errors on collection & project update dialogs.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/src/store/collections/collection-update-actions.ts b/src/store/collections/collection-update-actions.ts
index bf9c6449..2e66ce2c 100644
--- a/src/store/collections/collection-update-actions.ts
+++ b/src/store/collections/collection-update-actions.ts
@@ -52,7 +52,7 @@ export const updateCollection = (collection: CollectionUpdateFormDialogData) =>
             name: collection.name,
             storageClassesDesired: collection.storageClassesDesired,
             description: collection.description,
-            properties: collection.properties }
+            properties: collection.properties }, false
         ).then(updatedCollection => {
             updatedCollection = {...cachedCollection, ...updatedCollection};
             dispatch(collectionPanelActions.SET_COLLECTION(updatedCollection));
diff --git a/src/store/projects/project-update-actions.ts b/src/store/projects/project-update-actions.ts
index a6e67485..a9255e29 100644
--- a/src/store/projects/project-update-actions.ts
+++ b/src/store/projects/project-update-actions.ts
@@ -61,7 +61,8 @@ export const updateProject = (project: ProjectUpdateFormDialogData) =>
                     name: project.name,
                     description: project.description,
                     properties: project.properties,
-                });
+                },
+                false);
             dispatch(projectPanelActions.REQUEST_ITEMS());
             dispatch(reset(PROJECT_UPDATE_FORM_NAME));
             dispatch(dialogActions.CLOSE_DIALOG({ id: PROJECT_UPDATE_FORM_NAME }));

commit 85a30bc44cf21218a32be5aaf013faa262ae85e4
Author: Lucas Di Pentima <lucas.dipentima at curii.com>
Date:   Fri Dec 9 16:43:26 2022 +0100

    19691: Passes showErrors param on service layer's update method.
    
    Also, fixes error matching used to detect UniqueViolation errors, among
    other types.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima at curii.com>

diff --git a/src/services/collection-service/collection-service.ts b/src/services/collection-service/collection-service.ts
index e2c420d8..c1d57802 100644
--- a/src/services/collection-service/collection-service.ts
+++ b/src/services/collection-service/collection-service.ts
@@ -39,9 +39,9 @@ export class CollectionService extends TrashableResourceService<CollectionResour
         return super.create({ ...data, preserveVersion: true });
     }
 
-    update(uuid: string, data: Partial<CollectionResource>) {
+    update(uuid: string, data: Partial<CollectionResource>, showErrors?: boolean) {
         const select = [...Object.keys(data), 'version', 'modifiedAt'];
-        return super.update(uuid, { ...data, preserveVersion: true }, select);
+        return super.update(uuid, { ...data, preserveVersion: true }, showErrors, select);
     }
 
     async files(uuid: string) {
diff --git a/src/services/common-service/common-resource-service.ts b/src/services/common-service/common-resource-service.ts
index c6306779..ce66aa37 100644
--- a/src/services/common-service/common-resource-service.ts
+++ b/src/services/common-service/common-resource-service.ts
@@ -37,7 +37,7 @@ export class CommonResourceService<T extends Resource> extends CommonService<T>
         return super.create(payload);
     }
 
-    update(uuid: string, data: Partial<T>, select?: string[]) {
+    update(uuid: string, data: Partial<T>, showErrors?: boolean, select?: string[]) {
         let payload: any;
         if (data !== undefined) {
             this.readOnlyFields.forEach( field => delete data[field] );
@@ -48,12 +48,12 @@ export class CommonResourceService<T extends Resource> extends CommonService<T>
                 payload.select = ['uuid', ...select.map(field => snakeCase(field))];
             };
         }
-        return super.update(uuid, payload);
+        return super.update(uuid, payload, showErrors);
     }
 }
 
 export const getCommonResourceServiceError = (errorResponse: any) => {
-    if ('errors' in errorResponse && 'errorToken' in errorResponse) {
+    if ('errors' in errorResponse) {
         const error = errorResponse.errors.join('');
         switch (true) {
             case /UniqueViolation/.test(error):
diff --git a/src/services/common-service/common-service.ts b/src/services/common-service/common-service.ts
index b8e7dc67..fe7467a6 100644
--- a/src/services/common-service/common-service.ts
+++ b/src/services/common-service/common-service.ts
@@ -175,12 +175,14 @@ export class CommonService<T> {
         }
     }
 
-    update(uuid: string, data: Partial<T>) {
+    update(uuid: string, data: Partial<T>, showErrors?: boolean) {
         this.validateUuid(uuid);
         return CommonService.defaultResponse(
             this.serverApi
                 .put<T>(`/${this.resourceType}/${uuid}`, data && CommonService.mapKeys(snakeCase)(data)),
-            this.actions
+            this.actions,
+            false,
+            showErrors
         );
     }
 }

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list