Merge branch 'master' of git.curoverse.com:arvados-workbench2 into 13862-get-current...
authorMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 11 Oct 2018 19:06:59 +0000 (21:06 +0200)
committerMichal Klobukowski <michal.klobukowski@contractors.roche.com>
Thu, 11 Oct 2018 19:06:59 +0000 (21:06 +0200)
refs #2
13862

Arvados-DCO-1.1-Signed-off-by: Michal Klobukowski <michal.klobukowski@contractors.roche.com>

16 files changed:
Makefile
package.json
src/components/checkbox-field/checkbox-field.tsx [new file with mode: 0644]
src/services/search-service/search-service.ts
src/services/services.ts
src/store/search-bar/search-bar-actions.ts
src/store/search-bar/search-bar-reducer.ts
src/views-components/form-fields/search-bar-form-fields.tsx
src/views-components/search-bar/search-bar-advanced-view.tsx
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.test.tsx
src/views-components/search-bar/search-bar-view.tsx
src/views-components/search-bar/search-bar.tsx
src/views/workbench/workbench.tsx
src/views/workflow-panel/workflow-description-card.tsx

index 4252ca0ef8dcbf13780dc45d1a4e8af8304ce189..98c0e5197cc11628f52a55182002821f0a4a63be 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -70,7 +70,7 @@ yarn-install:
        yarn install
 
 test: yarn-install
-       yarn test --watchAll --bail --ci
+       yarn test --no-watchAll --bail --ci
 
 build: test
        yarn build
index 34e87afea018120d9b163e60bff334167baf42f9..d28ec550fd9458211eed6cfd194c1c486133ca74 100644 (file)
@@ -40,7 +40,7 @@
   "scripts": {
     "start": "react-scripts-ts start",
     "build": "REACT_APP_BUILD_NUMBER=$BUILD_NUMBER REACT_APP_GIT_COMMIT=$GIT_COMMIT react-scripts-ts build",
-    "test": "react-scripts-ts test --env=jsdom",
+    "test": "CI=true react-scripts-ts test --env=jsdom",
     "eject": "react-scripts-ts eject",
     "lint": "tslint src/** -t verbose"
   },
diff --git a/src/components/checkbox-field/checkbox-field.tsx b/src/components/checkbox-field/checkbox-field.tsx
new file mode 100644 (file)
index 0000000..a5d5b28
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { WrappedFieldProps } from 'redux-form';
+import { FormControlLabel, Checkbox } from '@material-ui/core';
+
+export const CheckboxField = (props: WrappedFieldProps & { label?: string }) =>
+    <FormControlLabel
+        control={
+            <Checkbox
+                checked={props.input.value}
+                onChange={props.input.onChange}
+                disabled={props.meta.submitting}
+                color="primary" />
+        }
+        label={props.label} 
+    />;
\ No newline at end of file
index 1fc61dd2199366c2e64b30c36da3c8d5a93dc192..f9392c237a1c46387f49891201e493ca9490cbb3 100644 (file)
@@ -2,11 +2,12 @@
 //
 // SPDX-License-Identifier: AGPL-3.0
 
-export class SearchQueriesService {
+export class SearchService {
     private recentQueries: string[] = this.getRecentQueries();
+    private savedQueries: string[] = this.getSavedQueries();
 
     saveRecentQuery(query: string) {
-        if (this.recentQueries.length >= 5) {
+        if (this.recentQueries.length >= MAX_NUMBER_OF_RECENT_QUERIES) {
             this.recentQueries.shift();
             this.recentQueries.push(query);
         } else {
@@ -18,4 +19,20 @@ export class SearchQueriesService {
     getRecentQueries() {
         return JSON.parse(localStorage.getItem('recentQueries') || '[]') as string[];
     }
-}
\ No newline at end of file
+
+    saveQuery(query: string) {
+        this.savedQueries.push(query);
+        localStorage.setItem('savedQueries', JSON.stringify(this.savedQueries));
+    }
+
+    getSavedQueries() {
+        return JSON.parse(localStorage.getItem('savedQueries') || '[]') as string[];
+    }
+
+    deleteSavedQuery(id: number) {
+        this.savedQueries.splice(id, 1);
+        localStorage.setItem('savedQueries', JSON.stringify(this.savedQueries));
+    }
+}
+
+const MAX_NUMBER_OF_RECENT_QUERIES = 5;
\ No newline at end of file
index 205d16c806e7abf3edd184b7de30c4ba1d66f68b..806fcae1f11b07276691967fd0560b54dd0f9269 100644 (file)
@@ -22,7 +22,7 @@ import { ContainerService } from './container-service/container-service';
 import { LogService } from './log-service/log-service';
 import { ApiActions } from "~/services/api/api-actions";
 import { WorkflowService } from "~/services/workflow-service/workflow-service";
-import { SearchQueriesService } from '~/services/search-service/search-service';
+import { SearchService } from '~/services/search-service/search-service';
 
 export type ServiceRepository = ReturnType<typeof createServices>;
 
@@ -49,7 +49,7 @@ export const createServices = (config: Config, actions: ApiActions) => {
     const collectionFilesService = new CollectionFilesService(collectionService);
     const favoriteService = new FavoriteService(linkService, groupsService);
     const tagService = new TagService(linkService);
-    const searchQueriesService = new SearchQueriesService();
+    const searchService = new SearchService();
 
     return {
         ancestorsService,
@@ -65,7 +65,7 @@ export const createServices = (config: Config, actions: ApiActions) => {
         linkService,
         logService,
         projectService,
-        searchQueriesService,
+        searchService,
         tagService,
         userService,
         webdavClient,
index dbc77a84e942ccb18028ac8296acdc934a88b543..59770cc60844d2aa0d52a3339c6b706f0a148a3f 100644 (file)
@@ -16,7 +16,8 @@ export const searchBarActions = unionize({
     OPEN_SEARCH_VIEW: ofType<{}>(),
     CLOSE_SEARCH_VIEW: ofType<{}>(),
     SET_SEARCH_RESULTS: ofType<GroupContentsResource[]>(),
-    SET_SEARCH_VALUE: ofType<string>()
+    SET_SEARCH_VALUE: ofType<string>(),
+    SET_SAVED_QUERIES: ofType<string[]>()
 });
 
 export type SearchBarActions = UnionOf<typeof searchBarActions>;
@@ -25,8 +26,10 @@ export interface SearchBarAdvanceFormData {
     type?: GroupContentsResource;
     cluster?: string;
     project?: string;
+    inTrash: boolean;
     dataFrom: string;
     dataTo: string;
+    saveQuery: boolean;
     searchQuery: string;
 }
 
@@ -35,16 +38,40 @@ export const SEARCH_BAR_ADVANCE_FORM_NAME = 'searchBarAdvanceFormName';
 export const goToView = (currentView: string) => searchBarActions.SET_CURRENT_VIEW(currentView);
 
 export const saveRecentQuery = (query: string) =>
-    (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
-        services.searchQueriesService.saveRecentQuery(query);
-    };
+    (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) =>
+        services.searchService.saveRecentQuery(query);
+
 
 export const loadRecentQueries = () =>
     (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
-        const recentSearchQueries = services.searchQueriesService.getRecentQueries();
+        const recentSearchQueries = services.searchService.getRecentQueries();
         return recentSearchQueries || [];
     };
 
+export const saveQuery = (data: SearchBarAdvanceFormData) =>
+    (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        if (data.saveQuery && data.searchQuery) {
+            services.searchService.saveQuery(data.searchQuery);
+            dispatch(searchBarActions.SET_SAVED_QUERIES(services.searchService.getSavedQueries()));
+        }
+    };
+
+export const deleteSavedQuery = (id: number) =>
+    (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        services.searchService.deleteSavedQuery(id);
+        const savedSearchQueries = services.searchService.getSavedQueries();
+        dispatch(searchBarActions.SET_SAVED_QUERIES(savedSearchQueries));
+        return savedSearchQueries || [];
+    };
+
+export const openSearchView = () =>
+    (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+        dispatch(searchBarActions.OPEN_SEARCH_VIEW());
+        const savedSearchQueries = services.searchService.getSavedQueries();
+        dispatch(searchBarActions.SET_SAVED_QUERIES(savedSearchQueries));
+    };
+
+
 export const searchData = (searchValue: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
         dispatch(searchBarActions.SET_SEARCH_VALUE(searchValue));
index 048cfea1fce22e55a58136cfa15926e90d204d31..ce2a77ccae1281ce2cc41ec53cbd7c68fb88842a 100644 (file)
@@ -10,6 +10,7 @@ interface SearchBar {
     open: boolean;
     searchResults: GroupContentsResource[];
     searchValue: string;
+    savedQueries: string[];
 }
 
 export enum SearchView {
@@ -22,7 +23,8 @@ const initialState: SearchBar = {
     currentView: SearchView.BASIC,
     open: false,
     searchResults: [],
-    searchValue: ''
+    searchValue: '',
+    savedQueries: ['']
 };
 
 export const searchBarReducer = (state = initialState, action: SearchBarActions): SearchBar =>
@@ -32,5 +34,6 @@ export const searchBarReducer = (state = initialState, action: SearchBarActions)
         CLOSE_SEARCH_VIEW: () => ({ ...state, open: false }),
         SET_SEARCH_RESULTS: (searchResults) => ({ ...state, searchResults }),
         SET_SEARCH_VALUE: (searchValue) => ({ ...state, searchValue }),
+        SET_SAVED_QUERIES: savedQueries => ({ ...state, savedQueries }),
         default: () => state
     });
\ No newline at end of file
index 269113218c2bf7434dc5058bd9f37839cecd35a1..210affcfdcf6db232177283554bf2eee98dd78c8 100644 (file)
@@ -3,9 +3,9 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import * as React from "react";
-import { Field } from "redux-form";
+import { Field } from 'redux-form';
 import { TextField } from "~/components/text-field/text-field";
-import { Checkbox, FormControlLabel } from '@material-ui/core';
+import { CheckboxField } from '~/components/checkbox-field/checkbox-field';
 
 export const SearchBarTypeField = () =>
     <Field
@@ -26,14 +26,9 @@ export const SearchBarProjectField = () =>
         label="Project name" />;
 
 export const SearchBarTrashField = () => 
-    <FormControlLabel
-        control={
-            <Checkbox
-                checked={false}
-                value="true"
-                color="primary"
-            />
-        }
+    <Field
+        name='inTrash'
+        component={CheckboxField}
         label="In trash" />;
 
 export const SearchBarDataFromField = () => 
@@ -61,14 +56,9 @@ export const SearchBarValueField = () =>
         label="Value" />;
 
 export const SearchBarSaveSearchField = () => 
-    <FormControlLabel
-        control={
-            <Checkbox
-                checked={false}
-                value="true"
-                color="primary"
-            />
-        }
+    <Field
+        name='saveQuery'
+        component={CheckboxField}
         label="Save search query" />;
 
 export const SearchBarQuerySearchField = () => 
index 93bd0a69ecfaf2638c96bc79f7275bcc35227e01..d96062ea9325b6bf4876bc4d5b51742c58c65ad5 100644 (file)
@@ -7,7 +7,7 @@ import { reduxForm, reset, InjectedFormProps } from 'redux-form';
 import { compose, Dispatch } from 'redux';
 import { Paper, StyleRulesCallback, withStyles, WithStyles, Button, Grid, IconButton, CircularProgress } from '@material-ui/core';
 import { SearchView } from '~/store/search-bar/search-bar-reducer';
-import { SEARCH_BAR_ADVANCE_FORM_NAME, SearchBarAdvanceFormData } from '~/store/search-bar/search-bar-actions';
+import { SEARCH_BAR_ADVANCE_FORM_NAME, SearchBarAdvanceFormData, saveQuery } from '~/store/search-bar/search-bar-actions';
 import { ArvadosTheme } from '~/common/custom-theme';
 import { CloseIcon } from '~/components/icon/icon';
 import { 
@@ -16,7 +16,7 @@ import {
     SearchBarSaveSearchField, SearchBarQuerySearchField
 } from '~/views-components/form-fields/search-bar-form-fields';
 
-type CssRules = 'form' | 'container' | 'closeIcon' | 'label' | 'buttonWrapper' | 'button' | 'circularProgress';
+type CssRules = 'form' | 'container' | 'closeIcon' | 'label' | 'buttonWrapper' | 'button' | 'circularProgress' | 'searchView';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     form: {
@@ -50,6 +50,10 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         left: 0,
         right: 0,
         margin: 'auto'
+    },
+    searchView: {
+        color: theme.palette.common.black,
+        borderRadius: `0 0 ${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px`
     }
 });
 
@@ -61,6 +65,7 @@ interface SearchBarAdvancedViewDataProps {
 
 interface SearchBarAdvancedViewActionProps {
     setView: (currentView: string) => void;
+    saveQuery: (data: SearchBarAdvanceFormData) => void;
 }
 
 type SearchBarAdvancedViewProps = SearchBarAdvancedViewActionProps & SearchBarAdvancedViewDataProps 
@@ -70,12 +75,13 @@ export const SearchBarAdvancedView = compose(
     reduxForm<SearchBarAdvanceFormData, SearchBarAdvancedViewActionProps>({
         form: SEARCH_BAR_ADVANCE_FORM_NAME,
         onSubmit: (data: SearchBarAdvanceFormData, dispatch: Dispatch) => {
+            dispatch<any>(saveQuery(data));
             dispatch(reset(SEARCH_BAR_ADVANCE_FORM_NAME));
         }
     }),
     withStyles(styles))(
         ({ classes, setView, handleSubmit, invalid, submitting, pristine }: SearchBarAdvancedViewProps) =>
-            <Paper>
+            <Paper className={classes.searchView}>
                 <form onSubmit={handleSubmit} className={classes.form}>
                     <Grid container direction="column" justify="flex-start" alignItems="flex-start">
                         <Grid item xs={12} container className={classes.container}>
index affaf5310cc561e0e60d9b5497dd0d47bce60067..8529450902bcfbc3d8ec628908e3f006c9a17d67 100644 (file)
@@ -16,7 +16,7 @@ const styles: StyleRulesCallback<CssRules> = theme => {
             padding: 0
         },
         searchView: {
-            borderRadius: `0 0 ${theme.spacing.unit / 4}px ${theme.spacing.unit / 4}px`
+            borderRadius: `0 0 ${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px`
         }
     };
 };
index 7f90ecdee5ccb0f98a100ef23cdaf92324529a6d..a191b2eec7da34fd0243d80b2dcc0c44dd3ae3e9 100644 (file)
@@ -17,7 +17,8 @@ const styles: StyleRulesCallback<CssRules> = theme => {
             paddingRight: theme.spacing.unit * 2,
             paddingBottom: theme.spacing.unit,
             fontSize: '14px',
-            cursor: 'pointer'
+            cursor: 'pointer',
+            color: theme.palette.primary.main
         },
         searchQueryList: {
             padding: `${theme.spacing.unit / 2}px ${theme.spacing.unit}px `,
@@ -29,7 +30,7 @@ const styles: StyleRulesCallback<CssRules> = theme => {
         },
         searchView: {
             color: theme.palette.common.black,
-            borderRadius: `0 0 ${theme.spacing.unit / 4}px ${theme.spacing.unit / 4}px`
+            borderRadius: `0 0 ${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px`
         }
     };
 };
@@ -37,19 +38,20 @@ const styles: StyleRulesCallback<CssRules> = theme => {
 interface SearchBarBasicViewProps {
     setView: (currentView: string) => void;
     recentQueries: () => string[];
+    deleteSavedQuery: (id: number) => void;
+    savedQueries: string[];
 }
 
 export const SearchBarBasicView = withStyles(styles)(
-    ({ classes, setView, recentQueries }: SearchBarBasicViewProps & WithStyles<CssRules>) =>
+    ({ classes, setView, recentQueries, deleteSavedQuery, savedQueries }: SearchBarBasicViewProps & WithStyles<CssRules>) =>
         <Paper className={classes.searchView}>
-            <div className={classes.searchQueryList}>Saved search queries</div>
+            <div className={classes.searchQueryList}>Recent search queries</div>
             <List component="nav" className={classes.list}>
-                <RenderSavedQueries text="Test" />
-                <RenderSavedQueries text="Demo" />
+                {recentQueries().map((query, index) => <RecentQueriesItem key={index} text={query} />)}
             </List>
-            <div className={classes.searchQueryList}>Recent search queries</div>
+            <div className={classes.searchQueryList}>Saved search queries</div>
             <List component="nav" className={classes.list}>
-                {recentQueries().map((query, index) => <RecentQueriesItem key={query + index} text={query} />)}
+                {savedQueries.map((query, index) => <RenderSavedQueries key={index} text={query} id={index} deleteSavedQuery={deleteSavedQuery} />)}
             </List>
             <div className={classes.advanced} onClick={() => setView(SearchView.ADVANCED)}>Advanced search</div>
         </Paper>
index 5cd1545c2f04f8f826f25965770265a9bb2d09bc..2ecb835381a9c52ae8308f6d2ce614612223f7f2 100644 (file)
@@ -98,6 +98,9 @@ const mockSearchProps = () => ({
     openView: jest.fn(),
     loseView: jest.fn(),
     closeView: jest.fn(),
+    saveRecentQuery: jest.fn(),
+    loadRecentQueries: () => ['test'],
     saveQuery: jest.fn(),
-    loadQueries: () => ['test']
+    deleteSavedQuery: jest.fn(),
+    openSearchView: jest.fn()
 });
\ No newline at end of file
index d6facbd7bcc23619b27104f0dd78c5fd7dc59c40..59fe4104fca3601845d4a89636a8377a173748ec 100644 (file)
@@ -21,31 +21,30 @@ import { SearchBarBasicView } from '~/views-components/search-bar/search-bar-bas
 import { SearchBarAdvancedView } from '~/views-components/search-bar/search-bar-advanced-view';
 import { SearchBarAutocompleteView, SearchBarAutocompleteViewDataProps } from '~/views-components/search-bar/search-bar-autocomplete-view';
 import { ArvadosTheme } from '~/common/custom-theme';
+import { SearchBarAdvanceFormData } from '~/store/search-bar/search-bar-actions';
 
-type CssRules = 'container' | 'containerSearchViewOpened' | 'input' | 'searchBar' | 'view';
+type CssRules = 'container' | 'containerSearchViewOpened' | 'input' | 'view';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => {
     return {
         container: {
             position: 'relative',
             width: '100%',
-            borderRadius: theme.spacing.unit / 4
+            borderRadius: theme.spacing.unit / 2
         },
         containerSearchViewOpened: {
             position: 'relative',
             width: '100%',
-            borderRadius: `${theme.spacing.unit / 4}px ${theme.spacing.unit / 4}px 0 0`
+            borderRadius: `${theme.spacing.unit / 2}px ${theme.spacing.unit / 2}px 0 0`
         },
         input: {
             border: 'none',
             padding: `0px ${theme.spacing.unit}px`
         },
-        searchBar: {
-            height: '30px'
-        },
         view: {
             position: 'absolute',
-            width: '100%'
+            width: '100%',
+            zIndex: 1
         }
     };
 };
@@ -53,17 +52,20 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => {
 type SearchBarDataProps = {
     searchValue: string;
     currentView: string;
-    open: boolean;
+    isPopoverOpen: boolean;
+    savedQueries: string[];
 } & SearchBarAutocompleteViewDataProps;
 
 interface SearchBarActionProps {
     onSearch: (value: string) => any;
     debounce?: number;
     onSetView: (currentView: string) => void;
-    openView: () => void;
     closeView: () => void;
-    saveQuery: (query: string) => void;
-    loadQueries: () => string[];
+    saveRecentQuery: (query: string) => void;
+    loadRecentQueries: () => string[];
+    saveQuery: (data: SearchBarAdvanceFormData) => void;
+    deleteSavedQuery: (id: number) => void;
+    openSearchView: () => void;
 }
 
 type SearchBarProps = SearchBarDataProps & SearchBarActionProps & WithStyles<CssRules>;
@@ -72,23 +74,29 @@ interface SearchBarState {
     value: string;
 }
 
-interface RenderQueriesProps {
+interface RenderSavedQueriesProps {
+    text: string | JSX.Element;
+    id: number;
+    deleteSavedQuery: (id: number) => void;
+}
+
+interface RenderRecentQueriesProps {
     text: string | JSX.Element;
 }
 
-export const RecentQueriesItem = (props: RenderQueriesProps) => {
+export const RecentQueriesItem = (props: RenderRecentQueriesProps) => {
     return <ListItem button>
         <ListItemText secondary={props.text} />
     </ListItem>;
 };
 
 
-export const RenderSavedQueries = (props: RenderQueriesProps) => {
+export const RenderSavedQueries = (props: RenderSavedQueriesProps) => {
     return <ListItem button>
         <ListItemText secondary={props.text} />
         <ListItemSecondaryAction>
             <Tooltip title="Remove">
-                <IconButton aria-label="Remove">
+                <IconButton aria-label="Remove" onClick={() => props.deleteSavedQuery(props.id)}>
                     <RemoveIcon />
                 </IconButton>
             </Tooltip>
@@ -107,10 +115,10 @@ export const SearchBarView = withStyles(styles)(
         timeout: number;
 
         render() {
-            const { classes, currentView, openView, closeView, open } = this.props;
+            const { classes, currentView, openSearchView, closeView, isPopoverOpen } = this.props;
             return <ClickAwayListener onClickAway={() => closeView()}>
-                <Paper className={open ? classes.containerSearchViewOpened : classes.container} >
-                    <form onSubmit={this.handleSubmit} className={classes.searchBar}>
+                <Paper className={isPopoverOpen ? classes.containerSearchViewOpened : classes.container} >
+                    <form onSubmit={this.handleSubmit}>
                         <Input
                             className={classes.input}
                             onChange={this.handleChange}
@@ -118,7 +126,7 @@ export const SearchBarView = withStyles(styles)(
                             value={this.state.value}
                             fullWidth={true}
                             disableUnderline={true}
-                            onClick={() => openView()}
+                            onClick={openSearchView}
                             endAdornment={
                                 <InputAdornment position="end">
                                     <Tooltip title='Search'>
@@ -130,9 +138,9 @@ export const SearchBarView = withStyles(styles)(
                             } />
                     </form>
                     <div className={classes.view}>
-                        {open && this.getView(currentView)}
+                        {isPopoverOpen && this.getView(currentView)}
                     </div>
-                </Paper>
+                </Paper >
             </ClickAwayListener>;
         }
 
@@ -151,26 +159,27 @@ export const SearchBarView = withStyles(styles)(
         }
 
         getView = (currentView: string) => {
+            const { onSetView, loadRecentQueries, savedQueries, deleteSavedQuery, searchValue, searchResults, saveQuery } = this.props;
             switch (currentView) {
                 case SearchView.BASIC:
-                    return <SearchBarBasicView setView={this.props.onSetView} recentQueries={this.props.loadQueries} />;
+                    return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} />;
                 case SearchView.ADVANCED:
-                    return <SearchBarAdvancedView setView={this.props.onSetView} />;
+                    return <SearchBarAdvancedView setView={onSetView} saveQuery={saveQuery}/>;
                 case SearchView.AUTOCOMPLETE:
-                    return <SearchBarAutocompleteView 
-                                searchResults={this.props.searchResults} 
-                                searchValue={this.props.searchValue} />;
+                    return <SearchBarAutocompleteView
+                        searchResults={searchResults}
+                        searchValue={searchValue} />;
                 default:
-                    return <SearchBarBasicView setView={this.props.onSetView} recentQueries={this.props.loadQueries} />;
+                    return <SearchBarBasicView setView={onSetView} recentQueries={loadRecentQueries} savedQueries={savedQueries} deleteSavedQuery={deleteSavedQuery} />;
             }
         }
 
         handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
             event.preventDefault();
             clearTimeout(this.timeout);
-            this.props.saveQuery(this.state.value);
+            this.props.saveRecentQuery(this.state.value);
             this.props.onSearch(this.state.value);
-            this.props.loadQueries();
+            this.props.loadRecentQueries();
         }
 
         handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
index 98440fda29517e7a62d2337fd04fe9b1572a2b74..8dcaaf842d6125a597f071320ff5acd034664d96 100644 (file)
@@ -5,26 +5,38 @@
 import { connect } from 'react-redux';
 import { RootState } from '~/store/store';
 import { Dispatch } from 'redux';
-import { goToView, searchData, searchBarActions } from '~/store/search-bar/search-bar-actions';
+import {
+    goToView,
+    searchData,
+    searchBarActions,
+    deleteSavedQuery,
+    saveRecentQuery,
+    loadRecentQueries,
+    saveQuery,
+    openSearchView
+} from '~/store/search-bar/search-bar-actions';
 import { SearchBarView } from '~/views-components/search-bar/search-bar-view';
-import { saveRecentQuery, loadRecentQueries } from '~/store/search-bar/search-bar-actions';
+import { SearchBarAdvanceFormData } from '~/store/search-bar/search-bar-actions';
 
 const mapStateToProps = ({ searchBar }: RootState) => {
     return {
         searchValue: searchBar.searchValue,
         currentView: searchBar.currentView,
-        open: searchBar.open,
-        searchResults: searchBar.searchResults
+        isPopoverOpen: searchBar.open,
+        searchResults: searchBar.searchResults,
+        savedQueries: searchBar.savedQueries
     };
 };
 
 const mapDispatchToProps = (dispatch: Dispatch) => ({
     onSearch: (valueSearch: string) => dispatch<any>(searchData(valueSearch)),
     onSetView: (currentView: string) => dispatch(goToView(currentView)),
-    openView: () => dispatch<any>(searchBarActions.OPEN_SEARCH_VIEW()),
     closeView: () => dispatch<any>(searchBarActions.CLOSE_SEARCH_VIEW()),
-    saveQuery: (query: string) => dispatch<any>(saveRecentQuery(query)),
-    loadQueries: () => dispatch<any>(loadRecentQueries())
+    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())
 });
 
 export const SearchBar = connect(mapStateToProps, mapDispatchToProps)(SearchBarView);
\ No newline at end of file
index d326c313dbb52b1212190c09ee3a29c97371873c..f26d50fba6bc330ef42cccc8b3481b80007ea0be 100644 (file)
@@ -83,7 +83,7 @@ export const WorkbenchPanel =
         <Grid container item xs className={classes.root}>
             <Grid container item xs className={classes.container}>
                 <SplitterLayout customClassName={classes.splitter} percentage={true}
-                    primaryIndex={0} primaryMinSize={15} secondaryInitialSize={85} secondaryMinSize={40}>
+                    primaryIndex={0} primaryMinSize={10} secondaryInitialSize={90} secondaryMinSize={40}>
                     <Grid container item xs component='aside' direction='column' className={classes.asidePanel}>
                         <SidePanel />
                     </Grid>
index a98356403bfd50ffd346c7b01c2d68c0dfd6de26..ecbc9f0c0a2e7b83a1849ffbc7ad578737bf76c7 100644 (file)
@@ -9,14 +9,21 @@ import { WorkflowIcon } from '~/components/icon/icon';
 import { DataTableDefaultView } from '~/components/data-table-default-view/data-table-default-view';
 import { WorkflowResource, parseWorkflowDefinition, getWorkflowInputs, getInputLabel, stringifyInputType } from '~/models/workflow';
 
-export type CssRules = 'root' | 'tab';
+export type CssRules = 'root' | 'tab' | 'inputTab';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     root: {
-        height: '100%',
+        height: '100%'
     },
     tab: {
         minWidth: '50%'
+    },
+    inputTab: {
+        overflowX: 'auto',
+        overflowY: 'hidden',
+        '&:last-child': {
+            paddingBottom: theme.spacing.unit / 2,
+        }
     }
 });
 
@@ -53,7 +60,7 @@ export const WorkflowDetailsCard = withStyles(styles)(
                                 messages={['Please select a workflow to see its description.']} />
                         )}
                 </CardContent>}
-                {value === 1 && <CardContent>
+                {value === 1 && <CardContent className={classes.inputTab}>
                     {workflow
                         ? this.renderInputsTable()
                         : <DataTableDefaultView