Files
sentryagent-idp/portal/components/charts/AgentHeatmap.tsx
SentryAgent.ai Developer eea885db04 feat(phase-6): WS3+WS4+WS6 — Analytics, API Tiers, AGNTCY Compliance
WS3 — Advanced Analytics Dashboard:
- DB migration: analytics_events table (tenant_id, date, metric_type, count)
- AnalyticsService: recordEvent (fire-and-forget), getTokenTrend, getAgentActivity, getAgentUsageSummary
- Analytics hooks in OAuth2Service (token_issued) and AgentService (agent_registered/deactivated)
- AnalyticsController + routes/analytics.ts (gated by ANALYTICS_ENABLED flag)
- Portal: TokenTrendChart (recharts LineChart), AgentHeatmap (recharts heatmap), /analytics page

WS4 — API Gateway Tiers:
- DB migration: tenant_tiers table; src/config/tiers.ts (free/pro/enterprise limits)
- TierService: getStatus, initiateUpgrade (Stripe), applyUpgrade; TierLimitError in errors.ts
- tierEnforcement middleware (Redis-backed daily call/token counters; TIER_ENFORCEMENT flag)
- Agent count enforcement in AgentService.create()
- Stripe webhook updated to call TierService.applyUpgrade() on checkout.session.completed
- TierController + routes/tiers.ts; Portal: /settings/tier page with upgrade flow

WS6 — AGNTCY Compliance Certification:
- ComplianceService: generateReport() (Redis-cached 5 min), exportAgentCards()
- Compliance sections: agent-identity (DID + credential expiry checks), audit-trail (Merkle chain)
- ComplianceController updated with getComplianceReport, exportAgentCards handlers
- routes/compliance.ts: new AGNTCY routes (gated by COMPLIANCE_ENABLED flag); SOC2 routes unaffected

QA:
- 28 new unit tests: AnalyticsService (8), TierService (9), ComplianceService (11) — all pass
- 673 total unit tests passing; 0 TypeScript errors across API and portal
- AGNTCY conformance test suite at tests/agntcy-conformance/ (4 protocol tests)
- Portal builds cleanly: 9 routes including /analytics and /settings/tier
- Feature flags verified: ANALYTICS_ENABLED, TIER_ENFORCEMENT, COMPLIANCE_ENABLED

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 02:20:09 +00:00

134 lines
3.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
/**
* AgentHeatmap — Recharts BarChart showing agent activity grouped by day-of-week.
*
* The API returns daily aggregates (no hour granularity), so this component
* aggregates event counts per day-of-week across all agents and renders a
* grouped bar chart (one bar per day, MonSun).
*
* This component is designed to be lazy-loaded via `next/dynamic`. Do NOT
* import it directly from a page; use dynamic(() => import('./AgentHeatmap'))
* so that recharts stays out of the main bundle.
*
* @module components/charts/AgentHeatmap
*/
import React, { useMemo } from 'react';
import {
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
} from 'recharts';
/** A single activity bucket from the API response. */
export interface AgentActivityBucket {
/** The agent's unique identifier. */
agent_id: string;
/** Day-of-week as an integer (0 = Sunday … 6 = Saturday). */
dow: number;
/** Total event count for this agent on this day-of-week. */
count: number;
}
/** Props for the AgentHeatmap component. */
export interface AgentHeatmapProps {
/**
* Array of per-agent, per-day-of-week activity buckets from
* `GET /api/analytics/agents/activity`.
*/
data: AgentActivityBucket[];
}
/** Display labels for days of the week, ordered MonSun (dow 10). */
const DOW_LABELS: Record<number, string> = {
0: 'Sun',
1: 'Mon',
2: 'Tue',
3: 'Wed',
4: 'Thu',
5: 'Fri',
6: 'Sat',
};
/** Ordered day-of-week values for Mon → Sun display. */
const DOW_ORDER = [1, 2, 3, 4, 5, 6, 0];
/** Aggregated count per day-of-week for chart rendering. */
interface DowAggregate {
day: string;
count: number;
}
/**
* Aggregates raw per-agent activity buckets into per-day-of-week totals
* suitable for the bar chart.
*
* @param data - Raw activity buckets from the API
* @returns Array of { day, count } sorted Mon → Sun
*/
function aggregateByDow(data: AgentActivityBucket[]): DowAggregate[] {
const totals: Record<number, number> = {};
for (const dow of DOW_ORDER) {
totals[dow] = 0;
}
for (const bucket of data) {
if (bucket.dow in totals) {
totals[bucket.dow] += bucket.count;
}
}
return DOW_ORDER.map((dow) => ({
day: DOW_LABELS[dow],
count: totals[dow],
}));
}
/**
* Renders a responsive bar chart of agent activity grouped by day-of-week
* using recharts. Data is aggregated across all agents.
*
* @param props - AgentHeatmapProps
* @returns JSX element
*/
export default function AgentHeatmap({
data,
}: AgentHeatmapProps): React.ReactElement {
const chartData = useMemo(() => aggregateByDow(data), [data]);
return (
<ResponsiveContainer width="100%" height={300}>
<BarChart
data={chartData}
margin={{ top: 8, right: 16, left: 0, bottom: 8 }}
>
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" vertical={false} />
<XAxis
dataKey="day"
tick={{ fontSize: 12, fill: '#64748b' }}
tickLine={false}
axisLine={{ stroke: '#cbd5e1' }}
/>
<YAxis
tick={{ fontSize: 12, fill: '#64748b' }}
tickLine={false}
axisLine={false}
allowDecimals={false}
/>
<Tooltip
formatter={(value: number) => [value.toLocaleString(), 'Events']}
contentStyle={{
borderRadius: '8px',
border: '1px solid #e2e8f0',
fontSize: '13px',
}}
/>
<Bar dataKey="count" fill="#6366f1" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
);
}