X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/bba514524b48490a8aeeb01376a10c853a90a2f2..83e7cbb4620d7e7d61c56fb25efc2069955eb78a:/services/workbench2/src/components/data-explorer/data-explorer.tsx

diff --git a/services/workbench2/src/components/data-explorer/data-explorer.tsx b/services/workbench2/src/components/data-explorer/data-explorer.tsx
index ba710bc783..40ecfc5b38 100644
--- a/services/workbench2/src/components/data-explorer/data-explorer.tsx
+++ b/services/workbench2/src/components/data-explorer/data-explorer.tsx
@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: AGPL-3.0
 
 import React from "react";
-import { Grid, Paper, Toolbar, StyleRulesCallback, withStyles, WithStyles, TablePagination, IconButton, Tooltip, Button } from "@material-ui/core";
+import { Grid, Paper, Toolbar, StyleRulesCallback, withStyles, WithStyles, TablePagination, IconButton, Tooltip, Button, Typography } from "@material-ui/core";
 import { ColumnSelector } from "components/column-selector/column-selector";
 import { DataTable, DataColumns, DataTableFetchMode } from "components/data-table/data-table";
 import { DataColumn } from "components/data-table/data-column";
@@ -16,14 +16,21 @@ import { DataTableFilters } from "components/data-table-filters/data-table-filte
 import { CloseIcon, IconType, MaximizeIcon, UnMaximizeIcon, MoreVerticalIcon } from "components/icon/icon";
 import { PaperProps } from "@material-ui/core/Paper";
 import { MPVPanelProps } from "components/multi-panel-view/multi-panel-view";
+import classNames from "classnames";
 
-type CssRules = "titleWrapper" | "searchBox" | "headerMenu" | "toolbar" | "footer" | "root" | "moreOptionsButton" | "title" | 'subProcessTitle' | "dataTable" | "container";
+type CssRules = "titleWrapper" | "msToolbarStyles" | "subpanelToolbarStyles" | "searchBox" | "headerMenu" | "toolbar" | "footer"| "loadMoreContainer" | "numResults" | "root" | "moreOptionsButton" | "title" | 'subProcessTitle' | 'progressWrapper' | 'progressWrapperNoTitle' | "dataTable" | "container";
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     titleWrapper: {
         display: "flex",
         justifyContent: "space-between",
     },
+    msToolbarStyles: {
+        paddingTop: "0.6rem",
+    },
+    subpanelToolbarStyles: {
+        paddingTop: "1.2rem",
+    },
     searchBox: {
         paddingBottom: 0,
     },
@@ -35,12 +42,24 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
     footer: {
         overflow: "auto",
     },
+    loadMoreContainer: {
+        minWidth: '8rem',
+    },
     root: {
         height: "100%",
+        flex: 1,
+        overflowY: "auto",
     },
     moreOptionsButton: {
         padding: 0,
     },
+    numResults: {
+        marginTop: 0,
+        fontSize: "10px",
+        marginLeft: "10px",
+        marginBottom: '-0.5rem',
+        minWidth: '8.5rem',
+    },
     title: {
         display: "inline-block",
         paddingLeft: theme.spacing.unit * 2,
@@ -56,6 +75,14 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         flexGrow: 0,
         paddingRight: "10px",
     },
+    progressWrapper: {
+        margin: "28px 0 0",
+        flexGrow: 1,
+        flexBasis: "100px",
+    },
+    progressWrapperNoTitle: {
+        paddingLeft: "10px",
+    },
     dataTable: {
         height: "100%",
         overflow: "auto",
@@ -92,11 +119,14 @@ interface DataExplorerDataProps<T> {
     title?: React.ReactNode;
     progressBar?: React.ReactNode;
     paperKey?: string;
-    currentItemUuid: string;
+    currentRouteUuid: string;
+    selectedResourceUuid: string;
     elementPath?: string;
     isMSToolbarVisible: boolean;
     checkedList: TCheckedList;
     isNotFound: boolean;
+    searchBarValue: string;
+    paperClassName?: string;
 }
 
 interface DataExplorerActionProps<T> {
@@ -114,14 +144,19 @@ interface DataExplorerActionProps<T> {
     extractKey?: (item: T) => React.Key;
     toggleMSToolbar: (isVisible: boolean) => void;
     setCheckedListOnStore: (checkedList: TCheckedList) => void;
+    setSelectedUuid: (uuid: string) => void;
 }
 
 type DataExplorerProps<T> = DataExplorerDataProps<T> & DataExplorerActionProps<T> & WithStyles<CssRules> & MPVPanelProps;
 
 export const DataExplorer = withStyles(styles)(
     class DataExplorerGeneric<T> extends React.Component<DataExplorerProps<T>> {
+        state = {
+            msToolbarInDetailsCard: true,
+        };
 
         multiSelectToolbarInTitle = !this.props.title && !this.props.progressBar;
+        maxItemsAvailable = 0;
 
         componentDidMount() {
             if (this.props.onSetColumns) {
@@ -129,6 +164,21 @@ export const DataExplorer = withStyles(styles)(
             }
         }
 
+        componentDidUpdate( prevProps: Readonly<DataExplorerProps<T>>, prevState: Readonly<{}>, snapshot?: any ): void {
+            const { selectedResourceUuid, currentRouteUuid } = this.props;
+            if(selectedResourceUuid !== prevProps.selectedResourceUuid || currentRouteUuid !== prevProps.currentRouteUuid) {
+                this.setState({
+                    msToolbarInDetailsCard: selectedResourceUuid === this.props.currentRouteUuid,
+                })
+            }
+            if (this.props.itemsAvailable !== prevProps.itemsAvailable) {
+                this.maxItemsAvailable = Math.max(this.maxItemsAvailable, this.props.itemsAvailable);
+            }
+            if (this.props.searchBarValue !== prevProps.searchBarValue) {
+                this.maxItemsAvailable = 0;
+            }
+        }
+
         render() {
             const {
                 columns,
@@ -155,7 +205,7 @@ export const DataExplorer = withStyles(styles)(
                 hideSearchInput,
                 paperKey,
                 fetchMode,
-                currentItemUuid,
+                selectedResourceUuid,
                 currentRoute,
                 title,
                 progressBar,
@@ -169,10 +219,11 @@ export const DataExplorer = withStyles(styles)(
                 setCheckedListOnStore,
                 checkedList,
                 working,
+                paperClassName,
             } = this.props;
             return (
                 <Paper
-                    className={classes.root}
+                    className={classNames(classes.root, paperClassName)}
                     {...paperProps}
                     key={paperKey}
                     data-cy={this.props["data-cy"]}
@@ -183,7 +234,7 @@ export const DataExplorer = withStyles(styles)(
                         wrap="nowrap"
                         className={classes.container}
                     >
-                        <div className={classes.titleWrapper} style={currentRoute?.includes('search-results') || !!progressBar ? {marginBottom: '-20px'} : {}}>
+                        <div data-cy="title-wrapper" className={classes.titleWrapper} style={currentRoute?.includes('search-results') || !!progressBar ? {marginBottom: '-20px'} : {}}>
                             {title && (
                                 <Grid
                                     item
@@ -193,8 +244,13 @@ export const DataExplorer = withStyles(styles)(
                                     {title}
                                 </Grid>
                             )}
-                            {!!progressBar && progressBar}
-                            {this.multiSelectToolbarInTitle && <MultiselectToolbar />}
+                            {!!progressBar &&
+                                <div className={classNames({
+                                    [classes.progressWrapper]: true,
+                                    [classes.progressWrapperNoTitle]: !title,
+                                })}>{progressBar}</div>
+                            }
+                            {this.multiSelectToolbarInTitle && !this.state.msToolbarInDetailsCard && <MultiselectToolbar injectedStyles={classes.msToolbarStyles} />}
                             {(!hideColumnSelector || !hideSearchInput || !!actions) && (
                                 <Grid
                                     className={classes.headerMenu}
@@ -260,7 +316,7 @@ export const DataExplorer = withStyles(styles)(
                                 </Grid>
                             )}
                         </div>
-                        {!this.multiSelectToolbarInTitle && <MultiselectToolbar />}
+                        {!this.multiSelectToolbarInTitle && <MultiselectToolbar isSubPanel={true} injectedStyles={classes.subpanelToolbarStyles}/>}
                         <Grid
                             item
                             xs="auto"
@@ -278,11 +334,13 @@ export const DataExplorer = withStyles(styles)(
                                 extractKey={extractKey}
                                 defaultViewIcon={defaultViewIcon}
                                 defaultViewMessages={defaultViewMessages}
-                                currentItemUuid={currentItemUuid}
                                 currentRoute={paperKey}
                                 toggleMSToolbar={toggleMSToolbar}
                                 setCheckedListOnStore={setCheckedListOnStore}
                                 checkedList={checkedList}
+                                selectedResourceUuid={selectedResourceUuid}
+                                setSelectedUuid={this.props.setSelectedUuid}
+                                currentRouteUuid={this.props.currentRouteUuid}
                                 working={working}
                                 isNotFound={this.props.isNotFound}
                             />
@@ -294,7 +352,7 @@ export const DataExplorer = withStyles(styles)(
                             <Toolbar className={classes.footer}>
                                 {elementPath && (
                                     <Grid container>
-                                        <span data-cy="element-path">{elementPath}</span>
+                                        <span data-cy="element-path">{elementPath.length > 2 ? elementPath : ''}</span>
                                     </Grid>
                                 )}
                                 <Grid
@@ -314,13 +372,21 @@ export const DataExplorer = withStyles(styles)(
                                             component="div"
                                         />
                                     ) : (
-                                        <Button
-                                            variant="text"
-                                            size="medium"
-                                            onClick={this.loadMore}
-                                        >
-                                            Load more
-                                        </Button>
+                                        <Grid className={classes.loadMoreContainer}>
+                                            <Typography  className={classes.numResults}>
+                                                Showing {items.length} / {this.maxItemsAvailable} results
+                                            </Typography>
+                                            <Button
+                                                size="small"
+                                                onClick={this.loadMore}
+                                                variant="contained"
+                                                color="primary"
+                                                style={{width: '100%', margin: '10px'}}
+                                                disabled={working || items.length >= itemsAvailable}
+                                            >
+                                                Load more
+                                            </Button>
+                                        </Grid>
                                     )}
                                 </Grid>
                             </Toolbar>
