diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts index 150cb73e83..0f286d6d1d 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/imageDeletionListeners.ts @@ -81,7 +81,7 @@ const deleteRasterLayerImages = (state: RootState, dispatch: AppDispatch, imageD selectCanvasSlice(state).rasterLayers.entities.forEach(({ id, objects }) => { let shouldDelete = false; for (const obj of objects) { - if (obj.type === 'image' && obj.image.image_name === imageDTO.image_name) { + if (obj.type === 'image' && 'image_name' in obj.image && obj.image.image_name === imageDTO.image_name) { shouldDelete = true; break; } diff --git a/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx b/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx index 93b3c50ce0..9c19a31e5f 100644 --- a/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx +++ b/invokeai/frontend/web/src/common/hooks/useImageUploadButton.tsx @@ -198,7 +198,7 @@ type UploadImageButtonProps = { isError?: boolean; } & ButtonProps; -export const UploadImageButton = memo((props: UploadImageButtonProps) => { +const UploadImageButton = memo((props: UploadImageButtonProps) => { const { children, isDisabled = false, onUpload, isError = false, ...rest } = props; const uploadApi = useImageUploadButton({ isDisabled, allowMultiple: false, onUpload }); return ( diff --git a/invokeai/frontend/web/src/common/hooks/useRelatedModelKeys.ts b/invokeai/frontend/web/src/common/hooks/useRelatedModelKeys.ts deleted file mode 100644 index 9349c9b63d..0000000000 --- a/invokeai/frontend/web/src/common/hooks/useRelatedModelKeys.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { EMPTY_ARRAY } from 'app/store/constants'; -import { useMemo } from 'react'; -import { useGetRelatedModelIdsBatchQuery } from 'services/api/endpoints/modelRelationships'; - -const options: Parameters[1] = { - selectFromResult: ({ data }) => { - if (!data) { - return { related: EMPTY_ARRAY }; - } - return data; - }, -}; - -/** - * Fetches related model keys for a given set of selected model keys. - * Returns a Set for fast lookup. - */ -export const useRelatedModelKeys = (selectedKeys: string[]) => { - const { related } = useGetRelatedModelIdsBatchQuery(selectedKeys, options); - - return useMemo(() => new Set(related), [related]); -}; diff --git a/invokeai/frontend/web/src/common/hooks/useSelectedModelKeys.ts b/invokeai/frontend/web/src/common/hooks/useSelectedModelKeys.ts deleted file mode 100644 index 83e1d3ac59..0000000000 --- a/invokeai/frontend/web/src/common/hooks/useSelectedModelKeys.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useAppSelector } from 'app/store/storeHooks'; - -/** - * Gathers all currently selected model keys from parameters and loras. - * This includes the main model, VAE, refiner model, controlnet, and loras. - */ -export const useSelectedModelKeys = () => { - return useAppSelector((state) => { - const keys = new Set(); - const main = state.params.model; - const vae = state.params.vae; - const refiner = state.params.refinerModel; - const controlnet = state.params.controlLora; - const loras = state.loras.loras.map((l) => l.model); - - if (main) { - keys.add(main.key); - } - if (vae) { - keys.add(vae.key); - } - if (refiner) { - keys.add(refiner.key); - } - if (controlnet) { - keys.add(controlnet.key); - } - for (const lora of loras) { - keys.add(lora.key); - } - - return keys; - }); -}; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasAlerts/CanvasAlertsSendingTo.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasAlerts/CanvasAlertsSendingTo.tsx deleted file mode 100644 index 96d388c70a..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasAlerts/CanvasAlertsSendingTo.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { Alert, AlertDescription, AlertIcon, AlertTitle, Button, Flex } from '@invoke-ai/ui-library'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; -import { useBoolean } from 'common/hooks/useBoolean'; -import { selectIsStaging } from 'features/controlLayers/store/canvasStagingAreaSlice'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; -import { useCurrentDestination } from 'features/queue/hooks/useCurrentDestination'; -import { selectActiveTab } from 'features/ui/store/uiSelectors'; -import { activeTabCanvasRightPanelChanged, setActiveTab } from 'features/ui/store/uiSlice'; -import { AnimatePresence, motion } from 'framer-motion'; -import type { PropsWithChildren, ReactNode } from 'react'; -import { useCallback, useMemo } from 'react'; -import { Trans, useTranslation } from 'react-i18next'; - -const ActivateImageViewerButton = (props: PropsWithChildren) => { - const imageViewer = useImageViewer(); - const dispatch = useAppDispatch(); - const onClick = useCallback(() => { - imageViewer.open(); - dispatch(activeTabCanvasRightPanelChanged('gallery')); - }, [imageViewer, dispatch]); - return ( - - ); -}; - -export const CanvasAlertsSendingToGallery = () => { - const { t } = useTranslation(); - const destination = useCurrentDestination(); - const tab = useAppSelector(selectActiveTab); - const isVisible = useMemo(() => { - // This alert should only be visible when the destination is gallery and the tab is canvas - if (tab !== 'canvas') { - return false; - } - if (!destination) { - return false; - } - - return destination === 'gallery'; - }, [destination, tab]); - - return ( - }} /> - } - isVisible={isVisible} - /> - ); -}; - -const ActivateCanvasButton = (props: PropsWithChildren) => { - const dispatch = useAppDispatch(); - const imageViewer = useImageViewer(); - const onClick = useCallback(() => { - dispatch(setActiveTab('canvas')); - dispatch(activeTabCanvasRightPanelChanged('layers')); - imageViewer.close(); - }, [dispatch, imageViewer]); - return ( - - ); -}; - -export const CanvasAlertsSendingToCanvas = () => { - const { t } = useTranslation(); - const destination = useCurrentDestination(); - const isStaging = useAppSelector(selectIsStaging); - const tab = useAppSelector(selectActiveTab); - const isVisible = useMemo(() => { - // When we are on a non-canvas tab, and the current generation's destination is not the canvas, we don't show the alert - // For example, on the workflows tab, when the destinatin is gallery, we don't show the alert - if (tab !== 'canvas' && destination !== 'canvas') { - return false; - } - if (isStaging) { - return true; - } - - if (!destination) { - return false; - } - - return destination === 'canvas'; - }, [destination, isStaging, tab]); - - return ( - }} /> - } - isVisible={isVisible} - /> - ); -}; - -const AlertWrapper = ({ - title, - description, - isVisible, -}: { - title: ReactNode; - description: ReactNode; - isVisible: boolean; -}) => { - const isHovered = useBoolean(false); - - return ( - - {(isVisible || isHovered.isTrue) && ( - - - - - {title} - - {description} - - - )} - - ); -}; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanel.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanel.tsx deleted file mode 100644 index 4e1b3d2c69..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanel.tsx +++ /dev/null @@ -1,261 +0,0 @@ -import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'; -import { dropTargetForElements, monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; -import { dropTargetForExternal, monitorForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter'; -import { Box, Button, Spacer, Tab, TabList, TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library'; -import { useAppDispatch, useAppSelector, useAppStore } from 'app/store/storeHooks'; -import { CanvasLayersPanelContent } from 'features/controlLayers/components/CanvasLayersPanelContent'; -import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; -import { selectEntityCountActive } from 'features/controlLayers/store/selectors'; -import { multipleImageDndSource, singleImageDndSource } from 'features/dnd/dnd'; -import { DndDropOverlay } from 'features/dnd/DndDropOverlay'; -import type { DndTargetState } from 'features/dnd/types'; -import RightPanelContent from 'features/gallery/components/GalleryTopBar'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; -import { selectActiveTabCanvasRightPanel } from 'features/ui/store/uiSelectors'; -import { activeTabCanvasRightPanelChanged } from 'features/ui/store/uiSlice'; -import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useTranslation } from 'react-i18next'; - -export const CanvasRightPanel = memo(() => { - const { t } = useTranslation(); - const activeTab = useAppSelector(selectActiveTabCanvasRightPanel); - const imageViewer = useImageViewer(); - const dispatch = useAppDispatch(); - - const tabIndex = useMemo(() => { - if (activeTab === 'gallery') { - return 1; - } else { - return 0; - } - }, [activeTab]); - - const onClickViewerToggleButton = useCallback(() => { - imageViewer.open(); - }, [imageViewer]); - - const onChangeTab = useCallback( - (index: number) => { - if (index === 0) { - dispatch(activeTabCanvasRightPanelChanged('layers')); - } else { - dispatch(activeTabCanvasRightPanelChanged('gallery')); - } - }, - [dispatch] - ); - - return ( - - - - - - - - - - - - - - - - - - ); -}); - -CanvasRightPanel.displayName = 'CanvasRightPanel'; - -const PanelTabs = memo(() => { - const { t } = useTranslation(); - const store = useAppStore(); - const activeEntityCount = useAppSelector(selectEntityCountActive); - const [layersTabDndState, setLayersTabDndState] = useState('idle'); - const [galleryTabDndState, setGalleryTabDndState] = useState('idle'); - const layersTabRef = useRef(null); - const galleryTabRef = useRef(null); - const timeoutRef = useRef(null); - - const layersTabLabel = useMemo(() => { - if (activeEntityCount === 0) { - return t('controlLayers.layer_other'); - } - return `${t('controlLayers.layer_other')} (${activeEntityCount})`; - }, [activeEntityCount, t]); - - useEffect(() => { - if (!layersTabRef.current) { - return; - } - - const getIsOnLayersTab = () => selectActiveTabCanvasRightPanel(store.getState()) === 'layers'; - - const onDragEnter = () => { - // If we are already on the layers tab, do nothing - if (getIsOnLayersTab()) { - return; - } - - // Else set the state to active and switch to the layers tab after a timeout - setLayersTabDndState('over'); - timeoutRef.current = window.setTimeout(() => { - timeoutRef.current = null; - store.dispatch(activeTabCanvasRightPanelChanged('layers')); - // When we switch tabs, the other tab should be pending - setLayersTabDndState('idle'); - setGalleryTabDndState('potential'); - }, 300); - }; - const onDragLeave = () => { - // Set the state to idle or pending depending on the current tab - if (getIsOnLayersTab()) { - setLayersTabDndState('idle'); - } else { - setLayersTabDndState('potential'); - } - // Abort the tab switch if it hasn't happened yet - if (timeoutRef.current !== null) { - clearTimeout(timeoutRef.current); - } - }; - const onDragStart = () => { - // Set the state to pending when a drag starts - setLayersTabDndState('potential'); - }; - return combine( - dropTargetForElements({ - element: layersTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForElements({ - canMonitor: ({ source }) => { - if (!singleImageDndSource.typeGuard(source.data) && !multipleImageDndSource.typeGuard(source.data)) { - return false; - } - // Only monitor if we are not already on the gallery tab - return !getIsOnLayersTab(); - }, - onDragStart, - }), - dropTargetForExternal({ - element: layersTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForExternal({ - canMonitor: () => !getIsOnLayersTab(), - onDragStart, - }) - ); - }, [store]); - - useEffect(() => { - if (!galleryTabRef.current) { - return; - } - - const getIsOnGalleryTab = () => selectActiveTabCanvasRightPanel(store.getState()) === 'gallery'; - - const onDragEnter = () => { - // If we are already on the gallery tab, do nothing - if (getIsOnGalleryTab()) { - return; - } - - // Else set the state to active and switch to the gallery tab after a timeout - setGalleryTabDndState('over'); - timeoutRef.current = window.setTimeout(() => { - timeoutRef.current = null; - store.dispatch(activeTabCanvasRightPanelChanged('gallery')); - // When we switch tabs, the other tab should be pending - setGalleryTabDndState('idle'); - setLayersTabDndState('potential'); - }, 300); - }; - - const onDragLeave = () => { - // Set the state to idle or pending depending on the current tab - if (getIsOnGalleryTab()) { - setGalleryTabDndState('idle'); - } else { - setGalleryTabDndState('potential'); - } - // Abort the tab switch if it hasn't happened yet - if (timeoutRef.current !== null) { - clearTimeout(timeoutRef.current); - } - }; - - const onDragStart = () => { - // Set the state to pending when a drag starts - setGalleryTabDndState('potential'); - }; - - return combine( - dropTargetForElements({ - element: galleryTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForElements({ - canMonitor: ({ source }) => { - if (!singleImageDndSource.typeGuard(source.data) && !multipleImageDndSource.typeGuard(source.data)) { - return false; - } - // Only monitor if we are not already on the gallery tab - return !getIsOnGalleryTab(); - }, - onDragStart, - }), - dropTargetForExternal({ - element: galleryTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForExternal({ - canMonitor: () => !getIsOnGalleryTab(), - onDragStart, - }) - ); - }, [store]); - - useEffect(() => { - const onDrop = () => { - // Reset the dnd state when a drop happens - setGalleryTabDndState('idle'); - setLayersTabDndState('idle'); - }; - const cleanup = combine(monitorForElements({ onDrop }), monitorForExternal({ onDrop })); - - return () => { - cleanup(); - if (timeoutRef.current !== null) { - clearTimeout(timeoutRef.current); - } - }; - }, []); - - return ( - <> - - - {layersTabLabel} - - - - - - {t('gallery.gallery')} - - - - - ); -}); - -PanelTabs.displayName = 'PanelTabs'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanelStacked.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanelStacked.tsx deleted file mode 100644 index 4806728f27..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasRightPanelStacked.tsx +++ /dev/null @@ -1,254 +0,0 @@ -import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'; -import { dropTargetForElements, monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; -import { dropTargetForExternal, monitorForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter'; -import { Box, Tab } from '@invoke-ai/ui-library'; -import { useAppDispatch, useAppSelector, useAppStore } from 'app/store/storeHooks'; -import { CanvasLayersPanelContent } from 'features/controlLayers/components/CanvasLayersPanelContent'; -import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; -import { selectEntityCountActive } from 'features/controlLayers/store/selectors'; -import { multipleImageDndSource, singleImageDndSource } from 'features/dnd/dnd'; -import { DndDropOverlay } from 'features/dnd/DndDropOverlay'; -import type { DndTargetState } from 'features/dnd/types'; -import RightPanelContent from 'features/gallery/components/GalleryTopBar'; -import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer'; -import { selectActiveTabCanvasRightPanel } from 'features/ui/store/uiSelectors'; -import { activeTabCanvasRightPanelChanged } from 'features/ui/store/uiSlice'; -import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; - -export const CanvasRightPanelStacked = memo(() => { - const { t } = useTranslation(); - const activeTab = useAppSelector(selectActiveTabCanvasRightPanel); - const imageViewer = useImageViewer(); - const dispatch = useAppDispatch(); - - const tabIndex = useMemo(() => { - if (activeTab === 'gallery') { - return 1; - } else { - return 0; - } - }, [activeTab]); - - const onClickViewerToggleButton = useCallback(() => { - imageViewer.open(); - }, [imageViewer]); - - const onChangeTab = useCallback( - (index: number) => { - if (index === 0) { - dispatch(activeTabCanvasRightPanelChanged('layers')); - } else { - dispatch(activeTabCanvasRightPanelChanged('gallery')); - } - }, - [dispatch] - ); - - return ( - - - - - - - - - - - - ); -}); - -CanvasRightPanelStacked.displayName = 'CanvasRightPanelStacked'; - -const PanelTabs = memo(() => { - const { t } = useTranslation(); - const store = useAppStore(); - const activeEntityCount = useAppSelector(selectEntityCountActive); - const [layersTabDndState, setLayersTabDndState] = useState('idle'); - const [galleryTabDndState, setGalleryTabDndState] = useState('idle'); - const layersTabRef = useRef(null); - const galleryTabRef = useRef(null); - const timeoutRef = useRef(null); - - const layersTabLabel = useMemo(() => { - if (activeEntityCount === 0) { - return t('controlLayers.layer_other'); - } - return `${t('controlLayers.layer_other')} (${activeEntityCount})`; - }, [activeEntityCount, t]); - - useEffect(() => { - if (!layersTabRef.current) { - return; - } - - const getIsOnLayersTab = () => selectActiveTabCanvasRightPanel(store.getState()) === 'layers'; - - const onDragEnter = () => { - // If we are already on the layers tab, do nothing - if (getIsOnLayersTab()) { - return; - } - - // Else set the state to active and switch to the layers tab after a timeout - setLayersTabDndState('over'); - timeoutRef.current = window.setTimeout(() => { - timeoutRef.current = null; - store.dispatch(activeTabCanvasRightPanelChanged('layers')); - // When we switch tabs, the other tab should be pending - setLayersTabDndState('idle'); - setGalleryTabDndState('potential'); - }, 300); - }; - const onDragLeave = () => { - // Set the state to idle or pending depending on the current tab - if (getIsOnLayersTab()) { - setLayersTabDndState('idle'); - } else { - setLayersTabDndState('potential'); - } - // Abort the tab switch if it hasn't happened yet - if (timeoutRef.current !== null) { - clearTimeout(timeoutRef.current); - } - }; - const onDragStart = () => { - // Set the state to pending when a drag starts - setLayersTabDndState('potential'); - }; - return combine( - dropTargetForElements({ - element: layersTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForElements({ - canMonitor: ({ source }) => { - if (!singleImageDndSource.typeGuard(source.data) && !multipleImageDndSource.typeGuard(source.data)) { - return false; - } - // Only monitor if we are not already on the gallery tab - return !getIsOnLayersTab(); - }, - onDragStart, - }), - dropTargetForExternal({ - element: layersTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForExternal({ - canMonitor: () => !getIsOnLayersTab(), - onDragStart, - }) - ); - }, [store]); - - useEffect(() => { - if (!galleryTabRef.current) { - return; - } - - const getIsOnGalleryTab = () => selectActiveTabCanvasRightPanel(store.getState()) === 'gallery'; - - const onDragEnter = () => { - // If we are already on the gallery tab, do nothing - if (getIsOnGalleryTab()) { - return; - } - - // Else set the state to active and switch to the gallery tab after a timeout - setGalleryTabDndState('over'); - timeoutRef.current = window.setTimeout(() => { - timeoutRef.current = null; - store.dispatch(activeTabCanvasRightPanelChanged('gallery')); - // When we switch tabs, the other tab should be pending - setGalleryTabDndState('idle'); - setLayersTabDndState('potential'); - }, 300); - }; - - const onDragLeave = () => { - // Set the state to idle or pending depending on the current tab - if (getIsOnGalleryTab()) { - setGalleryTabDndState('idle'); - } else { - setGalleryTabDndState('potential'); - } - // Abort the tab switch if it hasn't happened yet - if (timeoutRef.current !== null) { - clearTimeout(timeoutRef.current); - } - }; - - const onDragStart = () => { - // Set the state to pending when a drag starts - setGalleryTabDndState('potential'); - }; - - return combine( - dropTargetForElements({ - element: galleryTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForElements({ - canMonitor: ({ source }) => { - if (!singleImageDndSource.typeGuard(source.data) && !multipleImageDndSource.typeGuard(source.data)) { - return false; - } - // Only monitor if we are not already on the gallery tab - return !getIsOnGalleryTab(); - }, - onDragStart, - }), - dropTargetForExternal({ - element: galleryTabRef.current, - onDragEnter, - onDragLeave, - }), - monitorForExternal({ - canMonitor: () => !getIsOnGalleryTab(), - onDragStart, - }) - ); - }, [store]); - - useEffect(() => { - const onDrop = () => { - // Reset the dnd state when a drop happens - setGalleryTabDndState('idle'); - setLayersTabDndState('idle'); - }; - const cleanup = combine(monitorForElements({ onDrop }), monitorForExternal({ onDrop })); - - return () => { - cleanup(); - if (timeoutRef.current !== null) { - clearTimeout(timeoutRef.current); - } - }; - }, []); - - return ( - <> - - - {layersTabLabel} - - - - - - {t('gallery.gallery')} - - - - - ); -}); - -PanelTabs.displayName = 'PanelTabs'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/context.tsx b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/context.tsx index 5c8b667a3c..d4089d761d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/context.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/SimpleSession/context.tsx @@ -17,7 +17,7 @@ import type { S } from 'services/api/types'; import { $socket } from 'services/events/stores'; import { assert } from 'tsafe'; -export type ProgressData = { +type ProgressData = { itemId: number; progressEvent: S['InvocationProgressEvent'] | null; progressImage: ProgressImage | null; @@ -46,28 +46,7 @@ export const useProgressData = ( return value; }; -export const useHasProgressImage = ( - $progressData: WritableAtom>, - itemId: number -): boolean => { - const [value, setValue] = useState(false); - useEffect(() => { - const unsub = $progressData.subscribe((data) => { - const progressData = data[itemId]; - setValue(Boolean(progressData?.progressImage)); - }); - return () => { - unsub(); - }; - }, [$progressData, itemId]); - - return value; -}; - -export const setProgress = ( - $progressData: WritableAtom>, - data: S['InvocationProgressEvent'] -) => { +const setProgress = ($progressData: WritableAtom>, data: S['InvocationProgressEvent']) => { const progressData = $progressData.get(); const current = progressData[data.item_id]; if (current) { @@ -120,7 +99,7 @@ export const clearProgressImage = ($progressData: WritableAtom; $itemCount: Atom; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaIsStagingGate.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaIsStagingGate.tsx deleted file mode 100644 index d66e30d0c0..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaIsStagingGate.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useAppSelector } from 'app/store/storeHooks'; -import { selectIsStaging } from 'features/controlLayers/store/canvasStagingAreaSlice'; -import type { PropsWithChildren } from 'react'; -import { memo } from 'react'; -import { useGetQueueCountsByDestinationQuery } from 'services/api/endpoints/queue'; - -// This hook just serves as a persistent subscriber for the queue count query. -const queueCountArg = { destination: 'canvas' }; -const useCanvasQueueCountWatcher = () => { - useGetQueueCountsByDestinationQuery(queueCountArg); -}; - -export const StagingAreaIsStagingGate = memo((props: PropsWithChildren) => { - useCanvasQueueCountWatcher(); - const isStaging = useAppSelector(selectIsStaging); - - if (!isStaging) { - return null; - } - - return props.children; -}); - -StagingAreaIsStagingGate.displayName = 'StagingAreaIsStagingGate'; 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 3a1feddebc..147b473af7 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarAcceptButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarAcceptButton.tsx @@ -5,10 +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 { - selectImageCount, - stagingAreaReset, -} from 'features/controlLayers/store/canvasStagingAreaSlice'; +import { selectImageCount, stagingAreaReset } 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'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardSelectedButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardSelectedButton.tsx index 43a548aec0..c577bc4fa6 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardSelectedButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarDiscardSelectedButton.tsx @@ -1,12 +1,6 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useCanvasSessionContext } from 'features/controlLayers/components/SimpleSession/context'; -import { - selectImageCount, - selectSelectedImage, - selectStagedImageIndex, -} from 'features/controlLayers/store/canvasStagingAreaSlice'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { PiXBold } from 'react-icons/pi'; @@ -14,12 +8,8 @@ import { useDeleteQueueItemMutation } from 'services/api/endpoints/queue'; export const StagingAreaToolbarDiscardSelectedButton = memo(() => { const ctx = useCanvasSessionContext(); - const dispatch = useAppDispatch(); const [deleteQueueItem] = useDeleteQueueItemMutation(); const selectedItemId = useStore(ctx.$selectedItemId); - const index = useAppSelector(selectStagedImageIndex); - const selectedImage = useAppSelector(selectSelectedImage); - const imageCount = useAppSelector(selectImageCount); const { t } = useTranslation(); @@ -28,11 +18,6 @@ export const StagingAreaToolbarDiscardSelectedButton = memo(() => { return; } deleteQueueItem({ item_id: selectedItemId }); - // if (imageCount === 1) { - // dispatch(stagingAreaReset()); - // } else { - // dispatch(stagingAreaStagedImageDiscarded({ index })); - // } }, [selectedItemId, deleteQueueItem]); return ( diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarImageCountButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarImageCountButton.tsx index 7e14ff580a..446dea8836 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarImageCountButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarImageCountButton.tsx @@ -1,16 +1,12 @@ import { Button } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; -import { useAppSelector } from 'app/store/storeHooks'; import { useCanvasSessionContext } from 'features/controlLayers/components/SimpleSession/context'; -import { selectImageCount, selectStagedImageIndex } from 'features/controlLayers/store/canvasStagingAreaSlice'; import { memo, useMemo } from 'react'; export const StagingAreaToolbarImageCountButton = memo(() => { const ctx = useCanvasSessionContext(); const selectItemIndex = useStore(ctx.$selectedItemIndex); const itemCount = useStore(ctx.$itemCount); - const index = useAppSelector(selectStagedImageIndex); - const imageCount = useAppSelector(selectImageCount); const counterText = useMemo(() => { if (itemCount > 0 && selectItemIndex !== null) { diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarNextButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarNextButton.tsx index 8d60420de2..0a5b5e50de 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarNextButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarNextButton.tsx @@ -1,10 +1,8 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useIsRegionFocused } from 'common/hooks/focus'; import { useCanvasSessionContext } from 'features/controlLayers/components/SimpleSession/context'; import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; -import { selectImageCount } from 'features/controlLayers/store/canvasStagingAreaSlice'; import { memo, useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; @@ -13,9 +11,7 @@ import { PiArrowRightBold } from 'react-icons/pi'; export const StagingAreaToolbarNextButton = memo(() => { const ctx = useCanvasSessionContext(); const itemCount = useStore(ctx.$itemCount); - const dispatch = useAppDispatch(); const canvasManager = useCanvasManager(); - const imageCount = useAppSelector(selectImageCount); const shouldShowStagedImage = useStore(canvasManager.stagingArea.$shouldShowStagedImage); const isCanvasFocused = useIsRegionFocused('canvas'); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarPrevButton.tsx b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarPrevButton.tsx index ae1539a20a..430fdf9629 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarPrevButton.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/StagingArea/StagingAreaToolbarPrevButton.tsx @@ -1,10 +1,8 @@ import { IconButton } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; -import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useIsRegionFocused } from 'common/hooks/focus'; import { useCanvasSessionContext } from 'features/controlLayers/components/SimpleSession/context'; import { useCanvasManager } from 'features/controlLayers/contexts/CanvasManagerProviderGate'; -import { selectImageCount } from 'features/controlLayers/store/canvasStagingAreaSlice'; import { memo, useCallback } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; @@ -13,9 +11,7 @@ import { PiArrowLeftBold } from 'react-icons/pi'; export const StagingAreaToolbarPrevButton = memo(() => { const ctx = useCanvasSessionContext(); const itemCount = useStore(ctx.$itemCount); - const dispatch = useAppDispatch(); const canvasManager = useCanvasManager(); - const imageCount = useAppSelector(selectImageCount); const shouldShowStagedImage = useStore(canvasManager.stagingArea.$shouldShowStagedImage); const isCanvasFocused = useIsRegionFocused('canvas'); diff --git a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx index b3f0e21972..641b62dd98 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityHeaderWarnings.tsx @@ -4,6 +4,7 @@ import { EMPTY_ARRAY } from 'app/store/constants'; import { useAppSelector } from 'app/store/storeHooks'; import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; import { useEntityIsEnabled } from 'features/controlLayers/hooks/useEntityIsEnabled'; +import { selectMainModelConfig } from 'features/controlLayers/store/paramsSlice'; import { selectCanvasSlice, selectEntityOrThrow } from 'features/controlLayers/store/selectors'; import type { CanvasEntityIdentifier } from 'features/controlLayers/store/types'; import { @@ -18,7 +19,6 @@ import { upperFirst } from 'lodash-es'; import { memo, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { PiWarningBold } from 'react-icons/pi'; -import { selectMainModelConfig } from 'features/controlLayers/store/paramsSlice'; import type { Equals } from 'tsafe'; import { assert } from 'tsafe'; diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/addLayerHooks.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/addLayerHooks.ts index dfc4780d37..a1b0ba67c5 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/addLayerHooks.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/addLayerHooks.ts @@ -15,7 +15,7 @@ import { rgNegativePromptChanged, rgPositivePromptChanged, } from 'features/controlLayers/store/canvasSlice'; -import { selectBase } from 'features/controlLayers/store/paramsSlice'; +import { selectBase, selectMainModelConfig } from 'features/controlLayers/store/paramsSlice'; import { selectCanvasSlice, selectEntity } from 'features/controlLayers/store/selectors'; import type { CanvasEntityIdentifier, @@ -35,11 +35,7 @@ import { } from 'features/controlLayers/store/util'; import { zModelIdentifierField } from 'features/nodes/types/common'; import { useCallback } from 'react'; -import { - modelConfigsAdapterSelectors, - selectModelConfigsQuery, -} from 'services/api/endpoints/models'; -import { selectMainModelConfig } from '../store/paramsSlice'; +import { modelConfigsAdapterSelectors, selectModelConfigsQuery } from 'services/api/endpoints/models'; import type { ControlLoRAModelConfig, ControlNetModelConfig, diff --git a/invokeai/frontend/web/src/features/controlLayers/hooks/saveCanvasHooks.ts b/invokeai/frontend/web/src/features/controlLayers/hooks/saveCanvasHooks.ts index 5eb153cfc7..a1b2bac014 100644 --- a/invokeai/frontend/web/src/features/controlLayers/hooks/saveCanvasHooks.ts +++ b/invokeai/frontend/web/src/features/controlLayers/hooks/saveCanvasHooks.ts @@ -14,7 +14,12 @@ import { rgAdded, rgIPAdapterImageChanged, } from 'features/controlLayers/store/canvasSlice'; -import { selectNegativePrompt, selectPositivePrompt, selectSeed } from 'features/controlLayers/store/paramsSlice'; +import { + selectMainModelConfig, + selectNegativePrompt, + selectPositivePrompt, + selectSeed, +} from 'features/controlLayers/store/paramsSlice'; import { selectCanvasMetadata } from 'features/controlLayers/store/selectors'; import type { CanvasControlLayerState, @@ -33,7 +38,6 @@ import { toast } from 'features/toast/toast'; import { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { serializeError } from 'serialize-error'; -import { selectMainModelConfig } from '../store/paramsSlice'; import type { ImageDTO } from 'services/api/types'; import type { JsonObject } from 'type-fest'; diff --git a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasProgressImageModule.ts b/invokeai/frontend/web/src/features/controlLayers/konva/CanvasProgressImageModule.ts deleted file mode 100644 index c36933a6cf..0000000000 --- a/invokeai/frontend/web/src/features/controlLayers/konva/CanvasProgressImageModule.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { Mutex } from 'async-mutex'; -import { parseify } from 'common/util/serialize'; -import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager'; -import { CanvasModuleBase } from 'features/controlLayers/konva/CanvasModuleBase'; -import { getPrefixedId, loadImage } from 'features/controlLayers/konva/util'; -import { selectShowProgressOnCanvas } from 'features/controlLayers/store/canvasSettingsSlice'; -import Konva from 'konva'; -import { atom } from 'nanostores'; -import type { Logger } from 'roarr'; -import { selectCanvasQueueCounts } from 'services/api/endpoints/queue'; -import type { S } from 'services/api/types'; -import type { SetNonNullable } from 'type-fest'; - -type ProgressEventWithImage = SetNonNullable; -const isProgressEventWithImage = (val: S['InvocationProgressEvent']): val is ProgressEventWithImage => - Boolean(val.image); - -export class CanvasProgressImageModule extends CanvasModuleBase { - readonly type = 'progress_image'; - readonly id: string; - readonly path: string[]; - readonly parent: CanvasManager; - readonly manager: CanvasManager; - readonly log: Logger; - - konva: { - group: Konva.Group; - image: Konva.Image | null; // The image is loaded asynchronously, so it may not be available immediately - }; - $isLoading = atom(false); - $isError = atom(false); - imageElement: HTMLImageElement | null = null; - - subscriptions = new Set<() => void>(); - $lastProgressEvent = atom(null); - $hasActiveGeneration = atom(false); - mutex: Mutex = new Mutex(); - - constructor(manager: CanvasManager) { - super(); - this.id = getPrefixedId(this.type); - this.parent = manager; - this.manager = manager; - this.path = this.manager.buildPath(this); - this.log = this.manager.buildLogger(this); - - this.log.debug('Creating progress image module'); - - this.konva = { - group: new Konva.Group({ name: `${this.type}:group`, listening: false }), - image: null, - }; - - this.subscriptions.add(this.manager.stagingArea.$shouldShowStagedImage.listen(this.render)); - this.subscriptions.add(this.manager.stateApi.createStoreSubscription(selectShowProgressOnCanvas, this.render)); - this.subscriptions.add(this.setSocketEventListeners()); - this.subscriptions.add( - this.manager.stateApi.createStoreSubscription(selectCanvasQueueCounts, ({ data }) => { - if (data && (data.in_progress > 0 || data.pending > 0)) { - this.$hasActiveGeneration.set(true); - } else { - this.$hasActiveGeneration.set(false); - } - }) - ); - this.subscriptions.add(this.$lastProgressEvent.listen(this.render)); - } - - setSocketEventListeners = (): (() => void) => { - const progressListener = (data: S['InvocationProgressEvent']) => { - if (data.destination !== 'canvas') { - return; - } - if (!isProgressEventWithImage(data)) { - return; - } - if (!this.$hasActiveGeneration.get()) { - return; - } - this.$lastProgressEvent.set(data); - }; - - // Handle a canceled or failed canvas generation. We should clear the progress image in this case. - const queueItemStatusChangedListener = (data: S['QueueItemStatusChangedEvent']) => { - if (data.destination !== 'canvas') { - return; - } - - // The staging area module handles _completed_ events. Only care about failed or canceled here. - if (data.status === 'failed' || data.status === 'canceled') { - this.$lastProgressEvent.set(null); - this.$hasActiveGeneration.set(false); - } - }; - - const clearProgress = () => { - this.$lastProgressEvent.set(null); - }; - - this.manager.socket.on('invocation_progress', progressListener); - this.manager.socket.on('queue_item_status_changed', queueItemStatusChangedListener); - this.manager.socket.on('connect', clearProgress); - this.manager.socket.on('connect_error', clearProgress); - this.manager.socket.on('disconnect', clearProgress); - - return () => { - this.manager.socket.off('invocation_progress', progressListener); - this.manager.socket.off('queue_item_status_changed', queueItemStatusChangedListener); - this.manager.socket.off('connect', clearProgress); - this.manager.socket.off('connect_error', clearProgress); - this.manager.socket.off('disconnect', clearProgress); - }; - }; - - getNodes = () => { - return [this.konva.group]; - }; - - render = async () => { - const release = await this.mutex.acquire(); - - const event = this.$lastProgressEvent.get(); - const showProgressOnCanvas = this.manager.stateApi.runSelector(selectShowProgressOnCanvas); - - if (!event || !showProgressOnCanvas) { - this.konva.group.visible(false); - this.konva.image?.destroy(); - this.konva.image = null; - this.imageElement = null; - this.$isLoading.set(false); - this.$isError.set(false); - release(); - return; - } - - this.$isLoading.set(true); - - const { x, y, width, height } = this.manager.stateApi.getBbox().rect; - try { - this.imageElement = await loadImage(event.image.dataURL); - if (this.konva.image) { - this.konva.image.setAttrs({ - image: this.imageElement, - x, - y, - width, - height, - }); - } else { - this.konva.image = new Konva.Image({ - name: `${this.type}:image`, - listening: false, - image: this.imageElement, - x, - y, - width, - height, - perfectDrawEnabled: false, - }); - this.konva.group.add(this.konva.image); - } - // Should not be visible if the user has disabled showing staging images - this.konva.group.visible(this.manager.stagingArea.$shouldShowStagedImage.get()); - } catch { - this.$isError.set(true); - } finally { - this.$isLoading.set(false); - release(); - } - }; - - destroy = () => { - this.log.debug('Destroying module'); - this.subscriptions.forEach((unsubscribe) => unsubscribe()); - this.subscriptions.clear(); - this.konva.group.destroy(); - }; - - repr = () => { - return { - id: this.id, - type: this.type, - path: this.path, - $lastProgressEvent: parseify(this.$lastProgressEvent.get()), - $hasActiveGeneration: this.$hasActiveGeneration.get(), - $isError: this.$isError.get(), - $isLoading: this.$isLoading.get(), - }; - }; -} diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 8768187044..83912c5b4d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -64,7 +64,6 @@ const zImageWithDimsDataURL = z.object({ width: z.number().int().positive(), height: z.number().int().positive(), }); -export type ImageWithDimsDataURL = z.infer; const zBeginEndStepPct = z .tuple([z.number().gte(0).lte(1), z.number().gte(0).lte(1)]) @@ -100,7 +99,7 @@ const zRgbColor = z.object({ b: z.number().int().min(0).max(255), }); export type RgbColor = z.infer; -export const zRgbaColor = zRgbColor.extend({ +const zRgbaColor = zRgbColor.extend({ a: z.number().min(0).max(1), }); export type RgbaColor = z.infer; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/SizedSkeletonLoader.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/SizedSkeletonLoader.tsx deleted file mode 100644 index 82c4a52d14..0000000000 --- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/SizedSkeletonLoader.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Skeleton } from '@invoke-ai/ui-library'; -import { memo } from 'react'; - -type Props = { - width: number; - height: number; -}; - -export const SizedSkeletonLoader = memo(({ width, height }: Props) => { - return ; -}); - -SizedSkeletonLoader.displayName = 'SizedSkeletonLoader'; diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx index 29b6a46374..b2f5158b7a 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/CurrentImagePreview.tsx @@ -2,7 +2,6 @@ import { Box, Flex } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; import { useAppSelector } from 'app/store/storeHooks'; import { CanvasAlertsInvocationProgress } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsInvocationProgress'; -import { CanvasAlertsSendingToCanvas } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsSendingTo'; import { DndImage } from 'features/dnd/DndImage'; import ImageMetadataViewer from 'features/gallery/components/ImageMetadataViewer/ImageMetadataViewer'; import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons'; @@ -52,7 +51,6 @@ const CurrentImagePreview = ({ imageDTO }: { imageDTO?: ImageDTO }) => { pointerEvents="none" alignItems="flex-start" > - {shouldShowImageDetails && imageDTO && ( diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx index 34d9329532..521c0a2486 100644 --- a/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/ImageViewer/ImageViewer.tsx @@ -7,7 +7,6 @@ import CurrentImagePreview from 'features/gallery/components/ImageViewer/Current import { ImageComparison } from 'features/gallery/components/ImageViewer/ImageComparison'; import { ViewerToolbar } from 'features/gallery/components/ImageViewer/ViewerToolbar'; import { selectLastSelectedImageName } from 'features/gallery/store/gallerySelectors'; -import type { ReactNode } from 'react'; import { memo, useRef } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; @@ -16,25 +15,25 @@ import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useImageViewer } from './useImageViewer'; -type Props = { - closeButton?: ReactNode; -}; +// type Props = { +// closeButton?: ReactNode; +// }; -const useFocusRegionOptions = { - focusOnMount: true, -}; +// const useFocusRegionOptions = { +// focusOnMount: true, +// }; -const FOCUS_REGION_STYLES: SystemStyleObject = { - display: 'flex', - width: 'full', - height: 'full', - position: 'absolute', - flexDirection: 'column', - inset: 0, - alignItems: 'center', - justifyContent: 'center', - overflow: 'hidden', -}; +// const FOCUS_REGION_STYLES: SystemStyleObject = { +// display: 'flex', +// width: 'full', +// height: 'full', +// position: 'absolute', +// flexDirection: 'column', +// inset: 0, +// alignItems: 'center', +// justifyContent: 'center', +// overflow: 'hidden', +// }; export const ImageViewer = memo(() => { const lastSelectedImageName = useAppSelector(selectLastSelectedImageName); diff --git a/invokeai/frontend/web/src/features/nodes/types/common.ts b/invokeai/frontend/web/src/features/nodes/types/common.ts index c57954b2ec..7b1386b5ba 100644 --- a/invokeai/frontend/web/src/features/nodes/types/common.ts +++ b/invokeai/frontend/web/src/features/nodes/types/common.ts @@ -93,7 +93,7 @@ export const zMainModelBase = z.enum([ 'chatgpt-4o', 'flux-kontext', ]); -export type MainModelBase = z.infer; +type MainModelBase = z.infer; export const isMainModelBase = (base: unknown): base is MainModelBase => zMainModelBase.safeParse(base).success; const zModelType = z.enum([ 'main', diff --git a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts index ce87203eeb..2d0eb03d44 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graph/graphBuilderUtils.ts @@ -149,7 +149,7 @@ export const getInfill = ( assert(false, 'Unknown infill method'); }; -export const CANVAS_OUTPUT_PREFIX = 'canvas_output'; +const CANVAS_OUTPUT_PREFIX = 'canvas_output'; export const isMainModelWithoutUnet = (modelLoader: Invocation) => { return ( diff --git a/invokeai/frontend/web/src/features/queue/components/ClearQueueButton.tsx b/invokeai/frontend/web/src/features/queue/components/ClearQueueButton.tsx deleted file mode 100644 index 72fc05723e..0000000000 --- a/invokeai/frontend/web/src/features/queue/components/ClearQueueButton.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { ButtonProps } from '@invoke-ai/ui-library'; -import { Button } from '@invoke-ai/ui-library'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { PiTrashSimpleFill } from 'react-icons/pi'; - -import { useClearQueueDialog } from './ClearQueueConfirmationAlertDialog'; - -type Props = ButtonProps; - -const ClearQueueButton = (props: Props) => { - const { t } = useTranslation(); - const clearQueue = useClearQueueDialog(); - - return ( - <> - - - ); -}; - -export default memo(ClearQueueButton); diff --git a/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx b/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx index d4306e9473..9de86f9eb7 100644 --- a/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx +++ b/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx @@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'; const [useClearQueueConfirmationAlertDialog] = buildUseBoolean(false); -export const useClearQueueDialog = () => { +const useClearQueueDialog = () => { const dialog = useClearQueueConfirmationAlertDialog(); const { clearQueue, isLoading, isDisabled, queueStatus } = useClearQueue(); diff --git a/invokeai/frontend/web/src/features/ui/components/AppContent.tsx b/invokeai/frontend/web/src/features/ui/components/AppContent.tsx index 83f220e4a6..199e5d8c43 100644 --- a/invokeai/frontend/web/src/features/ui/components/AppContent.tsx +++ b/invokeai/frontend/web/src/features/ui/components/AppContent.tsx @@ -1,22 +1,15 @@ -import { Box, Flex } from '@invoke-ai/ui-library'; +import { Flex } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; -import { CanvasMainPanelContent } from 'features/controlLayers/components/CanvasMainPanelContent'; import { useDndMonitor } from 'features/dnd/useDndMonitor'; -import { ImageViewer } from 'features/gallery/components/ImageViewer/ImageViewer'; -import WorkflowsTabLeftPanel from 'features/nodes/components/sidePanel/WorkflowsTabLeftPanel'; -import QueueControls from 'features/queue/components/QueueControls'; import { useRegisteredHotkeys } from 'features/system/components/HotkeysModal/useHotkeyData'; import { FloatingLeftPanelButtons } from 'features/ui/components/FloatingLeftPanelButtons'; import { FloatingRightPanelButtons } from 'features/ui/components/FloatingRightPanelButtons'; -import ParametersPanelTextToImage from 'features/ui/components/ParametersPanels/ParametersPanelTextToImage'; +import { LeftPanelContent } from 'features/ui/components/LeftPanelContent'; +import { MainPanelContent } from 'features/ui/components/MainPanelContent'; import { RightPanelContent } from 'features/ui/components/RightPanelContent'; -import ModelManagerTab from 'features/ui/components/tabs/ModelManagerTab'; -import QueueTab from 'features/ui/components/tabs/QueueTab'; -import { WorkflowsMainPanel } from 'features/ui/components/tabs/WorkflowsTabContent'; import { VerticalNavBar } from 'features/ui/components/VerticalNavBar'; import type { UsePanelOptions } from 'features/ui/hooks/usePanel'; import { usePanel } from 'features/ui/hooks/usePanel'; -import { selectActiveTab } from 'features/ui/store/uiSelectors'; import { $isLeftPanelOpen, $isRightPanelOpen, @@ -29,10 +22,7 @@ import type { CSSProperties } from 'react'; import { memo, useMemo, useRef } from 'react'; import type { ImperativePanelGroupHandle } from 'react-resizable-panels'; import { Panel, PanelGroup } from 'react-resizable-panels'; -import type { Equals } from 'tsafe'; -import { assert } from 'tsafe'; -import ParametersPanelUpscale from './ParametersPanels/ParametersPanelUpscale'; import { VerticalResizeHandle } from './tabs/ResizeHandle'; const panelStyles: CSSProperties = { position: 'relative', height: '100%', width: '100%', minWidth: 0 }; @@ -153,42 +143,3 @@ export const AppContent = memo(() => { ); }); AppContent.displayName = 'AppContent'; - -const LeftPanelContent = memo(() => { - const tab = useAppSelector(selectActiveTab); - - return ( - - - - {tab === 'canvas' && } - {tab === 'upscaling' && } - {tab === 'workflows' && } - - - ); -}); -LeftPanelContent.displayName = 'LeftPanelContent'; - -const MainPanelContent = memo(() => { - const tab = useAppSelector(selectActiveTab); - - if (tab === 'canvas') { - return ; - } - if (tab === 'upscaling') { - return ; - } - if (tab === 'workflows') { - return ; - } - if (tab === 'models') { - return ; - } - if (tab === 'queue') { - return ; - } - - assert>(false); -}); -MainPanelContent.displayName = 'MainPanelContent'; diff --git a/invokeai/frontend/web/src/features/ui/components/LeftPanelContent.tsx b/invokeai/frontend/web/src/features/ui/components/LeftPanelContent.tsx index 873e803186..f6190ed58c 100644 --- a/invokeai/frontend/web/src/features/ui/components/LeftPanelContent.tsx +++ b/invokeai/frontend/web/src/features/ui/components/LeftPanelContent.tsx @@ -8,7 +8,7 @@ import { memo } from 'react'; import ParametersPanelUpscale from './ParametersPanels/ParametersPanelUpscale'; -const LeftPanelContent = memo(() => { +export const LeftPanelContent = memo(() => { const tab = useAppSelector(selectActiveTab); return ( diff --git a/invokeai/frontend/web/src/features/ui/components/MainPanelContent.tsx b/invokeai/frontend/web/src/features/ui/components/MainPanelContent.tsx index 58ac5a4558..48c812e6a1 100644 --- a/invokeai/frontend/web/src/features/ui/components/MainPanelContent.tsx +++ b/invokeai/frontend/web/src/features/ui/components/MainPanelContent.tsx @@ -9,7 +9,7 @@ import { memo } from 'react'; import type { Equals } from 'tsafe'; import { assert } from 'tsafe'; -const MainPanelContent = memo(() => { +export const MainPanelContent = memo(() => { const tab = useAppSelector(selectActiveTab); if (tab === 'canvas') { diff --git a/invokeai/frontend/web/src/services/api/endpoints/models.ts b/invokeai/frontend/web/src/services/api/endpoints/models.ts index 405c794582..bb526fab36 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/models.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/models.ts @@ -324,4 +324,3 @@ export const { } = modelsApi; export const selectModelConfigsQuery = modelsApi.endpoints.getModelConfigs.select(); - diff --git a/invokeai/frontend/web/src/services/api/endpoints/queue.ts b/invokeai/frontend/web/src/services/api/endpoints/queue.ts index 6a13f7e2e4..2239a5df3a 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/queue.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/queue.ts @@ -364,11 +364,8 @@ export const { useClearQueueMutation, usePruneQueueMutation, useGetQueueStatusQuery, - useGetQueueItemQuery, useListQueueItemsQuery, - useListAllQueueItemsQuery, useCancelQueueItemMutation, - useCancelByDestinationMutation, useDeleteQueueItemMutation, useDeleteQueueItemsByDestinationMutation, useGetBatchStatusQuery, diff --git a/invokeai/frontend/web/src/services/events/onInvocationComplete.tsx b/invokeai/frontend/web/src/services/events/onInvocationComplete.tsx index e26a2d05d7..8e299202e9 100644 --- a/invokeai/frontend/web/src/services/events/onInvocationComplete.tsx +++ b/invokeai/frontend/web/src/services/events/onInvocationComplete.tsx @@ -11,9 +11,7 @@ import { boardsApi } from 'services/api/endpoints/boards'; import { getImageDTOSafe, imagesApi } from 'services/api/endpoints/images'; import type { ImageDTO, S } from 'services/api/types'; import { getCategories, getListImagesUrl } from 'services/api/util'; -import { - $lastProgressEvent, -} from 'services/events/stores'; +import { $lastProgressEvent } from 'services/events/stores'; import type { Param0 } from 'tsafe'; import { objectEntries } from 'tsafe'; import type { JsonObject } from 'type-fest'; diff --git a/invokeai/frontend/web/src/services/events/setEventListeners.tsx b/invokeai/frontend/web/src/services/events/setEventListeners.tsx index 72ec0feb95..a5b4c069c5 100644 --- a/invokeai/frontend/web/src/services/events/setEventListeners.tsx +++ b/invokeai/frontend/web/src/services/events/setEventListeners.tsx @@ -31,14 +31,11 @@ import type { Socket } from 'socket.io-client'; import type { JsonObject } from 'type-fest'; import { - $lastCanvasProgressEvent, - $lastCanvasProgressImage, $lastProgressEvent, $lastUpscalingProgressEvent, $lastUpscalingProgressImage, $lastWorkflowsProgressEvent, $lastWorkflowsProgressImage, - $progressImages, } from './stores'; const log = logger('events'); @@ -116,22 +113,6 @@ export const setEventListeners = ({ socket, store, setIsConnected }: SetEventLis $lastProgressEvent.set(data); - if (data.image) { - const progressData = $progressImages.get()[session_id]; - if (progressData) { - $progressImages.setKey(session_id, { ...progressData, progressImage: data.image }); - } else { - $progressImages.setKey(session_id, { sessionId: session_id, isFinished: false, progressImage: data.image }); - } - } - - if (origin === 'canvas') { - $lastCanvasProgressEvent.set(data); - if (image) { - $lastCanvasProgressImage.set({ sessionId: session_id, image }); - } - } - if (origin === 'upscaling') { $lastUpscalingProgressEvent.set(data); if (image) { diff --git a/invokeai/frontend/web/src/services/events/stores.ts b/invokeai/frontend/web/src/services/events/stores.ts index 0d62110efd..c86e147ea4 100644 --- a/invokeai/frontend/web/src/services/events/stores.ts +++ b/invokeai/frontend/web/src/services/events/stores.ts @@ -1,8 +1,7 @@ import type { EphemeralProgressImage } from 'features/controlLayers/store/types'; -import type { ProgressImage } from 'features/nodes/types/common'; import { round } from 'lodash-es'; import { atom, computed, map } from 'nanostores'; -import type { ImageDTO, S } from 'services/api/types'; +import type { S } from 'services/api/types'; import type { AppSocket } from 'services/events/types'; import type { ManagerOptions, SocketOptions } from 'socket.io-client'; @@ -11,22 +10,6 @@ export const $socketOptions = map>({}); export const $isConnected = atom(false); export const $lastProgressEvent = atom(null); -export type ProgressAndResult = { - sessionId: string; - isFinished: boolean; - progressImage?: ProgressImage; - resultImage?: ImageDTO; -}; -export const $progressImages = map({} as Record); - -export type ProgressData = { - sessionId: string; - progressEvent: S['InvocationProgressEvent'] | null; - progressImage: ProgressImage | null; -}; - -export const $lastCanvasProgressEvent = atom(null); -export const $lastCanvasProgressImage = atom(null); export const $lastWorkflowsProgressEvent = atom(null); export const $lastWorkflowsProgressImage = atom(null); export const $lastUpscalingProgressEvent = atom(null);