diff --git a/frontend/src/components/GraphView.tsx b/frontend/src/components/GraphView.tsx index 9786566..7c13635 100644 --- a/frontend/src/components/GraphView.tsx +++ b/frontend/src/components/GraphView.tsx @@ -1,6 +1,8 @@ import { useEffect, useMemo, useState, type CSSProperties } from 'react'; import type { PodGraph, PodGraphNode, PodGraphEdge, PodGraphNodeKind } from '@podman/shared'; import { fetchPodGraph } from '../lib/graph.js'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; type Mode = 'risk' | 'learn' | 'all'; @@ -142,193 +144,174 @@ export function GraphView({ podId, onClose }: { podId: string; onClose: () => vo setSelected(null); } + const toggleVariant = (m: Mode) => (mode === m && !selected ? 'default' : 'outline'); + return ( -
- +
+
+ -
-
-
Team memory
-
What PodMan learned · {podId}
-
- -
+
+
+
+

Team memory

+

What PodMan learned · {podId}

+
+ +
-
- - - -
+
+ + + +
- {error && ( -

- Graph error: {error} -

- )} - {!graph && !error && ( -

- Loading graph… -

- )} + {error &&

Graph error: {error}

} + {!graph && !error && ( +

Loading graph…

+ )} - {graph && ( - <> -
-
-
Workflow metrics
- {graph.metrics.map((m) => ( -
-
{m.value}
-
{m.label}
-
{m.detail}
+ {graph && ( + <> +
+
+

+ Workflow metrics +

+ {graph.metrics.map((m) => ( +
+

{m.value}

+

+ {m.label} +

+

{m.detail}

+
+ ))}
- ))} -
-
- - {graph.edges.map((e) => { - const a = nodeById.get(e.source); - const b = nodeById.get(e.target); - if (!a || !b) return null; - const s = EDGE[e.kind]; - return ( - - ); - })} - {graph.nodes.map((n) => ( - setSelected((cur) => (cur === n.id ? null : n.id))} - onKeyDown={(ev) => { - if (ev.key === 'Enter' || ev.key === ' ') { - ev.preventDefault(); - setSelected((cur) => (cur === n.id ? null : n.id)); - } - }} +
+ - - - {n.label} - - + {graph.edges.map((e) => { + const a = nodeById.get(e.source); + const b = nodeById.get(e.target); + if (!a || !b) return null; + const s = EDGE[e.kind]; + return ( + + ); + })} + {graph.nodes.map((n) => ( + setSelected((cur) => (cur === n.id ? null : n.id))} + onKeyDown={(ev) => { + if (ev.key === 'Enter' || ev.key === ' ') { + ev.preventDefault(); + setSelected((cur) => (cur === n.id ? null : n.id)); + } + }} + > + + + {n.label} + + + ))} + +
+ +
+ {sel ? ( + <> +

+ {sel.kind} +

+

{sel.label}

+
+ Status + + {sel.status} + +
+
+ Relationships + {relCount} +
+

+ {sel.summary} +

+ + ) : ( + <> +

+ Continual learning +

+

It learned

+

+ The violet{' '} + + learned_from + {' '} + edges are ownership PodMan retained from accepted interventions — the graph + gets sharper every session. Click any node to trace its relationships. +

+ + )} +
+
+ +
+ {LEGEND.map((l) => ( + + + {l.label} + ))} - -
- -
- {sel ? ( - <> -
{sel.kind}
-
{sel.label}
-
- Status - {sel.status} -
-
- Relationships - {relCount} -
-
{sel.summary}
- - ) : ( - <> -
Continual learning
-
It learned
-
- The violet learned_from edges are ownership - PodMan retained from accepted interventions — the graph gets sharper every - session. Click any node to trace its relationships. -
- - )} -
-
- -
- {LEGEND.map((l) => ( - - - {l.label} - - ))} - - - collides - - - - learned_from - -
- - )} + + + collides + + + + learned_from + +
+ + )} +
+
); }