adds upload dialog and duplicates
This commit is contained in:
@@ -401,23 +401,40 @@ export async function trails_get_bounding_box(f: (url: RequestInfo | URL, config
|
||||
|
||||
}
|
||||
|
||||
export async function trails_upload(file: File, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch): Promise<TrailFilterValues> {
|
||||
const fd = new FormData()
|
||||
export async function trails_upload(file: File, ignoreDuplicates: boolean = false, onProgress?: (progress: number) => void) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
const fd = new FormData();
|
||||
fd.append("name", file.name);
|
||||
fd.append("file", file);
|
||||
fd.append("ignoreDuplicates", ignoreDuplicates ? "true" : "false")
|
||||
|
||||
fd.append("name", file.name),
|
||||
fd.append("file", file)
|
||||
xhr.open("PUT", "/api/v1/trail/upload", true);
|
||||
|
||||
const r = await f('/api/v1/trail/upload', {
|
||||
method: 'PUT',
|
||||
body: fd
|
||||
})
|
||||
if (!r.ok) {
|
||||
const response = await r.json();
|
||||
throw new APIError(r.status, response.message, response.detail)
|
||||
}
|
||||
xhr.upload.onprogress = function (event) {
|
||||
if (event.lengthComputable) {
|
||||
const percentComplete = (event.loaded / event.total) * 100;
|
||||
onProgress?.(percentComplete)
|
||||
}
|
||||
};
|
||||
|
||||
return await r.json();
|
||||
xhr.onload = async () => {
|
||||
const responseText = xhr.responseText;
|
||||
const response = responseText ? JSON.parse(responseText) : null;
|
||||
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
resolve(response);
|
||||
} else {
|
||||
reject(new APIError(xhr.status, response?.message || "Upload failed", response));
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => {
|
||||
reject(new APIError(xhr.status, xhr.statusText));
|
||||
};
|
||||
|
||||
xhr.send(fd);
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchGPX(trail: { gpx?: string } & Record<string, any>, f: (url: RequestInfo | URL, config?: RequestInit) => Promise<Response> = fetch) {
|
||||
|
||||
57
web/src/lib/stores/upload_store.svelte.ts
Normal file
57
web/src/lib/stores/upload_store.svelte.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { APIError } from "$lib/util/api_util";
|
||||
|
||||
export type Upload = {
|
||||
file: File;
|
||||
status: "enqueued" | "uploading" | "cancelled" | "success" | "error" | "duplicate";
|
||||
error?: string;
|
||||
duplicate?: { id: string, name: string };
|
||||
progress: number;
|
||||
function: (f: File, ignoreDuplicates?: boolean, onProgress?: (p: number) => void) => Promise<unknown>
|
||||
};
|
||||
|
||||
class UploadStore {
|
||||
enqueuedUploads: Upload[] = $state([]);
|
||||
completedUploads: Upload[] = $state([]);
|
||||
uploading: boolean = $state(false);
|
||||
}
|
||||
|
||||
export const uploadStore = new UploadStore();
|
||||
|
||||
|
||||
export async function processUploadQueue(batchSize: number = 3, ignoreDuplicates: boolean = false) {
|
||||
if (uploadStore.uploading) {
|
||||
return;
|
||||
}
|
||||
uploadStore.uploading = true;
|
||||
|
||||
while (uploadStore.enqueuedUploads.length > 0) {
|
||||
const batch = uploadStore.enqueuedUploads.slice(0, batchSize);
|
||||
const uploadPromises: Promise<unknown>[] = [];
|
||||
for (const b of batch) {
|
||||
b.status = "uploading";
|
||||
uploadPromises.push(
|
||||
b.function(b.file, ignoreDuplicates, (p: number) => {
|
||||
b.progress = p
|
||||
})
|
||||
);
|
||||
}
|
||||
const results = await Promise.all(
|
||||
uploadPromises.map((p) => p.catch((e) => e)),
|
||||
);
|
||||
results.forEach((r, i) => {
|
||||
const u = batch[i];
|
||||
if (r instanceof APIError && r.message == "Duplicate trail") {
|
||||
u.status = "duplicate"
|
||||
u.duplicate = { id: r.detail.id, name: r.detail.name };
|
||||
} else if (r instanceof APIError) {
|
||||
u.status = "error"
|
||||
u.error = r.message
|
||||
} else {
|
||||
u.status = "success"
|
||||
}
|
||||
uploadStore.completedUploads.push(u);
|
||||
});
|
||||
uploadStore.enqueuedUploads.splice(0, batchSize)
|
||||
}
|
||||
uploadStore.uploading = false;
|
||||
}
|
||||
Reference in New Issue
Block a user