Browse Source

节点大小处理

feature/071
yun 1 week ago
parent
commit
a74e690ec7
  1. 4
      src/hooks/useCanvasContextMenuActions.tsx
  2. 9
      src/store/execution/__tests__/derivedImageExecutor.test.ts
  3. 9
      src/store/execution/derivedImageExecutor.ts
  4. 24
      src/utils/canvasClipboard.ts

4
src/hooks/useCanvasContextMenuActions.tsx

@ -48,6 +48,7 @@ export function useCanvasContextMenuActions({
const addNode = useWorkflowStore((state) => state.addNode);
const updateNodeData = useWorkflowStore((state) => state.updateNodeData);
const updateMediaNodeData = useWorkflowStore((state) => state.updateMediaNodeData);
const copySelectedNodes = useWorkflowStore((state) => state.copySelectedNodes);
const copyNodesById = useWorkflowStore((state) => state.copyNodesById);
const pasteNodes = useWorkflowStore((state) => state.pasteNodes);
@ -67,9 +68,10 @@ export function useCanvasContextMenuActions({
clearClipboard,
addNode: (type, position) => addNode(type, position),
updateNodeData: (nodeId, data) => updateNodeData(nodeId, data as Partial<WorkflowNodeData>),
updateMediaNodeData: (nodeId, data, dimensions) => updateMediaNodeData(nodeId, data as Partial<WorkflowNodeData>, dimensions),
onError: (message) => showToast(message, "error"),
});
}, [addNode, clearClipboard, clipboard, getCanvasFlowCenter, nodes, pasteNodes, showToast, updateNodeData]);
}, [addNode, clearClipboard, clipboard, getCanvasFlowCenter, nodes, pasteNodes, showToast, updateMediaNodeData, updateNodeData]);
const handleKeyboardPaste = useCallback(() => {
pasteAtPosition();

9
src/store/execution/__tests__/derivedImageExecutor.test.ts

@ -37,6 +37,7 @@ function makeCtx(node: WorkflowNode, images: string[] = ["source.png"]): NodeExe
easeCurve: null,
}),
updateNodeData: vi.fn(),
updateMediaNodeData: vi.fn(),
getFreshNode: vi.fn().mockReturnValue(node),
getEdges: vi.fn().mockReturnValue([]),
getNodes: vi.fn().mockReturnValue([]),
@ -86,13 +87,13 @@ describe("derivedImageExecutor", () => {
expect(createCroppedImageBlob).toHaveBeenCalledWith("source.png", expect.objectContaining({ outputWidth: 100 }));
expect(uploadBlobToGatewayMedia).toHaveBeenCalledWith(blob, "crop.png", "image/png", "image");
expect(ctx.updateNodeData).toHaveBeenCalledWith("derived-1", expect.objectContaining({
expect(ctx.updateMediaNodeData).toHaveBeenCalledWith("derived-1", expect.objectContaining({
image: "https://media.example/crop.png",
previewImage: "https://media.example/crop-thumb.png",
dimensions: { width: 100, height: 80 },
status: "complete",
error: null,
}));
}), { width: 100, height: 80 });
});
it("sets an error when the source image is missing", async () => {
@ -151,10 +152,10 @@ describe("derivedImageExecutor", () => {
expect(loadCropImage).toHaveBeenCalledWith("source.png");
expect(drawImage).toHaveBeenCalledWith(expect.anything(), 0, 20, 20, 20, 0, 0, 20, 20);
expect(ctx.updateNodeData).toHaveBeenCalledWith("derived-1", expect.objectContaining({
expect(ctx.updateMediaNodeData).toHaveBeenCalledWith("derived-1", expect.objectContaining({
image: "https://media.example/grid.png",
dimensions: { width: 20, height: 20 },
status: "complete",
}));
}), { width: 20, height: 20 });
});
});

9
src/store/execution/derivedImageExecutor.ts

@ -130,7 +130,7 @@ export async function executeDerivedImage(ctx: NodeExecutionContext): Promise<vo
const filename = nodeData.filename || `${derivedImage.operation}-${Date.now()}.png`;
const uploaded = await uploadBlobToGatewayMedia(blob, filename, "image/png", "image");
ctx.updateNodeData(ctx.node.id, {
const completePatch = {
image: uploaded.url,
imageRef: undefined,
assetId: undefined,
@ -138,7 +138,12 @@ export async function executeDerivedImage(ctx: NodeExecutionContext): Promise<vo
dimensions,
status: "complete",
error: null,
});
};
if (ctx.updateMediaNodeData) {
ctx.updateMediaNodeData(ctx.node.id, completePatch, dimensions);
} else {
ctx.updateNodeData(ctx.node.id, completePatch);
}
} catch (error) {
const message = error instanceof Error ? error.message : "Image processing failed.";
ctx.updateNodeData(ctx.node.id, {

24
src/utils/canvasClipboard.ts

@ -16,6 +16,11 @@ interface PasteClipboardAtPositionOptions {
clearClipboard: () => void;
addNode: (type: "smartImage" | "smartText", position: XYPosition) => string;
updateNodeData: (nodeId: string, data: Partial<WorkflowNodeData>) => void;
updateMediaNodeData?: (
nodeId: string,
data: Partial<WorkflowNodeData>,
dimensions: { width: number; height: number } | null | undefined
) => void;
onError?: (message: string) => void;
}
@ -28,6 +33,7 @@ export function pasteClipboardAtPosition({
clearClipboard,
addNode,
updateNodeData,
updateMediaNodeData,
onError,
}: PasteClipboardAtPositionOptions): void {
if (clipboard && clipboard.nodes.length > 0) {
@ -60,21 +66,31 @@ export function pasteClipboardAtPosition({
);
if (selectedSmartImageNode) {
updateNodeData(selectedSmartImageNode.id, {
const patch: Partial<WorkflowNodeData> = {
image,
imageRef: undefined,
filename,
dimensions,
});
};
if (updateMediaNodeData) {
updateMediaNodeData(selectedSmartImageNode.id, patch, dimensions);
} else {
updateNodeData(selectedSmartImageNode.id, patch);
}
} else {
const center = getCanvasFlowCenter();
const position = flowPosition ?? { x: center.centerX, y: center.centerY };
const nodeId = addNode("smartImage", { x: position.x - 150, y: position.y - 140 });
updateNodeData(nodeId, {
const patch: Partial<WorkflowNodeData> = {
image,
filename,
dimensions,
});
};
if (updateMediaNodeData) {
updateMediaNodeData(nodeId, patch, dimensions);
} else {
updateNodeData(nodeId, patch);
}
}
};
reader.readAsDataURL(blob);

Loading…
Cancel
Save