Skip to content

Commit 51ba86f

Browse files
authored
Add progress bar on UI (#526)
1 parent f5922bb commit 51ba86f

File tree

6 files changed

+187
-102
lines changed

6 files changed

+187
-102
lines changed

portal-ui/src/actions.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import {
2020
SERVER_IS_LOADING,
2121
SERVER_NEEDS_RESTART,
2222
USER_LOGGED,
23+
SET_LOADING_PROGRESS,
24+
SET_SNACK_BAR_MESSAGE,
2325
} from "./types";
2426

2527
export function userLoggedIn(loggedIn: boolean) {
@@ -56,3 +58,17 @@ export function serverIsLoading(isLoading: boolean) {
5658
isLoading: isLoading,
5759
};
5860
}
61+
62+
export const setLoadingProgress = (progress: number) => {
63+
return {
64+
type: SET_LOADING_PROGRESS,
65+
loadingProgress: progress,
66+
};
67+
};
68+
69+
export const setSnackBarMessage = (message: string) => {
70+
return {
71+
type: SET_SNACK_BAR_MESSAGE,
72+
snackBarMessage: message,
73+
};
74+
};

portal-ui/src/reducer.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
SystemActionTypes,
2323
SystemState,
2424
USER_LOGGED,
25+
SET_LOADING_PROGRESS,
26+
SET_SNACK_BAR_MESSAGE,
2527
} from "./types";
2628

2729
const initialState: SystemState = {
@@ -32,6 +34,8 @@ const initialState: SystemState = {
3234
sidebarOpen: true,
3335
serverNeedsRestart: false,
3436
serverIsLoading: false,
37+
loadingProgress: 100,
38+
snackBarMessage: "",
3539
};
3640

3741
export function systemReducer(
@@ -65,6 +69,16 @@ export function systemReducer(
6569
...state,
6670
serverIsLoading: action.isLoading,
6771
};
72+
case SET_LOADING_PROGRESS:
73+
return {
74+
...state,
75+
loadingProgress: action.loadingProgress,
76+
};
77+
case SET_SNACK_BAR_MESSAGE:
78+
return {
79+
...state,
80+
snackBarMessage: action.snackBarMessage,
81+
};
6882
default:
6983
return state;
7084
}

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx

Lines changed: 48 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import { isNullOrUndefined } from "util";
3737
import { Button, Input } from "@material-ui/core";
3838
import * as reactMoment from "react-moment";
3939
import { CreateIcon } from "../../../../../../icons";
40-
import Snackbar from "@material-ui/core/Snackbar";
4140
import BrowserBreadcrumbs from "../../../../ObjectBrowser/BrowserBreadcrumbs";
4241
import get from "lodash/get";
4342
import { withRouter } from "react-router-dom";
@@ -51,6 +50,10 @@ import { ObjectBrowserState, Route } from "../../../../ObjectBrowser/reducers";
5150
import CreateFolderModal from "./CreateFolderModal";
5251
import UploadFile from "../../../../../../icons/UploadFile";
5352
import { download } from "../utils";
53+
import {
54+
setLoadingProgress,
55+
setSnackBarMessage,
56+
} from "../../../../../../actions";
5457

5558
const commonIcon = {
5659
backgroundRepeat: "no-repeat",
@@ -134,6 +137,8 @@ interface IListObjectsProps {
134137
setAllRoutes: (path: string) => any;
135138
routesList: Route[];
136139
setLastAsFile: () => any;
140+
setLoadingProgress: typeof setLoadingProgress;
141+
setSnackBarMessage: typeof setSnackBarMessage;
137142
}
138143

139144
interface ObjectBrowserReducer {
@@ -147,6 +152,8 @@ const ListObjects = ({
147152
setAllRoutes,
148153
routesList,
149154
setLastAsFile,
155+
setLoadingProgress,
156+
setSnackBarMessage,
150157
}: IListObjectsProps) => {
151158
const [records, setRecords] = useState<BucketObject[]>([]);
152159
const [loading, setLoading] = useState<boolean>(true);
@@ -155,8 +162,6 @@ const ListObjects = ({
155162
const [selectedObject, setSelectedObject] = useState<string>("");
156163
const [selectedBucket, setSelectedBucket] = useState<string>("");
157164
const [filterObjects, setFilterObjects] = useState<string>("");
158-
const [openSnackbar, setOpenSnackbar] = useState<boolean>(false);
159-
const [snackBarMessage, setSnackbarMessage] = useState<string>("");
160165

161166
useEffect(() => {
162167
const bucketName = match.params["bucket"];
@@ -185,26 +190,28 @@ const ListObjects = ({
185190
});
186191
};
187192

188-
let extraPath = "";
189-
if (internalPaths) {
190-
extraPath = `?prefix=${internalPaths}/`;
191-
}
193+
if (loading) {
194+
let extraPath = "";
195+
if (internalPaths) {
196+
extraPath = `?prefix=${internalPaths}/`;
197+
}
192198

193-
api
194-
.invoke("GET", `/api/v1/buckets/${bucketName}/objects${extraPath}`)
195-
.then((res: BucketObjectsList) => {
196-
setSelectedBucket(bucketName);
197-
setRecords(res.objects || []);
198-
// In case no objects were retrieved, We check if item is a file
199-
if (!res.objects && extraPath !== "") {
200-
verifyIfIsFile();
201-
return;
202-
}
203-
setLoading(false);
204-
})
205-
.catch((err: any) => {
206-
setLoading(false);
207-
});
199+
api
200+
.invoke("GET", `/api/v1/buckets/${bucketName}/objects${extraPath}`)
201+
.then((res: BucketObjectsList) => {
202+
setSelectedBucket(bucketName);
203+
setRecords(res.objects || []);
204+
// In case no objects were retrieved, We check if item is a file
205+
if (!res.objects && extraPath !== "") {
206+
verifyIfIsFile();
207+
return;
208+
}
209+
setLoading(false);
210+
})
211+
.catch((err: any) => {
212+
setLoading(false);
213+
});
214+
}
208215
}, [loading, match, setLastAsFile]);
209216

210217
useEffect(() => {
@@ -218,7 +225,7 @@ const ListObjects = ({
218225
setDeleteOpen(false);
219226

220227
if (refresh) {
221-
showSnackBarMessage(`Object '${selectedObject}' deleted successfully.`);
228+
setSnackBarMessage(`Object '${selectedObject}' deleted successfully.`);
222229
setLoading(true);
223230
}
224231
};
@@ -227,16 +234,6 @@ const ListObjects = ({
227234
setCreateFolderOpen(false);
228235
};
229236

230-
const showSnackBarMessage = (text: string) => {
231-
setSnackbarMessage(text);
232-
setOpenSnackbar(true);
233-
};
234-
235-
const closeSnackBar = () => {
236-
setSnackbarMessage("");
237-
setOpenSnackbar(false);
238-
};
239-
240237
const upload = (e: any, bucketName: string, path: string) => {
241238
if (isNullOrUndefined(e) || isNullOrUndefined(e.target)) {
242239
return;
@@ -252,31 +249,34 @@ const ListObjects = ({
252249
xhr.open("POST", uploadUrl, true);
253250

254251
xhr.withCredentials = false;
255-
xhr.onload = function (event) {
256-
// TODO: handle status
257-
if (xhr.status === 401 || xhr.status === 403) {
258-
showSnackBarMessage("An error occurred while uploading the file.");
259-
}
260-
if (xhr.status === 500) {
261-
showSnackBarMessage("An error occurred while uploading the file.");
252+
xhr.onload = function(event) {
253+
if (
254+
xhr.status === 401 ||
255+
xhr.status === 403 ||
256+
xhr.status === 400 ||
257+
xhr.status === 500
258+
) {
259+
setSnackBarMessage("An error occurred while uploading the file.");
262260
}
263261
if (xhr.status === 200) {
264-
showSnackBarMessage("Object uploaded successfully.");
265-
setLoading(true);
262+
setSnackBarMessage("Object uploaded successfully.");
266263
}
267264
};
268265

269266
xhr.upload.addEventListener("error", (event) => {
270-
// TODO: handle error
271-
showSnackBarMessage("An error occurred while uploading the file.");
267+
setSnackBarMessage("An error occurred while uploading the file.");
272268
});
273269

274270
xhr.upload.addEventListener("progress", (event) => {
275-
// TODO: handle progress with event.loaded, event.total
271+
setLoadingProgress(Math.floor((event.loaded * 100) / event.total));
276272
});
277273

278274
xhr.onerror = () => {
279-
showSnackBarMessage("An error occurred while uploading the file.");
275+
setSnackBarMessage("An error occurred while uploading the file.");
276+
};
277+
xhr.onloadend = () => {
278+
setLoading(true);
279+
setLoadingProgress(100);
280280
};
281281

282282
const formData = new FormData();
@@ -346,23 +346,9 @@ const ListObjects = ({
346346
path = `${splitPaths.slice(2).join("/")}/`;
347347
}
348348

349-
let file = e.target.files[0];
350-
showSnackBarMessage(`Uploading: ${file.name}`);
351349
upload(e, selectedBucket, path);
352350
};
353351

354-
const snackBarAction = (
355-
<Button
356-
color="secondary"
357-
size="small"
358-
onClick={() => {
359-
closeSnackBar();
360-
}}
361-
>
362-
Dismiss
363-
</Button>
364-
);
365-
366352
const tableActions = [
367353
{ type: "view", onClick: openPath, sendOnlyId: true },
368354
{ type: "download", onClick: downloadObject },
@@ -419,11 +405,6 @@ const ListObjects = ({
419405
onClose={closeAddFolderModal}
420406
/>
421407
)}
422-
<Snackbar
423-
open={openSnackbar}
424-
message={snackBarMessage}
425-
action={snackBarAction}
426-
/>
427408
<PageHeader label="Object Browser" />
428409
<Grid container>
429410
<Grid item xs={12} className={classes.container}>
@@ -526,6 +507,8 @@ const mapDispatchToProps = {
526507
addRoute,
527508
setAllRoutes,
528509
setLastAsFile,
510+
setLoadingProgress,
511+
setSnackBarMessage,
529512
};
530513

531514
const connector = connect(mapStateToProps, mapDispatchToProps);

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ShareFile.tsx

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, { useEffect, useState } from "react";
22
import { createStyles, Theme, withStyles } from "@material-ui/core/styles";
33
import CopyToClipboard from "react-copy-to-clipboard";
4-
import Snackbar from "@material-ui/core/Snackbar";
54
import Grid from "@material-ui/core/Grid";
65
import Button from "@material-ui/core/Button";
76
import { modalBasic } from "../../../../Common/FormComponents/common/styleLibrary";
@@ -12,6 +11,8 @@ import api from "../../../../../../common/api";
1211
import { IFileInfo } from "./types";
1312
import PredefinedList from "../../../../Common/FormComponents/PredefinedList/PredefinedList";
1413
import ErrorBlock from "../../../../../shared/ErrorBlock";
14+
import { setSnackBarMessage } from "../../../../../../actions";
15+
import { connect } from "react-redux";
1516

1617
const styles = (theme: Theme) =>
1718
createStyles({
@@ -30,6 +31,7 @@ interface IShareFileProps {
3031
bucketName: string;
3132
dataObject: IFileInfo;
3233
closeModalAndRefresh: () => void;
34+
setSnackBarMessage: typeof setSnackBarMessage;
3335
}
3436

3537
const ShareFile = ({
@@ -38,24 +40,13 @@ const ShareFile = ({
3840
closeModalAndRefresh,
3941
bucketName,
4042
dataObject,
43+
setSnackBarMessage,
4144
}: IShareFileProps) => {
4245
const [shareURL, setShareURL] = useState<string>("");
4346
const [isLoadingFile, setIsLoadingFile] = useState<boolean>(false);
4447
const [error, setError] = useState<string>("");
4548
const [selectedDate, setSelectedDate] = useState<string>("");
4649
const [dateValid, setDateValid] = useState<boolean>(true);
47-
const [openSnack, setOpenSnack] = useState<boolean>(false);
48-
const [snackBarMessage, setSnackbarMessage] = useState<string>("");
49-
50-
const showSnackBarMessage = (text: string) => {
51-
setSnackbarMessage(text);
52-
setOpenSnack(true);
53-
};
54-
55-
const closeSnackBar = () => {
56-
setSnackbarMessage("");
57-
setOpenSnack(false);
58-
};
5950

6051
const dateChanged = (newDate: string, isValid: boolean) => {
6152
setDateValid(isValid);
@@ -115,27 +106,8 @@ const ShareFile = ({
115106
}
116107
}, [dataObject, selectedDate, bucketName, dateValid, setShareURL]);
117108

118-
const snackBarAction = (
119-
<Button
120-
color="secondary"
121-
size="small"
122-
onClick={() => {
123-
closeSnackBar();
124-
}}
125-
>
126-
Dismiss
127-
</Button>
128-
);
129-
130109
return (
131110
<React.Fragment>
132-
{openSnack && (
133-
<Snackbar
134-
open={openSnack}
135-
message={snackBarMessage}
136-
action={snackBarAction}
137-
/>
138-
)}
139111
<ModalWrapper
140112
title="Share File"
141113
modalOpen={open}
@@ -169,7 +141,7 @@ const ShareFile = ({
169141
color="primary"
170142
startIcon={<CopyIcon />}
171143
onClick={() => {
172-
showSnackBarMessage("Share URL Copied to clipboard");
144+
setSnackBarMessage("Share URL Copied to clipboard");
173145
}}
174146
disabled={shareURL === "" || isLoadingFile}
175147
>
@@ -184,4 +156,10 @@ const ShareFile = ({
184156
);
185157
};
186158

187-
export default withStyles(styles)(ShareFile);
159+
const mapState = (state: IShareFileProps) => ({});
160+
161+
const connector = connect(mapState, {
162+
setSnackBarMessage,
163+
});
164+
165+
export default withStyles(styles)(connector(ShareFile));

0 commit comments

Comments
 (0)