Skip to content

Commit 0eec631

Browse files
committed
feat(showcase-dashboard): D6 rollup counter in AdaptiveStatsBar
1 parent a04896d commit 0eec631

6 files changed

Lines changed: 78 additions & 5 deletions

File tree

showcase/shell-dashboard/src/app/page.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import { BaselineTab } from "@/components/baseline-tab";
2020
import { DiscoveryAuthBanner } from "@/components/discovery-auth-banner";
2121
import type { ParityTier } from "@/components/parity-badge";
2222
import { getDocsStatus } from "@/lib/docs-status";
23-
import type { DepthDistribution } from "@/components/adaptive-stats-bar";
23+
import { resolveCell } from "@/lib/live-status";
24+
import type { DepthDistribution, D6Stats } from "@/components/adaptive-stats-bar";
2425
import catalog from "@/data/catalog.json";
2526
import type { CatalogData } from "@/data/catalog-types";
2627

@@ -171,6 +172,29 @@ export default function Page() {
171172
return dist;
172173
}, [liveStatus]);
173174

175+
// Compute D6 (parity-vs-reference) rollup counts across wired cells.
176+
const d6Stats = useMemo((): D6Stats => {
177+
let green = 0;
178+
let gray = 0;
179+
let red = 0;
180+
for (const cell of catalogData.cells) {
181+
if (cell.status !== "wired" || cell.feature === null) continue;
182+
const state = resolveCell(liveStatus, cell.integration, cell.feature);
183+
switch (state.d6.tone) {
184+
case "green":
185+
green++;
186+
break;
187+
case "red":
188+
red++;
189+
break;
190+
default:
191+
gray++;
192+
break;
193+
}
194+
}
195+
return { green, gray, red };
196+
}, [liveStatus]);
197+
174198
// renderCell callback wrapping UnifiedCell + buildCellModel.
175199
// buildCellModel is the single source of truth for cell state — it handles
176200
// not-supported features, ceiling detection, and chip color derivation.
@@ -259,6 +283,7 @@ export default function Page() {
259283
parityStats={parityStats}
260284
docsStats={docsStats}
261285
depthDistribution={depthDistribution}
286+
d6Stats={d6Stats}
262287
/>
263288
</div>
264289
<FeatureGrid

showcase/shell-dashboard/src/components/__tests__/overlay-selector-integration.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ describe("Overlay selector integration — real UI components", () => {
352352
const { getByTestId, getByText } = render(
353353
<ComposedCell
354354
ctx={ctx}
355-
overlays={overlaySet("links", "depth", "health", "docs", "parity")}
355+
overlays={overlaySet("links", "depth", "health", "docs", "parity", "d6")}
356356
catalogCell={catalogCell}
357357
/>,
358358
);
@@ -370,7 +370,7 @@ describe("Overlay selector integration — real UI components", () => {
370370
// Verify stacking order: links, depth, health, docs
371371
const composedCell = getByTestId("composed-cell");
372372
const children = Array.from(composedCell.children);
373-
expect(children.length).toBe(4); // parity adds no content layer
373+
expect(children.length).toBe(4); // parity and d6 add no content layer
374374

375375
// First child: links (contains "Demo")
376376
expect(children[0]?.textContent).toContain("Demo");

showcase/shell-dashboard/src/components/__tests__/overlay-toggle-bar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function renderBar(
2929
}
3030

3131
describe("OverlayToggleBar", () => {
32-
it("renders all 5 overlay pills", () => {
32+
it("renders all 6 overlay pills", () => {
3333
const { getByTestId } = renderBar();
3434
for (const overlay of ALL_OVERLAYS) {
3535
expect(getByTestId(`overlay-pill-${overlay}`)).toBeTruthy();

showcase/shell-dashboard/src/components/adaptive-stats-bar.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ export interface DepthDistribution {
2020
d0: number;
2121
}
2222

23+
/** D6 (parity-vs-reference) rollup counts. */
24+
export interface D6Stats {
25+
green: number;
26+
gray: number;
27+
red: number;
28+
}
29+
2330
export interface AdaptiveStatsBarProps {
2431
overlays: Set<Overlay>;
2532
catalog: CatalogData;
@@ -31,6 +38,8 @@ export interface AdaptiveStatsBarProps {
3138
docsStats?: { ok: number; missing: number; notFound: number; error: number };
3239
/** Depth distribution across wired cells (computed externally) */
3340
depthDistribution?: DepthDistribution;
41+
/** D6 parity-vs-reference counts (computed externally) */
42+
d6Stats?: D6Stats;
3443
}
3544

3645
/* ------------------------------------------------------------------ */
@@ -243,6 +252,37 @@ function ParitySection({ stats }: { stats: Record<ParityTier, number> }) {
243252
);
244253
}
245254

255+
function D6Section({ stats }: { stats: D6Stats }) {
256+
return (
257+
<div className="flex items-center gap-3">
258+
<span className="flex items-center gap-1">
259+
<Dot color="var(--ok)" />
260+
<MiniStat
261+
value={stats.green}
262+
label="green"
263+
colorClass="text-[var(--ok)]"
264+
/>
265+
</span>
266+
<span className="flex items-center gap-1">
267+
<Dot color="var(--text-muted)" />
268+
<MiniStat
269+
value={stats.gray}
270+
label="gray"
271+
colorClass="text-[var(--text-muted)]"
272+
/>
273+
</span>
274+
<span className="flex items-center gap-1">
275+
<Dot color="var(--danger)" />
276+
<MiniStat
277+
value={stats.red}
278+
label="red"
279+
colorClass="text-[var(--danger)]"
280+
/>
281+
</span>
282+
</div>
283+
);
284+
}
285+
246286
function DocsSection({
247287
stats,
248288
}: {
@@ -281,6 +321,7 @@ export function AdaptiveStatsBar({
281321
parityStats,
282322
docsStats,
283323
depthDistribution,
324+
d6Stats,
284325
}: AdaptiveStatsBarProps) {
285326
const sections: React.ReactNode[] = [];
286327

@@ -311,6 +352,10 @@ export function AdaptiveStatsBar({
311352
sections.push(<DocsSection key="docs" stats={docsStats} />);
312353
}
313354

355+
if (overlays.has("d6") && d6Stats) {
356+
sections.push(<D6Section key="d6" stats={d6Stats} />);
357+
}
358+
314359
return (
315360
<div
316361
data-testid="adaptive-stats-bar"

showcase/shell-dashboard/src/components/overlay-toggle-bar.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const ALL_OVERLAYS: readonly Overlay[] = [
2121
"health",
2222
"parity",
2323
"docs",
24+
"d6",
2425
];
2526

2627
export const PRESETS: readonly OverlayPreset[] = [
@@ -39,6 +40,7 @@ const OVERLAY_LABELS: Record<Overlay, string> = {
3940
health: "Health",
4041
parity: "Parity",
4142
docs: "Docs",
43+
d6: "D6",
4244
};
4345

4446
export interface OverlayToggleBarProps {

showcase/shell-dashboard/src/lib/overlay-types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export type Overlay = "links" | "depth" | "health" | "parity" | "docs";
1+
export type Overlay = "links" | "depth" | "health" | "parity" | "docs" | "d6";
22
export type OverlaySet = Set<Overlay>;
33

44
export const ALL_OVERLAYS: readonly Overlay[] = [
@@ -7,6 +7,7 @@ export const ALL_OVERLAYS: readonly Overlay[] = [
77
"health",
88
"parity",
99
"docs",
10+
"d6",
1011
] as const;
1112

1213
export const DEFAULT_OVERLAYS: readonly Overlay[] = [

0 commit comments

Comments
 (0)