feat(canvas): accelerate local previews and harden edge flows
This commit is contained in:
@@ -4,6 +4,7 @@ import type { Edge as RFEdge, Node as RFNode } from "@xyflow/react";
|
||||
import { withResolvedCompareData } from "../canvas-helpers";
|
||||
import {
|
||||
buildGraphSnapshot,
|
||||
pruneCanvasGraphNodeDataOverrides,
|
||||
resolveRenderPreviewInputFromGraph,
|
||||
} from "@/lib/canvas-render-preview";
|
||||
|
||||
@@ -100,6 +101,129 @@ describe("withResolvedCompareData", () => {
|
||||
});
|
||||
|
||||
describe("canvas preview graph helpers", () => {
|
||||
it("treats node data overrides as complete normalized objects when building a graph snapshot", () => {
|
||||
const graph = buildGraphSnapshot(
|
||||
[
|
||||
{
|
||||
id: "image-1",
|
||||
type: "image",
|
||||
data: {
|
||||
url: "https://cdn.example.com/persisted.png",
|
||||
previewUrl: "https://cdn.example.com/persisted-preview.png",
|
||||
label: "Persisted label",
|
||||
},
|
||||
},
|
||||
],
|
||||
[],
|
||||
{
|
||||
nodeDataOverrides: new Map([
|
||||
[
|
||||
"image-1",
|
||||
{
|
||||
url: "https://cdn.example.com/persisted-source.png",
|
||||
previewUrl: "https://cdn.example.com/override-preview.png",
|
||||
},
|
||||
],
|
||||
]),
|
||||
},
|
||||
);
|
||||
|
||||
expect(graph.nodesById.get("image-1")).toMatchObject({
|
||||
data: {
|
||||
url: "https://cdn.example.com/persisted-source.png",
|
||||
previewUrl: "https://cdn.example.com/override-preview.png",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("prunes stale node data overrides for deleted nodes and persisted catch-up", () => {
|
||||
const overrides = pruneCanvasGraphNodeDataOverrides(
|
||||
[
|
||||
{
|
||||
id: "image-1",
|
||||
type: "image",
|
||||
data: {
|
||||
url: "https://cdn.example.com/persisted-source.png",
|
||||
previewUrl: "https://cdn.example.com/persisted-preview.png",
|
||||
label: "Persisted label",
|
||||
},
|
||||
},
|
||||
],
|
||||
new Map([
|
||||
[
|
||||
"image-1",
|
||||
{
|
||||
url: "https://cdn.example.com/persisted-source.png",
|
||||
previewUrl: "https://cdn.example.com/local-preview.png",
|
||||
},
|
||||
],
|
||||
["deleted-node", { previewUrl: "https://cdn.example.com/stale-preview.png" }],
|
||||
]),
|
||||
);
|
||||
|
||||
expect(overrides).toEqual(
|
||||
new Map([
|
||||
[
|
||||
"image-1",
|
||||
{
|
||||
url: "https://cdn.example.com/persisted-source.png",
|
||||
previewUrl: "https://cdn.example.com/local-preview.png",
|
||||
},
|
||||
],
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps already-pruned node data overrides stable", () => {
|
||||
const override = { previewUrl: "https://cdn.example.com/local-preview.png" };
|
||||
const overrides = new Map([["image-1", override]]);
|
||||
|
||||
const nextOverrides = pruneCanvasGraphNodeDataOverrides(
|
||||
[
|
||||
{
|
||||
id: "image-1",
|
||||
type: "image",
|
||||
data: {
|
||||
url: "https://cdn.example.com/persisted-source.png",
|
||||
previewUrl: "https://cdn.example.com/persisted-preview.png",
|
||||
},
|
||||
},
|
||||
],
|
||||
overrides,
|
||||
);
|
||||
|
||||
expect(nextOverrides).toBe(overrides);
|
||||
});
|
||||
|
||||
it("keeps full nested overrides until persisted data fully catches up", () => {
|
||||
const override = {
|
||||
exposure: 0.8,
|
||||
adjustments: {
|
||||
shadows: 12,
|
||||
highlights: -4,
|
||||
},
|
||||
};
|
||||
|
||||
const nextOverrides = pruneCanvasGraphNodeDataOverrides(
|
||||
[
|
||||
{
|
||||
id: "curves-1",
|
||||
type: "curves",
|
||||
data: {
|
||||
exposure: 0.2,
|
||||
adjustments: {
|
||||
shadows: 0,
|
||||
highlights: -4,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
new Map([["curves-1", override]]),
|
||||
);
|
||||
|
||||
expect(nextOverrides).toEqual(new Map([["curves-1", override]]));
|
||||
});
|
||||
|
||||
it("resolves the upstream source and pipeline steps from a graph snapshot", () => {
|
||||
const graph = buildGraphSnapshot(
|
||||
[
|
||||
@@ -139,4 +263,50 @@ describe("canvas preview graph helpers", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("prefers local node data overrides during render preview resolution", () => {
|
||||
const graph = buildGraphSnapshot(
|
||||
[
|
||||
{
|
||||
id: "image-1",
|
||||
type: "image",
|
||||
data: { url: "https://cdn.example.com/persisted-source.png" },
|
||||
},
|
||||
{
|
||||
id: "curves-1",
|
||||
type: "curves",
|
||||
data: { exposure: 0.2 },
|
||||
},
|
||||
{
|
||||
id: "render-1",
|
||||
type: "render",
|
||||
data: {},
|
||||
},
|
||||
],
|
||||
[
|
||||
{ source: "image-1", target: "curves-1" },
|
||||
{ source: "curves-1", target: "render-1" },
|
||||
],
|
||||
{
|
||||
nodeDataOverrides: new Map([
|
||||
["image-1", { url: "https://cdn.example.com/override-source.png" }],
|
||||
["curves-1", { exposure: 0.8 }],
|
||||
]),
|
||||
},
|
||||
);
|
||||
|
||||
const preview = resolveRenderPreviewInputFromGraph({
|
||||
nodeId: "render-1",
|
||||
graph,
|
||||
});
|
||||
|
||||
expect(preview.sourceUrl).toBe("https://cdn.example.com/override-source.png");
|
||||
expect(preview.steps).toEqual([
|
||||
{
|
||||
nodeId: "curves-1",
|
||||
type: "curves",
|
||||
params: { exposure: 0.8 },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user