feat(canvas): enhance multi-image generation to track individual image statuses and prioritize display of the first successful result

This commit is contained in:
HouYunFei
2026-08-06 11:36:37 +08:00
parent de49430976
commit 58719739c7
9 changed files with 78 additions and 34 deletions
+14 -6
View File
@@ -293,8 +293,14 @@ function InfiniteCanvasPage() {
});
setRunningNodeId((current) => (current === runningId ? null : current));
if (!affectedNodeIds.size) return;
setNodes((prev) => prev.map((node) => (affectedNodeIds.has(node.id) && node.metadata?.status === NODE_STATUS_LOADING ? { ...node, metadata: { ...node.metadata, status: NODE_STATUS_IDLE, errorDetails: undefined } } : node)));
}, []);
setNodes((prev) =>
prev.map((node) =>
affectedNodeIds.has(node.id) && node.metadata?.status === NODE_STATUS_LOADING
? { ...node, metadata: { ...node.metadata, status: NODE_STATUS_IDLE, errorDetails: undefined, images: node.metadata.images?.map((image) => (image.status === NODE_STATUS_LOADING ? { ...image, status: NODE_STATUS_ERROR, errorDetails: t("common.requestCanceled") } : image)) } }
: node,
),
);
}, [t]);
const confirmStopGeneration = useCallback(
(nodeId: string) => {
@@ -1454,7 +1460,7 @@ function InfiniteCanvasPage() {
prev.map((node) => {
if (node.id !== nodeId) return node;
const image = node.metadata?.images?.find((item) => item.id === imageId);
if (!image) return node;
if (!image?.content) return node;
const size = fitNodeSize(image.naturalWidth, image.naturalHeight);
return {
...node,
@@ -2063,7 +2069,7 @@ function InfiniteCanvasPage() {
metadata: {
prompt: effectivePrompt,
status: NODE_STATUS_LOADING,
images: [],
images: imageIds.map((id) => ({ id, status: NODE_STATUS_LOADING, content: "", storageKey: "", naturalWidth: 0, naturalHeight: 0, bytes: 0, mimeType: "" })),
...generationMetadata,
},
};
@@ -2119,11 +2125,11 @@ function InfiniteCanvasPage() {
: await requestGeneration({ ...generationConfig, count: "1" }, effectivePrompt, { signal: controller.signal }).then((items) => items[0]);
const uploaded = await uploadImage(image.dataUrl);
const imageSize = fitNodeSize(uploaded.width, uploaded.height, imageConfig.width, imageConfig.height);
const item: CanvasNodeImage = { id: imageId, content: uploaded.url, storageKey: uploaded.storageKey, naturalWidth: uploaded.width, naturalHeight: uploaded.height, bytes: uploaded.bytes, mimeType: uploaded.mimeType };
const item: CanvasNodeImage = { id: imageId, status: NODE_STATUS_SUCCESS, content: uploaded.url, storageKey: uploaded.storageKey, naturalWidth: uploaded.width, naturalHeight: uploaded.height, bytes: uploaded.bytes, mimeType: uploaded.mimeType };
setNodes((prev) =>
prev.map((node) => {
if (node.id !== rootId) return node;
const images = [...(node.metadata?.images || []), item].sort((a, b) => imageIds.indexOf(a.id) - imageIds.indexOf(b.id));
const images = node.metadata?.images?.map((image) => (image.id === imageId ? item : image)) || [];
if (node.metadata?.primaryImageId) return { ...node, metadata: { ...node.metadata, images } };
const center = { x: node.position.x + node.width / 2, y: node.position.y + node.height / 2 };
return {
@@ -2152,6 +2158,7 @@ function InfiniteCanvasPage() {
const errorDetails = error instanceof Error ? error.message : t("canvas.projectPage.generationFailed");
if (!firstError) firstError = errorDetails;
hasFailure = true;
setNodes((prev) => prev.map((node) => (node.id === rootId ? { ...node, metadata: { ...node.metadata, images: node.metadata?.images?.map((image) => (image.id === imageId ? { ...image, status: NODE_STATUS_ERROR, errorDetails } : image)) } } : node)));
}
return false;
}),
@@ -2456,6 +2463,7 @@ function InfiniteCanvasPage() {
const imageSize = fitNodeSize(uploadedImage.width, uploadedImage.height, imageConfig.width, imageConfig.height);
const retryImage: CanvasNodeImage = {
id: node.metadata?.primaryImageId || nanoid(),
status: NODE_STATUS_SUCCESS,
content: uploadedImage.url,
storageKey: uploadedImage.storageKey,
naturalWidth: uploadedImage.width,