dc00a4f8f5
Wave 5-1 mypy adoption (D-058 relaxed-first): mypy 2.3.1, [tool.mypy] check_untyped_defs + no_implicit_optional + warn_unused_ignores + warn_redundant_casts + warn_unreachable, no overrides (every dep ships py.typed), files = ai_service + scripts/sandbox-agent.py + tests (not excluded). 215 errors → 0: ~140 fixed at source incl. genuine bugs found by the gate (LLMProvider protocol async-generator shape, SessionStore protocol sync/async mismatch, structured_reply genericity, get_args migrations, sandbox-agent Optional guard honesty, proctor test arg-order, dead ExecResult kwarg, 16 sqlmodel col() sites); 34 live suppressions scoped-coded + reasoned. Original 27 type:ignore dispositioned: 12 dead removed, 15 scoped (warn_unused_ignores self-eliminates the rest). Wired: scripts/typecheck.sh + package.json + turbo task + root ai:typecheck — pnpm typecheck now 5 tsc + mypy. Wave 5-2 recharts 2.15.4 → 3.10.1 (D-049/D-059): one breaking class (Tooltip formatter ValueType typing); 2 one-line inference fixes on the 2 chart files; no rollback needed (well inside the G-106 timebox). Deprecated direct dep resolved; uuid@9 gone from the tree. Build 248/248 with chart SSR markers verified in exported employer + dashboard pages. Wave 5-3 deprecated-transitive audit (G-109): 4 lockfile entries remain, all dev-only, none actionable within NFR budget — glob@7.2.3 + inflight + rimraf@3 via Storybook docgen chain (flat-cache@3); glob@10.5.0 via c8→test-exclude (D-052-binding coverage tool — swapping it is out of budget). Python: no EOL packages; zero-warning regime under filterwarnings=error is the machine-checked proof. Counts: 670 py / 44 web / 64 cli, zero warnings, G-104 allowlist still exactly 2. ---ci--- phase: 5 milestone: v0.7 status: execute ---/ci---
71 lines
1.9 KiB
TypeScript
71 lines
1.9 KiB
TypeScript
'use client';
|
|
|
|
import {
|
|
AreaChart,
|
|
Area,
|
|
XAxis,
|
|
YAxis,
|
|
CartesianGrid,
|
|
Tooltip,
|
|
ResponsiveContainer,
|
|
} from 'recharts';
|
|
import { colors } from '@nextcraft/ui';
|
|
|
|
const DATA = [
|
|
{ week: 'Week 1', mastery: 18 },
|
|
{ week: 'Week 2', mastery: 26 },
|
|
{ week: 'Week 3', mastery: 31 },
|
|
{ week: 'Week 4', mastery: 42 },
|
|
{ week: 'Week 5', mastery: 48 },
|
|
{ week: 'Week 6', mastery: 56 },
|
|
{ week: 'Week 7', mastery: 60 },
|
|
{ week: 'Week 8', mastery: 62 },
|
|
];
|
|
|
|
const tooltipStyle = {
|
|
borderRadius: 8,
|
|
border: `1px solid ${colors.neutral[200]}`,
|
|
fontSize: 12,
|
|
} as const;
|
|
|
|
const axisTick = { fontSize: 12, fill: colors.neutral[500] } as const;
|
|
|
|
export function ProgressGraph() {
|
|
return (
|
|
<div className="h-64 w-full">
|
|
<ResponsiveContainer width="100%" height="100%">
|
|
<AreaChart data={DATA} margin={{ top: 10, right: 16, left: -8, bottom: 0 }}>
|
|
<defs>
|
|
<linearGradient id="masteryFill" x1="0" y1="0" x2="0" y2="1">
|
|
<stop offset="0%" stopColor={colors.primary[500]} stopOpacity={0.35} />
|
|
<stop offset="100%" stopColor={colors.primary[500]} stopOpacity={0} />
|
|
</linearGradient>
|
|
</defs>
|
|
<CartesianGrid strokeDasharray="3 3" stroke={colors.neutral[200]} />
|
|
<XAxis
|
|
dataKey="week"
|
|
tick={axisTick}
|
|
stroke={colors.neutral[300]}
|
|
/>
|
|
<YAxis
|
|
domain={[0, 100]}
|
|
tick={axisTick}
|
|
stroke={colors.neutral[300]}
|
|
tickFormatter={(v) => `${v}%`}
|
|
/>
|
|
<Tooltip
|
|
contentStyle={tooltipStyle}
|
|
formatter={(value) => [`${value}%`, 'Mastery']}
|
|
/>
|
|
<Area
|
|
type="monotone"
|
|
dataKey="mastery"
|
|
stroke={colors.primary[600]}
|
|
strokeWidth={2}
|
|
fill="url(#masteryFill)"
|
|
/>
|
|
</AreaChart>
|
|
</ResponsiveContainer>
|
|
</div>
|
|
);
|
|
} |