diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 7f6b196a060..f3dcc8097d0 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -1185,6 +1185,7 @@ "modelAddedSimple": "Model Added to Queue", "modelImportCanceled": "Model Import Canceled", "outOfMemoryError": "Out of Memory Error", + "outOfMemoryErrorDescLocal": "Follow our Low VRAM guide to reduce OOMs.", "outOfMemoryErrorDesc": "Your current generation settings exceed system capacity. Please adjust your settings and try again.", "parameters": "Parameters", "parameterSet": "Parameter Recalled", @@ -2133,7 +2134,7 @@ "toGetStartedLocal": "To get started, make sure to download or import models needed to run Invoke. Then, enter a prompt in the box and click Invoke to generate your first image. Select a prompt template to improve results. You can choose to save your images directly to the Gallery or edit them to the Canvas.", "toGetStarted": "To get started, enter a prompt in the box and click Invoke to generate your first image. Select a prompt template to improve results. You can choose to save your images directly to the Gallery or edit them to the Canvas.", "gettingStartedSeries": "Want more guidance? Check out our Getting Started Series for tips on unlocking the full potential of the Invoke Studio.", - "lowVRAMMode": "For best performance, follow our Low VRAM mode guide.", + "lowVRAMMode": "For best performance, follow our Low VRAM guide.", "noModelsInstalled": "It looks like you don't have any models installed! You can download a starter model bundle or import models." }, "whatsNew": { diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/NoContentForViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/NoContentForViewer.tsx index 08a2b0c3bd9..bc035491a6c 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/NoContentForViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/NoContentForViewer.tsx @@ -1,15 +1,5 @@ -import { - Alert, - AlertDescription, - AlertIcon, - Button, - Divider, - Flex, - Icon, - Link, - Spinner, - Text, -} from '@invoke-ai/ui-library'; +import type { ButtonProps } from '@invoke-ai/ui-library'; +import { Alert, AlertDescription, AlertIcon, Button, Divider, Flex, Link, Spinner, Text } from '@invoke-ai/ui-library'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import { InvokeLogoIcon } from 'common/components/InvokeLogoIcon'; @@ -71,20 +61,19 @@ const LoadingSpinner = () => { ); }; -const ExternalLink = (props: PropsWithChildren<{ href: string }>) => { +export const ExternalLink = (props: ButtonProps & { href: string }) => { return ( + mt={-1} + {...props} + /> ); }; diff --git a/invokeai/frontend/web/src/features/toast/ErrorToastDescription.tsx b/invokeai/frontend/web/src/features/toast/ErrorToastDescription.tsx index 26baf9c739b..23f7ee64bda 100644 --- a/invokeai/frontend/web/src/features/toast/ErrorToastDescription.tsx +++ b/invokeai/frontend/web/src/features/toast/ErrorToastDescription.tsx @@ -1,39 +1,45 @@ import { Flex, IconButton, Text } from '@invoke-ai/ui-library'; -import { t } from 'i18next'; -import { useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; +import { ExternalLink } from 'features/gallery/components/ImageViewer/NoContentForViewer'; +import { useCallback, useMemo } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; import { PiCopyBold } from 'react-icons/pi'; -function onCopy(sessionId: string) { - navigator.clipboard.writeText(sessionId); -} +type Props = { errorType: string; errorMessage?: string | null; sessionId: string; isLocal: boolean }; -const ERROR_TYPE_TO_TITLE: Record = { - OutOfMemoryError: 'toast.outOfMemoryError', -}; +export const ErrorToastTitle = ({ errorType }: Props) => { + const { t } = useTranslation(); -const COMMERCIAL_ERROR_TYPE_TO_DESC: Record = { - OutOfMemoryError: 'toast.outOfMemoryErrorDesc', -}; + if (errorType === 'OutOfMemoryError') { + return t('toast.outOfMemoryError'); + } -export const getTitleFromErrorType = (errorType: string) => { - return t(ERROR_TYPE_TO_TITLE[errorType] ?? 'toast.serverError'); + return t('toast.serverError'); }; -type Props = { errorType: string; errorMessage?: string | null; sessionId: string; isLocal: boolean }; - -export default function ErrorToastDescription({ errorType, errorMessage, sessionId, isLocal }: Props) { +export default function ErrorToastDescription({ errorType, isLocal, sessionId, errorMessage }: Props) { const { t } = useTranslation(); + const description = useMemo(() => { - // Special handling for commercial error types - const descriptionTKey = isLocal ? null : COMMERCIAL_ERROR_TYPE_TO_DESC[errorType]; - if (descriptionTKey) { - return t(descriptionTKey); - } - if (errorMessage) { + if (errorType === 'OutOfMemoryError') { + if (isLocal) { + return ( + , + }} + /> + ); + } else { + return t('toast.outOfMemoryErrorDesc'); + } + } else if (errorMessage) { return `${errorType}: ${errorMessage}`; } }, [errorMessage, errorType, isLocal, t]); + + const copySessionId = useCallback(() => navigator.clipboard.writeText(sessionId), [sessionId]); + return ( {description && ( @@ -50,14 +56,12 @@ export default function ErrorToastDescription({ errorType, errorMessage, session size="sm" aria-label="Copy" icon={} - onClick={onCopy.bind(null, sessionId)} + onClick={copySessionId} variant="ghost" - sx={sx} + sx={{ svg: { fill: 'base.50' } }} /> )} ); } - -const sx = { svg: { fill: 'base.50' } }; diff --git a/invokeai/frontend/web/src/services/events/setEventListeners.tsx b/invokeai/frontend/web/src/services/events/setEventListeners.tsx index b3c8d72cea9..bb389b3406a 100644 --- a/invokeai/frontend/web/src/services/events/setEventListeners.tsx +++ b/invokeai/frontend/web/src/services/events/setEventListeners.tsx @@ -8,7 +8,7 @@ import type { AppStore } from 'app/store/store'; import { deepClone } from 'common/util/deepClone'; import { $nodeExecutionStates, upsertExecutionState } from 'features/nodes/hooks/useExecutionState'; import { zNodeStatus } from 'features/nodes/types/invocation'; -import ErrorToastDescription, { getTitleFromErrorType } from 'features/toast/ErrorToastDescription'; +import ErrorToastDescription, { ErrorToastTitle } from 'features/toast/ErrorToastDescription'; import { toast } from 'features/toast/toast'; import { t } from 'i18next'; import { forEach, isNil, round } from 'lodash-es'; @@ -400,7 +400,14 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis toast({ id: `INVOCATION_ERROR_${error_type}`, - title: getTitleFromErrorType(error_type), + title: ( + + ), status: 'error', duration: null, updateDescription: isLocal,