'use client' /** * Screen Flow Visualization * * Visualisiert alle Screens aus: * - Studio (Port 8000): Lehrer-Oberflaeche * - Admin v2 (Port 3002): Admin Panel */ import { useCallback, useState, useMemo, useEffect } from 'react' import ReactFlow, { Node, Edge, Controls, Background, MiniMap, useNodesState, useEdgesState, BackgroundVariant, MarkerType, Panel, } from 'reactflow' import 'reactflow/dist/style.css' // ============================================ // TYPES // ============================================ interface ScreenDefinition { id: string name: string description: string category: string icon: string url?: string } interface ConnectionDef { source: string target: string label?: string } type FlowType = 'studio' | 'admin' // ============================================ // STUDIO SCREENS (Port 8000) // ============================================ const STUDIO_SCREENS: ScreenDefinition[] = [ { id: 'lehrer-dashboard', name: 'Mein Dashboard', description: 'Hauptuebersicht mit Widgets', category: 'navigation', icon: '๐Ÿ ', url: '/app#lehrer-dashboard' }, { id: 'lehrer-onboarding', name: 'Erste Schritte', description: 'Onboarding & Schnellstart', category: 'navigation', icon: '๐Ÿš€', url: '/app#lehrer-onboarding' }, { id: 'hilfe', name: 'Dokumentation', description: 'Hilfe & Anleitungen', category: 'navigation', icon: '๐Ÿ“š', url: '/app#hilfe' }, { id: 'worksheets', name: 'Arbeitsblaetter Studio', description: 'Lernmaterialien erstellen', category: 'content', icon: '๐Ÿ“', url: '/app#worksheets' }, { id: 'content-creator', name: 'Content Creator', description: 'Inhalte erstellen', category: 'content', icon: 'โœจ', url: '/app#content-creator' }, { id: 'content-feed', name: 'Content Feed', description: 'Inhalte durchsuchen', category: 'content', icon: '๐Ÿ“ฐ', url: '/app#content-feed' }, { id: 'unit-creator', name: 'Unit Creator', description: 'Lerneinheiten erstellen', category: 'content', icon: '๐Ÿ“ฆ', url: '/app#unit-creator' }, { id: 'letters', name: 'Briefe & Vorlagen', description: 'Brief-Generator', category: 'content', icon: 'โœ‰๏ธ', url: '/app#letters' }, { id: 'correction', name: 'Korrektur', description: 'Arbeiten korrigieren', category: 'content', icon: 'โœ๏ธ', url: '/app#correction' }, { id: 'klausur-korrektur', name: 'Abiturklausuren', description: 'KI-gestuetzte Klausurkorrektur', category: 'content', icon: '๐Ÿ“‹', url: '/app#klausur-korrektur' }, { id: 'jitsi', name: 'Videokonferenz', description: 'Jitsi Meet Integration', category: 'communication', icon: '๐ŸŽฅ', url: '/app#jitsi' }, { id: 'messenger', name: 'Messenger', description: 'Matrix E2EE Chat', category: 'communication', icon: '๐Ÿ’ฌ', url: '/app#messenger' }, { id: 'mail', name: 'Unified Inbox', description: 'E-Mail Verwaltung', category: 'communication', icon: '๐Ÿ“ง', url: '/app#mail' }, { id: 'school-classes', name: 'Klassen', description: 'Klassenverwaltung', category: 'school', icon: '๐Ÿ‘ฅ', url: '/app#school-classes' }, { id: 'school-exams', name: 'Pruefungen', description: 'Pruefungsverwaltung', category: 'school', icon: '๐Ÿ“', url: '/app#school-exams' }, { id: 'school-grades', name: 'Noten', description: 'Notenverwaltung', category: 'school', icon: '๐Ÿ“Š', url: '/app#school-grades' }, { id: 'school-gradebook', name: 'Notenbuch', description: 'Digitales Notenbuch', category: 'school', icon: '๐Ÿ“–', url: '/app#school-gradebook' }, { id: 'school-certificates', name: 'Zeugnisse', description: 'Zeugniserstellung', category: 'school', icon: '๐ŸŽ“', url: '/app#school-certificates' }, { id: 'companion', name: 'Begleiter & Stunde', description: 'KI-Unterrichtsassistent', category: 'ai', icon: '๐Ÿค–', url: '/app#companion' }, { id: 'alerts', name: 'Alerts', description: 'News & Benachrichtigungen', category: 'ai', icon: '๐Ÿ””', url: '/app#alerts' }, { id: 'admin', name: 'Einstellungen', description: 'Systemeinstellungen', category: 'admin', icon: 'โš™๏ธ', url: '/app#admin' }, { id: 'rbac-admin', name: 'Rollen & Rechte', description: 'Berechtigungsverwaltung', category: 'admin', icon: '๐Ÿ”', url: '/app#rbac-admin' }, { id: 'abitur-docs-admin', name: 'Abitur Dokumente', description: 'Erwartungshorizonte', category: 'admin', icon: '๐Ÿ“„', url: '/app#abitur-docs-admin' }, { id: 'system-info', name: 'System Info', description: 'Systeminformationen', category: 'admin', icon: '๐Ÿ’ป', url: '/app#system-info' }, { id: 'workflow', name: 'Workflow', description: 'Automatisierungen', category: 'admin', icon: 'โšก', url: '/app#workflow' }, ] const STUDIO_CONNECTIONS: ConnectionDef[] = [ { source: 'lehrer-onboarding', target: 'worksheets', label: 'Arbeitsblaetter' }, { source: 'lehrer-onboarding', target: 'klausur-korrektur', label: 'Abiturklausuren' }, { source: 'lehrer-onboarding', target: 'correction', label: 'Korrektur' }, { source: 'lehrer-onboarding', target: 'letters', label: 'Briefe' }, { source: 'lehrer-onboarding', target: 'school-classes', label: 'Klassen' }, { source: 'lehrer-onboarding', target: 'jitsi', label: 'Meet' }, { source: 'lehrer-onboarding', target: 'hilfe', label: 'Doku' }, { source: 'lehrer-onboarding', target: 'admin', label: 'Settings' }, { source: 'lehrer-dashboard', target: 'worksheets' }, { source: 'lehrer-dashboard', target: 'correction' }, { source: 'lehrer-dashboard', target: 'jitsi' }, { source: 'lehrer-dashboard', target: 'letters' }, { source: 'lehrer-dashboard', target: 'messenger' }, { source: 'lehrer-dashboard', target: 'klausur-korrektur' }, { source: 'lehrer-dashboard', target: 'companion' }, { source: 'lehrer-dashboard', target: 'alerts' }, { source: 'lehrer-dashboard', target: 'mail' }, { source: 'lehrer-dashboard', target: 'school-classes' }, { source: 'lehrer-dashboard', target: 'lehrer-onboarding', label: 'Sidebar' }, { source: 'school-classes', target: 'school-exams' }, { source: 'school-classes', target: 'school-grades' }, { source: 'school-grades', target: 'school-gradebook' }, { source: 'school-gradebook', target: 'school-certificates' }, { source: 'worksheets', target: 'content-creator' }, { source: 'worksheets', target: 'unit-creator' }, { source: 'content-creator', target: 'content-feed' }, { source: 'klausur-korrektur', target: 'abitur-docs-admin' }, { source: 'admin', target: 'rbac-admin' }, { source: 'admin', target: 'system-info' }, { source: 'admin', target: 'workflow' }, ] // ============================================ // ADMIN v2 SCREENS (Port 3002) // Based on navigation.ts - Last updated: 2026-02-03 // ============================================ const ADMIN_SCREENS: ScreenDefinition[] = [ // === META / OVERVIEW === { id: 'admin-dashboard', name: 'Dashboard', description: 'Uebersicht & Statistiken', category: 'overview', icon: '๐Ÿ ', url: '/dashboard' }, { id: 'admin-onboarding', name: 'Onboarding', description: 'Lern-Wizards fuer alle Module', category: 'overview', icon: '๐Ÿ“–', url: '/onboarding' }, { id: 'admin-architecture', name: 'Architektur', description: 'Backend-Module & Datenfluss', category: 'overview', icon: '๐Ÿ—๏ธ', url: '/architecture' }, { id: 'admin-backlog', name: 'Production Backlog', description: 'Go-Live Checkliste', category: 'overview', icon: '๐Ÿ“', url: '/backlog' }, { id: 'admin-rbac', name: 'RBAC', description: 'Rollen & Berechtigungen', category: 'overview', icon: '๐Ÿ‘ฅ', url: '/rbac' }, // === COMPLIANCE SDK (Violet #8b5cf6) === // DSGVO - Datenschutz & Betroffenenrechte { id: 'admin-consent', name: 'Consent Verwaltung', description: 'Rechtliche Dokumente & Versionen', category: 'sdk', icon: '๐Ÿ“„', url: '/sdk/consent-management' }, { id: 'admin-dsr', name: 'Datenschutzanfragen', description: 'DSGVO Art. 15-21', category: 'sdk', icon: '๐Ÿ”’', url: '/sdk/dsr' }, { id: 'admin-einwilligungen', name: 'Einwilligungen', description: 'Nutzer-Consent Uebersicht', category: 'sdk', icon: 'โœ…', url: '/sdk/einwilligungen' }, { id: 'admin-vvt', name: 'VVT', description: 'Verarbeitungsverzeichnis Art. 30', category: 'sdk', icon: '๐Ÿ“‹', url: '/sdk/vvt' }, { id: 'admin-dsfa', name: 'DSFA', description: 'Datenschutz-Folgenabschaetzung', category: 'sdk', icon: 'โš–๏ธ', url: '/sdk/dsfa' }, { id: 'admin-tom', name: 'TOMs', description: 'Technische & Org. Massnahmen', category: 'sdk', icon: '๐Ÿ›ก๏ธ', url: '/sdk/tom' }, { id: 'admin-loeschfristen', name: 'Loeschfristen', description: 'Aufbewahrung & Deadlines', category: 'sdk', icon: '๐Ÿ—‘๏ธ', url: '/sdk/loeschfristen' }, { id: 'admin-advisory-board', name: 'Advisory Board', description: 'KI-Use-Case Pruefung', category: 'sdk', icon: '๐Ÿง‘โ€โš–๏ธ', url: '/sdk/advisory-board' }, { id: 'admin-escalations', name: 'Eskalations-Queue', description: 'DSB Review & Freigabe', category: 'sdk', icon: '๐Ÿšจ', url: '/sdk/escalations' }, // Compliance - Audit, GRC & Regulatorik { id: 'admin-compliance-hub', name: 'Compliance Hub', description: 'Zentrales GRC Dashboard', category: 'sdk', icon: 'โœ…', url: '/sdk/compliance-hub' }, { id: 'admin-audit-checklist', name: 'Audit Checkliste', description: '476 Anforderungen pruefen', category: 'sdk', icon: '๐Ÿ“‹', url: '/sdk/audit-checklist' }, { id: 'admin-requirements', name: 'Requirements', description: '558+ aus 19 Verordnungen', category: 'sdk', icon: '๐Ÿ“œ', url: '/sdk/requirements' }, { id: 'admin-controls', name: 'Controls', description: '474 Control-Mappings', category: 'sdk', icon: '๐ŸŽ›๏ธ', url: '/sdk/controls' }, { id: 'admin-evidence', name: 'Evidence', description: 'Nachweise & Dokumentation', category: 'sdk', icon: '๐Ÿ“Ž', url: '/sdk/evidence' }, { id: 'admin-risks', name: 'Risiken', description: 'Risk Matrix & Register', category: 'sdk', icon: 'โš ๏ธ', url: '/sdk/risks' }, { id: 'admin-audit-report', name: 'Audit Report', description: 'PDF Audit-Berichte', category: 'sdk', icon: '๐Ÿ“Š', url: '/sdk/audit-report' }, { id: 'admin-modules', name: 'Service Registry', description: '30+ Service-Module', category: 'sdk', icon: '๐Ÿ”ง', url: '/sdk/modules' }, { id: 'admin-dsms', name: 'DSMS', description: 'Datenschutz-Management-System', category: 'sdk', icon: '๐Ÿ›๏ธ', url: '/sdk/dsms' }, { id: 'admin-compliance-workflow', name: 'Workflow', description: 'Freigabe-Workflows', category: 'sdk', icon: '๐Ÿ”„', url: '/sdk/workflow' }, { id: 'admin-source-policy', name: 'Quellen-Policy', description: 'Datenquellen & Compliance', category: 'sdk', icon: '๐Ÿ“š', url: '/sdk/source-policy' }, { id: 'admin-ai-act', name: 'EU-AI-Act', description: 'KI-Risikoklassifizierung', category: 'sdk', icon: '๐Ÿค–', url: '/sdk/ai-act' }, { id: 'admin-obligations', name: 'Pflichten', description: 'NIS2, DSGVO, AI Act', category: 'sdk', icon: 'โšก', url: '/sdk/obligations' }, // === KI & AUTOMATISIERUNG (Teal #14b8a6) === { id: 'admin-rag', name: 'Daten & RAG', description: 'Training Data & RAG', category: 'ai', icon: '๐Ÿ—„๏ธ', url: '/ai/rag' }, { id: 'admin-ocr-labeling', name: 'OCR-Labeling', description: 'Handschrift-Training', category: 'ai', icon: 'โœ๏ธ', url: '/ai/ocr-labeling' }, { id: 'admin-magic-help', name: 'Magic Help', description: 'TrOCR Handschrift-OCR', category: 'ai', icon: '๐Ÿช„', url: '/ai/magic-help' }, { id: 'admin-klausur-korrektur', name: 'Klausur-Korrektur', description: 'Abitur-Korrektur mit KI', category: 'ai', icon: '๐Ÿ“', url: '/ai/klausur-korrektur' }, { id: 'admin-quality', name: 'Qualitaet & Audit', description: 'Compliance-Audit & Traceability', category: 'ai', icon: 'โœจ', url: '/ai/quality' }, { id: 'admin-test-quality', name: 'Test Quality (BQAS)', description: 'Golden Suite & Synthetic Tests', category: 'ai', icon: '๐Ÿงช', url: '/ai/test-quality' }, { id: 'admin-agents', name: 'Agent Management', description: 'Multi-Agent & SOUL-Editor', category: 'ai', icon: '๐Ÿง ', url: '/ai/agents' }, // === INFRASTRUKTUR (Orange #f97316) === { id: 'admin-gpu', name: 'GPU Infrastruktur', description: 'vast.ai GPU Management', category: 'infrastructure', icon: '๐Ÿ–ฅ๏ธ', url: '/infrastructure/gpu' }, { id: 'admin-middleware', name: 'Middleware', description: 'Stack & API Gateway', category: 'infrastructure', icon: '๐Ÿ”ง', url: '/infrastructure/middleware' }, { id: 'admin-security', name: 'Security', description: 'DevSecOps & Scans', category: 'infrastructure', icon: '๐Ÿ”', url: '/infrastructure/security' }, { id: 'admin-sbom', name: 'SBOM', description: 'Software Bill of Materials', category: 'infrastructure', icon: '๐Ÿ“ฆ', url: '/infrastructure/sbom' }, { id: 'admin-cicd', name: 'CI/CD', description: 'Pipelines & Deployments', category: 'infrastructure', icon: '๐Ÿ”„', url: '/infrastructure/ci-cd' }, { id: 'admin-tests', name: 'Test Dashboard', description: '195+ Tests & Coverage', category: 'infrastructure', icon: '๐Ÿงช', url: '/infrastructure/tests' }, // === BILDUNG (Blue #3b82f6) === { id: 'admin-edu-search', name: 'Education Search', description: 'Bildungsquellen & Crawler', category: 'education', icon: '๐Ÿ”', url: '/education/edu-search' }, { id: 'admin-zeugnisse', name: 'Zeugnisse-Crawler', description: 'Zeugnis-Daten', category: 'education', icon: '๐Ÿ“œ', url: '/education/zeugnisse-crawler' }, { id: 'admin-rag-pipeline', name: 'RAG Pipeline', description: 'Bildungsdokumente indexieren', category: 'ai', icon: '๐Ÿ”—', url: '/ai/rag-pipeline' }, { id: 'admin-foerderantrag', name: 'Foerderantrag-Wizard', description: 'DigitalPakt & Landesfoerderung', category: 'education', icon: '๐Ÿ’ฐ', url: '/education/foerderantrag' }, // === KOMMUNIKATION (Green #22c55e) === { id: 'admin-video', name: 'Video & Chat', description: 'Matrix & Jitsi Monitoring', category: 'communication', icon: '๐ŸŽฅ', url: '/communication/video-chat' }, { id: 'admin-matrix', name: 'Voice Service', description: 'Voice-First Interface', category: 'communication', icon: '๐ŸŽ™๏ธ', url: '/communication/matrix' }, { id: 'admin-mail', name: 'Unified Inbox', description: 'E-Mail & KI-Analyse', category: 'communication', icon: '๐Ÿ“ง', url: '/communication/mail' }, { id: 'admin-alerts', name: 'Alerts Monitoring', description: 'Google Alerts & Feeds', category: 'communication', icon: '๐Ÿ””', url: '/communication/alerts' }, // === ENTWICKLUNG (Slate #64748b) === { id: 'admin-workflow', name: 'Dev Workflow', description: 'Git, CI/CD & Team-Regeln', category: 'development', icon: 'โšก', url: '/development/workflow' }, { id: 'admin-game', name: 'Breakpilot Drive', description: 'Lernspiel Management', category: 'development', icon: '๐ŸŽฎ', url: '/development/game' }, { id: 'admin-unity', name: 'Unity Bridge', description: 'Unity Editor Steuerung', category: 'development', icon: '๐ŸŽฏ', url: '/development/unity-bridge' }, { id: 'admin-companion', name: 'Companion Dev', description: 'Lesson-Modus Entwicklung', category: 'development', icon: '๐Ÿ“š', url: '/development/companion' }, { id: 'admin-docs', name: 'Developer Docs', description: 'API & Architektur', category: 'development', icon: '๐Ÿ“–', url: '/development/docs' }, { id: 'admin-brandbook', name: 'Brandbook', description: 'Corporate Design', category: 'development', icon: '๐ŸŽจ', url: '/development/brandbook' }, { id: 'admin-screen-flow', name: 'Screen Flow', description: 'UI Screen-Verbindungen', category: 'development', icon: '๐Ÿ”€', url: '/development/screen-flow' }, { id: 'admin-content', name: 'Uebersetzungen', description: 'Website Content & Sprachen', category: 'development', icon: '๐ŸŒ', url: '/development/content' }, ] const ADMIN_CONNECTIONS: ConnectionDef[] = [ // === OVERVIEW/META FLOWS === { source: 'admin-dashboard', target: 'admin-onboarding', label: 'Erste Schritte' }, { source: 'admin-dashboard', target: 'admin-architecture', label: 'System' }, { source: 'admin-dashboard', target: 'admin-backlog', label: 'Go-Live' }, { source: 'admin-dashboard', target: 'admin-compliance-hub', label: 'Compliance' }, { source: 'admin-onboarding', target: 'admin-consent' }, { source: 'admin-rbac', target: 'admin-consent' }, // === DSGVO FLOW === { source: 'admin-consent', target: 'admin-einwilligungen', label: 'Nutzer' }, { source: 'admin-consent', target: 'admin-dsr' }, { source: 'admin-dsr', target: 'admin-loeschfristen' }, { source: 'admin-vvt', target: 'admin-tom' }, { source: 'admin-vvt', target: 'admin-dsfa' }, { source: 'admin-dsfa', target: 'admin-tom' }, { source: 'admin-advisory-board', target: 'admin-escalations', label: 'Eskalation' }, { source: 'admin-advisory-board', target: 'admin-dsfa', label: 'Risiko' }, // === COMPLIANCE FLOW === { source: 'admin-compliance-hub', target: 'admin-audit-checklist', label: 'Audit' }, { source: 'admin-compliance-hub', target: 'admin-requirements', label: 'Anforderungen' }, { source: 'admin-compliance-hub', target: 'admin-risks', label: 'Risiken' }, { source: 'admin-compliance-hub', target: 'admin-ai-act', label: 'AI Act' }, { source: 'admin-requirements', target: 'admin-controls' }, { source: 'admin-controls', target: 'admin-evidence' }, { source: 'admin-audit-checklist', target: 'admin-audit-report', label: 'Report' }, { source: 'admin-risks', target: 'admin-controls' }, { source: 'admin-modules', target: 'admin-controls' }, { source: 'admin-source-policy', target: 'admin-rag' }, { source: 'admin-obligations', target: 'admin-requirements' }, { source: 'admin-dsms', target: 'admin-compliance-workflow' }, // === KI & AUTOMATISIERUNG FLOW === { source: 'admin-rag', target: 'admin-quality' }, { source: 'admin-rag', target: 'admin-agents' }, { source: 'admin-ocr-labeling', target: 'admin-magic-help', label: 'Training' }, { source: 'admin-magic-help', target: 'admin-klausur-korrektur', label: 'Korrektur' }, { source: 'admin-quality', target: 'admin-test-quality' }, { source: 'admin-agents', target: 'admin-test-quality', label: 'BQAS' }, { source: 'admin-klausur-korrektur', target: 'admin-quality', label: 'Audit' }, // === INFRASTRUKTUR FLOW === { source: 'admin-security', target: 'admin-sbom', label: 'Dependencies' }, { source: 'admin-sbom', target: 'admin-tests' }, { source: 'admin-tests', target: 'admin-cicd', label: 'Pipeline' }, { source: 'admin-cicd', target: 'admin-middleware' }, { source: 'admin-middleware', target: 'admin-gpu', label: 'GPU' }, { source: 'admin-security', target: 'admin-compliance-hub', label: 'Compliance' }, // === BILDUNG FLOW === { source: 'admin-edu-search', target: 'admin-rag', label: 'Quellen' }, { source: 'admin-edu-search', target: 'admin-zeugnisse' }, { source: 'admin-training', target: 'admin-onboarding' }, { source: 'admin-foerderantrag', target: 'admin-docs', label: 'Docs' }, // === KOMMUNIKATION FLOW === { source: 'admin-video', target: 'admin-matrix', label: 'Voice' }, { source: 'admin-mail', target: 'admin-alerts' }, { source: 'admin-alerts', target: 'admin-mail', label: 'Inbox' }, // === ENTWICKLUNG FLOW === { source: 'admin-workflow', target: 'admin-cicd', label: 'Pipeline' }, { source: 'admin-workflow', target: 'admin-docs' }, { source: 'admin-game', target: 'admin-unity', label: 'Editor' }, { source: 'admin-companion', target: 'admin-agents', label: 'Agents' }, { source: 'admin-brandbook', target: 'admin-screen-flow' }, { source: 'admin-docs', target: 'admin-architecture' }, { source: 'admin-content', target: 'admin-brandbook' }, ] // ============================================ // CATEGORY COLORS // ============================================ const STUDIO_COLORS: Record = { navigation: { bg: '#dbeafe', border: '#3b82f6', text: '#1e40af' }, content: { bg: '#dcfce7', border: '#22c55e', text: '#166534' }, communication: { bg: '#fef3c7', border: '#f59e0b', text: '#92400e' }, school: { bg: '#fce7f3', border: '#ec4899', text: '#9d174d' }, admin: { bg: '#f3e8ff', border: '#a855f7', text: '#6b21a8' }, ai: { bg: '#cffafe', border: '#06b6d4', text: '#0e7490' }, } // Colors from navigation.ts const ADMIN_COLORS: Record = { overview: { bg: '#e0f2fe', border: '#0ea5e9', text: '#0369a1' }, // Sky (Meta) dsgvo: { bg: '#ede9fe', border: '#7c3aed', text: '#5b21b6' }, // Violet compliance: { bg: '#f3e8ff', border: '#9333ea', text: '#6b21a8' }, // Purple ai: { bg: '#ccfbf1', border: '#14b8a6', text: '#0f766e' }, // Teal infrastructure: { bg: '#ffedd5', border: '#f97316', text: '#c2410c' },// Orange education: { bg: '#dbeafe', border: '#3b82f6', text: '#1e40af' }, // Blue communication: { bg: '#dcfce7', border: '#22c55e', text: '#166534' }, // Green development: { bg: '#f1f5f9', border: '#64748b', text: '#334155' }, // Slate } const STUDIO_LABELS: Record = { navigation: 'Navigation', content: 'Content & Tools', communication: 'Kommunikation', school: 'Schulverwaltung', admin: 'Administration', ai: 'KI & Assistent', } // Labels from navigation.ts const ADMIN_LABELS: Record = { overview: 'Uebersicht & Meta', dsgvo: 'DSGVO', compliance: 'Compliance & GRC', ai: 'KI & Automatisierung', infrastructure: 'Infrastruktur & DevOps', education: 'Bildung & Schule', communication: 'Kommunikation & Alerts', development: 'Entwicklung & Produkte', } // ============================================ // HELPER: Find all connected nodes (recursive) // ============================================ function findConnectedNodes( startNodeId: string, connections: ConnectionDef[], direction: 'children' | 'parents' | 'both' = 'children' ): Set { const connected = new Set() connected.add(startNodeId) const queue = [startNodeId] while (queue.length > 0) { const current = queue.shift()! connections.forEach(conn => { if ((direction === 'children' || direction === 'both') && conn.source === current) { if (!connected.has(conn.target)) { connected.add(conn.target) queue.push(conn.target) } } if ((direction === 'parents' || direction === 'both') && conn.target === current) { if (!connected.has(conn.source)) { connected.add(conn.source) queue.push(conn.source) } } }) } return connected } // ============================================ // LAYOUT HELPERS // ============================================ const getNodePosition = ( id: string, category: string, screens: ScreenDefinition[], flowType: FlowType ) => { const studioPositions: Record = { navigation: { x: 400, y: 50 }, content: { x: 50, y: 250 }, communication: { x: 750, y: 250 }, school: { x: 50, y: 500 }, admin: { x: 750, y: 500 }, ai: { x: 400, y: 380 }, } const adminPositions: Record = { overview: { x: 400, y: 30 }, dsgvo: { x: 50, y: 150 }, compliance: { x: 700, y: 150 }, ai: { x: 50, y: 350 }, communication: { x: 400, y: 350 }, infrastructure: { x: 700, y: 350 }, education: { x: 50, y: 550 }, development: { x: 400, y: 550 }, } const positions = flowType === 'studio' ? studioPositions : adminPositions const base = positions[category] || { x: 400, y: 300 } const categoryScreens = screens.filter(s => s.category === category) const categoryIndex = categoryScreens.findIndex(s => s.id === id) const cols = Math.ceil(Math.sqrt(categoryScreens.length + 1)) const row = Math.floor(categoryIndex / cols) const col = categoryIndex % cols return { x: base.x + col * 160, y: base.y + row * 90, } } // ============================================ // MAIN COMPONENT // ============================================ export default function ScreenFlowPage() { const [flowType, setFlowType] = useState('admin') const [selectedCategory, setSelectedCategory] = useState(null) const [selectedNode, setSelectedNode] = useState(null) const [previewScreen, setPreviewScreen] = useState(null) // Get data based on flow type const screens = flowType === 'studio' ? STUDIO_SCREENS : ADMIN_SCREENS const connections = flowType === 'studio' ? STUDIO_CONNECTIONS : ADMIN_CONNECTIONS const colors = flowType === 'studio' ? STUDIO_COLORS : ADMIN_COLORS const labels = flowType === 'studio' ? STUDIO_LABELS : ADMIN_LABELS const baseUrl = flowType === 'studio' ? 'http://macmini:8000' : 'http://macmini:3002' // Calculate connected nodes const connectedNodes = useMemo(() => { if (!selectedNode) return new Set() return findConnectedNodes(selectedNode, connections, 'children') }, [selectedNode, connections]) // Create nodes with useMemo const initialNodes = useMemo((): Node[] => { return screens.map((screen) => { const catColors = colors[screen.category] || { bg: '#f1f5f9', border: '#94a3b8', text: '#475569' } const position = getNodePosition(screen.id, screen.category, screens, flowType) // Determine opacity let opacity = 1 if (selectedNode) { opacity = connectedNodes.has(screen.id) ? 1 : 0.2 } else if (selectedCategory) { opacity = screen.category === selectedCategory ? 1 : 0.2 } const isSelected = selectedNode === screen.id return { id: screen.id, type: 'default', position, data: { label: (
{screen.icon}
{screen.name}
), }, style: { background: isSelected ? catColors.border : catColors.bg, color: isSelected ? 'white' : catColors.text, border: `2px solid ${catColors.border}`, borderRadius: '12px', padding: '6px', minWidth: '110px', opacity, cursor: 'pointer', boxShadow: isSelected ? `0 0 20px ${catColors.border}` : 'none', }, } }) }, [screens, colors, flowType, selectedCategory, selectedNode, connectedNodes]) // Create edges with useMemo const initialEdges = useMemo((): Edge[] => { return connections.map((conn, index) => { const isHighlighted = selectedNode && (conn.source === selectedNode || conn.target === selectedNode) const isInSubtree = selectedNode && connectedNodes.has(conn.source) && connectedNodes.has(conn.target) return { id: `e-${conn.source}-${conn.target}-${index}`, source: conn.source, target: conn.target, label: conn.label, type: 'smoothstep', animated: isHighlighted || false, style: { stroke: isHighlighted ? '#3b82f6' : (isInSubtree ? '#94a3b8' : '#e2e8f0'), strokeWidth: isHighlighted ? 3 : 1.5, opacity: selectedNode ? (isInSubtree ? 1 : 0.15) : 1, }, labelStyle: { fontSize: 9, fill: '#64748b' }, labelBgStyle: { fill: '#f8fafc' }, markerEnd: { type: MarkerType.ArrowClosed, color: isHighlighted ? '#3b82f6' : '#94a3b8', width: 15, height: 15 }, } }) }, [connections, selectedNode, connectedNodes]) const [nodes, setNodes, onNodesChange] = useNodesState([]) const [edges, setEdges, onEdgesChange] = useEdgesState([]) // Update nodes/edges when dependencies change useEffect(() => { setNodes(initialNodes) setEdges(initialEdges) }, [initialNodes, initialEdges, setNodes, setEdges]) // Reset when flow type changes const handleFlowTypeChange = useCallback((newType: FlowType) => { setFlowType(newType) setSelectedNode(null) setSelectedCategory(null) setPreviewScreen(null) }, []) // Handle node click const onNodeClick = useCallback((_event: React.MouseEvent, node: Node) => { const screen = screens.find(s => s.id === node.id) if (selectedNode === node.id) { // Double-click: open in new tab if (screen?.url) { window.open(`${baseUrl}${screen.url}`, '_blank') } return } setSelectedNode(node.id) setSelectedCategory(null) if (screen) { setPreviewScreen(screen) } }, [screens, baseUrl, selectedNode]) // Handle background click - deselect const onPaneClick = useCallback(() => { setSelectedNode(null) setPreviewScreen(null) }, []) // Stats const stats = { totalScreens: screens.length, totalConnections: connections.length, connectedCount: connectedNodes.size, } const categories = Object.keys(labels) // Connected screens list const connectedScreens = selectedNode ? screens.filter(s => connectedNodes.has(s.id)) : [] return (
{/* Flow Type Selector */}
{/* Stats & Selection Info */}
{stats.totalScreens}
Screens
{stats.totalConnections}
Verbindungen
{selectedNode ? (
{previewScreen?.icon}
{previewScreen?.name}
{stats.connectedCount} verbundene Screen{stats.connectedCount !== 1 ? 's' : ''}
) : (
Klicke auf einen Screen um den Subtree zu sehen
)}
{/* Category Filter */}
{categories.map((key) => { const count = screens.filter(s => s.category === key).length const catColors = colors[key] || { bg: '#f1f5f9', border: '#94a3b8', text: '#475569' } return ( ) })}
{/* Connected Screens List */} {selectedNode && connectedScreens.length > 1 && (
Verbundene Screens:
{connectedScreens.map((screen) => { const catColors = colors[screen.category] || { bg: '#f1f5f9', border: '#94a3b8', text: '#475569' } const isCurrentNode = screen.id === selectedNode return ( ) })}
)} {/* Flow Diagram */}
{ const screen = screens.find(s => s.id === node.id) const catColors = screen ? colors[screen.category] : null return catColors?.border || '#94a3b8' }} maskColor="rgba(0, 0, 0, 0.1)" />
{flowType === 'studio' ? '๐ŸŽ“ Studio' : 'โš™๏ธ Admin v2'}
{categories.slice(0, 4).map((key) => { const catColors = colors[key] || { bg: '#f1f5f9', border: '#94a3b8' } return (
{labels[key]}
) })}
Klick = Subtree
Doppelklick = Oeffnen
{/* Screen List */}

Alle Screens ({screens.length})

{baseUrl}
{screens .filter(s => !selectedCategory || s.category === selectedCategory) .map((screen) => { const catColors = colors[screen.category] || { bg: '#f1f5f9', border: '#94a3b8', text: '#475569' } return ( ) })}
) }