diff --git a/invokeai/frontend/web/src/app/hooks/useStudioInitAction.ts b/invokeai/frontend/web/src/app/hooks/useStudioInitAction.ts index 29db2ff0b3..b08d40417a 100644 --- a/invokeai/frontend/web/src/app/hooks/useStudioInitAction.ts +++ b/invokeai/frontend/web/src/app/hooks/useStudioInitAction.ts @@ -2,8 +2,9 @@ import { useStore } from '@nanostores/react'; import { useAppStore } from 'app/store/storeHooks'; import { useAssertSingleton } from 'common/hooks/useAssertSingleton'; import { withResultAsync } from 'common/util/result'; +import { canvasReset } from 'features/controlLayers/store/actions'; import { rasterLayerAdded } from 'features/controlLayers/store/canvasSlice'; -import { canvasSessionTypeChanged } from 'features/controlLayers/store/canvasStagingAreaSlice'; +import { paramsReset } from 'features/controlLayers/store/paramsSlice'; import type { CanvasRasterLayerState } from 'features/controlLayers/store/types'; import { imageDTOToImageObject } from 'features/controlLayers/store/util'; import { $imageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; @@ -90,9 +91,8 @@ export const useStudioInitAction = (action?: StudioInitAction) => { const overrides: Partial = { objects: [imageObject], }; - store.dispatch(canvasSessionTypeChanged({ type: 'advanced' })); + store.dispatch(canvasReset()); store.dispatch(rasterLayerAdded({ overrides, isSelected: true })); - store.dispatch(setActiveTab('canvas')); store.dispatch(sentImageToCanvas()); $imageViewer.set(false); toast({ @@ -116,9 +116,9 @@ export const useStudioInitAction = (action?: StudioInitAction) => { return; } const metadata = getImageMetadataResult.value; + store.dispatch(canvasReset()); // This shows a toast await parseAndRecallAllMetadata(metadata, true); - store.dispatch(setActiveTab('canvas')); }, [store, t] ); @@ -162,15 +162,13 @@ export const useStudioInitAction = (action?: StudioInitAction) => { switch (destination) { case 'generation': // Go to the canvas tab, open the image viewer, and enable send-to-gallery mode - store.dispatch(canvasSessionTypeChanged({ type: 'simple' })); - store.dispatch(setActiveTab('canvas')); + store.dispatch(paramsReset()); store.dispatch(activeTabCanvasRightPanelChanged('gallery')); $imageViewer.set(true); break; case 'canvas': // Go to the canvas tab, close the image viewer, and disable send-to-gallery mode - store.dispatch(canvasSessionTypeChanged({ type: 'advanced' })); - store.dispatch(setActiveTab('canvas')); + store.dispatch(canvasReset()); $imageViewer.set(false); break; case 'workflows': 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 8deabbe967..d763884030 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 @@ -6,8 +6,10 @@ import { extractMessageFromAssertionError } from 'common/util/extractMessageFrom import { withResult, withResultAsync } from 'common/util/result'; import { parseify } from 'common/util/serialize'; import { - canvasSessionGenerationStarted, + canvasSessionIdCreated, + generateSessionIdCreated, selectCanvasSessionId, + selectGenerateSessionId, } from 'features/controlLayers/store/canvasStagingAreaSlice'; import { $canvasManager } from 'features/controlLayers/store/ephemeral'; import { prepareLinearUIBatch } from 'features/nodes/util/graph/buildLinearBatchConfig'; @@ -22,6 +24,7 @@ import { buildSD3Graph } from 'features/nodes/util/graph/generation/buildSD3Grap import { buildSDXLGraph } from 'features/nodes/util/graph/generation/buildSDXLGraph'; import { UnsupportedGenerationModeError } from 'features/nodes/util/graph/types'; import { toast } from 'features/toast/toast'; +import { selectActiveTab } from 'features/ui/store/uiSelectors'; import { serializeError } from 'serialize-error'; import { enqueueMutationFixedCacheKeyOptions, queueApi } from 'services/api/endpoints/queue'; import { assert, AssertionError } from 'tsafe'; @@ -36,12 +39,27 @@ export const addEnqueueRequestedLinear = (startAppListening: AppStartListening) effect: async (action, { getState, dispatch }) => { log.debug('Enqueue requested'); - if (!selectCanvasSessionId(getState())) { - dispatch(canvasSessionGenerationStarted()); + const tab = selectActiveTab(getState()); + let sessionId = null; + if (tab === 'generate') { + sessionId = selectGenerateSessionId(getState()); + if (!sessionId) { + dispatch(generateSessionIdCreated()); + sessionId = selectGenerateSessionId(getState()); + } + } else if (tab === 'canvas') { + sessionId = selectCanvasSessionId(getState()); + if (!sessionId) { + dispatch(canvasSessionIdCreated()); + sessionId = selectCanvasSessionId(getState()); + } + } else { + log.warn(`Enqueue requested in unsupported tab ${tab}`); + return; } const state = getState(); - const destination = state.canvasSession.id; + const destination = sessionId; assert(destination !== null); const { prepend } = action.payload; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx b/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx index 84466bf0cf..5aa618e389 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/NewSessionConfirmationAlertDialog.tsx @@ -2,7 +2,7 @@ import { Checkbox, ConfirmationAlertDialog, Flex, FormControl, FormLabel, Text } import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAssertSingleton } from 'common/hooks/useAssertSingleton'; import { buildUseBoolean } from 'common/hooks/useBoolean'; -import { canvasSessionTypeChanged } from 'features/controlLayers/store/canvasStagingAreaSlice'; +import { canvasSessionReset, generateSessionReset } from 'features/controlLayers/store/canvasStagingAreaSlice'; import { selectSystemShouldConfirmOnNewSession, shouldConfirmOnNewSessionToggled, @@ -20,7 +20,7 @@ export const useNewGallerySession = () => { const newSessionDialog = useNewGallerySessionDialog(); const newGallerySessionImmediate = useCallback(() => { - dispatch(canvasSessionTypeChanged({ type: 'simple' })); + dispatch(generateSessionReset()); dispatch(activeTabCanvasRightPanelChanged('gallery')); }, [dispatch]); @@ -41,7 +41,7 @@ export const useNewCanvasSession = () => { const newSessionDialog = useNewCanvasSessionDialog(); const newCanvasSessionImmediate = useCallback(() => { - dispatch(canvasSessionTypeChanged({ type: 'advanced' })); + dispatch(canvasSessionReset()); dispatch(activeTabCanvasRightPanelChanged('layers')); }, [dispatch]); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialState.tsx b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialState.tsx index 2e8cf7a29b..2c8f92af6f 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialState.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialState.tsx @@ -6,13 +6,22 @@ import { InitialStateAddAStyleReference } from 'features/controlLayers/component import { InitialStateEditImageCard } from 'features/controlLayers/components/SimpleSession/InitialStateEditImageCard'; import { InitialStateGenerateFromText } from 'features/controlLayers/components/SimpleSession/InitialStateGenerateFromText'; import { InitialStateUseALayoutImageCard } from 'features/controlLayers/components/SimpleSession/InitialStateUseALayoutImageCard'; -import { canvasSessionTypeChanged } from 'features/controlLayers/store/canvasStagingAreaSlice'; +import { toast } from 'features/toast/toast'; +import { setActiveTab } from 'features/ui/store/uiSlice'; import { memo, useCallback } from 'react'; export const InitialState = memo(() => { const dispatch = useAppDispatch(); const newCanvasSession = useCallback(() => { - dispatch(canvasSessionTypeChanged({ type: 'advanced' })); + dispatch(setActiveTab('canvas')); + toast({ + title: 'Switched to Canvas', + description: 'You are in advanced mode yadda yadda.', + status: 'info', + position: 'top', + // isClosable: false, + duration: 5000, + }); }, [dispatch]); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialStateButtonGridItem.tsx b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialStateButtonGridItem.tsx index 4861e4f475..b53e059843 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialStateButtonGridItem.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/InitialStateButtonGridItem.tsx @@ -1,28 +1,31 @@ import type { GridItemProps } from '@invoke-ai/ui-library'; -import { Button, GridItem } from '@invoke-ai/ui-library'; +import { Button, forwardRef, GridItem } from '@invoke-ai/ui-library'; import { memo } from 'react'; -export const InitialStateButtonGridItem = memo(({ children, ...rest }: GridItemProps) => { - return ( - - {children} - - ); -}); +export const InitialStateButtonGridItem = memo( + forwardRef(({ children, ...rest }: GridItemProps, ref) => { + return ( + + {children} + + ); + }) +); InitialStateButtonGridItem.displayName = 'InitialStateButtonGridItem'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/StagingAreaHeader.tsx b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/StagingAreaHeader.tsx index 0f4828c93f..480b9f1659 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/StagingAreaHeader.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/StagingAreaHeader.tsx @@ -1,6 +1,5 @@ /* eslint-disable i18next/no-literal-string */ import { Flex, Heading, Spacer } from '@invoke-ai/ui-library'; -import { StartOverButton } from 'features/controlLayers/components/StartOverButton'; import { memo } from 'react'; export const StagingAreaHeader = memo(() => { @@ -8,7 +7,6 @@ export const StagingAreaHeader = memo(() => { Review Session - ); }); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarAcceptButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarAcceptButton.tsx index 8718385567..1eb8451bb4 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarAcceptButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarAcceptButton.tsx @@ -5,7 +5,7 @@ import { useIsRegionFocused } from 'common/hooks/focus'; import { useCanvasSessionContext } from 'features/controlLayers/components/SimpleSession/context'; import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; import { rasterLayerAdded } from 'features/controlLayers/store/canvasSlice'; -import { canvasSessionGenerationFinished } from 'features/controlLayers/store/canvasStagingAreaSlice'; +import { canvasSessionReset } from 'features/controlLayers/store/canvasStagingAreaSlice'; import { selectBboxRect, selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors'; import type { CanvasRasterLayerState } from 'features/controlLayers/store/types'; import { imageNameToImageObject } from 'features/controlLayers/store/util'; @@ -40,7 +40,7 @@ export const StagingAreaToolbarAcceptButton = memo(() => { }; dispatch(rasterLayerAdded({ overrides, isSelected: selectedEntityIdentifier?.type === 'raster_layer' })); - dispatch(canvasSessionGenerationFinished()); + dispatch(canvasSessionReset()); deleteQueueItemsByDestination.trigger(ctx.session.id); }, [ selectedItemImageDTO, diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardAllButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardAllButton.tsx index 9c7f653898..7982385e7c 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardAllButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardAllButton.tsx @@ -1,7 +1,7 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useAppDispatch } from 'app/store/storeHooks'; import { useCanvasSessionContext } from 'features/controlLayers/components/SimpleSession/context'; -import { canvasSessionGenerationFinished } from 'features/controlLayers/store/canvasStagingAreaSlice'; +import { canvasSessionReset, generateSessionReset } from 'features/controlLayers/store/canvasStagingAreaSlice'; import { useDeleteQueueItemsByDestination } from 'features/queue/hooks/useDeleteQueueItemsByDestination'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -15,8 +15,13 @@ export const StagingAreaToolbarDiscardAllButton = memo(({ isDisabled }: { isDisa const discardAll = useCallback(() => { deleteQueueItemsByDestination.trigger(ctx.session.id); - dispatch(canvasSessionGenerationFinished()); - }, [deleteQueueItemsByDestination, ctx.session.id, dispatch]); + if (ctx.session.type === 'advanced') { + dispatch(canvasSessionReset()); + } else { + // ctx.session.type === 'simple' + dispatch(generateSessionReset()); + } + }, [deleteQueueItemsByDestination, ctx.session.id, ctx.session.type, dispatch]); return ( { const dispatch = useAppDispatch(); const startOver = useCallback(() => { - dispatch(canvasSessionTypeChanged({ type: 'simple' })); - }, [dispatch]); + // dispatch(canvasSessionTypeChanged({ type: 'simple' })); + $simpleId.set(null); + }, []); return (