feat(ui): show last progress message & placeholder in generation progress panel

This commit is contained in:
psychedelicious
2025-06-23 12:21:21 +10:00
parent aa2fc1f3f9
commit bed7a03f14
6 changed files with 68 additions and 15 deletions

View File

@@ -1,19 +1,14 @@
import { isImageField } from 'features/nodes/types/common';
import { isCanvasOutputNodeId } from 'features/nodes/util/graph/graphBuilderUtils';
import { round } from 'lodash-es';
import type { S } from 'services/api/types';
import { formatProgressMessage } from 'services/events/stores';
import { objectEntries } from 'tsafe';
export const getProgressMessage = (data?: S['InvocationProgressEvent'] | null) => {
if (!data) {
return 'Generating';
}
let message = data.message;
if (data.percentage) {
message += ` (${round(data.percentage * 100)}%)`;
}
return message;
return formatProgressMessage(data);
};
export const DROP_SHADOW = 'drop-shadow(0px 0px 4px rgb(0, 0, 0)) drop-shadow(0px 0px 4px rgba(0, 0, 0, 0.3))';

View File

@@ -2,9 +2,12 @@ import { Flex } from '@invoke-ai/ui-library';
import { ProgressImage } from 'features/gallery/components/ImageViewer/ProgressImage';
import { memo } from 'react';
import { ProgressIndicator } from './ProgressIndicator';
export const GenerationProgressPanel = memo(() => (
<Flex flexDir="column" w="full" h="full" overflow="hidden" p={2}>
<Flex position="relative" flexDir="column" w="full" h="full" overflow="hidden" p={2}>
<ProgressImage />
<ProgressIndicator position="absolute" top={6} right={6} size={8} />
</Flex>
));
GenerationProgressPanel.displayName = 'GenerationProgressPanel';

View File

@@ -1,5 +1,5 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Flex, Image } from '@invoke-ai/ui-library';
import { Flex, Heading, Image } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
@@ -7,6 +7,7 @@ import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { selectSystemSlice } from 'features/system/store/systemSlice';
import { memo, useMemo } from 'react';
import { PiPulseBold } from 'react-icons/pi';
import { useIsGenerationInProgress } from 'services/api/endpoints/queue';
import { $lastProgressImage } from 'services/events/stores';
const selectShouldAntialiasProgressImage = createSelector(
@@ -15,6 +16,7 @@ const selectShouldAntialiasProgressImage = createSelector(
);
export const ProgressImage = memo(() => {
const isGenerationInProgress = useIsGenerationInProgress();
const progressImage = useStore($lastProgressImage);
const shouldAntialiasProgressImage = useAppSelector(selectShouldAntialiasProgressImage);
@@ -25,7 +27,7 @@ export const ProgressImage = memo(() => {
[shouldAntialiasProgressImage]
);
if (!progressImage) {
if (!isGenerationInProgress) {
return (
<Flex width="full" height="full" alignItems="center" justifyContent="center">
<IAINoContentFallback icon={PiPulseBold} label="No Generation in Progress" />
@@ -33,6 +35,14 @@ export const ProgressImage = memo(() => {
);
}
if (!progressImage) {
return (
<Flex width="full" height="full" alignItems="center" justifyContent="center" minW={0} minH={0}>
<Heading>Waiting for Image</Heading>
</Flex>
);
}
return (
<Flex width="full" height="full" alignItems="center" justifyContent="center" minW={0} minH={0}>
<Image

View File

@@ -0,0 +1,38 @@
import type { CircularProgressProps, SystemStyleObject } from '@invoke-ai/ui-library';
import { CircularProgress, Tooltip } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { memo } from 'react';
import { useIsGenerationInProgress } from 'services/api/endpoints/queue';
import { $lastProgressEvent, formatProgressMessage } from 'services/events/stores';
const circleStyles: SystemStyleObject = {
circle: {
transitionProperty: 'none',
transitionDuration: '0s',
},
};
export const ProgressIndicator = memo((props: CircularProgressProps) => {
const isGenerationInProgress = useIsGenerationInProgress();
const lastProgressEvent = useStore($lastProgressEvent);
if (!isGenerationInProgress) {
return null;
}
if (!lastProgressEvent) {
return null;
}
return (
<Tooltip label={formatProgressMessage(lastProgressEvent)}>
<CircularProgress
size="14px"
color="invokeBlue.500"
thickness={14}
isIndeterminate={!lastProgressEvent || lastProgressEvent.percentage === null}
value={lastProgressEvent?.percentage ? lastProgressEvent.percentage * 100 : undefined}
sx={circleStyles}
{...props}
/>
</Tooltip>
);
});
ProgressIndicator.displayName = 'ProgressMessage';

View File

@@ -396,3 +396,8 @@ export const selectCanvasQueueCounts = queueApi.endpoints.getQueueCountsByDestin
export const enqueueMutationFixedCacheKeyOptions = {
fixedCacheKey: 'enqueueBatch',
} as const;
export const useIsGenerationInProgress = () => {
const { data } = useGetQueueStatusQuery();
return data && data.queue.in_progress > 0;
};

View File

@@ -21,10 +21,12 @@ export const $lastProgressMessage = computed($lastProgressEvent, (val) => {
if (!val) {
return null;
}
let message = val.message;
if (val.percentage) {
message += ` (${round(val.percentage * 100)}%)`;
return formatProgressMessage(val);
});
export const formatProgressMessage = (data: S['InvocationProgressEvent']): string => {
let message = data.message;
if (data.percentage) {
message += ` (${round(data.percentage * 100)}%)`;
}
return message;
});
};