From 358116bc225e6f886c29c69da63517a1ffa48f8f Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Tue, 26 Sep 2023 10:21:11 +1000 Subject: [PATCH] feat(ui): use spinner for queue loading state Skeletons are for when we know the number of specific content items that are loading. When the queue is loading, we don't know how many items there are, or how many will load, so the whole list should be replaced with loading state. The previous behaviour rendered a static number of skeletons. That number would rarely be the right number - the app shouldn't say "I'm loading 7 queue items", then load none, or load 50. A future enhancement could use the queue item skeleton component and go by the total number of queue items, as reported by the queue status. I tried this but had some layout jankiness, not worth the effort right now. The queue item skeleton component's styling was updated to support this future enhancement, making it exactly the same size as a queue item (it was a bit smaller before). --- invokeai/frontend/web/public/locales/en.json | 2 +- .../common/components/IAIImageFallback.tsx | 35 ++++++++ .../QueueList/QueueItemSkeleton.tsx | 41 ++++------ .../queue/components/QueueList/QueueList.tsx | 80 ++++++++----------- 4 files changed, 85 insertions(+), 73 deletions(-) diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index a28ef8d490..285da58e3c 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -79,7 +79,7 @@ "lightMode": "Light Mode", "linear": "Linear", "load": "Load", - "loading": "Loading", + "loading": "Loading $t({{noun}})...", "loadingInvokeAI": "Loading Invoke AI", "learnMore": "Learn More", "modelManager": "Model Manager", diff --git a/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx b/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx index ca61ea847f..3c1a05d527 100644 --- a/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx +++ b/invokeai/frontend/web/src/common/components/IAIImageFallback.tsx @@ -81,3 +81,38 @@ export const IAINoContentFallback = (props: IAINoImageFallbackProps) => { ); }; + +type IAINoImageFallbackWithSpinnerProps = FlexProps & { + label?: string; +}; + +export const IAINoContentFallbackWithSpinner = ( + props: IAINoImageFallbackWithSpinnerProps +) => { + const { sx, ...rest } = props; + + return ( + + + {props.label && {props.label}} + + ); +}; diff --git a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemSkeleton.tsx b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemSkeleton.tsx index 72a5fcdc96..529c46af74 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemSkeleton.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueItemSkeleton.tsx @@ -1,46 +1,37 @@ -import { Flex, Skeleton, Text } from '@chakra-ui/react'; +import { Flex, Skeleton } from '@chakra-ui/react'; import { memo } from 'react'; import { COLUMN_WIDTHS } from './constants'; const QueueItemSkeleton = () => { return ( - + - -   + +   - - -   + + +   - - -   + + +   - - -   + + +   - - -   + + +   diff --git a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueList.tsx b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueList.tsx index 19c61b4379..e136e6df6c 100644 --- a/invokeai/frontend/web/src/features/queue/components/QueueList/QueueList.tsx +++ b/invokeai/frontend/web/src/features/queue/components/QueueList/QueueList.tsx @@ -3,6 +3,7 @@ import { createSelector } from '@reduxjs/toolkit'; import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; +import { IAINoContentFallbackWithSpinner } from 'common/components/IAIImageFallback'; import { listCursorChanged, listPriorityChanged, @@ -23,7 +24,6 @@ import QueueItemComponent from './QueueItemComponent'; import QueueListComponent from './QueueListComponent'; import QueueListHeader from './QueueListHeader'; import { ListContext } from './types'; -import QueueItemSkeleton from './QueueItemSkeleton'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type TableVirtuosoScrollerRef = (ref: HTMLElement | Window | null) => any; @@ -126,54 +126,40 @@ const QueueList = () => { [openQueueItems, toggleQueueItem] ); + if (isLoading) { + return ; + } + + if (!queueItems.length) { + return ( + + + {t('queue.queueEmpty')} + + + ); + } + return ( - {isLoading ? ( - <> - - - - - - - - - - - - - ) : ( - <> - {queueItems.length ? ( - <> - - - - data={queueItems} - endReached={handleLoadMore} - scrollerRef={setScroller as TableVirtuosoScrollerRef} - itemContent={itemContent} - computeItemKey={computeItemKey} - components={components} - context={context} - /> - - - ) : ( - - - {t('queue.queueEmpty')} - - - )} - - )} + + + + data={queueItems} + endReached={handleLoadMore} + scrollerRef={setScroller as TableVirtuosoScrollerRef} + itemContent={itemContent} + computeItemKey={computeItemKey} + components={components} + context={context} + /> + ); };