20031: Add ability to create and update collections during replace_files, moveFiles...
authorStephen Smith <stephen@curii.com>
Wed, 12 Apr 2023 13:38:27 +0000 (09:38 -0400)
committerStephen Smith <stephen@curii.com>
Wed, 12 Apr 2023 13:38:27 +0000 (09:38 -0400)
Used to optimize move/copy to new to reduce api calls

Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

src/services/collection-service/collection-service.test.ts
src/services/collection-service/collection-service.ts
src/store/collections/collection-partial-copy-actions.ts
src/store/collections/collection-partial-move-actions.ts

index 304cbfd3110d056fa57f12cd0c455b1d53ffee6c..c8e907d379b4c657f3abb6cbc605e28853719585 100644 (file)
@@ -234,7 +234,7 @@ describe('collection-service', () => {
             const destinationPath = '/destinationPath';
 
             // when
-            await collectionService.copyFiles(sourcePdh, filePaths, destinationUuid, destinationPath);
+            await collectionService.copyFiles(sourcePdh, filePaths, {uuid: destinationUuid}, destinationPath);
 
             // then
             expect(serverApi.put).toHaveBeenCalledTimes(1);
@@ -261,7 +261,7 @@ describe('collection-service', () => {
             const destinationUuid = 'zzzzz-4zz18-ywq0rvhwwhkjnfq';
             const destinationPath = '/destinationPath';
 
-            await collectionService.copyFiles(sourcePdh, filePaths, destinationUuid, destinationPath);
+            await collectionService.copyFiles(sourcePdh, filePaths, {uuid: destinationUuid}, destinationPath);
 
             expect(serverApi.put).toHaveBeenCalledTimes(1);
             expect(serverApi.put).toHaveBeenCalledWith(
@@ -285,7 +285,7 @@ describe('collection-service', () => {
             const destinationUuid = 'zzzzz-4zz18-ywq0rvhwwhkjnfq';
             const destinationPath = '/';
 
-            await collectionService.copyFiles(sourcePdh, filePaths, destinationUuid, destinationPath);
+            await collectionService.copyFiles(sourcePdh, filePaths, {uuid: destinationUuid}, destinationPath);
 
             expect(serverApi.put).toHaveBeenCalledTimes(1);
             expect(serverApi.put).toHaveBeenCalledWith(
@@ -313,7 +313,7 @@ describe('collection-service', () => {
             const destinationPath = '/destinationPath';
 
             // when
-            await collectionService.moveFiles(srcCollectionUUID, srcCollectionPdh, filePaths, destinationUuid, destinationPath);
+            await collectionService.moveFiles(srcCollectionUUID, srcCollectionPdh, filePaths, {uuid: destinationUuid}, destinationPath);
 
             // then
             expect(serverApi.put).toHaveBeenCalledTimes(2);
@@ -357,7 +357,7 @@ describe('collection-service', () => {
             const destinationPath = '/destinationPath';
 
             // when
-            await collectionService.moveFiles(srcCollectionUUID, srcCollectionPdh, filePaths, srcCollectionUUID, destinationPath);
+            await collectionService.moveFiles(srcCollectionUUID, srcCollectionPdh, filePaths, {uuid: srcCollectionUUID}, destinationPath);
 
             // then
             expect(serverApi.put).toHaveBeenCalledTimes(1);
@@ -399,7 +399,7 @@ describe('collection-service', () => {
 
             // when
             try {
-                await collectionService.moveFiles(srcCollectionUUID, srcCollectionPdh, filePaths, destinationUuid, destinationPath);
+                await collectionService.moveFiles(srcCollectionUUID, srcCollectionPdh, filePaths, {uuid: destinationUuid}, destinationPath);
             } catch {}
 
             // then
index 74cf75956f7cec87a36abb8f0fdcaee5b7e0883e..7d734fa67993d23cfdf8fc17ff22593dbb94a489 100644 (file)
@@ -12,8 +12,11 @@ import { TrashableResourceService } from "services/common-service/trashable-reso
 import { ApiActions } from "services/api/api-actions";
 import { Session } from "models/session";
 import { CommonService } from "services/common-service/common-service";
+import { snakeCase } from "lodash";
 
 export type UploadProgress = (fileId: number, loaded: number, total: number, currentTime: number) => void;
+type CollectionPartialUpdateOrCreate =  Partial<CollectionResource> & Pick<CollectionResource, "uuid"> |
+                                        Partial<CollectionResource> & Pick<CollectionResource, "ownerUuid">;
 
 export const emptyCollectionPdh = 'd41d8cd98f00b204e9800998ecf8427e+0';
 
@@ -67,21 +70,33 @@ export class CollectionService extends TrashableResourceService<CollectionResour
         }, "/");
     }
 
-    private replaceFiles(collectionUuid: string, fileMap: {}, showErrors?: boolean) {
+    private replaceFiles(data: CollectionPartialUpdateOrCreate, fileMap: {}, showErrors?: boolean) {
         const payload = {
             collection: {
-                preserve_version: true
+                preserve_version: true,
+                ...CommonService.mapKeys(snakeCase)(data),
+                // Don't send uuid in payload when creating
+                uuid: undefined,
             },
             replace_files: fileMap
         };
-
-        return CommonService.defaultResponse(
-            this.serverApi
-                .put<CollectionResource>(`/${this.resourceType}/${collectionUuid}`, payload),
-            this.actions,
-            true, // mapKeys
-            showErrors
-        );
+        if (data.uuid) {
+            return CommonService.defaultResponse(
+                this.serverApi
+                    .put<CollectionResource>(`/${this.resourceType}/${data.uuid}`, payload),
+                this.actions,
+                true, // mapKeys
+                showErrors
+            );
+        } else {
+            return CommonService.defaultResponse(
+                this.serverApi
+                    .post<CollectionResource>(`/${this.resourceType}`, payload),
+                this.actions,
+                true, // mapKeys
+                showErrors
+            );
+        }
     }
 
     async uploadFiles(collectionUuid: string, files: File[], onProgress?: UploadProgress, targetLocation: string = '') {
@@ -94,7 +109,7 @@ export class CollectionService extends TrashableResourceService<CollectionResour
     }
 
     async renameFile(collectionUuid: string, collectionPdh: string, oldPath: string, newPath: string) {
-        return this.replaceFiles(collectionUuid, {
+        return this.replaceFiles({uuid: collectionUuid}, {
             [this.combineFilePath([newPath])]: `${collectionPdh}${this.combineFilePath([oldPath])}`,
             [this.combineFilePath([oldPath])]: '',
         });
@@ -152,10 +167,10 @@ export class CollectionService extends TrashableResourceService<CollectionResour
             }
         }, {})
 
-        return this.replaceFiles(collectionUuid, fileMap, showErrors);
+        return this.replaceFiles({uuid: collectionUuid}, fileMap, showErrors);
     }
 
-    copyFiles(sourcePdh: string, files: string[], destinationCollectionUuid: string, destinationPath: string, showErrors?: boolean) {
+    copyFiles(sourcePdh: string, files: string[], destinationCollection: CollectionPartialUpdateOrCreate, destinationPath: string, showErrors?: boolean) {
         const fileMap = files.reduce((obj, sourceFile) => {
             const sourceFileName = sourceFile.split('/').filter(Boolean).slice(-1).join("");
             return {
@@ -164,11 +179,11 @@ export class CollectionService extends TrashableResourceService<CollectionResour
             };
         }, {});
 
-        return this.replaceFiles(destinationCollectionUuid, fileMap, showErrors);
+        return this.replaceFiles(destinationCollection, fileMap, showErrors);
     }
 
-    moveFiles(sourceUuid: string, sourcePdh: string, files: string[], destinationCollectionUuid: string, destinationPath: string, showErrors?: boolean) {
-        if (sourceUuid === destinationCollectionUuid) {
+    moveFiles(sourceUuid: string, sourcePdh: string, files: string[], destinationCollection: CollectionPartialUpdateOrCreate, destinationPath: string, showErrors?: boolean) {
+        if (sourceUuid === destinationCollection.uuid) {
             const fileMap = files.reduce((obj, sourceFile) => {
                 const sourceFileName = sourceFile.split('/').filter(Boolean).slice(-1).join("");
                 return {
@@ -178,9 +193,9 @@ export class CollectionService extends TrashableResourceService<CollectionResour
                 };
             }, {});
 
-            return this.replaceFiles(sourceUuid, fileMap, showErrors)
+            return this.replaceFiles({uuid: sourceUuid}, fileMap, showErrors)
         } else {
-            return this.copyFiles(sourcePdh, files, destinationCollectionUuid, destinationPath, showErrors)
+            return this.copyFiles(sourcePdh, files, destinationCollection, destinationPath, showErrors)
                 .then(() => {
                     return this.deleteFiles(sourceUuid, files, showErrors);
                 });
@@ -190,7 +205,7 @@ export class CollectionService extends TrashableResourceService<CollectionResour
     createDirectory(collectionUuid: string, path: string, showErrors?: boolean) {
         const fileMap = {[this.combineFilePath([path])]: emptyCollectionPdh};
 
-        return this.replaceFiles(collectionUuid, fileMap, showErrors);
+        return this.replaceFiles({uuid: collectionUuid}, fileMap, showErrors);
     }
 
 }
index cccd7023e410e2b4c50e4c9decc7482e65c4ef12..359b6b83808f82fb1d4c06ce062a72f5808e1050 100644 (file)
@@ -55,20 +55,23 @@ export const copyCollectionPartialToNewCollection = ({ name, description, projec
                 dispatch(startSubmit(COLLECTION_PARTIAL_COPY_FORM_NAME));
                 dispatch(progressIndicatorActions.START_WORKING(COLLECTION_PARTIAL_COPY_FORM_NAME));
 
-                // 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})`), ''));
 
                 // Copy files
-                const updatedCollection = await services.collectionService.copyFiles(sourceCollection.portableDataHash, paths, newCollection.uuid, '/', false);
+                const updatedCollection = await services.collectionService.copyFiles(
+                    sourceCollection.portableDataHash,
+                    paths,
+                    {
+                        name,
+                        description,
+                        ownerUuid: projectUuid,
+                        uuid: undefined,
+                    },
+                    '/',
+                    false
+                );
                 dispatch(updateResources([updatedCollection]));
 
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_FORM_NAME }));
@@ -123,7 +126,7 @@ export const copyCollectionPartialToExistingCollection = ({ collectionUuid }: Co
                     .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
 
                 // Copy files
-                const updatedCollection = await services.collectionService.copyFiles(sourceCollection.portableDataHash, paths, collectionUuid, '/', false);
+                const updatedCollection = await services.collectionService.copyFiles(sourceCollection.portableDataHash, paths, {uuid: collectionUuid}, '/', false);
                 dispatch(updateResources([updatedCollection]));
 
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_COPY_TO_SELECTED_COLLECTION }));
index 19cac52db47311c1684b1293d3f63c2d1e3a2fd6..de64d99a09fe3f39a0db72e5007b971ba2f61d9f 100644 (file)
@@ -55,20 +55,24 @@ export const moveCollectionPartialToNewCollection = ({ name, description, projec
                 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);
+                const updatedCollection = await services.collectionService.moveFiles(
+                    sourceCollection.uuid,
+                    sourceCollection.portableDataHash,
+                    paths,
+                    {
+                        name,
+                        description,
+                        ownerUuid: projectUuid,
+                        uuid: undefined,
+                    },
+                    '/',
+                    false
+                );
                 dispatch(updateResources([updatedCollection]));
 
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_NEW_COLLECTION }));
@@ -118,7 +122,7 @@ export const moveCollectionPartialToExistingCollection = ({ collectionUuid }: Co
                     .map(file => file.id.replace(new RegExp(`(^${sourceCollection.uuid})`), ''));
 
                 // Move files
-                const updatedCollection = await services.collectionService.moveFiles(sourceCollection.uuid, sourceCollection.portableDataHash, paths, collectionUuid, '/', false);
+                const updatedCollection = await services.collectionService.moveFiles(sourceCollection.uuid, sourceCollection.portableDataHash, paths, {uuid: collectionUuid}, '/', false);
                 dispatch(updateResources([updatedCollection]));
 
                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_PARTIAL_MOVE_TO_SELECTED_COLLECTION }));