From 75acece1f1f171ca3e32a11b6ce97d8518ed4b41 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 8 Nov 2024 08:54:36 +1000 Subject: [PATCH] fix(ui): excessive toasts when generating on canvas - Add `withToast` flag to `uploadImage` util - Skip the toast if this is not set - Use the flag to disable toasts when canvas does internal image-uploading stuff that should be invisible to user --- .../listeners/imageUploaded.ts | 40 ++++++++++--------- .../konva/CanvasCompositorModule.ts | 1 + .../CanvasEntityObjectRenderer.ts | 1 + .../web/src/services/api/endpoints/images.ts | 26 +++++++++++- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts index 77e855e376b..d79ada93b98 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageUploaded.ts @@ -41,26 +41,30 @@ export const addImageUploadedFulfilledListener = (startAppListening: AppStartLis log.debug({ imageDTO }, 'Image uploaded'); - const DEFAULT_UPLOADED_TOAST = { - id: 'IMAGE_UPLOADED', - title: t('toast.imageUploaded'), - status: 'success', - } as const; - - // default action - just upload and alert user const boardId = imageDTO.board_id ?? 'none'; - if (lastUploadedToastTimeout !== null) { - window.clearTimeout(lastUploadedToastTimeout); + + if (action.meta.arg.originalArgs.withToast) { + const DEFAULT_UPLOADED_TOAST = { + id: 'IMAGE_UPLOADED', + title: t('toast.imageUploaded'), + status: 'success', + } as const; + + // default action - just upload and alert user + if (lastUploadedToastTimeout !== null) { + window.clearTimeout(lastUploadedToastTimeout); + } + const toastApi = toast({ + ...DEFAULT_UPLOADED_TOAST, + title: DEFAULT_UPLOADED_TOAST.title, + description: getUploadedToastDescription(boardId, state), + duration: null, // we will close the toast manually + }); + lastUploadedToastTimeout = window.setTimeout(() => { + toastApi.close(); + }, 3000); } - const toastApi = toast({ - ...DEFAULT_UPLOADED_TOAST, - title: DEFAULT_UPLOADED_TOAST.title, - description: getUploadedToastDescription(boardId, state), - duration: null, // we will close the toast manually - }); - lastUploadedToastTimeout = window.setTimeout(() => { - toastApi.close(); - }, 3000); + /** * We only want to change the board and view if this is the first upload of a batch, else we end up hijacking * the user's gallery board and view selection: diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasCompositorModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasCompositorModule.ts index 876c94689f3..6e321f4d791 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasCompositorModule.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasCompositorModule.ts @@ -302,6 +302,7 @@ export class CanvasCompositorModule extends CanvasModuleBase { is_intermediate: uploadOptions.is_intermediate, board_id: uploadOptions.is_intermediate ? undefined : selectAutoAddBoardId(this.manager.store.getState()), metadata: uploadOptions.metadata, + withToast: false, }) ); this.$isUploading.set(false); diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts index ba9b83a7ca2..7af3aad5606 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasEntity/CanvasEntityObjectRenderer.ts @@ -493,6 +493,7 @@ export class CanvasEntityObjectRenderer extends CanvasModuleBase { file: new File([blob], `${this.id}_rasterized.png`, { type: 'image/png' }), image_category: 'other', is_intermediate: true, + withToast: false, }); const imageObject = imageDTOToImageObject(imageDTO); if (replaceObjects) { diff --git a/invokeai/frontend/web/src/services/api/endpoints/images.ts b/invokeai/frontend/web/src/services/api/endpoints/images.ts index c830eddf61d..2464dbe8840 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/images.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/images.ts @@ -271,6 +271,7 @@ export const imagesApi = api.injectEndpoints({ crop_visible?: boolean; metadata?: JsonObject; isFirstUploadOfBatch?: boolean; + withToast?: boolean; } >({ query: ({ file, image_category, is_intermediate, session_id, board_id, crop_visible, metadata }) => { @@ -629,10 +630,20 @@ export type UploadImageArg = { board_id?: string; crop_visible?: boolean; metadata?: JsonObject; + withToast?: boolean; }; export const uploadImage = (arg: UploadImageArg): Promise => { - const { file, image_category, is_intermediate, crop_visible = false, board_id, metadata, session_id } = arg; + const { + file, + image_category, + is_intermediate, + crop_visible = false, + board_id, + metadata, + session_id, + withToast = true, + } = arg; const { dispatch } = getStore(); @@ -646,6 +657,7 @@ export const uploadImage = (arg: UploadImageArg): Promise => { board_id, metadata, session_id, + withToast, }, { track: false } ) @@ -657,7 +669,16 @@ export const uploadImages = async (args: UploadImageArg[]): Promise const { dispatch } = getStore(); const results = await Promise.allSettled( args.map((arg, i) => { - const { file, image_category, is_intermediate, crop_visible = false, board_id, metadata, session_id } = arg; + const { + file, + image_category, + is_intermediate, + crop_visible = false, + board_id, + metadata, + session_id, + withToast = true, + } = arg; const req = dispatch( imagesApi.endpoints.uploadImage.initiate( { @@ -669,6 +690,7 @@ export const uploadImages = async (args: UploadImageArg[]): Promise metadata, session_id, isFirstUploadOfBatch: i === 0, + withToast, }, { track: false } )