Skip to content
This repository was archived by the owner on May 30, 2023. It is now read-only.

Commit 10934cc

Browse files
authored
Merge pull request #227 from daita-technologies/feat/upgrade_limit_upload
feat: upgrade limit upload
2 parents 65d9b99 + ce0b9a4 commit 10934cc

5 files changed

Lines changed: 121 additions & 79 deletions

File tree

package.json

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"@types/react-helmet": "^6.1.5",
5252
"@types/react-router-dom": "^5.1.7",
5353
"@types/react-virtualized": "^9.21.15",
54+
"@types/react-window": "^1.8.5",
5455
"axios": "^0.21.1",
5556
"axios-middleware": "^0.3.1",
5657
"chart.js": "^3.7.1",
@@ -63,6 +64,7 @@
6364
"jszip": "^3.9.1",
6465
"lodash": "^4.17.21",
6566
"moment": "^2.29.2",
67+
"p-limit": "^4.0.0",
6668
"react": "^17.0.2",
6769
"react-chartjs-2": "^4.1.0",
6870
"react-dom": "^17.0.2",
@@ -77,6 +79,7 @@
7779
"react-scripts": "4.0.3",
7880
"react-toastify": "^8.1.0",
7981
"react-virtualized": "^9.22.3",
82+
"react-window": "^1.8.7",
8083
"redux": "^4.1.0",
8184
"redux-devtools-extension": "^2.13.9",
8285
"redux-saga": "^1.1.3",
@@ -105,18 +108,11 @@
105108
"react-app/jest"
106109
]
107110
},
108-
"browserslist": {
109-
"production": [
110-
">0.2%",
111-
"not dead",
112-
"not op_mini all"
113-
],
114-
"development": [
115-
"last 1 chrome version",
116-
"last 1 firefox version",
117-
"last 1 safari version"
118-
]
119-
},
111+
"browserslist": [
112+
">0.2%",
113+
"not dead",
114+
"not op_mini all"
115+
],
120116
"engines": {
121117
"node": ">=14.17.5",
122118
"npm": ">=6.14.14"

src/components/UploadFile/UploadFileItem.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { Box, IconButton, LinearProgress, Typography } from "@mui/material";
1+
import CheckIcon from "@mui/icons-material/Check";
22
import DeleteIcon from "@mui/icons-material/Delete";
33
import FileCopyIcon from "@mui/icons-material/FileCopy";
4-
import CheckIcon from "@mui/icons-material/Check";
4+
import { Box, IconButton, LinearProgress, Typography } from "@mui/material";
55
import { CircularProgressWithLabel, MyButton } from "components";
66
import {
77
ADDED_UPLOAD_FILE_STATUS,
@@ -12,19 +12,18 @@ import {
1212
UPLOADED_UPLOAD_FILE_STATUS,
1313
UPLOADING_UPLOAD_FILE_STATUS,
1414
} from "constants/uploadFile";
15+
import { useSelector } from "react-redux";
16+
import { RootState } from "reduxes";
1517
import { formatBytes } from "utils/general";
1618
import { UploadFileItemProps } from "./type";
1719

18-
const UploadFileItem = function (props: UploadFileItemProps) {
19-
const {
20-
file,
21-
status,
22-
uploadProgress,
23-
onClickDelete,
24-
onClickReplaceUpload,
25-
error,
26-
isUploading,
27-
} = props;
20+
function UploadFileItem(props: UploadFileItemProps) {
21+
const { fileName, onClickDelete, onClickReplaceUpload, isUploading, style } =
22+
props;
23+
24+
const { file, status, error, uploadProgress } = useSelector(
25+
(state: RootState) => state.uploadReducer.files[fileName]
26+
);
2827
const deleteButton = (
2928
<Box>
3029
<IconButton onClick={() => onClickDelete(file.name)} color="error">
@@ -97,6 +96,7 @@ const UploadFileItem = function (props: UploadFileItemProps) {
9796
py={2}
9897
borderBottom="1px solid"
9998
borderColor="text.secondary"
99+
style={{ ...style }}
100100
>
101101
<Box>
102102
<Typography fontWeight="bold">{file.name}</Typography>
@@ -115,6 +115,6 @@ const UploadFileItem = function (props: UploadFileItemProps) {
115115
{returnStatus()}
116116
</Box>
117117
);
118-
};
118+
}
119119

120120
export default UploadFileItem;

src/components/UploadFile/index.tsx

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,21 @@ import {
1616
INVALID_FILE_STATUS,
1717
UPLOADED_UPLOAD_FILE_STATUS,
1818
} from "constants/uploadFile";
19-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
19+
import pLimit from "p-limit";
20+
import {
21+
CSSProperties,
22+
useCallback,
23+
useEffect,
24+
useMemo,
25+
useRef,
26+
useState,
27+
} from "react";
2028
import { useDropzone } from "react-dropzone";
2129
import { useDispatch, useSelector } from "react-redux";
2230
import { toast } from "react-toastify";
31+
import { AutoSizer } from "react-virtualized";
32+
import { FixedSizeList as List } from "react-window";
33+
2334
import { selectorIsAlbumSelectMode } from "reduxes/album/selector";
2435
import {
2536
selectorIsGenerateImagesAugmenting,
@@ -131,6 +142,8 @@ const UploadFile = function (props: UploadFileProps) {
131142
selectorCurrentProjectTotalOriginalImage
132143
);
133144
const [isOpenUploadGuideDialog, setIsOpenUploadGuideDialog] = useState(false);
145+
const [resolutionChecking, setResolutionChecking] = useState(false);
146+
134147
const isDisabledUpload = useMemo(
135148
() =>
136149
isUploadChecking ||
@@ -194,51 +207,59 @@ const UploadFile = function (props: UploadFileProps) {
194207
const formatedFiles = convertArrayToObjectKeyFile(acceptedFiles);
195208
const files = { ...uploadFiles, ...formatedFiles };
196209
dispatch(addFile({ files: formatedFiles }));
197-
210+
setResolutionChecking(true);
211+
const limit = pLimit(3);
198212
if (files && Object.keys(files).length > 0) {
199213
const filesNeedCheck: Array<string> = [];
200-
const listPromiseLoadImages: Promise<LoadImageResult>[] = [];
214+
const listPromiseLoadImage: Promise<LoadImageResult>[] = [];
201215
Object.keys(files).forEach((fileName: string) => {
202216
if (files[fileName].status !== UPLOADED_UPLOAD_FILE_STATUS) {
203217
filesNeedCheck.push(fileName);
204218
if (isImageFile(fileName)) {
205-
listPromiseLoadImages.push(
206-
loadImage(files[fileName].file, fileName)
219+
listPromiseLoadImage.push(
220+
limit(() => loadImage(files[fileName].file, fileName))
207221
);
208222
}
209223
}
210224
});
211-
Promise.all(listPromiseLoadImages).then((values) => {
212-
values.forEach(({ image, fileName }) => {
213-
if (
214-
image.width > LIMIT_IMAGE_WIDTH ||
215-
image.height > LIMIT_IMAGE_HEIGHT
216-
) {
217-
dispatch(
218-
updateFile({
219-
fileName,
220-
updateInfo: {
221-
error: `The image resolution (${image.width} x ${image.height}) exceeds the limit allowed ${LIMIT_IMAGE_WIDTH} x ${LIMIT_IMAGE_HEIGHT}. Please remove it`,
222-
status: INVALID_FILE_STATUS,
223-
},
224-
})
225-
);
226-
227-
const indexOf = filesNeedCheck.indexOf(fileName);
228-
if (indexOf !== -1) {
229-
filesNeedCheck.splice(indexOf, 1);
225+
Promise.all(listPromiseLoadImage)
226+
.then((values) => {
227+
values.forEach(({ image, fileName }) => {
228+
if (
229+
image.width > LIMIT_IMAGE_WIDTH ||
230+
image.height > LIMIT_IMAGE_HEIGHT
231+
) {
232+
dispatch(
233+
updateFile({
234+
fileName,
235+
updateInfo: {
236+
error: `The image resolution (${image.width} x ${image.height}) exceeds the limit allowed ${LIMIT_IMAGE_WIDTH} x ${LIMIT_IMAGE_HEIGHT}. Please remove it`,
237+
status: INVALID_FILE_STATUS,
238+
},
239+
})
240+
);
241+
242+
const indexOf = filesNeedCheck.indexOf(fileName);
243+
if (indexOf !== -1) {
244+
filesNeedCheck.splice(indexOf, 1);
245+
}
230246
}
231-
}
247+
});
248+
setResolutionChecking(false);
249+
250+
dispatch(
251+
checkFileUpload({
252+
idToken: getLocalStorage(ID_TOKEN_NAME) || "",
253+
projectId,
254+
projectName,
255+
listFileName: filesNeedCheck,
256+
})
257+
);
258+
})
259+
.catch(() => {
260+
toast.error("The resolution checking process fails.");
261+
setResolutionChecking(false);
232262
});
233-
dispatch(
234-
checkFileUpload({
235-
idToken: getLocalStorage(ID_TOKEN_NAME) || "",
236-
projectId,
237-
projectName,
238-
listFileName: filesNeedCheck,
239-
})
240-
);
241-
});
242263
}
243264
}
244265
}, []);
@@ -352,23 +373,41 @@ const UploadFile = function (props: UploadFileProps) {
352373
</Typography>
353374
</Box>
354375
);
376+
const listFileName = useMemo(
377+
() => Object.keys(uploadFiles).sort(),
378+
[uploadFiles]
379+
);
380+
381+
// eslint-disable-next-line react/no-unstable-nested-components
382+
function Row({ index, style }: { index: number; style: CSSProperties }) {
383+
return (
384+
<UploadFileItem
385+
fileName={listFileName[index]}
386+
onClickDelete={onDeleteFile}
387+
onClickReplaceUpload={onReplaceUpload}
388+
isUploading={isUploading}
389+
style={style}
390+
/>
391+
);
392+
}
355393

356394
const renderUploadFileContent = () => {
357395
if (uploadFiles && Object.keys(uploadFiles).length > 0) {
358396
return (
359-
<Box sx={{ overflowY: "auto" }} maxHeight={400}>
360-
{Object.keys(uploadFiles).map((fileName: string) => (
361-
<UploadFileItem
362-
key={`upload-file-item-${uploadFiles[fileName].name}`}
363-
file={uploadFiles[fileName].file}
364-
status={uploadFiles[fileName].status}
365-
error={uploadFiles[fileName].error}
366-
uploadProgress={uploadFiles[fileName].uploadProgress}
367-
onClickDelete={onDeleteFile}
368-
onClickReplaceUpload={onReplaceUpload}
369-
isUploading={isUploading}
370-
/>
371-
))}
397+
<Box sx={{ overflowY: "auto" }} height={400}>
398+
<AutoSizer>
399+
{({ height, width }) => (
400+
<List
401+
className="List"
402+
height={height}
403+
width={width}
404+
itemCount={Object.keys(uploadFiles).length}
405+
itemSize={70}
406+
>
407+
{Row}
408+
</List>
409+
)}
410+
</AutoSizer>
372411
</Box>
373412
);
374413
}
@@ -486,6 +525,16 @@ const UploadFile = function (props: UploadFileProps) {
486525
</Typography>
487526
</Box>
488527
)}
528+
{resolutionChecking === true && (
529+
<Box display="flex" alignItems="center">
530+
<Box sx={{ width: "calc(100% - 35px)" }} mr={1} my={1}>
531+
<Box minWidth={35}>
532+
<Typography variant="body2">Resolution checking</Typography>
533+
</Box>
534+
<LinearProgress />
535+
</Box>
536+
</Box>
537+
)}
489538
{!!uploadingFileCount &&
490539
uploadingProgress >= 0 &&
491540
uploadingProgress < 100 && (

src/components/UploadFile/type.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
1-
import React from "react";
1+
import React, { CSSProperties } from "react";
22

33
export interface UploadFileProps {
44
projectId: string;
55
projectName: string;
66
}
77

88
export interface UploadFileItemProps {
9-
key?: string;
10-
file: File;
11-
status: string;
12-
uploadProgress?: number;
9+
fileName: string;
1310
onClickDelete: (fileName: string) => void;
1411
onClickReplaceUpload: (fileName: string) => void;
1512
isUploading: boolean;
16-
error?: string;
13+
style: CSSProperties;
1714
}
1815

1916
export interface UploadFromMenuProps {

src/constants/defaultValues.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export const LATEST_SELECTED_DATA_SOURCE_KEY_NAME =
146146

147147
export const MAX_ALLOW_UPLOAD_IMAGES = 1000;
148148
export const LIMIT_UPLOAD_IMAGE_SIZE = 5000000;
149-
export const MAX_ALLOW_UPLOAD_IMAGES_AT_THE_SAME_TIME = 300;
149+
export const MAX_ALLOW_UPLOAD_IMAGES_AT_THE_SAME_TIME = 1000;
150150

151151
export const ALL_DOWNLOAD_TYPE = "ALL";
152152
export const PREPROCESS_DOWNLOAD_TYPE = "PREPROCESS";

0 commit comments

Comments
 (0)