diff --git a/src/components/FlowEditor/editor/Automation2FlowEditor.module.css b/src/components/FlowEditor/editor/Automation2FlowEditor.module.css index bd66619..368ddf2 100644 --- a/src/components/FlowEditor/editor/Automation2FlowEditor.module.css +++ b/src/components/FlowEditor/editor/Automation2FlowEditor.module.css @@ -1187,6 +1187,12 @@ background: rgba(220, 53, 69, 0.1); } +.formFieldOptionsBlock { + margin-top: 0.4rem; + padding-top: 0.45rem; + border-top: 1px solid var(--border-color, #e8e8e8); +} + /* Upload node config */ .uploadNodeConfig { display: flex; diff --git a/src/components/FlowEditor/nodes/form/FormFieldOptionsEditor.tsx b/src/components/FlowEditor/nodes/form/FormFieldOptionsEditor.tsx new file mode 100644 index 0000000..ff3cf92 --- /dev/null +++ b/src/components/FlowEditor/nodes/form/FormFieldOptionsEditor.tsx @@ -0,0 +1,104 @@ +/** + * One text field per option — the text the end user sees in the dropdown. + * Stored as { value, label } with the same string so payload and UI stay in sync. + */ + +import React from 'react'; +import { FaTimes } from 'react-icons/fa'; +import { useLanguage } from '../../../../providers/language/LanguageContext'; +import type { FormFieldOptionRow } from './formFieldOptionsUtils'; + +export interface FormFieldOptionsEditorProps { + options: FormFieldOptionRow[]; + onChange: (next: FormFieldOptionRow[]) => void; + className?: string; + rowClassName?: string; +} + +export const FormFieldOptionsEditor: React.FC = ({ + options, + onChange, + className, + rowClassName, +}) => { + const { t } = useLanguage(); + const rootClass = className ?? ''; + const lineClass = rowClassName ?? ''; + + const setOptionText = (idx: number, text: string) => { + const next = options.map((o, i) => + i === idx ? { value: text, label: text } : o, + ); + onChange(next); + }; + + return ( +
+
+ {t('Auswahloptionen')} +
+ {options.map((opt, idx) => ( +
+ setOptionText(idx, e.target.value)} + style={{ + flex: '1 1 120px', + minWidth: 80, + padding: '4px 6px', + fontSize: '0.8rem', + borderRadius: 4, + border: '1px solid var(--border-color, #ddd)', + boxSizing: 'border-box', + }} + /> + +
+ ))} + +
+ ); +}; diff --git a/src/components/FlowEditor/nodes/form/FormNodeConfig.tsx b/src/components/FlowEditor/nodes/form/FormNodeConfig.tsx index d0a07f6..474e101 100644 --- a/src/components/FlowEditor/nodes/form/FormNodeConfig.tsx +++ b/src/components/FlowEditor/nodes/form/FormNodeConfig.tsx @@ -8,6 +8,12 @@ import type { FormField, NodeConfigRendererProps } from '../shared/types'; import { FORM_FIELD_TYPES, FORM_FIELD_TYPE_LABELS } from '../../../../utils/attributeTypeMapper'; import styles from '../../editor/Automation2FlowEditor.module.css'; import { useAutomation2DataFlow } from '../../context/Automation2DataFlowContext'; +import { FormFieldOptionsEditor } from './FormFieldOptionsEditor'; +import { + deriveFormFieldPayloadKey, + formFieldTypeHasConfigurableOptions, + normalizeFormFieldOptions, +} from './formFieldOptionsUtils'; import { useLanguage } from '../../../../providers/language/LanguageContext'; @@ -64,20 +70,12 @@ export const FormNodeConfig: React.FC = ({ params, upda
{ - const next = [...fields]; - next[i] = { ...next[i], name: e.target.value }; - updateParam('fields', next); - }} - /> - { + const label = e.target.value; const next = [...fields]; - next[i] = { ...next[i], label: e.target.value }; + next[i] = { ...next[i], label, name: deriveFormFieldPayloadKey(label, i) }; updateParam('fields', next); }} /> @@ -88,7 +86,12 @@ export const FormNodeConfig: React.FC = ({ params, upda value={f.type ?? 'text'} onChange={(e) => { const next = [...fields]; - next[i] = { name: f.name, label: f.label, type: e.target.value as FormField['type'], required: f.required }; + const type = e.target.value as FormField['type']; + const row: FormField = { ...f, type }; + if (formFieldTypeHasConfigurableOptions(type)) { + row.options = normalizeFormFieldOptions(row.options); + } + next[i] = row; updateParam('fields', next); }} style={{ width: 'auto', minWidth: 90 }} @@ -118,12 +121,31 @@ export const FormNodeConfig: React.FC = ({ params, upda
+ {formFieldTypeHasConfigurableOptions(f.type) ? ( + { + const next = [...fields]; + next[i] = { ...next[i], options: opts }; + updateParam('fields', next); + }} + /> + ) : null} ))} - {/* Row 2: Name + Typ + Pflicht */} -
-
-
Name (intern)
- updateField(i, 'name', e.target.value)} - style={inputStyle} - /> -
+ {/* Row 2: Typ + Pflicht */} +
Typ
- setTopFieldType(i, e.target.value)} style={selectStyle}> {fieldTypeOptions.map((ft) => ( ))} @@ -627,6 +645,14 @@ const FieldBuilderEditor: React.FC = ({ param, value, onChan Pflicht
+ {formFieldTypeHasConfigurableOptions(String(f.type)) ? ( +
+ updateField(i, 'options', opts)} + /> +
+ ) : null} {String(f.type) === 'group' && (
{t('Unterfelder')}
@@ -635,11 +661,16 @@ const FieldBuilderEditor: React.FC = ({ param, value, onChan
{ + const label = e.target.value; const nextFields = [...(Array.isArray(f.fields) ? f.fields : [])]; - nextFields[j] = { ...sub, name: e.target.value }; + nextFields[j] = { + ...sub, + label, + name: deriveFormFieldPayloadKey(label, j), + }; updateField(i, 'fields', nextFields); }} style={{ ...inputStyle, flex: 1 }} @@ -647,8 +678,13 @@ const FieldBuilderEditor: React.FC = ({ param, value, onChan { - const next = [...fields]; - next[idx] = { ...f, name: e.target.value }; - setFields(next); - }} - /> { + const label = e.target.value; const next = [...fields]; - next[idx] = { ...f, label: e.target.value }; + next[idx] = { ...f, label, name: deriveFormFieldPayloadKey(label, idx) }; setFields(next); }} /> @@ -74,7 +72,12 @@ export const FormStartNodeConfig: React.FC = ({ params, value={f.type ?? 'text'} onChange={(e) => { const next = [...fields]; - next[idx] = { name: f.name, label: f.label, type: e.target.value as FormField['type'] }; + const type = e.target.value as FormField['type']; + const row: FormField = { ...f, type }; + if (formFieldTypeHasConfigurableOptions(type)) { + row.options = normalizeFormFieldOptions(row.options); + } + next[idx] = row; setFields(next); }} > @@ -89,13 +92,32 @@ export const FormStartNodeConfig: React.FC = ({ params, > ✕ + {formFieldTypeHasConfigurableOptions(f.type) ? ( +
+ { + const next = [...fields]; + next[idx] = { ...next[idx], options: opts }; + setFields(next); + }} + /> +
+ ) : null}
))}