18834: Fixed uploading file to a subdirectory, added tests
authorDaniel Kutyła <daniel.kutyla@contractors.roche.com>
Mon, 28 Mar 2022 07:35:23 +0000 (09:35 +0200)
committerDaniel Kutyła <daniel.kutyla@contractors.roche.com>
Mon, 28 Mar 2022 07:35:23 +0000 (09:35 +0200)
Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła <daniel.kutyla@contractors.roche.com>

cypress/integration/collection.spec.js
src/components/collection-panel-files/collection-panel-files.tsx
src/services/collection-service/collection-service.ts
src/store/collections/collection-upload-actions.ts
src/views-components/collection-panel-files/collection-panel-files.ts
src/views-components/dialog-forms/files-upload-collection-dialog.ts

index b451fd66e865c5e2478f1453cf10bcdc7c9965fc..6537e1626905e916360b45eff5424a1f557879c7 100644 (file)
@@ -947,11 +947,11 @@ describe('Collection panel tests', function () {
             cy.createCollection(adminUser.token, {
                 name: `Test collection ${Math.floor(Math.random() * 999999)}`,
                 owner_uuid: activeUser.user.uuid,
-                manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
+                manifest_text: "./subdir 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo\n. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
             }).as('testCollection1');
         });
 
-        it('uploads a file and checks the collection UI to be fresh', () => {
+        it.only('uploads a file and checks the collection UI to be fresh', () => {
             cy.getAll('@testCollection1')
                 .then(function([testCollection1]) {
                     cy.loginAs(activeUser);
@@ -959,17 +959,25 @@ describe('Collection panel tests', function () {
                     cy.get('[data-cy=upload-button]').click();
                     cy.get('[data-cy=collection-files-panel]')
                         .contains('5mb_a.bin').should('not.exist');
-                    cy.get('[data-cy=collection-file-count]').should('contain', '1');
+                    cy.get('[data-cy=collection-file-count]').should('contain', '2');
                     cy.fixture('files/5mb.bin', 'base64').then(content => {
                         cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_a.bin');
                         cy.get('[data-cy=form-submit-btn]').click();
-                        cy.get('[data-cy=form-submit-btn]').should('not.exist');
+                        // cy.get('[data-cy=form-submit-btn]').should('not.exist');
+                        cy.get('[data-cy=collection-files-panel]')
+                            .contains('5mb_a.bin').should('exist');
+                        cy.get('[data-cy=collection-file-count]').should('contain', '3');
+
+                        cy.get('[data-cy=collection-files-panel]').contains('subdir').click();
+                        cy.get('[data-cy=upload-button]').click();
+                        cy.fixture('files/5mb.bin', 'base64').then(content => {
+                            cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_b.bin');
+                            cy.get('[data-cy=form-submit-btn]').click();
+                            // cy.get('[data-cy=form-submit-btn]').should('not.exist');
+                            cy.get('[data-cy=collection-files-panel]')
+                                 .contains('5mb_b.bin').should('exist');
+                        });
                     });
-                    // Confirm that the file browser has been updated.
-                    cy.get('[data-cy=collection-files-panel]')
-                        .contains('5mb_a.bin').should('exist');
-                    // Confirm that the collection panel has been updated.
-                    cy.get('[data-cy=collection-file-count]').should('contain', '2');
                 });
         });
 
index 1f7e8603c5ec25bb9afa8a1a68b8565b7c7a909d..56833f64bade2376fd68b157679d7d041bc78869 100644 (file)
@@ -28,7 +28,7 @@ export interface CollectionPanelFilesProps {
     isWritable: boolean;
     isLoading: boolean;
     tooManyFiles: boolean;
-    onUploadDataClick: () => void;
+    onUploadDataClick: (targetLocation?: string) => void;
     onSearchChange: (searchValue: string) => void;
     onItemMenuOpen: (event: React.MouseEvent<HTMLElement>, item: TreeItem<FileTreeData>, isWritable: boolean) => void;
     onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, isWritable: boolean) => void;
@@ -508,7 +508,7 @@ export const CollectionPanelFiles = withStyles(styles)(connect((state: RootState
                             className={classes.uploadButton}
                             data-cy='upload-button'
                             onClick={() => {
-                                onUploadDataClick();
+                                onUploadDataClick(rightKey === leftKey ? undefined : rightKey);
                             }}
                             variant='contained'
                             color='primary'
index a3a7cf8f3af89c88ddd7edac938719199df74cbf..9165e245db41102ca1c49fd0ea3c16e317d98f9d 100644 (file)
@@ -88,11 +88,11 @@ export class CollectionService extends TrashableResourceService<CollectionResour
         await this.update(collectionUuid, { preserveVersion: true });
     }
 
-    async uploadFiles(collectionUuid: string, files: File[], onProgress?: UploadProgress) {
+    async uploadFiles(collectionUuid: string, files: File[], onProgress?: UploadProgress, targetLocation: string = '') {
         if (collectionUuid === "" || files.length === 0) { return; }
         // files have to be uploaded sequentially
         for (let idx = 0; idx < files.length; idx++) {
-            await this.uploadFile(collectionUuid, files[idx], idx, onProgress);
+            await this.uploadFile(collectionUuid, files[idx], idx, onProgress, targetLocation);
         }
         await this.update(collectionUuid, { preserveVersion: true });
     }
@@ -120,8 +120,8 @@ export class CollectionService extends TrashableResourceService<CollectionResour
         };
     }
 
-    private async uploadFile(collectionUuid: string, file: File, fileId: number, onProgress: UploadProgress = () => { return; }) {
-        const fileURL = `c=${collectionUuid}/${file.name}`;
+    private async uploadFile(collectionUuid: string, file: File, fileId: number, onProgress: UploadProgress = () => { return; }, targetLocation: string = '') {
+        const fileURL = `c=${targetLocation !== '' ? targetLocation : collectionUuid}/${file.name}`;
         const requestConfig = {
             headers: {
                 'Content-Type': 'text/octet-stream'
index 0ca681b98ed2fcc9d8550165b477231f58fa0287..135538b074dbee437cebf55b5b9daf4ab4d1ecc8 100644 (file)
@@ -16,31 +16,31 @@ import { createTree } from 'models/tree';
 import { loadCollectionPanel } from '../collection-panel/collection-panel-action';
 import * as WorkbenchActions from 'store/workbench/workbench-actions';
 
-export const uploadCollectionFiles = (collectionUuid: string) =>
+export const uploadCollectionFiles = (collectionUuid: string, targetLocation?: string) =>
     async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         dispatch(fileUploaderActions.START_UPLOAD());
         const files = getState().fileUploader.map(file => file.file);
-        await services.collectionService.uploadFiles(collectionUuid, files, handleUploadProgress(dispatch));
+        await services.collectionService.uploadFiles(collectionUuid, files, handleUploadProgress(dispatch), targetLocation);
         dispatch(WorkbenchActions.loadCollection(collectionUuid));
         dispatch(fileUploaderActions.CLEAR_UPLOAD());
     };
 
 export const COLLECTION_UPLOAD_FILES_DIALOG = 'uploadCollectionFilesDialog';
 
-export const openUploadCollectionFilesDialog = () => (dispatch: Dispatch) => {
+export const openUploadCollectionFilesDialog = (targetLocation?: string) => (dispatch: Dispatch) => {
     dispatch(reset(COLLECTION_UPLOAD_FILES_DIALOG));
     dispatch(fileUploaderActions.CLEAR_UPLOAD());
-    dispatch<any>(dialogActions.OPEN_DIALOG({ id: COLLECTION_UPLOAD_FILES_DIALOG, data: {} }));
+    dispatch<any>(dialogActions.OPEN_DIALOG({ id: COLLECTION_UPLOAD_FILES_DIALOG, data: { targetLocation } }));
 };
 
-export const submitCollectionFiles = () =>
+export const submitCollectionFiles = (targetLocation?: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const currentCollection = getState().collectionPanel.item;
         if (currentCollection) {
             try {
                 dispatch(progressIndicatorActions.START_WORKING(COLLECTION_UPLOAD_FILES_DIALOG));
                 dispatch(startSubmit(COLLECTION_UPLOAD_FILES_DIALOG));
-                await dispatch<any>(uploadCollectionFiles(currentCollection.uuid))
+                await dispatch<any>(uploadCollectionFiles(currentCollection.uuid, targetLocation))
                     .then(() => dispatch<any>(collectionPanelFilesAction.SET_COLLECTION_FILES({ files: createTree() })));
                 dispatch<any>(loadCollectionFiles(currentCollection.uuid));
                 dispatch<any>(loadCollectionPanel(currentCollection.uuid));
index 6e57ab47142fa5744165b8f9e6b906e1b3b382b4..216ec66967be4c3ab7085dfff7970fd18c309549 100644 (file)
@@ -45,8 +45,8 @@ const memoizedMapStateToProps = () => {
 };
 
 const mapDispatchToProps = (dispatch: Dispatch): Pick<CollectionPanelFilesProps, 'onSearchChange' | 'onFileClick' | 'onUploadDataClick' | 'onCollapseToggle' | 'onSelectionToggle' | 'onItemMenuOpen' | 'onOptionsMenuOpen'> => ({
-    onUploadDataClick: () => {
-        dispatch<any>(openUploadCollectionFilesDialog());
+    onUploadDataClick: (targetLocation?: string) => {
+        dispatch<any>(openUploadCollectionFilesDialog(targetLocation));
     },
     onCollapseToggle: (id) => {
         dispatch(collectionPanelFilesAction.TOGGLE_COLLECTION_FILE_COLLAPSE({ id }));
index 2299777517e2f5e521740045318652dcb9b25a82..81dbb0e7432cb9e1fa8b2aad3d677989963137ea 100644 (file)
@@ -13,8 +13,9 @@ export const FilesUploadCollectionDialog = compose(
     withDialog(COLLECTION_UPLOAD_FILES_DIALOG),
     reduxForm<CollectionCreateFormDialogData>({
         form: COLLECTION_UPLOAD_FILES_DIALOG,
-        onSubmit: (data, dispatch) => {
-            dispatch(submitCollectionFiles());
+        onSubmit: (data, dispatch, dialog: any) => {
+            const targetLocation = (dialog.data || {}).targetLocation;
+            dispatch(submitCollectionFiles(targetLocation));
         }
     })
 )(DialogCollectionFilesUpload);