website (17 pages + 3 components): - multiplayer/wizard, middleware/wizard+test-wizard, communication - builds/wizard, staff-search, voice, sbom/wizard - foerderantrag, mail/tasks, tools/communication, sbom - compliance/evidence, uni-crawler, brandbook (already done) - CollectionsTab, IngestionTab, RiskHeatmap backend-lehrer (5 files): - letters_api (641 → 2), certificates_api (636 → 2) - alerts_agent/db/models (636 → 3) - llm_gateway/communication_service (614 → 2) - game/database already done in prior batch klausur-service (2 files): - hybrid_vocab_extractor (664 → 2) - klausur-service/frontend: api.ts (620 → 3), EHUploadWizard (591 → 2) voice-service (3 files): - bqas/rag_judge (618 → 3), runner (529 → 2) - enhanced_task_orchestrator (519 → 2) studio-v2 (6 files): - korrektur/[klausurId] (578 → 4), fairness (569 → 2) - AlertsWizard (552 → 2), OnboardingWizard (513 → 2) - korrektur/api.ts (506 → 3), geo-lernwelt (501 → 2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
'use client'
|
|
|
|
import { useMemo } from 'react'
|
|
import { Language } from '@/lib/compliance-i18n'
|
|
import { Risk, RISK_BADGE_COLORS } from './risk-heatmap-types'
|
|
|
|
interface RiskDistributionProps {
|
|
risks: Risk[]
|
|
lang?: Language
|
|
}
|
|
|
|
export function RiskDistribution({ risks, lang = 'de' }: RiskDistributionProps) {
|
|
const stats = useMemo(() => {
|
|
const byLevel: Record<string, number> = { critical: 0, high: 0, medium: 0, low: 0 }
|
|
risks.forEach((r) => {
|
|
byLevel[r.inherent_risk] = (byLevel[r.inherent_risk] || 0) + 1
|
|
})
|
|
return byLevel
|
|
}, [risks])
|
|
|
|
const total = risks.length || 1
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
{['critical', 'high', 'medium', 'low'].map((level) => {
|
|
const count = stats[level]
|
|
const percentage = (count / total) * 100
|
|
|
|
return (
|
|
<div key={level} className="flex items-center gap-2">
|
|
<span className="text-xs text-slate-500 w-16 capitalize">{level}</span>
|
|
<div className="flex-1 h-4 bg-slate-100 rounded overflow-hidden">
|
|
<div
|
|
className={`h-full ${RISK_BADGE_COLORS[level]} transition-all`}
|
|
style={{ width: `${percentage}%` }}
|
|
/>
|
|
</div>
|
|
<span className="text-xs font-medium text-slate-700 w-8 text-right">{count}</span>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|