diff --git a/frontend/src/app/socketio/emitters.ts b/frontend/src/app/socketio/emitters.ts
index 8ed94f17f3..fd534f014c 100644
--- a/frontend/src/app/socketio/emitters.ts
+++ b/frontend/src/app/socketio/emitters.ts
@@ -8,6 +8,7 @@ import {
import {
GalleryCategory,
GalleryState,
+ removeImage,
} from '../../features/gallery/gallerySlice';
import { OptionsState } from '../../features/options/optionsSlice';
import {
@@ -163,6 +164,7 @@ const makeSocketIOEmitters = (
},
emitDeleteImage: (imageToDelete: InvokeAI.Image) => {
const { url, uuid, category } = imageToDelete;
+ dispatch(removeImage(imageToDelete));
socketio.emit('deleteImage', url, uuid, category);
},
emitRequestImages: (category: GalleryCategory) => {
diff --git a/frontend/src/features/gallery/CurrentImageButtons.tsx b/frontend/src/features/gallery/CurrentImageButtons.tsx
index 7a6dc4e3fa..363c8689df 100644
--- a/frontend/src/features/gallery/CurrentImageButtons.tsx
+++ b/frontend/src/features/gallery/CurrentImageButtons.tsx
@@ -17,13 +17,7 @@ import { SystemState } from '../system/systemSlice';
import IAIButton from '../../common/components/IAIButton';
import { runESRGAN, runFacetool } from '../../app/socketio/actions';
import IAIIconButton from '../../common/components/IAIIconButton';
-import {
- MdDelete,
- MdFace,
- MdHd,
- MdImage,
- MdInfo,
-} from 'react-icons/md';
+import { MdDelete, MdFace, MdHd, MdImage, MdInfo } from 'react-icons/md';
import InvokePopover from './InvokePopover';
import UpscaleOptions from '../options/AdvancedOptions/Upscale/UpscaleOptions';
import FaceRestoreOptions from '../options/AdvancedOptions/FaceRestore/FaceRestoreOptions';
@@ -360,7 +354,9 @@ const CurrentImageButtons = ({ image }: CurrentImageButtonsProps) => {
icon={}
tooltip="Delete Image"
aria-label="Delete Image"
- isDisabled={Boolean(intermediateImage)}
+ isDisabled={
+ Boolean(intermediateImage) || !isConnected || isProcessing
+ }
/>
diff --git a/frontend/src/features/gallery/DeleteImageModal.tsx b/frontend/src/features/gallery/DeleteImageModal.tsx
index 29aa370278..002fb875f5 100644
--- a/frontend/src/features/gallery/DeleteImageModal.tsx
+++ b/frontend/src/features/gallery/DeleteImageModal.tsx
@@ -30,6 +30,13 @@ import { setShouldConfirmOnDelete, SystemState } from '../system/systemSlice';
import * as InvokeAI from '../../app/invokeai';
import { useHotkeys } from 'react-hotkeys-hook';
+const systemSelector = createSelector(
+ (state: RootState) => state.system,
+ (system: SystemState) => {
+ const { shouldConfirmOnDelete, isConnected, isProcessing } = system;
+ return { shouldConfirmOnDelete, isConnected, isProcessing };
+ }
+);
interface DeleteImageModalProps {
/**
* Component which, on click, should delete the image/open the modal.
@@ -41,11 +48,6 @@ interface DeleteImageModalProps {
image: InvokeAI.Image;
}
-const systemSelector = createSelector(
- (state: RootState) => state.system,
- (system: SystemState) => system.shouldConfirmOnDelete
-);
-
/**
* Needs a child, which will act as the button to delete an image.
* If system.shouldConfirmOnDelete is true, a confirmation modal is displayed.
@@ -56,9 +58,9 @@ const DeleteImageModal = forwardRef(
({ image, children }: DeleteImageModalProps, ref) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const dispatch = useAppDispatch();
- const shouldConfirmOnDelete = useAppSelector(systemSelector);
+ const { shouldConfirmOnDelete, isConnected, isProcessing } =
+ useAppSelector(systemSelector);
const cancelRef = useRef(null);
- const toast = useToast();
const handleClickDelete = (e: SyntheticEvent) => {
e.stopPropagation();
@@ -66,13 +68,9 @@ const DeleteImageModal = forwardRef(
};
const handleDelete = () => {
- dispatch(deleteImage(image));
- toast({
- title: 'Image Deleted',
- status: 'success',
- duration: 2500,
- isClosable: true,
- });
+ if (isConnected && !isProcessing) {
+ dispatch(deleteImage(image));
+ }
onClose();
};
diff --git a/frontend/src/features/gallery/HoverableImage.tsx b/frontend/src/features/gallery/HoverableImage.tsx
index e3dcabb158..23348a69b7 100644
--- a/frontend/src/features/gallery/HoverableImage.tsx
+++ b/frontend/src/features/gallery/HoverableImage.tsx
@@ -39,8 +39,12 @@ const memoEqualityCheck = (
*/
const HoverableImage = memo((props: HoverableImageProps) => {
const dispatch = useAppDispatch();
- const { activeTabName, galleryImageObjectFit, galleryImageMinimumWidth } =
- useAppSelector(hoverableImageSelector);
+ const {
+ activeTabName,
+ galleryImageObjectFit,
+ galleryImageMinimumWidth,
+ mayDeleteImage,
+ } = useAppSelector(hoverableImageSelector);
const { image, isSelected } = props;
const { url, uuid, metadata } = image;
@@ -177,6 +181,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
size="xs"
variant={'imageHoverIconButton'}
fontSize={14}
+ isDisabled={!mayDeleteImage}
/>
diff --git a/frontend/src/features/gallery/gallerySliceSelectors.ts b/frontend/src/features/gallery/gallerySliceSelectors.ts
index ddf823f331..56d7c9e247 100644
--- a/frontend/src/features/gallery/gallerySliceSelectors.ts
+++ b/frontend/src/features/gallery/gallerySliceSelectors.ts
@@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit';
import { RootState } from '../../app/store';
import { activeTabNameSelector } from '../options/optionsSelectors';
import { OptionsState } from '../options/optionsSlice';
+import { SystemState } from '../system/systemSlice';
import { GalleryState } from './gallerySlice';
export const imageGallerySelector = createSelector(
@@ -46,9 +47,20 @@ export const imageGallerySelector = createSelector(
);
export const hoverableImageSelector = createSelector(
- [(state: RootState) => state.options, (state: RootState) => state.gallery, activeTabNameSelector],
- (options: OptionsState, gallery: GalleryState, activeTabName) => {
+ [
+ (state: RootState) => state.options,
+ (state: RootState) => state.gallery,
+ (state: RootState) => state.system,
+ activeTabNameSelector,
+ ],
+ (
+ options: OptionsState,
+ gallery: GalleryState,
+ system: SystemState,
+ activeTabName
+ ) => {
return {
+ mayDeleteImage: system.isConnected && !system.isProcessing,
galleryImageObjectFit: gallery.galleryImageObjectFit,
galleryImageMinimumWidth: gallery.galleryImageMinimumWidth,
activeTabName,