wiki/implementation/Refactor Nyla UI basic components with new mandate SaaS model/analysis_and_implementation_plan.md
ValueOn AG 8fa4c870c7 upd
2026-01-23 21:05:15 +01:00

852 lines
26 KiB
Markdown

# 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 `<table>` |
| `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 (
<div className={styles.playgroundContainer}>
<div className={styles.chatSection}>
<div className={styles.chatColumns}>
{/* Links - Chat Messages (dynamische Breite) */}
<div
className={styles.chatLeft}
style={{ width: `${leftWidth}%` }}
>
<UnifiedContentArea />
</div>
{/* Resizable Divider */}
<div
className={`${styles.resizeDivider} ${isDragging ? styles.dragging : ''}`}
onMouseDown={handleMouseDown}
>
<div className={styles.dividerHandle} />
</div>
{/* Rechts - Dashboard (dynamische Breite) */}
<div
className={styles.chatRight}
style={{ width: `${100 - leftWidth}%` }}
>
<WorkflowDashboard />
</div>
</div>
</div>
<div className={styles.workflowFooter}>
<UserInputArea />
<DataStatistics />
</div>
</div>
);
};
```
#### 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<number>(() => {
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<HTMLElement | null>(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<number, {
operations: Map<string, Operation>;
rootOperations: string[];
expanded: boolean;
isCompleted: boolean;
}>;
operations: Map<string, {
logs: Map<string, LogEntry>;
parentId: string | null;
expanded: boolean;
latestProgress: number | null;
latestStatus: string | null;
roundNumber: number;
}>;
logExpandedStates: Map<string, boolean>;
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<WorkflowResponse>('/api/workflows/');
// Attributes vom Backend
const { data: attributesResponse } = useApi<AttributesResponse>('/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<Workflow>) => { /* ... */ },
};
};
```
#### 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 (
<div className={styles.page}>
<PageHeader title="Workflows" onRefresh={refetch} />
<FormGeneratorTable
data={workflows}
columns={columns}
loading={loading}
pagination={true}
actionButtons={[
{ type: 'edit', onAction: handleContinue },
{ type: 'delete' },
]}
customActions={[
{
id: 'continue',
icon: <FaPlay />,
onClick: handleContinue,
title: 'Workflow fortsetzen',
}
]}
onDelete={handleDelete}
hookData={{
refetch,
permissions,
pagination,
handleDelete,
handleInlineUpdate,
}}
/>
</div>
);
};
```
### 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<Entity | null>(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<Entity>) => {
const result = await handleCreate(data);
if (result.success) {
setShowCreateModal(false);
refetch();
}
};
const handleEditSubmit = async (data: Partial<Entity>) => {
if (!editingItem) return;
const result = await handleUpdate(editingItem.id, data);
if (result.success) {
setEditingItem(null);
refetch();
}
};
// Render
return (
<div className={styles.page}>
<PageHeader
title="Entities"
onRefresh={refetch}
onCreate={canCreate ? () => setShowCreateModal(true) : undefined}
/>
<FormGeneratorTable
data={data}
columns={columns}
loading={loading}
pagination={true}
actionButtons={[
...(canUpdate ? [{ type: 'edit', onAction: handleEditClick }] : []),
...(canDelete ? [{ type: 'delete' }] : []),
]}
onDelete={handleDelete}
hookData={{
refetch,
permissions,
pagination,
handleDelete,
handleInlineUpdate,
updateOptimistically,
}}
/>
{/* Create Modal */}
{showCreateModal && (
<Modal onClose={() => setShowCreateModal(false)}>
<FormGeneratorForm
attributes={formAttributes}
mode="create"
onSubmit={handleCreateSubmit}
onCancel={() => setShowCreateModal(false)}
/>
</Modal>
)}
{/* Edit Modal */}
{editingItem && (
<Modal onClose={() => setEditingItem(null)}>
<FormGeneratorForm
attributes={formAttributes}
data={editingItem}
mode="edit"
onSubmit={handleEditSubmit}
onCancel={() => setEditingItem(null)}
/>
</Modal>
)}
</div>
);
};
```
---
## 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*