Merge branch '21128-toolbar-context-menu'
[arvados-workbench2.git] / src / services / common-service / common-service.ts
index 6c2ba8fb529728ee4c6fd7ad22be9abd40959275..8e9fe631701bd0877075774f6d3666dd9fa73ec1 100644 (file)
@@ -2,11 +2,12 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import * as _ from "lodash";
-import { AxiosInstance, AxiosPromise } from "axios";
-import * as uuid from "uuid/v4";
+import { camelCase, isPlainObject, isArray, snakeCase } from "lodash";
+import { AxiosInstance, AxiosPromise, AxiosRequestConfig } from "axios";
+import uuid from "uuid/v4";
 import { ApiActions } from "services/api/api-actions";
-import * as QueryString from "query-string";
+import QueryString from "query-string";
+import { Session } from "models/session";
 
 interface Errors {
     status: number;
@@ -48,12 +49,12 @@ export class CommonService<T> {
     }
 
     static mapResponseKeys = (response: { data: any }) =>
-        CommonService.mapKeys(_.camelCase)(response.data)
+        CommonService.mapKeys(camelCase)(response.data)
 
     static mapKeys = (mapFn: (key: string) => string) =>
         (value: any): any => {
             switch (true) {
-                case _.isPlainObject(value):
+                case isPlainObject(value):
                     return Object
                         .keys(value)
                         .map(key => [key, mapFn(key)])
@@ -61,14 +62,14 @@ export class CommonService<T> {
                             ...newValue,
                             [newKey]: (key === 'items') ? CommonService.mapKeys(mapFn)(value[key]) : value[key]
                         }), {});
-                case _.isArray(value):
+                case isArray(value):
                     return value.map(CommonService.mapKeys(mapFn));
                 default:
                     return value;
             }
         }
 
-    private validateUuid(uuid: string) {
+    protected validateUuid(uuid: string) {
         if (uuid === "") {
             throw new Error('UUID cannot be empty string');
         }
@@ -86,83 +87,106 @@ export class CommonService<T> {
                 return mapKeys ? CommonService.mapResponseKeys(response) : response.data;
             })
             .catch(({ response }) => {
-                actions.progressFn(reqId, false);
-                const errors = CommonService.mapResponseKeys(response) as Errors;
-                errors.status = response.status;
-                actions.errorFn(reqId, errors, showErrors);
-                throw errors;
+                if (response) {
+                    actions.progressFn(reqId, false);
+                    const errors = CommonService.mapResponseKeys(response) as Errors;
+                    errors.status = response.status;
+                    actions.errorFn(reqId, errors, showErrors);
+                    throw errors;
+                }
             });
     }
 
     create(data?: Partial<T>, showErrors?: boolean) {
         return CommonService.defaultResponse(
             this.serverApi
-                .post<T>(`/${this.resourceType}`, data && CommonService.mapKeys(_.snakeCase)(data)),
+                .post<T>(`/${this.resourceType}`, data && CommonService.mapKeys(snakeCase)(data)),
             this.actions,
             true, // mapKeys
             showErrors
         );
     }
 
-    delete(uuid: string): Promise<T> {
+    delete(uuid: string, showErrors?: boolean): Promise<T> {
         this.validateUuid(uuid);
         return CommonService.defaultResponse(
             this.serverApi
                 .delete(`/${this.resourceType}/${uuid}`),
-            this.actions
+            this.actions,
+            true, // mapKeys
+            showErrors
         );
     }
 
-    get(uuid: string, showErrors?: boolean) {
+    get(uuid: string, showErrors?: boolean, select?: string[], session?: Session) {
         this.validateUuid(uuid);
+
+        const cfg: AxiosRequestConfig = {
+            params: {
+                select: select
+                    ? `[${select.map(snakeCase).map(s => `"${s}"`).join(',')}]`
+                    : undefined
+            }
+        };
+        if (session) {
+            cfg.baseURL = session.baseUrl;
+            cfg.headers = { 'Authorization': 'Bearer ' + session.token };
+        }
+
         return CommonService.defaultResponse(
             this.serverApi
-                .get<T>(`/${this.resourceType}/${uuid}`),
+                .get<T>(`/${this.resourceType}/${uuid}`, cfg),
             this.actions,
             true, // mapKeys
             showErrors
         );
     }
 
-    list(args: ListArguments = {}): Promise<ListResults<T>> {
-        const { filters, order, ...other } = args;
+    list(args: ListArguments = {}, showErrors?: boolean): Promise<ListResults<T>> {
+        const { filters, select, ...other } = args;
         const params = {
-            ...CommonService.mapKeys(_.snakeCase)(other),
+            ...CommonService.mapKeys(snakeCase)(other),
             filters: filters ? `[${filters}]` : undefined,
-            order: order ? order : undefined
+            select: select
+                ? `[${select.map(snakeCase).map(s => `"${s}"`).join(', ')}]`
+                : undefined
         };
 
         if (QueryString.stringify(params).length <= 1500) {
             return CommonService.defaultResponse(
                 this.serverApi.get(`/${this.resourceType}`, { params }),
-                this.actions
+                this.actions,
+                true,
+                showErrors
             );
         } else {
             // Using the POST special case to avoid URI length 414 errors.
-            const formData = new FormData();
+            // We must use urlencoded post body since api doesn't support form data
+            // const formData = new FormData();
+            const formData = new URLSearchParams();
             formData.append("_method", "GET");
-            Object.keys(params).map(key => {
+            Object.keys(params).forEach(key => {
                 if (params[key] !== undefined) {
                     formData.append(key, params[key]);
                 }
             });
             return CommonService.defaultResponse(
-                this.serverApi.post(`/${this.resourceType}`, formData, {
-                    params: {
-                        _method: 'GET'
-                    }
-                }),
-                this.actions
+                this.serverApi.post(`/${this.resourceType}`, formData, {}),
+                this.actions,
+                true,
+                showErrors
             );
         }
     }
 
-    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
+                .put<T>(`/${this.resourceType}/${uuid}`, data && CommonService.mapKeys(snakeCase)(data)),
+            this.actions,
+            undefined, // mapKeys
+            showErrors
         );
     }
 }