mitai-jinkendo/frontend/src/components/workflow/panels/InlineTemplateEditor.jsx
Lars a1723db387
Some checks failed
Deploy Development / deploy (push) Successful in 56s
Build Test / pytest-backend (push) Failing after 4s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
feat: Workflow Engine Part 3 - Inline Prompts (v0.9q)
Ermöglicht Analysis Nodes zwischen zwei Prompt-Modi zu wählen:
- Reference Mode: Basis-Prompt aus DB referenzieren (bestehend)
- Inline Mode: Template direkt im Node editieren (NEU)

Frontend:
- InlineTemplateEditor Component (~80 Zeilen)
- Radio Buttons in WorkflowEditorPage für Mode-Auswahl
- Placeholder Picker für beide Modi (End Node + Inline Template)
- Cursor-Position Tracking mit textareaRef
- Conditional Rendering basierend auf promptSource
- Validation: Entweder prompt_slug ODER inline_template

Backend:
- load_prompt_template() akzeptiert ganzen WorkflowNode (statt nur slug)
- Unterstützt inline_template (Mode 1) und prompt_slug (Mode 2)
- WorkflowNode.inline_template Feld hinzugefügt
- Validation: HTTPException wenn weder slug noch template

Serialization:
- inline_template in graph_data speichern/laden
- Backward-compatible mit bestehenden Workflows

Version: 0.9q
Module: workflow 0.7.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:45:00 +02:00

70 lines
2.1 KiB
JavaScript

import { useRef } from 'react'
/**
* InlineTemplateEditor - Template-Editor für Inline-Prompts
*
* Props:
* - value: Template-String
* - onChange: (template) => void
* - onPlaceholderPick: () => void - Öffnet Placeholder Picker
* - textareaRef: Ref für Cursor-Position (von Parent)
*/
export function InlineTemplateEditor({ value, onChange, onPlaceholderPick, textareaRef }) {
return (
<div className="inline-template-editor" style={{ marginTop: '12px' }}>
<label className="form-label">Template</label>
<div style={{ position: 'relative' }}>
<textarea
ref={textareaRef}
value={value || ''}
onChange={(e) => onChange(e.target.value)}
placeholder="Analysiere folgende Daten:&#10;&#10;Gewicht: {{ weight_current }}&#10;Ziel: {{ goal_weight }}&#10;&#10;Gib eine Empfehlung..."
rows={12}
style={{
width: '100%',
fontFamily: 'monospace',
fontSize: '13px',
padding: '12px',
paddingRight: '120px', // Platz für Button
borderRadius: '8px',
border: '1px solid var(--border)',
background: 'var(--bg)',
color: 'var(--text1)',
resize: 'vertical',
lineHeight: '1.5'
}}
/>
<button
className="btn-secondary"
onClick={onPlaceholderPick}
style={{
position: 'absolute',
top: '8px',
right: '8px',
fontSize: '11px',
padding: '6px 10px',
whiteSpace: 'nowrap'
}}
>
{'{{ }}'} Platzhalter
</button>
</div>
<div
className="help-text"
style={{
fontSize: '12px',
color: 'var(--text3)',
marginTop: '6px'
}}
>
💡 Tipp: Verwende <code style={{
background: 'var(--surface2)',
padding: '2px 6px',
borderRadius: '4px',
fontFamily: 'monospace'
}}>{'{{ placeholder_name }}'}</code> für dynamische Werte
</div>
</div>
)
}