Skip to content

Commit d1b8da6

Browse files
authored
Merge pull request #1412 from WildMeOrg/1408_bulk_import_image_size_issue
fix a race condition issue
2 parents 218db68 + a525f5e commit d1b8da6

File tree

2 files changed

+73
-46
lines changed

2 files changed

+73
-46
lines changed

frontend/src/pages/BulkImport/BulkImportImageUpload.jsx

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,22 @@ export const BulkImportImageUpload = observer(({ store, renderMode1 }) => {
3434
const theme = useContext(ThemeContext);
3535
const originalBorder = `1px dashed ${theme.primaryColors.primary500}`;
3636
const { data } = useGetSiteSettings();
37-
const maxSize = data?.maximumMediaSizeMegabytes || defaultMaxMediaSize;
37+
const serverMaxSize = data?.maximumMediaSizeMegabytes;
38+
const maxSizeForUI =
39+
serverMaxSize ?? store.maxImageSizeMB ?? defaultMaxMediaSize;
3840
const [isProcessingDrop, setIsProcessingDrop] = useState(false);
3941
const [renderMode, setRenderMode] = useState("grid");
4042
const THUMBNAIL_THRESHOLD = 50;
41-
store.setMaxImageCount(
42-
data?.maximumMediaCountEncounter || defaultMaxMediaCount,
43-
);
43+
useEffect(() => {
44+
if (serverMaxSize != null) {
45+
store.setMaxImageSizeMB(serverMaxSize);
46+
}
47+
const maxCount = data?.maximumMediaCountEncounter ?? defaultMaxMediaCount;
48+
if (maxCount != null) {
49+
store.setMaxImageCount(maxCount);
50+
}
51+
}, [store, serverMaxSize, data?.maximumMediaCountEncounter]);
52+
4453
const currentCount = store.imagePreview.length;
4554

4655
useEffect(() => {
@@ -57,15 +66,15 @@ export const BulkImportImageUpload = observer(({ store, renderMode1 }) => {
5766
const handleDragEnter = (e) => {
5867
e.preventDefault();
5968
e.currentTarget.style.border = "2px dashed #007BFF";
60-
// e.dataTransfer.style.backgroundColor = theme.primaryColors.primary100;
6169
};
6270

6371
useEffect(() => {
6472
const ref = fileInputRef.current;
6573
if (!ref) return;
74+
if (!data) return;
6675

6776
if (!store.flow) {
68-
store.initializeFlow(ref, maxSize);
77+
store.initializeFlow(ref);
6978
} else {
7079
store.flow.assignBrowse(ref);
7180
}
@@ -78,15 +87,15 @@ export const BulkImportImageUpload = observer(({ store, renderMode1 }) => {
7887
return () => {
7988
ref.removeEventListener("change", handleChange);
8089
};
81-
}, [store, maxSize]);
90+
}, [store, data]);
8291

8392
useEffect(() => {
8493
if (store.imagePreview.length > 0) {
8594
store.setImageSectionFileNames(
8695
store.imagePreview.map((preview) => preview.fileName),
8796
);
8897
if (store.filesParsed) {
89-
store.uploadFilteredFiles(maxSize);
98+
store.uploadFilteredFiles();
9099
}
91100
}
92101
}, [store.imagePreview.length, store.filesParsed]);
@@ -118,7 +127,7 @@ export const BulkImportImageUpload = observer(({ store, renderMode1 }) => {
118127
for (let i = 0; i < items.length; i++) {
119128
const item = items[i].webkitGetAsEntry?.();
120129
if (item) {
121-
store.traverseFileTree(item, maxSize);
130+
store.traverseFileTree(item);
122131
} else {
123132
const file = items[i].getAsFile();
124133
if (
@@ -130,7 +139,7 @@ export const BulkImportImageUpload = observer(({ store, renderMode1 }) => {
130139
}
131140
}
132141

133-
store.uploadFilteredFiles(maxSize);
142+
store.uploadFilteredFiles();
134143
};
135144

136145
return (
@@ -146,7 +155,7 @@ export const BulkImportImageUpload = observer(({ store, renderMode1 }) => {
146155
<FormattedMessage
147156
id="BULK_IMPORT_UPLOAD_IMAGE_DESC_PART_1"
148157
values={{
149-
maxSize: maxSize,
158+
maxSize: maxSizeForUI,
150159
maxImageCount: store.maxImageCount,
151160
}}
152161
/>
@@ -288,9 +297,8 @@ export const BulkImportImageUpload = observer(({ store, renderMode1 }) => {
288297
</div>
289298
)}
290299
<div>
291-
{(preview.fileSize / (1024 * 1024)).toFixed(2)} MB
292-
{(preview.fileSize / (1024 * 1024)).toFixed(2) >
293-
maxSize && (
300+
{preview.fileSize / (1024 * 1024) >
301+
store.maxImageSizeMB && (
294302
<div style={{ color: theme.statusColors.red500 }}>
295303
<FormattedMessage id="FILE_SIZE_EXCEEDED" />
296304
</div>

frontend/src/pages/BulkImport/BulkImportStore.js

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {
1313
latlongRule,
1414
parseEncounterDateString,
1515
} from "./BulkImportConstants";
16+
import { defaultMaxMediaSize } from "../../constants/photoUpload.js";
17+
import { toast } from "react-toastify";
1618

1719
dayjs.extend(customParseFormat);
1820
export class BulkImportStore {
@@ -38,6 +40,9 @@ export class BulkImportStore {
3840
_columnsDef = [];
3941
_rawColumns = [];
4042
_maxImageCount = 200;
43+
_maxImageSizeMB = defaultMaxMediaSize;
44+
_rejectedTooLarge = [];
45+
_rejectedToastTimer = null;
4146
_pageSize = 10;
4247
_locationID = [];
4348
_locationIDOptions = [];
@@ -424,6 +429,10 @@ export class BulkImportStore {
424429
return this._maxImageCount;
425430
}
426431

432+
get maxImageSizeMB() {
433+
return this._maxImageSizeMB;
434+
}
435+
427436
get worksheetInfo() {
428437
return this._worksheetInfo;
429438
}
@@ -656,6 +665,10 @@ export class BulkImportStore {
656665
this._maxImageCount = maxImageCount;
657666
}
658667

668+
setMaxImageSizeMB(mb) {
669+
this._maxImageSizeMB = Number(mb) || defaultMaxMediaSize;
670+
}
671+
659672
setLocationIDOptions(options) {
660673
this._locationIDOptions = options;
661674
}
@@ -990,7 +1003,7 @@ export class BulkImportStore {
9901003
this._submissionId = submissionId;
9911004
}
9921005

993-
initializeFlow(fileInputRef, maxSize) {
1006+
initializeFlow(fileInputRef) {
9941007
const submissionId = this._submissionId || uuidv4();
9951008
this._submissionId = submissionId;
9961009
const flowInstance = new Flow({
@@ -1009,16 +1022,15 @@ export class BulkImportStore {
10091022
`${file.name}-${file.size}-${file.lastModified}-${Math.random().toString(36).slice(2)}`;
10101023

10111024
flowInstance.assignBrowse(fileInputRef);
1012-
let rejectedFiles = [];
10131025
let hasShownImageLimitAlert = false;
10141026
flowInstance.on("fileAdded", (file) => {
10151027
const currentCount = this._imagePreview.length;
10161028
const totalCount = currentCount + 1;
1017-
const isTooLarge = file.size > maxSize * 1024 * 1024;
1029+
const maxSizeMB = this._maxImageSizeMB;
1030+
const isTooLarge = file.size > maxSizeMB * 1024 * 1024;
10181031

10191032
if (isTooLarge) {
1020-
const reason = "too large";
1021-
rejectedFiles.push(`${file.name} (${reason})`);
1033+
this._notifyTooLarge(file);
10221034
return false;
10231035
}
10241036

@@ -1115,10 +1127,6 @@ export class BulkImportStore {
11151127
});
11161128

11171129
flowInstance.on("fileError", (file, chunk) => {
1118-
// if (!navigator.onLine) {
1119-
// console.log(`Chunk uploading failed due to no internet connection`, file.name, chunk.offset);
1120-
// return;
1121-
// }
11221130
console.error(`Upload failed: ${file.name}, chunk: ${chunk.offset}`);
11231131
this._imagePreview = this._imagePreview.map((f) =>
11241132
f.fileName === file.name ? { ...f, error: true, progress: 0 } : f,
@@ -1130,6 +1138,27 @@ export class BulkImportStore {
11301138
this._flow = flowInstance;
11311139
}
11321140

1141+
_notifyTooLarge(file) {
1142+
const maxSizeMB = this._maxImageSizeMB;
1143+
this._rejectedTooLarge.push(file.name);
1144+
1145+
if (this._rejectedToastTimer) return;
1146+
1147+
this._rejectedToastTimer = setTimeout(() => {
1148+
const names = this._rejectedTooLarge;
1149+
this._rejectedTooLarge = [];
1150+
this._rejectedToastTimer = null;
1151+
1152+
const firstFew = names.slice(0, 5).join(", ");
1153+
const more = names.length > 5 ? ` (+${names.length - 5} more)` : "";
1154+
1155+
toast.error(
1156+
`Some files exceed the ${maxSizeMB}MB limit: ${firstFew}${more}`,
1157+
{ autoClose: 6000 },
1158+
);
1159+
}, 3000);
1160+
}
1161+
11331162
generateThumbnailsForFirst50() {
11341163
const previews = this._imagePreview;
11351164
if (previews.length > this._imageCountGenerateThumbnail)
@@ -1199,35 +1228,17 @@ export class BulkImportStore {
11991228
});
12001229
}
12011230

1202-
uploadFilteredFiles(maxSize) {
1231+
uploadFilteredFiles() {
12031232
if (!this._flow) {
12041233
console.warn("Flow instance not initialized.");
12051234
return;
12061235
}
1236+
const maxSize = this._maxImageSizeMB;
12071237

12081238
const validFiles = this._flow.files.filter(
12091239
(file) => file.size <= maxSize * 1024 * 1024,
12101240
);
12111241

1212-
const invalidFiles = this._flow.files.filter(
1213-
(file) => file.size > maxSize * 1024 * 1024,
1214-
);
1215-
1216-
if (invalidFiles.length > 0) {
1217-
console.warn(
1218-
`The following files are too large (> ${maxSize} MB) and will not be uploaded:`,
1219-
invalidFiles.map(
1220-
(f) => `${f.name} (${(f.size / 1024 / 1024).toFixed(2)} MB)`,
1221-
),
1222-
);
1223-
alert(
1224-
`The following files are too large (> ${maxSize} MB) and will not be uploaded:\n` +
1225-
invalidFiles
1226-
.map((f) => `${f.name} (${(f.size / 1024 / 1024).toFixed(2)} MB)`)
1227-
.join("\n"),
1228-
);
1229-
}
1230-
12311242
if (validFiles.length === 0) {
12321243
return;
12331244
}
@@ -1329,13 +1340,13 @@ export class BulkImportStore {
13291340
});
13301341
}
13311342

1332-
traverseFileTree(entry, maxSize) {
1343+
traverseFileTree(entry) {
13331344
this._incrementPending();
13341345

13351346
if (entry.isDirectory) {
13361347
const reader = entry.createReader();
13371348
reader.readEntries((entries) => {
1338-
entries.forEach((ent) => this.traverseFileTree(ent, maxSize));
1349+
entries.forEach((ent) => this.traverseFileTree(ent));
13391350
this._decrementPending();
13401351
});
13411352
} else if (entry.isFile) {
@@ -1347,7 +1358,15 @@ export class BulkImportStore {
13471358
// "image/bmp",
13481359
];
13491360
const isValid = supportedTypes.includes(file.type);
1350-
// && file.size <= maxSize * 1024 * 1024;
1361+
1362+
const maxSizeMB = this._maxImageSizeMB;
1363+
const isTooLarge = file.size > maxSizeMB * 1024 * 1024;
1364+
1365+
if (isTooLarge) {
1366+
this._notifyTooLarge({ name: file.name, size: file.size });
1367+
this._decrementPending();
1368+
return;
1369+
}
13511370

13521371
if (isValid && !this._imageSectionFileNames.includes(file.name)) {
13531372
this._collectedValidFiles.push(file);

0 commit comments

Comments
 (0)