fix(canvas): 节点复制 - 修复生图副本生成后消失 (#676)
Co-authored-by: tanzui <305375675@.com>
This commit is contained in:
1 parent
4b1ce20d2d
commit
1dfc8ce7ac
5 files changed
+85
-6
No files matched your search
@@ -4,7 +4,7 @@ import { getActiveUserScope, setActiveUserScope } from "../../src/lib/user-scope
|
||||
|
||||
type InstanceHook = (storeName: string, key: string, value: unknown) => Promise<void> | void;
|
||||
|
||||
type Scenario = "image-cleanup" | "scope-cleanup-switch" | "scope-cleanup-late-canvas-reference" | "video-commit-race" | "audio-commit-race" | "canvas-batch-commit-race" | "canvas-multi-output";
|
||||
type Scenario = "image-cleanup" | "scope-cleanup-switch" | "scope-cleanup-late-canvas-reference" | "video-commit-race" | "audio-commit-race" | "canvas-batch-commit-race" | "canvas-multi-output" | "canvas-copy-generation";
|
||||
|
||||
function installStorageHarness() {
|
||||
const originalCreateInstance = localforage.createInstance.bind(localforage);
|
||||
@@ -522,6 +522,57 @@ async function runCanvasBatchCommitRace(multiOutput = false) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 使用真实画布存储和生成持久化入口验证复制流程,不调用供应商或生成付费媒体。 */
|
||||
async function runCanvasCopyGeneration() {
|
||||
const harness = installStorageHarness();
|
||||
const previousScope = getActiveUserScope();
|
||||
try {
|
||||
setActiveUserScope("canvas-copy-generation");
|
||||
const { useCanvasStore, flushCanvasStorePersistence, CANVAS_STORE_KEY } = await import("../../src/stores/canvas/use-canvas-store");
|
||||
const { persistCanvasGenerationEffect } = await import("../../src/services/canvas-generation-consumer");
|
||||
const { isolateCopiedNodeMetadata } = await import("../../src/lib/canvas/canvas-node-copy");
|
||||
const { localForageStorageForScope } = await import("../../src/lib/localforage-storage");
|
||||
const { parseCanvasStorageDocument } = await import("../../src/lib/canvas/canvas-storage-revision");
|
||||
const { CanvasNodeType } = await import("../../src/types/canvas");
|
||||
const projectId = useCanvasStore.getState().createProject("copy generation");
|
||||
const readNodes = async () => {
|
||||
const stored = parseCanvasStorageDocument(await localForageStorageForScope(getActiveUserScope()).getItem(CANVAS_STORE_KEY));
|
||||
return stored.state.projects.find((project) => project.id === projectId)!.nodes;
|
||||
};
|
||||
const initial: import("../../src/types/canvas").CanvasNodeData = {
|
||||
id: "source", type: CanvasNodeType.Image, title: "source", position: { x: 0, y: 0 }, width: 320, height: 240,
|
||||
metadata: { content: "original-image", prompt: "test prompt", status: "success" },
|
||||
};
|
||||
useCanvasStore.getState().updateProject(projectId, { nodes: [initial] });
|
||||
await flushCanvasStorePersistence();
|
||||
const sourceEffect = "attach-node:old-task:source:0";
|
||||
await persistCanvasGenerationEffect({
|
||||
projectId, effectKey: sourceEffect, previousNodes: [initial],
|
||||
nodes: [{ ...initial, metadata: { ...initial.metadata, generationEffectKeys: [sourceEffect] } }],
|
||||
});
|
||||
const source = (await readNodes())[0]!;
|
||||
const copy = { ...source, id: "copy", title: "source_copy1", position: { x: 400, y: 0 }, metadata: isolateCopiedNodeMetadata(source, new Map([["source", "copy"]])) };
|
||||
useCanvasStore.getState().updateProject(projectId, { nodes: [source, copy] });
|
||||
await flushCanvasStorePersistence();
|
||||
const beforeGeneration = await readNodes();
|
||||
if (!beforeGeneration.some((node) => node.id === "copy")) throw new Error("复制节点在普通保存后丢失");
|
||||
|
||||
const pendingNodes = [source, { ...copy, metadata: { ...copy.metadata, status: "loading" as const, taskId: "new-task" } }];
|
||||
useCanvasStore.getState().updateProject(projectId, { nodes: pendingNodes });
|
||||
await flushCanvasStorePersistence();
|
||||
const copyEffect = "attach-node:new-task:copy:0";
|
||||
await persistCanvasGenerationEffect({
|
||||
projectId, effectKey: copyEffect, previousNodes: pendingNodes,
|
||||
nodes: pendingNodes.map((node) => node.id === "copy" ? { ...node, metadata: { ...node.metadata, content: "new-image", status: "success", generationEffectKeys: [copyEffect] } } : node),
|
||||
});
|
||||
await flushCanvasStorePersistence();
|
||||
return { beforeGeneration, restored: await readNodes() };
|
||||
} finally {
|
||||
setActiveUserScope(previousScope);
|
||||
harness.restore();
|
||||
}
|
||||
}
|
||||
|
||||
self.onmessage = async (event: MessageEvent<Scenario>) => {
|
||||
try {
|
||||
const result =
|
||||
@@ -533,9 +584,11 @@ self.onmessage = async (event: MessageEvent<Scenario>) => {
|
||||
? await runScopeCleanupAfterLateCanvasReference()
|
||||
: event.data === "canvas-multi-output"
|
||||
? await runCanvasBatchCommitRace(true)
|
||||
: event.data === "canvas-batch-commit-race"
|
||||
? await runCanvasBatchCommitRace()
|
||||
: await runMediaCommitRace(event.data === "audio-commit-race" ? "audio" : "video");
|
||||
: event.data === "canvas-copy-generation"
|
||||
? await runCanvasCopyGeneration()
|
||||
: event.data === "canvas-batch-commit-race"
|
||||
? await runCanvasBatchCommitRace()
|
||||
: await runMediaCommitRace(event.data === "audio-commit-race" ? "audio" : "video");
|
||||
self.postMessage({ ok: true, result });
|
||||
} catch (error) {
|
||||
self.postMessage({ ok: false, error: error instanceof Error ? `${error.name}: ${error.message}` : String(error) });
|
||||
|
||||
Reference in new issue
Block a user