same field cannot be added to form multiple times in workflow editor

This commit is contained in:
Attila Cseh
2025-08-06 10:47:30 +02:00
committed by psychedelicious
parent f4981a6ba9
commit 325dacd29c
4 changed files with 19 additions and 13 deletions

View File

@@ -11,7 +11,7 @@ type Props = {
export const InputFieldAddToFormRoot = memo(({ nodeId, fieldName }: Props) => {
const { t } = useTranslation();
const addToRoot = useAddNodeFieldToRoot(nodeId, fieldName);
const { isAddedToRoot, addNodeFieldToRoot } = useAddNodeFieldToRoot(nodeId, fieldName);
return (
<IconButton
@@ -21,7 +21,8 @@ export const InputFieldAddToFormRoot = memo(({ nodeId, fieldName }: Props) => {
icon={<PiPlusBold />}
pointerEvents="auto"
size="xs"
onClick={addToRoot}
onClick={addNodeFieldToRoot}
isDisabled={isAddedToRoot}
/>
);
});

View File

@@ -2,15 +2,20 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useInputFieldInstance } from 'features/nodes/hooks/useInputFieldInstance';
import { useInputFieldTemplateOrThrow } from 'features/nodes/hooks/useInputFieldTemplateOrThrow';
import { formElementAdded } from 'features/nodes/store/nodesSlice';
import { selectFormRootElementId } from 'features/nodes/store/selectors';
import { buildSelectWorkflowFormNodeExists, selectFormRootElementId } from 'features/nodes/store/selectors';
import { buildNodeFieldElement } from 'features/nodes/types/workflow';
import { useCallback } from 'react';
import { useCallback, useMemo } from 'react';
export const useAddNodeFieldToRoot = (nodeId: string, fieldName: string) => {
const dispatch = useAppDispatch();
const rootElementId = useAppSelector(selectFormRootElementId);
const fieldTemplate = useInputFieldTemplateOrThrow(fieldName);
const field = useInputFieldInstance(fieldName);
const selectWorkflowFormNodeExists = useMemo(
() => buildSelectWorkflowFormNodeExists(nodeId, fieldName),
[nodeId, fieldName]
);
const isAddedToRoot = useAppSelector(selectWorkflowFormNodeExists);
const addNodeFieldToRoot = useCallback(() => {
const element = buildNodeFieldElement(nodeId, fieldName, fieldTemplate.type);
@@ -23,5 +28,5 @@ export const useAddNodeFieldToRoot = (nodeId: string, fieldName: string) => {
);
}, [nodeId, fieldName, fieldTemplate.type, dispatch, rootElementId, field.value]);
return addNodeFieldToRoot;
return { isAddedToRoot, addNodeFieldToRoot };
};

View File

@@ -6,7 +6,7 @@ import { $templates } from 'features/nodes/store/nodesSlice';
import {
selectNodes,
selectNodesSlice,
selectWorkflowFormNodeFieldFieldIdentifiersDeduped,
selectWorkflowFormNodeFieldFieldIdentifiers,
selectWorkflowId,
} from 'features/nodes/store/selectors';
import type { Templates } from 'features/nodes/store/types';
@@ -54,7 +54,7 @@ export const useIsValidationRunInProgress = () => {
};
export const selectFieldIdentifiersWithInvocationTypes = createSelector(
selectWorkflowFormNodeFieldFieldIdentifiersDeduped,
selectWorkflowFormNodeFieldFieldIdentifiers,
selectNodesSlice,
(fieldIdentifiers, nodes) => {
const result: FieldIdentiferWithLabelAndType[] = [];

View File

@@ -1,7 +1,6 @@
import type { Selector } from '@reduxjs/toolkit';
import { createSelector } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import { uniqBy } from 'es-toolkit/compat';
import { getElement } from 'features/nodes/components/sidePanel/builder/form-manipulation';
import type { NodesState } from 'features/nodes/store/types';
import type { FieldInputInstance } from 'features/nodes/types/field';
@@ -94,12 +93,13 @@ export const selectFormInitialValues = createNodesSelector((workflow) => workflo
export const selectNodeFieldElements = createNodesSelector((workflow) =>
Object.values(workflow.form.elements).filter(isNodeFieldElement)
);
export const selectWorkflowFormNodeFieldFieldIdentifiersDeduped = createSelector(
export const selectWorkflowFormNodeFieldFieldIdentifiers = createSelector(
selectNodeFieldElements,
(nodeFieldElements) =>
uniqBy(nodeFieldElements, (el) => `${el.data.fieldIdentifier.nodeId}-${el.data.fieldIdentifier.fieldName}`).map(
(el) => el.data.fieldIdentifier
)
(nodeFieldElements) => nodeFieldElements.map((el) => el.data.fieldIdentifier)
);
export const buildSelectElement = (id: string) => createNodesSelector((workflow) => workflow.form?.elements[id]);
export const buildSelectWorkflowFormNodeExists = (nodeId: string, fieldName: string) =>
createSelector(selectWorkflowFormNodeFieldFieldIdentifiers, (identifiers) =>
identifiers.some((identifier) => identifier.nodeId === nodeId && identifier.fieldName === fieldName)
);