18549: Layout fixed, tests updated 18549-global-search-results-show-path
authorDaniel Kutyła <daniel.kutyla@contractors.roche.com>
Wed, 16 Mar 2022 22:32:30 +0000 (23:32 +0100)
committerDaniel Kutyła <daniel.kutyla@contractors.roche.com>
Wed, 16 Mar 2022 22:32:30 +0000 (23:32 +0100)
Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła <daniel.kutyla@contractors.roche.com>

cypress/integration/search.spec.js
src/components/column-selector/column-selector.tsx
src/components/data-explorer/data-explorer.tsx
src/views/search-results-panel/search-results-panel-view.tsx
src/views/search-results-panel/search-results-panel.tsx

index 95e0bc95d341226ff5787e6128c0c548b0430e94..403516b324f4b78084103fc94c7c46318375635d 100644 (file)
@@ -82,7 +82,7 @@ describe('Search tests', function() {
         });
     });
 
         });
     });
 
-    it('can search for old collection versions', function() {
+    it.only('can display path of the selected item', function() {
         const colName = `Collection ${Math.floor(Math.random() * Math.floor(999999))}`;
 
         // Creates the collection using the admin token so we can set up
         const colName = `Collection ${Math.floor(Math.random() * Math.floor(999999))}`;
 
         // Creates the collection using the admin token so we can set up
@@ -101,7 +101,7 @@ describe('Search tests', function() {
 
             cy.get('[data-cy=search-results]').contains(colName).closest('tr').click();
 
 
             cy.get('[data-cy=search-results]').contains(colName).closest('tr').click();
 
-            cy.get('[data-cy=snackbar]').should('contain', `/ Projects / ${colName}`);
+            cy.get('[data-cy=element-path]').should('contain', `/ Projects / ${colName}`);
         });
     });
 });
\ No newline at end of file
         });
     });
 });
\ No newline at end of file
index 317e6bc0c40f8148e4ef009281aa3317eb2656f3..5fbef6b62c1e37d2c882c5968f3983d3f5f2fcf6 100644 (file)
@@ -14,6 +14,7 @@ import { ArvadosTheme } from "common/custom-theme";
 interface ColumnSelectorDataProps {
     columns: DataColumns<any>;
     onColumnToggle: (column: DataColumn<any>) => void;
 interface ColumnSelectorDataProps {
     columns: DataColumns<any>;
     onColumnToggle: (column: DataColumn<any>) => void;
+    className?: string;
 }
 
 type CssRules = "checkbox";
 }
 
 type CssRules = "checkbox";
index 55840ae9fd52a752f8b90e73c1f3cc06370c19b9..051f5d34a6ef45ebc33d1cbcbbab5e1815b05184 100644 (file)
@@ -15,7 +15,7 @@ import { CloseIcon, MaximizeIcon, MoreOptionsIcon } from 'components/icon/icon';
 import { PaperProps } from '@material-ui/core/Paper';
 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
 
 import { PaperProps } from '@material-ui/core/Paper';
 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
 
-type CssRules = 'searchBox' | "toolbar" | "toolbarUnderTitle" | "footer" | "root" | 'moreOptionsButton' | 'title' | 'dataTable' | 'container';
+type CssRules = 'searchBox' | 'headerMenu' | "toolbar" | "footer" | "root" | 'moreOptionsButton' | 'title' | 'dataTable' | 'container';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     searchBox: {
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     searchBox: {
@@ -25,9 +25,6 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         paddingTop: theme.spacing.unit,
         paddingRight: theme.spacing.unit * 2,
     },
         paddingTop: theme.spacing.unit,
         paddingRight: theme.spacing.unit * 2,
     },
-    toolbarUnderTitle: {
-        paddingTop: 0
-    },
     footer: {
         overflow: 'auto'
     },
     footer: {
         overflow: 'auto'
     },
@@ -38,6 +35,7 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         padding: 0
     },
     title: {
         padding: 0
     },
     title: {
+        display: 'inline-block',
         paddingLeft: theme.spacing.unit * 3,
         paddingTop: theme.spacing.unit * 3,
         fontSize: '18px'
         paddingLeft: theme.spacing.unit * 3,
         paddingTop: theme.spacing.unit * 3,
         fontSize: '18px'
@@ -49,6 +47,10 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     container: {
         height: '100%',
     },
     container: {
         height: '100%',
     },
+    headerMenu: {
+        float: 'right',
+        display: 'inline-block'
+    }
 });
 
 interface DataExplorerDataProps<T> {
 });
 
 interface DataExplorerDataProps<T> {
@@ -71,6 +73,7 @@ interface DataExplorerDataProps<T> {
     title?: React.ReactNode;
     paperKey?: string;
     currentItemUuid: string;
     title?: React.ReactNode;
     paperKey?: string;
     currentItemUuid: string;
+    elementPath?: string;
 }
 
 interface DataExplorerActionProps<T> {
 }
 
 interface DataExplorerActionProps<T> {
@@ -107,36 +110,43 @@ export const DataExplorer = withStyles(styles)(
                 items, itemsAvailable, onRowClick, onRowDoubleClick, classes,
                 dataTableDefaultView, hideColumnSelector, actions, paperProps, hideSearchInput,
                 paperKey, fetchMode, currentItemUuid, title,
                 items, itemsAvailable, onRowClick, onRowDoubleClick, classes,
                 dataTableDefaultView, hideColumnSelector, actions, paperProps, hideSearchInput,
                 paperKey, fetchMode, currentItemUuid, title,
-                doHidePanel, doMaximizePanel, panelName, panelMaximized
+                doHidePanel, doMaximizePanel, panelName, panelMaximized, elementPath
             } = this.props;
 
             const dataCy = this.props["data-cy"];
             return <Paper className={classes.root} {...paperProps} key={paperKey} data-cy={dataCy}>
                 <Grid container direction="column" wrap="nowrap" className={classes.container}>
             } = this.props;
 
             const dataCy = this.props["data-cy"];
             return <Paper className={classes.root} {...paperProps} key={paperKey} data-cy={dataCy}>
                 <Grid container direction="column" wrap="nowrap" className={classes.container}>
-                {title && <Grid item xs className={classes.title}>{title}</Grid>}
-                {(!hideColumnSelector || !hideSearchInput || !!actions) && <Grid item xs><Toolbar className={title ? classes.toolbarUnderTitle : classes.toolbar}>
-                    <Grid container justify="space-between" wrap="nowrap" alignItems="center">
-                        {!hideSearchInput && <div className={classes.searchBox}>
-                            {!hideSearchInput && <SearchInput
-                                label={searchLabel}
-                                value={searchValue}
-                                selfClearProp={currentItemUuid}
-                                onSearch={onSearch} />}
-                        </div>}
-                        {actions}
-                        {!hideColumnSelector && <ColumnSelector
-                            columns={columns}
-                            onColumnToggle={onColumnToggle} />}
-                    </Grid>
-                    { doMaximizePanel && !panelMaximized &&
-                        <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
-                            <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
-                        </Tooltip> }
-                    { doHidePanel &&
-                        <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
-                            <IconButton onClick={doHidePanel}><CloseIcon /></IconButton>
-                        </Tooltip> }
-                </Toolbar></Grid>}
+                    <div>
+                        {title && <Grid item xs className={classes.title}>{title}</Grid>}
+                        {
+                            (!hideColumnSelector || !hideSearchInput || !!actions) &&
+                            <Grid className={classes.headerMenu} item xs>
+                                <Toolbar className={classes.toolbar}>
+                                    <Grid container justify="space-between" wrap="nowrap" alignItems="center">
+                                        {!hideSearchInput && <div className={classes.searchBox}>
+                                            {!hideSearchInput && <SearchInput
+                                                label={searchLabel}
+                                                value={searchValue}
+                                                selfClearProp={currentItemUuid}
+                                                onSearch={onSearch} />}
+                                        </div>}
+                                        {actions}
+                                        {!hideColumnSelector && <ColumnSelector
+                                            columns={columns}
+                                            onColumnToggle={onColumnToggle} />}
+                                    </Grid>
+                                    { doMaximizePanel && !panelMaximized &&
+                                        <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
+                                            <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
+                                        </Tooltip> }
+                                    { doHidePanel &&
+                                        <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
+                                            <IconButton onClick={doHidePanel}><CloseIcon /></IconButton>
+                                        </Tooltip> }
+                                </Toolbar>
+                            </Grid>
+                        }
+                    </div>
                 <Grid item xs="auto" className={classes.dataTable}><DataTable
                     columns={this.props.contextMenuColumn ? [...columns, this.contextMenuColumn] : columns}
                     items={items}
                 <Grid item xs="auto" className={classes.dataTable}><DataTable
                     columns={this.props.contextMenuColumn ? [...columns, this.contextMenuColumn] : columns}
                     items={items}
@@ -151,7 +161,15 @@ export const DataExplorer = withStyles(styles)(
                     currentItemUuid={currentItemUuid}
                     currentRoute={paperKey} /></Grid>
                 <Grid item xs><Toolbar className={classes.footer}>
                     currentItemUuid={currentItemUuid}
                     currentRoute={paperKey} /></Grid>
                 <Grid item xs><Toolbar className={classes.footer}>
-                    <Grid container justify="flex-end">
+                    {
+                        elementPath &&
+                        <Grid container>
+                            <span data-cy="element-path">
+                                {elementPath}
+                            </span>
+                        </Grid>
+                    }
+                    <Grid container={!elementPath} justify="flex-end">
                         {fetchMode === DataTableFetchMode.PAGINATED ? <TablePagination
                             count={itemsAvailable}
                             rowsPerPage={rowsPerPage}
                         {fetchMode === DataTableFetchMode.PAGINATED ? <TablePagination
                             count={itemsAvailable}
                             rowsPerPage={rowsPerPage}
index fd420b83ffadd624c6ac22b12d9654f5a91d68ff..60fdd33ef3a49fc44718b61c383f167a22f3c3f6 100644 (file)
@@ -28,6 +28,7 @@ import { Link } from 'react-router-dom';
 import { StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core';
 import { ArvadosTheme } from 'common/custom-theme';
 import { getSearchSessions } from 'store/search-bar/search-bar-actions';
 import { StyleRulesCallback, withStyles, WithStyles } from '@material-ui/core';
 import { ArvadosTheme } from 'common/custom-theme';
 import { getSearchSessions } from 'store/search-bar/search-bar-actions';
+import { camelCase } from 'lodash';
 
 export enum SearchResultsPanelColumnNames {
     CLUSTER = "Cluster",
 
 export enum SearchResultsPanelColumnNames {
     CLUSTER = "Cluster",
@@ -39,9 +40,12 @@ export enum SearchResultsPanelColumnNames {
     LAST_MODIFIED = "Last modified"
 }
 
     LAST_MODIFIED = "Last modified"
 }
 
-export type CssRules = 'siteManagerLink';
+export type CssRules = 'siteManagerLink' | 'searchResults';
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+    searchResults: {
+        width: '100%'
+    },
     siteManagerLink: {
         marginRight: theme.spacing.unit * 2,
         float: 'right'
     siteManagerLink: {
         marginRight: theme.spacing.unit * 2,
         float: 'right'
@@ -111,9 +115,10 @@ export const SearchResultsPanelView = withStyles(styles, { withTheme: true })(
         const homeCluster = props.user.uuid.substring(0, 5);
         const loggedIn = props.sessions.filter((ss) => ss.loggedIn && ss.userIsActive);
         const [selectedItem, setSelectedItem] = useState('');
         const homeCluster = props.user.uuid.substring(0, 5);
         const loggedIn = props.sessions.filter((ss) => ss.loggedIn && ss.userIsActive);
         const [selectedItem, setSelectedItem] = useState('');
+        const [itemPath, setItemPath] = useState<string[]>([]);
 
         useEffect(() => {
 
         useEffect(() => {
-            let itemPath: string[] = [];
+            let tmpPath: string[] = [];
 
             (async () => {
                 if (selectedItem !== '') {
 
             (async () => {
                 if (selectedItem !== '') {
@@ -122,16 +127,16 @@ export const SearchResultsPanelView = withStyles(styles, { withTheme: true })(
 
                     while (itemKind !== ResourceKind.USER) {
                         const clusterId = searchUuid.split('-')[0];
 
                     while (itemKind !== ResourceKind.USER) {
                         const clusterId = searchUuid.split('-')[0];
-                        const serviceType = itemKind?.replace('arvados#', '');
+                        const serviceType = camelCase(itemKind?.replace('arvados#', ''));
                         const service = Object.values(servicesProvider.getServices())
                             .filter(({resourceType}) => !!resourceType)
                         const service = Object.values(servicesProvider.getServices())
                             .filter(({resourceType}) => !!resourceType)
-                            .find(({resourceType}) => resourceType.indexOf(serviceType) > -1);
+                            .find(({resourceType}) => camelCase(resourceType).indexOf(serviceType) > -1);
                         const sessions = getSearchSessions(clusterId, props.sessions);
 
                         if (sessions.length > 0) {
                             const session = sessions[0];
                             const { name, ownerUuid } = await (service as any).get(searchUuid, false, session);
                         const sessions = getSearchSessions(clusterId, props.sessions);
 
                         if (sessions.length > 0) {
                             const session = sessions[0];
                             const { name, ownerUuid } = await (service as any).get(searchUuid, false, session);
-                            itemPath.push(name);
+                            tmpPath.push(name);
                             searchUuid = ownerUuid;
                             itemKind = extractUuidKind(searchUuid);
                         } else {
                             searchUuid = ownerUuid;
                             itemKind = extractUuidKind(searchUuid);
                         } else {
@@ -139,8 +144,8 @@ export const SearchResultsPanelView = withStyles(styles, { withTheme: true })(
                         }
                     }
 
                         }
                     }
 
-                    itemPath.push(props.user.uuid === searchUuid ? 'Projects' : 'Shared with me');
-                    props.onPathDisplay(`/ ${itemPath.reverse().join(' / ')}`);
+                    tmpPath.push(props.user.uuid === searchUuid ? 'Projects' : 'Shared with me');
+                    setItemPath(tmpPath);
                 }
             })();
 
                 }
             })();
 
@@ -153,13 +158,14 @@ export const SearchResultsPanelView = withStyles(styles, { withTheme: true })(
         // eslint-disable-next-line react-hooks/exhaustive-deps
         },[props.onItemClick]);
 
         // eslint-disable-next-line react-hooks/exhaustive-deps
         },[props.onItemClick]);
 
-        return <span data-cy='search-results'>
+        return <span data-cy='search-results' className={props.classes.searchResults}>
             <DataExplorer
             id={SEARCH_RESULTS_PANEL_ID}
             onRowClick={onItemClick}
             onRowDoubleClick={props.onItemDoubleClick}
             onContextMenu={props.onContextMenu}
             contextMenuColumn={false}
             <DataExplorer
             id={SEARCH_RESULTS_PANEL_ID}
             onRowClick={onItemClick}
             onRowDoubleClick={props.onItemDoubleClick}
             onContextMenu={props.onContextMenu}
             contextMenuColumn={false}
+            elementPath={`/ ${itemPath.reverse().join(' / ')}`}
             hideSearchInput
             title={
                 <div>
             hideSearchInput
             title={
                 <div>
index 6d1d2bf569f6d06d287f67fbde1f4e94901a05b3..d25682f6e1d8b59a07d4c91c4e8a469bd119504b 100644 (file)
@@ -14,7 +14,6 @@ import { SearchBarAdvancedFormData } from 'models/search-bar';
 import { User } from "models/user";
 import { Config } from 'common/config';
 import { Session } from "models/session";
 import { User } from "models/user";
 import { Config } from 'common/config';
 import { Session } from "models/session";
-import { snackbarActions, SnackbarKind } from "store/snackbar/snackbar-actions";
 
 export interface SearchResultsPanelDataProps {
     data: SearchBarAdvancedFormData;
 
 export interface SearchResultsPanelDataProps {
     data: SearchBarAdvancedFormData;
@@ -29,7 +28,6 @@ export interface SearchResultsPanelActionProps {
     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: string) => void;
     onDialogOpen: (ownerUuid: string) => void;
     onItemDoubleClick: (item: string) => void;
     onContextMenu: (event: React.MouseEvent<HTMLElement>, item: string) => void;
     onDialogOpen: (ownerUuid: string) => void;
     onItemDoubleClick: (item: string) => void;
-    onPathDisplay: (path: string) => void;
 }
 
 export type SearchResultsPanelProps = SearchResultsPanelDataProps & SearchResultsPanelActionProps;
 }
 
 export type SearchResultsPanelProps = SearchResultsPanelDataProps & SearchResultsPanelActionProps;
@@ -51,15 +49,7 @@ const mapDispatchToProps = (dispatch: Dispatch): SearchResultsPanelActionProps =
     },
     onItemDoubleClick: uuid => {
         dispatch<any>(navigateTo(uuid));
     },
     onItemDoubleClick: uuid => {
         dispatch<any>(navigateTo(uuid));
-    },
-    onPathDisplay: (path: string) => {
-        dispatch(snackbarActions.SHIFT_MESSAGES());
-        dispatch(snackbarActions.OPEN_SNACKBAR({
-            message: path,
-            kind: SnackbarKind.INFO,
-            hideDuration: 9999999999,
-        }));
-    },
+    }
 });
 
 export const SearchResultsPanel = connect(mapStateToProps, mapDispatchToProps)(SearchResultsPanelView);
 });
 
 export const SearchResultsPanel = connect(mapStateToProps, mapDispatchToProps)(SearchResultsPanelView);