diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx
index eb6496f43e..e819c04352 100644
--- a/invokeai/frontend/web/src/app/components/App.tsx
+++ b/invokeai/frontend/web/src/app/components/App.tsx
@@ -2,9 +2,6 @@ import ImageUploader from 'common/components/ImageUploader';
import SiteHeader from 'features/system/components/SiteHeader';
import ProgressBar from 'features/system/components/ProgressBar';
import InvokeTabs from 'features/ui/components/InvokeTabs';
-
-import useToastWatcher from 'features/system/hooks/useToastWatcher';
-
import FloatingGalleryButton from 'features/ui/components/FloatingGalleryButton';
import FloatingParametersPanelButtons from 'features/ui/components/FloatingParametersPanelButtons';
import { Box, Flex, Grid, Portal } from '@chakra-ui/react';
@@ -17,13 +14,14 @@ import { motion, AnimatePresence } from 'framer-motion';
import Loading from 'common/components/Loading/Loading';
import { useIsApplicationReady } from 'features/system/hooks/useIsApplicationReady';
import { PartialAppConfig } from 'app/types/invokeai';
-import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
import { configChanged } from 'features/system/store/configSlice';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { useLogger } from 'app/logging/useLogger';
import ParametersDrawer from 'features/ui/components/ParametersDrawer';
import { languageSelector } from 'features/system/store/systemSelectors';
import i18n from 'i18n';
+import Toaster from './Toaster';
+import GlobalHotkeys from './GlobalHotkeys';
const DEFAULT_CONFIG = {};
@@ -38,9 +36,6 @@ const App = ({
headerComponent,
setIsReady,
}: Props) => {
- useToastWatcher();
- useGlobalHotkeys();
-
const language = useAppSelector(languageSelector);
const log = useLogger();
@@ -77,65 +72,69 @@ const App = ({
}, [isApplicationReady, setIsReady]);
return (
-
- {isLightboxEnabled && }
-
-
-
- {headerComponent || }
-
+
+ {isLightboxEnabled && }
+
+
+
-
-
-
-
+ {headerComponent || }
+
+
+
+
+
-
-
+
+
-
- {!isApplicationReady && !loadingOverridden && (
-
-
-
-
-
-
- )}
-
+
+ {!isApplicationReady && !loadingOverridden && (
+
+
+
+
+
+
+ )}
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ >
);
};
diff --git a/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts
similarity index 89%
rename from invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts
rename to invokeai/frontend/web/src/app/components/GlobalHotkeys.ts
index 3935a390fb..c4660416bf 100644
--- a/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts
+++ b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts
@@ -10,6 +10,7 @@ import {
togglePinParametersPanel,
} from 'features/ui/store/uiSlice';
import { isEqual } from 'lodash-es';
+import React, { memo } from 'react';
import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook';
const globalHotkeysSelector = createSelector(
@@ -27,7 +28,11 @@ const globalHotkeysSelector = createSelector(
// TODO: Does not catch keypresses while focused in an input. Maybe there is a way?
-export const useGlobalHotkeys = () => {
+/**
+ * Logical component. Handles app-level global hotkeys.
+ * @returns null
+ */
+const GlobalHotkeys: React.FC = () => {
const dispatch = useAppDispatch();
const { shift } = useAppSelector(globalHotkeysSelector);
@@ -75,4 +80,8 @@ export const useGlobalHotkeys = () => {
useHotkeys('4', () => {
dispatch(setActiveTab('nodes'));
});
+
+ return null;
};
+
+export default memo(GlobalHotkeys);
diff --git a/invokeai/frontend/web/src/app/components/Toaster.ts b/invokeai/frontend/web/src/app/components/Toaster.ts
new file mode 100644
index 0000000000..66ba1d4925
--- /dev/null
+++ b/invokeai/frontend/web/src/app/components/Toaster.ts
@@ -0,0 +1,65 @@
+import { useToast, UseToastOptions } from '@chakra-ui/react';
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { toastQueueSelector } from 'features/system/store/systemSelectors';
+import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
+import { useCallback, useEffect } from 'react';
+
+export type MakeToastArg = string | UseToastOptions;
+
+/**
+ * Makes a toast from a string or a UseToastOptions object.
+ * If a string is passed, the toast will have the status 'info' and will be closable with a duration of 2500ms.
+ */
+export const makeToast = (arg: MakeToastArg): UseToastOptions => {
+ if (typeof arg === 'string') {
+ return {
+ title: arg,
+ status: 'info',
+ isClosable: true,
+ duration: 2500,
+ };
+ }
+
+ return { status: 'info', isClosable: true, duration: 2500, ...arg };
+};
+
+/**
+ * Logical component. Watches the toast queue and makes toasts when the queue is not empty.
+ * @returns null
+ */
+const Toaster = () => {
+ const dispatch = useAppDispatch();
+ const toastQueue = useAppSelector(toastQueueSelector);
+ const toast = useToast();
+ useEffect(() => {
+ toastQueue.forEach((t) => {
+ toast(t);
+ });
+ toastQueue.length > 0 && dispatch(clearToastQueue());
+ }, [dispatch, toast, toastQueue]);
+
+ return null;
+};
+
+/**
+ * Returns a function that can be used to make a toast.
+ * @example
+ * const toaster = useAppToaster();
+ * toaster('Hello world!');
+ * toaster({ title: 'Hello world!', status: 'success' });
+ * @returns A function that can be used to make a toast.
+ * @see makeToast
+ * @see MakeToastArg
+ * @see UseToastOptions
+ */
+export const useAppToaster = () => {
+ const dispatch = useAppDispatch();
+ const toaster = useCallback(
+ (arg: MakeToastArg) => dispatch(addToast(makeToast(arg))),
+ [dispatch]
+ );
+
+ return toaster;
+};
+
+export default Toaster;
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts
index 6bc2f9e9bc..ae3a35f537 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/initialImageSelected.ts
@@ -2,11 +2,11 @@ import { initialImageChanged } from 'features/parameters/store/generationSlice';
import { Image, isInvokeAIImage } from 'app/types/invokeai';
import { selectResultsById } from 'features/gallery/store/resultsSlice';
import { selectUploadsById } from 'features/gallery/store/uploadsSlice';
-import { makeToast } from 'features/system/hooks/useToastWatcher';
import { t } from 'i18next';
import { addToast } from 'features/system/store/systemSlice';
import { startAppListening } from '..';
import { initialImageSelected } from 'features/parameters/store/actions';
+import { makeToast } from 'app/components/Toaster';
export const addInitialImageSelectedListener = () => {
startAppListening({
diff --git a/invokeai/frontend/web/src/common/components/ImageUploader.tsx b/invokeai/frontend/web/src/common/components/ImageUploader.tsx
index ee3b9d135e..c773fb85ed 100644
--- a/invokeai/frontend/web/src/common/components/ImageUploader.tsx
+++ b/invokeai/frontend/web/src/common/components/ImageUploader.tsx
@@ -1,4 +1,4 @@
-import { Box, useToast } from '@chakra-ui/react';
+import { Box } from '@chakra-ui/react';
import { ImageUploaderTriggerContext } from 'app/contexts/ImageUploaderTriggerContext';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import useImageUploader from 'common/hooks/useImageUploader';
@@ -16,6 +16,7 @@ import { FileRejection, useDropzone } from 'react-dropzone';
import { useTranslation } from 'react-i18next';
import { imageUploaded } from 'services/thunks/image';
import ImageUploadOverlay from './ImageUploadOverlay';
+import { useAppToaster } from 'app/components/Toaster';
type ImageUploaderProps = {
children: ReactNode;
@@ -25,7 +26,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
const { children } = props;
const dispatch = useAppDispatch();
const activeTabName = useAppSelector(activeTabNameSelector);
- const toast = useToast({});
+ const toaster = useAppToaster();
const { t } = useTranslation();
const [isHandlingUpload, setIsHandlingUpload] = useState(false);
const { setOpenUploader } = useImageUploader();
@@ -37,14 +38,14 @@ const ImageUploader = (props: ImageUploaderProps) => {
(acc: string, cur: { message: string }) => `${acc}\n${cur.message}`,
''
);
- toast({
+ toaster({
title: t('toast.uploadFailed'),
description: msg,
status: 'error',
isClosable: true,
});
},
- [t, toast]
+ [t, toaster]
);
const fileAcceptedCallback = useCallback(
@@ -105,7 +106,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
e.stopImmediatePropagation();
if (imageItems.length > 1) {
- toast({
+ toaster({
description: t('toast.uploadFailedMultipleImagesDesc'),
status: 'error',
isClosable: true,
@@ -116,7 +117,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
const file = imageItems[0].getAsFile();
if (!file) {
- toast({
+ toaster({
description: t('toast.uploadFailedUnableToLoadDesc'),
status: 'error',
isClosable: true,
@@ -130,7 +131,7 @@ const ImageUploader = (props: ImageUploaderProps) => {
return () => {
document.removeEventListener('paste', pasteImageListener);
};
- }, [t, dispatch, toast, activeTabName]);
+ }, [t, dispatch, toaster, activeTabName]);
const overlaySecondaryText = ['img2img', 'unifiedCanvas'].includes(
activeTabName
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
index e76f3fa41e..980c317ac3 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
@@ -5,15 +5,8 @@ import {
ButtonGroup,
Flex,
FlexProps,
- IconButton,
Link,
- Menu,
- MenuButton,
- MenuItemOption,
- MenuList,
- MenuOptionGroup,
useDisclosure,
- useToast,
} from '@chakra-ui/react';
// import { runESRGAN, runFacetool } from 'app/socketio/actions';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
@@ -70,6 +63,7 @@ import FaceRestoreSettings from 'features/parameters/components/Parameters/FaceR
import UpscaleSettings from 'features/parameters/components/Parameters/Upscale/UpscaleSettings';
import { allParametersSet } from 'features/parameters/store/generationSlice';
import DeleteImageButton from './ImageActionButtons/DeleteImageButton';
+import { useAppToaster } from 'app/components/Toaster';
const currentImageButtonsSelector = createSelector(
[
@@ -164,7 +158,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
onClose: onDeleteDialogClose,
} = useDisclosure();
- const toast = useToast();
+ const toaster = useAppToaster();
const { t } = useTranslation();
const { recallPrompt, recallSeed, recallAllParameters } = useParameters();
@@ -213,7 +207,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
const url = getImageUrl();
if (!url) {
- toast({
+ toaster({
title: t('toast.problemCopyingImageLink'),
status: 'error',
duration: 2500,
@@ -224,14 +218,14 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
}
navigator.clipboard.writeText(url).then(() => {
- toast({
+ toaster({
title: t('toast.imageLinkCopied'),
status: 'success',
duration: 2500,
isClosable: true,
});
});
- }, [toast, shouldTransformUrls, getUrl, t, image]);
+ }, [toaster, shouldTransformUrls, getUrl, t, image]);
const handlePreviewVisibility = useCallback(() => {
dispatch(setShouldHidePreview(!shouldHidePreview));
@@ -346,13 +340,13 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
dispatch(setActiveTab('unifiedCanvas'));
}
- toast({
+ toaster({
title: t('toast.sentToUnifiedCanvas'),
status: 'success',
duration: 2500,
isClosable: true,
});
- }, [image, isLightboxOpen, dispatch, activeTabName, toast, t]);
+ }, [image, isLightboxOpen, dispatch, activeTabName, toaster, t]);
useHotkeys(
'i',
@@ -360,7 +354,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
if (image) {
handleClickShowImageDetails();
} else {
- toast({
+ toaster({
title: t('toast.metadataLoadFailed'),
status: 'error',
duration: 2500,
@@ -368,7 +362,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
});
}
},
- [image, shouldShowImageDetails]
+ [image, shouldShowImageDetails, toaster]
);
const handleDelete = useCallback(() => {
diff --git a/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx b/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx
index c3980a9ad4..6eb44de99c 100644
--- a/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/HoverableImage.tsx
@@ -6,7 +6,6 @@ import {
MenuItem,
MenuList,
useDisclosure,
- useToast,
} from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { imageSelected } from 'features/gallery/store/gallerySlice';
@@ -35,6 +34,7 @@ import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { useParameters } from 'features/parameters/hooks/useParameters';
import { initialImageSelected } from 'features/parameters/store/actions';
import { requestedImageDeletion } from '../store/actions';
+import { useAppToaster } from 'app/components/Toaster';
export const selector = createSelector(
[gallerySelector, systemSelector, lightboxSelector, activeTabNameSelector],
@@ -101,7 +101,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
const [isHovered, setIsHovered] = useState(false);
- const toast = useToast();
+ const toaster = useAppToaster();
const { t } = useTranslation();
@@ -176,7 +176,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
dispatch(setActiveTab('unifiedCanvas'));
}
- toast({
+ toaster({
title: t('toast.sentToUnifiedCanvas'),
status: 'success',
duration: 2500,
diff --git a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx b/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx
index a4ce2f55f6..db390ed518 100644
--- a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx
@@ -13,10 +13,9 @@ import { nodeAdded } from '../store/nodesSlice';
import { map } from 'lodash-es';
import { RootState } from 'app/store/store';
import { useBuildInvocation } from '../hooks/useBuildInvocation';
-import { addToast } from 'features/system/store/systemSlice';
-import { makeToast } from 'features/system/hooks/useToastWatcher';
import { AnyInvocationType } from 'services/events/types';
import IAIIconButton from 'common/components/IAIIconButton';
+import { useAppToaster } from 'app/components/Toaster';
const AddNodeMenu = () => {
const dispatch = useAppDispatch();
@@ -27,22 +26,23 @@ const AddNodeMenu = () => {
const buildInvocation = useBuildInvocation();
+ const toaster = useAppToaster();
+
const addNode = useCallback(
(nodeType: AnyInvocationType) => {
const invocation = buildInvocation(nodeType);
if (!invocation) {
- const toast = makeToast({
+ toaster({
status: 'error',
title: `Unknown Invocation type ${nodeType}`,
});
- dispatch(addToast(toast));
return;
}
dispatch(nodeAdded(invocation));
},
- [dispatch, buildInvocation]
+ [dispatch, buildInvocation, toaster]
);
return (
diff --git a/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx b/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx
index b06619e76f..c441297fe8 100644
--- a/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/search/NodeSearch.tsx
@@ -16,11 +16,11 @@ import {
import { Tooltip } from '@chakra-ui/tooltip';
import { AnyInvocationType } from 'services/events/types';
import { useBuildInvocation } from 'features/nodes/hooks/useBuildInvocation';
-import { makeToast } from 'features/system/hooks/useToastWatcher';
import { addToast } from 'features/system/store/systemSlice';
import { nodeAdded } from '../../store/nodesSlice';
import Fuse from 'fuse.js';
import { InvocationTemplate } from 'features/nodes/types/types';
+import { useAppToaster } from 'app/components/Toaster';
interface NodeListItemProps {
title: string;
@@ -63,6 +63,7 @@ const NodeSearch = () => {
const buildInvocation = useBuildInvocation();
const dispatch = useAppDispatch();
+ const toaster = useAppToaster();
const [searchText, setSearchText] = useState('');
const [showNodeList, setShowNodeList] = useState(false);
@@ -89,17 +90,16 @@ const NodeSearch = () => {
const invocation = buildInvocation(nodeType);
if (!invocation) {
- const toast = makeToast({
+ toaster({
status: 'error',
title: `Unknown Invocation type ${nodeType}`,
});
- dispatch(addToast(toast));
return;
}
dispatch(nodeAdded(invocation));
},
- [dispatch, buildInvocation]
+ [dispatch, buildInvocation, toaster]
);
const renderNodeList = () => {
diff --git a/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts b/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts
index a093010343..138d54402c 100644
--- a/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts
+++ b/invokeai/frontend/web/src/features/parameters/hooks/useParameters.ts
@@ -1,4 +1,3 @@
-import { useToast } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
import { isFinite, isString } from 'lodash-es';
import { useCallback } from 'react';
@@ -10,10 +9,11 @@ import { NUMPY_RAND_MAX } from 'app/constants';
import { initialImageSelected } from '../store/actions';
import { Image } from 'app/types/invokeai';
import { setActiveTab } from 'features/ui/store/uiSlice';
+import { useAppToaster } from 'app/components/Toaster';
export const useParameters = () => {
const dispatch = useAppDispatch();
- const toast = useToast();
+ const toaster = useAppToaster();
const { t } = useTranslation();
const setBothPrompts = useSetBothPrompts();
@@ -23,7 +23,7 @@ export const useParameters = () => {
const recallPrompt = useCallback(
(prompt: unknown) => {
if (!isString(prompt)) {
- toast({
+ toaster({
title: t('toast.promptNotSet'),
description: t('toast.promptNotSetDesc'),
status: 'warning',
@@ -34,14 +34,14 @@ export const useParameters = () => {
}
setBothPrompts(prompt);
- toast({
+ toaster({
title: t('toast.promptSet'),
status: 'info',
duration: 2500,
isClosable: true,
});
},
- [t, toast, setBothPrompts]
+ [t, toaster, setBothPrompts]
);
/**
@@ -51,7 +51,7 @@ export const useParameters = () => {
(seed: unknown) => {
const s = Number(seed);
if (!isFinite(s) || (isFinite(s) && !(s >= 0 && s <= NUMPY_RAND_MAX))) {
- toast({
+ toaster({
title: t('toast.seedNotSet'),
description: t('toast.seedNotSetDesc'),
status: 'warning',
@@ -62,14 +62,14 @@ export const useParameters = () => {
}
dispatch(setSeed(s));
- toast({
+ toaster({
title: t('toast.seedSet'),
status: 'info',
duration: 2500,
isClosable: true,
});
},
- [t, toast, dispatch]
+ [t, toaster, dispatch]
);
/**
@@ -78,7 +78,7 @@ export const useParameters = () => {
const recallInitialImage = useCallback(
async (image: unknown) => {
if (!isImageField(image)) {
- toast({
+ toaster({
title: t('toast.initialImageNotSet'),
description: t('toast.initialImageNotSetDesc'),
status: 'warning',
@@ -91,14 +91,14 @@ export const useParameters = () => {
dispatch(
initialImageSelected({ name: image.image_name, type: image.image_type })
);
- toast({
+ toaster({
title: t('toast.initialImageSet'),
status: 'info',
duration: 2500,
isClosable: true,
});
},
- [t, toast, dispatch]
+ [t, toaster, dispatch]
);
/**
@@ -123,14 +123,14 @@ export const useParameters = () => {
dispatch(setActiveTab('txt2img'));
}
- toast({
+ toaster({
title: t('toast.parametersSet'),
status: 'success',
duration: 2500,
isClosable: true,
});
} else {
- toast({
+ toaster({
title: t('toast.parametersNotSet'),
description: t('toast.parametersNotSetDesc'),
status: 'error',
@@ -139,7 +139,7 @@ export const useParameters = () => {
});
}
},
- [t, toast, dispatch]
+ [t, toaster, dispatch]
);
return {
diff --git a/invokeai/frontend/web/src/features/system/hooks/useToastWatcher.ts b/invokeai/frontend/web/src/features/system/hooks/useToastWatcher.ts
deleted file mode 100644
index b51bf48a36..0000000000
--- a/invokeai/frontend/web/src/features/system/hooks/useToastWatcher.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { useToast, UseToastOptions } from '@chakra-ui/react';
-import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
-import { toastQueueSelector } from 'features/system/store/systemSelectors';
-import { clearToastQueue } from 'features/system/store/systemSlice';
-import { useEffect } from 'react';
-
-export type MakeToastArg = string | UseToastOptions;
-
-export const makeToast = (arg: MakeToastArg): UseToastOptions => {
- if (typeof arg === 'string') {
- return {
- title: arg,
- status: 'info',
- isClosable: true,
- duration: 2500,
- };
- }
-
- return { status: 'info', isClosable: true, duration: 2500, ...arg };
-};
-
-const useToastWatcher = () => {
- const dispatch = useAppDispatch();
- const toastQueue = useAppSelector(toastQueueSelector);
- const toast = useToast();
- useEffect(() => {
- toastQueue.forEach((t) => {
- toast(t);
- });
- toastQueue.length > 0 && dispatch(clearToastQueue());
- }, [dispatch, toast, toastQueue]);
-};
-
-export default useToastWatcher;
diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts
index 5cc6ca3a43..bbe7ed4da6 100644
--- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts
+++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts
@@ -15,7 +15,7 @@ import {
} from 'services/events/actions';
import { ProgressImage } from 'services/events/types';
-import { makeToast } from '../hooks/useToastWatcher';
+import { makeToast } from '../../../app/components/Toaster';
import { sessionCanceled, sessionInvoked } from 'services/thunks/session';
import { receivedModels } from 'services/thunks/model';
import { parsedOpenAPISchema } from 'features/nodes/store/nodesSlice';
diff --git a/invokeai/frontend/web/src/services/events/util/setEventListeners.ts b/invokeai/frontend/web/src/services/events/util/setEventListeners.ts
index 88bb11147c..e9356dd271 100644
--- a/invokeai/frontend/web/src/services/events/util/setEventListeners.ts
+++ b/invokeai/frontend/web/src/services/events/util/setEventListeners.ts
@@ -22,7 +22,7 @@ import {
} from 'services/thunks/gallery';
import { receivedModels } from 'services/thunks/model';
import { receivedOpenAPISchema } from 'services/thunks/schema';
-import { makeToast } from '../../../features/system/hooks/useToastWatcher';
+import { makeToast } from '../../../app/components/Toaster';
import { addToast } from '../../../features/system/store/systemSlice';
type SetEventListenersArg = {