mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
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).
This commit is contained in:
parent
1e3590111d
commit
358116bc22
@ -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",
|
||||
|
@ -81,3 +81,38 @@ export const IAINoContentFallback = (props: IAINoImageFallbackProps) => {
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
type IAINoImageFallbackWithSpinnerProps = FlexProps & {
|
||||
label?: string;
|
||||
};
|
||||
|
||||
export const IAINoContentFallbackWithSpinner = (
|
||||
props: IAINoImageFallbackWithSpinnerProps
|
||||
) => {
|
||||
const { sx, ...rest } = props;
|
||||
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 'base',
|
||||
flexDir: 'column',
|
||||
gap: 2,
|
||||
userSelect: 'none',
|
||||
opacity: 0.7,
|
||||
color: 'base.700',
|
||||
_dark: {
|
||||
color: 'base.500',
|
||||
},
|
||||
...sx,
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
<Spinner size="xl" />
|
||||
{props.label && <Text textAlign="center">{props.label}</Text>}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -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 (
|
||||
<Flex
|
||||
alignItems="center"
|
||||
gap={4}
|
||||
p={1}
|
||||
pb={2}
|
||||
textTransform="uppercase"
|
||||
fontWeight={700}
|
||||
fontSize="xs"
|
||||
letterSpacing={1}
|
||||
>
|
||||
<Flex alignItems="center" p={1.5} gap={4} minH={9} h="full" w="full">
|
||||
<Flex
|
||||
w={COLUMN_WIDTHS.number}
|
||||
justifyContent="flex-end"
|
||||
alignItems="center"
|
||||
>
|
||||
<Skeleton width="20px">
|
||||
<Text variant="subtext"> </Text>
|
||||
<Skeleton w="full" h="full">
|
||||
|
||||
</Skeleton>
|
||||
</Flex>
|
||||
<Flex ps={0.5} w={COLUMN_WIDTHS.statusBadge} alignItems="center">
|
||||
<Skeleton width="100%">
|
||||
<Text variant="subtext"> </Text>
|
||||
<Flex w={COLUMN_WIDTHS.statusBadge} alignItems="center">
|
||||
<Skeleton w="full" h="full">
|
||||
|
||||
</Skeleton>
|
||||
</Flex>
|
||||
<Flex ps={0.5} w={COLUMN_WIDTHS.time} alignItems="center">
|
||||
<Skeleton width="100%">
|
||||
<Text variant="subtext"> </Text>
|
||||
<Flex w={COLUMN_WIDTHS.time} alignItems="center">
|
||||
<Skeleton w="full" h="full">
|
||||
|
||||
</Skeleton>
|
||||
</Flex>
|
||||
<Flex ps={0.5} w={COLUMN_WIDTHS.batchId} alignItems="center">
|
||||
<Skeleton width="100%">
|
||||
<Text variant="subtext"> </Text>
|
||||
<Flex w={COLUMN_WIDTHS.batchId} alignItems="center">
|
||||
<Skeleton w="full" h="full">
|
||||
|
||||
</Skeleton>
|
||||
</Flex>
|
||||
<Flex ps={0.5} w={COLUMN_WIDTHS.fieldValues} alignItems="center" flex="1">
|
||||
<Skeleton width="100%">
|
||||
<Text variant="subtext"> </Text>
|
||||
<Flex w={COLUMN_WIDTHS.fieldValues} alignItems="center" flexGrow={1}>
|
||||
<Skeleton w="full" h="full">
|
||||
|
||||
</Skeleton>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
@ -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 <IAINoContentFallbackWithSpinner />;
|
||||
}
|
||||
|
||||
if (!queueItems.length) {
|
||||
return (
|
||||
<Flex w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Heading color="base.400" _dark={{ color: 'base.500' }}>
|
||||
{t('queue.queueEmpty')}
|
||||
</Heading>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex w="full" h="full" flexDir="column">
|
||||
{isLoading ? (
|
||||
<>
|
||||
<QueueListHeader />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
<QueueItemSkeleton />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{queueItems.length ? (
|
||||
<>
|
||||
<QueueListHeader />
|
||||
<Flex
|
||||
ref={rootRef}
|
||||
w="full"
|
||||
h="full"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<Virtuoso<SessionQueueItemDTO, ListContext>
|
||||
data={queueItems}
|
||||
endReached={handleLoadMore}
|
||||
scrollerRef={setScroller as TableVirtuosoScrollerRef}
|
||||
itemContent={itemContent}
|
||||
computeItemKey={computeItemKey}
|
||||
components={components}
|
||||
context={context}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
) : (
|
||||
<Flex w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<Heading color="base.400" _dark={{ color: 'base.500' }}>
|
||||
{t('queue.queueEmpty')}
|
||||
</Heading>
|
||||
</Flex>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<QueueListHeader />
|
||||
<Flex
|
||||
ref={rootRef}
|
||||
w="full"
|
||||
h="full"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<Virtuoso<SessionQueueItemDTO, ListContext>
|
||||
data={queueItems}
|
||||
endReached={handleLoadMore}
|
||||
scrollerRef={setScroller as TableVirtuosoScrollerRef}
|
||||
itemContent={itemContent}
|
||||
computeItemKey={computeItemKey}
|
||||
components={components}
|
||||
context={context}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user