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:
@@ -1,6 +1,6 @@
|
||||
import { useState, useMemo, useCallback, useEffect } from "react";
|
||||
import { Plus, LayoutGrid, Filter, ArrowUpDown, Activity, CheckCircle, AlertCircle, Folder, Inbox } from "lucide-react";
|
||||
import type { ProjectInfo, ProjectHealth } from "../api";
|
||||
import type { ProjectInfo, ProjectHealth, NodeInfo } from "../api";
|
||||
import type { ProjectStatus } from "@fusion/core";
|
||||
import { ProjectCard } from "./ProjectCard";
|
||||
import { ProjectGridSkeleton } from "./ProjectGridSkeleton";
|
||||
@@ -15,6 +15,7 @@ export interface ProjectOverviewProps {
|
||||
onResumeProject: (project: ProjectInfo) => void;
|
||||
onRemoveProject: (project: ProjectInfo) => void;
|
||||
onViewAllProjects?: () => void;
|
||||
nodes?: NodeInfo[];
|
||||
}
|
||||
|
||||
type FilterTab = "all" | "active" | "paused" | "errored";
|
||||
@@ -43,6 +44,7 @@ export function ProjectOverview({
|
||||
onPauseProject,
|
||||
onResumeProject,
|
||||
onRemoveProject,
|
||||
nodes = [],
|
||||
}: ProjectOverviewProps) {
|
||||
const [activeFilter, setActiveFilter] = useState<FilterTab>("all");
|
||||
const [sortBy, setSortBy] = useState<SortOption>("activity");
|
||||
@@ -327,17 +329,21 @@ export function ProjectOverview({
|
||||
|
||||
{/* Project grid */}
|
||||
<div className="project-grid">
|
||||
{sortedProjects.map(({ project, health }) => (
|
||||
<ProjectCard
|
||||
key={project.id}
|
||||
project={project}
|
||||
health={health}
|
||||
onSelect={handleSelectProject}
|
||||
onPause={onPauseProject}
|
||||
onResume={onResumeProject}
|
||||
onRemove={onRemoveProject}
|
||||
/>
|
||||
))}
|
||||
{sortedProjects.map(({ project, health }) => {
|
||||
const projectNode = nodes.find((node) => node.id === project.nodeId);
|
||||
return (
|
||||
<ProjectCard
|
||||
key={project.id}
|
||||
project={project}
|
||||
health={health}
|
||||
node={projectNode}
|
||||
onSelect={handleSelectProject}
|
||||
onPause={onPauseProject}
|
||||
onResume={onResumeProject}
|
||||
onRemove={onRemoveProject}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* No results state */}
|
||||
|
||||
Reference in New Issue
Block a user