/** * Form node config - draggable fields, types, required toggle */ import React, { useEffect, useState } from 'react'; import { FaGripVertical, FaTimes } from 'react-icons/fa'; import type { FormField, NodeConfigRendererProps } from '../shared/types'; import { fetchConnections, type UserConnection } from '../../../../api/workflowApi'; import styles from '../../editor/Automation2FlowEditor.module.css'; import { useLanguage } from '../../../../providers/language/LanguageContext'; export const FormNodeConfig: React.FC = ({ params, updateParam, instanceId, request, }) => { const { t } = useLanguage(); const fields = (params.fields as FormField[]) ?? []; const [connections, setConnections] = useState([]); const [connectionsLoading, setConnectionsLoading] = useState(false); useEffect(() => { if (!instanceId || !request) { setConnections([]); return; } let cancelled = false; setConnectionsLoading(true); fetchConnections(request, instanceId) .then((rows) => { if (!cancelled) setConnections(rows.filter((c) => c.authority === 'clickup')); }) .catch(() => { if (!cancelled) setConnections([]); }) .finally(() => { if (!cancelled) setConnectionsLoading(false); }); return () => { cancelled = true; }; }, [instanceId, request]); const moveField = (fromIndex: number, toIndex: number) => { if (fromIndex < 0 || toIndex < 0 || fromIndex >= fields.length || toIndex >= fields.length) return; const next = [...fields]; const [removed] = next.splice(fromIndex, 1); next.splice(toIndex, 0, removed); updateParam('fields', next); }; const removeField = (index: number) => { const next = fields.filter((_, i) => i !== index); updateParam('fields', next); }; return (
{fields.map((f, i) => (
{ e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }} onDrop={(e) => { e.preventDefault(); const from = parseInt(e.dataTransfer.getData('text/plain'), 10); if (!Number.isNaN(from) && from !== i) moveField(from, i); }} >
{ e.dataTransfer.setData('text/plain', String(i)); e.dataTransfer.effectAllowed = 'move'; }} >
{ const next = [...fields]; next[i] = { ...next[i], name: e.target.value }; updateParam('fields', next); }} /> { const next = [...fields]; next[i] = { ...next[i], label: e.target.value }; updateParam('fields', next); }} />
{f.type === 'clickup_status' ? (
{Array.isArray(f.clickupStatusOptions) && f.clickupStatusOptions.length > 0 ? (

{t( 'Dropdown mit {count} Status aus der ClickUp-Liste (Wert = exakter Status-Name für die API).', { count: String(f.clickupStatusOptions.length) } )}

) : (

{t( 'Keine Optionen — im ClickUp-Knoten „Aufgabe erstellen“ Liste wählen und „Formular mit Liste abgleichen“.' )}

)}
) : null} {f.type === 'clickup_tasks' ? (
{ const next = [...fields]; next[i] = { ...next[i], clickupListId: e.target.value }; updateParam('fields', next); }} style={{ width: '100%' }} />

{t('Liefert beim Ausfüllen denselben Wert wie ein ClickUp-Relationship-Feld:')}{' '} {'{ add: [taskId], rem: [] }'}{' '} {t('— im ClickUp-Node per Datenquelle auf das Formularfeld mappen.')}

) : null}
))}
); };