From d4da00e607b34d8a6e8d8f794ce6bb4cac219cec Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:44:42 +1000 Subject: [PATCH] feat(ui): "stagingArea" -> "session" --- .../addCommitStagingAreaImageListener.ts | 8 +-- .../listeners/enqueueRequestedLinear.ts | 10 +-- .../socketio/socketInvocationComplete.ts | 6 +- .../StagingArea/StagingAreaToolbar.tsx | 36 +++++------ .../controlLayers/components/ToolChooser.tsx | 2 +- .../controlLayers/konva/CanvasManager.ts | 2 +- .../controlLayers/konva/CanvasStagingArea.ts | 2 +- .../controlLayers/konva/CanvasStateApi.ts | 2 +- .../controlLayers/store/canvasV2Slice.ts | 28 +++++---- .../controlLayers/store/sessionReducers.ts | 62 +++++++++++++++++++ .../store/stagingAreaReducers.ts | 57 ----------------- .../src/features/controlLayers/store/types.ts | 7 ++- .../gallery/hooks/useGalleryHotkeys.ts | 2 +- 13 files changed, 116 insertions(+), 108 deletions(-) create mode 100644 invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts delete mode 100644 invokeai/frontend/web/src/features/controlLayers/store/stagingAreaReducers.ts diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts index 1da9b90b9e..3dbc159e76 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/addCommitStagingAreaImageListener.ts @@ -4,8 +4,8 @@ import type { AppStartListening } from 'app/store/middleware/listenerMiddleware' import { layerAdded, layerImageAdded, - stagingAreaCanceledStaging, - stagingAreaImageAccepted, + sessionStagingCanceled, + sessionStagedImageAccepted, } from 'features/controlLayers/store/canvasV2Slice'; import { toast } from 'features/toast/toast'; import { t } from 'i18next'; @@ -14,7 +14,7 @@ import { assert } from 'tsafe'; export const addStagingListeners = (startAppListening: AppStartListening) => { startAppListening({ - matcher: isAnyOf(stagingAreaCanceledStaging, stagingAreaImageAccepted), + matcher: isAnyOf(sessionStagingCanceled, sessionStagedImageAccepted), effect: async (_, { dispatch }) => { const log = logger('canvas'); @@ -47,7 +47,7 @@ export const addStagingListeners = (startAppListening: AppStartListening) => { }); startAppListening({ - actionCreator: stagingAreaImageAccepted, + actionCreator: sessionStagedImageAccepted, effect: async (action, api) => { const { imageDTO } = action.payload; const { layers, selectedEntityIdentifier, bbox } = api.getState().canvasV2; diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts index 6359e55e40..df29d7cb9c 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/enqueueRequestedLinear.ts @@ -1,7 +1,7 @@ import { enqueueRequested } from 'app/store/actions'; import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; import { getCanvasManager } from 'features/controlLayers/konva/CanvasManager'; -import { stagingAreaCanceledStaging, stagingAreaStartedStaging } from 'features/controlLayers/store/canvasV2Slice'; +import { sessionStagingCanceled, sessionStartedStaging } from 'features/controlLayers/store/canvasV2Slice'; import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig'; import { buildSD1Graph } from 'features/nodes/util/graph/generation/buildSD1Graph'; import { buildSDXLGraph } from 'features/nodes/util/graph/generation/buildSDXLGraph'; @@ -18,8 +18,8 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening) const { prepend } = action.payload; let didStartStaging = false; - if (!state.canvasV2.stagingArea.isStaging) { - dispatch(stagingAreaStartedStaging()); + if (!state.canvasV2.session.isStaging) { + dispatch(sessionStartedStaging()); didStartStaging = true; } @@ -48,8 +48,8 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening) req.reset(); await req.unwrap(); } catch { - if (didStartStaging && getState().canvasV2.stagingArea.isStaging) { - dispatch(stagingAreaCanceledStaging()); + if (didStartStaging && getState().canvasV2.session.isStaging) { + dispatch(sessionStagingCanceled()); } } }, diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts index e963023522..9b36a2b3f9 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketInvocationComplete.ts @@ -2,7 +2,7 @@ import { logger } from 'app/logging/logger'; import type { AppStartListening } from 'app/store/middleware/listenerMiddleware'; import { deepClone } from 'common/util/deepClone'; import { parseify } from 'common/util/serialize'; -import { stagingAreaImageAdded } from 'features/controlLayers/store/canvasV2Slice'; +import { sessionImageStaged } from 'features/controlLayers/store/canvasV2Slice'; import { boardIdSelected, galleryViewChanged, imageSelected, offsetChanged } from 'features/gallery/store/gallerySlice'; import { $nodeExecutionStates, upsertExecutionState } from 'features/nodes/hooks/useExecutionState'; import { zNodeStatus } from 'features/nodes/types/invocation'; @@ -42,8 +42,8 @@ export const addInvocationCompleteEventListener = (startAppListening: AppStartLi // handle tab-specific logic if (data.origin === 'canvas') { - if (data.invocation_source_id === CANVAS_OUTPUT && canvasV2.stagingArea.isStaging) { - dispatch(stagingAreaImageAdded({ imageDTO })); + if (data.invocation_source_id === CANVAS_OUTPUT && canvasV2.session.isStaging) { + dispatch(sessionImageStaged({ imageDTO })); } } else if (data.origin === 'workflows') { const nes = deepClone($nodeExecutionStates.get()[invocation_source_id]); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbar.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbar.tsx index f8e00a9176..62b243157c 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbar.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbar.tsx @@ -3,11 +3,11 @@ import { useStore } from '@nanostores/react'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { $shouldShowStagedImage, - stagingAreaCanceledStaging, - stagingAreaImageAccepted, - stagingAreaImageDiscarded, - stagingAreaNextImageSelected, - stagingAreaPreviousImageSelected, + sessionStagingCanceled, + sessionStagedImageAccepted, + sessionStagedImageDiscarded, + sessionNextStagedImageSelected, + sessionPrevStagedImageSelected, } from 'features/controlLayers/store/canvasV2Slice'; import { memo, useCallback, useMemo } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; @@ -24,7 +24,7 @@ import { } from 'react-icons/pi'; export const StagingAreaToolbar = memo(() => { - const isStaging = useAppSelector((s) => s.canvasV2.stagingArea.isStaging); + const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging); if (!isStaging) { return null; @@ -37,30 +37,30 @@ StagingAreaToolbar.displayName = 'StagingAreaToolbar'; export const StagingAreaToolbarContent = memo(() => { const dispatch = useAppDispatch(); - const stagingArea = useAppSelector((s) => s.canvasV2.stagingArea); + const stagingArea = useAppSelector((s) => s.canvasV2.session); const shouldShowStagedImage = useStore($shouldShowStagedImage); - const images = useMemo(() => stagingArea.images, [stagingArea]); + const images = useMemo(() => stagingArea.stagedImages, [stagingArea]); const selectedImageDTO = useMemo(() => { - return images[stagingArea.selectedImageIndex] ?? null; - }, [images, stagingArea.selectedImageIndex]); + return images[stagingArea.selectedStagedImageIndex] ?? null; + }, [images, stagingArea.selectedStagedImageIndex]); // const [changeIsImageIntermediate] = useChangeImageIsIntermediateMutation(); const { t } = useTranslation(); const onPrev = useCallback(() => { - dispatch(stagingAreaPreviousImageSelected()); + dispatch(sessionPrevStagedImageSelected()); }, [dispatch]); const onNext = useCallback(() => { - dispatch(stagingAreaNextImageSelected()); + dispatch(sessionNextStagedImageSelected()); }, [dispatch]); const onAccept = useCallback(() => { if (!selectedImageDTO) { return; } - dispatch(stagingAreaImageAccepted({ imageDTO: selectedImageDTO })); + dispatch(sessionStagedImageAccepted({ imageDTO: selectedImageDTO })); }, [dispatch, selectedImageDTO]); const onDiscardOne = useCallback(() => { @@ -68,14 +68,14 @@ export const StagingAreaToolbarContent = memo(() => { return; } if (images.length === 1) { - dispatch(stagingAreaCanceledStaging()); + dispatch(sessionStagingCanceled()); } else { - dispatch(stagingAreaImageDiscarded({ imageDTO: selectedImageDTO })); + dispatch(sessionStagedImageDiscarded({ imageDTO: selectedImageDTO })); } }, [dispatch, selectedImageDTO, images.length]); const onDiscardAll = useCallback(() => { - dispatch(stagingAreaCanceledStaging()); + dispatch(sessionStagingCanceled()); }, [dispatch]); const onToggleShouldShowStagedImage = useCallback(() => { @@ -109,11 +109,11 @@ export const StagingAreaToolbarContent = memo(() => { const counterText = useMemo(() => { if (images.length > 0) { - return `${(stagingArea.selectedImageIndex ?? 0) + 1} of ${images.length}`; + return `${(stagingArea.selectedStagedImageIndex ?? 0) + 1} of ${images.length}`; } else { return `0 of 0`; } - }, [images.length, stagingArea.selectedImageIndex]); + }, [images.length, stagingArea.selectedStagedImageIndex]); return ( <> diff --git a/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx b/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx index 89901bde2d..dc07df3581 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/ToolChooser.tsx @@ -43,7 +43,7 @@ export const ToolChooser: React.FC = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const selectedEntityIdentifier = useAppSelector(selectSelectedEntityIdentifier); - const isStaging = useAppSelector((s) => s.canvasV2.stagingArea.isStaging); + const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging); const isDrawingToolDisabled = useMemo( () => !getIsDrawingToolEnabled(selectedEntityIdentifier), [selectedEntityIdentifier] diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts index 7f42b6d566..54681d5132 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasManager.ts @@ -281,7 +281,7 @@ export class CanvasManager { // debouncedUpdateBboxes(stage, canvasV2.layers, canvasV2.controlAdapters, canvasV2.regions, onBboxChanged); } - if (this.isFirstRender || state.stagingArea !== this.prevState.stagingArea) { + if (this.isFirstRender || state.session !== this.prevState.session) { log.debug('Rendering staging area'); this.preview.stagingArea.render(); } diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStagingArea.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStagingArea.ts index 76d793ecb2..b4f1c25a16 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStagingArea.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStagingArea.ts @@ -25,7 +25,7 @@ export class CanvasStagingArea { const shouldShowStagedImage = this.manager.stateApi.getShouldShowStagedImage(); const lastProgressEvent = this.manager.stateApi.getLastProgressEvent(); - this.imageDTO = stagingArea.images[stagingArea.selectedImageIndex] ?? null; + this.imageDTO = stagingArea.stagedImages[stagingArea.selectedStagedImageIndex] ?? null; if (this.imageDTO) { if (this.image) { diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts index 869e165a50..bfbc58ae9e 100644 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts +++ b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasStateApi.ts @@ -232,7 +232,7 @@ export class CanvasStateApi { return this.getState().settings.maskOpacity; }; getStagingAreaState = () => { - return this.getState().stagingArea; + return this.getState().session; }; getIsSelected = (id: string) => { return this.getSelectedEntity()?.id === id; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts index be800e82d8..8b6a80fe67 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasV2Slice.ts @@ -13,8 +13,8 @@ import { layersReducers } from 'features/controlLayers/store/layersReducers'; import { lorasReducers } from 'features/controlLayers/store/lorasReducers'; import { paramsReducers } from 'features/controlLayers/store/paramsReducers'; import { regionsReducers } from 'features/controlLayers/store/regionsReducers'; +import { sessionReducers } from 'features/controlLayers/store/sessionReducers'; import { settingsReducers } from 'features/controlLayers/store/settingsReducers'; -import { stagingAreaReducers } from 'features/controlLayers/store/stagingAreaReducers'; import { toolReducers } from 'features/controlLayers/store/toolReducers'; import { initialAspectRatioState } from 'features/parameters/components/ImageSize/constants'; import type { AspectRatioState } from 'features/parameters/components/ImageSize/types'; @@ -122,10 +122,11 @@ const initialState: CanvasV2State = { refinerNegativeAestheticScore: 2.5, refinerStart: 0.8, }, - stagingArea: { + session: { + isActive: false, isStaging: false, - images: [], - selectedImageIndex: 0, + stagedImages: [], + selectedStagedImageIndex: 0, }, }; @@ -144,7 +145,7 @@ export const canvasV2Slice = createSlice({ ...toolReducers, ...bboxReducers, ...inpaintMaskReducers, - ...stagingAreaReducers, + ...sessionReducers, widthChanged: (state, action: PayloadAction<{ width: number; updateAspectRatio?: boolean; clamp?: boolean }>) => { const { width, updateAspectRatio, clamp } = action.payload; state.document.width = clamp ? Math.max(roundDownToMultiple(width, 8), 64) : width; @@ -184,7 +185,7 @@ export const canvasV2Slice = createSlice({ state.layers = deepClone(initialState.layers); state.regions = deepClone(initialState.regions); state.selectedEntityIdentifier = deepClone(initialState.selectedEntityIdentifier); - state.stagingArea = deepClone(initialState.stagingArea); + state.session = deepClone(initialState.session); state.tool = deepClone(initialState.tool); }, }, @@ -350,13 +351,14 @@ export const { imEraserLineAdded, imRectShapeAdded, // Staging - stagingAreaStartedStaging, - stagingAreaImageAdded, - stagingAreaImageDiscarded, - stagingAreaImageAccepted, - stagingAreaCanceledStaging, - stagingAreaNextImageSelected, - stagingAreaPreviousImageSelected, + sessionStarted, + sessionStartedStaging, + sessionImageStaged, + sessionStagedImageDiscarded, + sessionStagedImageAccepted, + sessionStagingCanceled, + sessionNextStagedImageSelected, + sessionPrevStagedImageSelected, } = canvasV2Slice.actions; export const selectCanvasV2Slice = (state: RootState) => state.canvasV2; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts new file mode 100644 index 0000000000..f9910eacf0 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/store/sessionReducers.ts @@ -0,0 +1,62 @@ +import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; +import type { CanvasV2State } from 'features/controlLayers/store/types'; +import type { ImageDTO } from 'services/api/types'; + +export const sessionReducers = { + sessionStarted: (state) => { + state.session.isActive = true; + }, + sessionStartedStaging: (state) => { + state.session.isStaging = true; + state.session.selectedStagedImageIndex = 0; + // When we start staging, the user should not be interacting with the stage except to move it around. Set the tool + // to view. + state.tool.selectedBuffer = state.tool.selected; + state.tool.selected = 'view'; + }, + sessionImageStaged: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => { + const { imageDTO } = action.payload; + state.session.stagedImages.push(imageDTO); + state.session.selectedStagedImageIndex = state.session.stagedImages.length - 1; + }, + sessionNextStagedImageSelected: (state) => { + state.session.selectedStagedImageIndex = + (state.session.selectedStagedImageIndex + 1) % state.session.stagedImages.length; + }, + sessionPrevStagedImageSelected: (state) => { + state.session.selectedStagedImageIndex = + (state.session.selectedStagedImageIndex - 1 + state.session.stagedImages.length) % + state.session.stagedImages.length; + }, + sessionStagedImageDiscarded: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => { + const { imageDTO } = action.payload; + state.session.stagedImages = state.session.stagedImages.filter((image) => image.image_name !== imageDTO.image_name); + state.session.selectedStagedImageIndex = Math.min( + state.session.selectedStagedImageIndex, + state.session.stagedImages.length - 1 + ); + if (state.session.stagedImages.length === 0) { + state.session.isStaging = false; + } + }, + sessionStagedImageAccepted: (state, _: PayloadAction<{ imageDTO: ImageDTO }>) => { + // When we finish staging, reset the tool back to the previous selection. + state.session.isStaging = false; + state.session.stagedImages = []; + state.session.selectedStagedImageIndex = 0; + if (state.tool.selectedBuffer) { + state.tool.selected = state.tool.selectedBuffer; + state.tool.selectedBuffer = null; + } + }, + sessionStagingCanceled: (state) => { + state.session.isStaging = false; + state.session.stagedImages = []; + state.session.selectedStagedImageIndex = 0; + // When we finish staging, reset the tool back to the previous selection. + if (state.tool.selectedBuffer) { + state.tool.selected = state.tool.selectedBuffer; + state.tool.selectedBuffer = null; + } + }, +} satisfies SliceCaseReducers; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/stagingAreaReducers.ts b/invokeai/frontend/web/src/features/controlLayers/store/stagingAreaReducers.ts deleted file mode 100644 index 9e6168d966..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/store/stagingAreaReducers.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { PayloadAction, SliceCaseReducers } from '@reduxjs/toolkit'; -import type { CanvasV2State } from 'features/controlLayers/store/types'; -import type { ImageDTO } from 'services/api/types'; - -export const stagingAreaReducers = { - stagingAreaStartedStaging: (state) => { - state.stagingArea.isStaging = true; - state.stagingArea.selectedImageIndex = 0; - // When we start staging, the user should not be interacting with the stage except to move it around. Set the tool - // to view. - state.tool.selectedBuffer = state.tool.selected; - state.tool.selected = 'view'; - }, - stagingAreaImageAdded: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => { - const { imageDTO } = action.payload; - state.stagingArea.images.push(imageDTO); - state.stagingArea.selectedImageIndex = state.stagingArea.images.length - 1; - }, - stagingAreaNextImageSelected: (state) => { - state.stagingArea.selectedImageIndex = (state.stagingArea.selectedImageIndex + 1) % state.stagingArea.images.length; - }, - stagingAreaPreviousImageSelected: (state) => { - state.stagingArea.selectedImageIndex = - (state.stagingArea.selectedImageIndex - 1 + state.stagingArea.images.length) % state.stagingArea.images.length; - }, - stagingAreaImageDiscarded: (state, action: PayloadAction<{ imageDTO: ImageDTO }>) => { - const { imageDTO } = action.payload; - state.stagingArea.images = state.stagingArea.images.filter((image) => image.image_name !== imageDTO.image_name); - state.stagingArea.selectedImageIndex = Math.min( - state.stagingArea.selectedImageIndex, - state.stagingArea.images.length - 1 - ); - if (state.stagingArea.images.length === 0) { - state.stagingArea.isStaging = false; - } - }, - stagingAreaImageAccepted: (state, _: PayloadAction<{ imageDTO: ImageDTO }>) => { - // When we finish staging, reset the tool back to the previous selection. - state.stagingArea.isStaging = false; - state.stagingArea.images = []; - state.stagingArea.selectedImageIndex = 0; - if (state.tool.selectedBuffer) { - state.tool.selected = state.tool.selectedBuffer; - state.tool.selectedBuffer = null; - } - }, - stagingAreaCanceledStaging: (state) => { - state.stagingArea.isStaging = false; - state.stagingArea.images = []; - state.stagingArea.selectedImageIndex = 0; - // When we finish staging, reset the tool back to the previous selection. - if (state.tool.selectedBuffer) { - state.tool.selected = state.tool.selectedBuffer; - state.tool.selectedBuffer = null; - } - }, -} satisfies SliceCaseReducers; diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 92697568ea..18c8928940 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -895,10 +895,11 @@ export type CanvasV2State = { refinerNegativeAestheticScore: number; refinerStart: number; }; - stagingArea: { + session: { + isActive: boolean; isStaging: boolean; - images: ImageDTO[]; - selectedImageIndex: number; + stagedImages: ImageDTO[]; + selectedStagedImageIndex: number; }; }; diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryHotkeys.ts b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryHotkeys.ts index e6b68e7b77..8199d8f63e 100644 --- a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryHotkeys.ts +++ b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryHotkeys.ts @@ -9,7 +9,7 @@ import { useListImagesQuery } from 'services/api/endpoints/images'; * Registers gallery hotkeys. This hook is a singleton. */ export const useGalleryHotkeys = () => { - const isStaging = useAppSelector((s) => s.canvasV2.stagingArea.isStaging); + const isStaging = useAppSelector((s) => s.canvasV2.session.isStaging); const { goNext, goPrev, isNextEnabled, isPrevEnabled } = useGalleryPagination(); const queryArgs = useAppSelector(selectListImagesQueryArgs);