feat(ui): progress images in gallery and viewer

This commit is contained in:
psychedelicious 2023-05-10 13:58:34 +10:00
parent e94d0b2d40
commit fdc2232ea0
17 changed files with 309 additions and 96 deletions

View File

@ -531,7 +531,7 @@
"useCanvasBeta": "Use Canvas Beta Layout", "useCanvasBeta": "Use Canvas Beta Layout",
"enableImageDebugging": "Enable Image Debugging", "enableImageDebugging": "Enable Image Debugging",
"useSlidersForAll": "Use Sliders For All Options", "useSlidersForAll": "Use Sliders For All Options",
"autoShowProgress": "Auto Show Progress Images", "showProgressInViewer": "Show Progress Images in Viewer",
"resetWebUI": "Reset Web UI", "resetWebUI": "Reset Web UI",
"resetWebUIDesc1": "Resetting the web UI only resets the browser's local cache of your images and remembered settings. It does not delete any images from disk.", "resetWebUIDesc1": "Resetting the web UI only resets the browser's local cache of your images and remembered settings. It does not delete any images from disk.",
"resetWebUIDesc2": "If images aren't showing up in the gallery or something else isn't working, please try resetting before submitting an issue on GitHub.", "resetWebUIDesc2": "If images aren't showing up in the gallery or something else isn't working, please try resetting before submitting an issue on GitHub.",

View File

@ -27,7 +27,7 @@ import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
import { configChanged } from 'features/system/store/configSlice'; import { configChanged } from 'features/system/store/configSlice';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { useLogger } from 'app/logging/useLogger'; import { useLogger } from 'app/logging/useLogger';
import ProgressImagePreview from 'features/parameters/components/ProgressImagePreview'; import ProgressImagePreview from 'features/parameters/components/_ProgressImagePreview';
import ParametersDrawer from 'features/ui/components/ParametersDrawer'; import ParametersDrawer from 'features/ui/components/ParametersDrawer';
const DEFAULT_CONFIG = {}; const DEFAULT_CONFIG = {};
@ -124,7 +124,6 @@ const App = ({ config = DEFAULT_CONFIG, children }: Props) => {
<Portal> <Portal>
<FloatingGalleryButton /> <FloatingGalleryButton />
</Portal> </Portal>
<ProgressImagePreview />
</Grid> </Grid>
); );
}; };

View File

@ -10,6 +10,7 @@ export const actionSanitizer = <A extends AnyAction>(action: A): A => {
// Sanitize nodes as needed // Sanitize nodes as needed
forEach(action.payload.nodes, (node, key) => { forEach(action.payload.nodes, (node, key) => {
// Don't log the whole freaking dataURL
if (node.type === 'dataURL_image') { if (node.type === 'dataURL_image') {
const { dataURL, ...rest } = node; const { dataURL, ...rest } = node;
sanitizedNodes[key] = { ...rest, dataURL: '<dataURL>' }; sanitizedNodes[key] = { ...rest, dataURL: '<dataURL>' };

View File

@ -27,7 +27,7 @@ const IAIPopover = (props: IAIPopoverProps) => {
return ( return (
<Popover isLazy={isLazy} {...rest}> <Popover isLazy={isLazy} {...rest}>
<PopoverTrigger>{triggerComponent}</PopoverTrigger> <PopoverTrigger>{triggerComponent}</PopoverTrigger>
<PopoverContent> <PopoverContent shadow="dark-lg">
{hasArrow && <PopoverArrow />} {hasArrow && <PopoverArrow />}
{children} {children}
</PopoverContent> </PopoverContent>

View File

@ -5,7 +5,13 @@ import {
ButtonGroup, ButtonGroup,
Flex, Flex,
FlexProps, FlexProps,
IconButton,
Link, Link,
Menu,
MenuButton,
MenuItemOption,
MenuList,
MenuOptionGroup,
useDisclosure, useDisclosure,
useToast, useToast,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@ -46,6 +52,7 @@ import {
FaShare, FaShare,
FaShareAlt, FaShareAlt,
FaTrash, FaTrash,
FaWrench,
} from 'react-icons/fa'; } from 'react-icons/fa';
import { import {
gallerySelector, gallerySelector,
@ -62,6 +69,7 @@ import { requestedImageDeletion } from '../store/actions';
import FaceRestoreSettings from 'features/parameters/components/Parameters/FaceRestore/FaceRestoreSettings'; import FaceRestoreSettings from 'features/parameters/components/Parameters/FaceRestore/FaceRestoreSettings';
import UpscaleSettings from 'features/parameters/components/Parameters/Upscale/UpscaleSettings'; import UpscaleSettings from 'features/parameters/components/Parameters/Upscale/UpscaleSettings';
import { allParametersSet } from 'features/parameters/store/generationSlice'; import { allParametersSet } from 'features/parameters/store/generationSlice';
import DeleteImageButton from './ImageActionButtons/DeleteImageButton';
const currentImageButtonsSelector = createSelector( const currentImageButtonsSelector = createSelector(
[ [
@ -451,7 +459,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
</Link> </Link>
</Flex> </Flex>
</IAIPopover> </IAIPopover>
<IAIIconButton {/* <IAIIconButton
icon={shouldHidePreview ? <FaEyeSlash /> : <FaEye />} icon={shouldHidePreview ? <FaEyeSlash /> : <FaEye />}
tooltip={ tooltip={
!shouldHidePreview !shouldHidePreview
@ -465,7 +473,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
} }
isChecked={shouldHidePreview} isChecked={shouldHidePreview}
onClick={handlePreviewVisibility} onClick={handlePreviewVisibility}
/> /> */}
{isLightboxEnabled && ( {isLightboxEnabled && (
<IAIIconButton <IAIIconButton
icon={<FaExpand />} icon={<FaExpand />}
@ -592,23 +600,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
</ButtonGroup> </ButtonGroup>
<ButtonGroup isAttached={true}> <ButtonGroup isAttached={true}>
<IAIIconButton <DeleteImageButton image={image} />
onClick={handleInitiateDelete}
icon={<FaTrash />}
tooltip={`${t('gallery.deleteImage')} (Del)`}
aria-label={`${t('gallery.deleteImage')} (Del)`}
isDisabled={!image || !isConnected}
colorScheme="error"
/>
</ButtonGroup> </ButtonGroup>
</Flex> </Flex>
{image && (
<DeleteImageModal
isOpen={isDeleteDialogOpen}
onClose={onDeleteDialogClose}
handleDelete={handleDelete}
/>
)}
</> </>
); );
}; };

View File

@ -1,4 +1,4 @@
import { Box, Flex, Image } from '@chakra-ui/react'; import { Box, Flex, Image, Skeleton, useBoolean } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { useGetUrl } from 'common/util/getUrl'; import { useGetUrl } from 'common/util/getUrl';
@ -10,16 +10,25 @@ import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer';
import NextPrevImageButtons from './NextPrevImageButtons'; import NextPrevImageButtons from './NextPrevImageButtons';
import CurrentImageHidden from './CurrentImageHidden'; import CurrentImageHidden from './CurrentImageHidden';
import { DragEvent, memo, useCallback } from 'react'; import { DragEvent, memo, useCallback } from 'react';
import { systemSelector } from 'features/system/store/systemSelectors';
import CurrentImageFallback from './CurrentImageFallback';
export const imagesSelector = createSelector( export const imagesSelector = createSelector(
[uiSelector, gallerySelector], [uiSelector, gallerySelector, systemSelector],
(ui, gallery) => { (ui, gallery, system) => {
const { shouldShowImageDetails, shouldHidePreview } = ui; const {
shouldShowImageDetails,
shouldHidePreview,
shouldShowProgressInViewer,
} = ui;
const { selectedImage } = gallery; const { selectedImage } = gallery;
const { progressImage } = system;
return { return {
shouldShowImageDetails, shouldShowImageDetails,
shouldHidePreview, shouldHidePreview,
image: selectedImage, image: selectedImage,
progressImage,
shouldShowProgressInViewer,
}; };
}, },
{ {
@ -30,10 +39,17 @@ export const imagesSelector = createSelector(
); );
const CurrentImagePreview = () => { const CurrentImagePreview = () => {
const { shouldShowImageDetails, image, shouldHidePreview } = const {
useAppSelector(imagesSelector); shouldShowImageDetails,
image,
shouldHidePreview,
progressImage,
shouldShowProgressInViewer,
} = useAppSelector(imagesSelector);
const { getUrl } = useGetUrl(); const { getUrl } = useGetUrl();
const [isLoaded, { on, off }] = useBoolean();
const handleDragStart = useCallback( const handleDragStart = useCallback(
(e: DragEvent<HTMLDivElement>) => { (e: DragEvent<HTMLDivElement>) => {
if (!image) { if (!image) {
@ -56,13 +72,11 @@ const CurrentImagePreview = () => {
height: '100%', height: '100%',
}} }}
> >
{image && ( {progressImage && shouldShowProgressInViewer ? (
<Image <Image
onDragStart={handleDragStart} src={progressImage.dataURL}
src={shouldHidePreview ? undefined : getUrl(image.url)} width={progressImage.width}
width={image.metadata.width || 'auto'} height={progressImage.height}
height={image.metadata.height || 'auto'}
fallback={shouldHidePreview ? <CurrentImageHidden /> : undefined}
sx={{ sx={{
objectFit: 'contain', objectFit: 'contain',
maxWidth: '100%', maxWidth: '100%',
@ -72,6 +86,31 @@ const CurrentImagePreview = () => {
borderRadius: 'base', borderRadius: 'base',
}} }}
/> />
) : (
image && (
<Image
onDragStart={handleDragStart}
fallbackStrategy="beforeLoadOrError"
src={shouldHidePreview ? undefined : getUrl(image.url)}
width={image.metadata.width || 'auto'}
height={image.metadata.height || 'auto'}
fallback={
shouldHidePreview ? (
<CurrentImageHidden />
) : (
<CurrentImageFallback />
)
}
sx={{
objectFit: 'contain',
maxWidth: '100%',
maxHeight: '100%',
height: 'auto',
position: 'absolute',
borderRadius: 'base',
}}
/>
)
)} )}
{shouldShowImageDetails && image && 'metadata' in image && ( {shouldShowImageDetails && image && 'metadata' in image && (
<Box <Box

View File

@ -0,0 +1,62 @@
import { Box, Flex, Image } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { systemSelector } from 'features/system/store/systemSelectors';
import { memo } from 'react';
import { gallerySelector } from '../store/gallerySelectors';
const selector = createSelector(
[systemSelector, gallerySelector],
(system, gallery) => {
const { shouldUseSingleGalleryColumn, galleryImageObjectFit } = gallery;
const { progressImage } = system;
return {
progressImage,
shouldUseSingleGalleryColumn,
galleryImageObjectFit,
};
},
defaultSelectorOptions
);
const GalleryProgressImage = () => {
const { progressImage, shouldUseSingleGalleryColumn, galleryImageObjectFit } =
useAppSelector(selector);
if (!progressImage) {
return null;
}
return (
<Flex
sx={{
w: 'full',
h: 'full',
alignItems: 'center',
justifyContent: 'center',
aspectRatio: '1/1',
}}
>
<Image
draggable={false}
src={progressImage.dataURL}
width={progressImage.width}
height={progressImage.height}
sx={{
objectFit: shouldUseSingleGalleryColumn
? 'contain'
: galleryImageObjectFit,
width: '100%',
height: '100%',
maxWidth: '100%',
maxHeight: '100%',
borderRadius: 'base',
}}
/>
</Flex>
);
};
export default memo(GalleryProgressImage);

View File

@ -0,0 +1,92 @@
import { createSelector } from '@reduxjs/toolkit';
import { useDisclosure } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton';
import { systemSelector } from 'features/system/store/systemSelectors';
import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next';
import { FaTrash } from 'react-icons/fa';
import { memo, useCallback } from 'react';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import DeleteImageModal from '../DeleteImageModal';
import { requestedImageDeletion } from 'features/gallery/store/actions';
import { Image } from 'app/types/invokeai';
const selector = createSelector(
[systemSelector],
(system) => {
const { isProcessing, isConnected, shouldConfirmOnDelete } = system;
return {
canDeleteImage: isConnected && !isProcessing,
shouldConfirmOnDelete,
isProcessing,
isConnected,
};
},
defaultSelectorOptions
);
type DeleteImageButtonProps = {
image: Image | undefined;
};
const DeleteImageButton = (props: DeleteImageButtonProps) => {
const { image } = props;
const dispatch = useAppDispatch();
const { isProcessing, isConnected, canDeleteImage, shouldConfirmOnDelete } =
useAppSelector(selector);
const {
isOpen: isDeleteDialogOpen,
onOpen: onDeleteDialogOpen,
onClose: onDeleteDialogClose,
} = useDisclosure();
const { t } = useTranslation();
const handleDelete = useCallback(() => {
if (canDeleteImage && image) {
dispatch(requestedImageDeletion(image));
}
}, [image, canDeleteImage, dispatch]);
const handleInitiateDelete = useCallback(() => {
if (shouldConfirmOnDelete) {
onDeleteDialogOpen();
} else {
handleDelete();
}
}, [shouldConfirmOnDelete, onDeleteDialogOpen, handleDelete]);
useHotkeys('delete', handleInitiateDelete, [
image,
shouldConfirmOnDelete,
isConnected,
isProcessing,
]);
return (
<>
<IAIIconButton
onClick={handleInitiateDelete}
icon={<FaTrash />}
tooltip={`${t('gallery.deleteImage')} (Del)`}
aria-label={`${t('gallery.deleteImage')} (Del)`}
isDisabled={!image || !isConnected}
colorScheme="error"
/>
{image && (
<DeleteImageModal
isOpen={isDeleteDialogOpen}
onClose={onDeleteDialogClose}
handleDelete={handleDelete}
/>
)}
</>
);
};
export default memo(DeleteImageButton);

View File

@ -5,6 +5,7 @@ import {
FlexProps, FlexProps,
Grid, Grid,
Icon, Icon,
Image,
Text, Text,
forwardRef, forwardRef,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@ -14,7 +15,10 @@ import IAICheckbox from 'common/components/IAICheckbox';
import IAIIconButton from 'common/components/IAIIconButton'; import IAIIconButton from 'common/components/IAIIconButton';
import IAIPopover from 'common/components/IAIPopover'; import IAIPopover from 'common/components/IAIPopover';
import IAISlider from 'common/components/IAISlider'; import IAISlider from 'common/components/IAISlider';
import { imageGallerySelector } from 'features/gallery/store/gallerySelectors'; import {
gallerySelector,
imageGallerySelector,
} from 'features/gallery/store/gallerySelectors';
import { import {
setCurrentCategory, setCurrentCategory,
setGalleryImageMinimumWidth, setGalleryImageMinimumWidth,
@ -50,30 +54,48 @@ import { uploadsAdapter } from '../store/uploadsSlice';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { Virtuoso, VirtuosoGrid } from 'react-virtuoso'; import { Virtuoso, VirtuosoGrid } from 'react-virtuoso';
import ProgressImagePreview from 'features/parameters/components/_ProgressImagePreview';
import ProgressImage from 'features/parameters/components/ProgressImage';
import { systemSelector } from 'features/system/store/systemSelectors';
import { Image as ImageType } from 'app/types/invokeai';
import { ProgressImage as ProgressImageType } from 'services/events/types';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import GalleryProgressImage from './GalleryProgressImage';
const GALLERY_SHOW_BUTTONS_MIN_WIDTH = 290; const GALLERY_SHOW_BUTTONS_MIN_WIDTH = 290;
const PROGRESS_IMAGE_PLACEHOLDER = 'PROGRESS_IMAGE_PLACEHOLDER';
const gallerySelector = createSelector( const selector = createSelector(
[ [(state: RootState) => state],
(state: RootState) => state.uploads, (state) => {
(state: RootState) => state.results, const { results, uploads, system, gallery } = state;
(state: RootState) => state.gallery,
],
(uploads, results, gallery) => {
const { currentCategory } = gallery; const { currentCategory } = gallery;
return currentCategory === 'results' const tempImages: (ImageType | typeof PROGRESS_IMAGE_PLACEHOLDER)[] = [];
? {
images: resultsAdapter.getSelectors().selectAll(results), if (system.progressImage) {
isLoading: results.isLoading, tempImages.push(PROGRESS_IMAGE_PLACEHOLDER);
areMoreImagesAvailable: results.page < results.pages - 1, }
}
: { if (currentCategory === 'results') {
images: uploadsAdapter.getSelectors().selectAll(uploads), return {
isLoading: uploads.isLoading, images: tempImages.concat(
areMoreImagesAvailable: uploads.page < uploads.pages - 1, resultsAdapter.getSelectors().selectAll(results)
}; ),
} isLoading: results.isLoading,
areMoreImagesAvailable: results.page < results.pages - 1,
};
}
return {
images: tempImages.concat(
uploadsAdapter.getSelectors().selectAll(uploads)
),
isLoading: uploads.isLoading,
areMoreImagesAvailable: uploads.page < uploads.pages - 1,
};
},
defaultSelectorOptions
); );
const ImageGalleryContent = () => { const ImageGalleryContent = () => {
@ -108,7 +130,7 @@ const ImageGalleryContent = () => {
} = useAppSelector(imageGallerySelector); } = useAppSelector(imageGallerySelector);
const { images, areMoreImagesAvailable, isLoading } = const { images, areMoreImagesAvailable, isLoading } =
useAppSelector(gallerySelector); useAppSelector(selector);
const handleClickLoadMore = () => { const handleClickLoadMore = () => {
if (currentCategory === 'results') { if (currentCategory === 'results') {
@ -186,8 +208,6 @@ const ImageGalleryContent = () => {
h: 'full', h: 'full',
w: 'full', w: 'full',
borderRadius: 'base', borderRadius: 'base',
// bg: 'base.850',
// p: 2,
}} }}
> >
<Flex <Flex
@ -311,16 +331,24 @@ const ImageGalleryContent = () => {
endReached={handleEndReached} endReached={handleEndReached}
scrollerRef={(ref) => setScrollerRef(ref)} scrollerRef={(ref) => setScrollerRef(ref)}
itemContent={(index, image) => { itemContent={(index, image) => {
const { name } = image; const isSelected =
const isSelected = selectedImage?.name === name; image === PROGRESS_IMAGE_PLACEHOLDER
? false
: selectedImage?.name === image?.name;
return ( return (
<Flex sx={{ pb: 2 }}> <Flex sx={{ pb: 2 }}>
<HoverableImage {image === PROGRESS_IMAGE_PLACEHOLDER ? (
key={`${name}-${image.thumbnail}`} <GalleryProgressImage
image={image} key={PROGRESS_IMAGE_PLACEHOLDER}
isSelected={isSelected} />
/> ) : (
<HoverableImage
key={`${image.name}-${image.thumbnail}`}
image={image}
isSelected={isSelected}
/>
)}
</Flex> </Flex>
); );
}} }}
@ -336,12 +364,16 @@ const ImageGalleryContent = () => {
}} }}
scrollerRef={setScroller} scrollerRef={setScroller}
itemContent={(index, image) => { itemContent={(index, image) => {
const { name } = image; const isSelected =
const isSelected = selectedImage?.name === name; image === PROGRESS_IMAGE_PLACEHOLDER
? false
: selectedImage?.name === image?.name;
return ( return image === PROGRESS_IMAGE_PLACEHOLDER ? (
<GalleryProgressImage key={PROGRESS_IMAGE_PLACEHOLDER} />
) : (
<HoverableImage <HoverableImage
key={`${name}-${image.thumbnail}`} key={`${image.name}-${image.thumbnail}`}
image={image} image={image}
isSelected={isSelected} isSelected={isSelected}
/> />

View File

@ -28,13 +28,14 @@ export const buildImg2ImgNode = (
img2imgStrength: strength, img2imgStrength: strength,
shouldFitToWidthHeight: fit, shouldFitToWidthHeight: fit,
shouldRandomizeSeed, shouldRandomizeSeed,
initialImage,
} = generation; } = generation;
const initialImage = initialImageSelector(state); // const initialImage = initialImageSelector(state);
if (!initialImage) { if (!initialImage) {
// TODO: handle this // TODO: handle this
// throw 'no initial image'; throw 'no initial image';
} }
const imageToImageNode: ImageToImageInvocation = { const imageToImageNode: ImageToImageInvocation = {
@ -47,12 +48,10 @@ export const buildImg2ImgNode = (
cfg_scale: cfgScale, cfg_scale: cfgScale,
scheduler: sampler as ImageToImageInvocation['scheduler'], scheduler: sampler as ImageToImageInvocation['scheduler'],
model, model,
image: initialImage image: {
? { image_name: initialImage.name,
image_name: initialImage.name, image_type: initialImage.type,
image_type: initialImage.type, },
}
: undefined,
strength, strength,
fit, fit,
}; };

View File

@ -28,7 +28,7 @@ import {
} from 'features/system/store/systemSlice'; } from 'features/system/store/systemSlice';
import { uiSelector } from 'features/ui/store/uiSelectors'; import { uiSelector } from 'features/ui/store/uiSelectors';
import { import {
setShouldAutoShowProgressImages, setShouldShowProgressInViewer,
setShouldUseCanvasBetaLayout, setShouldUseCanvasBetaLayout,
setShouldUseSliders, setShouldUseSliders,
} from 'features/ui/store/uiSlice'; } from 'features/ui/store/uiSlice';
@ -54,7 +54,7 @@ const selector = createSelector(
const { const {
shouldUseCanvasBetaLayout, shouldUseCanvasBetaLayout,
shouldUseSliders, shouldUseSliders,
shouldAutoShowProgressImages, shouldShowProgressInViewer,
} = ui; } = ui;
return { return {
@ -63,7 +63,7 @@ const selector = createSelector(
enableImageDebugging, enableImageDebugging,
shouldUseCanvasBetaLayout, shouldUseCanvasBetaLayout,
shouldUseSliders, shouldUseSliders,
shouldAutoShowProgressImages, shouldShowProgressInViewer,
consoleLogLevel, consoleLogLevel,
shouldLogToConsole, shouldLogToConsole,
}; };
@ -114,7 +114,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
enableImageDebugging, enableImageDebugging,
shouldUseCanvasBetaLayout, shouldUseCanvasBetaLayout,
shouldUseSliders, shouldUseSliders,
shouldAutoShowProgressImages, shouldShowProgressInViewer,
consoleLogLevel, consoleLogLevel,
shouldLogToConsole, shouldLogToConsole,
} = useAppSelector(selector); } = useAppSelector(selector);
@ -197,10 +197,10 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
} }
/> />
<IAISwitch <IAISwitch
label={t('settings.autoShowProgress')} label={t('settings.showProgressInViewer')}
isChecked={shouldAutoShowProgressImages} isChecked={shouldShowProgressInViewer}
onChange={(e: ChangeEvent<HTMLInputElement>) => onChange={(e: ChangeEvent<HTMLInputElement>) =>
dispatch(setShouldAutoShowProgressImages(e.target.checked)) dispatch(setShouldShowProgressInViewer(e.target.checked))
} }
/> />
</Flex> </Flex>

View File

@ -9,6 +9,7 @@ import { AnimatePresence, motion } from 'framer-motion';
import { useMemo, useRef } from 'react'; import { useMemo, useRef } from 'react';
import { FaCircle } from 'react-icons/fa'; import { FaCircle } from 'react-icons/fa';
import { useHoverDirty } from 'react-use'; import { useHoverDirty } from 'react-use';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
const statusIndicatorSelector = createSelector( const statusIndicatorSelector = createSelector(
systemSelector, systemSelector,
@ -31,9 +32,7 @@ const statusIndicatorSelector = createSelector(
currentStatusHasSteps, currentStatusHasSteps,
}; };
}, },
{ defaultSelectorOptions
memoizeOptions: { resultEqualityCheck: isEqual },
}
); );
const StatusIndicator = () => { const StatusIndicator = () => {

View File

@ -354,6 +354,7 @@ export const systemSlice = createSlice({
state.currentStep = 0; state.currentStep = 0;
state.totalSteps = 0; state.totalSteps = 0;
state.statusTranslationKey = 'common.statusProcessingComplete'; state.statusTranslationKey = 'common.statusProcessingComplete';
state.progressImage = null;
if (state.canceledSession === data.graph_execution_state_id) { if (state.canceledSession === data.graph_execution_state_id) {
state.isProcessing = false; state.isProcessing = false;
@ -373,6 +374,7 @@ export const systemSlice = createSlice({
state.currentStep = 0; state.currentStep = 0;
state.totalSteps = 0; state.totalSteps = 0;
state.statusTranslationKey = 'common.statusError'; state.statusTranslationKey = 'common.statusError';
state.progressImage = null;
state.toastQueue.push( state.toastQueue.push(
makeToast({ title: t('toast.serverError'), status: 'error' }) makeToast({ title: t('toast.serverError'), status: 'error' })

View File

@ -23,7 +23,7 @@ export const initialUIState: UIState = {
canvasTabAccordionState: [], canvasTabAccordionState: [],
floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 }, floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 },
shouldShowProgressImages: false, shouldShowProgressImages: false,
shouldAutoShowProgressImages: false, shouldShowProgressInViewer: false,
shouldShowImageParameters: false, shouldShowImageParameters: false,
}; };
@ -135,11 +135,8 @@ export const uiSlice = createSlice({
setShouldShowProgressImages: (state, action: PayloadAction<boolean>) => { setShouldShowProgressImages: (state, action: PayloadAction<boolean>) => {
state.shouldShowProgressImages = action.payload; state.shouldShowProgressImages = action.payload;
}, },
setShouldAutoShowProgressImages: ( setShouldShowProgressInViewer: (state, action: PayloadAction<boolean>) => {
state, state.shouldShowProgressInViewer = action.payload;
action: PayloadAction<boolean>
) => {
state.shouldAutoShowProgressImages = action.payload;
}, },
shouldShowImageParametersChanged: ( shouldShowImageParametersChanged: (
state, state,
@ -173,7 +170,7 @@ export const {
floatingProgressImageMoved, floatingProgressImageMoved,
floatingProgressImageResized, floatingProgressImageResized,
setShouldShowProgressImages, setShouldShowProgressImages,
setShouldAutoShowProgressImages, setShouldShowProgressInViewer,
shouldShowImageParametersChanged, shouldShowImageParametersChanged,
} = uiSlice.actions; } = uiSlice.actions;

View File

@ -31,6 +31,6 @@ export interface UIState {
canvasTabAccordionState: number[]; canvasTabAccordionState: number[];
floatingProgressImageRect: Rect; floatingProgressImageRect: Rect;
shouldShowProgressImages: boolean; shouldShowProgressImages: boolean;
shouldAutoShowProgressImages: boolean; shouldShowProgressInViewer: boolean;
shouldShowImageParameters: boolean; shouldShowImageParameters: boolean;
} }

View File

@ -20,9 +20,6 @@ const invokeAIContent = defineStyle((_props) => {
minW: 'unset', minW: 'unset',
width: 'unset', width: 'unset',
p: 4, p: 4,
borderWidth: '2px',
borderStyle: 'solid',
borderColor: 'base.600',
bg: 'base.800', bg: 'base.800',
}; };
}); });