diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index b96175c25d..94dff3934a 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -546,7 +546,6 @@ "availableSchedulers": "Available Schedulers" }, "toast": { - "problemCreatingSession": "Problem Creating Session", "serverError": "Server Error", "disconnected": "Disconnected from Server", "connected": "Connected to Server", diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts index 5c726c317f..dae56804af 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts @@ -49,6 +49,11 @@ import { addSessionCreatedPendingListener, addSessionCreatedRejectedListener, } from './listeners/sessionCreated'; +import { + addSessionInvokedFulfilledListener, + addSessionInvokedPendingListener, + addSessionInvokedRejectedListener, +} from './listeners/sessionInvoked'; export const listenerMiddleware = createListenerMiddleware(); @@ -88,13 +93,18 @@ addImageMetadataReceivedRejectedListener(); addImageUrlsReceivedFulfilledListener(); addImageUrlsReceivedRejectedListener(); -// Invoking stuff +// Invoking on tabs addUserInvokedCanvasListener(); addUserInvokedNodesListener(); addUserInvokedTextToImageListener(); addUserInvokedImageToImageListener(); addSessionReadyToInvokeListener(); +// Actual session invoking +addSessionInvokedPendingListener(); +addSessionInvokedFulfilledListener(); +addSessionInvokedRejectedListener(); + // Canvas actions addCanvasSavedToGalleryListener(); addCanvasDownloadedAsImageListener(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/sessionInvoked.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/sessionInvoked.ts new file mode 100644 index 0000000000..bddadbc359 --- /dev/null +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/sessionInvoked.ts @@ -0,0 +1,45 @@ +import { log } from 'app/logging/useLogger'; +import { startAppListening } from '..'; +import { sessionInvoked } from 'services/thunks/session'; +import { serializeError } from 'serialize-error'; + +const moduleLog = log.child({ namespace: 'session' }); + +export const addSessionInvokedPendingListener = () => { + startAppListening({ + actionCreator: sessionInvoked.pending, + effect: (action, { getState, dispatch }) => { + // + }, + }); +}; + +export const addSessionInvokedFulfilledListener = () => { + startAppListening({ + actionCreator: sessionInvoked.fulfilled, + effect: (action, { getState, dispatch }) => { + const { sessionId } = action.meta.arg; + moduleLog.info({ data: { sessionId } }, `Session invoked (${sessionId})`); + }, + }); +}; + +export const addSessionInvokedRejectedListener = () => { + startAppListening({ + actionCreator: sessionInvoked.rejected, + effect: (action, { getState, dispatch }) => { + if (action.payload) { + const { arg, error } = action.payload; + moduleLog.error( + { + data: { + arg, + error: serializeError(error), + }, + }, + `Problem invoking session` + ); + } + }, + }); +}; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/sessionReadyToInvoke.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/sessionReadyToInvoke.ts index eb65017a25..4fae2d96c0 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/sessionReadyToInvoke.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/sessionReadyToInvoke.ts @@ -3,7 +3,7 @@ import { sessionInvoked } from 'services/thunks/session'; import { log } from 'app/logging/useLogger'; import { sessionReadyToInvoke } from 'features/system/store/actions'; -const moduleLog = log.child({ namespace: 'invoke' }); +const moduleLog = log.child({ namespace: 'session' }); export const addSessionReadyToInvokeListener = () => { startAppListening({ @@ -11,7 +11,10 @@ export const addSessionReadyToInvokeListener = () => { effect: (action, { getState, dispatch }) => { const { sessionId } = getState().system; if (sessionId) { - moduleLog.info({ sessionId }, `Session invoked (${sessionId})})`); + moduleLog.info( + { sessionId }, + `Session ready to invoke (${sessionId})})` + ); dispatch(sessionInvoked({ sessionId })); } }, diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index 8845e0b843..403fd60501 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -1,5 +1,5 @@ import { UseToastOptions } from '@chakra-ui/react'; -import type { PayloadAction } from '@reduxjs/toolkit'; +import { PayloadAction, isAnyOf } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; import * as InvokeAI from 'app/types/invokeai'; import { @@ -349,13 +349,6 @@ export const systemSlice = createSlice({ state.statusTranslationKey = 'common.statusPreparing'; }); - builder.addCase(sessionInvoked.rejected, (state, action) => { - const error = action.payload as string | undefined; - state.toastQueue.push( - makeToast({ title: error || t('toast.serverError'), status: 'error' }) - ); - }); - /** * Session Canceled - FULFILLED */ @@ -374,23 +367,6 @@ export const systemSlice = createSlice({ ); }); - /** - * Session Created - REJECTED - */ - builder.addCase(sessionCreated.rejected, (state, action) => { - state.isProcessing = false; - state.isCancelable = false; - state.isCancelScheduled = false; - state.currentStep = 0; - state.totalSteps = 0; - state.statusTranslationKey = 'common.statusConnected'; - state.progressImage = null; - - state.toastQueue.push( - makeToast({ title: t('toast.problemCreatingSession'), status: 'error' }) - ); - }); - /** * Session Canceled */ @@ -437,6 +413,26 @@ export const systemSlice = createSlice({ builder.addCase(imageUploaded.fulfilled, (state) => { state.isUploading = false; }); + + // *** Matchers - must be after all cases *** + + /** + * Session Invoked - REJECTED + * Session Created - REJECTED + */ + builder.addMatcher(isAnySessionRejected, (state, action) => { + state.isProcessing = false; + state.isCancelable = false; + state.isCancelScheduled = false; + state.currentStep = 0; + state.totalSteps = 0; + state.statusTranslationKey = 'common.statusConnected'; + state.progressImage = null; + + state.toastQueue.push( + makeToast({ title: t('toast.serverError'), status: 'error' }) + ); + }); }, }); @@ -465,3 +461,8 @@ export const { } = systemSlice.actions; export default systemSlice.reducer; + +const isAnySessionRejected = isAnyOf( + sessionCreated.rejected, + sessionInvoked.rejected +); diff --git a/invokeai/frontend/web/src/services/thunks/session.ts b/invokeai/frontend/web/src/services/thunks/session.ts index 546789d5b7..efab401520 100644 --- a/invokeai/frontend/web/src/services/thunks/session.ts +++ b/invokeai/frontend/web/src/services/thunks/session.ts @@ -1,6 +1,7 @@ import { createAppAsyncThunk } from 'app/store/storeUtils'; import { GraphExecutionState, SessionsService } from 'services/api'; import { log } from 'app/logging/useLogger'; +import { isObject } from 'lodash-es'; const sessionLog = log.child({ namespace: 'session' }); @@ -21,7 +22,7 @@ export const sessionCreated = createAppAsyncThunk< GraphExecutionState, SessionCreatedArg, SessionCreatedThunkConfig ->('api/sessionCreated', async (arg: SessionCreatedArg, { rejectWithValue }) => { +>('api/sessionCreated', async (arg, { rejectWithValue }) => { try { const response = await SessionsService.createSession({ requestBody: arg.graph, @@ -32,76 +33,41 @@ export const sessionCreated = createAppAsyncThunk< } }); -type NodeAddedArg = Parameters<(typeof SessionsService)['addNode']>[0]; +type SessionInvokedArg = { sessionId: string }; -/** - * `SessionsService.addNode()` thunk - */ -export const nodeAdded = createAppAsyncThunk( - 'api/nodeAdded', - async ( - arg: { node: NodeAddedArg['requestBody']; sessionId: string }, - _thunkApi - ) => { - const response = await SessionsService.addNode({ - requestBody: arg.node, - sessionId: arg.sessionId, - }); +type SessionInvokedThunkConfig = { + rejectValue: { + arg: SessionInvokedArg; + error: unknown; + }; +}; - sessionLog.info({ arg, response }, `Node added (${response})`); - - return response; - } -); - -type NodeUpdatedArg = Parameters<(typeof SessionsService)['updateNode']>[0]; - -/** - * `SessionsService.addNode()` thunk - */ -export const nodeUpdated = createAppAsyncThunk( - 'api/nodeUpdated', - async ( - arg: { node: NodeUpdatedArg['requestBody']; sessionId: string }, - _thunkApi - ) => { - const response = await SessionsService.updateNode({ - requestBody: arg.node, - sessionId: arg.sessionId, - nodePath: arg.node.id, - }); - - sessionLog.info({ arg, response }, `Node updated (${response})`); - - return response; - } -); +const isErrorWithStatus = (error: unknown): error is { status: number } => + isObject(error) && 'status' in error; /** * `SessionsService.invokeSession()` thunk */ -export const sessionInvoked = createAppAsyncThunk( - 'api/sessionInvoked', - async (arg: { sessionId: string }, { rejectWithValue }) => { - const { sessionId } = arg; +export const sessionInvoked = createAppAsyncThunk< + any, + SessionInvokedArg, + SessionInvokedThunkConfig +>('api/sessionInvoked', async (arg, { rejectWithValue }) => { + const { sessionId } = arg; - try { - const response = await SessionsService.invokeSession({ - sessionId, - all: true, - }); - sessionLog.info({ arg, response }, `Session invoked (${sessionId})`); - - return response; - } catch (error) { - const err = error as any; - if (err.status === 403) { - return rejectWithValue(err.body.detail); - } - throw error; + try { + const response = await SessionsService.invokeSession({ + sessionId, + all: true, + }); + return response; + } catch (error) { + if (isErrorWithStatus(error) && error.status === 403) { + return rejectWithValue({ arg, error: (error as any).body.detail }); } + return rejectWithValue({ arg, error }); } -); +}); type SessionCanceledArg = Parameters< (typeof SessionsService)['cancelSessionInvoke']