Files
trustos/frontend/src/components/ScoreTrend.tsx
drjones 463dff883b feat: initial TrustOS platform scaffold
- FastAPI backend: auth, findings, dashboard, attack paths, footprint, AI translator, risk calculator, PDF report generator
- Next.js frontend: Vault dashboard, login, findings table, finding detail with AI coach, digital footprint, reports
- PostgreSQL data model: tenants, users, assets, findings, risk scores, audit reports, attack paths
- Docker Compose + Dockerfiles for all services
- Demo seed data: Acme Corp with 6 findings and 90-day risk score history
- AI Risk Translator (OpenAI/Anthropic) with plain-English business impact
- Role-based access: executive / it_admin / trustos_admin
- Scope-lock engine: authorization required before any assessment

Stage 1-8 complete: Phase 1 Vault Audit product ready
2026-07-05 09:46:08 +00:00

71 lines
2.2 KiB
TypeScript

"use client";
import {
LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip,
ResponsiveContainer, ReferenceLine
} from "recharts";
interface ScoreTrendProps {
data: { date: string; score: number }[];
}
const CustomTooltip = ({ active, payload, label }: any) => {
if (active && payload?.length) {
return (
<div className="bg-vault-dark border border-vault-border rounded-lg px-3 py-2 shadow-xl">
<p className="text-vault-muted text-xs mb-1">{label}</p>
<p className="text-vault-sapphireLight font-bold text-sm">Score: {payload[0].value}</p>
</div>
);
}
return null;
};
export default function ScoreTrend({ data }: ScoreTrendProps) {
// Thin the data to ~30 points for readability
const step = Math.ceil(data.length / 30);
const thinned = data.filter((_, i) => i % step === 0 || i === data.length - 1);
// Format dates to short labels
const formatted = thinned.map(d => ({
...d,
shortDate: d.date.slice(5), // MM-DD
}));
return (
<ResponsiveContainer width="100%" height={180}>
<LineChart data={formatted} margin={{ top: 5, right: 10, left: -20, bottom: 0 }}>
<defs>
<linearGradient id="scoreGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#3b82d4" stopOpacity={0.3} />
<stop offset="95%" stopColor="#3b82d4" stopOpacity={0} />
</linearGradient>
</defs>
<CartesianGrid strokeDasharray="3 3" stroke="#2d3447" />
<XAxis
dataKey="shortDate"
tick={{ fill: "#64748b", fontSize: 10 }}
axisLine={{ stroke: "#2d3447" }}
tickLine={false}
interval="preserveStartEnd"
/>
<YAxis
domain={[0, 100]}
tick={{ fill: "#64748b", fontSize: 10 }}
axisLine={false}
tickLine={false}
/>
<Tooltip content={<CustomTooltip />} />
<ReferenceLine y={75} stroke="#3b82d430" strokeDasharray="4 4" />
<Line
type="monotone"
dataKey="score"
stroke="#3b82d4"
strokeWidth={2}
dot={false}
activeDot={{ r: 5, fill: "#3b82d4", stroke: "#0a0d14", strokeWidth: 2 }}
/>
</LineChart>
</ResponsiveContainer>
);
}