fix: prevent possible race condition on upload flows/folders (#4114)
* ✨ (create-file-upload.ts): improve file upload functionality by adding cleanup logic and handling edge cases for resolving file selection * 🐛 (create-file-upload.ts): fix removing input element from the DOM by checking if it is contained in the document body before removal 💡 (create-file-upload.ts): add a comment to clarify the purpose of the setTimeout function for a fallback timeout of 1 minute * ✨ (create-file-upload.ts): change createFileUpload function to be asynchronous to support Promise return type for better handling of file upload operations * 📝 (create-file-upload.ts): improve error handling when removing input element from the DOM 📝 (create-file-upload.ts): remove unnecessary comment about timeout value in the code
This commit is contained in:
parent
8516f31d58
commit
6bad987f38
1 changed files with 45 additions and 20 deletions
|
|
@ -2,34 +2,59 @@ export async function createFileUpload(props?: {
|
|||
accept?: string;
|
||||
multiple?: boolean;
|
||||
}): Promise<File[]> {
|
||||
let lock = false;
|
||||
return new Promise((resolve) => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = props?.accept ?? ".json";
|
||||
input.multiple = props?.multiple ?? true;
|
||||
input.style.display = "none";
|
||||
// add a change event listener to the file input
|
||||
input.onchange = async (e: Event) => {
|
||||
lock = true;
|
||||
resolve(Array.from((e.target as HTMLInputElement).files!));
|
||||
document.body.removeChild(input);
|
||||
|
||||
let isResolved = false;
|
||||
|
||||
const cleanup = () => {
|
||||
// Check if the input element still exists in the DOM before attempting to remove it
|
||||
if (input && document.body.contains(input)) {
|
||||
try {
|
||||
document.body.removeChild(input);
|
||||
} catch (error) {
|
||||
console.warn("Error removing input element:", error);
|
||||
}
|
||||
}
|
||||
window.removeEventListener("focus", handleFocus);
|
||||
};
|
||||
window.addEventListener(
|
||||
"focus",
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
if (!lock) {
|
||||
resolve([]);
|
||||
document.body.removeChild(input);
|
||||
}
|
||||
}, 300);
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
// add the input element to the body to ensure it is part of the DOM
|
||||
|
||||
const handleChange = (e: Event) => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
const files = Array.from((e.target as HTMLInputElement).files!);
|
||||
cleanup();
|
||||
resolve(files);
|
||||
}
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
setTimeout(() => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
cleanup();
|
||||
resolve([]);
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
|
||||
input.addEventListener("change", handleChange);
|
||||
window.addEventListener("focus", handleFocus);
|
||||
|
||||
document.body.appendChild(input);
|
||||
// trigger the file input click event to open the file dialog
|
||||
input.click();
|
||||
|
||||
// Fallback timeout to ensure resolution
|
||||
setTimeout(() => {
|
||||
if (!isResolved) {
|
||||
isResolved = true;
|
||||
cleanup();
|
||||
resolve([]);
|
||||
}
|
||||
}, 60000);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue