feat(canvas): Agent引用与局部重绘 - 完善附件预览多图展开并修复取消清理
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,91 @@
|
||||
import { CanvasNodeType, type CanvasNodeData, type CanvasNodeMetadata } from "@/types/canvas";
|
||||
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData, type CanvasNodeMetadata } from "@/types/canvas";
|
||||
|
||||
export function liveImageBatchChildren(root: CanvasNodeData, nodes: CanvasNodeData[]) {
|
||||
if (root.type !== CanvasNodeType.Image) return [];
|
||||
const listed = new Set(root.metadata?.batchChildIds || []);
|
||||
return nodes.filter((node) => node.id !== root.id && (node.metadata?.batchRootId === root.id || listed.has(node.id)));
|
||||
}
|
||||
|
||||
export function retireImageBatchChildren(root: CanvasNodeData, nodes: CanvasNodeData[], connections: CanvasConnection[]) {
|
||||
const children = liveImageBatchChildren(root, nodes);
|
||||
if (!children.length) return { nodes, connections, removedIds: [] as string[] };
|
||||
const removedIds = children.filter((node) => !node.metadata?.content).map((node) => node.id);
|
||||
const removed = new Set(removedIds);
|
||||
const kept = children.filter((node) => Boolean(node.metadata?.content));
|
||||
const nextNodes = nodes
|
||||
.filter((node) => !removed.has(node.id))
|
||||
.map((node) => {
|
||||
if (node.id === root.id) {
|
||||
const metadata = { ...node.metadata, imageBatchExpanded: true };
|
||||
delete metadata.batchChildIds;
|
||||
delete metadata.primaryImageId;
|
||||
delete metadata.batchFailedCount;
|
||||
if (!metadata.content) metadata.status = "idle";
|
||||
return { ...node, metadata };
|
||||
}
|
||||
const index = kept.findIndex((item) => item.id === node.id);
|
||||
if (index < 0) return node;
|
||||
const metadata = { ...node.metadata };
|
||||
delete metadata.batchRootId;
|
||||
return {
|
||||
...node,
|
||||
position: { x: root.position.x - node.width - 48, y: root.position.y + index * (node.height + 24) },
|
||||
metadata,
|
||||
};
|
||||
});
|
||||
return {
|
||||
nodes: nextNodes,
|
||||
connections: connections.filter((connection) => !removed.has(connection.fromNodeId) && !removed.has(connection.toNodeId)),
|
||||
removedIds,
|
||||
};
|
||||
}
|
||||
|
||||
export function cancelIncompleteImageBatch(rootId: string, childIds: string[], nodes: CanvasNodeData[], connections: CanvasConnection[]) {
|
||||
const childIdSet = new Set(childIds);
|
||||
const removedIds = nodes.filter((node) => childIdSet.has(node.id) && !node.metadata?.content).map((node) => node.id);
|
||||
const removed = new Set(removedIds);
|
||||
const nextNodes = nodes
|
||||
.filter((node) => !removed.has(node.id))
|
||||
.map((node) => {
|
||||
if (node.id !== rootId) return node;
|
||||
const remaining = (node.metadata?.batchChildIds || []).filter((id) => !removed.has(id) && nodes.some((item) => item.id === id && item.metadata?.content));
|
||||
const hasContent = Boolean(node.metadata?.content);
|
||||
const metadata = {
|
||||
...node.metadata,
|
||||
batchChildIds: remaining.length ? remaining : undefined,
|
||||
isBatchRoot: remaining.length > 1 ? true : undefined,
|
||||
imageBatchExpanded: remaining.length > 1 ? true : undefined,
|
||||
status: hasContent ? node.metadata?.status : "idle",
|
||||
};
|
||||
if (!hasContent) {
|
||||
delete metadata.errorDetails;
|
||||
delete metadata.generationErrorCode;
|
||||
delete metadata.failedPromptFingerprint;
|
||||
}
|
||||
if (remaining.length <= 1) {
|
||||
delete metadata.batchFailedCount;
|
||||
delete metadata.primaryImageId;
|
||||
delete metadata.isBatchRoot;
|
||||
delete metadata.imageBatchExpanded;
|
||||
delete metadata.batchChildIds;
|
||||
}
|
||||
return { ...node, metadata };
|
||||
});
|
||||
const remainingIds = new Set(
|
||||
nextNodes.find((node) => node.id === rootId)?.metadata?.batchChildIds || [],
|
||||
);
|
||||
const detached = nextNodes.map((node) => {
|
||||
if (!childIdSet.has(node.id) || remainingIds.has(node.id)) return node;
|
||||
const metadata = { ...node.metadata };
|
||||
delete metadata.batchRootId;
|
||||
return { ...node, metadata };
|
||||
});
|
||||
return {
|
||||
nodes: detached,
|
||||
connections: connections.filter((connection) => !removed.has(connection.fromNodeId) && !removed.has(connection.toNodeId)),
|
||||
removedIds,
|
||||
};
|
||||
}
|
||||
|
||||
export function failedImageBatchChildren(root: CanvasNodeData, nodes: CanvasNodeData[]) {
|
||||
if (root.type !== CanvasNodeType.Image || !root.metadata?.isBatchRoot) return [];
|
||||
|
||||
@@ -226,6 +226,14 @@ export function buildOrderedCanvasResourceReferences(nodes: CanvasNodeData[], ac
|
||||
return labelResourceNodes(nodes.filter(isResourceNode), active);
|
||||
}
|
||||
|
||||
export function imageGenerationReferenceConnections(sourceNodeId: string, targetNodeId: string, nodes: CanvasNodeData[], connections: CanvasConnection[], createId: () => string): CanvasConnection[] {
|
||||
if (!sourceNodeId || sourceNodeId === targetNodeId) return [];
|
||||
const existing = new Set(connections.filter((connection) => connection.toNodeId === targetNodeId).map((connection) => connection.fromNodeId));
|
||||
return getMentionResourceNodes(sourceNodeId, nodes, connections)
|
||||
.filter((node) => node.id !== sourceNodeId && node.id !== targetNodeId && !existing.has(node.id))
|
||||
.map((node) => ({ id: createId(), fromNodeId: node.id, toNodeId: targetNodeId }));
|
||||
}
|
||||
|
||||
export function getMentionResourceNodes(nodeId: string, nodes: CanvasNodeData[], connections: CanvasConnection[]) {
|
||||
const configInputs = getConnectedConfigResourceNodes(nodeId, nodes, connections);
|
||||
if (configInputs.length) return configInputs;
|
||||
|
||||
Reference in New Issue
Block a user