feat: Fertigstellungsgrad für Betrieb-Module im SDK Flow
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 35s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 17s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 35s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 22s
CI / test-python-dsms-gateway (push) Successful in 17s
flow-data.ts: - completion?: number Feld im SDKFlowStep Interface - Completion-Werte für 7 Betrieb-Module (Academy/Training ausgenommen): consent-management: 75%, dsr: 65%, whistleblower: 60%, incidents: 55%, notfallplan: 50%, vendor-compliance: 35%, escalations: 30% - Bewertungsbasis: Frontend-Reifegrad + API-Abdeckung + Backend-Persistenz page.tsx: - completionColor() + completionLabel() Hilfsfunktionen (4-stufige Farbskala) - BetriebOverviewPanel: Übersicht mit Balken + Ø-Wert (erscheint bei Filter=Betrieb) - DetailPanel: Fertigstellungsgrad-Abschnitt ganz oben (Balken + Label) - ReactFlow-Nodes: % + Mini-Fortschrittsbalken im Node-Label - Step-Tabelle: 24px-Fortschrittsbalken-Spalte für alle Steps mit completion Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,13 @@ export interface SDKFlowStep {
|
||||
generates?: string[]
|
||||
isOptional?: boolean
|
||||
url: string
|
||||
|
||||
/**
|
||||
* Fertigstellungsgrad in Prozent (0–100).
|
||||
* Nur für Betrieb-Module gesetzt (außer academy/training).
|
||||
* Berechnung: Frontend-Reifegrad + Backend-Persistenz + API-Abdeckung.
|
||||
*/
|
||||
completion?: number
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -632,6 +639,7 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
|
||||
ragPurpose: 'Art. 15-21 DSGVO Betroffenenrechte',
|
||||
isOptional: false,
|
||||
url: '/sdk/dsr',
|
||||
completion: 65,
|
||||
},
|
||||
{
|
||||
id: 'escalations',
|
||||
@@ -653,6 +661,7 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
|
||||
ragCollections: [],
|
||||
isOptional: false,
|
||||
url: '/sdk/escalations',
|
||||
completion: 30,
|
||||
},
|
||||
{
|
||||
id: 'vendor-compliance',
|
||||
@@ -675,6 +684,7 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
|
||||
ragPurpose: 'AVV-Vorlagen und Pruefkataloge',
|
||||
isOptional: false,
|
||||
url: '/sdk/vendor-compliance',
|
||||
completion: 35,
|
||||
},
|
||||
{
|
||||
id: 'consent-management',
|
||||
@@ -696,6 +706,7 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
|
||||
ragCollections: [],
|
||||
isOptional: false,
|
||||
url: '/sdk/consent-management',
|
||||
completion: 75,
|
||||
},
|
||||
{
|
||||
id: 'notfallplan',
|
||||
@@ -718,6 +729,7 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
|
||||
generates: ['Notfallplan (PDF)'],
|
||||
isOptional: false,
|
||||
url: '/sdk/notfallplan',
|
||||
completion: 50,
|
||||
},
|
||||
{
|
||||
id: 'incidents',
|
||||
@@ -739,6 +751,7 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
|
||||
ragCollections: [],
|
||||
isOptional: false,
|
||||
url: '/sdk/incidents',
|
||||
completion: 55,
|
||||
},
|
||||
{
|
||||
id: 'whistleblower',
|
||||
@@ -760,6 +773,7 @@ export const SDK_FLOW_STEPS: SDKFlowStep[] = [
|
||||
ragCollections: [],
|
||||
isOptional: false,
|
||||
url: '/sdk/whistleblower',
|
||||
completion: 60,
|
||||
},
|
||||
{
|
||||
id: 'academy',
|
||||
|
||||
@@ -77,6 +77,98 @@ function getStepPosition(step: SDKFlowStep): { x: number; y: number } {
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// HELPERS — FERTIGSTELLUNGSGRAD
|
||||
// =============================================================================
|
||||
|
||||
function completionColor(pct: number): string {
|
||||
if (pct >= 70) return '#22c55e' // green
|
||||
if (pct >= 50) return '#84cc16' // lime
|
||||
if (pct >= 35) return '#f59e0b' // amber
|
||||
return '#ef4444' // red
|
||||
}
|
||||
|
||||
function completionLabel(pct: number): string {
|
||||
if (pct >= 70) return 'Fortgeschritten'
|
||||
if (pct >= 50) return 'In Entwicklung'
|
||||
if (pct >= 35) return 'Begonnen'
|
||||
return 'Frühe Phase'
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BETRIEB OVERVIEW PANEL
|
||||
// =============================================================================
|
||||
|
||||
function BetriebOverviewPanel() {
|
||||
const betriebWithCompletion = SDK_FLOW_STEPS.filter(
|
||||
s => s.package === 'betrieb' && s.completion !== undefined
|
||||
).sort((a, b) => (b.completion ?? 0) - (a.completion ?? 0))
|
||||
|
||||
const avg = Math.round(
|
||||
betriebWithCompletion.reduce((sum, s) => sum + (s.completion ?? 0), 0) /
|
||||
betriebWithCompletion.length
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-xl border border-slate-200 shadow-sm p-5">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<h3 className="font-semibold text-slate-800">
|
||||
⚙️ Betrieb — Fertigstellungsgrad
|
||||
</h3>
|
||||
<p className="text-xs text-slate-400 mt-0.5">
|
||||
{betriebWithCompletion.length} Module bewertet · Academy & Training ausgeschlossen
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-2xl font-bold" style={{ color: completionColor(avg) }}>
|
||||
{avg}%
|
||||
</div>
|
||||
<div className="text-xs text-slate-400">Ø Fertigstellung</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{betriebWithCompletion.map(step => {
|
||||
const pct = step.completion ?? 0
|
||||
const color = completionColor(pct)
|
||||
return (
|
||||
<div key={step.id}>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-slate-700">{step.name}</span>
|
||||
<span
|
||||
className="px-1.5 py-0.5 rounded text-[10px] font-medium"
|
||||
style={{ background: color + '22', color }}
|
||||
>
|
||||
{completionLabel(pct)}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-sm font-bold" style={{ color }}>{pct}%</span>
|
||||
</div>
|
||||
<div className="h-2 bg-slate-100 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full transition-all"
|
||||
style={{ width: `${pct}%`, background: color }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 mt-1 text-[10px] text-slate-400">
|
||||
{step.checkpointId && (
|
||||
<span className="bg-red-50 text-red-500 px-1 rounded">{step.checkpointId}</span>
|
||||
)}
|
||||
<span>{step.dbTables.length > 0 ? `DB: ${step.dbTables.length} Tabellen` : 'Kein DB-Backend'}</span>
|
||||
{step.ragCollections.length > 0 && (
|
||||
<span className="text-green-600">RAG: {step.ragCollections.length}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// DETAIL PANEL
|
||||
// =============================================================================
|
||||
@@ -120,6 +212,38 @@ function DetailPanel({
|
||||
</div>
|
||||
|
||||
<div className="p-4 space-y-4">
|
||||
{/* Fertigstellungsgrad */}
|
||||
{step.completion !== undefined && (
|
||||
<div className="bg-slate-50 rounded-lg p-3">
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<span className="text-xs font-semibold text-slate-500 uppercase">
|
||||
Fertigstellungsgrad
|
||||
</span>
|
||||
<span
|
||||
className="text-lg font-bold"
|
||||
style={{ color: completionColor(step.completion) }}
|
||||
>
|
||||
{step.completion}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-2.5 bg-slate-200 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full"
|
||||
style={{
|
||||
width: `${step.completion}%`,
|
||||
background: completionColor(step.completion),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="text-xs mt-1.5 font-medium"
|
||||
style={{ color: completionColor(step.completion) }}
|
||||
>
|
||||
{completionLabel(step.completion)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Beschreibung */}
|
||||
<div>
|
||||
<p className="text-sm text-slate-700 leading-relaxed">{step.description}</p>
|
||||
@@ -359,6 +483,28 @@ export default function SDKFlowPage() {
|
||||
{step.checkpointId || ''}
|
||||
{badge}
|
||||
</div>
|
||||
{step.completion !== undefined && (
|
||||
<div className="mt-1.5 px-1">
|
||||
<div
|
||||
className="flex items-center justify-center gap-1 text-[9px] font-bold mb-0.5"
|
||||
style={{ color: isSelected ? 'rgba(255,255,255,0.9)' : completionColor(step.completion) }}
|
||||
>
|
||||
{step.completion}%
|
||||
</div>
|
||||
<div
|
||||
className="h-1 rounded-full overflow-hidden"
|
||||
style={{ background: isSelected ? 'rgba(255,255,255,0.25)' : 'rgba(0,0,0,0.1)' }}
|
||||
>
|
||||
<div
|
||||
className="h-full rounded-full"
|
||||
style={{
|
||||
width: `${step.completion}%`,
|
||||
background: isSelected ? 'rgba(255,255,255,0.8)' : completionColor(step.completion),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
@@ -771,6 +917,9 @@ export default function SDKFlowPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Betrieb Fertigstellungsgrad Übersicht */}
|
||||
{packageFilter === 'betrieb' && <BetriebOverviewPanel />}
|
||||
|
||||
{/* Step Table (below flow) */}
|
||||
<div className="bg-white rounded-xl border border-slate-200 shadow-sm overflow-hidden">
|
||||
<div className="px-4 py-3 bg-slate-50 border-b">
|
||||
@@ -831,6 +980,29 @@ export default function SDKFlowPage() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{step.completion !== undefined ? (
|
||||
<div className="shrink-0 w-24 mr-2">
|
||||
<div className="flex items-center justify-between mb-0.5">
|
||||
<span
|
||||
className="text-[10px] font-bold"
|
||||
style={{ color: completionColor(step.completion) }}
|
||||
>
|
||||
{step.completion}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-1.5 bg-slate-100 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full rounded-full"
|
||||
style={{
|
||||
width: `${step.completion}%`,
|
||||
background: completionColor(step.completion),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="shrink-0 w-24 mr-2" />
|
||||
)}
|
||||
<span
|
||||
className="px-2 py-0.5 rounded text-[10px] font-medium shrink-0"
|
||||
style={{ background: pkg.color.bg, color: pkg.color.text }}
|
||||
|
||||
Reference in New Issue
Block a user