import { AlertTriangle, CheckCircle2, GitFork, Layers, Link2, Package } from "lucide-react"
import { useGraph } from "@/services/api/hooks"
import type { GraphNode } from "@/types"
// A read-only diagnostic of how programs/deployments relate — repos (provenance),
// `requires` edges (dependency), and the derived predicates functional?/fresh?.
// Everything is computed server-side from git + config; nothing is stored.
export function GraphPage() {
const { data, isLoading, error } = useGraph()
if (isLoading) {
return
Failed to load graph.
}
const monorepos = data.repos.filter((r) => r.programs.length > 1)
const staleRepos = data.repos.filter((r) => r.fresh === false)
const depEdges = data.edges.filter((e) => e.kind === "deployment")
const unhealthy = data.nodes.filter((n) => !n.functional)
const depended = data.nodes
.filter((n) => n.depended_on_by > 0)
.sort((a, b) => b.depended_on_by - a.depended_on_by)
return (
Relationship Graph
Derived, never stored — repos from git, requires edges, and the{" "}
functional? / fresh? predicates, computed on the fly.
{monorepos.length === 0 && (
No monorepos — every program has its own repo.
)}
{monorepos.map((r) => (
{r.key}
→ {r.programs.join(", ")}
))}
{staleRepos.length > 0 && (
{staleRepos.length} repo(s) not fresh: {staleRepos.map((r) => r.key).join(", ")}
)}
{depEdges.length === 0 ? (
None declared yet — front-end/back-end deps have no encoded edge.
) : (
depEdges.map((e, i) => (
{e.src} requires {e.dst}
{e.bind && → ${e.bind}}
))
)}
{unhealthy.length === 0 ? (
All deployments functional.
) : (
unhealthy.map((n) => (
✗ {n.name}{" "}
unmet: {n.unmet.join(", ")}
))
)}
{depended.length > 0 && (
{depended.map((n: GraphNode) => (
{n.name} ← {n.depended_on_by} dependent(s)
))}
)}
)
}
function Stat({ label, value, sub, tone }: { label: string; value: number; sub?: string; tone?: "ok" | "warn" }) {
const color = tone === "warn" ? "text-amber-400" : tone === "ok" ? "text-green-400" : ""
return (