# Refactor Nyla UI - Analyse und Implementation Plan ## Datum: 23. Januar 2026 --- ## Executive Summary Die Seiten **Chat Playground**, **Workflows**, **Automations**, **Prompts**, **Files** und **Connections** im neuen UI (`frontend_nyla`) sind inkomplett implementiert. Sie nutzen: - Eigene, vereinfachte Table-Komponenten statt des etablierten `FormGenerator`-Systems - Fehlende Dashboard- und Chat-Elemente (PlaygroundPage) - Keine RBAC-Berechtigungsprüfung - Keine Backend-Pagination/Sorting/Filtering - Keine standardisierten CRUD-Modals ### Design-Prinzipien für die Implementation > **WICHTIG:** Das bestehende Look & Feel von Nyla MUSS beibehalten werden! > > - Keine neuen Styles oder Design-Patterns einführen > - Bestehende CSS-Module und Komponenten-Styles wiederverwenden > - Nur **fehlende Logik ergänzen**, nicht das visuelle Design ändern > - Neue Komponenten müssen sich nahtlos in das bestehende Design einfügen --- ## 1. IST-Analyse ### 1.1 Chat Playground (PlaygroundPage.tsx) **Aktueller Zustand:** Die PlaygroundPage ist extrem vereinfacht und hat fast alle Funktionen aus dem alten UI (`frontend_agents`) verloren. **Was FEHLT (Vergleich zu `frontend_agents/public/htmlparts/part_workflow.html`):** | Element | Alt (frontend_agents) | Neu (frontend_nyla) | Ziel | |---------|----------------------|---------------------|------| | **Layout** | 70/30 Spalten (Chat/Dashboard) | Single-Column, kein Dashboard | **Resizable Spalten mit Drag-Divider** | | **Dashboard** | Hierarchisches Dashboard mit Rounds → Operations → Logs | ❌ Komplett fehlt | Logik portieren, Nyla-Styles | | **Progress-Tracking** | Progress-Bars pro Operation | ❌ Komplett fehlt | Logik portieren, Nyla-Styles | | **Collapse/Expand** | Für Rounds, Operations, Logs | ❌ Komplett fehlt | Logik portieren | | **Prompt-Auswahl** | Dropdown mit Prompts aus API | ❌ Fehlt | Bestehende DropdownSelect nutzen | | **Workflow-Modus** | Dropdown mit Enum aus Backend | ❌ Fehlt | Bestehende DropdownSelect nutzen | | **Datei-Upload** | Button + Drag & Drop, mehrere Dateien | ❌ Fehlt | Bestehende DragDropOverlay nutzen | | **Voice Recording** | Mikrofon-Button mit STT | ❌ Fehlt | Logik portieren, Nyla Button-Styles | | **Stop/Reset Buttons** | Stop, Reset, Refresh Tokens | Nur Läuft... Button | Bestehende Button-Komponenten | | **Data Statistics** | Sent/Received/Time/Tokens | ❌ Fehlt | Logik portieren, Nyla-Styles | | **File Preview Modal** | Vorschau, Download, Copy, TTS | ❌ Fehlt | Bestehende Popup-Komponente nutzen | | **Unified Content Area** | Kombinierte Logs + Messages chronologisch | Getrennte Listen | Bestehende Log/Messages nutzen | | **Auto-Scroll** | Automatisches Scrollen | ❌ Fehlt | Bestehende AutoScroll nutzen | | **Empty State** | Mit Link zur Einführung | Einfacher Text | Nyla-Styles | **Vorhandene Hooks im `frontend_nyla/src/hooks/playground/`:** ``` - useDashboardInputForm.ts - useDashboardLogTree.ts - useWorkflowLifecycle.ts - useWorkflowOperations.ts - useWorkflowPolling.ts - useWorkflows.ts - playgroundUtils.ts ``` **Problem:** Die Hooks sind vorhanden, aber die UI-Komponenten nutzen sie nicht vollständig! ### 1.2 Workflows, Automations, Prompts, Files, Connections **Aktueller Zustand:** Diese Seiten haben eigene, einfache Table-Implementierungen statt `FormGeneratorTable`. **Vergleich:** | Feature | AdminUsersPage (korrekt) | WorkflowsPage (falsch) | |---------|--------------------------|------------------------| | `FormGeneratorTable` | ✅ Verwendet | ❌ Eigene `` | | `FormGeneratorForm` | ✅ Für Create/Edit Modals | ❌ Keine Modals | | `attributes` vom Backend | ✅ Über Hook | ❌ Hardcoded Columns | | `columns` aus attributes | ✅ Dynamisch generiert | ❌ Hardcoded | | Backend-Pagination | ✅ Via hookData | ❌ Client-seitig | | Backend-Sorting | ✅ Via hookData | ❌ Client-seitig | | Backend-Filtering | ✅ Via hookData | ❌ Client-seitig | | Inline-Editing | ✅ Für Boolean-Felder | ❌ Nicht unterstützt | | RBAC Permissions | ✅ `permissions?.create !== 'n'` | ❌ Keine Prüfung | | Action Buttons | ✅ Standard + Custom | ❌ Nur Delete | | Loading State | ✅ Overlay | ❌ Einfacher Text | | Empty State | ✅ Mit Icon und CTA | ❌ Einfacher Text | | Error State | ✅ Mit Retry-Button | ❌ Einfacher Text | --- ## 2. Vorhandene Ressourcen im frontend_nyla ### 2.1 FormGenerator-System (vollständig implementiert) **Komponenten:** - `FormGeneratorTable` - Tabelle mit Pagination, Sorting, Filtering - `FormGeneratorForm` - Backend-driven Formulare - `FormGeneratorList` - Listenansicht - `FormGeneratorControls` - Such- und Filter-Controls - Action Buttons: Edit, Delete, View, Copy, Custom **Features:** - FK-Resolution (Foreign Keys anzeigen als Labels) - TextMultilingual-Support - Inline-Editing für Boolean-Felder - Column-Resizing mit LocalStorage-Persistenz - Multi-Column-Sorting ### 2.2 Vorhandene Hooks **Workflows:** - `useWorkflows.ts` - `useUserWorkflows()`, `useWorkflowOperations()` **Automations:** - `useAutomations.ts` - `useAutomations()`, `useAutomationOperations()` **Prompts:** - `usePrompts.ts` - `usePrompts()`, `usePromptOperations()` **Files:** - `useFiles.ts` - `useUserFiles()`, `useFileOperations()` **Connections:** - `useConnections.ts` - `useConnections()` (vollständig) **Playground-spezifisch:** - `hooks/playground/useDashboardInputForm.ts` - `hooks/playground/useDashboardLogTree.ts` - `hooks/playground/useWorkflowLifecycle.ts` - `hooks/playground/useWorkflowOperations.ts` - `hooks/playground/useWorkflowPolling.ts` ### 2.3 Bestehende Nyla UI-Komponenten (WIEDERVERWENDEN!) > **WICHTIG:** Diese Komponenten definieren das Nyla Look & Feel und sollten > bei der Implementation wiederverwendet werden! **UiComponents (in `components/UiComponents/`):** - `Button/` - Standard-Buttons, CreateButton, UploadButton - `TextField/` - Input-Felder - `DropdownSelect/` - Select-Komponente - `DragDropOverlay/` - Für File-Upload mit Drag & Drop - `Log/` - Log-Darstellung mit LogMessage - `Messages/` - Chat-Nachrichten - `Popup/` - Modal-Dialoge - `Toast/` - Notifications - `Tabs/` - Tab-Navigation - `AutoScroll/` - Auto-Scroll-Funktionalität **Diese Komponenten-Styles übernehmen:** - Farben (CSS-Variablen) - Typografie - Abstände/Padding - Border-Radien - Hover-/Focus-States --- ## 3. Implementation Plan ### Phase 1: Chat Playground (Priorität HOCH) #### 3.1.1 Layout-Refactoring **Datei:** `frontend_nyla/src/pages/workflows/PlaygroundPage.tsx` **Design-Prinzip:** Bestehendes Nyla Look & Feel beibehalten, nur fehlende Logik ergänzen! 1. **Resizable Spalten-Layout mit Drag-Divider:** Statt eines fixen 70/30-Layouts wird ein **dynamisch anpassbares Layout** implementiert: - Default: 70% Chat / 30% Dashboard - Benutzer kann die Trennlinie mit der Maus verschieben - Min/Max-Grenzen: Chat min 40%, Dashboard min 20% - Spaltenbreite wird in LocalStorage persistiert ```tsx import { useResizablePanels } from '../../hooks/useResizablePanels'; const PlaygroundPage: React.FC = () => { // Hook für resizable panels mit LocalStorage-Persistenz const { leftWidth, // in Prozent (default 70) isDragging, handleMouseDown, // Auf Divider anwenden } = useResizablePanels({ storageKey: 'playground-panel-width', defaultLeftWidth: 70, minLeftWidth: 40, maxLeftWidth: 80, }); return (
{/* Links - Chat Messages (dynamische Breite) */}
{/* Resizable Divider */}
{/* Rechts - Dashboard (dynamische Breite) */}
); }; ``` #### 3.1.1.1 Hook: useResizablePanels **Zu erstellen:** `frontend_nyla/src/hooks/useResizablePanels.ts` ```typescript import { useState, useCallback, useEffect, useRef } from 'react'; interface UseResizablePanelsOptions { storageKey: string; defaultLeftWidth: number; // in % minLeftWidth: number; // in % maxLeftWidth: number; // in % } export const useResizablePanels = ({ storageKey, defaultLeftWidth, minLeftWidth, maxLeftWidth, }: UseResizablePanelsOptions) => { // Initialer Wert aus LocalStorage oder Default const [leftWidth, setLeftWidth] = useState(() => { const stored = localStorage.getItem(storageKey); if (stored) { const parsed = parseFloat(stored); if (!isNaN(parsed) && parsed >= minLeftWidth && parsed <= maxLeftWidth) { return parsed; } } return defaultLeftWidth; }); const [isDragging, setIsDragging] = useState(false); const containerRef = useRef(null); // Mouse-Event-Handler const handleMouseDown = useCallback((e: React.MouseEvent) => { e.preventDefault(); setIsDragging(true); containerRef.current = (e.target as HTMLElement).closest('.chatColumns'); }, []); useEffect(() => { if (!isDragging) return; const handleMouseMove = (e: MouseEvent) => { if (!containerRef.current) return; const containerRect = containerRef.current.getBoundingClientRect(); const newLeftWidth = ((e.clientX - containerRect.left) / containerRect.width) * 100; // Clamp zwischen min und max const clampedWidth = Math.max(minLeftWidth, Math.min(maxLeftWidth, newLeftWidth)); setLeftWidth(clampedWidth); }; const handleMouseUp = () => { setIsDragging(false); // In LocalStorage speichern localStorage.setItem(storageKey, leftWidth.toString()); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; }, [isDragging, leftWidth, storageKey, minLeftWidth, maxLeftWidth]); return { leftWidth, isDragging, handleMouseDown, setLeftWidth, }; }; ``` #### 3.1.1.2 CSS für Resizable Divider **In `Playground.module.css` hinzufügen:** ```css /* Resizable Divider - passend zum Nyla Design */ .resizeDivider { width: 6px; cursor: col-resize; background-color: transparent; position: relative; flex-shrink: 0; z-index: 10; transition: background-color 0.15s ease; } .resizeDivider:hover, .resizeDivider.dragging { background-color: var(--color-border-hover, rgba(255, 255, 255, 0.1)); } .dividerHandle { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 4px; height: 40px; border-radius: 2px; background-color: var(--color-text-muted, rgba(255, 255, 255, 0.3)); opacity: 0; transition: opacity 0.15s ease; } .resizeDivider:hover .dividerHandle, .resizeDivider.dragging .dividerHandle { opacity: 1; } /* Verhindert Text-Selektion während Drag */ .chatColumns.dragging { user-select: none; } ``` #### 3.1.2 Neue Komponenten erstellen > **Design-Prinzip:** Alle neuen Komponenten müssen das bestehende Nyla Look & Feel nutzen! > - Bestehende CSS-Variablen verwenden (aus `:root` oder Theme) > - Vorhandene Button-/Input-Styles wiederverwenden > - Keine neuen Farbschemata oder Typografie einführen > - Komponenten-Styles in Module-CSS kapseln **Zu erstellen in `frontend_nyla/src/components/Playground/`:** | Komponente | Beschreibung | Logik basiert auf | Styles | |------------|--------------|-------------------|--------| | `WorkflowDashboard.tsx` | Hierarchisches Dashboard | `workflowUiRendererDashboard.js` | Nyla-Styles | | `UnifiedContentArea.tsx` | Kombinierte Logs + Messages | `workflowUiRenderer.js` | Nyla-Styles | | `UserInputArea.tsx` | Prompt-Auswahl, Input, Buttons | `part_workflow.html` | Bestehende Nyla Input-Styles | | `DataStatistics.tsx` | Sent/Received/Time/Tokens | `part_workflow.html` | Nyla-Styles | | `FilePreviewModal.tsx` | Datei-Vorschau | Existiert teilweise | Bestehende Modal-Styles | | `WorkflowControls.tsx` | Stop, Reset, Start Buttons | `workflowUiControls.js` | Bestehende Button-Styles | **Wichtig:** Diese Komponenten sollen die **Logik** aus dem alten `frontend_agents` übernehmen, aber das **visuelle Design** von Nyla beibehalten. Das heisst: - Hooks und State-Management aus `frontend_agents` portieren - CSS-Styles aus den bestehenden Nyla-Komponenten verwenden/erweitern #### 3.1.3 Dashboard Implementation **State-Struktur:** ```typescript interface DashboardLogTree { rounds: Map; rootOperations: string[]; expanded: boolean; isCompleted: boolean; }>; operations: Map; parentId: string | null; expanded: boolean; latestProgress: number | null; latestStatus: string | null; roundNumber: number; }>; logExpandedStates: Map; currentRound: number | null; } ``` **Verwendung von existierendem Hook:** ```typescript import { useDashboardLogTree } from '../../hooks/playground/useDashboardLogTree'; const { dashboardLogTree, processDashboardLogs, toggleRoundExpanded, toggleOperationExpanded, clearDashboard, } = useDashboardLogTree(); ``` #### 3.1.4 Input-Bereich Implementation **Neue Elemente:** - Prompt-Dropdown (aus `usePrompts()`) - Workflow-Modus-Dropdown (aus `/api/options/workflow.mode`) - File-Upload mit Drag & Drop - Voice-Recording-Button - Stop/Reset/Start-Buttons ### Phase 2-6: Data-Seiten (Workflows, Automations, Prompts, Files, Connections) > **Design-Prinzip für alle Data-Seiten:** > - `FormGeneratorTable` und `FormGeneratorForm` verwenden (bereits Nyla-konform) > - Bestehende Page-Header-Styles aus Admin-Seiten übernehmen > - Keine neuen Layouts/Designs einführen > - Nur fehlende Hooks/Logik ergänzen ### Phase 2: Workflows Page (Priorität HOCH) #### 3.2.1 Hook erweitern **Datei:** `frontend_nyla/src/hooks/useWorkflows.ts` Erweitern um: ```typescript export const useWorkflowsAdmin = () => { const { data, loading, error, refetch } = useApi('/api/workflows/'); // Attributes vom Backend const { data: attributesResponse } = useApi('/api/attributes/ChatWorkflow'); return { data: data?.items || [], attributes: attributesResponse?.attributes || [], columns: generateColumns(attributesResponse?.attributes), permissions: data?.permissions, pagination: data?.pagination, loading, error, refetch, // Operations handleDelete: async (id: string) => { /* ... */ }, handleInlineUpdate: async (id: string, data: Partial) => { /* ... */ }, }; }; ``` #### 3.2.2 Page umschreiben **Datei:** `frontend_nyla/src/pages/workflows/WorkflowsPage.tsx` Nach Pattern von `AdminUsersPage.tsx`: ```tsx import { FormGeneratorTable } from '../../components/FormGenerator'; import { useWorkflowsAdmin } from '../../hooks/useWorkflows'; export const WorkflowsPage: React.FC = () => { const { data: workflows, attributes, columns, permissions, pagination, loading, error, refetch, handleDelete, handleInlineUpdate, } = useWorkflowsAdmin(); return (
, onClick: handleContinue, title: 'Workflow fortsetzen', } ]} onDelete={handleDelete} hookData={{ refetch, permissions, pagination, handleDelete, handleInlineUpdate, }} />
); }; ``` ### Phase 3: Automations Page **Analog zu Workflows Page:** 1. Hook erweitern: `useAutomationsAdmin()` 2. Page umschreiben mit `FormGeneratorTable` 3. Custom Actions: Execute, Toggle Active ### Phase 4: Prompts Page **Spezifische Anpassungen:** 1. Hook erweitern: `usePromptsAdmin()` 2. Page umschreiben mit `FormGeneratorTable` 3. Create/Edit Modal mit `FormGeneratorForm` 4. Content-Feld als Textarea ### Phase 5: Files Page **Spezifische Anpassungen:** 1. Hook erweitern: `useFilesAdmin()` 2. Page umschreiben mit `FormGeneratorTable` 3. Custom Actions: Download, Preview 4. Upload-Button mit `UploadButton`-Komponente ### Phase 6: Connections Page **Spezifische Anpassungen:** 1. Hook erweitern: `useConnectionsAdmin()` 2. Page umschreiben mit `FormGeneratorTable` 3. Custom Actions: Connect, Refresh Token 4. Provider-spezifische Buttons (Google, Microsoft) --- ## 4. Detaillierte Änderungsliste ### 4.1 Zu erstellende Dateien ``` frontend_nyla/src/ ├── hooks/ │ └── useResizablePanels.ts # NEU: Hook für resizable panels ├── components/ │ └── Playground/ │ ├── index.ts │ ├── Playground.module.css # NEU: Layout-Styles inkl. Divider │ ├── WorkflowDashboard/ │ │ ├── index.ts │ │ ├── WorkflowDashboard.tsx # Logik aus workflowUiRendererDashboard.js │ │ ├── WorkflowDashboard.module.css │ │ ├── DashboardRound.tsx │ │ ├── DashboardOperation.tsx │ │ └── DashboardProgressBar.tsx │ ├── UnifiedContentArea/ │ │ ├── index.ts │ │ ├── UnifiedContentArea.tsx # Logik aus workflowUiRenderer.js │ │ ├── UnifiedContentArea.module.css │ │ ├── MessageItem.tsx │ │ └── LogItem.tsx │ ├── UserInputArea/ │ │ ├── index.ts │ │ ├── UserInputArea.tsx # Logik aus workflow.js + part_workflow.html │ │ ├── UserInputArea.module.css │ │ ├── PromptSelector.tsx │ │ ├── WorkflowModeSelector.tsx │ │ └── VoiceRecordButton.tsx │ ├── WorkflowControls/ │ │ ├── index.ts │ │ ├── WorkflowControls.tsx # Logik aus workflowUiControls.js │ │ └── WorkflowControls.module.css │ └── DataStatistics/ │ ├── index.ts │ ├── DataStatistics.tsx │ └── DataStatistics.module.css ``` > **Hinweis:** Alle `.module.css` Dateien sollen bestehende Nyla CSS-Variablen nutzen > und sich nahtlos ins bestehende Design einfügen! ### 4.2 Zu ändernde Dateien | Datei | Änderung | |-------|----------| | `pages/workflows/PlaygroundPage.tsx` | Kompletter Rewrite mit neuen Komponenten | | `pages/workflows/WorkflowsPage.tsx` | Umschreiben auf FormGeneratorTable | | `pages/workflows/AutomationsPage.tsx` | Umschreiben auf FormGeneratorTable | | `pages/basedata/PromptsPage.tsx` | Umschreiben auf FormGeneratorTable | | `pages/basedata/FilesPage.tsx` | Umschreiben auf FormGeneratorTable | | `pages/basedata/ConnectionsPage.tsx` | Umschreiben auf FormGeneratorTable | | `hooks/useWorkflows.ts` | Admin-Hook hinzufügen | | `hooks/useAutomations.ts` | Admin-Hook hinzufügen | | `hooks/usePrompts.ts` | Admin-Hook hinzufügen | | `hooks/useFiles.ts` | Admin-Hook hinzufügen | | `hooks/useConnections.ts` | Admin-Hook hinzufügen | ### 4.3 CSS-Anpassungen **Neue CSS-Module:** - `Playground.module.css` - Hauptlayout - `WorkflowDashboard.module.css` - Dashboard-Styles - `UnifiedContentArea.module.css` - Content-Styles **Bestehende zu aktualisieren:** - `WorkflowPages.module.css` - Für alle Workflow-Seiten --- ## 5. API-Endpunkte (bereits vorhanden) | Endpunkt | Verwendung | |----------|------------| | `/api/workflows/` | Liste, CRUD | | `/api/workflows/{id}` | Einzelner Workflow | | `/api/workflows/{id}/chat-data` | Unified Chat-Daten | | `/api/automations/` | Liste, CRUD | | `/api/prompts/` | Liste, CRUD | | `/api/files/` | Liste, CRUD | | `/api/connections/` | Liste, CRUD | | `/api/attributes/{EntityType}` | Attribute-Definitionen | | `/api/options/workflow.mode` | Workflow-Modus-Enum | --- ## 6. Migrations-Checkliste ### Chat Playground - [ ] `useResizablePanels` Hook erstellen - [ ] Resizable Spalten-Layout implementieren (mit Drag-Divider) - [ ] WorkflowDashboard-Komponente erstellen (Logik aus frontend_agents, Nyla-Styles) - [ ] UnifiedContentArea-Komponente erstellen (Logik aus frontend_agents, Nyla-Styles) - [ ] UserInputArea mit allen Features erstellen (Nyla Input-Styles) - [ ] DataStatistics-Komponente erstellen (Nyla-Styles) - [ ] Polling integrieren (bestehende Hooks nutzen) - [ ] File-Upload mit Drag & Drop (bestehende DragDropOverlay nutzen) - [ ] Voice-Recording integrieren - [ ] LocalStorage-Persistenz für Panel-Breite ### Workflows Page - [ ] Hook `useWorkflowsAdmin` erstellen - [ ] Page auf FormGeneratorTable umstellen - [ ] Action Buttons konfigurieren - [ ] RBAC-Permissions implementieren ### Automations Page - [ ] Hook `useAutomationsAdmin` erstellen - [ ] Page auf FormGeneratorTable umstellen - [ ] Toggle Active implementieren - [ ] Execute-Action implementieren ### Prompts Page - [ ] Hook `usePromptsAdmin` erstellen - [ ] Page auf FormGeneratorTable umstellen - [ ] Create/Edit Modals mit FormGeneratorForm - [ ] Content-Textarea korrekt anzeigen ### Files Page - [ ] Hook `useFilesAdmin` erstellen - [ ] Page auf FormGeneratorTable umstellen - [ ] Download/Preview Actions - [ ] Upload-Button integrieren ### Connections Page - [ ] Hook `useConnectionsAdmin` erstellen - [ ] Page auf FormGeneratorTable umstellen - [ ] Connect/Refresh Actions - [ ] Provider-spezifische Buttons --- ## 7. Schätzung Aufwand | Phase | Aufwand | Priorität | |-------|---------|-----------| | Phase 1: Chat Playground | Hoch | KRITISCH | | Phase 2: Workflows Page | Mittel | Hoch | | Phase 3: Automations Page | Mittel | Hoch | | Phase 4: Prompts Page | Niedrig | Mittel | | Phase 5: Files Page | Niedrig | Mittel | | Phase 6: Connections Page | Niedrig | Mittel | --- ## 8. Anhang: Pattern-Referenz ### Standard-Page-Struktur ```tsx import React, { useState, useMemo } from 'react'; import { FormGeneratorTable, FormGeneratorForm } from '../../components/FormGenerator'; import { useEntityAdmin, useEntityOperations } from '../../hooks/useEntity'; import styles from './Page.module.css'; interface Entity { id: string; [key: string]: any; } export const EntityPage: React.FC = () => { // Hooks const { data, attributes, columns, permissions, pagination, loading, error, refetch, fetchById, handleInlineUpdate, updateOptimistically, } = useEntityAdmin(); const { handleCreate, handleUpdate, handleDelete, } = useEntityOperations(); // State const [showCreateModal, setShowCreateModal] = useState(false); const [editingItem, setEditingItem] = useState(null); // Permissions const canCreate = permissions?.create !== 'n'; const canUpdate = permissions?.update !== 'n'; const canDelete = permissions?.delete !== 'n'; // Form Attributes const formAttributes = useMemo(() => { return (attributes || []).filter(attr => !['id'].includes(attr.name)); }, [attributes]); // Handlers const handleEditClick = async (item: Entity) => { const fullItem = await fetchById(item.id); if (fullItem) setEditingItem(fullItem); }; const handleCreateSubmit = async (data: Partial) => { const result = await handleCreate(data); if (result.success) { setShowCreateModal(false); refetch(); } }; const handleEditSubmit = async (data: Partial) => { if (!editingItem) return; const result = await handleUpdate(editingItem.id, data); if (result.success) { setEditingItem(null); refetch(); } }; // Render return (
setShowCreateModal(true) : undefined} /> {/* Create Modal */} {showCreateModal && ( setShowCreateModal(false)}> setShowCreateModal(false)} /> )} {/* Edit Modal */} {editingItem && ( setEditingItem(null)}> setEditingItem(null)} /> )}
); }; ``` --- ## 9. Design-Konsistenz-Checklist Bei jeder Implementation prüfen: - [ ] **CSS-Variablen:** Werden bestehende Nyla CSS-Variablen verwendet? (Farben, Abstände, etc.) - [ ] **Komponenten:** Werden bestehende UiComponents wiederverwendet wo möglich? - [ ] **Styles:** Sind neue Styles konsistent mit bestehendem Nyla-Design? - [ ] **Keine Neuerungen:** Wurden keine neuen Design-Patterns eingeführt? - [ ] **Dark/Light Mode:** Funktioniert die Komponente in beiden Modi? - [ ] **Responsive:** Funktioniert die Komponente auf verschiedenen Bildschirmgrössen? --- *Dokumentation erstellt am 23. Januar 2026* *Aktualisiert: Resizable Panels und Design-Prinzipien hinzugefügt*