[ARVADOS-WORKBENCH2] updated: 1.3.0-236-g3b7eae04

Git user git at public.curoverse.com
Sun Dec 23 05:44:56 EST 2018


Summary of changes:
 src/models/search-bar.ts                           |  8 +--
 .../common-service/common-resource-service.ts      |  5 +-
 src/services/groups-service/groups-service.ts      | 22 ++++---
 src/store/auth/auth-action-session.ts              |  2 +-
 src/store/search-bar/search-bar-actions.test.ts    |  9 ++-
 src/store/search-bar/search-bar-actions.ts         | 77 ++++++++++++++--------
 .../search-results-middleware-service.ts           | 35 ++++++----
 .../form-fields/search-bar-form-fields.tsx         | 12 ++--
 8 files changed, 97 insertions(+), 73 deletions(-)

       via  3b7eae043b41eaebd5cd78d3a74584bcc1290ee7 (commit)
      from  1b438678854a42f00e19f351caf0004c7d46ff8c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 3b7eae043b41eaebd5cd78d3a74584bcc1290ee7
Author: Daniel Kos <unodgs at gmail.com>
Date:   Sun Dec 23 11:44:49 2018 +0100

    Add multi cluster search
    
    Feature #14348
    
    Arvados-DCO-1.1-Signed-off-by: Daniel Kos <unodgs at gmail.com>

diff --git a/src/models/search-bar.ts b/src/models/search-bar.ts
index 798f9c8f..effaeed4 100644
--- a/src/models/search-bar.ts
+++ b/src/models/search-bar.ts
@@ -6,7 +6,7 @@ import { ResourceKind } from '~/models/resource';
 
 export type SearchBarAdvanceFormData = {
     type?: ResourceKind;
-    cluster?: ClusterObjectType;
+    cluster?: string;
     projectUuid?: string;
     inTrash: boolean;
     dateFrom: string;
@@ -21,9 +21,3 @@ export interface PropertyValue {
     key: string;
     value: string;
 }
-
-export enum ClusterObjectType {
-    INDIANAPOLIS = "indianapolis",
-    KAISERAUGST = "kaiseraugst",
-    PENZBERG = "penzberg"
-}
diff --git a/src/services/common-service/common-resource-service.ts b/src/services/common-service/common-resource-service.ts
index 471c32fa..17c287d2 100644
--- a/src/services/common-service/common-resource-service.ts
+++ b/src/services/common-service/common-resource-service.ts
@@ -2,7 +2,6 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-import * as _ from "lodash";
 import { AxiosInstance } from "axios";
 import { Resource } from "src/models/resource";
 import { ApiActions } from "~/services/api/api-actions";
@@ -18,11 +17,9 @@ export enum CommonResourceServiceError {
 }
 
 export class CommonResourceService<T extends Resource> extends CommonService<T> {
-
-    constructor(serverApi: AxiosInstance, resourceType: string, actions: ApiActions) {
+   constructor(serverApi: AxiosInstance, resourceType: string, actions: ApiActions) {
         super(serverApi, resourceType, actions);
     }
-    
 }
 
 export const getCommonResourceServiceError = (errorResponse: any) => {
diff --git a/src/services/groups-service/groups-service.ts b/src/services/groups-service/groups-service.ts
index 668a0ac5..7dfd0c13 100644
--- a/src/services/groups-service/groups-service.ts
+++ b/src/services/groups-service/groups-service.ts
@@ -5,7 +5,7 @@
 import * as _ from "lodash";
 import { CommonResourceService } from '~/services/common-service/common-resource-service';
 import { ListResults, ListArguments } from '~/services/common-service/common-service';
-import { AxiosInstance } from "axios";
+import { AxiosInstance, AxiosRequestConfig } from "axios";
 import { CollectionResource } from "~/models/collection";
 import { ProjectResource } from "~/models/project";
 import { ProcessResource } from "~/models/process";
@@ -13,6 +13,7 @@ import { ResourceKind } from '~/models/resource';
 import { TrashableResourceService } from "~/services/common-service/trashable-resource-service";
 import { ApiActions } from "~/services/api/api-actions";
 import { GroupResource } from "~/models/group";
+import { Session } from "~/models/session";
 
 export interface ContentsArguments {
     limit?: number;
@@ -39,7 +40,7 @@ export class GroupsService<T extends GroupResource = GroupResource> extends Tras
         super(serverApi, "groups", actions);
     }
 
-    async contents(uuid: string, args: ContentsArguments = {}): Promise<ListResults<GroupContentsResource>> {
+    async contents(uuid: string, args: ContentsArguments = {}, session?: Session): Promise<ListResults<GroupContentsResource>> {
         const { filters, order, ...other } = args;
         const params = {
             ...other,
@@ -48,17 +49,18 @@ export class GroupsService<T extends GroupResource = GroupResource> extends Tras
         };
 
         const pathUrl = uuid ? `${uuid}/contents` : 'contents';
+
+        const cfg: AxiosRequestConfig = { params: CommonResourceService.mapKeys(_.snakeCase)(params) };
+        if (session) {
+            cfg.baseURL = session.baseUrl;
+        }
+
         const response = await CommonResourceService.defaultResponse(
-                this.serverApi
-                    .get(this.resourceType + pathUrl, {
-                        params: CommonResourceService.mapKeys(_.snakeCase)(params)
-                    }),
-                this.actions,
-                false
-            );
+            this.serverApi.get(this.resourceType + pathUrl, cfg), this.actions, false
+        );
 
         const { items, ...res } = response;
-        const mappedItems = items.map((item: GroupContentsResource) => {
+        const mappedItems = (items || []).map((item: GroupContentsResource) => {
             const mappedItem = TrashableResourceService.mapKeys(_.camelCase)(item);
             if (item.kind === ResourceKind.COLLECTION || item.kind === ResourceKind.PROJECT) {
                 const { properties } = item;
diff --git a/src/store/auth/auth-action-session.ts b/src/store/auth/auth-action-session.ts
index e5e2e575..46ecc441 100644
--- a/src/store/auth/auth-action-session.ts
+++ b/src/store/auth/auth-action-session.ts
@@ -99,7 +99,7 @@ const clusterLogin = async (clusterId: string, baseUrl: string, activeSession: S
     };
 };
 
-const getActiveSession = (sessions: Session[]): Session | undefined => sessions.find(s => s.active);
+export const getActiveSession = (sessions: Session[]): Session | undefined => sessions.find(s => s.active);
 
 export const validateCluster = async (remoteHost: string, clusterId: string, activeSession: Session): Promise<{ user: User; token: string, baseUrl: string }> => {
     const baseUrl = await getRemoteHostBaseUrl(remoteHost);
diff --git a/src/store/search-bar/search-bar-actions.test.ts b/src/store/search-bar/search-bar-actions.test.ts
index aa6e4759..ea290b4d 100644
--- a/src/store/search-bar/search-bar-actions.test.ts
+++ b/src/store/search-bar/search-bar-actions.test.ts
@@ -4,7 +4,6 @@
 
 import { getAdvancedDataFromQuery, getQueryFromAdvancedData, parseSearchQuery } from "~/store/search-bar/search-bar-actions";
 import { ResourceKind } from "~/models/resource";
-import { ClusterObjectType } from "~/models/search-bar";
 
 describe('search-bar-actions', () => {
     describe('parseSearchQuery', () => {
@@ -95,11 +94,11 @@ describe('search-bar-actions', () => {
         });
 
         it('should correctly build advanced data record from query #2', () => {
-            const r = getAdvancedDataFromQuery('document from:2017-08-01 pdf has:filesize:101mb is:trashed type:arvados#collection cluster:indianapolis');
+            const r = getAdvancedDataFromQuery('document from:2017-08-01 pdf has:filesize:101mb is:trashed type:arvados#collection cluster:c97qx');
             expect(r).toEqual({
                 searchValue: 'document pdf',
                 type: ResourceKind.COLLECTION,
-                cluster: ClusterObjectType.INDIANAPOLIS,
+                cluster: 'c97qx',
                 projectUuid: undefined,
                 inTrash: true,
                 dateFrom: '2017-08-01',
@@ -119,7 +118,7 @@ describe('search-bar-actions', () => {
             const q = getQueryFromAdvancedData({
                 searchValue: 'document pdf',
                 type: ResourceKind.COLLECTION,
-                cluster: ClusterObjectType.INDIANAPOLIS,
+                cluster: 'c97qx',
                 projectUuid: undefined,
                 inTrash: true,
                 dateFrom: '2017-08-01',
@@ -131,7 +130,7 @@ describe('search-bar-actions', () => {
                 saveQuery: false,
                 queryName: ''
             });
-            expect(q).toBe('document pdf type:arvados#collection cluster:indianapolis is:trashed from:2017-08-01 has:filesize:101mb');
+            expect(q).toBe('document pdf type:arvados#collection cluster:c97qx is:trashed from:2017-08-01 has:filesize:101mb');
         });
     });
 });
diff --git a/src/store/search-bar/search-bar-actions.ts b/src/store/search-bar/search-bar-actions.ts
index 199ec3f9..cfa07ebc 100644
--- a/src/store/search-bar/search-bar-actions.ts
+++ b/src/store/search-bar/search-bar-actions.ts
@@ -15,11 +15,12 @@ import { GroupClass } from '~/models/group';
 import { SearchView } from '~/store/search-bar/search-bar-reducer';
 import { navigateTo, navigateToSearchResults } from '~/store/navigation/navigation-action';
 import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
-import { ClusterObjectType, PropertyValue, SearchBarAdvanceFormData } from '~/models/search-bar';
+import { PropertyValue, SearchBarAdvanceFormData } from '~/models/search-bar';
 import { debounce } from 'debounce';
 import * as _ from "lodash";
 import { getModifiedKeysValues } from "~/common/objects";
 import { activateSearchBarProject } from "~/store/search-bar/search-bar-tree-actions";
+import { Session } from "~/models/session";
 
 export const searchBarActions = unionize({
     SET_CURRENT_VIEW: ofType<string>(),
@@ -205,13 +206,18 @@ const searchGroups = (searchValue: string, limit: number) =>
         const currentView = getState().searchBar.currentView;
 
         if (searchValue || currentView === SearchView.ADVANCED) {
-            const filters = getFilters('name', searchValue);
-            const { items } = await services.groupsService.contents('', {
-                filters,
-                limit,
-                recursive: true
+            const sq = parseSearchQuery(searchValue);
+            const clusterId = getSearchQueryFirstProp(sq, 'cluster');
+            const sessions = getSearchSessions(clusterId, getState().auth.sessions);
+            sessions.forEach(async session => {
+                const filters = getFilters('name', searchValue, sq);
+                const { items } = await services.groupsService.contents('', {
+                    filters,
+                    limit,
+                    recursive: true
+                }, session);
+                dispatch(searchBarActions.SET_SEARCH_RESULTS(items));
             });
-            dispatch(searchBarActions.SET_SEARCH_RESULTS(items));
         }
     };
 
@@ -288,7 +294,7 @@ export const getQueryFromAdvancedData = (data: SearchBarAdvanceFormData, prevDat
     return value;
 };
 
-export interface ParseSearchQuery {
+export class ParseSearchQuery {
     hasKeywords: boolean;
     values: string[];
     properties: {
@@ -351,9 +357,9 @@ export const parseSearchQuery: (query: string) => ParseSearchQuery = (searchValu
     return { hasKeywords: keywordsCnt > 0, values, properties };
 };
 
-const getFirstProp = (sq: ParseSearchQuery, name: string) => sq.properties[name] && sq.properties[name][0];
-const getPropValue = (sq: ParseSearchQuery, name: string, value: string) => sq.properties[name] && sq.properties[name].find((v: string) => v === value);
-const getProperties = (sq: ParseSearchQuery): PropertyValue[] => {
+export const getSearchQueryFirstProp = (sq: ParseSearchQuery, name: string) => sq.properties[name] && sq.properties[name][0];
+export const getSearchQueryPropValue = (sq: ParseSearchQuery, name: string, value: string) => sq.properties[name] && sq.properties[name].find((v: string) => v === value);
+export const getSearchQueryProperties = (sq: ParseSearchQuery): PropertyValue[] => {
     if (sq.properties.has) {
         return sq.properties.has.map((value: string) => {
             const v = value.split(':');
@@ -371,23 +377,26 @@ export const getAdvancedDataFromQuery = (query: string): SearchBarAdvanceFormDat
 
     return {
         searchValue: sq.values.join(' '),
-        type: getFirstProp(sq, 'type') as ResourceKind,
-        cluster: getFirstProp(sq, 'cluster') as ClusterObjectType,
-        projectUuid: getFirstProp(sq, 'project'),
-        inTrash: getPropValue(sq, 'is', 'trashed') !== undefined,
-        dateFrom: getFirstProp(sq, 'from'),
-        dateTo: getFirstProp(sq, 'to'),
-        properties: getProperties(sq),
+        type: getSearchQueryFirstProp(sq, 'type') as ResourceKind,
+        cluster: getSearchQueryFirstProp(sq, 'cluster'),
+        projectUuid: getSearchQueryFirstProp(sq, 'project'),
+        inTrash: getSearchQueryPropValue(sq, 'is', 'trashed') !== undefined,
+        dateFrom: getSearchQueryFirstProp(sq, 'from'),
+        dateTo: getSearchQueryFirstProp(sq, 'to'),
+        properties: getSearchQueryProperties(sq),
         saveQuery: false,
         queryName: ''
     };
 };
 
-export const getFilters = (filterName: string, searchValue: string): string => {
+export const getSearchSessions = (clusterId: string | undefined, sessions: Session[]): Session[] => {
+    return sessions.filter(s => s.loggedIn && (!clusterId || s.clusterId === clusterId));
+};
+
+export const getFilters = (filterName: string, searchValue: string, sq: ParseSearchQuery): string => {
     const filter = new FilterBuilder();
-    const sq = parseSearchQuery(searchValue);
 
-    const resourceKind = getFirstProp(sq, 'type') as ResourceKind;
+    const resourceKind = getSearchQueryFirstProp(sq, 'type') as ResourceKind;
 
     let prefix = '';
     switch (resourceKind) {
@@ -402,11 +411,16 @@ export const getFilters = (filterName: string, searchValue: string): string => {
             break;
     }
 
+    const isTrashed = getSearchQueryPropValue(sq, 'is', 'trashed');
+
     if (!sq.hasKeywords) {
         filter
             .addILike(filterName, searchValue, GroupContentsResourcePrefix.COLLECTION)
-            .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROCESS)
             .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROJECT);
+
+        if (isTrashed) {
+            filter.addILike(filterName, searchValue, GroupContentsResourcePrefix.PROCESS);
+        }
     } else {
         if (prefix) {
             sq.values.forEach(v =>
@@ -416,33 +430,38 @@ export const getFilters = (filterName: string, searchValue: string): string => {
             sq.values.forEach(v => {
                 filter
                     .addILike(filterName, v, GroupContentsResourcePrefix.COLLECTION)
-                    .addILike(filterName, v, GroupContentsResourcePrefix.PROCESS)
                     .addILike(filterName, v, GroupContentsResourcePrefix.PROJECT);
+
+                if (isTrashed) {
+                    filter.addILike(filterName, v, GroupContentsResourcePrefix.PROCESS);
+                }
             });
         }
 
-        if (getPropValue(sq, 'is', 'trashed')) {
+        if (isTrashed) {
             filter.addEqual("is_trashed", true);
         }
 
-        const projectUuid = getFirstProp(sq, 'project');
+        const projectUuid = getSearchQueryFirstProp(sq, 'project');
         if (projectUuid) {
             filter.addEqual('uuid', projectUuid, prefix);
         }
 
-        const dateFrom = getFirstProp(sq, 'from');
+        const dateFrom = getSearchQueryFirstProp(sq, 'from');
         if (dateFrom) {
             filter.addGte('modified_at', buildDateFilter(dateFrom));
         }
 
-        const dateTo = getFirstProp(sq, 'to');
+        const dateTo = getSearchQueryFirstProp(sq, 'to');
         if (dateTo) {
             filter.addLte('modified_at', buildDateFilter(dateTo));
         }
 
-        const props = getProperties(sq);
+        const props = getSearchQueryProperties(sq);
         props.forEach(p => {
-            // filter.addILike(`properties.${p.key}`, p.value);
+            if (p.value) {
+                filter.addILike(`properties.${p.key}`, p.value);
+            }
             filter.addExists(p.key);
         });
     }
diff --git a/src/store/search-results-panel/search-results-middleware-service.ts b/src/store/search-results-panel/search-results-middleware-service.ts
index aa09838e..5e806e71 100644
--- a/src/store/search-results-panel/search-results-middleware-service.ts
+++ b/src/store/search-results-panel/search-results-middleware-service.ts
@@ -15,8 +15,14 @@ import { OrderDirection, OrderBuilder } from '~/services/api/order-builder';
 import { GroupContentsResource, GroupContentsResourcePrefix } from "~/services/groups-service/groups-service";
 import { ListResults } from '~/services/common-service/common-service';
 import { searchResultsPanelActions } from '~/store/search-results-panel/search-results-panel-actions';
-import { getFilters } from '~/store/search-bar/search-bar-actions';
+import {
+    getFilters,
+    getSearchQueryFirstProp,
+    getSearchSessions, ParseSearchQuery,
+    parseSearchQuery
+} from '~/store/search-bar/search-bar-actions';
 import { getSortColumn } from "~/store/data-explorer/data-explorer-reducer";
+import { Session } from "~/models/session";
 
 export class SearchResultsMiddlewareService extends DataExplorerMiddlewareService {
     constructor(private services: ServiceRepository, id: string) {
@@ -28,19 +34,24 @@ export class SearchResultsMiddlewareService extends DataExplorerMiddlewareServic
         const userUuid = state.auth.user!.uuid;
         const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
         const searchValue = state.searchBar.searchValue;
-        try {
-            const response = await this.services.groupsService.contents('', getParams(dataExplorer, searchValue));
-            api.dispatch(updateResources(response.items));
-            api.dispatch(setItems(response));
-        } catch {
-            api.dispatch(couldNotFetchSearchResults());
-        }
+        const sq = parseSearchQuery(searchValue);
+        const clusterId = getSearchQueryFirstProp(sq, 'cluster');
+        const sessions = getSearchSessions(clusterId, state.auth.sessions);
+        sessions.forEach(async session => {
+            try {
+                const response = await this.services.groupsService.contents(userUuid, getParams(dataExplorer, searchValue, sq), session);
+                api.dispatch(updateResources(response.items));
+                api.dispatch(setItems(response));
+            } catch {
+                api.dispatch(couldNotFetchSearchResults(session));
+            }
+        });
     }
 }
 
-export const getParams = (dataExplorer: DataExplorer, searchValue: string) => ({
+export const getParams = (dataExplorer: DataExplorer, searchValue: string, sq: ParseSearchQuery) => ({
     ...dataExplorerToListParams(dataExplorer),
-    filters: getFilters('name', searchValue),
+    filters: getFilters('name', searchValue, sq),
     order: getOrder(dataExplorer)
 });
 
@@ -69,8 +80,8 @@ export const setItems = (listResults: ListResults<GroupContentsResource>) =>
         items: listResults.items.map(resource => resource.uuid),
     });
 
-const couldNotFetchSearchResults = () =>
+const couldNotFetchSearchResults = (session: Session) =>
     snackbarActions.OPEN_SNACKBAR({
-        message: 'Could not fetch search results.',
+        message: `Could not fetch search results for ${session.clusterId}.`,
         kind: SnackbarKind.ERROR
     });
diff --git a/src/views-components/form-fields/search-bar-form-fields.tsx b/src/views-components/form-fields/search-bar-form-fields.tsx
index 6fb23498..8de48ea7 100644
--- a/src/views-components/form-fields/search-bar-form-fields.tsx
+++ b/src/views-components/form-fields/search-bar-form-fields.tsx
@@ -8,7 +8,6 @@ import { TextField, DateTextField } from "~/components/text-field/text-field";
 import { CheckboxField } from '~/components/checkbox-field/checkbox-field';
 import { NativeSelectField } from '~/components/select-field/select-field';
 import { ResourceKind } from '~/models/resource';
-import { ClusterObjectType } from '~/models/search-bar';
 import { HomeTreePicker } from '~/views-components/projects-tree-picker/home-tree-picker';
 import { SEARCH_BAR_ADVANCE_FORM_PICKER_ID } from '~/store/search-bar/search-bar-actions';
 import { SearchBarAdvancedPropertiesView } from '~/views-components/search-bar/search-bar-advanced-properties-view';
@@ -39,10 +38,13 @@ interface SearchBarClusterFieldProps {
 
 export const SearchBarClusterField = connect(
     (state: RootState) => ({
-        clusters: [{key: '', value: 'Any'}].concat(state.auth.sessions.map(s => ({
-            key: s.clusterId,
-            value: s.clusterId
-        })))
+        clusters: [{key: '', value: 'Any'}].concat(
+            state.auth.sessions
+                .filter(s => s.loggedIn)
+                .map(s => ({
+                    key: s.clusterId,
+                    value: s.clusterId
+                })))
     }))((props: SearchBarClusterFieldProps) => <Field
         name='cluster'
         component={NativeSelectField}

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list