Skip to content

Commit 325dacd

Browse files
Attila Csehpsychedelicious
authored andcommitted
same field cannot be added to form multiple times in workflow editor
1 parent f4981a6 commit 325dacd

File tree

4 files changed

+19
-13
lines changed

4 files changed

+19
-13
lines changed

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/InputFieldAddToFormRoot.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type Props = {
1111

1212
export const InputFieldAddToFormRoot = memo(({ nodeId, fieldName }: Props) => {
1313
const { t } = useTranslation();
14-
const addToRoot = useAddNodeFieldToRoot(nodeId, fieldName);
14+
const { isAddedToRoot, addNodeFieldToRoot } = useAddNodeFieldToRoot(nodeId, fieldName);
1515

1616
return (
1717
<IconButton
@@ -21,7 +21,8 @@ export const InputFieldAddToFormRoot = memo(({ nodeId, fieldName }: Props) => {
2121
icon={<PiPlusBold />}
2222
pointerEvents="auto"
2323
size="xs"
24-
onClick={addToRoot}
24+
onClick={addNodeFieldToRoot}
25+
isDisabled={isAddedToRoot}
2526
/>
2627
);
2728
});

invokeai/frontend/web/src/features/nodes/components/sidePanel/builder/use-add-node-field-to-root.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
22
import { useInputFieldInstance } from 'features/nodes/hooks/useInputFieldInstance';
33
import { useInputFieldTemplateOrThrow } from 'features/nodes/hooks/useInputFieldTemplateOrThrow';
44
import { formElementAdded } from 'features/nodes/store/nodesSlice';
5-
import { selectFormRootElementId } from 'features/nodes/store/selectors';
5+
import { buildSelectWorkflowFormNodeExists, selectFormRootElementId } from 'features/nodes/store/selectors';
66
import { buildNodeFieldElement } from 'features/nodes/types/workflow';
7-
import { useCallback } from 'react';
7+
import { useCallback, useMemo } from 'react';
88

99
export const useAddNodeFieldToRoot = (nodeId: string, fieldName: string) => {
1010
const dispatch = useAppDispatch();
1111
const rootElementId = useAppSelector(selectFormRootElementId);
1212
const fieldTemplate = useInputFieldTemplateOrThrow(fieldName);
1313
const field = useInputFieldInstance(fieldName);
14+
const selectWorkflowFormNodeExists = useMemo(
15+
() => buildSelectWorkflowFormNodeExists(nodeId, fieldName),
16+
[nodeId, fieldName]
17+
);
18+
const isAddedToRoot = useAppSelector(selectWorkflowFormNodeExists);
1419

1520
const addNodeFieldToRoot = useCallback(() => {
1621
const element = buildNodeFieldElement(nodeId, fieldName, fieldTemplate.type);
@@ -23,5 +28,5 @@ export const useAddNodeFieldToRoot = (nodeId: string, fieldName: string) => {
2328
);
2429
}, [nodeId, fieldName, fieldTemplate.type, dispatch, rootElementId, field.value]);
2530

26-
return addNodeFieldToRoot;
31+
return { isAddedToRoot, addNodeFieldToRoot };
2732
};

invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/publish.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { $templates } from 'features/nodes/store/nodesSlice';
66
import {
77
selectNodes,
88
selectNodesSlice,
9-
selectWorkflowFormNodeFieldFieldIdentifiersDeduped,
9+
selectWorkflowFormNodeFieldFieldIdentifiers,
1010
selectWorkflowId,
1111
} from 'features/nodes/store/selectors';
1212
import type { Templates } from 'features/nodes/store/types';
@@ -54,7 +54,7 @@ export const useIsValidationRunInProgress = () => {
5454
};
5555

5656
export const selectFieldIdentifiersWithInvocationTypes = createSelector(
57-
selectWorkflowFormNodeFieldFieldIdentifiersDeduped,
57+
selectWorkflowFormNodeFieldFieldIdentifiers,
5858
selectNodesSlice,
5959
(fieldIdentifiers, nodes) => {
6060
const result: FieldIdentiferWithLabelAndType[] = [];

invokeai/frontend/web/src/features/nodes/store/selectors.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Selector } from '@reduxjs/toolkit';
22
import { createSelector } from '@reduxjs/toolkit';
33
import type { RootState } from 'app/store/store';
4-
import { uniqBy } from 'es-toolkit/compat';
54
import { getElement } from 'features/nodes/components/sidePanel/builder/form-manipulation';
65
import type { NodesState } from 'features/nodes/store/types';
76
import type { FieldInputInstance } from 'features/nodes/types/field';
@@ -94,12 +93,13 @@ export const selectFormInitialValues = createNodesSelector((workflow) => workflo
9493
export const selectNodeFieldElements = createNodesSelector((workflow) =>
9594
Object.values(workflow.form.elements).filter(isNodeFieldElement)
9695
);
97-
export const selectWorkflowFormNodeFieldFieldIdentifiersDeduped = createSelector(
96+
export const selectWorkflowFormNodeFieldFieldIdentifiers = createSelector(
9897
selectNodeFieldElements,
99-
(nodeFieldElements) =>
100-
uniqBy(nodeFieldElements, (el) => `${el.data.fieldIdentifier.nodeId}-${el.data.fieldIdentifier.fieldName}`).map(
101-
(el) => el.data.fieldIdentifier
102-
)
98+
(nodeFieldElements) => nodeFieldElements.map((el) => el.data.fieldIdentifier)
10399
);
104100

105101
export const buildSelectElement = (id: string) => createNodesSelector((workflow) => workflow.form?.elements[id]);
102+
export const buildSelectWorkflowFormNodeExists = (nodeId: string, fieldName: string) =>
103+
createSelector(selectWorkflowFormNodeFieldFieldIdentifiers, (identifiers) =>
104+
identifiers.some((identifier) => identifier.nodeId === nodeId && identifier.fieldName === fieldName)
105+
);

0 commit comments

Comments
 (0)