This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/admin-v2/components/common/ArchitectureView.tsx
BreakPilot Dev 660295e218 fix(admin-v2): Restore complete admin-v2 application
The admin-v2 application was incomplete in the repository. This commit
restores all missing components:

- Admin pages (76 pages): dashboard, ai, compliance, dsgvo, education,
  infrastructure, communication, development, onboarding, rbac
- SDK pages (45 pages): tom, dsfa, vvt, loeschfristen, einwilligungen,
  vendor-compliance, tom-generator, dsr, and more
- Developer portal (25 pages): API docs, SDK guides, frameworks
- All components, lib files, hooks, and types
- Updated package.json with all dependencies

The issue was caused by incomplete initial repository state - the full
admin-v2 codebase existed in backend/admin-v2 and docs-src/admin-v2
but was never fully synced to the main admin-v2 directory.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-08 23:40:15 -08:00

340 lines
14 KiB
TypeScript

'use client'
/**
* ArchitectureView - Shows backend modules and their connection status
*
* This component helps track which backend modules are connected to the frontend
* during migration and ensures no modules get lost.
*/
import { useState } from 'react'
import Link from 'next/link'
import {
MODULE_REGISTRY,
getModulesByCategory,
getModuleStats,
getCategoryStats,
type BackendModule
} from '@/lib/module-registry'
interface ArchitectureViewProps {
category?: BackendModule['category']
showAllCategories?: boolean
}
const STATUS_CONFIG = {
connected: {
label: 'Verbunden',
color: 'bg-green-100 text-green-700 border-green-200',
dot: 'bg-green-500'
},
partial: {
label: 'Teilweise',
color: 'bg-yellow-100 text-yellow-700 border-yellow-200',
dot: 'bg-yellow-500'
},
'not-connected': {
label: 'Nicht verbunden',
color: 'bg-red-100 text-red-700 border-red-200',
dot: 'bg-red-500'
},
deprecated: {
label: 'Veraltet',
color: 'bg-slate-100 text-slate-700 border-slate-200',
dot: 'bg-slate-500'
}
}
const PRIORITY_CONFIG = {
critical: { label: 'Kritisch', color: 'text-red-600' },
high: { label: 'Hoch', color: 'text-orange-600' },
medium: { label: 'Mittel', color: 'text-yellow-600' },
low: { label: 'Niedrig', color: 'text-slate-600' }
}
const CATEGORY_CONFIG: Record<BackendModule['category'], { name: string; icon: string; color: string }> = {
compliance: { name: 'DSGVO & Compliance', icon: 'shield', color: 'purple' },
ai: { name: 'KI & Automatisierung', icon: 'brain', color: 'teal' },
infrastructure: { name: 'Infrastruktur & DevOps', icon: 'server', color: 'orange' },
education: { name: 'Bildung & Schule', icon: 'graduation', color: 'blue' },
communication: { name: 'Kommunikation & Alerts', icon: 'mail', color: 'green' },
development: { name: 'Entwicklung & Produkte', icon: 'code', color: 'slate' }
}
export function ArchitectureView({ category, showAllCategories = false }: ArchitectureViewProps) {
const [expandedModule, setExpandedModule] = useState<string | null>(null)
const [filterStatus, setFilterStatus] = useState<string>('all')
const modules = category && !showAllCategories
? getModulesByCategory(category)
: MODULE_REGISTRY
const filteredModules = filterStatus === 'all'
? modules
: modules.filter(m => m.frontend.status === filterStatus)
const stats = category && !showAllCategories
? getCategoryStats(category)
: getModuleStats()
return (
<div className="space-y-6">
{/* Stats Overview */}
<div className="bg-white rounded-xl shadow-sm border p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-slate-900">
Migrations-Fortschritt
{category && !showAllCategories && (
<span className="ml-2 text-slate-500 font-normal">
- {CATEGORY_CONFIG[category].name}
</span>
)}
</h2>
<span className="text-2xl font-bold text-purple-600">
{stats.percentComplete}%
</span>
</div>
{/* Progress Bar */}
<div className="h-4 bg-slate-200 rounded-full overflow-hidden mb-4">
<div
className="h-full bg-gradient-to-r from-green-500 to-emerald-500 transition-all duration-500"
style={{ width: `${stats.percentComplete}%` }}
/>
</div>
{/* Status Counts */}
<div className="grid grid-cols-4 gap-4">
<div className="text-center">
<div className="text-2xl font-bold text-green-600">{stats.connected}</div>
<div className="text-sm text-slate-500">Verbunden</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-yellow-600">{stats.partial}</div>
<div className="text-sm text-slate-500">Teilweise</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-red-600">{stats.notConnected}</div>
<div className="text-sm text-slate-500">Nicht verbunden</div>
</div>
<div className="text-center">
<div className="text-2xl font-bold text-slate-600">{stats.total}</div>
<div className="text-sm text-slate-500">Gesamt</div>
</div>
</div>
</div>
{/* Filter */}
<div className="flex items-center gap-2">
<span className="text-sm text-slate-500">Filter:</span>
<button
onClick={() => setFilterStatus('all')}
className={`px-3 py-1 rounded-full text-sm ${
filterStatus === 'all' ? 'bg-purple-100 text-purple-700' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'
}`}
>
Alle ({modules.length})
</button>
<button
onClick={() => setFilterStatus('connected')}
className={`px-3 py-1 rounded-full text-sm ${
filterStatus === 'connected' ? 'bg-green-100 text-green-700' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'
}`}
>
Verbunden
</button>
<button
onClick={() => setFilterStatus('partial')}
className={`px-3 py-1 rounded-full text-sm ${
filterStatus === 'partial' ? 'bg-yellow-100 text-yellow-700' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'
}`}
>
Teilweise
</button>
<button
onClick={() => setFilterStatus('not-connected')}
className={`px-3 py-1 rounded-full text-sm ${
filterStatus === 'not-connected' ? 'bg-red-100 text-red-700' : 'bg-slate-100 text-slate-600 hover:bg-slate-200'
}`}
>
Nicht verbunden
</button>
</div>
{/* Module List */}
<div className="space-y-3">
{filteredModules.map((module) => (
<div
key={module.id}
className="bg-white rounded-xl shadow-sm border overflow-hidden"
>
{/* Module Header */}
<button
onClick={() => setExpandedModule(expandedModule === module.id ? null : module.id)}
className="w-full px-4 py-3 flex items-center justify-between hover:bg-slate-50 transition-colors"
>
<div className="flex items-center gap-3">
<div className={`w-2 h-2 rounded-full ${STATUS_CONFIG[module.frontend.status].dot}`} />
<div className="text-left">
<div className="font-medium text-slate-900">{module.name}</div>
<div className="text-sm text-slate-500">{module.description}</div>
</div>
</div>
<div className="flex items-center gap-3">
<span className={`px-2 py-1 rounded text-xs border ${STATUS_CONFIG[module.frontend.status].color}`}>
{STATUS_CONFIG[module.frontend.status].label}
</span>
<span className={`text-xs ${PRIORITY_CONFIG[module.priority].color}`}>
{PRIORITY_CONFIG[module.priority].label}
</span>
<svg
className={`w-5 h-5 text-slate-400 transition-transform ${expandedModule === module.id ? 'rotate-180' : ''}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</div>
</button>
{/* Module Details */}
{expandedModule === module.id && (
<div className="px-4 py-4 border-t border-slate-200 bg-slate-50">
<div className="grid grid-cols-2 gap-6">
{/* Backend Info */}
<div>
<h4 className="font-medium text-slate-900 mb-2">Backend</h4>
<div className="space-y-2 text-sm">
<div className="flex items-center gap-2">
<span className="text-slate-500">Service:</span>
<code className="px-2 py-0.5 bg-slate-200 rounded text-slate-700">
{module.backend.service}
</code>
</div>
<div className="flex items-center gap-2">
<span className="text-slate-500">Port:</span>
<code className="px-2 py-0.5 bg-slate-200 rounded text-slate-700">
{module.backend.port}
</code>
</div>
<div className="flex items-center gap-2">
<span className="text-slate-500">Base Path:</span>
<code className="px-2 py-0.5 bg-slate-200 rounded text-slate-700">
{module.backend.basePath}
</code>
</div>
</div>
<h5 className="font-medium text-slate-700 mt-4 mb-2">Endpoints</h5>
<div className="space-y-1 max-h-48 overflow-y-auto">
{module.backend.endpoints.map((ep, idx) => (
<div key={idx} className="flex items-center gap-2 text-sm">
<span className={`px-1.5 py-0.5 rounded text-xs font-mono ${
ep.method === 'GET' ? 'bg-blue-100 text-blue-700' :
ep.method === 'POST' ? 'bg-green-100 text-green-700' :
ep.method === 'PUT' ? 'bg-yellow-100 text-yellow-700' :
'bg-red-100 text-red-700'
}`}>
{ep.method}
</span>
<code className="text-slate-600 text-xs">{ep.path}</code>
<span className="text-slate-400 text-xs">- {ep.description}</span>
</div>
))}
</div>
</div>
{/* Frontend Info */}
<div>
<h4 className="font-medium text-slate-900 mb-2">Frontend</h4>
<div className="space-y-3 text-sm">
<div>
<span className="text-slate-500 block mb-1">Admin v2 Seite:</span>
{module.frontend.adminV2Page ? (
<Link
href={module.frontend.adminV2Page}
className="text-purple-600 hover:text-purple-800 hover:underline"
>
{module.frontend.adminV2Page}
</Link>
) : (
<span className="text-red-500 italic">Noch nicht angelegt</span>
)}
</div>
<div>
<span className="text-slate-500 block mb-1">Altes Admin (Referenz):</span>
{module.frontend.oldAdminPage ? (
<code className="px-2 py-0.5 bg-slate-200 rounded text-slate-700">
{module.frontend.oldAdminPage}
</code>
) : (
<span className="text-slate-400 italic">-</span>
)}
</div>
{module.notes && (
<div className="mt-3 p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
<span className="text-yellow-700 text-sm">{module.notes}</span>
</div>
)}
{module.dependencies && module.dependencies.length > 0 && (
<div>
<span className="text-slate-500 block mb-1">Abhaengigkeiten:</span>
<div className="flex flex-wrap gap-1">
{module.dependencies.map((dep) => (
<span key={dep} className="px-2 py-0.5 bg-purple-100 text-purple-700 rounded text-xs">
{dep}
</span>
))}
</div>
</div>
)}
</div>
</div>
</div>
</div>
)}
</div>
))}
</div>
{/* Category Summary (if showing all) */}
{showAllCategories && (
<div className="bg-white rounded-xl shadow-sm border p-6 mt-8">
<h3 className="text-lg font-semibold text-slate-900 mb-4">Kategorie-Uebersicht</h3>
<div className="grid grid-cols-2 gap-4">
{(Object.keys(CATEGORY_CONFIG) as BackendModule['category'][]).map((cat) => {
const catStats = getCategoryStats(cat)
return (
<div key={cat} className="p-4 border border-slate-200 rounded-lg">
<div className="flex items-center justify-between mb-2">
<span className="font-medium text-slate-900">{CATEGORY_CONFIG[cat].name}</span>
<span className={`text-sm ${catStats.percentComplete === 100 ? 'text-green-600' : 'text-slate-500'}`}>
{catStats.percentComplete}%
</span>
</div>
<div className="h-2 bg-slate-200 rounded-full overflow-hidden">
<div
className={`h-full transition-all duration-500 ${
catStats.percentComplete === 100 ? 'bg-green-500' :
catStats.percentComplete > 50 ? 'bg-yellow-500' : 'bg-red-500'
}`}
style={{ width: `${catStats.percentComplete}%` }}
/>
</div>
<div className="flex justify-between mt-2 text-xs text-slate-500">
<span>{catStats.connected}/{catStats.total} verbunden</span>
{catStats.notConnected > 0 && (
<span className="text-red-500">{catStats.notConnected} offen</span>
)}
</div>
</div>
)
})}
</div>
</div>
)}
</div>
)
}