tidy(ui): use settings for node field settings instead of config

Non-functional naming change to clarify the logic
This commit is contained in:
psychedelicious
2025-03-24 11:58:28 +10:00
parent c0dc6ac4e1
commit 3162ce94dc
6 changed files with 153 additions and 135 deletions

View File

@@ -9,7 +9,7 @@ import { FormElementEditModeContent } from 'features/nodes/components/sidePanel/
import { FormElementEditModeHeader } from 'features/nodes/components/sidePanel/builder/FormElementEditModeHeader';
import { NodeFieldElementDescriptionEditable } from 'features/nodes/components/sidePanel/builder/NodeFieldElementDescriptionEditable';
import { NodeFieldElementLabelEditable } from 'features/nodes/components/sidePanel/builder/NodeFieldElementLabelEditable';
import { NodeFieldElementStringDropdownConfig } from 'features/nodes/components/sidePanel/builder/NodeFieldElementStringDropdownConfig';
import { NodeFieldElementStringDropdownSettings } from 'features/nodes/components/sidePanel/builder/NodeFieldElementStringDropdownSettings';
import { useMouseOverFormField, useMouseOverNode } from 'features/nodes/hooks/useMouseOverNode';
import type { NodeFieldElement } from 'features/nodes/types/workflow';
import { NODE_FIELD_CLASS_NAME } from 'features/nodes/types/workflow';
@@ -77,7 +77,7 @@ const NodeFieldElementEditModeContent = memo(
{data.settings?.type === 'string-field-config' && data.settings.component === 'dropdown' && (
<>
<Divider />
<NodeFieldElementStringDropdownConfig id={id} settings={data.settings} />
<NodeFieldElementStringDropdownSettings id={id} settings={data.settings} />
</>
)}
</FormControl>

View File

@@ -14,42 +14,48 @@ import { useTranslation } from 'react-i18next';
type Props = {
id: string;
config: NodeFieldFloatSettings;
settings: NodeFieldFloatSettings;
nodeId: string;
fieldName: string;
fieldTemplate: FloatFieldInputTemplate;
};
export const NodeFieldElementFloatSettings = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props) => {
export const NodeFieldElementFloatSettings = memo(({ id, settings, nodeId, fieldName, fieldTemplate }: Props) => {
return (
<>
<SettingComponent id={id} config={config} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingMin id={id} config={config} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingMax id={id} config={config} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingComponent
id={id}
settings={settings}
nodeId={nodeId}
fieldName={fieldName}
fieldTemplate={fieldTemplate}
/>
<SettingMin id={id} settings={settings} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingMax id={id} settings={settings} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
</>
);
});
NodeFieldElementFloatSettings.displayName = 'NodeFieldElementFloatSettings';
const SettingComponent = memo(({ id, config }: Props) => {
const SettingComponent = memo(({ id, settings }: Props) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const onChangeComponent = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
const newConfig: NodeFieldFloatSettings = {
...config,
const newSettings: NodeFieldFloatSettings = {
...settings,
component: zNumberComponent.parse(e.target.value),
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
},
[config, dispatch, id]
[settings, dispatch, id]
);
return (
<FormControl orientation="vertical">
<FormLabel flex={1}>{t('workflows.builder.component')}</FormLabel>
<Select value={config.component} onChange={onChangeComponent} size="sm">
<Select value={settings.component} onChange={onChangeComponent} size="sm">
<option value="number-input">{t('workflows.builder.numberInput')}</option>
<option value="slider">{t('workflows.builder.slider')}</option>
<option value="number-input-and-slider">{t('workflows.builder.both')}</option>
@@ -59,36 +65,36 @@ const SettingComponent = memo(({ id, config }: Props) => {
});
SettingComponent.displayName = 'SettingComponent';
const SettingMin = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props) => {
const SettingMin = memo(({ id, settings, nodeId, fieldName, fieldTemplate }: Props) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const field = useInputFieldInstance<FloatFieldInputInstance>(nodeId, fieldName);
const floatField = useFloatField(nodeId, fieldName, fieldTemplate);
const onToggleSetting = useCallback(() => {
const newConfig: NodeFieldFloatSettings = {
...config,
min: config.min !== undefined ? undefined : floatField.min,
const onToggleOverride = useCallback(() => {
const newSettings: NodeFieldFloatSettings = {
...settings,
min: settings.min !== undefined ? undefined : floatField.min,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
}, [config, dispatch, floatField, id]);
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
}, [settings, dispatch, floatField, id]);
const onChange = useCallback(
(min: number) => {
const newConfig: NodeFieldFloatSettings = {
...config,
const newSettings: NodeFieldFloatSettings = {
...settings,
min,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
// We may need to update the value if it is outside the new min/max range
const constrained = constrainNumber(field.value, floatField, newConfig);
const constrained = constrainNumber(field.value, floatField, newSettings);
if (field.value !== constrained) {
dispatch(fieldFloatValueChanged({ nodeId, fieldName, value: constrained }));
}
},
[config, dispatch, field.value, fieldName, floatField, id, nodeId]
[settings, dispatch, field.value, fieldName, floatField, id, nodeId]
);
const constraintMin = useMemo(
@@ -97,20 +103,20 @@ const SettingMin = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props
);
const constraintMax = useMemo(
() => (config.max ?? floatField.max) - floatField.step,
[config.max, floatField.max, floatField.step]
() => (settings.max ?? floatField.max) - floatField.step,
[settings.max, floatField.max, floatField.step]
);
return (
<FormControl orientation="vertical">
<Flex justifyContent="space-between" w="full" alignItems="center">
<FormLabel m={0}>{t('workflows.builder.minimum')}</FormLabel>
<Switch isChecked={config.min !== undefined} onChange={onToggleSetting} size="sm" />
<Switch isChecked={settings.min !== undefined} onChange={onToggleOverride} size="sm" />
</Flex>
<CompositeNumberInput
w="full"
isDisabled={config.min === undefined}
value={config.min === undefined ? (`${floatField.min} (inherited)` as unknown as number) : config.min}
isDisabled={settings.min === undefined}
value={settings.min === undefined ? (`${floatField.min} (inherited)` as unknown as number) : settings.min}
onChange={onChange}
min={constraintMin}
max={constraintMax}
@@ -121,41 +127,41 @@ const SettingMin = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props
});
SettingMin.displayName = 'SettingMin';
const SettingMax = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props) => {
const SettingMax = memo(({ id, settings, nodeId, fieldName, fieldTemplate }: Props) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const field = useInputFieldInstance<FloatFieldInputInstance>(nodeId, fieldName);
const floatField = useFloatField(nodeId, fieldName, fieldTemplate);
const onToggleSetting = useCallback(() => {
const newConfig: NodeFieldFloatSettings = {
...config,
max: config.max !== undefined ? undefined : floatField.max,
const onToggleOverride = useCallback(() => {
const newSettings: NodeFieldFloatSettings = {
...settings,
max: settings.max !== undefined ? undefined : floatField.max,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
}, [config, dispatch, floatField, id]);
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
}, [settings, dispatch, floatField, id]);
const onChange = useCallback(
(max: number) => {
const newConfig: NodeFieldFloatSettings = {
...config,
const newSettings: NodeFieldFloatSettings = {
...settings,
max,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
// We may need to update the value if it is outside the new min/max range
const constrained = constrainNumber(field.value, floatField, newConfig);
const constrained = constrainNumber(field.value, floatField, newSettings);
if (field.value !== constrained) {
dispatch(fieldFloatValueChanged({ nodeId, fieldName, value: constrained }));
}
},
[config, dispatch, field.value, fieldName, floatField, id, nodeId]
[settings, dispatch, field.value, fieldName, floatField, id, nodeId]
);
const constraintMin = useMemo(
() => (config.min ?? floatField.min) + floatField.step,
[config.min, floatField.min, floatField.step]
() => (settings.min ?? floatField.min) + floatField.step,
[settings.min, floatField.min, floatField.step]
);
const constraintMax = useMemo(
@@ -167,12 +173,12 @@ const SettingMax = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props
<FormControl orientation="vertical">
<Flex justifyContent="space-between" w="full" alignItems="center">
<FormLabel m={0}>{t('workflows.builder.maximum')}</FormLabel>
<Switch isChecked={config.max !== undefined} onChange={onToggleSetting} size="sm" />
<Switch isChecked={settings.max !== undefined} onChange={onToggleOverride} size="sm" />
</Flex>
<CompositeNumberInput
w="full"
isDisabled={config.max === undefined}
value={config.max === undefined ? (`${floatField.max} (inherited)` as unknown as number) : config.max}
isDisabled={settings.max === undefined}
value={settings.max === undefined ? (`${floatField.max} (inherited)` as unknown as number) : settings.max}
onChange={onChange}
min={constraintMin}
max={constraintMax}

View File

@@ -15,42 +15,48 @@ import { useTranslation } from 'react-i18next';
type Props = {
id: string;
config: NodeFieldIntegerSettings;
settings: NodeFieldIntegerSettings;
nodeId: string;
fieldName: string;
fieldTemplate: IntegerFieldInputTemplate;
};
export const NodeFieldElementIntegerSettings = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props) => {
export const NodeFieldElementIntegerSettings = memo(({ id, settings, nodeId, fieldName, fieldTemplate }: Props) => {
return (
<>
<SettingComponent id={id} config={config} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingMin id={id} config={config} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingMax id={id} config={config} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingComponent
id={id}
settings={settings}
nodeId={nodeId}
fieldName={fieldName}
fieldTemplate={fieldTemplate}
/>
<SettingMin id={id} settings={settings} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
<SettingMax id={id} settings={settings} nodeId={nodeId} fieldName={fieldName} fieldTemplate={fieldTemplate} />
</>
);
});
NodeFieldElementIntegerSettings.displayName = 'NodeFieldElementIntegerSettings';
const SettingComponent = memo(({ id, config }: Props) => {
const SettingComponent = memo(({ id, settings }: Props) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const onChangeComponent = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
const newConfig: NodeFieldIntegerSettings = {
...config,
const newSettings: NodeFieldIntegerSettings = {
...settings,
component: zNumberComponent.parse(e.target.value),
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
},
[config, dispatch, id]
[settings, dispatch, id]
);
return (
<FormControl orientation="vertical">
<FormLabel flex={1}>{t('workflows.builder.component')}</FormLabel>
<Select value={config.component} onChange={onChangeComponent} size="sm">
<Select value={settings.component} onChange={onChangeComponent} size="sm">
<option value="number-input">{t('workflows.builder.numberInput')}</option>
<option value="slider">{t('workflows.builder.slider')}</option>
<option value="number-input-and-slider">{t('workflows.builder.both')}</option>
@@ -60,37 +66,37 @@ const SettingComponent = memo(({ id, config }: Props) => {
});
SettingComponent.displayName = 'SettingComponent';
const SettingMin = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props) => {
const SettingMin = memo(({ id, settings, nodeId, fieldName, fieldTemplate }: Props) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const field = useInputFieldInstance<IntegerFieldInputInstance>(nodeId, fieldName);
const integerField = useIntegerField(nodeId, fieldName, fieldTemplate);
const onToggleSetting = useCallback(() => {
const newConfig: NodeFieldIntegerSettings = {
...config,
min: config.min !== undefined ? undefined : integerField.min,
const onToggleOverride = useCallback(() => {
const newSettings: NodeFieldIntegerSettings = {
...settings,
min: settings.min !== undefined ? undefined : integerField.min,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
}, [config, dispatch, integerField.min, id]);
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
}, [settings, dispatch, integerField.min, id]);
const onChange = useCallback(
(min: number) => {
const newConfig: NodeFieldIntegerSettings = {
...config,
const newSettings: NodeFieldIntegerSettings = {
...settings,
min,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
// We may need to update the value if it is outside the new min/max range
const constrained = constrainNumber(field.value, integerField, newConfig);
const constrained = constrainNumber(field.value, integerField, newSettings);
if (field.value !== constrained) {
dispatch(fieldIntegerValueChanged({ nodeId, fieldName, value: constrained }));
}
},
[config, dispatch, id, field, integerField, nodeId, fieldName]
[settings, dispatch, id, field, integerField, nodeId, fieldName]
);
const constraintMin = useMemo(
@@ -99,20 +105,20 @@ const SettingMin = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props
);
const constraintMax = useMemo(
() => (config.max ?? integerField.max) - integerField.step,
[config.max, integerField.max, integerField.step]
() => (settings.max ?? integerField.max) - integerField.step,
[settings.max, integerField.max, integerField.step]
);
return (
<FormControl orientation="vertical">
<Flex justifyContent="space-between" w="full" alignItems="center">
<FormLabel m={0}>{t('workflows.builder.minimum')}</FormLabel>
<Switch isChecked={config.min !== undefined} onChange={onToggleSetting} size="sm" />
<Switch isChecked={settings.min !== undefined} onChange={onToggleOverride} size="sm" />
</Flex>
<CompositeNumberInput
w="full"
isDisabled={config.min === undefined}
value={config.min ?? (`${integerField.min} (inherited)` as unknown as number)}
isDisabled={settings.min === undefined}
value={settings.min ?? (`${integerField.min} (inherited)` as unknown as number)}
onChange={onChange}
min={constraintMin}
max={constraintMax}
@@ -123,42 +129,42 @@ const SettingMin = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props
});
SettingMin.displayName = 'SettingMin';
const SettingMax = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props) => {
const SettingMax = memo(({ id, settings, nodeId, fieldName, fieldTemplate }: Props) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const field = useInputFieldInstance<IntegerFieldInputInstance>(nodeId, fieldName);
const integerField = useIntegerField(nodeId, fieldName, fieldTemplate);
const onToggleSetting = useCallback(() => {
const newConfig: NodeFieldIntegerSettings = {
...config,
max: config.max !== undefined ? undefined : integerField.max,
const onToggleOverride = useCallback(() => {
const newSettings: NodeFieldIntegerSettings = {
...settings,
max: settings.max !== undefined ? undefined : integerField.max,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
}, [config, dispatch, integerField.max, id]);
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
}, [settings, dispatch, integerField.max, id]);
const onChange = useCallback(
(max: number) => {
const newConfig: NodeFieldIntegerSettings = {
...config,
const newSettings: NodeFieldIntegerSettings = {
...settings,
max,
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newConfig } }));
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
// We may need to update the value if it is outside the new min/max range
const constrained = constrainNumber(field.value, integerField, newConfig);
const constrained = constrainNumber(field.value, integerField, newSettings);
if (field.value !== constrained) {
dispatch(fieldIntegerValueChanged({ nodeId, fieldName, value: constrained }));
}
},
[config, dispatch, field.value, fieldName, integerField, id, nodeId]
[settings, dispatch, field.value, fieldName, integerField, id, nodeId]
);
const constraintMin = useMemo(
() => (config.min ?? integerField.min) + integerField.step,
[config.min, integerField.min, integerField.step]
() => (settings.min ?? integerField.min) + integerField.step,
[settings.min, integerField.min, integerField.step]
);
const constraintMax = useMemo(
@@ -170,12 +176,12 @@ const SettingMax = memo(({ id, config, nodeId, fieldName, fieldTemplate }: Props
<FormControl orientation="vertical">
<Flex justifyContent="space-between" w="full" alignItems="center">
<FormLabel m={0}>{t('workflows.builder.maximum')}</FormLabel>
<Switch isChecked={config.max !== undefined} onChange={onToggleSetting} size="sm" />
<Switch isChecked={settings.max !== undefined} onChange={onToggleOverride} size="sm" />
</Flex>
<CompositeNumberInput
w="full"
isDisabled={config.max === undefined}
value={config.max ?? (`${integerField.max} (inherited)` as unknown as number)}
isDisabled={settings.max === undefined}
value={settings.max ?? (`${integerField.max} (inherited)` as unknown as number)}
onChange={onChange}
min={constraintMin}
max={constraintMax}

View File

@@ -79,7 +79,7 @@ export const NodeFieldElementSettings = memo(({ element }: { element: NodeFieldE
{settings?.type === 'integer-field-config' && isIntegerFieldInputTemplate(fieldTemplate) && (
<NodeFieldElementIntegerSettings
id={id}
config={settings}
settings={settings}
nodeId={nodeId}
fieldName={fieldName}
fieldTemplate={fieldTemplate}
@@ -88,13 +88,15 @@ export const NodeFieldElementSettings = memo(({ element }: { element: NodeFieldE
{settings?.type === 'float-field-config' && isFloatFieldInputTemplate(fieldTemplate) && (
<NodeFieldElementFloatSettings
id={id}
config={settings}
settings={settings}
nodeId={nodeId}
fieldName={fieldName}
fieldTemplate={fieldTemplate}
/>
)}
{settings?.type === 'string-field-config' && <NodeFieldElementStringSettings id={id} config={settings} />}
{settings?.type === 'string-field-config' && (
<NodeFieldElementStringSettings id={id} settings={settings} />
)}
</Flex>
</PopoverBody>
</PopoverContent>

View File

@@ -12,7 +12,7 @@ import { PiArrowCounterClockwiseBold, PiPlusBold, PiXBold } from 'react-icons/pi
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
export const NodeFieldElementStringDropdownConfig = memo(
export const NodeFieldElementStringDropdownSettings = memo(
({ id, settings }: { id: string; settings: NodeFieldStringDropdownSettings }) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
@@ -130,7 +130,7 @@ export const NodeFieldElementStringDropdownConfig = memo(
}
);
NodeFieldElementStringDropdownConfig.displayName = 'NodeFieldElementStringDropdownConfig';
NodeFieldElementStringDropdownSettings.displayName = 'NodeFieldElementStringDropdownSettings';
type ListItemContentProps = {
value: string;

View File

@@ -7,45 +7,49 @@ import type { ChangeEvent } from 'react';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
export const NodeFieldElementStringSettings = memo(
({ id, config }: { id: string; config: NodeFieldStringSettings }) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
type Props = {
id: string;
settings: NodeFieldStringSettings;
};
const onChangeComponent = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
const component = zStringComponent.parse(e.target.value);
if (component === config.component) {
// no change
return;
}
if (component === 'dropdown') {
// if the component is changing to dropdown, we need to set the options
const settings: NodeFieldStringSettings = {
...config,
component,
options: [getDefaultStringOption()],
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings } }));
return;
}
export const NodeFieldElementStringSettings = memo(({ id, settings }: Props) => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const onChangeComponent = useCallback(
(e: ChangeEvent<HTMLSelectElement>) => {
const component = zStringComponent.parse(e.target.value);
if (component === settings.component) {
// no change
return;
}
if (component === 'dropdown') {
// if the component is changing to dropdown, we need to set the options
const newSettings: NodeFieldStringSettings = {
...settings,
component,
options: [getDefaultStringOption()],
};
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
return;
} else {
// if the component is changing from dropdown, we need to remove the options
const settings: NodeFieldStringSettings = omit({ ...config, component }, 'options');
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings } }));
},
[config, dispatch, id]
);
const newSettings: NodeFieldStringSettings = omit({ ...settings, component }, 'options');
dispatch(formElementNodeFieldDataChanged({ id, changes: { settings: newSettings } }));
}
},
[settings, dispatch, id]
);
return (
<FormControl>
<FormLabel flex={1}>{t('workflows.builder.component')}</FormLabel>
<Select value={config.component} onChange={onChangeComponent} size="sm">
<option value="input">{t('workflows.builder.singleLine')}</option>
<option value="textarea">{t('workflows.builder.multiLine')}</option>
<option value="dropdown">{t('workflows.builder.dropdown')}</option>
</Select>
</FormControl>
);
}
);
return (
<FormControl>
<FormLabel flex={1}>{t('workflows.builder.component')}</FormLabel>
<Select value={settings.component} onChange={onChangeComponent} size="sm">
<option value="input">{t('workflows.builder.singleLine')}</option>
<option value="textarea">{t('workflows.builder.multiLine')}</option>
<option value="dropdown">{t('workflows.builder.dropdown')}</option>
</Select>
</FormControl>
);
});
NodeFieldElementStringSettings.displayName = 'NodeFieldElementStringSettings';