feat(graph): dynamic force-directed Team-memory graph + learning-loop & activity rails
Rebuild the live "Team memory" view so the light/real-data version matches the dark Bauhaus mock and the graph is genuinely DYNAMIC instead of dead static columns. Frontend (frontend/src/components/graph/*, composed into GraphView.tsx): - forceSim.ts: a tiny dependency-free force layout (charge repulsion, link springs, centroid recentering + gentle pull, 2-pass collision, bounds clamp, alpha anneal). No d3-force dependency added — keeps the shared pnpm-lock untouched so CI's frozen-lockfile install and the deploy path are unaffected. - GraphCanvas.tsx: SVG render driven by the sim — draggable + pinnable nodes (double-click to release), curved edges that fan parallel pairs, weight-sized geometric node shapes, fade-in on new nodes/edges, animated learned_from dash, risk-path lighting with the rest dimmed, label collision-avoidance. - MetricsRail / LearningLoop / ActivityStream / SelectedNodePanel / encoding.ts: the mock's rails + stream + detail panel, light shadcn (ToggleGroup, ScrollArea, Badge, Button) on theme tokens; only the SVG is bespoke. - GraphView polls /api/pods/:id/graph every 5s and diffs (positions preserved across refreshes), with a best-effort ws /api/events nudge. A stale selection (node gone across a poll) is dropped so the canvas can't dim entirely. Backend (additive — materializer de-noise untouched): - live.ts: buildLoop() (observe→store→predict→outcome→adapt counts, deepest-recent stage active) and buildActivity() (time-sorted typed feed, same isFilePath / ENGINEER_NOISE / signature de-noise) emitted alongside nodes/edges/metrics. - demo.ts: fallback loop + activity so the panels render on the demo path. - shared/src/graph.ts: additive optional PodGraph.loop / .activity + LearningStage / ActivityEvent types. Verified: pnpm lint + -r typecheck + -r build pass; Playwright on the dev build confirmed force layout (distinct positions, ticks on load under StrictMode), drag, risk-mode dimming (opacity 0.14), selection panel, legend, and no overlaps on both the clean demo and the 31-node live hairball. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import type { PodGraphNode } from '@podman/shared';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { statusColor, VIOLET } from './encoding.js';
|
||||
|
||||
export function SelectedNodePanel({
|
||||
node,
|
||||
relCount,
|
||||
}: {
|
||||
node: PodGraphNode | undefined;
|
||||
relCount: number;
|
||||
}) {
|
||||
if (!node) {
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<p className="mb-2 text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Continual learning
|
||||
</p>
|
||||
<h3 className="mb-2 font-heading text-base font-medium">It learned</h3>
|
||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
||||
The violet{' '}
|
||||
<span className="font-medium" style={{ color: VIOLET }}>
|
||||
learned_from
|
||||
</span>{' '}
|
||||
edges are ownership PodMan retained from accepted interventions — the graph gets sharper
|
||||
every session. Click any node to trace its relationships, or drag to rearrange.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
{node.kind}
|
||||
</p>
|
||||
<h3 className="mb-2 mt-0.5 font-heading text-lg font-medium">{node.label}</h3>
|
||||
<div className="flex items-center justify-between border-b py-1.5 text-sm text-muted-foreground">
|
||||
<span>Status</span>
|
||||
<Badge variant="outline" style={{ color: statusColor(node.status) }}>
|
||||
{node.status}
|
||||
</Badge>
|
||||
</div>
|
||||
<div className="flex items-center justify-between border-b py-1.5 text-sm text-muted-foreground">
|
||||
<span>Relationships</span>
|
||||
<span className="font-medium text-foreground">{relCount}</span>
|
||||
</div>
|
||||
{node.summary && (
|
||||
<p className="mt-2.5 text-sm leading-relaxed text-muted-foreground">{node.summary}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user