diff --git a/invokeai/frontend/web/.eslintrc.js b/invokeai/frontend/web/.eslintrc.js index f4af658ea2..0af0ca835b 100644 --- a/invokeai/frontend/web/.eslintrc.js +++ b/invokeai/frontend/web/.eslintrc.js @@ -33,6 +33,18 @@ module.exports = { 'The Clipboard API is not available by default in Firefox. Use the `useClipboard` hook instead, which wraps clipboard access to prevent errors.', }, ], + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: 'lodash-es', + importNames: ['isEqual'], + message: 'Please use objectEquals from @observ33r/object-equals instead.', + }, + ], + }, + ], }, overrides: [ /** diff --git a/invokeai/frontend/web/package.json b/invokeai/frontend/web/package.json index c5e580c049..2d56486545 100644 --- a/invokeai/frontend/web/package.json +++ b/invokeai/frontend/web/package.json @@ -60,7 +60,8 @@ "@fontsource-variable/inter": "^5.2.5", "@invoke-ai/ui-library": "^0.0.46", "@nanostores/react": "^1.0.0", - "@reduxjs/toolkit": "2.8.2", + "@observ33r/object-equals": "^1.1.4", + "@reduxjs/toolkit": "2.7.0", "@roarr/browser-log-writer": "^1.3.0", "@xyflow/react": "^12.6.0", "async-mutex": "^0.5.0", diff --git a/invokeai/frontend/web/pnpm-lock.yaml b/invokeai/frontend/web/pnpm-lock.yaml index 61fba0669c..3d28543249 100644 --- a/invokeai/frontend/web/pnpm-lock.yaml +++ b/invokeai/frontend/web/pnpm-lock.yaml @@ -29,9 +29,12 @@ dependencies: '@nanostores/react': specifier: ^1.0.0 version: 1.0.0(nanostores@1.0.1)(react@18.3.1) + '@observ33r/object-equals': + specifier: ^1.1.4 + version: 1.1.4 '@reduxjs/toolkit': - specifier: 2.8.2 - version: 2.8.2(react-redux@9.2.0)(react@18.3.1) + specifier: 2.7.0 + version: 2.7.0(react-redux@9.2.0)(react@18.3.1) '@roarr/browser-log-writer': specifier: ^1.3.0 version: 1.3.0 @@ -1853,6 +1856,10 @@ packages: fastq: 1.17.1 dev: true + /@observ33r/object-equals@1.1.4: + resolution: {integrity: sha512-a46ys2Zvyyu1NPo8C8mF6FLztVxxaBtXpZwxlQutaaRtQFcD71yTMwyPY4DOuHsz//YEZjLkCw+mJoKDiG/CgA==} + dev: false + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2164,8 +2171,8 @@ packages: - supports-color dev: true - /@reduxjs/toolkit@2.8.2(react-redux@9.2.0)(react@18.3.1): - resolution: {integrity: sha512-MYlOhQ0sLdw4ud48FoC5w0dH9VfWQjtCjreKwYTT3l+r427qYC5Y8PihNutepr8XrNaBUDQo9khWUwQxZaqt5A==} + /@reduxjs/toolkit@2.7.0(react-redux@9.2.0)(react@18.3.1): + resolution: {integrity: sha512-XVwolG6eTqwV0N8z/oDlN93ITCIGIop6leXlGJI/4EKy+0POYkR+ABHRSdGXY+0MQvJBP8yAzh+EYFxTuvmBiQ==} peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -3098,7 +3105,7 @@ packages: /@types/lodash.mergewith@4.6.7: resolution: {integrity: sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A==} dependencies: - '@types/lodash': 4.17.16 + '@types/lodash': 4.17.18 dev: false /@types/lodash.mergewith@4.6.9: @@ -3110,8 +3117,8 @@ packages: /@types/lodash@4.17.10: resolution: {integrity: sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==} - /@types/lodash@4.17.16: - resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==} + /@types/lodash@4.17.18: + resolution: {integrity: sha512-KJ65INaxqxmU6EoCiJmRPZC9H9RVWCRd349tXM2M3O5NA7cY6YL7c0bHAHQ93NOfTObEQ004kd2QVHs/r0+m4g==} dev: false /@types/mdx@2.0.13: diff --git a/invokeai/frontend/web/src/app/store/createMemoizedSelector.ts b/invokeai/frontend/web/src/app/store/createMemoizedSelector.ts index e9ecc6966d..7e32afbd3c 100644 --- a/invokeai/frontend/web/src/app/store/createMemoizedSelector.ts +++ b/invokeai/frontend/web/src/app/store/createMemoizedSelector.ts @@ -1,13 +1,13 @@ +import { objectEquals } from '@observ33r/object-equals'; import { createDraftSafeSelectorCreator, createSelectorCreator, lruMemoize } from '@reduxjs/toolkit'; -import { isEqual } from 'lodash-es'; /** - * A memoized selector creator that uses LRU cache and lodash's isEqual for equality check. + * A memoized selector creator that uses LRU cache and @observ33r/object-equals's objectEquals for equality check. */ export const createMemoizedSelector = createSelectorCreator({ memoize: lruMemoize, memoizeOptions: { - resultEqualityCheck: isEqual, + resultEqualityCheck: objectEquals, }, argsMemoize: lruMemoize, }); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketConnected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketConnected.ts index 8556a6becc..a66cbe74e5 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketConnected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketConnected.ts @@ -1,8 +1,8 @@ +import { objectEquals } from '@observ33r/object-equals'; import { createAction } from '@reduxjs/toolkit'; import { logger } from 'app/logging/logger'; import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; import { $baseUrl } from 'app/store/nanostores/baseUrl'; -import { isEqual } from 'lodash-es'; import { atom } from 'nanostores'; import { api } from 'services/api'; import { modelsApi } from 'services/api/endpoints/models'; @@ -64,7 +64,7 @@ export const addSocketConnectedEventListener = (startAppListening: AppStartListe const nextQueueStatusData = await queueStatusRequest.unwrap(); // If the queue hasn't changed, we don't need to do anything. - if (isEqual(prevQueueStatusData?.queue, nextQueueStatusData.queue)) { + if (objectEquals(prevQueueStatusData?.queue, nextQueueStatusData.queue)) { return; } diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts index 0b00dacb7b..44a029ea68 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasObject/CanvasObjectImage.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import { Mutex } from 'async-mutex'; import { deepClone } from 'common/util/deepClone'; import { withResultAsync } from 'common/util/result'; @@ -12,7 +13,6 @@ import { getKonvaNodeDebugAttrs, loadImage } from 'features/controlLayers/konva/ import type { CanvasImageState } from 'features/controlLayers/store/types'; import { t } from 'i18next'; import Konva from 'konva'; -import { isEqual } from 'lodash-es'; import type { Logger } from 'roarr'; import { getImageDTOSafe } from 'services/api/endpoints/images'; @@ -198,7 +198,7 @@ export class CanvasObjectImage extends CanvasModuleBase { const { image } = state; const { width, height } = image; - if (force || (!isEqual(this.state, state) && !this.isLoading)) { + if (force || (!objectEquals(this.state, state) && !this.isLoading)) { const release = await this.mutex.acquire(); try { diff --git a/invokeai/frontend/web/src/features/controlLayers/store/refImagesSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/refImagesSlice.ts index c979bd1685..535e1dfc74 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/refImagesSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/refImagesSlice.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { PayloadAction } from '@reduxjs/toolkit'; import { createSelector, createSlice } from '@reduxjs/toolkit'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; @@ -6,7 +7,7 @@ import { getPrefixedId } from 'features/controlLayers/konva/util'; import { canvasMetadataRecalled } from 'features/controlLayers/store/canvasSlice'; import type { FLUXReduxImageInfluence, RefImagesState } from 'features/controlLayers/store/types'; import { zModelIdentifierField } from 'features/nodes/types/common'; -import { clamp, isEqual } from 'lodash-es'; +import { clamp } from 'lodash-es'; import type { ApiModelConfig, FLUXReduxModelConfig, ImageDTO, IPAdapterModelConfig } from 'services/api/types'; import { assert } from 'tsafe'; import type { PartialDeep } from 'type-fest'; @@ -102,7 +103,7 @@ export const refImagesSlice = createSlice({ return; } - if (isEqual(oldModel, entity.config.model)) { + if (objectEquals(oldModel, entity.config.model)) { // Nothing changed, so we don't need to do anything return; } diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts index f10d4fd6be..eae9db2e16 100644 --- a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts @@ -1,7 +1,8 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; import type { PersistConfig, RootState } from 'app/store/store'; -import { isEqual, uniq } from 'lodash-es'; +import { uniq } from 'lodash-es'; import type { BoardRecordOrderBy } from 'services/api/types'; import type { BoardId, ComparisonMode, GalleryState, GalleryView, OrderDir } from './types'; @@ -53,7 +54,7 @@ export const gallerySlice = createSlice({ } // If the selected image is different from the current selection, clear the selection and select the new image - if (!isEqual(state.selection[0], selectedImageName)) { + if (state.selection[0] !== selectedImageName) { state.selection = [selectedImageName]; return; } @@ -74,7 +75,7 @@ export const gallerySlice = createSlice({ } // If the new selection is different, update the selection - if (!isEqual(newSelection, state.selection)) { + if (!objectEquals(newSelection, state.selection)) { state.selection = newSelection; return; } diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldDefaultValue.ts b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldDefaultValue.ts index 1c9c929b8c..ab3bc1319b 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldDefaultValue.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldDefaultValue.ts @@ -1,10 +1,10 @@ +import { objectEquals } from '@observ33r/object-equals'; import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useInputFieldTemplateOrThrow } from 'features/nodes/hooks/useInputFieldTemplateOrThrow'; import { fieldValueReset } from 'features/nodes/store/nodesSlice'; import { selectNodesSlice } from 'features/nodes/store/selectors'; import { isInvocationNode } from 'features/nodes/types/invocation'; -import { isEqual } from 'lodash-es'; import { useCallback, useMemo } from 'react'; export const useInputFieldDefaultValue = (nodeId: string, fieldName: string) => { @@ -19,7 +19,7 @@ export const useInputFieldDefaultValue = (nodeId: string, fieldName: string) => return; } const value = node.data.inputs[fieldName]?.value; - return !isEqual(value, fieldTemplate.default); + return !objectEquals(value, fieldTemplate.default); }), [fieldName, fieldTemplate.default, nodeId] ); diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldInitialFormValue.ts b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldInitialFormValue.ts index ce1f117426..436da83852 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldInitialFormValue.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useInputFieldInitialFormValue.ts @@ -1,9 +1,9 @@ +import { objectEquals } from '@observ33r/object-equals'; import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { fieldValueReset } from 'features/nodes/store/nodesSlice'; import { selectNodesSlice } from 'features/nodes/store/selectors'; import { isInvocationNode } from 'features/nodes/types/invocation'; -import { isEqual } from 'lodash-es'; import { useCallback, useMemo } from 'react'; const uniqueNonexistentValue = Symbol('uniqueNonexistentValue'); @@ -32,7 +32,7 @@ export const useInputFieldInitialFormValue = (elementId: string, nodeId: string, return; } const value = node.data.inputs[fieldName]?.value; - return !isEqual(value, initialValue); + return !objectEquals(value, initialValue); }), [fieldName, initialValue, nodeId] ); diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useNodeCopyPaste.ts b/invokeai/frontend/web/src/features/nodes/hooks/useNodeCopyPaste.ts index 979cfa74fd..4dd29e00c5 100644 --- a/invokeai/frontend/web/src/features/nodes/hooks/useNodeCopyPaste.ts +++ b/invokeai/frontend/web/src/features/nodes/hooks/useNodeCopyPaste.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { EdgeChange, NodeChange } from '@xyflow/react'; import { logger } from 'app/logging/logger'; import { getStore } from 'app/store/nanostores/store'; @@ -16,7 +17,7 @@ import { findUnoccupiedPosition } from 'features/nodes/store/util/findUnoccupied import { validateConnection } from 'features/nodes/store/util/validateConnection'; import type { AnyEdge, AnyNode } from 'features/nodes/types/invocation'; import { t } from 'i18next'; -import { isEqual, uniqWith } from 'lodash-es'; +import { uniqWith } from 'lodash-es'; import { v4 as uuidv4 } from 'uuid'; const log = logger('workflows'); @@ -44,7 +45,7 @@ const _pasteSelection = (withEdgesToCopiedNodes?: boolean) => { if (withEdgesToCopiedNodes) { const edgesToCopiedNodes = deepClone($edgesToCopiedNodes.get()); - copiedEdges = uniqWith([...copiedEdges, ...edgesToCopiedNodes], isEqual); + copiedEdges = uniqWith([...copiedEdges, ...edgesToCopiedNodes], objectEquals); } // Calculate an offset to reposition nodes to surround the cursor position, maintaining relative positioning diff --git a/invokeai/frontend/web/src/features/nodes/store/util/areTypesEqual.ts b/invokeai/frontend/web/src/features/nodes/store/util/areTypesEqual.ts index 8502cb563c..1e0fa768b8 100644 --- a/invokeai/frontend/web/src/features/nodes/store/util/areTypesEqual.ts +++ b/invokeai/frontend/web/src/features/nodes/store/util/areTypesEqual.ts @@ -1,5 +1,6 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { FieldType } from 'features/nodes/types/field'; -import { isEqual, omit } from 'lodash-es'; +import { omit } from 'lodash-es'; /** * Checks if two types are equal. If the field types have original types, those are also compared. Any match is @@ -13,16 +14,16 @@ export const areTypesEqual = (firstType: FieldType, secondType: FieldType) => { const _secondType = 'originalType' in secondType ? omit(secondType, 'originalType') : secondType; const _originalFirstType = 'originalType' in firstType ? firstType.originalType : null; const _originalSecondType = 'originalType' in secondType ? secondType.originalType : null; - if (isEqual(_firstType, _secondType)) { + if (objectEquals(_firstType, _secondType)) { return true; } - if (_originalSecondType && isEqual(_firstType, _originalSecondType)) { + if (_originalSecondType && objectEquals(_firstType, _originalSecondType)) { return true; } - if (_originalFirstType && isEqual(_originalFirstType, _secondType)) { + if (_originalFirstType && objectEquals(_originalFirstType, _secondType)) { return true; } - if (_originalFirstType && _originalSecondType && isEqual(_originalFirstType, _originalSecondType)) { + if (_originalFirstType && _originalSecondType && objectEquals(_originalFirstType, _originalSecondType)) { return true; } return false; diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/Graph.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/Graph.ts index 9da719509b..2841bd27a7 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/Graph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/Graph.ts @@ -1,6 +1,7 @@ +import { objectEquals } from '@observ33r/object-equals'; import { getPrefixedId } from 'features/controlLayers/konva/util'; import { type ModelIdentifierField, zModelIdentifierField } from 'features/nodes/types/common'; -import { forEach, groupBy, isEqual, unset, values } from 'lodash-es'; +import { forEach, groupBy, unset, values } from 'lodash-es'; import type { AnyInvocation, AnyInvocationIncMetadata, @@ -169,7 +170,7 @@ export class Graph { source: { node_id: fromNode.id, field: fromField }, destination: { node_id: toNode.id, field: toField }, }; - const edgeAlreadyExists = this._graph.edges.some((e) => isEqual(e, edge)); + const edgeAlreadyExists = this._graph.edges.some((e) => objectEquals(e, edge)); assert(!edgeAlreadyExists, `Edge ${Graph.edgeToString(edge)} already exists`); this._graph.edges.push(edge); return edge; @@ -182,7 +183,7 @@ export class Graph { * @raises `AssertionError` if an edge with the same source and destination already exists. */ addEdgeFromObj(edge: Edge): Edge { - const edgeAlreadyExists = this._graph.edges.some((e) => isEqual(e, edge)); + const edgeAlreadyExists = this._graph.edges.some((e) => objectEquals(e, edge)); assert(!edgeAlreadyExists, `Edge ${Graph.edgeToString(edge)} already exists`); this._graph.edges.push(edge); return edge; @@ -275,11 +276,11 @@ export class Graph { } /** - * INTERNAL: Delete _all_ matching edges from the graph. Uses _.isEqual for comparison. + * INTERNAL: Delete _all_ matching edges from the graph. Uses _.objectEquals for comparison. * @param edge The edge to delete */ private _deleteEdge(edge: Edge): void { - this._graph.edges = this._graph.edges.filter((e) => !isEqual(e, edge)); + this._graph.edges = this._graph.edges.filter((e) => !objectEquals(e, edge)); } /** @@ -317,7 +318,7 @@ export class Graph { this.getNode(edge.source.node_id); this.getNode(edge.destination.node_id); assert( - !this._graph.edges.filter((e) => e !== edge).find((e) => isEqual(e, edge)), + !this._graph.edges.filter((e) => e !== edge).find((e) => objectEquals(e, edge)), `Duplicate edge: ${Graph.edgeToString(edge)}` ); } diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addFLUXFill.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addFLUXFill.ts index c839bfbf18..2925630822 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addFLUXFill.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addFLUXFill.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { RootState } from 'app/store/store'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import { getPrefixedId } from 'features/controlLayers/konva/util'; @@ -6,7 +7,6 @@ import { selectParamsSlice } from 'features/controlLayers/store/paramsSlice'; import { selectCanvasSlice } from 'features/controlLayers/store/selectors'; import type { Dimensions } from 'features/controlLayers/store/types'; import type { Graph } from 'features/nodes/util/graph/generation/Graph'; -import { isEqual } from 'lodash-es'; import type { Invocation } from 'services/api/types'; type AddFLUXFillArg = { @@ -52,7 +52,7 @@ export const addFLUXFill = async ({ const fluxFill = g.addNode({ type: 'flux_fill', id: getPrefixedId('flux_fill') }); - const needsScaleBeforeProcessing = !isEqual(scaledSize, originalSize); + const needsScaleBeforeProcessing = !objectEquals(scaledSize, originalSize); if (needsScaleBeforeProcessing) { // Scale before processing requires some resizing diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts index 07b15980f2..86896ff4ac 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addImageToImage.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import { getPrefixedId } from 'features/controlLayers/konva/util'; import type { CanvasState, Dimensions } from 'features/controlLayers/store/types'; @@ -8,7 +9,6 @@ import type { MainModelLoaderNodes, VaeSourceNodes, } from 'features/nodes/util/graph/types'; -import { isEqual } from 'lodash-es'; import type { Invocation } from 'services/api/types'; type AddImageToImageArg = { @@ -45,7 +45,7 @@ export const addImageToImage = async ({ silent: true, }); - if (!isEqual(scaledSize, originalSize)) { + if (!objectEquals(scaledSize, originalSize)) { // Resize the initial image to the scaled size, denoise, then resize back to the original size const resizeImageToScaledSize = g.addNode({ type: 'img_resize', diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts index 82191385a0..f0273c0a66 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addInpaint.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { RootState } from 'app/store/store'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import { getPrefixedId } from 'features/controlLayers/konva/util'; @@ -13,7 +14,6 @@ import type { MainModelLoaderNodes, VaeSourceNodes, } from 'features/nodes/util/graph/types'; -import { isEqual } from 'lodash-es'; import type { ImageDTO, Invocation } from 'services/api/types'; type AddInpaintArg = { @@ -93,7 +93,7 @@ export const addInpaint = async ({ } ); - const needsScaleBeforeProcessing = !isEqual(scaledSize, originalSize); + const needsScaleBeforeProcessing = !objectEquals(scaledSize, originalSize); if (needsScaleBeforeProcessing) { // Scale before processing requires some resizing diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts index d02e6c6621..e11fc61b67 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addOutpaint.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import type { RootState } from 'app/store/store'; import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; import { getPrefixedId } from 'features/controlLayers/konva/util'; @@ -14,7 +15,6 @@ import type { MainModelLoaderNodes, VaeSourceNodes, } from 'features/nodes/util/graph/types'; -import { isEqual } from 'lodash-es'; import type { ImageDTO, Invocation } from 'services/api/types'; type AddOutpaintArg = { @@ -98,7 +98,7 @@ export const addOutpaint = async ({ const infill = getInfill(g, params); - const needsScaleBeforeProcessing = !isEqual(scaledSize, originalSize); + const needsScaleBeforeProcessing = !objectEquals(scaledSize, originalSize); if (needsScaleBeforeProcessing) { // Scale before processing requires some resizing diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts index 5878aa9580..227d2066bd 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/generation/addTextToImage.ts @@ -1,8 +1,8 @@ +import { objectEquals } from '@observ33r/object-equals'; import { getPrefixedId } from 'features/controlLayers/konva/util'; import type { Dimensions } from 'features/controlLayers/store/types'; import type { Graph } from 'features/nodes/util/graph/generation/Graph'; import type { LatentToImageNodes } from 'features/nodes/util/graph/types'; -import { isEqual } from 'lodash-es'; import type { Invocation } from 'services/api/types'; type AddTextToImageArg = { @@ -18,7 +18,7 @@ export const addTextToImage = ({ originalSize, scaledSize, }: AddTextToImageArg): Invocation<'img_resize' | 'l2i' | 'flux_vae_decode' | 'sd3_l2i' | 'cogview4_l2i'> => { - if (!isEqual(scaledSize, originalSize)) { + if (!objectEquals(scaledSize, originalSize)) { // We need to resize the output image back to the original size const resizeImageToOriginalSize = g.addNode({ id: getPrefixedId('resize_image_to_original_size'), diff --git a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts index a28c1fedf9..a5521aef83 100644 --- a/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/schema/parseSchema.ts @@ -1,3 +1,4 @@ +import { objectEquals } from '@observ33r/object-equals'; import { logger } from 'app/logging/logger'; import { deepClone } from 'common/util/deepClone'; import { parseify } from 'common/util/serialize'; @@ -17,7 +18,7 @@ import { isInvocationSchemaObject, } from 'features/nodes/types/openapi'; import { t } from 'i18next'; -import { isEqual, reduce } from 'lodash-es'; +import { reduce } from 'lodash-es'; import type { OpenAPIV3_1 } from 'openapi-types'; import { serializeError } from 'serialize-error'; import type { JsonObject } from 'type-fest'; @@ -153,7 +154,7 @@ export const parseSchema = ( return inputsAccumulator; } - if (isStatefulFieldType(fieldType) && originalFieldType && !isEqual(originalFieldType, fieldType)) { + if (isStatefulFieldType(fieldType) && originalFieldType && !objectEquals(originalFieldType, fieldType)) { fieldType.originalType = deepClone(originalFieldType); } @@ -225,7 +226,7 @@ export const parseSchema = ( return outputsAccumulator; } - if (isStatefulFieldType(fieldType) && originalFieldType && !isEqual(originalFieldType, fieldType)) { + if (isStatefulFieldType(fieldType) && originalFieldType && !objectEquals(originalFieldType, fieldType)) { fieldType.originalType = deepClone(originalFieldType); }