refactor(admin): split architecture page.tsx into colocated components
Extract DetailPanel, ArchHeader, Toolbar, ArchCanvas and ServiceTable into _components/, the ReactFlow node/edge builder into _hooks/useArchGraph, and layout constants/helpers into _layout.ts. page.tsx drops from 950 to 91 LOC, well below the 300 soft target. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
'use client'
|
||||
|
||||
import { ARCH_SERVICES, LAYERS, type ArchService } from '../architecture-data'
|
||||
|
||||
export default function DetailPanel({
|
||||
service,
|
||||
onClose,
|
||||
}: {
|
||||
service: ArchService
|
||||
onClose: () => void
|
||||
}) {
|
||||
const layer = LAYERS[service.layer]
|
||||
|
||||
return (
|
||||
<div className="w-80 bg-white border-l border-slate-200 overflow-y-auto">
|
||||
<div className="sticky top-0 bg-white z-10 border-b border-slate-200">
|
||||
<div className="flex items-center justify-between p-4">
|
||||
<h3 className="font-bold text-slate-900">{service.name}</h3>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="text-slate-400 hover:text-slate-600 text-lg leading-none"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
</div>
|
||||
<div className="px-4 pb-3 flex items-center gap-2">
|
||||
<span
|
||||
className="px-2 py-0.5 rounded text-xs font-medium"
|
||||
style={{ background: layer.colorBg, color: layer.colorText }}
|
||||
>
|
||||
{layer.name}
|
||||
</span>
|
||||
<span className="text-xs text-slate-400">{service.tech}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4 space-y-4">
|
||||
{/* Beschreibung */}
|
||||
<p className="text-sm text-slate-700 leading-relaxed">{service.description}</p>
|
||||
<p className="text-xs text-slate-500 leading-relaxed mt-1">{service.descriptionLong}</p>
|
||||
|
||||
{/* Tech + Port + Container */}
|
||||
<div className="bg-slate-50 rounded-lg p-3 space-y-2">
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-slate-500">Tech</span>
|
||||
<span className="font-medium text-slate-800">{service.tech}</span>
|
||||
</div>
|
||||
{service.port && (
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-slate-500">Port</span>
|
||||
<code className="text-xs bg-slate-200 px-1.5 py-0.5 rounded">{service.port}</code>
|
||||
</div>
|
||||
)}
|
||||
{service.url && (
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-slate-500">URL</span>
|
||||
<a
|
||||
href={service.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-xs text-blue-600 hover:underline truncate max-w-[180px]"
|
||||
>
|
||||
{service.url}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-slate-500">Container</span>
|
||||
<code className="text-xs bg-slate-200 px-1.5 py-0.5 rounded truncate max-w-[180px]">{service.container}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* DB Tables */}
|
||||
{service.dbTables.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-xs font-semibold text-slate-500 uppercase mb-1.5">
|
||||
DB-Tabellen ({service.dbTables.length})
|
||||
</h4>
|
||||
<div className="space-y-1">
|
||||
{service.dbTables.map(table => (
|
||||
<div
|
||||
key={table}
|
||||
className="text-sm bg-slate-100 rounded px-2 py-1"
|
||||
>
|
||||
<code className="text-slate-700 text-xs">{table}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* RAG Collections */}
|
||||
{service.ragCollections.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-xs font-semibold text-slate-500 uppercase mb-1.5">
|
||||
RAG-Collections ({service.ragCollections.length})
|
||||
</h4>
|
||||
<div className="space-y-1">
|
||||
{service.ragCollections.map(rag => (
|
||||
<div
|
||||
key={rag}
|
||||
className="text-sm bg-green-50 rounded px-2 py-1"
|
||||
>
|
||||
<code className="text-green-700 text-xs">{rag}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* API Endpoints */}
|
||||
{service.apiEndpoints.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-xs font-semibold text-slate-500 uppercase mb-1.5">
|
||||
API-Endpunkte ({service.apiEndpoints.length})
|
||||
</h4>
|
||||
<div className="space-y-1">
|
||||
{service.apiEndpoints.map(ep => (
|
||||
<div
|
||||
key={ep}
|
||||
className="text-sm bg-violet-50 rounded px-2 py-1"
|
||||
>
|
||||
<code className="text-violet-700 text-xs">{ep}</code>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Dependencies */}
|
||||
{service.dependsOn.length > 0 && (
|
||||
<div>
|
||||
<h4 className="text-xs font-semibold text-slate-500 uppercase mb-1.5">
|
||||
Abhaengigkeiten
|
||||
</h4>
|
||||
<div className="space-y-1">
|
||||
{service.dependsOn.map(depId => {
|
||||
const dep = ARCH_SERVICES.find(s => s.id === depId)
|
||||
return (
|
||||
<div
|
||||
key={depId}
|
||||
className="text-sm text-slate-600 bg-slate-50 rounded px-2 py-1"
|
||||
>
|
||||
{dep?.name || depId}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Open URL */}
|
||||
{service.url && (
|
||||
<button
|
||||
onClick={() => window.open(service.url!, '_blank')}
|
||||
className="w-full mt-2 px-4 py-2 bg-purple-600 text-white rounded-lg text-sm font-medium hover:bg-purple-700 transition-colors"
|
||||
>
|
||||
Service oeffnen
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user