Skip to content

Commit 4458822

Browse files
committed
Cleanup file upload behavior
1 parent 1cfa410 commit 4458822

File tree

2 files changed

+48
-43
lines changed

2 files changed

+48
-43
lines changed

resources/scripts/components/server/files/UploadButton.tsx

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ export default ({ className }: WithClassname) => {
3535

3636
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
3737
const directory = ServerContext.useStoreState((state) => state.files.directory);
38-
const appendFileUpload = ServerContext.useStoreActions((actions) => actions.files.appendFileUpload);
39-
const removeFileUpload = ServerContext.useStoreActions((actions) => actions.files.removeFileUpload);
38+
const { clearFileUploads, appendFileUpload, removeFileUpload } = ServerContext.useStoreActions(
39+
(actions) => actions.files
40+
);
4041

4142
useEventListener(
4243
'dragenter',
@@ -52,62 +53,57 @@ export default ({ className }: WithClassname) => {
5253

5354
useEventListener('dragexit', () => setVisible(false), { capture: true });
5455

55-
useEffect(() => {
56-
if (!visible) return;
57-
58-
const hide = () => setVisible(false);
59-
60-
window.addEventListener('keydown', hide);
61-
return () => {
62-
window.removeEventListener('keydown', hide);
63-
};
64-
}, [visible]);
56+
useEventListener('keydown', () => {
57+
visible && setVisible(false);
58+
});
6559

6660
useEffect(() => {
6761
return () => timeouts.forEach(clearTimeout);
6862
}, []);
6963

70-
const onFileSubmission = (files: FileList) => {
71-
const formData: FormData[] = [];
64+
const onUploadProgress = (data: ProgressEvent, name: string) => {
65+
appendFileUpload({ name, loaded: data.loaded, total: data.total });
66+
if (data.loaded >= data.total) {
67+
const timeout = setTimeout(() => removeFileUpload(name), 500);
68+
setTimeouts((t) => [...t, timeout]);
69+
}
70+
};
7271

72+
const onFileSubmission = (files: FileList) => {
7373
clearAndAddHttpError();
7474
const list = Array.from(files);
7575
if (list.some((file) => !file.type && file.size % 4096 === 0)) {
7676
return addError('Folder uploads are not supported at this time.', 'Error');
7777
}
7878

79-
Array.from(files).forEach((file) => {
80-
const form = new FormData();
81-
form.append('files', file);
82-
formData.push(form);
83-
});
84-
85-
if (formData.length === 0) {
79+
if (!list.length) {
8680
return;
8781
}
8882

89-
Promise.all(
90-
Array.from(formData).map((f) =>
83+
const uploads = list.map((file) => {
84+
appendFileUpload({ name: file.name, loaded: 0, total: file.size });
85+
return () =>
9186
getFileUploadUrl(uuid).then((url) =>
92-
axios.post(`${url}&directory=${directory}`, f, {
93-
headers: { 'Content-Type': 'multipart/form-data' },
94-
onUploadProgress: (data: ProgressEvent) => {
95-
// @ts-expect-error this is valid
96-
const name = f.getAll('files')[0].name;
97-
98-
appendFileUpload({ name: name, loaded: data.loaded, total: data.total });
99-
100-
if (data.loaded === data.total) {
101-
const timeout = setTimeout(() => removeFileUpload(name), 500);
102-
setTimeouts((t) => [...t, timeout]);
103-
}
104-
},
105-
})
106-
)
107-
)
108-
)
87+
axios.post(
88+
url,
89+
{ files: file },
90+
{
91+
headers: { 'Content-Type': 'multipart/form-data' },
92+
params: { directory },
93+
onUploadProgress: (data) => {
94+
onUploadProgress(data, file.name);
95+
},
96+
}
97+
)
98+
);
99+
});
100+
101+
Promise.all(uploads.map((fn) => fn()))
109102
.then(() => mutate())
110-
.catch(clearAndAddHttpError);
103+
.catch((error) => {
104+
clearFileUploads();
105+
clearAndAddHttpError(error);
106+
});
111107
};
112108

113109
return (

resources/scripts/state/server/files.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export interface ServerFileStore {
1717
appendSelectedFile: Action<ServerFileStore, string>;
1818
removeSelectedFile: Action<ServerFileStore, string>;
1919

20+
clearFileUploads: Action<ServerFileStore>;
2021
appendFileUpload: Action<ServerFileStore, FileUpload>;
2122
removeFileUpload: Action<ServerFileStore, string>;
2223
}
@@ -42,12 +43,20 @@ const files: ServerFileStore = {
4243
state.selectedFiles = state.selectedFiles.filter((f) => f !== payload);
4344
}),
4445

46+
clearFileUploads: action((state) => {
47+
state.uploads = [];
48+
}),
49+
4550
appendFileUpload: action((state, payload) => {
46-
state.uploads = state.uploads.filter((f) => f.name !== payload.name).concat(payload);
51+
if (!state.uploads.some(({ name }) => name === payload.name)) {
52+
state.uploads = [...state.uploads, payload];
53+
} else {
54+
state.uploads = state.uploads.map((file) => (file.name === payload.name ? payload : file));
55+
}
4756
}),
4857

4958
removeFileUpload: action((state, payload) => {
50-
state.uploads = state.uploads.filter((f) => f.name !== payload);
59+
state.uploads = state.uploads.filter(({ name }) => name !== payload);
5160
}),
5261
};
5362

0 commit comments

Comments
 (0)