feat(FN-3952): expose full mesh state aggregation and fix graph selection b
Exposed full mesh state aggregation via mesh routes with corresponding tests, refined the dependency graph to decouple node selection from opening task details, and documented the new aggregation API. Fusion-Task-Id: FN-3952
This commit is contained in:
@@ -105,8 +105,8 @@ export function GraphTaskNode({
|
||||
data-current-step={isActive && hasValidCurrentStep ? String(task.currentStep) : undefined}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onClick={(event) => {
|
||||
onClick?.(event);
|
||||
onClick={onClick}
|
||||
onDoubleClick={(event) => {
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ describe("DependencyGraph highlighting", () => {
|
||||
expect(screen.getByTestId("graph-task-node-A").className).toContain("graph-task-node--highlighted");
|
||||
});
|
||||
|
||||
it("applies edge dimming/highlighting and preserves click-to-detail", () => {
|
||||
it("applies edge dimming/highlighting and preserves double-click-to-detail", () => {
|
||||
const onOpenDetail = vi.fn();
|
||||
render(<DependencyGraph tasks={tasks} onOpenDetail={onOpenDetail} />);
|
||||
|
||||
@@ -99,7 +99,7 @@ describe("DependencyGraph highlighting", () => {
|
||||
expect(edgeAB?.className.baseVal || edgeAB?.className).toContain("graph-edge--highlighted");
|
||||
expect(edgeCB?.className.baseVal || edgeCB?.className).toContain("graph-edge--highlighted");
|
||||
|
||||
fireEvent.click(screen.getByTestId("task-C"));
|
||||
fireEvent.doubleClick(screen.getByTestId("graph-task-node-C"));
|
||||
expect(onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "C" }));
|
||||
});
|
||||
|
||||
@@ -117,18 +117,33 @@ describe("DependencyGraph", () => {
|
||||
expect(fitToGraph).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clicking a card triggers onOpenDetail exactly once", () => {
|
||||
it("single-clicking a node selects it without opening detail", () => {
|
||||
const onOpenDetail = vi.fn();
|
||||
render(<DependencyGraph tasks={[createTask("A", "in-progress")]} onOpenDetail={onOpenDetail} />);
|
||||
fireEvent.click(screen.getByTestId("task-A"));
|
||||
const node = screen.getByTestId("graph-task-node-A");
|
||||
|
||||
fireEvent.click(node);
|
||||
|
||||
expect(node.className).toContain("graph-node--draggable");
|
||||
expect(onOpenDetail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("double-clicking a node opens detail", () => {
|
||||
const onOpenDetail = vi.fn();
|
||||
render(<DependencyGraph tasks={[createTask("A", "in-progress")]} onOpenDetail={onOpenDetail} />);
|
||||
|
||||
fireEvent.doubleClick(screen.getByTestId("graph-task-node-A"));
|
||||
|
||||
expect(onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "A" }));
|
||||
});
|
||||
|
||||
it("falls back to onOpenTaskDetail when onOpenDetail is not provided", () => {
|
||||
it("double-click falls back to onOpenTaskDetail when onOpenDetail is not provided", () => {
|
||||
const onOpenTaskDetail = vi.fn();
|
||||
render(<DependencyGraph tasks={[createTask("A", "in-progress")]} onOpenTaskDetail={onOpenTaskDetail} />);
|
||||
fireEvent.click(screen.getByTestId("task-A"));
|
||||
|
||||
fireEvent.doubleClick(screen.getByTestId("graph-task-node-A"));
|
||||
|
||||
expect(onOpenTaskDetail).toHaveBeenCalledWith("A");
|
||||
});
|
||||
|
||||
|
||||
@@ -220,18 +220,17 @@ describe("GraphTaskNode", () => {
|
||||
expect(screen.getByTestId("graph-task-node-FN-TEST").hasAttribute("data-current-step")).toBe(false);
|
||||
});
|
||||
|
||||
it("clicking card opens task detail exactly once", () => {
|
||||
it("double-clicking card opens task detail exactly once", () => {
|
||||
const props = createProps(createTask());
|
||||
const { container } = render(<GraphTaskNode {...props} />);
|
||||
|
||||
const card = container.querySelector(".card");
|
||||
expect(card).toBeTruthy();
|
||||
fireEvent.click(card!);
|
||||
const node = screen.getByTestId("graph-task-node-FN-TEST");
|
||||
fireEvent.doubleClick(node);
|
||||
expect(props.onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(props.onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "FN-TEST" }));
|
||||
});
|
||||
|
||||
it("clicking active indicator surface opens task detail", () => {
|
||||
it("single click on active indicator surface does not open task detail", () => {
|
||||
const props = createProps(createTask({ column: "in-progress", status: "executing" }));
|
||||
const { container } = render(<GraphTaskNode {...props} />);
|
||||
|
||||
@@ -239,8 +238,7 @@ describe("GraphTaskNode", () => {
|
||||
expect(indicator).toBeTruthy();
|
||||
fireEvent.click(indicator!);
|
||||
|
||||
expect(props.onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(props.onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "FN-TEST" }));
|
||||
expect(props.onOpenDetail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("applies highlighted class only when requested", () => {
|
||||
|
||||
@@ -67,7 +67,7 @@ describe("dependency graph plugin host integration contract", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByTestId("task-FN-HOST"));
|
||||
fireEvent.doubleClick(screen.getByTestId("graph-task-node-FN-HOST"));
|
||||
expect(openTaskDetail).toHaveBeenCalledTimes(1);
|
||||
expect(openTaskDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "FN-HOST" }));
|
||||
});
|
||||
|
||||
@@ -72,11 +72,11 @@ describe("dependency graph interactions", () => {
|
||||
expect(result.current.pan.y).toBeCloseTo(150, 3);
|
||||
});
|
||||
|
||||
it("clicking a node opens task detail", () => {
|
||||
it("double-clicking a node opens task detail", () => {
|
||||
const onOpenDetail = vi.fn();
|
||||
render(<DependencyGraph tasks={[createTask("A", "in-progress")]} onOpenDetail={onOpenDetail} />);
|
||||
|
||||
fireEvent.click(screen.getByTestId("task-A"));
|
||||
fireEvent.doubleClick(screen.getByTestId("graph-task-node-A"));
|
||||
expect(onOpenDetail).toHaveBeenCalledTimes(1);
|
||||
expect(onOpenDetail).toHaveBeenCalledWith(expect.objectContaining({ id: "A" }));
|
||||
expect(screen.getAllByText(/Executing/).length).toBeGreaterThan(0);
|
||||
|
||||
Reference in New Issue
Block a user