2960: Merge branch 'main' into 2960-keepstore-streaming
[arvados.git] / services / workbench2 / src / components / data-explorer / data-explorer.tsx
index ad5762dfeb1bac4bda716b02ff60bdd646c6dbf0..ba710bc783e9ca6368c5355d042a3930e677af8b 100644 (file)
@@ -17,15 +17,20 @@ import { CloseIcon, IconType, MaximizeIcon, UnMaximizeIcon, MoreVerticalIcon } f
 import { PaperProps } from "@material-ui/core/Paper";
 import { MPVPanelProps } from "components/multi-panel-view/multi-panel-view";
 
-type CssRules = "searchBox" | "headerMenu" | "toolbar" | "footer" | "root" | "moreOptionsButton" | "title" | "dataTable" | "container";
+type CssRules = "titleWrapper" | "searchBox" | "headerMenu" | "toolbar" | "footer" | "root" | "moreOptionsButton" | "title" | 'subProcessTitle' | "dataTable" | "container";
 
 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+    titleWrapper: {
+        display: "flex",
+        justifyContent: "space-between",
+    },
     searchBox: {
         paddingBottom: 0,
     },
     toolbar: {
         paddingTop: 0,
         paddingRight: theme.spacing.unit,
+        paddingLeft: "10px",
     },
     footer: {
         overflow: "auto",
@@ -41,6 +46,15 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         paddingLeft: theme.spacing.unit * 2,
         paddingTop: theme.spacing.unit * 2,
         fontSize: "18px",
+        paddingRight: "10px",
+    },
+    subProcessTitle: {
+        display: "inline-block",
+        paddingLeft: theme.spacing.unit * 2,
+        paddingTop: theme.spacing.unit * 2,
+        fontSize: "18px",
+        flexGrow: 0,
+        paddingRight: "10px",
     },
     dataTable: {
         height: "100%",
@@ -50,11 +64,9 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
         height: "100%",
     },
     headerMenu: {
-        width: "100%",
-        float: "right",
-        display: "flex",
-        flexDirection: "row-reverse",
-        justifyContent: "space-between",
+        marginLeft: "auto",
+        flexBasis: "initial",
+        flexGrow: 0,
     },
 });
 
@@ -72,18 +84,19 @@ interface DataExplorerDataProps<T> {
     defaultViewIcon?: IconType;
     defaultViewMessages?: string[];
     working?: boolean;
-    currentRefresh?: string;
     currentRoute?: string;
     hideColumnSelector?: boolean;
     paperProps?: PaperProps;
     actions?: React.ReactNode;
     hideSearchInput?: boolean;
     title?: React.ReactNode;
+    progressBar?: React.ReactNode;
     paperKey?: string;
     currentItemUuid: string;
     elementPath?: string;
     isMSToolbarVisible: boolean;
     checkedList: TCheckedList;
+    isNotFound: boolean;
 }
 
 interface DataExplorerActionProps<T> {
@@ -107,50 +120,13 @@ type DataExplorerProps<T> = DataExplorerDataProps<T> & DataExplorerActionProps<T
 
 export const DataExplorer = withStyles(styles)(
     class DataExplorerGeneric<T> extends React.Component<DataExplorerProps<T>> {
-        state = {
-            showLoading: false,
-            prevRefresh: "",
-            prevRoute: "",
-        };
-
-        componentDidUpdate(prevProps: DataExplorerProps<T>) {
-            const currentRefresh = this.props.currentRefresh || "";
-            const currentRoute = this.props.currentRoute || "";
 
-            if (currentRoute !== this.state.prevRoute) {
-                // Component already mounted, but the user comes from a route change,
-                // like browsing through a project hierarchy.
-                this.setState({
-                    showLoading: this.props.working,
-                    prevRoute: currentRoute,
-                });
-            }
-
-            if (currentRefresh !== this.state.prevRefresh) {
-                // Component already mounted, but the user just clicked the
-                // refresh button.
-                this.setState({
-                    showLoading: this.props.working,
-                    prevRefresh: currentRefresh,
-                });
-            }
-            if (this.state.showLoading && !this.props.working) {
-                this.setState({
-                    showLoading: false,
-                });
-            }
-        }
+        multiSelectToolbarInTitle = !this.props.title && !this.props.progressBar;
 
         componentDidMount() {
             if (this.props.onSetColumns) {
                 this.props.onSetColumns(this.props.columns);
             }
-            // Component just mounted, so we need to show the loading indicator.
-            this.setState({
-                showLoading: this.props.working,
-                prevRefresh: this.props.currentRefresh || "",
-                prevRoute: this.props.currentRoute || "",
-            });
         }
 
         render() {
@@ -180,7 +156,9 @@ export const DataExplorer = withStyles(styles)(
                 paperKey,
                 fetchMode,
                 currentItemUuid,
+                currentRoute,
                 title,
+                progressBar,
                 doHidePanel,
                 doMaximizePanel,
                 doUnMaximizePanel,
@@ -190,6 +168,7 @@ export const DataExplorer = withStyles(styles)(
                 toggleMSToolbar,
                 setCheckedListOnStore,
                 checkedList,
+                working,
             } = this.props;
             return (
                 <Paper
@@ -204,16 +183,18 @@ export const DataExplorer = withStyles(styles)(
                         wrap="nowrap"
                         className={classes.container}
                     >
-                        <div>
+                        <div className={classes.titleWrapper} style={currentRoute?.includes('search-results') || !!progressBar ? {marginBottom: '-20px'} : {}}>
                             {title && (
                                 <Grid
                                     item
                                     xs
-                                    className={classes.title}
+                                    className={!!progressBar ? classes.subProcessTitle : classes.title}
                                 >
                                     {title}
                                 </Grid>
                             )}
+                            {!!progressBar && progressBar}
+                            {this.multiSelectToolbarInTitle && <MultiselectToolbar />}
                             {(!hideColumnSelector || !hideSearchInput || !!actions) && (
                                 <Grid
                                     className={classes.headerMenu}
@@ -221,25 +202,27 @@ export const DataExplorer = withStyles(styles)(
                                     xs
                                 >
                                     <Toolbar className={classes.toolbar}>
-                                        {!hideSearchInput && (
-                                            <div className={classes.searchBox}>
-                                                {!hideSearchInput && (
-                                                    <SearchInput
-                                                        label={searchLabel}
-                                                        value={searchValue}
-                                                        selfClearProp={""}
-                                                        onSearch={onSearch}
-                                                    />
-                                                )}
-                                            </div>
-                                        )}
-                                        {actions}
-                                        {!hideColumnSelector && (
-                                            <ColumnSelector
-                                                columns={columns}
-                                                onColumnToggle={onColumnToggle}
-                                            />
-                                        )}
+                                        <Grid container justify="space-between" wrap="nowrap" alignItems="center">
+                                            {!hideSearchInput && (
+                                                <div className={classes.searchBox}>
+                                                    {!hideSearchInput && (
+                                                        <SearchInput
+                                                            label={searchLabel}
+                                                            value={searchValue}
+                                                            selfClearProp={""}
+                                                            onSearch={onSearch}
+                                                        />
+                                                    )}
+                                                </div>
+                                            )}
+                                            {actions}
+                                            {!hideColumnSelector && (
+                                                <ColumnSelector
+                                                    columns={columns}
+                                                    onColumnToggle={onColumnToggle}
+                                                />
+                                            )}
+                                        </Grid>
                                         {doUnMaximizePanel && panelMaximized && (
                                             <Tooltip
                                                 title={`Unmaximize ${panelName || "panel"}`}
@@ -274,14 +257,15 @@ export const DataExplorer = withStyles(styles)(
                                             </Tooltip>
                                         )}
                                     </Toolbar>
-                                    <MultiselectToolbar />
                                 </Grid>
                             )}
                         </div>
+                        {!this.multiSelectToolbarInTitle && <MultiselectToolbar />}
                         <Grid
                             item
                             xs="auto"
                             className={classes.dataTable}
+                            style={currentRoute?.includes('search-results')  || !!progressBar ? {marginTop: '-10px'} : {}}
                         >
                             <DataTable
                                 columns={this.props.contextMenuColumn ? [...columns, this.contextMenuColumn] : columns}
@@ -292,7 +276,6 @@ export const DataExplorer = withStyles(styles)(
                                 onFiltersChange={onFiltersChange}
                                 onSortToggle={onSortToggle}
                                 extractKey={extractKey}
-                                working={this.state.showLoading}
                                 defaultViewIcon={defaultViewIcon}
                                 defaultViewMessages={defaultViewMessages}
                                 currentItemUuid={currentItemUuid}
@@ -300,6 +283,8 @@ export const DataExplorer = withStyles(styles)(
                                 toggleMSToolbar={toggleMSToolbar}
                                 setCheckedListOnStore={setCheckedListOnStore}
                                 checkedList={checkedList}
+                                working={working}
+                                isNotFound={this.props.isNotFound}
                             />
                         </Grid>
                         <Grid
@@ -368,7 +353,10 @@ export const DataExplorer = withStyles(styles)(
                 >
                     <IconButton
                         className={this.props.classes.moreOptionsButton}
-                        onClick={event => this.props.onContextMenu(event, item)}
+                        onClick={event => {
+                            event.stopPropagation()
+                            this.props.onContextMenu(event, item)
+                        }}
                     >
                         <MoreVerticalIcon />
                     </IconButton>