[arvados-workbench2] created: 2.4.0-327-g9700822f

git repository hosting git at public.arvados.org
Fri Oct 28 13:26:07 UTC 2022


        at  9700822f13c7f81939e8344e799d2d30f749c2f7 (commit)


commit 9700822f13c7f81939e8344e799d2d30f749c2f7
Author: Daniel Kutyła <daniel.kutyla at contractors.roche.com>
Date:   Fri Oct 28 15:25:18 2022 +0200

    19275: Fix for race conditions in the full text search bar
    
    Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła <daniel.kutyla at contractors.roche.com>

diff --git a/src/services/common-service/common-service.ts b/src/services/common-service/common-service.ts
index bdae87ab..b8e7dc67 100644
--- a/src/services/common-service/common-service.ts
+++ b/src/services/common-service/common-service.ts
@@ -87,11 +87,13 @@ 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;
+                }
             });
     }
 
diff --git a/src/services/groups-service/groups-service.ts b/src/services/groups-service/groups-service.ts
index dc6a798c..b69483cb 100644
--- a/src/services/groups-service/groups-service.ts
+++ b/src/services/groups-service/groups-service.ts
@@ -2,6 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
+import { CancelToken } from 'axios';
 import { snakeCase, camelCase } from "lodash";
 import { CommonResourceService } from 'services/common-service/common-resource-service';
 import { ListResults, ListArguments } from 'services/common-service/common-service';
@@ -41,7 +42,7 @@ export class GroupsService<T extends GroupResource = GroupResource> extends Tras
         super(serverApi, "groups", actions);
     }
 
-    async contents(uuid: string, args: ContentsArguments = {}, session?: Session): Promise<ListResults<GroupContentsResource>> {
+    async contents(uuid: string, args: ContentsArguments = {}, session?: Session, cancelToken?: CancelToken): Promise<ListResults<GroupContentsResource>> {
         const { filters, order, ...other } = args;
         const params = {
             ...other,
@@ -56,6 +57,10 @@ export class GroupsService<T extends GroupResource = GroupResource> extends Tras
             cfg.headers = { 'Authorization': 'Bearer ' + session.token };
         }
 
+        if (cancelToken) {
+            cfg.cancelToken = cancelToken;
+        }
+
         const response = await CommonResourceService.defaultResponse(
             this.serverApi.get(this.resourceType + pathUrl, cfg), this.actions, false
         );
diff --git a/src/store/search-bar/search-bar-actions.ts b/src/store/search-bar/search-bar-actions.ts
index 7d76ec69..8b03ddd7 100644
--- a/src/store/search-bar/search-bar-actions.ts
+++ b/src/store/search-bar/search-bar-actions.ts
@@ -2,6 +2,7 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
+import axios from "axios";
 import { ofType, unionize, UnionOf } from "common/unionize";
 import { GroupContentsResource, GroupContentsResourcePrefix } from 'services/groups-service/groups-service';
 import { Dispatch } from 'redux';
@@ -62,13 +63,13 @@ export const loadRecentQueries = () =>
         return recentQueries;
     };
 
-export const searchData = (searchValue: string) =>
+export const searchData = (searchValue: string, useCancel = false) =>
     async (dispatch: Dispatch, getState: () => RootState) => {
         const currentView = getState().searchBar.currentView;
         dispatch(searchResultsPanelActions.CLEAR());
         dispatch(searchBarActions.SET_SEARCH_VALUE(searchValue));
         if (searchValue.length > 0) {
-            dispatch<any>(searchGroups(searchValue, 5));
+            dispatch<any>(searchGroups(searchValue, 5, useCancel));
             if (currentView === SearchView.BASIC) {
                 dispatch(searchBarActions.CLOSE_SEARCH_VIEW());
                 dispatch(navigateToSearchResults(searchValue));
@@ -203,26 +204,41 @@ export const submitData = (event: React.FormEvent<HTMLFormElement>) =>
         }
     };
 
-
-const searchGroups = (searchValue: string, limit: number) =>
+let cancelTokens: any[] = [];
+const searchGroups = (searchValue: string, limit: number, useCancel = false) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         const currentView = getState().searchBar.currentView;
 
-        if (searchValue || currentView === SearchView.ADVANCED) {
-            const { cluster: clusterId } = getAdvancedDataFromQuery(searchValue);
-            const sessions = getSearchSessions(clusterId, getState().auth.sessions);
-            const lists: ListResults<GroupContentsResource>[] = await Promise.all(sessions.map(session => {
-                const filters = queryToFilters(searchValue, session.apiRevision);
-                return services.groupsService.contents('', {
-                    filters,
-                    limit,
-                    recursive: true
-                }, session);
-            }));
-
-            const items = lists.reduce((items, list) => items.concat(list.items), [] as GroupContentsResource[]);
-            dispatch(searchBarActions.SET_SEARCH_RESULTS(items));
+        if (cancelTokens.length > 0 && useCancel) {
+            cancelTokens.forEach(cancelToken => (cancelToken as any).cancel('New search request triggered.'));
+            cancelTokens = [];
         }
+
+        setTimeout(async () => {
+            if (searchValue || currentView === SearchView.ADVANCED) {
+                const { cluster: clusterId } = getAdvancedDataFromQuery(searchValue);
+                const sessions = getSearchSessions(clusterId, getState().auth.sessions);
+                const lists: ListResults<GroupContentsResource>[] = await Promise.all(sessions.map((session, index) => {
+                    cancelTokens.push(axios.CancelToken.source());
+                    const filters = queryToFilters(searchValue, session.apiRevision);
+                    return services.groupsService.contents('', {
+                        filters,
+                        limit,
+                        recursive: true
+                    }, session, cancelTokens[index].token);
+                }));
+    
+                cancelTokens = [];
+    
+                const items = lists.reduce((items, list) => items.concat(list.items), [] as GroupContentsResource[]);
+    
+                if (lists.filter(list => !!(list as any).items).length !== lists.length) {
+                    dispatch(searchBarActions.SET_SEARCH_RESULTS([]));
+                } else {
+                    dispatch(searchBarActions.SET_SEARCH_RESULTS(items));
+                }
+            }
+        }, 10);
     };
 
 const buildQueryFromKeyMap = (data: any, keyMap: string[][]) => {
diff --git a/src/views-components/search-bar/search-bar.tsx b/src/views-components/search-bar/search-bar.tsx
index 327644ed..6a4d2a62 100644
--- a/src/views-components/search-bar/search-bar.tsx
+++ b/src/views-components/search-bar/search-bar.tsx
@@ -38,7 +38,7 @@ const mapStateToProps = ({ searchBar, form }: RootState): SearchBarDataProps =>
 };
 
 const mapDispatchToProps = (dispatch: Dispatch): SearchBarActionProps => ({
-    onSearch: (valueSearch: string) => dispatch<any>(searchData(valueSearch)),
+    onSearch: (valueSearch: string) => dispatch<any>(searchData(valueSearch, true)),
     onChange: (event: React.ChangeEvent<HTMLInputElement>) => dispatch<any>(changeData(event.target.value)),
     onSetView: (currentView: string) => dispatch(goToView(currentView)),
     onSubmit: (event: React.FormEvent<HTMLFormElement>) => dispatch<any>(submitData(event)),

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list