feat: add treemap and punchcard heatmap to dashboard L1/L2 (#94)
Treemap: rectangle area = transaction volume, color = SLA compliance (green→red). Shows apps at L1, routes at L2. Click navigates deeper. Punchcard heatmap: 7-day rolling weekday x 24-hour grid showing transaction volume and error patterns. Two side-by-side views (transactions + errors) reveal temporal clustering. Backend: new GET /search/stats/punchcard endpoint aggregating stats_1m_all/app by DOW x hour over rolling 7 days. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,8 +15,11 @@ import type { KpiItem, Column } from '@cameleer/design-system';
|
||||
import { useGlobalFilters } from '@cameleer/design-system';
|
||||
import { useRouteMetrics } from '../../api/queries/catalog';
|
||||
import { useExecutionStats, useStatsTimeseries } from '../../api/queries/executions';
|
||||
import { useTimeseriesByApp, useTopErrors, useAllAppSettings } from '../../api/queries/dashboard';
|
||||
import { useTimeseriesByApp, useTopErrors, useAllAppSettings, usePunchcard } from '../../api/queries/dashboard';
|
||||
import type { AppSettings } from '../../api/queries/dashboard';
|
||||
import { Treemap } from './Treemap';
|
||||
import type { TreemapItem } from './Treemap';
|
||||
import { PunchcardHeatmap } from './PunchcardHeatmap';
|
||||
import type { RouteMetrics } from '../../api/types';
|
||||
import {
|
||||
computeHealthDot,
|
||||
@@ -294,6 +297,7 @@ export default function DashboardL1() {
|
||||
const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo);
|
||||
const { data: timeseriesByApp } = useTimeseriesByApp(timeFrom, timeTo);
|
||||
const { data: topErrors } = useTopErrors(timeFrom, timeTo);
|
||||
const { data: punchcardData } = usePunchcard();
|
||||
const { data: allAppSettings } = useAllAppSettings();
|
||||
|
||||
// Build settings lookup map
|
||||
@@ -387,6 +391,12 @@ export default function DashboardL1() {
|
||||
}));
|
||||
}, [timeseriesByApp]);
|
||||
|
||||
// Treemap items: one per app, sized by exchange count, colored by SLA
|
||||
const treemapItems: TreemapItem[] = useMemo(
|
||||
() => appRows.map(r => ({ id: r.appId, label: r.appId, value: r.throughput, slaCompliance: r.slaCompliance })),
|
||||
[appRows],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<div className={styles.refreshIndicator}>
|
||||
@@ -437,6 +447,30 @@ export default function DashboardL1() {
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Treemap: app volume vs SLA compliance */}
|
||||
{treemapItems.length > 0 && (
|
||||
<Card title="Application Volume vs SLA Compliance">
|
||||
<Treemap
|
||||
items={treemapItems}
|
||||
width={800}
|
||||
height={250}
|
||||
onItemClick={(id) => navigate(`/dashboard/${id}`)}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Punchcard heatmaps: transactions and errors by weekday x hour */}
|
||||
{(punchcardData?.length ?? 0) > 0 && (
|
||||
<div className={styles.chartGrid}>
|
||||
<Card title="Transaction Volume (7-day pattern)">
|
||||
<PunchcardHeatmap cells={punchcardData!} mode="transactions" width={380} height={300} />
|
||||
</Card>
|
||||
<Card title="Error Volume (7-day pattern)">
|
||||
<PunchcardHeatmap cells={punchcardData!} mode="errors" width={380} height={300} />
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user