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,