diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts index eb7a793d3a..d3f20971b7 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardAndImagesDeleted.ts @@ -1,7 +1,5 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; -import { resetCanvas } from 'features/canvas/store/canvasSlice'; -import { controlAdaptersReset } from 'features/controlAdapters/store/controlAdaptersSlice'; -import { allLayersDeleted } from 'features/controlLayers/store/canvasV2Slice'; +import { caAllDeleted, ipaAllDeleted, layerAllDeleted } from 'features/controlLayers/store/canvasV2Slice'; import { getImageUsage } from 'features/deleteImageModal/store/selectors'; import { nodeEditorReset } from 'features/nodes/store/nodesSlice'; import { imagesApi } from 'services/api/endpoints/images'; @@ -14,18 +12,18 @@ export const addDeleteBoardAndImagesFulfilledListener = (startAppListening: AppS // Remove all deleted images from the UI - let wasCanvasReset = false; + let wereLayersReset = false; let wasNodeEditorReset = false; let wereControlAdaptersReset = false; - let wereControlLayersReset = false; + let wereIPAdaptersReset = false; - const { canvas, nodes, controlAdapters, canvasV2 } = getState(); + const { nodes, canvasV2 } = getState(); deleted_images.forEach((image_name) => { - const imageUsage = getImageUsage(canvas, nodes.present, controlAdapters, canvasV2, image_name); + const imageUsage = getImageUsage(nodes.present, canvasV2, image_name); - if (imageUsage.isCanvasImage && !wasCanvasReset) { - dispatch(resetCanvas()); - wasCanvasReset = true; + if (imageUsage.isLayerImage && !wereLayersReset) { + dispatch(layerAllDeleted()); + wereLayersReset = true; } if (imageUsage.isNodesImage && !wasNodeEditorReset) { @@ -33,14 +31,14 @@ export const addDeleteBoardAndImagesFulfilledListener = (startAppListening: AppS wasNodeEditorReset = true; } - if (imageUsage.isControlImage && !wereControlAdaptersReset) { - dispatch(controlAdaptersReset()); + if (imageUsage.isControlAdapterImage && !wereControlAdaptersReset) { + dispatch(caAllDeleted()); wereControlAdaptersReset = true; } - if (imageUsage.isControlLayerImage && !wereControlLayersReset) { - dispatch(allLayersDeleted()); - wereControlLayersReset = true; + if (imageUsage.isIPAdapterImage && !wereIPAdaptersReset) { + dispatch(ipaAllDeleted()); + wereIPAdaptersReset = true; } }); }, diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts index cb4e9ec8c8..7b579d2a4a 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts @@ -3,18 +3,11 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware' import type { AppDispatch, RootState } from 'app/store/store'; import { resetCanvas } from 'features/canvas/store/canvasSlice'; import { - controlAdapterImageChanged, - controlAdapterProcessedImageChanged, - selectControlAdapterAll, -} from 'features/controlAdapters/store/controlAdaptersSlice'; -import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; -import { layerDeleted } from 'features/controlLayers/store/canvasV2Slice'; -import { - isControlAdapterLayer, - isInitialImageLayer, - isIPAdapterLayer, - isRegionalGuidanceLayer, -} from 'features/controlLayers/store/types'; + caImageChanged, + caProcessedImageChanged, + ipaImageChanged, + layerDeleted, +} from 'features/controlLayers/store/canvasV2Slice'; import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions'; import { isModalOpenChanged } from 'features/deleteImageModal/store/slice'; import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors'; @@ -48,51 +41,33 @@ const deleteNodesImages = (state: RootState, dispatch: AppDispatch, imageDTO: Im }; const deleteControlAdapterImages = (state: RootState, dispatch: AppDispatch, imageDTO: ImageDTO) => { - forEach(selectControlAdapterAll(state.controlAdapters), (ca) => { - if ( - ca.controlImage === imageDTO.image_name || - (isControlNetOrT2IAdapter(ca) && ca.processedControlImage === imageDTO.image_name) - ) { - dispatch( - controlAdapterImageChanged({ - id: ca.id, - controlImage: null, - }) - ); - dispatch( - controlAdapterProcessedImageChanged({ - id: ca.id, - processedControlImage: null, - }) - ); + state.canvasV2.controlAdapters.forEach(({ id, image, processedImage }) => { + if (image?.name === imageDTO.image_name || processedImage?.name === imageDTO.image_name) { + dispatch(caImageChanged({ id, imageDTO: null })); + dispatch(caProcessedImageChanged({ id, imageDTO: null })); } }); }; -const deleteControlLayerImages = (state: RootState, dispatch: AppDispatch, imageDTO: ImageDTO) => { - state.canvasV2.layers.forEach((l) => { - if (isRegionalGuidanceLayer(l)) { - if (l.ipAdapters.some((ipa) => ipa.image?.name === imageDTO.image_name)) { - dispatch(layerDeleted(l.id)); +const deleteIPAdapterImages = (state: RootState, dispatch: AppDispatch, imageDTO: ImageDTO) => { + state.canvasV2.ipAdapters.forEach(({ id, image }) => { + if (image?.name === imageDTO.image_name) { + dispatch(ipaImageChanged({ id, imageDTO: null })); + } + }); +}; + +const deleteLayerImages = (state: RootState, dispatch: AppDispatch, imageDTO: ImageDTO) => { + state.canvasV2.layers.forEach(({ id, objects }) => { + let shouldDelete = false; + for (const obj of objects) { + if (obj.type === 'image' && obj.image.name === imageDTO.image_name) { + shouldDelete = true; + break; } } - if (isControlAdapterLayer(l)) { - if ( - l.controlAdapter.image?.name === imageDTO.image_name || - l.controlAdapter.processedImage?.name === imageDTO.image_name - ) { - dispatch(layerDeleted(l.id)); - } - } - if (isIPAdapterLayer(l)) { - if (l.ipAdapter.image?.name === imageDTO.image_name) { - dispatch(layerDeleted(l.id)); - } - } - if (isInitialImageLayer(l)) { - if (l.image?.name === imageDTO.image_name) { - dispatch(layerDeleted(l.id)); - } + if (shouldDelete) { + dispatch(layerDeleted({ id })); } }); }; @@ -145,14 +120,10 @@ export const addImageDeletionListeners = (startAppListening: AppStartListening) } } - // We need to reset the features where the image is in use - none of these work if their image(s) don't exist - if (imageUsage.isCanvasImage) { - dispatch(resetCanvas()); - } - - deleteControlAdapterImages(state, dispatch, imageDTO); deleteNodesImages(state, dispatch, imageDTO); - deleteControlLayerImages(state, dispatch, imageDTO); + deleteControlAdapterImages(state, dispatch, imageDTO); + deleteIPAdapterImages(state, dispatch, imageDTO); + deleteLayerImages(state, dispatch, imageDTO); } catch { // no-op } finally { @@ -189,14 +160,15 @@ export const addImageDeletionListeners = (startAppListening: AppStartListening) // We need to reset the features where the image is in use - none of these work if their image(s) don't exist - if (imagesUsage.some((i) => i.isCanvasImage)) { + if (imagesUsage.some((i) => i.isLayerImage)) { dispatch(resetCanvas()); } imageDTOs.forEach((imageDTO) => { - deleteControlAdapterImages(state, dispatch, imageDTO); deleteNodesImages(state, dispatch, imageDTO); - deleteControlLayerImages(state, dispatch, imageDTO); + deleteControlAdapterImages(state, dispatch, imageDTO); + deleteIPAdapterImages(state, dispatch, imageDTO); + deleteLayerImages(state, dispatch, imageDTO); }); } catch { // no-op diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts index 845c9a21f2..2e20d97b46 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageToDeleteSelected.ts @@ -13,9 +13,10 @@ export const addImageToDeleteSelectedListener = (startAppListening: AppStartList const imagesUsage = selectImageUsage(getState()); const isImageInUse = - imagesUsage.some((i) => i.isCanvasImage) || - imagesUsage.some((i) => i.isControlImage) || - imagesUsage.some((i) => i.isNodesImage); + imagesUsage.some((i) => i.isLayerImage) || + imagesUsage.some((i) => i.isControlAdapterImage) || + imagesUsage.some((i) => i.isIPAdapterImage) || + imagesUsage.some((i) => i.isLayerImage); if (shouldConfirmOnDelete || isImageInUse) { dispatch(isModalOpenChanged(true)); diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts index 8b1721cb3f..60abd47769 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts @@ -194,11 +194,13 @@ export const { layerLinePointAdded, layerRectAdded, layerImageAdded, + layerAllDeleted, // IP Adapters ipaAdded, ipaRecalled, ipaIsEnabledToggled, ipaDeleted, + ipaAllDeleted, ipaImageChanged, ipaMethodChanged, ipaModelChanged, @@ -209,6 +211,7 @@ export const { caAdded, caBboxChanged, caDeleted, + caAllDeleted, caIsEnabledToggled, caMovedBackwardOne, caMovedForwardOne, @@ -234,6 +237,7 @@ export const { rgTranslated, rgBboxChanged, rgDeleted, + rgAllDeleted, rgGlobalOpacityChanged, rgMovedForwardOne, rgMovedToFront, diff --git a/invokeai/frontend/web/src/features/controlLayers/store/controlAdaptersReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/controlAdaptersReducers.ts index 84c12e5f3a..0a744c6c28 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/controlAdaptersReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/controlAdaptersReducers.ts @@ -82,6 +82,9 @@ export const controlAdaptersReducers = { const { id } = action.payload; state.controlAdapters = state.controlAdapters.filter((ca) => ca.id !== id); }, + caAllDeleted: (state) => { + state.controlAdapters = []; + }, caOpacityChanged: (state, action: PayloadAction<{ id: string; opacity: number }>) => { const { id, opacity } = action.payload; const ca = selectCA(state, id); diff --git a/invokeai/frontend/web/src/features/controlLayers/store/ipAdaptersReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/ipAdaptersReducers.ts index 16cf222b60..fb6ff8d987 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/ipAdaptersReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/ipAdaptersReducers.ts @@ -39,7 +39,11 @@ export const ipAdaptersReducers = { } }, ipaDeleted: (state, action: PayloadAction<{ id: string }>) => { - state.ipAdapters = state.ipAdapters.filter((ipa) => ipa.id !== action.payload.id); + const { id } = action.payload; + state.ipAdapters = state.ipAdapters.filter((ipa) => ipa.id !== id); + }, + ipaAllDeleted: (state) => { + state.ipAdapters = []; }, ipaImageChanged: (state, action: PayloadAction<{ id: string; imageDTO: ImageDTO | null }>) => { const { id, imageDTO } = action.payload; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts index d44585fd4f..6b3e58f8a2 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/layersReducers.ts @@ -88,6 +88,9 @@ export const layersReducers = { const { id } = action.payload; state.layers = state.layers.filter((l) => l.id !== id); }, + layerAllDeleted: (state) => { + state.layers = []; + }, layerOpacityChanged: (state, action: PayloadAction<{ id: string; opacity: number }>) => { const { id, opacity } = action.payload; const layer = selectLayer(state, id); diff --git a/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts index 56f3b935d9..35b584adb7 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/regionsReducers.ts @@ -117,6 +117,9 @@ export const regionsReducers = { const { id } = action.payload; state.regions = state.regions.filter((ca) => ca.id !== id); }, + rgAllDeleted: (state) => { + state.regions = []; + }, rgGlobalOpacityChanged: (state, action: PayloadAction<{ opacity: number }>) => { const { opacity } = action.payload; state.maskFillOpacity = opacity; diff --git a/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx b/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx index 3d33999c71..30f59aed1f 100644 --- a/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx +++ b/invokeai/frontend/web/src/features/deleteImageModal/components/DeleteImageModal.tsx @@ -1,8 +1,6 @@ import { ConfirmationAlertDialog, Divider, Flex, FormControl, FormLabel, Switch, Text } from '@invoke-ai/ui-library'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { selectCanvasSlice } from 'features/canvas/store/canvasSlice'; -import { selectControlAdaptersSlice } from 'features/controlAdapters/store/controlAdaptersSlice'; import { selectCanvasV2Slice } from 'features/controlLayers/store/canvasV2Slice'; import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions'; import { getImageUsage, selectImageUsage } from 'features/deleteImageModal/store/selectors'; @@ -22,26 +20,17 @@ import { useTranslation } from 'react-i18next'; import ImageUsageMessage from './ImageUsageMessage'; const selectImageUsages = createMemoizedSelector( - [ - selectDeleteImageModalSlice, - selectCanvasSlice, - selectNodesSlice, - selectControlAdaptersSlice, - selectCanvasV2Slice, - selectImageUsage, - ], - (deleteImageModal, canvas, nodes, controlAdapters, controlLayers, imagesUsage) => { + [selectDeleteImageModalSlice, selectNodesSlice, selectCanvasV2Slice, selectImageUsage], + (deleteImageModal, nodes, canvasV2, imagesUsage) => { const { imagesToDelete } = deleteImageModal; - const allImageUsage = (imagesToDelete ?? []).map(({ image_name }) => - getImageUsage(canvas, nodes, controlAdapters, canvasV2, image_name) - ); + const allImageUsage = (imagesToDelete ?? []).map(({ image_name }) => getImageUsage(nodes, canvasV2, image_name)); const imageUsageSummary: ImageUsage = { - isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage), + isLayerImage: some(allImageUsage, (i) => i.isLayerImage), isNodesImage: some(allImageUsage, (i) => i.isNodesImage), - isControlImage: some(allImageUsage, (i) => i.isControlImage), - isControlLayerImage: some(allImageUsage, (i) => i.isControlLayerImage), + isControlAdapterImage: some(allImageUsage, (i) => i.isControlAdapterImage), + isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage), }; return { diff --git a/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx b/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx index d76716d01d..8f71922e0a 100644 --- a/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx +++ b/invokeai/frontend/web/src/features/deleteImageModal/components/ImageUsageMessage.tsx @@ -29,10 +29,10 @@ const ImageUsageMessage = (props: Props) => { <> {topMessage} - {imageUsage.isCanvasImage && {t('ui.tabs.canvasTab')}} - {imageUsage.isControlImage && {t('common.controlNet')}} + {imageUsage.isLayerImage && {t('controlLayers.layers')}} + {imageUsage.isControlAdapterImage && {t('controlLayers.controlAdapters')}} + {imageUsage.isIPAdapterImage && {t('controlLayers.ipAdapters')}} {imageUsage.isNodesImage && {t('ui.tabs.workflowsTab')}} - {imageUsage.isControlLayerImage && {t('ui.tabs.generationTab')}} {bottomMessage} diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts index ce36e9080d..5874fe9c71 100644 --- a/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts +++ b/invokeai/frontend/web/src/features/deleteImageModal/store/selectors.ts @@ -1,20 +1,6 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; -import { selectCanvasSlice } from 'features/canvas/store/canvasSlice'; -import type { CanvasState } from 'features/canvas/store/canvasTypes'; -import { - selectControlAdapterAll, - selectControlAdaptersSlice, -} from 'features/controlAdapters/store/controlAdaptersSlice'; -import type { ControlAdaptersState } from 'features/controlAdapters/store/types'; -import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { selectCanvasV2Slice } from 'features/controlLayers/store/canvasV2Slice'; import type { CanvasV2State } from 'features/controlLayers/store/types'; -import { - isControlAdapterLayer, - isInitialImageLayer, - isIPAdapterLayer, - isRegionalGuidanceLayer, -} from 'features/controlLayers/store/types'; import { selectDeleteImageModalSlice } from 'features/deleteImageModal/store/slice'; import { selectNodesSlice } from 'features/nodes/store/nodesSlice'; import type { NodesState } from 'features/nodes/store/types'; @@ -24,47 +10,28 @@ import { some } from 'lodash-es'; import type { ImageUsage } from './types'; -export const getImageUsage = ( - canvas: CanvasState, - nodes: NodesState, - controlAdapters: ControlAdaptersState, - controlLayers: CanvasV2State, - image_name: string -) => { - const isCanvasImage = canvas.layerState.objects.some((obj) => obj.kind === 'image' && obj.imageName === image_name); - - const isNodesImage = nodes.nodes.filter(isInvocationNode).some((node) => { - return some( - node.data.inputs, - (input) => isImageFieldInputInstance(input) && input.value?.image_name === image_name - ); - }); - - const isControlImage = selectControlAdapterAll(controlAdapters).some( - (ca) => ca.controlImage === image_name || (isControlNetOrT2IAdapter(ca) && ca.processedControlImage === image_name) +export const getImageUsage = (nodes: NodesState, canvasV2: CanvasV2State, image_name: string) => { + const isLayerImage = canvasV2.layers.some((layer) => + layer.objects.some((obj) => obj.type === 'image' && obj.image.name === image_name) ); - const isControlLayerImage = controlLayers.layers.some((l) => { - if (isRegionalGuidanceLayer(l)) { - return l.ipAdapters.some((ipa) => ipa.image?.name === image_name); - } - if (isControlAdapterLayer(l)) { - return l.controlAdapter.image?.name === image_name || l.controlAdapter.processedImage?.name === image_name; - } - if (isIPAdapterLayer(l)) { - return l.ipAdapter.image?.name === image_name; - } - if (isInitialImageLayer(l)) { - return l.image?.name === image_name; - } - return false; - }); + const isNodesImage = nodes.nodes + .filter(isInvocationNode) + .some((node) => + some(node.data.inputs, (input) => isImageFieldInputInstance(input) && input.value?.image_name === image_name) + ); + + const isControlAdapterImage = canvasV2.controlAdapters.some( + (ca) => ca.image?.name === image_name || ca.processedImage?.name === image_name + ); + + const isIPAdapterImage = canvasV2.ipAdapters.some((ipa) => ipa.image?.name === image_name); const imageUsage: ImageUsage = { - isCanvasImage, + isLayerImage, isNodesImage, - isControlImage, - isControlLayerImage, + isControlAdapterImage, + isIPAdapterImage, }; return imageUsage; @@ -72,20 +39,16 @@ export const getImageUsage = ( export const selectImageUsage = createMemoizedSelector( selectDeleteImageModalSlice, - selectCanvasSlice, selectNodesSlice, - selectControlAdaptersSlice, selectCanvasV2Slice, - (deleteImageModal, canvas, nodes, controlAdapters, controlLayers) => { + (deleteImageModal, nodes, canvasV2) => { const { imagesToDelete } = deleteImageModal; if (!imagesToDelete.length) { return []; } - const imagesUsage = imagesToDelete.map((i) => - getImageUsage(canvas, nodes, controlAdapters, canvasV2, i.image_name) - ); + const imagesUsage = imagesToDelete.map((i) => getImageUsage(nodes, canvasV2, i.image_name)); return imagesUsage; } diff --git a/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts b/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts index 2cc3dd90b4..259a510646 100644 --- a/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts +++ b/invokeai/frontend/web/src/features/deleteImageModal/store/types.ts @@ -6,8 +6,8 @@ export type DeleteImageState = { }; export type ImageUsage = { - isCanvasImage: boolean; isNodesImage: boolean; - isControlImage: boolean; - isControlLayerImage: boolean; + isControlAdapterImage: boolean; + isIPAdapterImage: boolean; + isLayerImage: boolean; }; diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/DeleteBoardModal.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/DeleteBoardModal.tsx index fd9a52a69d..9ef21177da 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/DeleteBoardModal.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/DeleteBoardModal.tsx @@ -13,8 +13,6 @@ import { import { skipToken } from '@reduxjs/toolkit/query'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { useAppSelector } from 'app/store/storeHooks'; -import { selectCanvasSlice } from 'features/canvas/store/canvasSlice'; -import { selectControlAdaptersSlice } from 'features/controlAdapters/store/controlAdaptersSlice'; import { selectCanvasV2Slice } from 'features/controlLayers/store/canvasV2Slice'; import ImageUsageMessage from 'features/deleteImageModal/components/ImageUsageMessage'; import { getImageUsage } from 'features/deleteImageModal/store/selectors'; @@ -41,23 +39,18 @@ const DeleteBoardModal = (props: Props) => { const selectImageUsageSummary = useMemo( () => - createMemoizedSelector( - [selectCanvasSlice, selectNodesSlice, selectControlAdaptersSlice, selectCanvasV2Slice], - (canvas, nodes, controlAdapters, controlLayers) => { - const allImageUsage = (boardImageNames ?? []).map((imageName) => - getImageUsage(canvas, nodes, controlAdapters, canvasV2, imageName) - ); + createMemoizedSelector([selectNodesSlice, selectCanvasV2Slice], (nodes, canvasV2) => { + const allImageUsage = (boardImageNames ?? []).map((imageName) => getImageUsage(nodes, canvasV2, imageName)); - const imageUsageSummary: ImageUsage = { - isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage), - isNodesImage: some(allImageUsage, (i) => i.isNodesImage), - isControlImage: some(allImageUsage, (i) => i.isControlImage), - isControlLayerImage: some(allImageUsage, (i) => i.isControlLayerImage), - }; + const imageUsageSummary: ImageUsage = { + isLayerImage: some(allImageUsage, (i) => i.isLayerImage), + isNodesImage: some(allImageUsage, (i) => i.isNodesImage), + isControlAdapterImage: some(allImageUsage, (i) => i.isControlAdapterImage), + isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage), + }; - return imageUsageSummary; - } - ), + return imageUsageSummary; + }), [boardImageNames] ); diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx index 6af1aaf8b2..19ad53eede 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx @@ -15,7 +15,6 @@ import { imageToCompareChanged } from 'features/gallery/store/gallerySlice'; import { $templates } from 'features/nodes/store/nodesSlice'; import { selectOptimalDimension } from 'features/parameters/store/generationSlice'; import { upscaleInitialImageChanged } from 'features/parameters/store/upscaleSlice'; -import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { toast } from 'features/toast/toast'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { useGetAndLoadEmbeddedWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadEmbeddedWorkflow'; @@ -52,7 +51,6 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const maySelectForCompare = useAppSelector((s) => s.gallery.imageToCompare?.image_name !== imageDTO.image_name); const dispatch = useAppDispatch(); const { t } = useTranslation(); - const isCanvasEnabled = useFeatureStatus('canvas'); const customStarUi = useStore($customStarUI); const { downloadImage } = useDownloadImage(); const templates = useStore($templates);