code quality improvements and improved file error handling
This commit is contained in:
@@ -139,6 +139,10 @@ const SystemConfigFields = () => {
|
||||
name={"softwareUpdate"}
|
||||
selectedFile={values.softwareUpdate}
|
||||
/>
|
||||
<div className="border-b border-gray-600">
|
||||
<p>Reboot</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700 transition w-full max-w-md"
|
||||
|
||||
@@ -14,16 +14,24 @@ const SystemFileUpload = ({ name, selectedFile }: SystemFileUploadProps) => {
|
||||
|
||||
const handleFileUploadClick = () => {
|
||||
if (!selectedFile) return;
|
||||
uploadSettings(selectedFile, {
|
||||
timeoutMs: 30000,
|
||||
fieldName: "upload",
|
||||
});
|
||||
const settings = {
|
||||
file: selectedFile,
|
||||
opts: {
|
||||
timeoutMs: 30000,
|
||||
fieldName: "upload",
|
||||
uploadUrl: "http://192.168.75.11/upload/software-update/2'",
|
||||
},
|
||||
};
|
||||
uploadSettings(settings);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="py-8 w-full">
|
||||
<div className="border-b border-gray-600">
|
||||
<h2>Software Update file upload</h2>
|
||||
</div>
|
||||
<FormGroup>
|
||||
<div className="flex-1 flex justify-end md:w-2/3">
|
||||
<div className="flex-1 flex md:w-2/3 my-5">
|
||||
<input
|
||||
type="file"
|
||||
name="softwareUpdate"
|
||||
|
||||
64
src/components/SettingForms/System/Upload.ts
Normal file
64
src/components/SettingForms/System/Upload.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
// CORS (server missing Access-Control-Allow-* headers)??
|
||||
|
||||
type BlobFileUpload = {
|
||||
file: File | null;
|
||||
opts?: {
|
||||
timeoutMs?: number;
|
||||
fieldName?: string;
|
||||
overrideFileName?: string;
|
||||
uploadUrl: URL | string;
|
||||
};
|
||||
};
|
||||
|
||||
export async function sendBlobFileUpload({
|
||||
file,
|
||||
opts,
|
||||
}: BlobFileUpload): Promise<string> {
|
||||
if (!file) throw new Error("No file supplied");
|
||||
if (!opts?.uploadUrl) throw new Error("No URL supplied");
|
||||
|
||||
if (file?.type !== "text/csv") {
|
||||
throw new Error("This file is not supported, please upload a CSV file.");
|
||||
}
|
||||
const timeoutMs = opts?.timeoutMs ?? 30000;
|
||||
const fieldName = opts?.fieldName ?? "upload";
|
||||
const fileName = opts?.overrideFileName ?? file?.name;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const form = new FormData();
|
||||
|
||||
form.append(fieldName, file, fileName);
|
||||
|
||||
const resp = await fetch(opts?.uploadUrl, {
|
||||
method: "POST",
|
||||
body: form,
|
||||
signal: controller.signal,
|
||||
redirect: "follow",
|
||||
});
|
||||
|
||||
const bodyText = await resp.text();
|
||||
|
||||
if (!resp.ok) {
|
||||
throw new Error(
|
||||
`Upload failed (${resp.status} ${resp.statusText}) from ${opts.uploadUrl} — ${bodyText}`
|
||||
);
|
||||
}
|
||||
return bodyText;
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof DOMException && err.name === "AbortError") {
|
||||
throw new Error(`Timeout uploading to ${opts.uploadUrl}.`);
|
||||
}
|
||||
// In browsers, fetch throws TypeError on network-level failures
|
||||
if (err instanceof TypeError) {
|
||||
throw new Error(
|
||||
`HTTP error uploading to ${opts.uploadUrl}: ${err.message}`
|
||||
);
|
||||
}
|
||||
throw new Error("HTTP method POST is not supported by this URL");
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// CORS (server missing Access-Control-Allow-* headers)??
|
||||
export async function sendBlobFileUpload(
|
||||
file: File,
|
||||
opts?: { timeoutMs?: number; fieldName?: string; overrideFileName?: string }
|
||||
): Promise<string> {
|
||||
const timeoutMs = opts?.timeoutMs ?? 30000;
|
||||
const fieldName = opts?.fieldName ?? "upload";
|
||||
const fileName = opts?.overrideFileName ?? file.name;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
try {
|
||||
const form = new FormData();
|
||||
form.append(fieldName, file, fileName);
|
||||
|
||||
const resp = await fetch("http://192.168.75.11/upload/hotlist-upload/2", {
|
||||
method: "POST",
|
||||
body: form,
|
||||
signal: controller.signal,
|
||||
redirect: "follow",
|
||||
});
|
||||
|
||||
const bodyText = await resp.text();
|
||||
|
||||
if (!resp.ok) {
|
||||
// throw new Error(
|
||||
// `Server returned ${resp.status}: ${resp.statusText}. Details: ${bodyText}`
|
||||
// );
|
||||
return `Server returned ${resp.status}: ${resp.statusText}. Details: ${bodyText}`;
|
||||
}
|
||||
return bodyText;
|
||||
} catch (err: any) {
|
||||
if (err?.name === "AbortError") {
|
||||
return `Timeout uploading to /upload/software-update/2.`;
|
||||
}
|
||||
// In browsers, fetch throws TypeError on network-level failures
|
||||
if (err instanceof TypeError) {
|
||||
return `HTTP error uploading to /upload/software-update/2: ${err.message}`;
|
||||
}
|
||||
return `Unexpected error uploading to /upload/software-update/2: ${
|
||||
err?.message ?? String(err)
|
||||
} ${err?.cause ?? ""}`;
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user