ui-nyla/src/components/FlowEditor/editor/WorkflowConfigurationModal.tsx
2026-04-11 19:44:52 +02:00

123 lines
4.3 KiB
TypeScript

/**
* Workflow configuration — primary start kind drives the canvas start node.
*/
import React, { useState, useEffect } from 'react';
import type { WorkflowEntryPoint } from '../../../api/workflowApi';
import {
getPrimaryStartKind,
buildInvocationsForPrimaryKind,
} from '../nodes/runtime/workflowStartSync';
import styles from './Automation2FlowEditor.module.css';
import { useLanguage } from '../../../providers/language/LanguageContext';
/** Vier Einstiege; bei „Immer aktiv“ folgt später die Listener-Konfiguration (E-Mail, Webhook, …). */
function _getKindOptions(t: (key: string) => string): { value: string; label: string }[] {
return [
{ value: 'manual', label: t('Manueller Trigger') },
{ value: 'form', label: t('Formular') },
{ value: 'schedule', label: t('Zeitplan') },
{ value: 'always_on', label: t('Immer aktiv') },
];
}
interface WorkflowConfigurationModalProps {
open: boolean;
onClose: () => void;
invocations: WorkflowEntryPoint[];
onApply: (next: WorkflowEntryPoint[]) => void;
}
const _validKinds = ['manual', 'form', 'schedule', 'always_on'];
function normalizeLoadedKind(k: string): string {
if (_validKinds.includes(k)) return k;
if (['email', 'webhook', 'event'].includes(k)) return 'always_on';
if (k === 'api') return 'manual';
return 'manual';
}
export const WorkflowConfigurationModal: React.FC<WorkflowConfigurationModalProps> = ({ open,
onClose,
invocations,
onApply,
}) => {
const { t } = useLanguage();
const kindOptions = _getKindOptions(t);
const [kind, setKind] = useState(() => normalizeLoadedKind(getPrimaryStartKind(invocations)));
const [titleDe, setTitleDe] = useState('');
useEffect(() => {
if (!open) return;
const k = normalizeLoadedKind(getPrimaryStartKind(invocations));
setKind(k);
const entry = invocations[0];
const entryTitle = entry?.title;
if (typeof entryTitle === 'string') setTitleDe(entryTitle);
else if (entryTitle && typeof entryTitle === 'object') setTitleDe(entryTitle.de || entryTitle.en || '');
else setTitleDe('');
}, [open, invocations]);
if (!open) return null;
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const label =
titleDe.trim() || kindOptions.find((o) => o.value === kind)?.label || t('Start');
const next = buildInvocationsForPrimaryKind(kind, invocations, label);
onApply(next);
onClose();
};
return (
<div className={styles.workflowModalBackdrop} role="dialog" aria-modal="true" aria-labelledby="wf-cfg-title">
<div className={styles.workflowModal}>
<h3 id="wf-cfg-title" className={styles.workflowModalTitle}>
{t('Workflow-Konfiguration')}
</h3>
<p className={styles.workflowModalHint}>
{t(
'Legen Sie fest, wie dieser Workflow gestartet werden soll. Die Start-Node im Editor passt sich dem gewählten Einstieg an (z. B. Formular-Felder auf der Start-Node bearbeiten).'
)}
</p>
<form onSubmit={handleSubmit}>
<label className={styles.workflowModalLabel} htmlFor="wf-start-title">
{t('Titel der Start Node')}
</label>
<input
id="wf-start-title"
className={styles.workflowModalInput}
value={titleDe}
onChange={(e) => setTitleDe(e.target.value)}
placeholder={t('z.B. Angebot anlegen')}
/>
<div className={styles.workflowModalRadioGroup} role="radiogroup" aria-label={t('Einstiegsart')}>
{kindOptions.map((o) => (
<label key={o.value} className={styles.workflowModalRadio}>
<input
type="radio"
name="kind"
value={o.value}
checked={kind === o.value}
onChange={() => setKind(o.value)}
/>
{o.label}
</label>
))}
</div>
<div className={styles.workflowModalActions}>
<button type="button" className={styles.workflowModalBtnSecondary} onClick={onClose}>
{t('Abbrechen')}
</button>
<button type="submit" className={styles.workflowModalBtnPrimary}>
{t('Übernehmen')}
</button>
</div>
</form>
</div>
</div>
);
};