mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix(files): record the source tool in toolChain on Save to Files (#435)
Save to Files posted only the blob, so userFiles.toolChain stayed null and the library showed "Tools Used: None". Thread the producing toolId through /api/v1/files/upload (validated optional field) and store it as a one-element toolChain, matching the pipeline path. Claude-Session: https://claude.ai/code/session_01UvVCMNUBrgpghk8gye5gav
This commit is contained in:
@@ -254,7 +254,16 @@ export async function userFileRoutes(app: FastifyInstance): Promise<void> {
|
|||||||
|
|
||||||
const parts = request.parts();
|
const parts = request.parts();
|
||||||
|
|
||||||
|
// Optional "toolId" field records the tool that produced these files so the
|
||||||
|
// library shows it under "Tools Used". Sent before the file part(s).
|
||||||
|
let sourceToolId: string | null = null;
|
||||||
|
|
||||||
for await (const part of parts) {
|
for await (const part of parts) {
|
||||||
|
if (part.type === "field" && part.fieldname === "toolId") {
|
||||||
|
const value = typeof part.value === "string" ? part.value : "";
|
||||||
|
if (/^[a-z0-9-]{1,40}$/.test(value)) sourceToolId = value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (part.type !== "file") continue;
|
if (part.type !== "file") continue;
|
||||||
|
|
||||||
// Consume the stream into a buffer
|
// Consume the stream into a buffer
|
||||||
@@ -304,7 +313,7 @@ export async function userFileRoutes(app: FastifyInstance): Promise<void> {
|
|||||||
height: isValidImage ? validation.height : null,
|
height: isValidImage ? validation.height : null,
|
||||||
version: 1,
|
version: 1,
|
||||||
parentId: null,
|
parentId: null,
|
||||||
toolChain: null,
|
toolChain: sourceToolId ? [sourceToolId] : null,
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
return reply.status(409).send({ error: "Failed to save file record" });
|
return reply.status(409).send({ error: "Failed to save file record" });
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ export function ReviewPanel({
|
|||||||
const res = await fetch(downloadUrl);
|
const res = await fetch(downloadUrl);
|
||||||
const blob = await res.blob();
|
const blob = await res.blob();
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
// Record which tool produced this file so the library shows it under
|
||||||
|
// "Tools Used" (append before the file so the field is parsed first).
|
||||||
|
if (currentToolId) formData.append("toolId", currentToolId);
|
||||||
formData.append("file", new File([blob], filename, { type: fileType }));
|
formData.append("file", new File([blob], filename, { type: fileType }));
|
||||||
const uploadRes = await fetch("/api/v1/files/upload", {
|
const uploadRes = await fetch("/api/v1/files/upload", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -100,7 +103,7 @@ export function ReviewPanel({
|
|||||||
setSaveStatus("error");
|
setSaveStatus("error");
|
||||||
setTimeout(() => setSaveStatus("idle"), 3000);
|
setTimeout(() => setSaveStatus("idle"), 3000);
|
||||||
}
|
}
|
||||||
}, [downloadUrl, filename, fileType]);
|
}, [downloadUrl, filename, fileType, currentToolId]);
|
||||||
|
|
||||||
const hasBatchStats =
|
const hasBatchStats =
|
||||||
totalCount != null && totalCount > 1 && successCount != null && failedCount != null;
|
totalCount != null && totalCount > 1 && successCount != null && failedCount != null;
|
||||||
|
|||||||
Reference in New Issue
Block a user