130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
/**
|
|
* CanvasHeader - Workflow controls (Neu, Speichern, laden, Ausführen) and execute result.
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { FaCog, FaPlay, FaSpinner } from 'react-icons/fa';
|
|
import type { Automation2Workflow, ExecuteGraphResponse } from '../../../api/automation2Api';
|
|
import styles from './Automation2FlowEditor.module.css';
|
|
|
|
interface CanvasHeaderProps {
|
|
workflows: Automation2Workflow[];
|
|
currentWorkflowId: string | null;
|
|
onWorkflowSelect: (workflowId: string | null) => void;
|
|
onNew: () => void;
|
|
onSave: () => void;
|
|
onExecute: () => void;
|
|
onWorkflowSettings?: () => void;
|
|
saving: boolean;
|
|
executing: boolean;
|
|
hasNodes: boolean;
|
|
executeResult: ExecuteGraphResponse | null;
|
|
}
|
|
|
|
export const CanvasHeader: React.FC<CanvasHeaderProps> = ({
|
|
workflows,
|
|
currentWorkflowId,
|
|
onWorkflowSelect,
|
|
onNew,
|
|
onSave,
|
|
onExecute,
|
|
onWorkflowSettings,
|
|
saving,
|
|
executing,
|
|
hasNodes,
|
|
executeResult,
|
|
}) => (
|
|
<div className={styles.canvasHeader}>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }}>
|
|
<h4 className={styles.canvasTitle} style={{ margin: 0 }}>
|
|
Workflow-Editor
|
|
</h4>
|
|
{onWorkflowSettings && (
|
|
<button
|
|
type="button"
|
|
className={styles.canvasGearBtn}
|
|
title="Workflow-Konfiguration (Einstieg / Starts)"
|
|
aria-label="Workflow-Konfiguration"
|
|
onClick={onWorkflowSettings}
|
|
>
|
|
<FaCog />
|
|
</button>
|
|
)}
|
|
<button type="button" className={styles.retryButton} onClick={onNew}>
|
|
Neu
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className={styles.retryButton}
|
|
onClick={onSave}
|
|
disabled={saving || !hasNodes}
|
|
>
|
|
{saving ? <FaSpinner className={styles.spinner} /> : 'Speichern'}
|
|
</button>
|
|
<select
|
|
value={currentWorkflowId ?? ''}
|
|
onChange={(e) => {
|
|
const id = e.target.value ? e.target.value : null;
|
|
onWorkflowSelect(id);
|
|
}}
|
|
style={{ padding: '0.4rem', minWidth: 180 }}
|
|
>
|
|
<option value="">— Workflow laden —</option>
|
|
{workflows.map((w) => (
|
|
<option key={w.id} value={w.id}>
|
|
{w.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<button
|
|
type="button"
|
|
className={styles.retryButton}
|
|
onClick={onExecute}
|
|
disabled={executing || !hasNodes}
|
|
>
|
|
{executing ? (
|
|
<>
|
|
<FaSpinner className={styles.spinner} style={{ marginRight: '0.5rem', display: 'inline-block' }} />
|
|
Ausführen…
|
|
</>
|
|
) : (
|
|
<>
|
|
<FaPlay style={{ marginRight: '0.5rem' }} />
|
|
Ausführen
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
{executeResult && (
|
|
<div
|
|
style={{
|
|
marginTop: '0.5rem',
|
|
padding: '0.5rem',
|
|
borderRadius: 6,
|
|
fontSize: '0.875rem',
|
|
background: executeResult.success
|
|
? 'rgba(40,167,69,0.15)'
|
|
: (executeResult as { paused?: boolean }).paused
|
|
? 'rgba(0,123,255,0.15)'
|
|
: 'rgba(220,53,69,0.15)',
|
|
color: executeResult.success
|
|
? 'var(--success-color,#28a745)'
|
|
: (executeResult as { paused?: boolean }).paused
|
|
? 'var(--primary-color,#007bff)'
|
|
: 'var(--danger-color,#dc3545)',
|
|
}}
|
|
>
|
|
{executeResult.success ? (
|
|
<>✓ Ausführung abgeschlossen.</>
|
|
) : (executeResult as { paused?: boolean }).paused ? (
|
|
<>
|
|
⏸ Workflow pausiert. Öffne <strong>Workflows & Tasks</strong> in der Sidebar, um den
|
|
Task zu bearbeiten.
|
|
</>
|
|
) : (
|
|
<>✗ {executeResult.error ?? 'Unbekannter Fehler'}</>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|