@@ -649,9 +642,9 @@ export default function Analysis() {
{canUseAI && pipelinePrompts.length === 0 && (
-
Keine aktiven Pipeline-Prompts verfügbar.
+
Keine aktiven Pipeline- oder Workflow-Auswertungen verfügbar.
- Erstelle Pipeline-Prompts im Admin-Bereich unter Admin → KI-Prompts.
+ Pipelines und Workflows werden im Admin unter KI-Prompts bzw. Workflow-Editor angelegt.
)}
@@ -675,7 +668,10 @@ export default function Analysis() {
onClick={() => setHistoryScopePick(scope)}
aria-current={activeHistoryScope === scope ? 'page' : undefined}
>
- {prompts.find(pr => pr.slug === scope)?.display_name || SLUG_LABELS[scope] || scope}
+ {(() => {
+ const pr = prompts.find((p) => p.slug === scope)
+ return pr?.display_name || pr?.name || SLUG_LABELS[scope] || scope
+ })()}
({grouped[scope].length})
))}
diff --git a/frontend/src/pages/WorkflowEditorPage.jsx b/frontend/src/pages/WorkflowEditorPage.jsx
index c85f23b..42a875a 100644
--- a/frontend/src/pages/WorkflowEditorPage.jsx
+++ b/frontend/src/pages/WorkflowEditorPage.jsx
@@ -22,6 +22,28 @@ import { InlineTemplateEditor } from '../components/workflow/panels/InlineTempla
import { Toast } from '../components/Toast'
import { ConfirmDialog } from '../components/ConfirmDialog'
import '../styles/workflowEditor.css'
+import {
+ ANALYSIS_CATEGORY_ORDER,
+ ANALYSIS_CATEGORY_LABELS,
+} from '../config/analysisCategories'
+
+/** Aus Start-Node → Felder für Analyse-UI / ai_prompts (display_name, description, category) */
+function getWorkflowAnalysisPublishFields(nodes, fallbackName) {
+ const start = nodes.find((n) => n.type === 'start')
+ const d = start?.data || {}
+ const title =
+ String(d.analysis_title ?? '').trim() ||
+ String(fallbackName ?? '').trim() ||
+ 'Workflow'
+ const description = String(d.analysis_description ?? '').trim()
+ const category =
+ String(d.analysis_category ?? 'ganzheitlich').toLowerCase().trim() || 'ganzheitlich'
+ return {
+ display_name: title,
+ description: description || null,
+ category,
+ }
+}
// Node-Type Mapping
const nodeTypes = {
@@ -45,7 +67,6 @@ export default function WorkflowEditorPage() {
const selectedNode = selectedNodeId ? nodes.find(n => n.id === selectedNodeId) : null
const [currentPrompt, setCurrentPrompt] = useState(null)
const [workflowName, setWorkflowName] = useState('Neuer Workflow')
- const [workflowDescription, setWorkflowDescription] = useState('')
const [validationErrors, setValidationErrors] = useState([])
const [validationWarnings, setValidationWarnings] = useState([])
const [loading, setLoading] = useState(false)
@@ -103,16 +124,26 @@ export default function WorkflowEditorPage() {
}, [])
const handleAddNode = (nodeType) => {
- const newNode = {
+ const base = {
id: `node_${nodeIdCounter++}`,
type: nodeType,
position: { x: 250, y: 100 + nodes.length * 100 },
data: {
- label: `${nodeType.charAt(0).toUpperCase() + nodeType.slice(1)} ${nodeIdCounter - 1}`
+ label: `${nodeType.charAt(0).toUpperCase() + nodeType.slice(1)} ${nodeIdCounter - 1}`,
+ },
+ }
+ if (nodeType === 'start') {
+ base.data = {
+ label: 'Start',
+ analysis_title:
+ workflowName && workflowName !== 'Neuer Workflow'
+ ? workflowName
+ : '',
+ analysis_description: '',
+ analysis_category: 'ganzheitlich',
}
}
-
- setNodes((nds) => [...nds, newNode])
+ setNodes((nds) => [...nds, base])
}
const handleNodeUpdate = (nodeId, updates) => {
@@ -152,13 +183,20 @@ export default function WorkflowEditorPage() {
})
console.log('📊 Serialized graph_data:', graph_data)
+ const { display_name, description, category } = getWorkflowAnalysisPublishFields(
+ nodes,
+ workflowName
+ )
+
if (currentPrompt) {
// Update existing
console.log('📝 Updating existing workflow:', currentPrompt.id)
await api.updateUnifiedPrompt(currentPrompt.id, {
type: 'workflow',
name: workflowName,
- description: workflowDescription,
+ display_name,
+ description: description ?? undefined,
+ category,
graph_data
})
setToast({ message: '✅ Workflow gespeichert!', type: 'success' })
@@ -168,7 +206,9 @@ export default function WorkflowEditorPage() {
const result = await api.createUnifiedPrompt({
type: 'workflow',
name: workflowName,
- description: workflowDescription,
+ display_name,
+ description: description ?? undefined,
+ category,
graph_data
})
console.log('✅ Workflow created:', result)
@@ -203,11 +243,30 @@ export default function WorkflowEditorPage() {
const { nodes: loadedNodes, edges: loadedEdges } = deserializeFromWorkflowGraph(prompt.graph_data)
console.log('🎯 Deserialized:', { nodes: loadedNodes, edges: loadedEdges })
- setNodes(loadedNodes)
+ const mergedNodes = loadedNodes.map((n) => {
+ if (n.type !== 'start') return n
+ const hasStoredTitle = Object.prototype.hasOwnProperty.call(n.data || {}, 'analysis_title')
+ return {
+ ...n,
+ data: {
+ label: n.data?.label || 'Start',
+ ...n.data,
+ analysis_title: hasStoredTitle
+ ? n.data.analysis_title
+ : (prompt.display_name || prompt.name || ''),
+ analysis_description: Object.prototype.hasOwnProperty.call(n.data || {}, 'analysis_description')
+ ? n.data.analysis_description
+ : (prompt.description || ''),
+ analysis_category:
+ (n.data?.analysis_category || prompt.category || 'ganzheitlich').toLowerCase(),
+ },
+ }
+ })
+
+ setNodes(mergedNodes)
setEdges(loadedEdges)
setCurrentPrompt(prompt)
setWorkflowName(prompt.name)
- setWorkflowDescription(prompt.description || '')
// nodeIdCounter aktualisieren
const maxId = Math.max(
@@ -242,7 +301,6 @@ export default function WorkflowEditorPage() {
setEdges([])
setCurrentPrompt(null)
setWorkflowName('Neuer Workflow')
- setWorkflowDescription('')
setSelectedNodeId(null)
navigate('/workflow-editor/new')
}
@@ -342,7 +400,8 @@ export default function WorkflowEditorPage() {
type="text"
value={workflowName}
onChange={(e) => setWorkflowName(e.target.value)}
- placeholder="Workflow-Name"
+ placeholder="Interner Workflow-Name (Slug-Basis)"
+ title="Technischer Name in der Datenbank. Den sichtbaren Titel für die KI-Analyse setzt du in der Start-Node."
style={{ flex: 1, padding: '8px', borderRadius: '4px', border: '1px solid var(--border)' }}
/>
@@ -495,9 +554,88 @@ export default function WorkflowEditorPage() {
)}
+ {/* Start-Node: Metadaten für KI-Analyse (wie Pipeline: display_name, description, category) */}
+ {selectedNode.type === 'start' && (
+
+
Anzeige in KI-Analyse
+
+ Titel, Kurzbeschreibung und Kategorie erscheinen auf der Analyse-Seite, im Verlauf und in der
+ Kategorie-Navigation – analog zu Pipeline-Prompts im Admin.
+
+
+ Titel (sichtbar für Nutzer)
+
+
+ handleNodeUpdate(selectedNode.id, { analysis_title: e.target.value })
+ }
+ placeholder="z. B. Ganzheitliche Auswertung"
+ style={{
+ width: '100%',
+ padding: '8px',
+ borderRadius: '4px',
+ border: '1px solid var(--border)',
+ background: 'var(--surface)',
+ color: 'var(--text1)',
+ fontSize: '14px',
+ marginBottom: 12,
+ }}
+ />
+
+ Kurzbeschreibung (optional)
+
+