f8b45dd3d1
Die vier Kern-Module in eine Gruppe "Produkt-Compliance (CE & Cyber)" (Gap-Analyse, Maschinensicherheit/CE, Cyber Resilience/CRA) — iace+cra benachbart, KI-Compliance nicht mehr dazwischen gekeilt. Labels entschaerft (kein "IACE"-Codename, keine doppelten Header). Interne/Entwickler-Module (Kataloge/Templates, Korpus/coverage, Quellen, Engine-Internals, Admin) in eine per useInternalUI() gegatete Sektion "Intern · Entwicklung" — Kunden sehen sie nie (Default versteckt; intern = macmini/localhost o. Browser-Opt-in). coverage erstmals erreichbar (war verwaist). Toter SidebarModuleNav.tsx geloescht. Alle bestehenden Routen erhalten. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
200 lines
12 KiB
TypeScript
200 lines
12 KiB
TypeScript
'use client'
|
|
// =============================================================================
|
|
// SIDEBAR MODULE LIST
|
|
// Customer-facing module groups (always shown) + an internal/developer section
|
|
// (catalog/template management, corpus curation, engine internals, admin tooling)
|
|
// gated by useInternalUI() so customers never see it. See lib/sdk/useInternalUI.
|
|
// =============================================================================
|
|
|
|
import React from 'react'
|
|
import Link from 'next/link'
|
|
import { usePathname } from 'next/navigation'
|
|
import { AdditionalModuleItem, withProject } from './SidebarSubComponents'
|
|
import { useInternalUI } from '@/lib/sdk/useInternalUI'
|
|
|
|
interface SidebarModuleListProps {
|
|
collapsed: boolean
|
|
projectId?: string
|
|
pendingCRCount: number
|
|
}
|
|
|
|
const ic = (d: string) => (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d={d} />
|
|
</svg>
|
|
)
|
|
|
|
// Shared icon path data (de-duplicated from the previous inline SVGs).
|
|
const I = {
|
|
barChart: 'M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z',
|
|
shieldCheck: 'M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z',
|
|
iace: 'M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z',
|
|
clipboardCheck: 'M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4',
|
|
list: 'M4 6h16M4 10h16M4 14h16M4 18h16',
|
|
bolt: 'M13 10V3L4 14h7v7l9-11h-7z',
|
|
euReg: 'M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4',
|
|
optimizer: 'M13 7h8m0 0v8m0-8l-8 8-4-4-6 6',
|
|
chip: 'M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z',
|
|
grid: 'M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z',
|
|
eyeCircle: 'M15 12a3 3 0 11-6 0 3 3 0 016 0z',
|
|
consent: 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10',
|
|
users: 'M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z',
|
|
user: 'M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z',
|
|
clock: 'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z',
|
|
envelope: 'M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z',
|
|
card: 'M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z',
|
|
rolesUsers: 'M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z',
|
|
book: 'M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253',
|
|
warning: 'M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z',
|
|
catalog: 'M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4',
|
|
globe: 'M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9',
|
|
search: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z',
|
|
checkCircle: 'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z',
|
|
architecture: 'M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01',
|
|
portfolio: 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10',
|
|
roadmap: 'M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2',
|
|
code: 'M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4',
|
|
}
|
|
|
|
function SectionHeader({ label, collapsed, tone = 'gray' }: { label: string; collapsed: boolean; tone?: 'gray' | 'indigo' | 'purple' | 'slate' }) {
|
|
if (collapsed) return null
|
|
const cls = {
|
|
gray: 'text-gray-400 font-medium',
|
|
indigo: 'text-indigo-600 font-semibold',
|
|
purple: 'text-purple-600 font-semibold',
|
|
slate: 'text-slate-500 font-semibold',
|
|
}[tone]
|
|
return <div className={`px-4 py-2 text-xs uppercase tracking-wider ${cls}`}>{label}</div>
|
|
}
|
|
|
|
export function SidebarModuleList({ collapsed, projectId, pendingCRCount }: SidebarModuleListProps) {
|
|
const pathname = usePathname()
|
|
const showInternal = useInternalUI()
|
|
const active = (href: string, prefix = false) =>
|
|
prefix ? (pathname?.startsWith(href) ?? false) : pathname === href
|
|
const item = (href: string, d: string, label: string, prefix = false) => (
|
|
<AdditionalModuleItem href={href} icon={ic(d)} label={label} isActive={active(href, prefix)} collapsed={collapsed} projectId={projectId} />
|
|
)
|
|
|
|
return (
|
|
<>
|
|
{/* === KUNDE === */}
|
|
|
|
{/* Produkt-Compliance (CE & Cyber) — die vier Kern-Module zusammen */}
|
|
<div className="border-t-2 border-indigo-200 py-2 bg-indigo-50/30">
|
|
<SectionHeader label="Produkt-Compliance (CE & Cyber)" collapsed={collapsed} tone="indigo" />
|
|
{item('/sdk/gap-analysis', I.barChart, 'Gap-Analyse', true)}
|
|
{item('/sdk/iace', I.iace, 'Maschinensicherheit (CE)', true)}
|
|
{item('/sdk/cra', I.shieldCheck, 'Cyber Resilience (CRA)', true)}
|
|
</div>
|
|
|
|
{/* KI-Compliance */}
|
|
<div className="border-t border-gray-100 py-2">
|
|
<SectionHeader label="KI-Compliance" collapsed={collapsed} />
|
|
{item('/sdk/advisory-board', I.clipboardCheck, 'Use Case Erfassung')}
|
|
{item('/sdk/use-cases', I.list, 'Use Cases', true)}
|
|
{item('/sdk/ai-act', I.bolt, 'AI Act', true)}
|
|
{item('/sdk/ai-registration', I.euReg, 'EU Registrierung', true)}
|
|
{item('/sdk/compliance-optimizer', I.optimizer, 'Compliance Optimizer', true)}
|
|
{item('/sdk/agent', I.chip, 'Compliance Agent', true)}
|
|
{item('/sdk/benchmark', I.barChart, 'Branchen-Benchmark', true)}
|
|
</div>
|
|
|
|
{/* Datenschutz (CMP) */}
|
|
<div className="border-t-2 border-purple-200 py-2 bg-purple-50/30">
|
|
<SectionHeader label="Datenschutz" collapsed={collapsed} tone="purple" />
|
|
{item('/sdk/cmp', I.grid, 'Dashboard')}
|
|
{item('/sdk/cookie-banner', I.shieldCheck, 'Cookie-Banner', true)}
|
|
{item('/sdk/cookie-banner/preview', I.eyeCircle, 'Live-Vorschau')}
|
|
{item('/sdk/einwilligungen', I.clipboardCheck, 'Consent-Records', true)}
|
|
{item('/sdk/consent-management', I.consent, 'Consent-Verwaltung')}
|
|
{item('/sdk/vendor-compliance', I.users, 'Vendor-Compliance', true)}
|
|
{item('/sdk/dsr', I.user, 'DSR Portal', true)}
|
|
{item('/sdk/loeschfristen', I.clock, 'Loeschfristen')}
|
|
{item('/sdk/email-templates', I.envelope, 'E-Mail-Templates')}
|
|
</div>
|
|
|
|
{/* Verträge & Audit */}
|
|
<div className="border-t border-gray-100 py-2">
|
|
<SectionHeader label="Verträge & Audit" collapsed={collapsed} />
|
|
{item('/sdk/vendor-assessment', I.clipboardCheck, 'Vertragspruefung', true)}
|
|
{item('/sdk/audit-timeline', I.clock, 'Audit Timeline', true)}
|
|
</div>
|
|
|
|
{/* Payment / Terminal */}
|
|
<div className="border-t border-gray-100 py-2">
|
|
<SectionHeader label="Payment / Terminal" collapsed={collapsed} />
|
|
{item('/sdk/payment-compliance', I.card, 'Payment Compliance', true)}
|
|
</div>
|
|
|
|
{/* Betrieb & Nachweise */}
|
|
<div className="border-t border-gray-100 py-2">
|
|
<SectionHeader label="Betrieb & Nachweise" collapsed={collapsed} />
|
|
{item('/sdk/rollenkonzept', I.rolesUsers, 'Rollenkonzept', true)}
|
|
{item('/sdk/training', I.book, 'Schulung (Admin)')}
|
|
{item('/sdk/training/learner', I.user, 'Schulung (Learner)')}
|
|
{item('/sdk/security-backlog', I.warning, 'Security Backlog')}
|
|
{item('/sdk/compliance-hub', I.barChart, 'Compliance Hub')}
|
|
{item('/sdk/isms', I.shieldCheck, 'ISMS Readiness')}
|
|
{item('/sdk/wiki', I.book, 'Compliance Wiki', true)}
|
|
</div>
|
|
|
|
{/* === INTERN · ENTWICKLUNG (nur intern sichtbar, nie für Kunden) === */}
|
|
{showInternal && (
|
|
<div className="border-t-2 border-slate-300 py-2 bg-slate-100/60">
|
|
<SectionHeader label="Intern · Entwicklung" collapsed={collapsed} tone="slate" />
|
|
{item('/sdk/coverage', I.clipboardCheck, 'Abdeckung / Korpus', true)}
|
|
{item('/sdk/catalog-manager', I.catalog, 'Kataloge / Templates')}
|
|
{item('/sdk/source-policy', I.globe, 'Quellen-Verwaltung', true)}
|
|
{item('/sdk/rag', I.search, 'Legal RAG')}
|
|
{item('/sdk/quality', I.checkCircle, 'AI Quality')}
|
|
{item('/sdk/assertions', I.clipboardCheck, 'Assertions')}
|
|
{item('/sdk/dsms', I.shieldCheck, 'DSMS')}
|
|
{item('/sdk/sdk-flow', I.bolt, 'SDK Flow')}
|
|
{item('/sdk/architecture', I.architecture, 'Architektur')}
|
|
{item('/sdk/agents', I.chip, 'Agenten', true)}
|
|
{item('/sdk/workshop', I.users, 'Workshop')}
|
|
{item('/sdk/portfolio', I.portfolio, 'Portfolio')}
|
|
{item('/sdk/roadmap', I.roadmap, 'Roadmap')}
|
|
{item('/sdk/audit-llm', I.barChart, 'LLM Audit')}
|
|
{item('/sdk/rbac', I.shieldCheck, 'RBAC Admin')}
|
|
{item('/sdk/api-docs', I.code, 'API-Referenz')}
|
|
|
|
{/* Change Requests — needs badge so handled directly */}
|
|
<Link
|
|
href={withProject('/sdk/change-requests', projectId)}
|
|
className={`flex items-center gap-3 px-4 py-2.5 text-sm transition-colors ${
|
|
collapsed ? 'justify-center' : ''
|
|
} ${
|
|
pathname === '/sdk/change-requests'
|
|
? 'bg-purple-100 text-purple-900 font-medium'
|
|
: 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'
|
|
}`}
|
|
title={collapsed ? `Änderungsanfragen (${pendingCRCount})` : undefined}
|
|
>
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01" />
|
|
</svg>
|
|
{!collapsed && (
|
|
<span className="flex items-center gap-2">
|
|
Änderungsanfragen
|
|
{pendingCRCount > 0 && (
|
|
<span className="px-1.5 py-0.5 text-xs font-bold bg-red-500 text-white rounded-full min-w-[1.25rem] text-center">
|
|
{pendingCRCount}
|
|
</span>
|
|
)}
|
|
</span>
|
|
)}
|
|
{collapsed && pendingCRCount > 0 && (
|
|
<span className="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full" />
|
|
)}
|
|
</Link>
|
|
|
|
<AdditionalModuleItem href="https://macmini:3006" icon={ic(I.code)} label="Developer Portal" isActive={false} collapsed={collapsed} projectId={projectId} />
|
|
<AdditionalModuleItem href="https://macmini:8011" icon={ic(I.book)} label="SDK Dokumentation" isActive={false} collapsed={collapsed} projectId={projectId} />
|
|
</div>
|
|
)}
|
|
</>
|
|
)
|
|
}
|