Add more error handlers
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 21 Aug 2018 07:30:15 +0000 (09:30 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Tue, 21 Aug 2018 07:30:15 +0000 (09:30 +0200)
Feature #13831

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

src/common/api/common-resource-service.ts
src/services/services.ts
src/views-components/move-to-dialog/move-to-dialog.tsx

index da5bc33cf7c08f33af05e7e5c938c6b9e0663bc4..53084b4bb5e0f3ab00c2a52e94130a4c2c50368e 100644 (file)
@@ -31,6 +31,7 @@ export interface Errors {
 
 export enum CommonResourceServiceError {
     UNIQUE_VIOLATION = 'UniqueViolation',
+    OWNERSHIP_CYCLE = 'OwnershipCycle',
     UNKNOWN = 'Unknown',
     NONE = 'None'
 }
@@ -104,10 +105,10 @@ export class CommonResourceService<T extends Resource> {
                 }));
     }
 
-    update(uuid: string, data: any) {
+    update(uuid: string, data: Partial<T>) {
         return CommonResourceService.defaultResponse(
             this.serverApi
-                .put<T>(this.resourceType + uuid, data));
+                .put<T>(this.resourceType + uuid, data && CommonResourceService.mapKeys(_.snakeCase)(data)));
 
     }
 }
@@ -118,6 +119,8 @@ export const getCommonResourceServiceError = (errorResponse: any) => {
         switch (true) {
             case /UniqueViolation/.test(error):
                 return CommonResourceServiceError.UNIQUE_VIOLATION;
+            case /Owner uuid has an ownership cycle/.test(error):
+                return CommonResourceServiceError.OWNERSHIP_CYCLE;
             default:
                 return CommonResourceServiceError.UNKNOWN;
         }
index c2615a34e7211acdbd75322c90fa9dbf6f839681..d3e82f93d7cd582f8a85f2ee81f0ac46e5776c71 100644 (file)
@@ -14,7 +14,8 @@ import { CollectionFilesService } from "./collection-files-service/collection-fi
 import { KeepService } from "./keep-service/keep-service";
 import { WebDAV } from "../common/webdav";
 import { Config } from "../common/config";
-import { ResourceKind } from '~/models/resource';
+import { ResourceKind, Resource } from '~/models/resource';
+import { CommonResourceService } from '../common/api/common-resource-service';
 
 export type ServiceRepository = ReturnType<typeof createServices>;
 
@@ -50,7 +51,7 @@ export const createServices = (config: Config) => {
     };
 };
 
-export const getResourceService = (resourceKind: ResourceKind, serviceRepository: ServiceRepository) => {
+export const getResourceService = (resourceKind: ResourceKind, serviceRepository: ServiceRepository): undefined | CommonResourceService<Resource> => {
     switch (resourceKind) {
         case ResourceKind.PROJECT:
             return serviceRepository.projectService;
index e45bc22bb3eb91b4939f927244cb5f5064c760b4..ad3db4829ee7b5af581b3b1b42cd19f1ce036f68 100644 (file)
@@ -40,13 +40,15 @@ export const moveResource = (resource: MoveToDialogResource) =>
         if (service) {
             try {
                 const originalResource = await service.get(resource.uuid);
-                await service.update(resource.uuid, { ...originalResource, owner_uuid: resource.ownerUuid });
+                await service.update(resource.uuid, { ...originalResource, ownerUuid: resource.ownerUuid });
                 dispatch(dialogActions.CLOSE_DIALOG({ id: MOVE_TO_DIALOG }));
                 dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Resource has been moved', hideDuration: 2000 }));
             } catch (e) {
                 const error = getCommonResourceServiceError(e);
                 if (error === CommonResourceServiceError.UNIQUE_VIOLATION) {
-                    dispatch(stopSubmit(MOVE_TO_DIALOG, { ownerUuid: 'A resource with the same name already exists in the target project' }));
+                    dispatch(stopSubmit(MOVE_TO_DIALOG, { ownerUuid: 'A resource with the same name already exists in the target project.' }));
+                } else if (error === CommonResourceServiceError.OWNERSHIP_CYCLE) {
+                    dispatch(stopSubmit(MOVE_TO_DIALOG, { ownerUuid: 'Cannot move a project into itself.' }));
                 } else {
                     dispatch(dialogActions.CLOSE_DIALOG({ id: MOVE_TO_DIALOG }));
                     dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not move the resource.', hideDuration: 2000 }));
@@ -77,16 +79,18 @@ const MoveToDialogFields = (props: InjectedFormProps<MoveToDialogResource>) =>
         component={Picker}
         validate={validation} />;
 
-const sameUuid = (value: string, allValues: MoveToDialogResource) =>
-    value === allValues.uuid && 'Cannot move the project to itself';
-
-const validation = [require, sameUuid];
+const validation = [require];
 
 const Picker = (props: WrappedFieldProps) =>
-    <div style={{ height: '144px', display: 'flex', flexDirection: 'column' }}>
-        <ProjectTreePicker onChange={projectUuid => props.input.onChange(projectUuid)} />
+    <div style={{ height: '200px', display: 'flex', flexDirection: 'column' }}>
+        <ProjectTreePicker onChange={handleChange(props)} />
         {props.meta.dirty && props.meta.error &&
             <Typography variant='caption' color='error'>
                 {props.meta.error}
             </Typography>}
     </div>;
+
+const handleChange = (props: WrappedFieldProps) => (value: string) =>
+    props.input.value === value
+        ? props.input.onChange('')
+        : props.input.onChange(value);
\ No newline at end of file