Browse Source

Update welcome modal tests and input image storage hashing approach

handoff-20260429-1057
shrimbly 6 months ago
parent
commit
7efa8fe8d3
  1. 8
      src/components/__tests__/QuickstartInitialView.test.tsx
  2. 73
      src/utils/imageStorage.ts

8
src/components/__tests__/QuickstartInitialView.test.tsx

@ -209,7 +209,7 @@ describe("QuickstartInitialView", () => {
expect(twitterLink).toHaveAttribute("rel", "noopener noreferrer");
});
it("should render docs coming soon text (not as a link)", () => {
it("should render docs link", () => {
render(
<QuickstartInitialView
onSelectBlankCanvas={mockOnSelectBlankCanvas}
@ -219,8 +219,10 @@ describe("QuickstartInitialView", () => {
/>
);
expect(screen.getByText("Docs (coming soon)")).toBeInTheDocument();
expect(screen.getByText("Docs (coming soon)").closest("a")).toBeNull();
const docsLink = screen.getByText("Docs").closest("a");
expect(docsLink).toHaveAttribute("href", "https://node-banana-docs.vercel.app/");
expect(docsLink).toHaveAttribute("target", "_blank");
expect(docsLink).toHaveAttribute("rel", "noopener noreferrer");
});
});

73
src/utils/imageStorage.ts

@ -62,13 +62,12 @@ async function externalizeNodeImages(
switch (node.type) {
case "imageInput": {
const d = data as import("@/types").ImageInputNodeData;
if (isBase64DataUrl(d.image)) {
// Skip if already has a valid imageRef (prevents duplicates on re-save after hydration)
if (d.imageRef && isBase64DataUrl(d.image)) {
newData = { ...d, image: null };
} else if (isBase64DataUrl(d.image)) {
const imageId = await saveImageAndGetId(d.image, workflowPath, savedImageIds, "inputs");
newData = {
...d,
image: null,
imageRef: imageId,
};
newData = { ...d, image: null, imageRef: imageId };
} else {
newData = d;
}
@ -83,11 +82,16 @@ async function externalizeNodeImages(
let outputImage = d.outputImage;
// Annotation images are user-created, save to inputs
if (isBase64DataUrl(d.sourceImage)) {
// Skip if already has ref (prevents duplicates on re-save after hydration)
if (d.sourceImageRef && isBase64DataUrl(d.sourceImage)) {
sourceImage = null;
} else if (isBase64DataUrl(d.sourceImage)) {
sourceImageRef = await saveImageAndGetId(d.sourceImage, workflowPath, savedImageIds, "inputs");
sourceImage = null;
}
if (isBase64DataUrl(d.outputImage)) {
if (d.outputImageRef && isBase64DataUrl(d.outputImage)) {
outputImage = null;
} else if (isBase64DataUrl(d.outputImage)) {
outputImageRef = await saveImageAndGetId(d.outputImage, workflowPath, savedImageIds, "inputs");
outputImage = null;
}
@ -106,20 +110,28 @@ async function externalizeNodeImages(
const d = data as import("@/types").NanoBananaNodeData;
let outputImageRef = d.outputImageRef;
let outputImage = d.outputImage;
const inputImageRefs: string[] = [];
let inputImageRefs = d.inputImageRefs ? [...d.inputImageRefs] : [];
const inputImages: string[] = [];
// Handle output image - AI generated, save to generations
if (isBase64DataUrl(d.outputImage)) {
// Skip if already has ref (prevents duplicates on re-save after hydration)
if (d.outputImageRef && isBase64DataUrl(d.outputImage)) {
outputImage = null;
} else if (isBase64DataUrl(d.outputImage)) {
outputImageRef = await saveImageAndGetId(d.outputImage, workflowPath, savedImageIds, "generations");
outputImage = null;
}
// Handle input images array (these come from connected nodes, save to inputs if present)
for (const img of d.inputImages) {
if (isBase64DataUrl(img)) {
// Skip if corresponding inputImageRef already exists
for (let i = 0; i < d.inputImages.length; i++) {
const img = d.inputImages[i];
const existingRef = d.inputImageRefs?.[i];
if (existingRef && isBase64DataUrl(img)) {
inputImages.push(""); // Already has ref, just clear the base64
} else if (isBase64DataUrl(img)) {
const ref = await saveImageAndGetId(img, workflowPath, savedImageIds, "inputs");
inputImageRefs.push(ref);
inputImageRefs[i] = ref;
inputImages.push(""); // Empty placeholder
} else {
inputImages.push(img);
@ -138,14 +150,19 @@ async function externalizeNodeImages(
case "llmGenerate": {
const d = data as import("@/types").LLMGenerateNodeData;
const inputImageRefs: string[] = [];
let inputImageRefs = d.inputImageRefs ? [...d.inputImageRefs] : [];
const inputImages: string[] = [];
// Handle input images array (save to inputs)
for (const img of d.inputImages) {
if (isBase64DataUrl(img)) {
// Skip if corresponding inputImageRef already exists
for (let i = 0; i < d.inputImages.length; i++) {
const img = d.inputImages[i];
const existingRef = d.inputImageRefs?.[i];
if (existingRef && isBase64DataUrl(img)) {
inputImages.push(""); // Already has ref, just clear the base64
} else if (isBase64DataUrl(img)) {
const ref = await saveImageAndGetId(img, workflowPath, savedImageIds, "inputs");
inputImageRefs.push(ref);
inputImageRefs[i] = ref;
inputImages.push(""); // Empty placeholder
} else {
inputImages.push(img);
@ -163,13 +180,12 @@ async function externalizeNodeImages(
case "output": {
const d = data as import("@/types").OutputNodeData;
// Output displays generated content, save to generations
if (isBase64DataUrl(d.image)) {
// Skip if already has ref (prevents duplicates on re-save after hydration)
if (d.imageRef && isBase64DataUrl(d.image)) {
newData = { ...d, image: null };
} else if (isBase64DataUrl(d.image)) {
const imageId = await saveImageAndGetId(d.image, workflowPath, savedImageIds, "generations");
newData = {
...d,
image: null,
imageRef: imageId,
};
newData = { ...d, image: null, imageRef: imageId };
} else {
newData = d;
}
@ -179,13 +195,12 @@ async function externalizeNodeImages(
case "splitGrid": {
const d = data as import("@/types").SplitGridNodeData;
// SplitGrid source is input content, save to inputs
if (isBase64DataUrl(d.sourceImage)) {
// Skip if already has ref (prevents duplicates on re-save after hydration)
if (d.sourceImageRef && isBase64DataUrl(d.sourceImage)) {
newData = { ...d, sourceImage: null };
} else if (isBase64DataUrl(d.sourceImage)) {
const imageId = await saveImageAndGetId(d.sourceImage, workflowPath, savedImageIds, "inputs");
newData = {
...d,
sourceImage: null,
sourceImageRef: imageId,
};
newData = { ...d, sourceImage: null, sourceImageRef: imageId };
} else {
newData = d;
}

Loading…
Cancel
Save