diff --git a/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx b/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx index 0bf7d226ce..17e23ff26f 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/CanvasMainPanelContent.tsx @@ -1,5 +1,5 @@ /* eslint-disable i18next/no-literal-string */ -import type { SystemStyleObject } from '@invoke-ai/ui-library'; +import type { ButtonGroupProps, SystemStyleObject, TextProps } from '@invoke-ai/ui-library'; import { Box, Button, @@ -26,6 +26,7 @@ import { EMPTY_ARRAY } from 'app/store/constants'; import { useAppStore } from 'app/store/nanostores/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { FocusRegionWrapper } from 'common/components/FocusRegionWrapper'; +import { IAINoContentFallbackWithSpinner } from 'common/components/IAIImageFallback'; import { useImageUploadButton } from 'common/hooks/useImageUploadButton'; import { CanvasAlertsPreserveMask } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsPreserveMask'; import { CanvasAlertsSelectedEntityStatus } from 'features/controlLayers/components/CanvasAlerts/CanvasAlertsSelectedEntityStatus'; @@ -63,7 +64,7 @@ import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useListAllQueueItemsQuery } from 'services/api/endpoints/queue'; import type { ImageDTO, S } from 'services/api/types'; import type { ProgressData } from 'services/events/stores'; -import { $socket, clearProgressEvent, setProgress, useHasProgressImage, useProgressData } from 'services/events/stores'; +import { $socket, clearProgressImage, setProgress, useHasProgressImage, useProgressData } from 'services/events/stores'; import type { Equals, Param0 } from 'tsafe'; import { assert, objectEntries } from 'tsafe'; @@ -464,9 +465,6 @@ const StagingArea = memo(() => { if (data.status === 'in_progress' && autoSwitch) { onSelectItemId(data.item_id); } - if (data.status === 'completed' || data.status === 'canceled' || data.status === 'failed') { - clearProgressEvent(ctx.$progressData, data.session_id); - } }; socket.on('queue_item_status_changed', onQueueItemStatusChanged); @@ -512,6 +510,7 @@ const StagingArea = memo(() => { {selectedItem && selectedItemIndex !== null && ( { {items.map((item, i) => ( `queue-item-status-card-${item_id}`; @@ -607,7 +606,6 @@ type QueueItemStatusCardMiniProps = { const QueueItemCard = memo( ({ item, isSelected, number, onSelectItemId, onChangeAutoSwitch, size }: QueueItemStatusCardMiniProps) => { const ctx = useStagingContext(); - const [isImageLoaded, setIsImageLoaded] = useState(false); const hasProgressImage = useHasProgressImage(ctx.$progressData, item.session_id); const outputImageName = useMemo(() => { @@ -631,24 +629,6 @@ const QueueItemCard = memo( const { currentData: imageDTO } = useGetImageDTOQuery(outputImageName ?? skipToken); - const syncIsReady = useCallback(async () => { - if (!imageDTO) { - setIsImageLoaded(false); - return; - } - try { - const _ = await loadImage(size === 'mini' ? imageDTO.thumbnail_url : imageDTO.image_url, true); - setIsImageLoaded(true); - return; - } catch { - setIsImageLoaded(false); - } - }, [imageDTO, size]); - - useEffect(() => { - syncIsReady(); - }, [syncIsReady]); - const onClick = useCallback(() => { onSelectItemId(item.item_id); }, [item.item_id, onSelectItemId]); @@ -657,22 +637,38 @@ const QueueItemCard = memo( onChangeAutoSwitch(item.status === 'in_progress'); }, [item.status, onChangeAutoSwitch]); - if (imageDTO && isImageLoaded) { + const syncIsReady = useCallback(async () => { + if (!imageDTO) { + return; + } + try { + await loadImage(imageDTO.image_url, true); + clearProgressImage(ctx.$progressData, item.session_id); + return; + } catch { + // noop + } + }, [ctx.$progressData, imageDTO, item.session_id]); + + useEffect(() => { + syncIsReady(); + }, [syncIsReady]); + + if (imageDTO && !hasProgressImage) { return ( - - {`#${number}`} + + {size === 'mini' && } {size === 'full' && ( - - - + <> + + + )} ); @@ -689,15 +685,13 @@ const QueueItemCard = memo( onDoubleClick={onDoubleClick} > - {`#${number}`} - {size === 'full' && } + {size === 'mini' && } + {size === 'full' && ( + <> + + + + )} ); } @@ -712,14 +706,19 @@ const getMessage = (data: S['InvocationProgressEvent']) => { return message; }; -const ProgressMessage = memo(({ session_id }: { session_id: string }) => { +const ItemNumber = memo(({ number, ...rest }: { number: number } & TextProps) => { + return {`#${number}`}; +}); +ItemNumber.displayName = 'ItemNumber'; + +const ProgressMessage = memo(({ session_id, ...rest }: { session_id: string } & TextProps) => { const { $progressData } = useStagingContext(); const { progressEvent } = useProgressData($progressData, session_id); if (!progressEvent) { return null; } return ( - + {getMessage(progressEvent)} ); @@ -755,7 +754,14 @@ const InProgressContent = memo(({ item }: { item: S['SessionQueueItem'] }) => { if (progressImage) { return ( <> - + ); @@ -773,11 +779,7 @@ const InProgressContent = memo(({ item }: { item: S['SessionQueueItem'] }) => { } if (item.status === 'completed') { - return ( - - Unable to get image - - ); + return ; } assert>(false); }); @@ -809,7 +811,7 @@ const ProgressCircle = memo(({ data }: { data?: S['InvocationProgressEvent'] | n }); ProgressCircle.displayName = 'ProgressCircle'; -const ImageActions = memo(({ imageDTO }: { imageDTO: ImageDTO }) => { +const ImageActions = memo(({ imageDTO, ...rest }: { imageDTO: ImageDTO } & ButtonGroupProps) => { const { getState, dispatch } = useAppStore(); const vary = useCallback(() => { @@ -842,7 +844,7 @@ const ImageActions = memo(({ imageDTO }: { imageDTO: ImageDTO }) => { }); }, [dispatch, getState, imageDTO]); return ( - +