Interactive Feedback when list objects take a long time (#655)
* Interactive Feedback when list objects take a long time * Remove cancel button Co-authored-by: Alex <33497058+bexsoft@users.noreply.github.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
searchField,
|
||||
} from "../../../../Common/FormComponents/common/styleLibrary";
|
||||
import PageHeader from "../../../../Common/PageHeader/PageHeader";
|
||||
import { Button, Input } from "@material-ui/core";
|
||||
import { Button, Input, Typography } from "@material-ui/core";
|
||||
import * as reactMoment from "react-moment";
|
||||
import { CreateIcon } from "../../../../../../icons";
|
||||
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
|
||||
@@ -150,6 +150,30 @@ interface IListObjectsProps {
|
||||
fileDownloadStarted: typeof fileDownloadStarted;
|
||||
}
|
||||
|
||||
function useInterval(callback: any, delay: number) {
|
||||
const savedCallback = useRef<Function | null>(null);
|
||||
|
||||
// Remember the latest callback.
|
||||
useEffect(() => {
|
||||
savedCallback.current = callback;
|
||||
}, [callback]);
|
||||
|
||||
// Set up the interval.
|
||||
useEffect(() => {
|
||||
function tick() {
|
||||
if (savedCallback !== undefined && savedCallback.current) {
|
||||
savedCallback.current();
|
||||
}
|
||||
}
|
||||
if (delay !== null) {
|
||||
let id = setInterval(tick, delay);
|
||||
return () => clearInterval(id);
|
||||
}
|
||||
}, [delay]);
|
||||
}
|
||||
|
||||
const defLoading = <Typography component="h3">Loading...</Typography>;
|
||||
|
||||
const ListObjects = ({
|
||||
classes,
|
||||
match,
|
||||
@@ -171,6 +195,41 @@ const ListObjects = ({
|
||||
const [selectedObject, setSelectedObject] = useState<string>("");
|
||||
const [selectedBucket, setSelectedBucket] = useState<string>("");
|
||||
const [filterObjects, setFilterObjects] = useState<string>("");
|
||||
const [loadingPromise, setLoadingPromise] = useState<Promise<any> | null>(
|
||||
null
|
||||
);
|
||||
const [loadingStartTime, setLoadingStartTime] = useState<number>(0);
|
||||
const [loadingMessage, setLoadingMessage] = useState<React.ReactNode>(
|
||||
defLoading
|
||||
);
|
||||
|
||||
const updateMessage = () => {
|
||||
let timeDelta = Date.now() - loadingStartTime;
|
||||
|
||||
if (timeDelta / 1000 >= 6) {
|
||||
setLoadingMessage(
|
||||
<React.Fragment>
|
||||
<Typography component="h3">
|
||||
This operation is taking longer than expected... (
|
||||
{Math.ceil(timeDelta / 1000)}s)
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
);
|
||||
} else if (timeDelta / 1000 >= 3) {
|
||||
setLoadingMessage(
|
||||
<Typography component="h3">
|
||||
This operation is taking longer than expected...
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useInterval(() => {
|
||||
// Your custom logic here
|
||||
if (loading) {
|
||||
updateMessage();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
useEffect(() => {
|
||||
const bucketName = match.params["bucket"];
|
||||
@@ -206,7 +265,11 @@ const ListObjects = ({
|
||||
extraPath = `?prefix=${internalPaths}/`;
|
||||
}
|
||||
|
||||
api
|
||||
let currentTimestamp = Date.now() + 0;
|
||||
setLoadingStartTime(currentTimestamp);
|
||||
setLoadingMessage(defLoading);
|
||||
|
||||
let p = api
|
||||
.invoke("GET", `/api/v1/buckets/${bucketName}/objects${extraPath}`)
|
||||
.then((res: BucketObjectsList) => {
|
||||
setSelectedBucket(bucketName);
|
||||
@@ -239,6 +302,7 @@ const ListObjects = ({
|
||||
setLoading(false);
|
||||
setErrorSnackMessage(err);
|
||||
});
|
||||
setLoadingPromise(p);
|
||||
}
|
||||
}, [loading, match, setLastAsFile, setErrorSnackMessage]);
|
||||
|
||||
@@ -558,6 +622,7 @@ const ListObjects = ({
|
||||
},
|
||||
]}
|
||||
isLoading={loading}
|
||||
loadingMessage={loadingMessage}
|
||||
entityName="Objects"
|
||||
idField="name"
|
||||
records={filteredRecords}
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import React, { useState, Fragment } from "react";
|
||||
import React, { Fragment, useState } from "react";
|
||||
import get from "lodash/get";
|
||||
import isString from "lodash/isString";
|
||||
import {
|
||||
Checkbox,
|
||||
Grid,
|
||||
IconButton,
|
||||
LinearProgress,
|
||||
Paper,
|
||||
Grid,
|
||||
Checkbox,
|
||||
Typography,
|
||||
IconButton,
|
||||
Popover,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import { Table, Column, AutoSizer, InfiniteLoader } from "react-virtualized";
|
||||
import { AutoSizer, Column, InfiniteLoader, Table } from "react-virtualized";
|
||||
import { createStyles, withStyles } from "@material-ui/core/styles";
|
||||
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||
import ViewColumnIcon from "@material-ui/icons/ViewColumn";
|
||||
@@ -43,11 +43,12 @@ import CheckboxWrapper from "../FormComponents/CheckboxWrapper/CheckboxWrapper";
|
||||
|
||||
interface ItemActions {
|
||||
type: string;
|
||||
onClick?(valueToSend: any): any;
|
||||
to?: string;
|
||||
sendOnlyId?: boolean;
|
||||
hideButtonFunction?: (itemValue: any) => boolean;
|
||||
showLoaderFunction?: (itemValue: any) => boolean;
|
||||
|
||||
onClick?(valueToSend: any): any;
|
||||
}
|
||||
|
||||
interface IColumns {
|
||||
@@ -83,6 +84,7 @@ interface TableWrapperProps {
|
||||
onSelect?: (e: React.ChangeEvent<HTMLInputElement>) => any;
|
||||
idField: string;
|
||||
isLoading: boolean;
|
||||
loadingMessage?: React.ReactNode;
|
||||
records: any[];
|
||||
classes: any;
|
||||
entityName: string;
|
||||
@@ -491,6 +493,7 @@ const TableWrapper = ({
|
||||
onSelect,
|
||||
records,
|
||||
isLoading,
|
||||
loadingMessage = <Typography component="h3">Loading...</Typography>,
|
||||
entityName,
|
||||
selectedItems,
|
||||
idField,
|
||||
@@ -600,7 +603,7 @@ const TableWrapper = ({
|
||||
{isLoading && (
|
||||
<Grid container className={classes.loadingBox}>
|
||||
<Grid item xs={12} style={{ textAlign: "center" }}>
|
||||
<Typography component="h3">Loading...</Typography>
|
||||
{loadingMessage}
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<LinearProgress />
|
||||
|
||||
Reference in New Issue
Block a user