From 46d39bad38511f87474bd128c54b7b0ad372801e Mon Sep 17 00:00:00 2001 From: Lars Date: Thu, 9 Apr 2026 12:58:03 +0200 Subject: [PATCH] feat: Part 2 - Workflow Frontend Execute Integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend-Komponenten für Workflow-Ausführung implementiert: **Neue Komponenten:** - WorkflowExecutePanel.jsx (~140 Zeilen) - Execute Button mit Loading State - Debug Mode Toggle - Error Handling Display - WorkflowResultViewer.jsx (~300 Zeilen) - Fixed Panel (rechts, 600px) - Final Output mit Copy-Button - Node States (collapsible, Debug Mode) - All Signals Display - Error Display **Integration:** - WorkflowEditorPage.jsx - ExecutePanel in Toolbar - executionResult State - handleExecutionComplete Handler - Slug wird beim Erstellen gespeichert **API:** - api.executeWorkflow(slug, variables, debug, save) - Nutzt /prompts/execute Endpoint - Debug Mode Default: true **Part 2 Status:** ~80% abgeschlossen - ✅ Execute Button - ✅ Result Viewer - ⏸️ Execution History (später entscheiden) Version: v0.9o Date: 2026-04-09 Co-Authored-By: Claude Opus 4.6 --- backend/version.py | 4 +- .../workflow/panels/WorkflowExecutePanel.jsx | 139 ++++++++ .../workflow/panels/WorkflowResultViewer.jsx | 303 ++++++++++++++++++ frontend/src/pages/WorkflowEditorPage.jsx | 26 +- frontend/src/utils/api.js | 10 + 5 files changed, 479 insertions(+), 3 deletions(-) create mode 100644 frontend/src/components/workflow/panels/WorkflowExecutePanel.jsx create mode 100644 frontend/src/components/workflow/panels/WorkflowResultViewer.jsx diff --git a/backend/version.py b/backend/version.py index abefb7c..14cd65c 100644 --- a/backend/version.py +++ b/backend/version.py @@ -7,8 +7,8 @@ Semantic Versioning: MAJOR.MINOR.PATCH - PATCH: Bugfix, kleine Änderung, Refactor """ -APP_VERSION = "0.9n" -BUILD_DATE = "2026-04-05" +APP_VERSION = "0.9o" +BUILD_DATE = "2026-04-09" DB_SCHEMA_VERSION = "20260406e" # Migration 041 MODULE_VERSIONS = { diff --git a/frontend/src/components/workflow/panels/WorkflowExecutePanel.jsx b/frontend/src/components/workflow/panels/WorkflowExecutePanel.jsx new file mode 100644 index 0000000..24096a4 --- /dev/null +++ b/frontend/src/components/workflow/panels/WorkflowExecutePanel.jsx @@ -0,0 +1,139 @@ +import { useState } from 'react' +import { api } from '../../../utils/api' + +/** + * WorkflowExecutePanel - Execution Controls für Workflow Editor + * + * Features: + * - Execute Button mit Loading State + * - Error Handling + * - Success State + * - Debug Mode Toggle + * + * Part 2: Frontend Execute Integration + */ +export function WorkflowExecutePanel({ + currentPrompt, + onExecutionComplete, + disabled = false +}) { + const [executing, setExecuting] = useState(false) + const [error, setError] = useState(null) + const [debugMode, setDebugMode] = useState(true) + + const handleExecute = async () => { + if (!currentPrompt || !currentPrompt.slug) { + setError('Workflow muss zuerst gespeichert werden (benötigt slug)') + return + } + + try { + setExecuting(true) + setError(null) + + console.log('🚀 Executing workflow:', currentPrompt.slug) + + const result = await api.executeWorkflow( + currentPrompt.slug, + null, // variables (später erweiterbar) + debugMode, + false // save (nicht in ai_insights speichern) + ) + + console.log('✅ Workflow execution completed:', result) + + // Success - kurze Bestätigung + if (result.status === 'completed') { + // Callback mit result + if (onExecutionComplete) { + onExecutionComplete(result) + } + } else if (result.status === 'failed') { + setError(result.error || 'Workflow-Ausführung fehlgeschlagen') + } + + } catch (e) { + console.error('❌ Workflow execution error:', e) + setError(e.message) + } finally { + setExecuting(false) + } + } + + return ( +
+ {/* Debug Mode Toggle */} + + + {/* Execute Button */} + + + {/* Error Display */} + {error && ( +
+ ❌ {error} +
+ )} +
+ ) +} diff --git a/frontend/src/components/workflow/panels/WorkflowResultViewer.jsx b/frontend/src/components/workflow/panels/WorkflowResultViewer.jsx new file mode 100644 index 0000000..add6aa5 --- /dev/null +++ b/frontend/src/components/workflow/panels/WorkflowResultViewer.jsx @@ -0,0 +1,303 @@ +import { useState } from 'react' + +/** + * WorkflowResultViewer - Zeigt Execution-Ergebnisse eines Workflows + * + * Features: + * - Aggregated Result (Final Output) + * - Node States (wenn Debug Mode aktiv) + * - Collapsible Sections + * - Copy to Clipboard + * + * Part 2: Frontend Execute Integration + */ +export function WorkflowResultViewer({ result, onClose }) { + const [expandedNodes, setExpandedNodes] = useState({}) + + if (!result) { + return null + } + + const toggleNode = (nodeId) => { + setExpandedNodes((prev) => ({ ...prev, [nodeId]: !prev[nodeId] })) + } + + const copyToClipboard = (text) => { + navigator.clipboard.writeText(text) + alert('In Zwischenablage kopiert') + } + + const aggregated = result.aggregated_result || {} + const nodeStates = result.node_states || [] + + return ( +
+ {/* Header */} +
+

+ Workflow-Ergebnis + {result.status === 'completed' && ( + + )} + {result.status === 'failed' && ( + + )} +

+ +
+ + {/* Content */} +
+ {/* Execution Info */} +
+
Execution ID: {result.execution_id}
+
Status: {result.status}
+ {aggregated.total_nodes && ( +
Nodes: {aggregated.executed_nodes}/{aggregated.total_nodes}
+ )} + {aggregated.failed_nodes > 0 && ( +
+ Failed Nodes: {aggregated.failed_nodes} +
+ )} +
+ + {/* Final Output */} +
+
+

+ Final Output +

+ {aggregated.analysis_core && ( + + )} +
+
+ {aggregated.analysis_core || aggregated.combined_analysis || '(Kein Output)'} +
+
+ + {/* All Signals */} + {aggregated.all_signals && aggregated.all_signals.length > 0 && ( +
+

+ All Signals ({aggregated.all_signals.length}) +

+
+ {aggregated.all_signals.map((signal, idx) => ( +
+ • {signal} +
+ ))} +
+
+ )} + + {/* Node States (Debug Info) */} + {nodeStates.length > 0 && ( +
+

+ Node States (Debug) +

+
+ {nodeStates.map((node) => ( +
+ {/* Node Header */} +
toggleNode(node.node_id)} + style={{ + padding: '10px 12px', + background: 'var(--surface2)', + cursor: 'pointer', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + fontSize: '13px', + fontWeight: 500 + }} + > +
+ {node.node_type === 'start' && '🚀'} + {node.node_type === 'analysis' && '🤖'} + {node.node_type === 'logic' && '⚡'} + {node.node_type === 'join' && '🔀'} + {node.node_type === 'end' && '🏁'} + {' '} + {node.node_label || node.node_id} + {node.status === 'skipped' && ( + + (skipped) + + )} +
+
+ {expandedNodes[node.node_id] ? '▼' : '▶'} +
+
+ + {/* Node Details */} + {expandedNodes[node.node_id] && ( +
+ {node.output && ( +
+ Output: +
+                            {typeof node.output === 'string'
+                              ? node.output
+                              : JSON.stringify(node.output, null, 2)}
+                          
+
+ )} + {node.error && ( +
+ Error: {node.error} +
+ )} + {node.metadata && ( +
+ Metadata: +
+                            {JSON.stringify(node.metadata, null, 2)}
+                          
+
+ )} +
+ )} +
+ ))} +
+
+ )} + + {/* Error (if failed) */} + {result.error && ( +
+ Error: {result.error} +
+ )} +
+
+ ) +} diff --git a/frontend/src/pages/WorkflowEditorPage.jsx b/frontend/src/pages/WorkflowEditorPage.jsx index 036f876..a761be2 100644 --- a/frontend/src/pages/WorkflowEditorPage.jsx +++ b/frontend/src/pages/WorkflowEditorPage.jsx @@ -14,6 +14,8 @@ import { QuestionAugmentationPanel } from '../components/workflow/panels/Questio import { LogicExpressionEditor } from '../components/workflow/panels/LogicExpressionEditor' import { FallbackConfig } from '../components/workflow/panels/FallbackConfig' import { JoinConfig } from '../components/workflow/panels/JoinConfig' +import { WorkflowExecutePanel } from '../components/workflow/panels/WorkflowExecutePanel' +import { WorkflowResultViewer } from '../components/workflow/panels/WorkflowResultViewer' import '../styles/workflowEditor.css' // Node-Type Mapping @@ -44,6 +46,7 @@ export default function WorkflowEditorPage() { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [availablePrompts, setAvailablePrompts] = useState([]) + const [executionResult, setExecutionResult] = useState(null) // Load available basis prompts for Analysis nodes useEffect(() => { @@ -156,7 +159,7 @@ export default function WorkflowEditorPage() { graph_data }) console.log('✅ Workflow created:', result) - setCurrentPrompt({ id: result.id, name: workflowName }) + setCurrentPrompt({ id: result.id, slug: result.slug, name: workflowName }) alert('Workflow erstellt!') console.log('🚀 Navigating to:', `/workflow-editor/${result.id}`) navigate(`/workflow-editor/${result.id}`) @@ -249,6 +252,11 @@ export default function WorkflowEditorPage() { } } + const handleExecutionComplete = (result) => { + console.log('🎯 Execution completed:', result) + setExecutionResult(result) + } + // ── Render ──────────────────────────────────────────────────────────────── return ( @@ -273,6 +281,14 @@ export default function WorkflowEditorPage() { + + {/* Execute Panel */} + 0} + /> +