Skip to content

Commit 3f4b595

Browse files
authored
Improved folder drop upload behavior (#1331)
1 parent 3d357c8 commit 3f4b595

File tree

3 files changed

+183
-120
lines changed

3 files changed

+183
-120
lines changed

portal-ui/package.json

Lines changed: 99 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,101 @@
11
{
2-
"name": "portal-ui",
3-
"version": "0.1.0",
4-
"homepage": ".",
5-
"private": true,
6-
"dependencies": {
7-
"@date-io/moment": "1.x",
8-
"@emotion/react": "^11.4.1",
9-
"@emotion/styled": "^11.3.0",
10-
"@hot-loader/react-dom": "17.0.1",
11-
"@mui/icons-material": "^5.0.4",
12-
"@mui/lab": "^5.0.0-alpha.30",
13-
"@mui/material": "^5.0.4",
14-
"@mui/styled-engine-sc": "^5.0.3",
15-
"@mui/styles": "^5.0.1",
16-
"@types/history": "^4.7.3",
17-
"@types/jest": "24.0.23",
18-
"@types/lodash": "^4.14.149",
19-
"@types/node": "12.12.8",
20-
"@types/react": "17.0.0",
21-
"@types/react-copy-to-clipboard": "^4.3.0",
22-
"@types/react-dom": "16.9.4",
23-
"@types/react-grid-layout": "^1.1.1",
24-
"@types/react-redux": "^7.1.5",
25-
"@types/react-router": "^5.1.3",
26-
"@types/react-router-dom": "^5.1.2",
27-
"@types/react-virtualized": "^9.21.10",
28-
"@types/superagent": "^4.1.12",
29-
"@types/webpack-env": "^1.14.1",
30-
"@types/websocket": "^1.0.0",
31-
"ansi-to-react": "^6.0.5",
32-
"chart.js": "^2.9.3",
33-
"codemirror": "^5.52.2",
34-
"history": "^4.10.1",
35-
"local-storage-fallback": "^4.1.1",
36-
"lodash": "^4.17.21",
37-
"moment": "^2.29.1",
38-
"react": "^17.0.2",
39-
"react-async-hook": "^3.6.1",
40-
"react-chartjs-2": "^2.9.0",
41-
"react-codemirror2": "^7.1.0",
42-
"react-copy-to-clipboard": "^5.0.2",
43-
"react-dom": "17.0.1",
44-
"react-grid-layout": "^1.2.0",
45-
"react-hot-loader": "^4.13.0",
46-
"react-moment": "^1.1.1",
47-
"react-redux": "^7.1.3",
48-
"react-router-dom": "^5.1.2",
49-
"react-virtualized": "^9.22.2",
50-
"react-window-infinite-loader": "^1.0.5",
51-
"recharts": "^2.1.1",
52-
"redux": "^4.0.5",
53-
"redux-thunk": "^2.3.0",
54-
"styled-components": "^5.3.1",
55-
"superagent": "^6.1.0",
56-
"typeface-roboto": "^0.0.75",
57-
"use-debounce": "^5.0.1",
58-
"websocket": "^1.0.31"
59-
},
60-
"scripts": {
61-
"start": "PORT=5005 react-app-rewired start",
62-
"build": "react-scripts build",
63-
"test": "react-scripts test",
64-
"eject": "react-scripts eject"
65-
},
66-
"eslintConfig": {
67-
"extends": "react-app"
68-
},
69-
"browserslist": {
70-
"production": [
71-
">0.2%",
72-
"not dead",
73-
"not op_mini all"
74-
],
75-
"development": [
76-
"last 1 chrome version",
77-
"last 1 firefox version",
78-
"last 1 safari version"
79-
]
80-
},
81-
"proxy": "http://localhost:9090/",
82-
"devDependencies": {
83-
"@types/recharts": "^1.8.22",
84-
"prettier": "2.5.1",
85-
"react-app-rewire-hot-loader": "^2.0.1",
86-
"react-app-rewired": "^2.1.6",
87-
"react-scripts": "4.0.3",
88-
"typescript": "^4.4.3"
89-
},
90-
"resolutions": {
91-
"@types/jest/**/ansi-regex": "^5.0.1",
92-
"react-scripts/**/ansi-regex": "^5.0.1",
93-
"react-scripts/**/nth-check": "^2.0.1",
94-
"react-scripts/**/set-value": "^4.0.1",
95-
"react-scripts/**/immer": "^9.0.6",
96-
"react-scripts/**/glob-parent": "^5.1.2",
97-
"react-scripts/**/browserslist": "^4.16.5",
98-
"react-scripts/**/ansi-html": "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz"
99-
}
2+
"name": "portal-ui",
3+
"version": "0.1.0",
4+
"homepage": ".",
5+
"private": true,
6+
"dependencies": {
7+
"@date-io/moment": "1.x",
8+
"@emotion/react": "^11.4.1",
9+
"@emotion/styled": "^11.3.0",
10+
"@hot-loader/react-dom": "17.0.1",
11+
"@mui/icons-material": "^5.0.4",
12+
"@mui/lab": "^5.0.0-alpha.30",
13+
"@mui/material": "^5.0.4",
14+
"@mui/styled-engine-sc": "^5.0.3",
15+
"@mui/styles": "^5.0.1",
16+
"@types/history": "^4.7.3",
17+
"@types/jest": "24.0.23",
18+
"@types/lodash": "^4.14.149",
19+
"@types/node": "12.12.8",
20+
"@types/react": "17.0.0",
21+
"@types/react-copy-to-clipboard": "^4.3.0",
22+
"@types/react-dom": "16.9.4",
23+
"@types/react-grid-layout": "^1.1.1",
24+
"@types/react-redux": "^7.1.5",
25+
"@types/react-router": "^5.1.3",
26+
"@types/react-router-dom": "^5.1.2",
27+
"@types/react-virtualized": "^9.21.10",
28+
"@types/superagent": "^4.1.12",
29+
"@types/webpack-env": "^1.14.1",
30+
"@types/websocket": "^1.0.0",
31+
"ansi-to-react": "^6.0.5",
32+
"chart.js": "^2.9.3",
33+
"codemirror": "^5.52.2",
34+
"history": "^4.10.1",
35+
"local-storage-fallback": "^4.1.1",
36+
"lodash": "^4.17.21",
37+
"moment": "^2.29.1",
38+
"react": "^17.0.2",
39+
"react-async-hook": "^3.6.1",
40+
"react-chartjs-2": "^2.9.0",
41+
"react-codemirror2": "^7.1.0",
42+
"react-copy-to-clipboard": "^5.0.2",
43+
"react-dom": "17.0.1",
44+
"react-dropzone": "^11.4.2",
45+
"react-grid-layout": "^1.2.0",
46+
"react-hot-loader": "^4.13.0",
47+
"react-moment": "^1.1.1",
48+
"react-redux": "^7.1.3",
49+
"react-router-dom": "^5.1.2",
50+
"react-virtualized": "^9.22.2",
51+
"react-window-infinite-loader": "^1.0.5",
52+
"recharts": "^2.1.1",
53+
"redux": "^4.0.5",
54+
"redux-thunk": "^2.3.0",
55+
"styled-components": "^5.3.1",
56+
"superagent": "^6.1.0",
57+
"typeface-roboto": "^0.0.75",
58+
"use-debounce": "^5.0.1",
59+
"websocket": "^1.0.31"
60+
},
61+
"scripts": {
62+
"start": "PORT=5005 react-app-rewired start",
63+
"build": "react-scripts build",
64+
"test": "react-scripts test",
65+
"eject": "react-scripts eject"
66+
},
67+
"eslintConfig": {
68+
"extends": "react-app"
69+
},
70+
"browserslist": {
71+
"production": [
72+
">0.2%",
73+
"not dead",
74+
"not op_mini all"
75+
],
76+
"development": [
77+
"last 1 chrome version",
78+
"last 1 firefox version",
79+
"last 1 safari version"
80+
]
81+
},
82+
"proxy": "http://localhost:9090/",
83+
"devDependencies": {
84+
"@types/recharts": "^1.8.22",
85+
"prettier": "2.3.2",
86+
"react-app-rewire-hot-loader": "^2.0.1",
87+
"react-app-rewired": "^2.1.6",
88+
"react-scripts": "4.0.3",
89+
"typescript": "^4.4.3"
90+
},
91+
"resolutions": {
92+
"@types/jest/**/ansi-regex": "^5.0.1",
93+
"react-scripts/**/ansi-regex": "^5.0.1",
94+
"react-scripts/**/nth-check": "^2.0.1",
95+
"react-scripts/**/set-value": "^4.0.1",
96+
"react-scripts/**/immer": "^9.0.6",
97+
"react-scripts/**/glob-parent": "^5.1.2",
98+
"react-scripts/**/browserslist": "^4.16.5",
99+
"react-scripts/**/ansi-html": "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz"
100+
}
100101
}

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

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
import React, { Fragment, useEffect, useRef, useState } from "react";
1818
import { connect } from "react-redux";
19+
import {useDropzone} from 'react-dropzone'
20+
1921
import { Theme } from "@mui/material/styles";
2022
import createStyles from "@mui/styles/createStyles";
2123
import withStyles from "@mui/styles/withStyles";
@@ -83,6 +85,7 @@ import withSuspense from "../../../../Common/Components/withSuspense";
8385
import { displayName } from "./utils";
8486
import { DownloadIcon, UploadFolderIcon } from "../../../../../../icons";
8587

88+
8689
const AddFolderIcon = React.lazy(
8790
() => import("../../../../../../icons/AddFolderIcon")
8891
);
@@ -250,6 +253,10 @@ const ListObjects = ({
250253
>("ASC");
251254
const [currentSortField, setCurrentSortField] = useState<string>("name");
252255
const [iniLoad, setIniLoad] = useState<boolean>(false);
256+
257+
258+
259+
253260

254261
const internalPaths = get(match.params, "subpaths", "");
255262
const bucketName = match.params["bucketName"];
@@ -572,29 +579,38 @@ const ListObjects = ({
572579
setCreateFolderOpen(false);
573580
};
574581

575-
const upload = (e: any, bucketName: string, path: string) => {
576-
if (
582+
const handleUploadButton = (e: any) => {
583+
if (
577584
e === null ||
578585
e === undefined ||
579-
e.target === null ||
580-
e.target === undefined
586+
e.target.files === null ||
587+
e.target.files === undefined
581588
) {
582589
return;
583590
}
584591
e.preventDefault();
592+
var newFiles : File[] = [];
585593

586-
let files = e.target.files;
594+
for (var i=0; i<e.target.files.length; i++) {
595+
newFiles.push(e.target.files[i])
587596

597+
}
598+
uploadObject(newFiles, "");
599+
}
600+
601+
const upload = (files: File[], bucketName: string, path: string, folderPath: string) => {
602+
588603
if (files.length > 0) {
589-
for (let file of files) {
604+
for (let file of files) {
590605
let uploadUrl = `api/v1/buckets/${bucketName}/objects/upload`;
591606
const fileName = file.name;
592607
const blobFile = new Blob([file], { type: file.type });
593608

594609
let encodedPath = "";
595-
596-
const relativeFolderPath = get(file, "webkitRelativePath", "");
597-
610+
const relativeFolderPath = get(file, "webkitRelativePath", "") !== ""
611+
? get(file, "webkitRelativePath", "")
612+
: folderPath
613+
598614
if (path !== "" || relativeFolderPath !== "") {
599615
const finalFolderPath = relativeFolderPath
600616
.split("/")
@@ -672,13 +688,14 @@ const ListObjects = ({
672688
};
673689

674690
const formData = new FormData();
675-
formData.append(file.size, blobFile, fileName);
676-
691+
if (file.size !== undefined){
692+
formData.append(file.size.toString(), blobFile, fileName);
693+
677694
xhr.send(formData);
695+
}
678696
}
679697
}
680698

681-
e.target.value = null;
682699
};
683700

684701
const displayParsedDate = (object: BucketObject) => {
@@ -741,15 +758,26 @@ const ListObjects = ({
741758
return;
742759
};
743760

744-
const uploadObject = (e: any): void => {
761+
const uploadObject = (files: File[], folderPath: string): void => {
745762
let pathPrefix = "";
746763
if (internalPaths) {
747764
const decodedPath = decodeFileName(internalPaths);
748765
pathPrefix = decodedPath.endsWith("/") ? decodedPath : decodedPath + "/";
749-
}
750-
upload(e, bucketName, pathPrefix);
766+
}
767+
768+
upload(files, bucketName, pathPrefix, folderPath);
769+
751770
};
752771

772+
const onDrop = React.useCallback(acceptedFiles => {
773+
774+
let newFolderPath: string = acceptedFiles[0].path;
775+
uploadObject(acceptedFiles , newFolderPath);
776+
777+
}, [uploadObject]);
778+
779+
const {getRootProps, getInputProps} = useDropzone({noClick: true, onDrop});
780+
753781
const openPreview = (fileObject: BucketObject) => {
754782
setSelectedPreview(fileObject);
755783
setPreviewOpen(true);
@@ -969,6 +997,8 @@ const ListObjects = ({
969997
}
970998
};
971999

1000+
1001+
9721002
return (
9731003
<React.Fragment>
9741004
{shareFileModalOpen && selectedPreview && (
@@ -1086,7 +1116,7 @@ const ListObjects = ({
10861116
<input
10871117
type="file"
10881118
multiple
1089-
onChange={(e) => uploadObject(e)}
1119+
onChange={handleUploadButton}
10901120
id="file-input"
10911121
style={{ display: "none" }}
10921122
ref={fileUpload}
@@ -1110,11 +1140,19 @@ const ListObjects = ({
11101140
>
11111141
<UploadFolderIcon />
11121142
</BoxIconButton>
1143+
<input
1144+
type="file"
1145+
multiple
1146+
onChange={handleUploadButton}
1147+
id="file-input"
1148+
style={{ display: "none" }}
1149+
ref={folderUpload}
1150+
/>
11131151
</SecureComponent>
11141152
<input
11151153
type="file"
11161154
multiple
1117-
onChange={(e) => uploadObject(e)}
1155+
onChange={handleUploadButton}
11181156
id="file-input"
11191157
style={{ display: "none" }}
11201158
ref={folderUpload}
@@ -1212,6 +1250,8 @@ const ListObjects = ({
12121250
<Grid item xs={12}>
12131251
<br />
12141252
</Grid>
1253+
<div {...getRootProps()}>
1254+
<input {...getInputProps()} />
12151255
<Grid item xs={12} className={classes.tableBlock}>
12161256
<SecureComponent
12171257
scopes={[IAM_SCOPES.S3_LIST_BUCKET]}
@@ -1241,7 +1281,8 @@ const ListObjects = ({
12411281
/>
12421282
</SecureComponent>
12431283
</Grid>
1244-
</PageLayout>
1284+
</div>
1285+
</PageLayout>
12451286
</React.Fragment>
12461287
);
12471288
};

0 commit comments

Comments
 (0)