X-Git-Url: https://git.arvados.org/arvados-workbench2.git/blobdiff_plain/5b0a7e3709bac2d69100ec87a46f37846aba7d14..62cb779efb0b098c05053e957c765a807467b28b:/src/store/search-bar/search-bar-actions.ts diff --git a/src/store/search-bar/search-bar-actions.ts b/src/store/search-bar/search-bar-actions.ts index d9dc0a64..af40e86a 100644 --- a/src/store/search-bar/search-bar-actions.ts +++ b/src/store/search-bar/search-bar-actions.ts @@ -2,28 +2,29 @@ // // SPDX-License-Identifier: AGPL-3.0 -import { ofType, unionize, UnionOf } from "~/common/unionize"; -import { GroupContentsResource, GroupContentsResourcePrefix } from '~/services/groups-service/groups-service'; +import axios from "axios"; +import { ofType, unionize, UnionOf } from "common/unionize"; +import { GroupContentsResource, GroupContentsResourcePrefix } from 'services/groups-service/groups-service'; import { Dispatch } from 'redux'; import { change, initialize, untouch } from 'redux-form'; -import { RootState } from '~/store/store'; -import { initUserProject, treePickerActions } from '~/store/tree-picker/tree-picker-actions'; -import { ServiceRepository } from '~/services/services'; -import { FilterBuilder } from "~/services/api/filter-builder"; -import { ResourceKind, RESOURCE_UUID_REGEX, COLLECTION_PDH_REGEX } from '~/models/resource'; -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 { PropertyValue, SearchBarAdvancedFormData } from '~/models/search-bar'; -import * as _ from "lodash"; -import { getModifiedKeysValues } from "~/common/objects"; -import { activateSearchBarProject } from "~/store/search-bar/search-bar-tree-actions"; -import { Session } from "~/models/session"; -import { searchResultsPanelActions } from "~/store/search-results-panel/search-results-panel-actions"; -import { ListResults } from "~/services/common-service/common-service"; +import { RootState } from 'store/store'; +import { initUserProject, treePickerActions } from 'store/tree-picker/tree-picker-actions'; +import { ServiceRepository } from 'services/services'; +import { FilterBuilder } from "services/api/filter-builder"; +import { ResourceKind, RESOURCE_UUID_REGEX, COLLECTION_PDH_REGEX } from 'models/resource'; +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 { PropertyValue, SearchBarAdvancedFormData } from 'models/search-bar'; +import { union } from "lodash"; +import { getModifiedKeysValues } from "common/objects"; +import { activateSearchBarProject } from "store/search-bar/search-bar-tree-actions"; +import { Session } from "models/session"; +import { searchResultsPanelActions } from "store/search-results-panel/search-results-panel-actions"; +import { ListResults } from "services/common-service/common-service"; import * as parser from './search-query/arv-parser'; import { Keywords } from './search-query/arv-parser'; -import { Vocabulary, getTagKeyLabel, getTagValueLabel } from "~/models/vocabulary"; +import { Vocabulary, getTagKeyLabel, getTagValueLabel } from "models/vocabulary"; export const searchBarActions = unionize({ SET_CURRENT_VIEW: ofType(), @@ -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(searchGroups(searchValue, 5)); + dispatch(searchGroups(searchValue, 5, useCancel)); if (currentView === SearchView.BASIC) { dispatch(searchBarActions.CLOSE_SEARCH_VIEW()); dispatch(navigateToSearchResults(searchValue)); @@ -88,6 +89,9 @@ export const searchAdvancedData = (data: SearchBarAdvancedFormData) => export const setSearchValueFromAdvancedData = (data: SearchBarAdvancedFormData, prevData?: SearchBarAdvancedFormData) => (dispatch: Dispatch, getState: () => RootState) => { + if (data.projectObject) { + data.projectUuid = data.projectObject.uuid; + } const searchValue = getState().searchBar.searchValue; const value = getQueryFromAdvancedData({ ...data, @@ -97,8 +101,11 @@ export const setSearchValueFromAdvancedData = (data: SearchBarAdvancedFormData, }; export const setAdvancedDataFromSearchValue = (search: string, vocabulary: Vocabulary) => - async (dispatch: Dispatch) => { + async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const data = getAdvancedDataFromQuery(search, vocabulary); + if (data.projectUuid) { + data.projectObject = await services.projectService.get(data.projectUuid); + } dispatch(initialize(SEARCH_BAR_ADVANCED_FORM_NAME, data)); if (data.projectUuid) { await dispatch(activateSearchBarProject(data.projectUuid)); @@ -203,26 +210,41 @@ export const submitData = (event: React.FormEvent) => } }; - -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[] = 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[] = 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[][]) => { @@ -268,12 +290,13 @@ export const getQueryFromAdvancedData = (data: SearchBarAdvancedFormData, prevDa cluster: data.cluster, projectUuid: data.projectUuid, inTrash: data.inTrash, + pastVersions: data.pastVersions, dateFrom: data.dateFrom, dateTo: data.dateTo, }; (data.properties || []).forEach(p => fo[`prop-"${p.keyID || p.key}":"${p.valueID || p.value}"`] = `"${p.valueID || p.value}"` - ); + ); return fo; }; @@ -282,17 +305,18 @@ export const getQueryFromAdvancedData = (data: SearchBarAdvancedFormData, prevDa ['cluster', 'cluster'], ['project', 'projectUuid'], [`is:${parser.States.TRASHED}`, 'inTrash'], + [`is:${parser.States.PAST_VERSION}`, 'pastVersions'], ['from', 'dateFrom'], ['to', 'dateTo'] ]; - _.union(data.properties, prevData ? prevData.properties : []) + union(data.properties, prevData ? prevData.properties : []) .forEach(p => keyMap.push( [`has:"${p.keyID || p.key}"`, `prop-"${p.keyID || p.key}":"${p.valueID || p.value}"`] )); - const modified = getModifiedKeysValues(flatData(data), prevData ? flatData(prevData):{}); + const modified = getModifiedKeysValues(flatData(data), prevData ? flatData(prevData) : {}); value = buildQueryFromKeyMap( - {searchValue: data.searchValue, ...modified} as SearchBarAdvancedFormData, keyMap); + { searchValue: data.searchValue, ...modified } as SearchBarAdvancedFormData, keyMap); value = value.trim(); return value; @@ -307,6 +331,7 @@ export const getAdvancedDataFromQuery = (query: string, vocabulary?: Vocabulary) cluster: getValue(Keywords.CLUSTER), projectUuid: getValue(Keywords.PROJECT), inTrash: parser.isTrashed(tokens), + pastVersions: parser.isPastVersion(tokens), dateFrom: getValue(Keywords.FROM) || '', dateTo: getValue(Keywords.TO) || '', properties: vocabulary