- 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
58 lines
1.5 KiB
TypeScript
58 lines
1.5 KiB
TypeScript
import { useMemo } from "react";
|
|
import type { NodeInfo } from "../api";
|
|
|
|
interface ProjectNodeSelectorProps {
|
|
projectId: string;
|
|
currentNodeId?: string;
|
|
onSelect: (nodeId: string | null) => void;
|
|
nodes: NodeInfo[];
|
|
disabled?: boolean;
|
|
}
|
|
|
|
const STATUS_DOT: Record<NodeInfo["status"], string> = {
|
|
online: "🟢",
|
|
offline: "🔴",
|
|
connecting: "🟡",
|
|
error: "🔴",
|
|
};
|
|
|
|
export function ProjectNodeSelector({
|
|
projectId,
|
|
currentNodeId,
|
|
onSelect,
|
|
nodes,
|
|
disabled = false,
|
|
}: ProjectNodeSelectorProps) {
|
|
const sortedNodes = useMemo(() => {
|
|
return [...nodes].sort((a, b) => a.name.localeCompare(b.name));
|
|
}, [nodes]);
|
|
|
|
const selectedValue = currentNodeId ?? "";
|
|
|
|
return (
|
|
<label className="project-node-selector" htmlFor={`project-node-selector-${projectId}`}>
|
|
<span className="project-node-selector__label">Runtime Node</span>
|
|
<select
|
|
id={`project-node-selector-${projectId}`}
|
|
value={selectedValue}
|
|
onChange={(event) => {
|
|
const value = event.target.value;
|
|
onSelect(value ? value : null);
|
|
}}
|
|
disabled={disabled}
|
|
>
|
|
<option value="">Auto (no assignment)</option>
|
|
{sortedNodes.map((node) => (
|
|
<option
|
|
key={node.id}
|
|
value={node.id}
|
|
className={node.status === "offline" || node.status === "error" ? "project-node-selector__option--dim" : ""}
|
|
>
|
|
{STATUS_DOT[node.status]} {node.name} ({node.type})
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
);
|
|
}
|