Browse Source

线修改

feature/260608
TianYun 1 month ago
parent
commit
9562c66108
  1. 44
      src/components/__tests__/EditableEdge.test.tsx
  2. 17
      src/components/edges/EditableEdge.tsx
  3. 2
      src/components/nodes/GroupNode.tsx

44
src/components/__tests__/EditableEdge.test.tsx

@ -58,6 +58,8 @@ const createDefaultProps = (overrides = {}) => ({
const createDefaultState = (overrides = {}) => ({
edgeStyle: "angular" as const,
nodes: [],
runningNodeIds: new Set<string>(),
currentNodeIds: [] as string[],
...overrides,
});
@ -287,6 +289,23 @@ describe("EditableEdge", () => {
expect(stroke).toContain("-active");
});
it("should show pulse animation when connected to selected node", () => {
mockUseWorkflowStore.mockImplementation((selector) => {
return selector(createDefaultState({
nodes: [{ id: "node-1", selected: true }],
}));
});
const { container } = render(
<TestWrapper>
<EditableEdge {...createDefaultProps()} />
</TestWrapper>
);
const paths = container.querySelectorAll("path");
expect(paths.length).toBeGreaterThan(2);
});
it("should have dimmed opacity when not connected to selected node", () => {
mockUseWorkflowStore.mockImplementation((selector) => {
return selector(createDefaultState({
@ -308,12 +327,33 @@ describe("EditableEdge", () => {
});
describe("Loading Animation", () => {
it("should show pulse animation when target node is loading", () => {
it("should show pulse animation when target node is running", () => {
mockUseWorkflowStore.mockImplementation((selector) => {
return selector(createDefaultState({
nodes: [
{ id: "node-1", type: "prompt", selected: false },
{ id: "node-2", type: "generateVideo", selected: false, data: { status: "idle" } },
],
runningNodeIds: new Set(["node-2"]),
}));
});
const { container } = render(
<TestWrapper>
<EditableEdge {...createDefaultProps()} />
</TestWrapper>
);
const paths = container.querySelectorAll("path");
expect(paths.length).toBeGreaterThan(2);
});
it("should show pulse animation when target node data is loading", () => {
mockUseWorkflowStore.mockImplementation((selector) => {
return selector(createDefaultState({
nodes: [
{ id: "node-1", type: "prompt", selected: false },
{ id: "node-2", type: "nanoBanana", selected: false, data: { status: "loading" } },
{ id: "node-2", type: "generateAudio", selected: false, data: { status: "loading" } },
],
}));
});

17
src/components/edges/EditableEdge.tsx

@ -9,7 +9,7 @@ import {
useReactFlow,
} from "@xyflow/react";
import { useWorkflowStore } from "@/store/workflowStore";
import { NanoBananaNodeData, WorkflowEdgeData } from "@/types";
import { WorkflowEdgeData } from "@/types";
import { getSharedGradientId } from "./SharedEdgeGradients";
interface EdgeData extends WorkflowEdgeData {
@ -65,12 +65,15 @@ export function EditableEdge({
const offsetY = edgeData?.offsetY ?? 0;
const hasPause = edgeData?.hasPause ?? false;
// Narrow selector: only re-renders when target loading status changes
const isTargetLoading = useWorkflowStore((state) => {
// Animate incoming edges for the node-level task state, with node data status as a fallback.
const isTargetRunning = useWorkflowStore((state) => {
if (state.runningNodeIds.has(target) || state.currentNodeIds.includes(target)) {
return true;
}
const targetNode = state.nodes.find((n) => n.id === target);
if (targetNode?.type !== "nanoBanana") return false;
return (targetNode.data as NanoBananaNodeData).status === "loading";
return (targetNode?.data as { status?: unknown } | undefined)?.status === "loading";
});
const shouldAnimateEdge = isConnectedToSelection || isTargetRunning;
// Determine edge color based on handle type (magenta for loop edges, orange if paused)
const edgeColor = useMemo(() => {
@ -233,8 +236,8 @@ export function EditableEdge({
}}
/>
{/* Animated pulse overlay when target is loading */}
{isTargetLoading && (
{/* Animated pulse overlay for selected-node context and running targets */}
{shouldAnimateEdge && (
<>
{/* Outer glow — replaces blur(6px) filter for better perf on Windows */}
<path

2
src/components/nodes/GroupNode.tsx

@ -364,7 +364,7 @@ export function GroupNode({ id, data, selected }: NodeProps<GroupNodeType>) {
type="button"
className={`nodrag nopan flex h-8 w-[96px] shrink-0 items-center justify-center gap-1 rounded px-2 text-[11px] font-medium transition-colors focus:outline-none focus:ring-1 ${isGroupRunning
? "text-red-300 hover:bg-red-500/10 hover:text-red-200 focus:ring-red-500/60"
: "text-emerald-300 hover:bg-emerald-500/10 hover:text-emerald-200 focus:ring-emerald-500/60"
: "text-neutral-100 hover:bg-neutral-700 hover:text-white focus:ring-neutral-500"
}`}
onClick={handleRunGroup}
title={t("group.runWholeGroup")}

Loading…
Cancel
Save