diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts
index 9bfb784439..4b30d14e74 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedNodes.ts
@@ -9,7 +9,6 @@ import {
isIntegerFieldCollectionInputInstance,
isStringFieldCollectionInputInstance,
} from 'features/nodes/types/field';
-import { getNumberFieldCollectionValue } from 'features/nodes/types/fieldValidators';
import type { InvocationNodeEdge } from 'features/nodes/types/invocation';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { buildNodesGraph } from 'features/nodes/util/graph/buildNodesGraph';
@@ -107,7 +106,7 @@ export const addEnqueueRequestedNodes = (startAppListening: AppStartListening) =
// Find outgoing edges from the batch node, we will remove these from the graph and create batch data collection items from them instead
const edgesFromStringBatch = nodes.edges.filter((e) => e.source === node.id && e.sourceHandle === 'value');
- addBatchDataCollectionItem(edgesFromStringBatch, getNumberFieldCollectionValue(integers.value));
+ addBatchDataCollectionItem(edgesFromStringBatch, integers.value);
}
// Grab float batch nodes for special handling
@@ -126,7 +125,7 @@ export const addEnqueueRequestedNodes = (startAppListening: AppStartListening) =
// Find outgoing edges from the batch node, we will remove these from the graph and create batch data collection items from them instead
const edgesFromStringBatch = nodes.edges.filter((e) => e.source === node.id && e.sourceHandle === 'value');
- addBatchDataCollectionItem(edgesFromStringBatch, getNumberFieldCollectionValue(floats.value));
+ addBatchDataCollectionItem(edgesFromStringBatch, floats.value);
}
const batchConfig: BatchConfig = {
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/NumberFieldCollectionInputComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/NumberFieldCollectionInputComponent.tsx
index 5d07ee97c3..bfe6685c9a 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/NumberFieldCollectionInputComponent.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/NumberFieldCollectionInputComponent.tsx
@@ -1,34 +1,21 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
-import {
- Box,
- CompositeNumberInput,
- Flex,
- FormControl,
- FormLabel,
- Grid,
- GridItem,
- IconButton,
- Text,
-} from '@invoke-ai/ui-library';
+import { Box, CompositeNumberInput, Flex, Grid, GridItem, IconButton } from '@invoke-ai/ui-library';
import { NUMPY_RAND_MAX } from 'app/constants';
import { useAppStore } from 'app/store/nanostores/store';
-import { useAppDispatch } from 'app/store/storeHooks';
import { getOverlayScrollbarsParams, overlayScrollbarsStyles } from 'common/components/OverlayScrollbars/constants';
import { useFieldIsInvalid } from 'features/nodes/hooks/useFieldIsInvalid';
import { fieldNumberCollectionValueChanged } from 'features/nodes/store/nodesSlice';
import type {
FloatFieldCollectionInputInstance,
FloatFieldCollectionInputTemplate,
- FloatStartStepCountGenerator,
IntegerFieldCollectionInputInstance,
IntegerFieldCollectionInputTemplate,
- IntegerStartStepCountGenerator,
} from 'features/nodes/types/field';
import { isNil } from 'lodash-es';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
-import { PiLightbulbFill, PiPencilSimpleFill, PiPlusBold, PiXBold } from 'react-icons/pi';
+import { PiPlusBold, PiXBold } from 'react-icons/pi';
import type { FieldComponentProps } from './types';
@@ -50,40 +37,68 @@ export const NumberFieldCollectionInputComponent = memo(
) => {
const { nodeId, field, fieldTemplate } = props;
const store = useAppStore();
+
const isInvalid = useFieldIsInvalid(nodeId, field.name);
const isIntegerField = useMemo(() => fieldTemplate.type.name === 'IntegerField', [fieldTemplate.type]);
- const entryMode = useMemo(() => {
- if (!field.value) {
- return 'manual';
- }
- if (Array.isArray(field.value)) {
- return 'manual';
- }
- return 'step';
- }, [field.value]);
-
- const toggleEntryMode = useCallback(() => {
- if (!field.value || Array.isArray(field.value)) {
- const newValue: IntegerStartStepCountGenerator | FloatStartStepCountGenerator = isIntegerField
- ? { type: 'integer-start-step-count-generator', start: 0, step: 1, count: 1 }
- : { type: 'float-start-step-count-generator', start: 0, step: 1, count: 1 };
+ const onRemoveNumber = useCallback(
+ (index: number) => {
+ const newValue = field.value ? [...field.value] : [];
+ newValue.splice(index, 1);
store.dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName: field.name, value: newValue }));
- } else {
- store.dispatch(
- fieldNumberCollectionValueChanged({
- nodeId,
- fieldName: field.name,
- value: [0],
- })
- );
- }
- }, [field.name, field.value, isIntegerField, nodeId, store]);
+ },
+ [field.name, field.value, nodeId, store]
+ );
+
+ const onChangeNumber = useCallback(
+ (index: number, value: number) => {
+ const newValue = field.value ? [...field.value] : [];
+ newValue[index] = value;
+ store.dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName: field.name, value: newValue }));
+ },
+ [field.name, field.value, nodeId, store]
+ );
const onAddNumber = useCallback(() => {
- const newValue = field.value && Array.isArray(field.value) ? [...field.value, 0] : [0];
+ const newValue = field.value ? [...field.value, 0] : [0];
store.dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName: field.name, value: newValue }));
- }, [field.value, field.name, store, nodeId]);
+ }, [field.name, field.value, nodeId, store]);
+
+ const min = useMemo(() => {
+ let min = -NUMPY_RAND_MAX;
+ if (!isNil(fieldTemplate.minimum)) {
+ min = fieldTemplate.minimum;
+ }
+ if (!isNil(fieldTemplate.exclusiveMinimum)) {
+ min = fieldTemplate.exclusiveMinimum + 0.01;
+ }
+ return min;
+ }, [fieldTemplate.exclusiveMinimum, fieldTemplate.minimum]);
+
+ const max = useMemo(() => {
+ let max = NUMPY_RAND_MAX;
+ if (!isNil(fieldTemplate.maximum)) {
+ max = fieldTemplate.maximum;
+ }
+ if (!isNil(fieldTemplate.exclusiveMaximum)) {
+ max = fieldTemplate.exclusiveMaximum - 0.01;
+ }
+ return max;
+ }, [fieldTemplate.exclusiveMaximum, fieldTemplate.maximum]);
+
+ const step = useMemo(() => {
+ if (isNil(fieldTemplate.multipleOf)) {
+ return isIntegerField ? 1 : 0.1;
+ }
+ return fieldTemplate.multipleOf;
+ }, [fieldTemplate.multipleOf, isIntegerField]);
+
+ const fineStep = useMemo(() => {
+ if (isNil(fieldTemplate.multipleOf)) {
+ return isIntegerField ? 1 : 0.01;
+ }
+ return fieldTemplate.multipleOf;
+ }, [fieldTemplate.multipleOf, isIntegerField]);
return (
-
- {!field.value ||
- (Array.isArray(field.value) && (
- <>
- Manual
+ {(!field.value || field.value.length === 0) && (
+
+ }
+ variant="ghost"
+ size="sm"
+ />
+
+ )}
+ {field.value && field.value.length > 0 && (
+
+
+
}
variant="ghost"
size="sm"
/>
- >
- ))}
- {field.value && !Array.isArray(field.value) && (
- <>
- Generator
- >
- )}
- : }
- variant="ghost"
- size="sm"
- />
-
- {field.value && !Array.isArray(field.value) && (
-
- )}
- {field.value && Array.isArray(field.value) && field.value.length > 0 && (
-
+ {field.value.map((value, index) => (
+
+
+
+ ))}
+
+
+
)}
);
@@ -144,163 +164,6 @@ export const NumberFieldCollectionInputComponent = memo(
NumberFieldCollectionInputComponent.displayName = 'NumberFieldCollectionInputComponent';
-const GeneratorEntry = ({
- nodeId,
- fieldName,
- value,
- fieldTemplate,
-}: {
- nodeId: string;
- fieldName: string;
- value: IntegerStartStepCountGenerator | FloatStartStepCountGenerator;
- fieldTemplate: IntegerFieldCollectionInputTemplate | FloatFieldCollectionInputTemplate;
-}) => {
- const dispatch = useAppDispatch();
- const isIntegerField = useMemo(() => fieldTemplate.type.name === 'IntegerField', [fieldTemplate.type]);
- const onChangeStart = useCallback(
- (v: number) => {
- const newValue = { ...value, start: v };
- dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName, value: newValue }));
- },
- [dispatch, fieldName, nodeId, value]
- );
- const onChangeCount = useCallback(
- (v: number) => {
- const newValue = { ...value, count: v };
- dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName, value: newValue }));
- },
- [dispatch, fieldName, nodeId, value]
- );
- const onChangeStep = useCallback(
- (v: number) => {
- const newValue = { ...value, step: v };
- dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName, value: newValue }));
- },
- [dispatch, fieldName, nodeId, value]
- );
-
- return (
-
-
- Start
-
-
-
- Count
-
-
-
- Step
-
-
-
- );
-};
-
-const ManualEntry = ({
- nodeId,
- fieldName,
- value,
- fieldTemplate,
-}: {
- nodeId: string;
- fieldName: string;
- value: number[];
- fieldTemplate: IntegerFieldCollectionInputTemplate | FloatFieldCollectionInputTemplate;
-}) => {
- const dispatch = useAppDispatch();
- const isIntegerField = useMemo(() => fieldTemplate.type.name === 'IntegerField', [fieldTemplate.type]);
-
- const onRemoveNumber = useCallback(
- (index: number) => {
- const newValue = [...value];
- newValue.splice(index, 1);
- dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName, value: newValue }));
- },
- [value, dispatch, nodeId, fieldName]
- );
-
- const onChangeNumber = useCallback(
- (index: number, num: number) => {
- const newValue = [...value];
- newValue[index] = num;
- dispatch(fieldNumberCollectionValueChanged({ nodeId, fieldName, value: newValue }));
- },
- [value, dispatch, nodeId, fieldName]
- );
-
- const min = useMemo(() => {
- let min = -NUMPY_RAND_MAX;
- if (!isNil(fieldTemplate.minimum)) {
- min = fieldTemplate.minimum;
- }
- if (!isNil(fieldTemplate.exclusiveMinimum)) {
- min = fieldTemplate.exclusiveMinimum + 0.01;
- }
- return min;
- }, [fieldTemplate.exclusiveMinimum, fieldTemplate.minimum]);
-
- const max = useMemo(() => {
- let max = NUMPY_RAND_MAX;
- if (!isNil(fieldTemplate.maximum)) {
- max = fieldTemplate.maximum;
- }
- if (!isNil(fieldTemplate.exclusiveMaximum)) {
- max = fieldTemplate.exclusiveMaximum - 0.01;
- }
- return max;
- }, [fieldTemplate.exclusiveMaximum, fieldTemplate.maximum]);
-
- const step = useMemo(() => {
- if (isNil(fieldTemplate.multipleOf)) {
- return isIntegerField ? 1 : 0.1;
- }
- return fieldTemplate.multipleOf;
- }, [fieldTemplate.multipleOf, isIntegerField]);
-
- const fineStep = useMemo(() => {
- if (isNil(fieldTemplate.multipleOf)) {
- return isIntegerField ? 1 : 0.01;
- }
- return fieldTemplate.multipleOf;
- }, [fieldTemplate.multipleOf, isIntegerField]);
-
- return (
-
-
-
- {value.map((value, index) => (
-
-
-
- ))}
-
-
-
- );
-};
-
type NumberListItemContentProps = {
value: number;
index: number;
diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
index 9dde995d42..5b031dc072 100644
--- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
+++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
@@ -15,7 +15,6 @@ import type {
ControlNetModelFieldValue,
EnumFieldValue,
FieldValue,
- FloatFieldCollectionValue,
FloatFieldValue,
FluxVAEModelFieldValue,
ImageFieldCollectionValue,
@@ -323,10 +322,7 @@ export const nodesSlice = createSlice({
fieldNumberValueChanged: (state, action: FieldValueAction) => {
fieldValueReducer(state, action, zIntegerFieldValue.or(zFloatFieldValue));
},
- fieldNumberCollectionValueChanged: (
- state,
- action: FieldValueAction
- ) => {
+ fieldNumberCollectionValueChanged: (state, action: FieldValueAction) => {
fieldValueReducer(state, action, zIntegerFieldCollectionValue.or(zFloatFieldCollectionValue));
},
fieldBooleanValueChanged: (state, action: FieldValueAction) => {
diff --git a/invokeai/frontend/web/src/features/nodes/types/field.ts b/invokeai/frontend/web/src/features/nodes/types/field.ts
index 4355efbf3b..1ccc6ec9bb 100644
--- a/invokeai/frontend/web/src/features/nodes/types/field.ts
+++ b/invokeai/frontend/web/src/features/nodes/types/field.ts
@@ -279,17 +279,7 @@ export const isIntegerFieldInputTemplate = buildTypeGuard(zIntegerFieldInputTemp
// #endregion
// #region IntegerField Collection
-const zIntegerStartStepCountGenerator = z.object({
- type: z.literal('integer-start-step-count-generator'),
- start: z.number().int(),
- step: z.number().int(),
- count: z.number().int().gte(1),
-});
-export type IntegerStartStepCountGenerator = z.infer;
-export const isIntegerStartStepCountGenerator = buildTypeGuard(zIntegerStartStepCountGenerator);
-export const zIntegerFieldCollectionValue = z
- .union([z.array(zIntegerFieldValue), zIntegerStartStepCountGenerator])
- .optional();
+export const zIntegerFieldCollectionValue = z.array(zIntegerFieldValue).optional();
const zIntegerFieldCollectionInputInstance = zFieldInputInstanceBase.extend({
value: zIntegerFieldCollectionValue,
});
@@ -327,6 +317,7 @@ export const isIntegerFieldCollectionInputTemplate = buildTypeGuard(zIntegerFiel
// #endregion
// #region FloatField
+
export const zFloatFieldValue = z.number();
const zFloatFieldInputInstance = zFieldInputInstanceBase.extend({
value: zFloatFieldValue,
@@ -352,17 +343,7 @@ export const isFloatFieldInputTemplate = buildTypeGuard(zFloatFieldInputTemplate
// #endregion
// #region FloatField Collection
-const zFloatStartStepCountGenerator = z.object({
- type: z.literal('float-start-step-count-generator'),
- start: z.number(),
- step: z.number(),
- count: z.number().gte(1),
-});
-export type FloatStartStepCountGenerator = z.infer;
-export const isFloatStartStepCountGenerator = buildTypeGuard(zFloatStartStepCountGenerator);
-export const zFloatFieldCollectionValue = z
- .union([z.array(zFloatFieldValue), zFloatStartStepCountGenerator])
- .optional();
+export const zFloatFieldCollectionValue = z.array(zFloatFieldValue).optional();
const zFloatFieldCollectionInputInstance = zFieldInputInstanceBase.extend({
value: zFloatFieldCollectionValue,
});
diff --git a/invokeai/frontend/web/src/features/nodes/types/fieldValidators.ts b/invokeai/frontend/web/src/features/nodes/types/fieldValidators.ts
index 9fc2fd1909..4dbfc588c0 100644
--- a/invokeai/frontend/web/src/features/nodes/types/fieldValidators.ts
+++ b/invokeai/frontend/web/src/features/nodes/types/fieldValidators.ts
@@ -8,7 +8,6 @@ import type {
StringFieldCollectionInputTemplate,
StringFieldCollectionValue,
} from 'features/nodes/types/field';
-import { numberStartStepCountGenerator } from 'features/nodes/types/generators';
import { t } from 'i18next';
export const validateImageFieldCollectionValue = (
@@ -68,24 +67,12 @@ export const validateStringFieldCollectionValue = (
return reasons;
};
-export const getNumberFieldCollectionValue = (
- fieldValue: NonNullable | NonNullable
-): number[] => {
- if (Array.isArray(fieldValue)) {
- return fieldValue;
- }
- return numberStartStepCountGenerator(fieldValue);
-};
-
export const validateNumberFieldCollectionValue = (
- fieldValue: NonNullable | NonNullable,
+ value: NonNullable | NonNullable,
template: IntegerFieldCollectionInputTemplate | FloatFieldCollectionInputTemplate
): string[] => {
const reasons: string[] = [];
const { minItems, maxItems, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf } = template;
-
- const value = getNumberFieldCollectionValue(fieldValue);
-
const count = value.length;
// Image collections may have min or max items to validate
diff --git a/invokeai/frontend/web/src/features/nodes/types/generators.ts b/invokeai/frontend/web/src/features/nodes/types/generators.ts
deleted file mode 100644
index ddcf958632..0000000000
--- a/invokeai/frontend/web/src/features/nodes/types/generators.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import type { FloatStartStepCountGenerator, IntegerStartStepCountGenerator } from 'features/nodes/types/field';
-
-export const numberStartStepCountGenerator = ({
- start,
- step,
- count,
-}: FloatStartStepCountGenerator | IntegerStartStepCountGenerator): number[] => {
- return Array.from({ length: count }, (_, i) => start + i * step);
-};