Adds useToastWatcher hook

- Dispatch an `addToast` action with standard Chakra toast options object to add a toast to the toastQueue
- The hook is called in App.tsx and just useEffect's w/ toastQueue as dependency to create the toasts
- So now you can add toasts anywhere you have access to `dispatch`, which includes middleware and thunks
- Adds first usage of this for the save image buttons in canvas
This commit is contained in:
psychedelicious 2022-11-18 20:07:34 +11:00 committed by blessedcoolant
parent c69573e65d
commit 04cb2d39cb
8 changed files with 62 additions and 32 deletions

View File

@ -15,6 +15,7 @@ import { activeTabNameSelector } from 'features/options/optionsSelectors';
import { SystemState } from 'features/system/systemSlice';
import _ from 'lodash';
import { Model } from './invokeai';
import useToastWatcher from 'features/system/hooks/useToastWatcher';
keepGUIAlive();
@ -50,18 +51,13 @@ const appSelector = createSelector(
const shouldShowGalleryButton =
!(shouldShowGallery || (shouldHoldGalleryOpen && !shouldPinGallery)) &&
['txt2img', 'img2img', 'unifiedCanvas'].includes(
activeTabName
);
['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName);
const shouldShowOptionsPanelButton =
!(
shouldShowOptionsPanel ||
(shouldHoldOptionsPanelOpen && !shouldPinOptionsPanel)
) &&
['txt2img', 'img2img', 'unifiedCanvas'].includes(
activeTabName
);
) && ['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName);
return {
modelStatusText,
@ -80,6 +76,8 @@ const App = () => {
const { shouldShowGalleryButton, shouldShowOptionsPanelButton } =
useAppSelector(appSelector);
useToastWatcher();
return (
<div className="App">
<ImageUploader>

View File

@ -23,7 +23,6 @@ import {
clearIntermediateImage,
GalleryState,
removeImage,
setCurrentImage,
setIntermediateImage,
} from 'features/gallery/gallerySlice';

View File

@ -43,8 +43,6 @@ export const socketioMiddleware = () => {
onGalleryImages,
onProcessingCanceled,
onImageDeleted,
// onImageUploaded,
// onMaskImageUploaded,
onSystemConfig,
onModelChanged,
onModelChangeFailed,
@ -58,8 +56,6 @@ export const socketioMiddleware = () => {
emitRequestImages,
emitRequestNewImages,
emitCancelProcessing,
// emitUploadImage,
// emitUploadMaskImage,
emitRequestSystemConfig,
emitRequestModelChange,
} = makeSocketIOEmitters(store, socketio);
@ -104,14 +100,6 @@ export const socketioMiddleware = () => {
onImageDeleted(data);
});
// socketio.on('imageUploaded', (data: InvokeAI.ImageUploadResponse) => {
// onImageUploaded(data);
// });
// socketio.on('maskImageUploaded', (data: InvokeAI.ImageUrlResponse) => {
// onMaskImageUploaded(data);
// });
socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => {
onSystemConfig(data);
});
@ -166,16 +154,6 @@ export const socketioMiddleware = () => {
break;
}
// case 'socketio/uploadImage': {
// emitUploadImage(action.payload);
// break;
// }
// case 'socketio/uploadMaskImage': {
// emitUploadMaskImage(action.payload);
// break;
// }
case 'socketio/requestSystemConfig': {
emitRequestSystemConfig();
break;

View File

@ -6,6 +6,7 @@ import layerToDataURL from './layerToDataURL';
import downloadFile from './downloadFile';
import copyImage from './copyImage';
import { getCanvasBaseLayer } from './konvaInstanceProvider';
import { addToast } from 'features/system/systemSlice';
export const mergeAndUploadCanvas = createAsyncThunk(
'canvas/mergeAndUploadCanvas',
@ -21,7 +22,7 @@ export const mergeAndUploadCanvas = createAsyncThunk(
const { saveToGallery, downloadAfterSaving, cropVisible, copyAfterSaving } =
args;
const { getState } = thunkAPI;
const { getState, dispatch } = thunkAPI;
const state = getState() as RootState;
@ -60,11 +61,27 @@ export const mergeAndUploadCanvas = createAsyncThunk(
if (downloadAfterSaving) {
downloadFile(url);
dispatch(
addToast({
title: 'Image Download Started',
status: 'success',
duration: 2500,
isClosable: true,
})
);
return;
}
if (copyAfterSaving) {
copyImage(url, width, height);
dispatch(
addToast({
title: 'Image Copied',
status: 'success',
duration: 2500,
isClosable: true,
})
);
return;
}

View File

@ -27,3 +27,6 @@ export const mayGenerateMultipleImagesSelector = createSelector(
},
}
);
export const optionsSelector = (state: RootState): OptionsState =>
state.options;

View File

@ -0,0 +1,19 @@
import { useToast } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store';
import { useEffect } from 'react';
import { toastQueueSelector } from '../systemSelectors';
import { clearToastQueue } from '../systemSlice';
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;

View File

@ -0,0 +1,6 @@
import { RootState } from 'app/store';
import { SystemState } from './systemSlice';
export const systemSelector = (state: RootState): SystemState => state.system;
export const toastQueueSelector = (state: RootState) => state.system.toastQueue;

View File

@ -1,6 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import { ExpandedIndex } from '@chakra-ui/react';
import { ExpandedIndex, UseToastOptions } from '@chakra-ui/react';
import * as InvokeAI from 'app/invokeai';
export type LogLevel = 'info' | 'warning' | 'error';
@ -45,6 +45,7 @@ export interface SystemState
isCancelable: boolean;
saveIntermediatesInterval: number;
enableImageDebugging: boolean;
toastQueue: UseToastOptions[];
}
const initialSystemState: SystemState = {
@ -76,6 +77,7 @@ const initialSystemState: SystemState = {
isCancelable: true,
saveIntermediatesInterval: 5,
enableImageDebugging: false,
toastQueue: [],
};
export const systemSlice = createSlice({
@ -206,6 +208,12 @@ export const systemSlice = createSlice({
setEnableImageDebugging: (state, action: PayloadAction<boolean>) => {
state.enableImageDebugging = action.payload;
},
addToast: (state, action: PayloadAction<UseToastOptions>) => {
state.toastQueue.push(action.payload);
},
clearToastQueue: (state) => {
state.toastQueue = [];
},
},
});
@ -231,6 +239,8 @@ export const {
setSaveIntermediatesInterval,
setEnableImageDebugging,
generationRequested,
addToast,
clearToastQueue,
} = systemSlice.actions;
export default systemSlice.reducer;