mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat: Handle IP Adapter Image being reset on being deleted.
This commit is contained in:
parent
b60b1e359e
commit
4dd289b337
@ -49,6 +49,7 @@
|
|||||||
"close": "Close",
|
"close": "Close",
|
||||||
"communityLabel": "Community",
|
"communityLabel": "Community",
|
||||||
"controlNet": "Controlnet",
|
"controlNet": "Controlnet",
|
||||||
|
"ipAdapter": "IP Adapter",
|
||||||
"darkMode": "Dark Mode",
|
"darkMode": "Dark Mode",
|
||||||
"discordLabel": "Discord",
|
"discordLabel": "Discord",
|
||||||
"dontAskMeAgain": "Don't ask me again",
|
"dontAskMeAgain": "Don't ask me again",
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
||||||
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
import {
|
||||||
|
controlNetReset,
|
||||||
|
ipAdapterStateReset,
|
||||||
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import { getImageUsage } from 'features/deleteImageModal/store/selectors';
|
import { getImageUsage } from 'features/deleteImageModal/store/selectors';
|
||||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||||
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
||||||
@ -18,6 +21,7 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
|
|||||||
let wasCanvasReset = false;
|
let wasCanvasReset = false;
|
||||||
let wasNodeEditorReset = false;
|
let wasNodeEditorReset = false;
|
||||||
let wasControlNetReset = false;
|
let wasControlNetReset = false;
|
||||||
|
let wasIPAdapterReset = false;
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
deleted_images.forEach((image_name) => {
|
deleted_images.forEach((image_name) => {
|
||||||
@ -42,6 +46,11 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
|
|||||||
dispatch(controlNetReset());
|
dispatch(controlNetReset());
|
||||||
wasControlNetReset = true;
|
wasControlNetReset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (imageUsage.isIPAdapterImage && !wasIPAdapterReset) {
|
||||||
|
dispatch(ipAdapterStateReset());
|
||||||
|
wasIPAdapterReset = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -3,6 +3,7 @@ import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
|||||||
import {
|
import {
|
||||||
controlNetImageChanged,
|
controlNetImageChanged,
|
||||||
controlNetProcessedImageChanged,
|
controlNetProcessedImageChanged,
|
||||||
|
ipAdapterImageChanged,
|
||||||
} from 'features/controlNet/store/controlNetSlice';
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
|
||||||
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
|
import { isModalOpenChanged } from 'features/deleteImageModal/store/slice';
|
||||||
@ -110,6 +111,14 @@ export const addRequestedSingleImageDeletionListener = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove IP Adapter Set Image if image is deleted.
|
||||||
|
if (
|
||||||
|
getState().controlNet.ipAdapterInfo.adapterImage?.image_name ===
|
||||||
|
imageDTO.image_name
|
||||||
|
) {
|
||||||
|
dispatch(ipAdapterImageChanged(null));
|
||||||
|
}
|
||||||
|
|
||||||
// reset nodes that use the deleted images
|
// reset nodes that use the deleted images
|
||||||
getState().nodes.nodes.forEach((node) => {
|
getState().nodes.nodes.forEach((node) => {
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
@ -227,6 +236,14 @@ export const addRequestedMultipleImageDeletionListener = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove IP Adapter Set Image if image is deleted.
|
||||||
|
if (
|
||||||
|
getState().controlNet.ipAdapterInfo.adapterImage?.image_name ===
|
||||||
|
imageDTO.image_name
|
||||||
|
) {
|
||||||
|
dispatch(ipAdapterImageChanged(null));
|
||||||
|
}
|
||||||
|
|
||||||
// reset nodes that use the deleted images
|
// reset nodes that use the deleted images
|
||||||
getState().nodes.nodes.forEach((node) => {
|
getState().nodes.nodes.forEach((node) => {
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
|
@ -19,6 +19,7 @@ export const addImageToDeleteSelectedListener = () => {
|
|||||||
imagesUsage.some((i) => i.isCanvasImage) ||
|
imagesUsage.some((i) => i.isCanvasImage) ||
|
||||||
imagesUsage.some((i) => i.isInitialImage) ||
|
imagesUsage.some((i) => i.isInitialImage) ||
|
||||||
imagesUsage.some((i) => i.isControlNetImage) ||
|
imagesUsage.some((i) => i.isControlNetImage) ||
|
||||||
|
imagesUsage.some((i) => i.isIPAdapterImage) ||
|
||||||
imagesUsage.some((i) => i.isNodesImage);
|
imagesUsage.some((i) => i.isNodesImage);
|
||||||
|
|
||||||
if (shouldConfirmOnDelete || isImageInUse) {
|
if (shouldConfirmOnDelete || isImageInUse) {
|
||||||
|
@ -386,6 +386,14 @@ export const controlNetSlice = createSlice({
|
|||||||
) => {
|
) => {
|
||||||
state.ipAdapterInfo.model = action.payload;
|
state.ipAdapterInfo.model = action.payload;
|
||||||
},
|
},
|
||||||
|
ipAdapterStateReset: (state) => {
|
||||||
|
state.isIPAdapterEnabled = false;
|
||||||
|
state.ipAdapterInfo = {
|
||||||
|
adapterImage: null,
|
||||||
|
model: null,
|
||||||
|
weight: 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(controlNetImageProcessed, (state, action) => {
|
builder.addCase(controlNetImageProcessed, (state, action) => {
|
||||||
@ -449,6 +457,7 @@ export const {
|
|||||||
ipAdapterImageChanged,
|
ipAdapterImageChanged,
|
||||||
ipAdapterWeightChanged,
|
ipAdapterWeightChanged,
|
||||||
ipAdapterModelChanged,
|
ipAdapterModelChanged,
|
||||||
|
ipAdapterStateReset,
|
||||||
} = controlNetSlice.actions;
|
} = controlNetSlice.actions;
|
||||||
|
|
||||||
export default controlNetSlice.reducer;
|
export default controlNetSlice.reducer;
|
||||||
|
@ -10,20 +10,20 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
||||||
import { stateSelector } from 'app/store/store';
|
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { imageDeletionConfirmed } from '../store/actions';
|
import { imageDeletionConfirmed } from '../store/actions';
|
||||||
import { getImageUsage, selectImageUsage } from '../store/selectors';
|
import { getImageUsage, selectImageUsage } from '../store/selectors';
|
||||||
import { imageDeletionCanceled, isModalOpenChanged } from '../store/slice';
|
import { imageDeletionCanceled, isModalOpenChanged } from '../store/slice';
|
||||||
import ImageUsageMessage from './ImageUsageMessage';
|
|
||||||
import { ImageUsage } from '../store/types';
|
import { ImageUsage } from '../store/types';
|
||||||
|
import ImageUsageMessage from './ImageUsageMessage';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[stateSelector, selectImageUsage],
|
[stateSelector, selectImageUsage],
|
||||||
@ -42,6 +42,7 @@ const selector = createSelector(
|
|||||||
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
||||||
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
||||||
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
||||||
|
isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage),
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { ImageUsage } from '../store/types';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ImageUsage } from '../store/types';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
imageUsage?: ImageUsage;
|
imageUsage?: ImageUsage;
|
||||||
@ -38,6 +38,9 @@ const ImageUsageMessage = (props: Props) => {
|
|||||||
{imageUsage.isControlNetImage && (
|
{imageUsage.isControlNetImage && (
|
||||||
<ListItem>{t('common.controlNet')}</ListItem>
|
<ListItem>{t('common.controlNet')}</ListItem>
|
||||||
)}
|
)}
|
||||||
|
{imageUsage.isIPAdapterImage && (
|
||||||
|
<ListItem>{t('common.ipAdapter')}</ListItem>
|
||||||
|
)}
|
||||||
{imageUsage.isNodesImage && (
|
{imageUsage.isNodesImage && (
|
||||||
<ListItem>{t('common.nodeEditor')}</ListItem>
|
<ListItem>{t('common.nodeEditor')}</ListItem>
|
||||||
)}
|
)}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
|
import { isInvocationNode } from 'features/nodes/types/types';
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { ImageUsage } from './types';
|
import { ImageUsage } from './types';
|
||||||
import { isInvocationNode } from 'features/nodes/types/types';
|
|
||||||
|
|
||||||
export const getImageUsage = (state: RootState, image_name: string) => {
|
export const getImageUsage = (state: RootState, image_name: string) => {
|
||||||
const { generation, canvas, nodes, controlNet } = state;
|
const { generation, canvas, nodes, controlNet } = state;
|
||||||
@ -27,11 +27,15 @@ export const getImageUsage = (state: RootState, image_name: string) => {
|
|||||||
c.controlImage === image_name || c.processedControlImage === image_name
|
c.controlImage === image_name || c.processedControlImage === image_name
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isIPAdapterImage =
|
||||||
|
controlNet.ipAdapterInfo.adapterImage?.image_name === image_name;
|
||||||
|
|
||||||
const imageUsage: ImageUsage = {
|
const imageUsage: ImageUsage = {
|
||||||
isInitialImage,
|
isInitialImage,
|
||||||
isCanvasImage,
|
isCanvasImage,
|
||||||
isNodesImage,
|
isNodesImage,
|
||||||
isControlNetImage,
|
isControlNetImage,
|
||||||
|
isIPAdapterImage,
|
||||||
};
|
};
|
||||||
|
|
||||||
return imageUsage;
|
return imageUsage;
|
||||||
|
@ -10,4 +10,5 @@ export type ImageUsage = {
|
|||||||
isCanvasImage: boolean;
|
isCanvasImage: boolean;
|
||||||
isNodesImage: boolean;
|
isNodesImage: boolean;
|
||||||
isControlNetImage: boolean;
|
isControlNetImage: boolean;
|
||||||
|
isIPAdapterImage: boolean;
|
||||||
};
|
};
|
||||||
|
@ -53,6 +53,7 @@ const DeleteBoardModal = (props: Props) => {
|
|||||||
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
|
||||||
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
|
||||||
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
isControlNetImage: some(allImageUsage, (i) => i.isControlNetImage),
|
||||||
|
isIPAdapterImage: some(allImageUsage, (i) => i.isIPAdapterImage),
|
||||||
};
|
};
|
||||||
return { imageUsageSummary };
|
return { imageUsageSummary };
|
||||||
}),
|
}),
|
||||||
|
Loading…
Reference in New Issue
Block a user