searching on text
authorPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Mon, 15 Oct 2018 13:28:20 +0000 (15:28 +0200)
committerPawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>
Mon, 15 Oct 2018 13:28:20 +0000 (15:28 +0200)
Feature #14277

Arvados-DCO-1.1-Signed-off-by: Pawel Kowalczyk <pawel.kowalczyk@contractors.roche.com>

src/routes/routes.ts
src/store/navigation/navigation-action.ts
src/store/search-bar/search-bar-actions.ts
src/store/search-results-panel/search-results-middleware-service.ts
src/store/store.ts
src/views-components/search-bar/search-bar-autocomplete-view.tsx
src/views-components/search-bar/search-bar-basic-view.tsx
src/views-components/search-bar/search-bar-view.tsx
src/views-components/search-bar/search-bar.tsx
src/views/search-results-panel/search-results-panel-view.tsx
src/views/search-results-panel/search-results-panel.tsx

index 34eea4f17612befd56cf57a3b487f759766f82cf..d5041976a75e347a33e39bbb862343c20cf793a5 100644 (file)
@@ -19,7 +19,7 @@ export const Routes = {
     SHARED_WITH_ME: '/shared-with-me',
     RUN_PROCESS: '/run-process',
     WORKFLOWS: '/workflows',
-    SEARCH_RESULTS: '/q'
+    SEARCH_RESULTS: '/search'
 };
 
 export const getResourceUrl = (uuid: string) => {
index 48bd606e41b146d1f73849d27e3957a84ab9fee8..b060afc433c11df2f554ea1160c53f309f16cc68 100644 (file)
@@ -56,4 +56,6 @@ export const navigateToRootProject = (dispatch: Dispatch, getState: () => RootSt
 
 export const navigateToSharedWithMe = push(Routes.SHARED_WITH_ME);
 
-export const navigateToRunProcess = push(Routes.RUN_PROCESS);
\ No newline at end of file
+export const navigateToRunProcess = push(Routes.RUN_PROCESS);
+
+export const navigateToSearchResults = push(Routes.SEARCH_RESULTS);
\ No newline at end of file
index 2f30e02dc96bd050f9914037ac4e93a2c81725b0..394920a5d7c776aaec41841c0d13161fb5701446 100644 (file)
@@ -11,6 +11,8 @@ import { FilterBuilder } from "~/services/api/filter-builder";
 import { ResourceKind } from '~/models/resource';
 import { GroupClass } from '~/models/group';
 import { SearchView } from '~/store/search-bar/search-bar-reducer';
+import { navigateToSearchResults, navigateTo } from '~/store/navigation/navigation-action';
+import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
 
 export const searchBarActions = unionize({
     SET_CURRENT_VIEW: ofType<string>(),
@@ -54,6 +56,7 @@ export const saveQuery = (data: SearchBarAdvanceFormData) =>
         if (data.saveQuery && data.searchQuery) {
             services.searchService.saveQuery(data.searchQuery);
             dispatch(searchBarActions.SET_SAVED_QUERIES(services.searchService.getSavedQueries()));
+            dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Query has been sucessfully saved', kind: SnackbarKind.SUCCESS }));
         }
     };
 
@@ -68,14 +71,28 @@ export const deleteSavedQuery = (id: number) =>
 export const openSearchView = () =>
     (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
         dispatch(searchBarActions.OPEN_SEARCH_VIEW());
-        dispatch(searchBarActions.SET_CURRENT_VIEW(SearchView.BASIC));
         const savedSearchQueries = services.searchService.getSavedQueries();
         dispatch(searchBarActions.SET_SAVED_QUERIES(savedSearchQueries));
     };
 
+export const closeSearchView = () =>
+    (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(searchBarActions.CLOSE_SEARCH_VIEW());
+        dispatch(searchBarActions.SET_CURRENT_VIEW(SearchView.BASIC));
+    };
 
+export const navigateToItem = (uuid: string) =>
+    (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(searchBarActions.CLOSE_SEARCH_VIEW());
+        dispatch(navigateTo(uuid));
+    };
+    
 export const searchData = (searchValue: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+        const currentView = getState().searchBar.currentView;
+        if (currentView !== SearchView.AUTOCOMPLETE) {
+            dispatch(searchBarActions.CLOSE_SEARCH_VIEW());
+        }
         dispatch(searchBarActions.SET_SEARCH_VALUE(searchValue));
         dispatch(searchBarActions.SET_SEARCH_RESULTS([]));
         if (searchValue) {
@@ -87,9 +104,10 @@ export const searchData = (searchValue: string) =>
             });
             dispatch(searchBarActions.SET_SEARCH_RESULTS(items));
         }
+        dispatch(navigateToSearchResults);
     };
 
-const getFilters = (filterName: string, searchValue: string): string => {
+export const getFilters = (filterName: string, searchValue: string): string => {
     return new FilterBuilder()
         .addIsA("uuid", [ResourceKind.PROJECT, ResourceKind.COLLECTION, ResourceKind.PROCESS])
         .addILike(filterName, searchValue, GroupContentsResourcePrefix.COLLECTION)
index 2ae2dee3ebcfb6614ff93fac7a0eb5ca9a91d69a..924a0f09756c718d5dbdcd49e58383910bed8cdc 100644 (file)
@@ -16,6 +16,7 @@ import { OrderDirection, OrderBuilder } from '~/services/api/order-builder';
 import { GroupContentsResource, GroupContentsResourcePrefix } from "~/services/groups-service/groups-service";
 import { ListResults } from '~/services/common-service/common-resource-service';
 import { searchResultsPanelActions } from '~/store/search-results-panel/search-results-panel-actions';
+import { getFilters } from '~/store/search-bar/search-bar-actions';
 
 export class SearchResultsMiddlewareService extends DataExplorerMiddlewareService {
     constructor(private services: ServiceRepository, id: string) {
@@ -26,8 +27,9 @@ export class SearchResultsMiddlewareService extends DataExplorerMiddlewareServic
         const state = api.getState();
         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(userUuid, getParams(dataExplorer));
+            const response = await this.services.groupsService.contents(userUuid, getParams(dataExplorer, searchValue));
             api.dispatch(updateResources(response.items));
             api.dispatch(setItems(response));
         } catch {
@@ -36,18 +38,11 @@ export class SearchResultsMiddlewareService extends DataExplorerMiddlewareServic
     }
 }
 
-export const getParams = (dataExplorer: DataExplorer) => ({
+export const getParams = (dataExplorer: DataExplorer, searchValue: string) => ({
     ...dataExplorerToListParams(dataExplorer),
-    order: getOrder(dataExplorer),
-    filters: getFilters(dataExplorer)
+    filters: getFilters('name', searchValue)
 });
 
-export const getFilters = (dataExplorer: DataExplorer) => {
-    const filters = new FilterBuilder()
-        .addILike("name", dataExplorer.searchValue)
-        .getFilters();
-    return filters;
-};
 
 export const getOrder = (dataExplorer: DataExplorer) => {
     const sortColumn = dataExplorer.columns.find(c => c.sortDirection !== SortDirection.NONE);
index 064faeca59a0cd289ef42c2d29d47b294d3b9db6..7a0d58f8a568f555e7dc633c69eec2ee3642517e 100644 (file)
@@ -40,6 +40,8 @@ import { WorkflowMiddlewareService } from './workflow-panel/workflow-middleware-
 import { WORKFLOW_PANEL_ID } from './workflow-panel/workflow-panel-actions';
 import { appInfoReducer } from '~/store/app-info/app-info-reducer';
 import { searchBarReducer } from './search-bar/search-bar-reducer';
+import { SEARCH_RESULTS_PANEL_ID } from '~/store/search-results-panel/search-results-panel-actions';
+import { SearchResultsMiddlewareService } from './search-results-panel/search-results-middleware-service';
 
 const composeEnhancers =
     (process.env.NODE_ENV === 'development' &&
@@ -62,6 +64,9 @@ export function configureStore(history: History, services: ServiceRepository): R
     const trashPanelMiddleware = dataExplorerMiddleware(
         new TrashPanelMiddlewareService(services, TRASH_PANEL_ID)
     );
+    const searchResultsPanelMiddleware = dataExplorerMiddleware(
+        new SearchResultsMiddlewareService(services, SEARCH_RESULTS_PANEL_ID)
+    );
     const sharedWithMePanelMiddleware = dataExplorerMiddleware(
         new SharedWithMeMiddlewareService(services, SHARED_WITH_ME_PANEL_ID)
     );
@@ -75,6 +80,7 @@ export function configureStore(history: History, services: ServiceRepository): R
         projectPanelMiddleware,
         favoritePanelMiddleware,
         trashPanelMiddleware,
+        searchResultsPanelMiddleware,
         sharedWithMePanelMiddleware,
         workflowPanelMiddleware
     ];
index 8529450902bcfbc3d8ec628908e3f006c9a17d67..48172424ce2685bd12a6183559bb7e458339f7a3 100644 (file)
@@ -4,7 +4,7 @@
 
 import * as React from 'react';
 import { Paper, StyleRulesCallback, withStyles, WithStyles, List } from '@material-ui/core';
-import { RecentQueriesItem } from '~/views-components/search-bar/search-bar-view';
+import { RenderAutocompleteItems } from '~/views-components/search-bar/search-bar-view';
 import { GroupContentsResource } from '~/services/groups-service/groups-service';
 import Highlighter from "react-highlight-words";
 
@@ -24,16 +24,17 @@ const styles: StyleRulesCallback<CssRules> = theme => {
 export interface SearchBarAutocompleteViewDataProps {
     searchResults?: GroupContentsResource[];
     searchValue?: string;
+    navigateTo: (uuid: string) => void;
 }
 
 type SearchBarAutocompleteViewProps = SearchBarAutocompleteViewDataProps & WithStyles<CssRules>;
 
 export const SearchBarAutocompleteView = withStyles(styles)(
-    ({ classes, searchResults, searchValue }: SearchBarAutocompleteViewProps) =>
+    ({ classes, searchResults, searchValue, navigateTo }: SearchBarAutocompleteViewProps) =>
         <Paper className={classes.searchView}>
             {searchResults && <List component="nav" className={classes.list}>
                 {searchResults.map((item: GroupContentsResource) => {
-                    return <RecentQueriesItem key={item.uuid} text={getFormattedText(item.name, searchValue)} />;
+                    return <RenderAutocompleteItems key={item.uuid} text={getFormattedText(item.name, searchValue)} navigateTo={navigateTo} uuid={item.uuid} />;
                 })}
             </List>}
         </Paper>
index a191b2eec7da34fd0243d80b2dcc0c44dd3ae3e9..97a5d3e34086e31bdbdc3f03a8ac1db73278a77d 100644 (file)
@@ -5,7 +5,7 @@
 import * as React from 'react';
 import { Paper, StyleRulesCallback, withStyles, WithStyles, List } from '@material-ui/core';
 import { SearchView } from '~/store/search-bar/search-bar-reducer';
-import { RecentQueriesItem, RenderSavedQueries } from '~/views-components/search-bar/search-bar-view';
+import { RenderRecentQueries, RenderSavedQueries } from '~/views-components/search-bar/search-bar-view';
 
 type CssRules = 'advanced' | 'searchQueryList' | 'list' | 'searchView';
 
@@ -40,18 +40,19 @@ interface SearchBarBasicViewProps {
     recentQueries: () => string[];
     deleteSavedQuery: (id: number) => void;
     savedQueries: string[];
+    onSearch: (searchValue: string) => void;
 }
 
 export const SearchBarBasicView = withStyles(styles)(
-    ({ classes, setView, recentQueries, deleteSavedQuery, savedQueries }: SearchBarBasicViewProps & WithStyles<CssRules>) =>
+    ({ classes, setView, recentQueries, deleteSavedQuery, savedQueries, onSearch }: SearchBarBasicViewProps & WithStyles<CssRules>) =>
         <Paper className={classes.searchView}>
             <div className={classes.searchQueryList}>Recent search queries</div>
             <List component="nav" className={classes.list}>
-                {recentQueries().map((query, index) => <RecentQueriesItem key={index} text={query} />)}
+                {recentQueries().map((query, index) => <RenderRecentQueries key={index} text={query} onSearch={onSearch} />)}
             </List>
             <div className={classes.searchQueryList}>Saved search queries</div>
             <List component="nav" className={classes.list}>
-                {savedQueries.map((query, index) => <RenderSavedQueries key={index} text={query} id={index} deleteSavedQuery={deleteSavedQuery} />)}
+                {savedQueries.map((query, index) => <RenderSavedQueries key={index} text={query} id={index} deleteSavedQuery={deleteSavedQuery} onSearch={onSearch} />)}
             </List>
             <div className={classes.advanced} onClick={() => setView(SearchView.ADVANCED)}>Advanced search</div>
         </Paper>
index f394084cf55d4a9d8cc5d2e97751de54b4e263e2..51062646cdc1965e4797e0b7d52ebc8a408f487d 100644 (file)
@@ -66,6 +66,7 @@ interface SearchBarActionProps {
     saveQuery: (data: SearchBarAdvanceFormData) => void;
     deleteSavedQuery: (id: number) => void;
     openSearchView: () => void;
+    navigateTo: (uuid: string) => void;
 }
 
 type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
@@ -74,26 +75,41 @@ interface SearchBarState {
     value: string;
 }
 
-interface RenderSavedQueriesProps {
+
+
+interface RenderRecentQueriesProps {
     text: string | JSX.Element;
-    id: number;
-    deleteSavedQuery: (id: number) => void;
+    onSearch: (searchValue: string | JSX.Element) => void;
 }
 
-interface RenderRecentQueriesProps {
+export const RenderRecentQueries = (props: RenderRecentQueriesProps) => {
+    return <ListItem button>
+        <ListItemText secondary={props.text} onClick={() => props.onSearch(props.text)} />
+    </ListItem>;
+};
+
+interface RenderAutocompleteItemsProps {
     text: string | JSX.Element;
+    navigateTo: (uuid: string) => void;
+    uuid: string;
 }
 
-export const RecentQueriesItem = (props: RenderRecentQueriesProps) => {
+export const RenderAutocompleteItems = (props: RenderAutocompleteItemsProps) => {
     return <ListItem button>
-        <ListItemText secondary={props.text} />
+        <ListItemText secondary={props.text} onClick={() => props.navigateTo(props.uuid)} />
     </ListItem>;
 };
 
+interface RenderSavedQueriesProps {
+    text: string | JSX.Element;
+    id: number;
+    deleteSavedQuery: (id: number) => void;
+    onSearch: (searchValue: string | JSX.Element) => void;
+}
 
 export const RenderSavedQueries = (props: RenderSavedQueriesProps) => {
     return <ListItem button>
-        <ListItemText secondary={props.text} />
+        <ListItemText secondary={props.text} onClick={() => props.onSearch(props.text)} />
         <ListItemSecondaryAction>
             <Tooltip title="Remove">
                 <IconButton aria-label="Remove" onClick={() => props.deleteSavedQuery(props.id)}>
@@ -159,18 +175,19 @@ export const SearchBarView = withStyles(styles)(
         }
 
         getView = (currentView: string) => {
-            const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue, searchResults, saveQuery } = this.props;
+            const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue, searchResults, saveQuery, onSearch, navigateTo } = this.props;
             switch (currentView) {
                 case SearchView.BASIC:
-                    return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} />;
+                    return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} onSearch={onSearch} />;
                 case SearchView.ADVANCED:
-                    return <SearchBarAdvancedView setView={onSetView} saveQuery={saveQuery}/>;
+                    return <SearchBarAdvancedView setView={onSetView} saveQuery={saveQuery} />;
                 case SearchView.AUTOCOMPLETE:
                     return <SearchBarAutocompleteView
+                        navigateTo={navigateTo}
                         searchResults={searchResults}
                         searchValue={searchValue} />;
                 default:
-                    return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} />;
+                    return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} onSearch={onSearch} />;
             }
         }
 
index 8dcaaf842d6125a597f071320ff5acd034664d96..5c42af20caa03e3b88db25f7d55e4debeaae5374 100644 (file)
@@ -8,7 +8,6 @@ import { Dispatch } from 'redux';
 import {
     goToView,
     searchData,
-    searchBarActions,
     deleteSavedQuery,
     saveRecentQuery,
     loadRecentQueries,
@@ -17,6 +16,7 @@ import {
 } from '~/store/search-bar/search-bar-actions';
 import { SearchBarView } from '~/views-components/search-bar/search-bar-view';
 import { SearchBarAdvanceFormData } from '~/store/search-bar/search-bar-actions';
+import { closeSearchView, navigateToItem } from '~/store/search-bar/search-bar-actions';
 
 const mapStateToProps = ({ searchBar }: RootState) => {
     return {
@@ -31,12 +31,13 @@ const mapStateToProps = ({ searchBar }: RootState) => {
 const mapDispatchToProps = (dispatch: Dispatch) => ({
     onSearch: (valueSearch: string) => dispatch<any>(searchData(valueSearch)),
     onSetView: (currentView: string) => dispatch(goToView(currentView)),
-    closeView: () => dispatch<any>(searchBarActions.CLOSE_SEARCH_VIEW()),
+    closeView: () => dispatch<any>(closeSearchView()),
     saveRecentQuery: (query: string) => dispatch<any>(saveRecentQuery(query)),
     loadRecentQueries: () => dispatch<any>(loadRecentQueries()),
     saveQuery: (data: SearchBarAdvanceFormData) => dispatch<any>(saveQuery(data)),
     deleteSavedQuery: (id: number) => dispatch<any>(deleteSavedQuery(id)),
-    openSearchView: () => dispatch<any>(openSearchView())
+    openSearchView: () => dispatch<any>(openSearchView()),
+    navigateTo: (uuid: string) => dispatch<any>(navigateToItem(uuid))
 });
 
 export const SearchBar = connect(mapStateToProps, mapDispatchToProps)(SearchBarView);
\ No newline at end of file
index 2f1f8898940cd1c612c53fc7f7d1746c9d66c385..a31263abad0b98a7530d43cfa673e5e7e2390823 100644 (file)
@@ -62,7 +62,7 @@ export const searchResultsPanelColumns: DataColumns<string, WorkflowPanelFilter>
         selected: true,
         configurable: true,
         filters: [],
-        render: uuid => <ResourceName uuid={uuid} />
+        render: uuid => <ResourceFileSize uuid={uuid} />
     },
     {
         name: SearchResultsPanelColumnNames.STATUS,
index 8b01ca3f410e03d0e7f29d8cf5a50ef5ac75497a..fd322d75fc2877f40bc405bde1a037f1505a3531 100644 (file)
@@ -5,23 +5,12 @@
 import { Dispatch } from "redux";
 import { connect } from "react-redux";
 import { navigateTo } from '~/store/navigation/navigation-action';
-import { SearchResultsPanelActionProps, SearchResultsPanelDataProps } from './search-results-panel-view';
-import { RootState } from '~/store/store';
+import { SearchResultsPanelActionProps } from './search-results-panel-view';
 import { openContextMenu, resourceKindToContextMenuKind } from '~/store/context-menu/context-menu-actions';
 import { ResourceKind } from '~/models/resource';
 import { loadDetailsPanel } from '~/store/details-panel/details-panel-action';
 import { SearchResultsPanelView } from '~/views/search-results-panel/search-results-panel-view';
 
-const mapStateToProps = (state: RootState): SearchResultsPanelDataProps => ({
-    data: {
-        inTrash: false,
-        dataFrom: '',
-        dataTo: '',
-        saveQuery: false,
-        searchQuery: ''
-    }
-});
-
 const mapDispatchToProps = (dispatch: Dispatch): SearchResultsPanelActionProps => ({
     onContextMenu: (event, resourceUuid) => {
         const kind = resourceKindToContextMenuKind(resourceUuid);
@@ -44,4 +33,4 @@ const mapDispatchToProps = (dispatch: Dispatch): SearchResultsPanelActionProps =
     }
 });
 
-export const SearchResultsPanel = connect(mapStateToProps, mapDispatchToProps)(SearchResultsPanelView);
\ No newline at end of file
+export const SearchResultsPanel = connect(null, mapDispatchToProps)(SearchResultsPanelView);
\ No newline at end of file