mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
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:
parent
c69573e65d
commit
04cb2d39cb
@ -15,6 +15,7 @@ import { activeTabNameSelector } from 'features/options/optionsSelectors';
|
|||||||
import { SystemState } from 'features/system/systemSlice';
|
import { SystemState } from 'features/system/systemSlice';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { Model } from './invokeai';
|
import { Model } from './invokeai';
|
||||||
|
import useToastWatcher from 'features/system/hooks/useToastWatcher';
|
||||||
|
|
||||||
keepGUIAlive();
|
keepGUIAlive();
|
||||||
|
|
||||||
@ -50,18 +51,13 @@ const appSelector = createSelector(
|
|||||||
|
|
||||||
const shouldShowGalleryButton =
|
const shouldShowGalleryButton =
|
||||||
!(shouldShowGallery || (shouldHoldGalleryOpen && !shouldPinGallery)) &&
|
!(shouldShowGallery || (shouldHoldGalleryOpen && !shouldPinGallery)) &&
|
||||||
['txt2img', 'img2img', 'unifiedCanvas'].includes(
|
['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName);
|
||||||
activeTabName
|
|
||||||
);
|
|
||||||
|
|
||||||
const shouldShowOptionsPanelButton =
|
const shouldShowOptionsPanelButton =
|
||||||
!(
|
!(
|
||||||
shouldShowOptionsPanel ||
|
shouldShowOptionsPanel ||
|
||||||
(shouldHoldOptionsPanelOpen && !shouldPinOptionsPanel)
|
(shouldHoldOptionsPanelOpen && !shouldPinOptionsPanel)
|
||||||
) &&
|
) && ['txt2img', 'img2img', 'unifiedCanvas'].includes(activeTabName);
|
||||||
['txt2img', 'img2img', 'unifiedCanvas'].includes(
|
|
||||||
activeTabName
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
modelStatusText,
|
modelStatusText,
|
||||||
@ -80,6 +76,8 @@ const App = () => {
|
|||||||
const { shouldShowGalleryButton, shouldShowOptionsPanelButton } =
|
const { shouldShowGalleryButton, shouldShowOptionsPanelButton } =
|
||||||
useAppSelector(appSelector);
|
useAppSelector(appSelector);
|
||||||
|
|
||||||
|
useToastWatcher();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<ImageUploader>
|
<ImageUploader>
|
||||||
|
@ -23,7 +23,6 @@ import {
|
|||||||
clearIntermediateImage,
|
clearIntermediateImage,
|
||||||
GalleryState,
|
GalleryState,
|
||||||
removeImage,
|
removeImage,
|
||||||
setCurrentImage,
|
|
||||||
setIntermediateImage,
|
setIntermediateImage,
|
||||||
} from 'features/gallery/gallerySlice';
|
} from 'features/gallery/gallerySlice';
|
||||||
|
|
||||||
|
@ -43,8 +43,6 @@ export const socketioMiddleware = () => {
|
|||||||
onGalleryImages,
|
onGalleryImages,
|
||||||
onProcessingCanceled,
|
onProcessingCanceled,
|
||||||
onImageDeleted,
|
onImageDeleted,
|
||||||
// onImageUploaded,
|
|
||||||
// onMaskImageUploaded,
|
|
||||||
onSystemConfig,
|
onSystemConfig,
|
||||||
onModelChanged,
|
onModelChanged,
|
||||||
onModelChangeFailed,
|
onModelChangeFailed,
|
||||||
@ -58,8 +56,6 @@ export const socketioMiddleware = () => {
|
|||||||
emitRequestImages,
|
emitRequestImages,
|
||||||
emitRequestNewImages,
|
emitRequestNewImages,
|
||||||
emitCancelProcessing,
|
emitCancelProcessing,
|
||||||
// emitUploadImage,
|
|
||||||
// emitUploadMaskImage,
|
|
||||||
emitRequestSystemConfig,
|
emitRequestSystemConfig,
|
||||||
emitRequestModelChange,
|
emitRequestModelChange,
|
||||||
} = makeSocketIOEmitters(store, socketio);
|
} = makeSocketIOEmitters(store, socketio);
|
||||||
@ -104,14 +100,6 @@ export const socketioMiddleware = () => {
|
|||||||
onImageDeleted(data);
|
onImageDeleted(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
// socketio.on('imageUploaded', (data: InvokeAI.ImageUploadResponse) => {
|
|
||||||
// onImageUploaded(data);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// socketio.on('maskImageUploaded', (data: InvokeAI.ImageUrlResponse) => {
|
|
||||||
// onMaskImageUploaded(data);
|
|
||||||
// });
|
|
||||||
|
|
||||||
socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => {
|
socketio.on('systemConfig', (data: InvokeAI.SystemConfig) => {
|
||||||
onSystemConfig(data);
|
onSystemConfig(data);
|
||||||
});
|
});
|
||||||
@ -166,16 +154,6 @@ export const socketioMiddleware = () => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// case 'socketio/uploadImage': {
|
|
||||||
// emitUploadImage(action.payload);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// case 'socketio/uploadMaskImage': {
|
|
||||||
// emitUploadMaskImage(action.payload);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
case 'socketio/requestSystemConfig': {
|
case 'socketio/requestSystemConfig': {
|
||||||
emitRequestSystemConfig();
|
emitRequestSystemConfig();
|
||||||
break;
|
break;
|
||||||
|
@ -6,6 +6,7 @@ import layerToDataURL from './layerToDataURL';
|
|||||||
import downloadFile from './downloadFile';
|
import downloadFile from './downloadFile';
|
||||||
import copyImage from './copyImage';
|
import copyImage from './copyImage';
|
||||||
import { getCanvasBaseLayer } from './konvaInstanceProvider';
|
import { getCanvasBaseLayer } from './konvaInstanceProvider';
|
||||||
|
import { addToast } from 'features/system/systemSlice';
|
||||||
|
|
||||||
export const mergeAndUploadCanvas = createAsyncThunk(
|
export const mergeAndUploadCanvas = createAsyncThunk(
|
||||||
'canvas/mergeAndUploadCanvas',
|
'canvas/mergeAndUploadCanvas',
|
||||||
@ -21,7 +22,7 @@ export const mergeAndUploadCanvas = createAsyncThunk(
|
|||||||
const { saveToGallery, downloadAfterSaving, cropVisible, copyAfterSaving } =
|
const { saveToGallery, downloadAfterSaving, cropVisible, copyAfterSaving } =
|
||||||
args;
|
args;
|
||||||
|
|
||||||
const { getState } = thunkAPI;
|
const { getState, dispatch } = thunkAPI;
|
||||||
|
|
||||||
const state = getState() as RootState;
|
const state = getState() as RootState;
|
||||||
|
|
||||||
@ -60,11 +61,27 @@ export const mergeAndUploadCanvas = createAsyncThunk(
|
|||||||
|
|
||||||
if (downloadAfterSaving) {
|
if (downloadAfterSaving) {
|
||||||
downloadFile(url);
|
downloadFile(url);
|
||||||
|
dispatch(
|
||||||
|
addToast({
|
||||||
|
title: 'Image Download Started',
|
||||||
|
status: 'success',
|
||||||
|
duration: 2500,
|
||||||
|
isClosable: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copyAfterSaving) {
|
if (copyAfterSaving) {
|
||||||
copyImage(url, width, height);
|
copyImage(url, width, height);
|
||||||
|
dispatch(
|
||||||
|
addToast({
|
||||||
|
title: 'Image Copied',
|
||||||
|
status: 'success',
|
||||||
|
duration: 2500,
|
||||||
|
isClosable: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,3 +27,6 @@ export const mayGenerateMultipleImagesSelector = createSelector(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const optionsSelector = (state: RootState): OptionsState =>
|
||||||
|
state.options;
|
||||||
|
19
frontend/src/features/system/hooks/useToastWatcher.ts
Normal file
19
frontend/src/features/system/hooks/useToastWatcher.ts
Normal 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;
|
6
frontend/src/features/system/systemSelectors.ts
Normal file
6
frontend/src/features/system/systemSelectors.ts
Normal 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;
|
@ -1,6 +1,6 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import type { PayloadAction } 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';
|
import * as InvokeAI from 'app/invokeai';
|
||||||
|
|
||||||
export type LogLevel = 'info' | 'warning' | 'error';
|
export type LogLevel = 'info' | 'warning' | 'error';
|
||||||
@ -45,6 +45,7 @@ export interface SystemState
|
|||||||
isCancelable: boolean;
|
isCancelable: boolean;
|
||||||
saveIntermediatesInterval: number;
|
saveIntermediatesInterval: number;
|
||||||
enableImageDebugging: boolean;
|
enableImageDebugging: boolean;
|
||||||
|
toastQueue: UseToastOptions[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialSystemState: SystemState = {
|
const initialSystemState: SystemState = {
|
||||||
@ -76,6 +77,7 @@ const initialSystemState: SystemState = {
|
|||||||
isCancelable: true,
|
isCancelable: true,
|
||||||
saveIntermediatesInterval: 5,
|
saveIntermediatesInterval: 5,
|
||||||
enableImageDebugging: false,
|
enableImageDebugging: false,
|
||||||
|
toastQueue: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const systemSlice = createSlice({
|
export const systemSlice = createSlice({
|
||||||
@ -206,6 +208,12 @@ export const systemSlice = createSlice({
|
|||||||
setEnableImageDebugging: (state, action: PayloadAction<boolean>) => {
|
setEnableImageDebugging: (state, action: PayloadAction<boolean>) => {
|
||||||
state.enableImageDebugging = action.payload;
|
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,
|
setSaveIntermediatesInterval,
|
||||||
setEnableImageDebugging,
|
setEnableImageDebugging,
|
||||||
generationRequested,
|
generationRequested,
|
||||||
|
addToast,
|
||||||
|
clearToastQueue,
|
||||||
} = systemSlice.actions;
|
} = systemSlice.actions;
|
||||||
|
|
||||||
export default systemSlice.reducer;
|
export default systemSlice.reducer;
|
||||||
|
Loading…
Reference in New Issue
Block a user