feat(FN-1081): add dashboard nodes management workflow
- Add node API typings and client methods plus a polling useNodes hook with visibility-triggered refresh - Introduce NodesView with NodeCard, AddNodeModal, and NodeDetailModal to register, inspect, update, health-check, and remove nodes - Wire the Nodes surface into the app shell/header and add project node assignment UI with project card node badges - Add unit coverage for useNodes, NodesView, NodeCard, Header, and ProjectCard behavior, plus node-specific dashboard styling
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { ProjectCard } from "../ProjectCard";
|
||||
import type { RegisteredProject, ProjectHealth } from "@fusion/core";
|
||||
import type { NodeInfo } from "../../api";
|
||||
|
||||
// Mock lucide-react to avoid SVG rendering issues in test env
|
||||
vi.mock("lucide-react", () => ({
|
||||
@@ -41,6 +42,19 @@ function makeHealth(overrides: Partial<ProjectHealth> = {}): ProjectHealth {
|
||||
};
|
||||
}
|
||||
|
||||
function makeNode(overrides: Partial<NodeInfo> = {}): NodeInfo {
|
||||
return {
|
||||
id: "node_001",
|
||||
name: "Build Node",
|
||||
type: "local",
|
||||
status: "online",
|
||||
maxConcurrent: 2,
|
||||
createdAt: "2026-01-01T00:00:00.000Z",
|
||||
updatedAt: "2026-01-01T00:00:00.000Z",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
describe("ProjectCard", () => {
|
||||
@@ -60,6 +74,22 @@ describe("ProjectCard", () => {
|
||||
expect(screen.getByText("/path/to/project")).toBeDefined();
|
||||
});
|
||||
|
||||
it("renders assigned node badge when node is provided", () => {
|
||||
render(
|
||||
<ProjectCard
|
||||
project={makeProject()}
|
||||
health={makeHealth()}
|
||||
node={makeNode({ name: "Remote Worker" })}
|
||||
onSelect={noop}
|
||||
onPause={noop}
|
||||
onResume={noop}
|
||||
onRemove={noop}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText("on: Remote Worker")).toBeDefined();
|
||||
});
|
||||
|
||||
it("truncates long paths", () => {
|
||||
const longPath = "/very/long/path/to/the/project/directory/that/needs/truncation";
|
||||
render(
|
||||
|
||||
Reference in New Issue
Block a user