mitai-jinkendo/frontend/src/components/workflow/panels/JoinConfig.jsx
Lars dc59596f01
Some checks failed
Deploy Development / deploy (push) Failing after 1s
Build Test / lint-backend (push) Successful in 1s
Build Test / build-frontend (push) Successful in 14s
feat: Phase 5 - Visual Workflow Editor (Option B)
Backend (Mini-Backend 1-2h):
- Migration 016: ai_prompts.graph_data JSONB column
- workflow_executor: graph_data parameter support (backward-compatible)
- prompt_executor: execute_workflow_prompt uses graph_data

Frontend (Main effort 25-35h):
- WorkflowCanvas: React Flow wrapper component
- 5 Custom Nodes: Start, End, Analysis, Logic, Join
- 4 Config Panels: QuestionAugmentation, LogicExpression, Fallback, Join
- workflowValidation: Structural + logical validation
- workflowSerializer: Canvas ↔ JSONB conversion
- WorkflowEditorPage: Main orchestration (420 LOC)
- Route: /workflow-editor/:id
- CSS: workflowEditor.css (300 LOC)

Architecture:
- Option B: ai_prompts.type='workflow' (not separate table)
- panels/ subdirectory for clean separation
- WorkflowCanvas reusable component
- User GUI identical (Workflows = Prompts)
- Backward-compatible (type='pipeline' unchanged)

Version: v0.9m → v0.9n (Phase 5 complete)
Module: workflow 0.5.0 → 0.6.0

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

68 lines
2.3 KiB
JavaScript

/**
* JoinConfig - Konfiguration für Join Nodes
*
* Props:
* - node: React Flow Node object (type='join')
* - onChange: (nodeId, updates) => void
*/
export function JoinConfig({ node, onChange }) {
const joinStrategy = node.data.join_strategy || 'wait_all'
const skipHandling = node.data.skip_handling || 'ignore_skipped'
const minPaths = node.data.min_paths || 2
const handleStrategyChange = (e) => {
onChange(node.id, { join_strategy: e.target.value })
}
const handleSkipChange = (e) => {
onChange(node.id, { skip_handling: e.target.value })
}
const handleMinPathsChange = (e) => {
const value = parseInt(e.target.value) || 2
onChange(node.id, { min_paths: value })
}
return (
<div className="config-section">
<h3>Join-Konfiguration</h3>
<label>Join-Strategie</label>
<select value={joinStrategy} onChange={handleStrategyChange}>
<option value="wait_all">Alle Pfade warten (wait_all)</option>
<option value="wait_any">Mindestens ein Pfad (wait_any)</option>
<option value="best_effort">Verfügbare nutzen (best_effort)</option>
</select>
<div className="help-text">
{joinStrategy === 'wait_all' && 'Wartet auf alle eingehenden Pfade. Fehler wenn einer fehlt.'}
{joinStrategy === 'wait_any' && 'Wartet auf mindestens einen Pfad. Erste verfügbare Ausführung.'}
{joinStrategy === 'best_effort' && 'Fehlertoleranz: Nutzt verfügbare Pfade, auch wenn nicht alle da sind.'}
</div>
<label style={{ marginTop: '16px' }}>Skip-Handling</label>
<select value={skipHandling} onChange={handleSkipChange}>
<option value="ignore_skipped">Übersprungene ignorieren</option>
<option value="use_placeholder">Platzhalter verwenden</option>
<option value="require_minimum">Mindestanzahl erforderlich</option>
</select>
{skipHandling === 'require_minimum' && (
<>
<label style={{ marginTop: '12px' }}>Mindestanzahl Pfade</label>
<input
type="number"
min="1"
value={minPaths}
onChange={handleMinPathsChange}
/>
</>
)}
<div className="help-text" style={{ marginTop: '8px', fontSize: '11px', color: 'var(--text3)' }}>
💡 Phase 4: Path Consolidation
</div>
</div>
)
}