mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): progress images in gallery and viewer
This commit is contained in:
parent
e94d0b2d40
commit
fdc2232ea0
@ -531,7 +531,7 @@
|
||||
"useCanvasBeta": "Use Canvas Beta Layout",
|
||||
"enableImageDebugging": "Enable Image Debugging",
|
||||
"useSlidersForAll": "Use Sliders For All Options",
|
||||
"autoShowProgress": "Auto Show Progress Images",
|
||||
"showProgressInViewer": "Show Progress Images in Viewer",
|
||||
"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.",
|
||||
"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.",
|
||||
|
@ -27,7 +27,7 @@ import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
|
||||
import { configChanged } from 'features/system/store/configSlice';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
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';
|
||||
|
||||
const DEFAULT_CONFIG = {};
|
||||
@ -124,7 +124,6 @@ const App = ({ config = DEFAULT_CONFIG, children }: Props) => {
|
||||
<Portal>
|
||||
<FloatingGalleryButton />
|
||||
</Portal>
|
||||
<ProgressImagePreview />
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
@ -10,6 +10,7 @@ export const actionSanitizer = <A extends AnyAction>(action: A): A => {
|
||||
|
||||
// Sanitize nodes as needed
|
||||
forEach(action.payload.nodes, (node, key) => {
|
||||
// Don't log the whole freaking dataURL
|
||||
if (node.type === 'dataURL_image') {
|
||||
const { dataURL, ...rest } = node;
|
||||
sanitizedNodes[key] = { ...rest, dataURL: '<dataURL>' };
|
||||
|
@ -27,7 +27,7 @@ const IAIPopover = (props: IAIPopoverProps) => {
|
||||
return (
|
||||
<Popover isLazy={isLazy} {...rest}>
|
||||
<PopoverTrigger>{triggerComponent}</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<PopoverContent shadow="dark-lg">
|
||||
{hasArrow && <PopoverArrow />}
|
||||
{children}
|
||||
</PopoverContent>
|
||||
|
@ -5,7 +5,13 @@ import {
|
||||
ButtonGroup,
|
||||
Flex,
|
||||
FlexProps,
|
||||
IconButton,
|
||||
Link,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItemOption,
|
||||
MenuList,
|
||||
MenuOptionGroup,
|
||||
useDisclosure,
|
||||
useToast,
|
||||
} from '@chakra-ui/react';
|
||||
@ -46,6 +52,7 @@ import {
|
||||
FaShare,
|
||||
FaShareAlt,
|
||||
FaTrash,
|
||||
FaWrench,
|
||||
} from 'react-icons/fa';
|
||||
import {
|
||||
gallerySelector,
|
||||
@ -62,6 +69,7 @@ import { requestedImageDeletion } from '../store/actions';
|
||||
import FaceRestoreSettings from 'features/parameters/components/Parameters/FaceRestore/FaceRestoreSettings';
|
||||
import UpscaleSettings from 'features/parameters/components/Parameters/Upscale/UpscaleSettings';
|
||||
import { allParametersSet } from 'features/parameters/store/generationSlice';
|
||||
import DeleteImageButton from './ImageActionButtons/DeleteImageButton';
|
||||
|
||||
const currentImageButtonsSelector = createSelector(
|
||||
[
|
||||
@ -451,7 +459,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
||||
</Link>
|
||||
</Flex>
|
||||
</IAIPopover>
|
||||
<IAIIconButton
|
||||
{/* <IAIIconButton
|
||||
icon={shouldHidePreview ? <FaEyeSlash /> : <FaEye />}
|
||||
tooltip={
|
||||
!shouldHidePreview
|
||||
@ -465,7 +473,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
||||
}
|
||||
isChecked={shouldHidePreview}
|
||||
onClick={handlePreviewVisibility}
|
||||
/>
|
||||
/> */}
|
||||
{isLightboxEnabled && (
|
||||
<IAIIconButton
|
||||
icon={<FaExpand />}
|
||||
@ -592,23 +600,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
||||
</ButtonGroup>
|
||||
|
||||
<ButtonGroup isAttached={true}>
|
||||
<IAIIconButton
|
||||
onClick={handleInitiateDelete}
|
||||
icon={<FaTrash />}
|
||||
tooltip={`${t('gallery.deleteImage')} (Del)`}
|
||||
aria-label={`${t('gallery.deleteImage')} (Del)`}
|
||||
isDisabled={!image || !isConnected}
|
||||
colorScheme="error"
|
||||
/>
|
||||
<DeleteImageButton image={image} />
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
{image && (
|
||||
<DeleteImageModal
|
||||
isOpen={isDeleteDialogOpen}
|
||||
onClose={onDeleteDialogClose}
|
||||
handleDelete={handleDelete}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -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 { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useGetUrl } from 'common/util/getUrl';
|
||||
@ -10,16 +10,25 @@ import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer';
|
||||
import NextPrevImageButtons from './NextPrevImageButtons';
|
||||
import CurrentImageHidden from './CurrentImageHidden';
|
||||
import { DragEvent, memo, useCallback } from 'react';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import CurrentImageFallback from './CurrentImageFallback';
|
||||
|
||||
export const imagesSelector = createSelector(
|
||||
[uiSelector, gallerySelector],
|
||||
(ui, gallery) => {
|
||||
const { shouldShowImageDetails, shouldHidePreview } = ui;
|
||||
[uiSelector, gallerySelector, systemSelector],
|
||||
(ui, gallery, system) => {
|
||||
const {
|
||||
shouldShowImageDetails,
|
||||
shouldHidePreview,
|
||||
shouldShowProgressInViewer,
|
||||
} = ui;
|
||||
const { selectedImage } = gallery;
|
||||
const { progressImage } = system;
|
||||
return {
|
||||
shouldShowImageDetails,
|
||||
shouldHidePreview,
|
||||
image: selectedImage,
|
||||
progressImage,
|
||||
shouldShowProgressInViewer,
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -30,10 +39,17 @@ export const imagesSelector = createSelector(
|
||||
);
|
||||
|
||||
const CurrentImagePreview = () => {
|
||||
const { shouldShowImageDetails, image, shouldHidePreview } =
|
||||
useAppSelector(imagesSelector);
|
||||
const {
|
||||
shouldShowImageDetails,
|
||||
image,
|
||||
shouldHidePreview,
|
||||
progressImage,
|
||||
shouldShowProgressInViewer,
|
||||
} = useAppSelector(imagesSelector);
|
||||
const { getUrl } = useGetUrl();
|
||||
|
||||
const [isLoaded, { on, off }] = useBoolean();
|
||||
|
||||
const handleDragStart = useCallback(
|
||||
(e: DragEvent<HTMLDivElement>) => {
|
||||
if (!image) {
|
||||
@ -56,13 +72,11 @@ const CurrentImagePreview = () => {
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
{image && (
|
||||
{progressImage && shouldShowProgressInViewer ? (
|
||||
<Image
|
||||
onDragStart={handleDragStart}
|
||||
src={shouldHidePreview ? undefined : getUrl(image.url)}
|
||||
width={image.metadata.width || 'auto'}
|
||||
height={image.metadata.height || 'auto'}
|
||||
fallback={shouldHidePreview ? <CurrentImageHidden /> : undefined}
|
||||
src={progressImage.dataURL}
|
||||
width={progressImage.width}
|
||||
height={progressImage.height}
|
||||
sx={{
|
||||
objectFit: 'contain',
|
||||
maxWidth: '100%',
|
||||
@ -72,6 +86,31 @@ const CurrentImagePreview = () => {
|
||||
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 && (
|
||||
<Box
|
||||
|
@ -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);
|
@ -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);
|
@ -5,6 +5,7 @@ import {
|
||||
FlexProps,
|
||||
Grid,
|
||||
Icon,
|
||||
Image,
|
||||
Text,
|
||||
forwardRef,
|
||||
} from '@chakra-ui/react';
|
||||
@ -14,7 +15,10 @@ import IAICheckbox from 'common/components/IAICheckbox';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import IAIPopover from 'common/components/IAIPopover';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { imageGallerySelector } from 'features/gallery/store/gallerySelectors';
|
||||
import {
|
||||
gallerySelector,
|
||||
imageGallerySelector,
|
||||
} from 'features/gallery/store/gallerySelectors';
|
||||
import {
|
||||
setCurrentCategory,
|
||||
setGalleryImageMinimumWidth,
|
||||
@ -50,30 +54,48 @@ import { uploadsAdapter } from '../store/uploadsSlice';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { RootState } from 'app/store/store';
|
||||
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 PROGRESS_IMAGE_PLACEHOLDER = 'PROGRESS_IMAGE_PLACEHOLDER';
|
||||
|
||||
const gallerySelector = createSelector(
|
||||
[
|
||||
(state: RootState) => state.uploads,
|
||||
(state: RootState) => state.results,
|
||||
(state: RootState) => state.gallery,
|
||||
],
|
||||
(uploads, results, gallery) => {
|
||||
const selector = createSelector(
|
||||
[(state: RootState) => state],
|
||||
(state) => {
|
||||
const { results, uploads, system, gallery } = state;
|
||||
const { currentCategory } = gallery;
|
||||
|
||||
return currentCategory === 'results'
|
||||
? {
|
||||
images: resultsAdapter.getSelectors().selectAll(results),
|
||||
const tempImages: (ImageType | typeof PROGRESS_IMAGE_PLACEHOLDER)[] = [];
|
||||
|
||||
if (system.progressImage) {
|
||||
tempImages.push(PROGRESS_IMAGE_PLACEHOLDER);
|
||||
}
|
||||
|
||||
if (currentCategory === 'results') {
|
||||
return {
|
||||
images: tempImages.concat(
|
||||
resultsAdapter.getSelectors().selectAll(results)
|
||||
),
|
||||
isLoading: results.isLoading,
|
||||
areMoreImagesAvailable: results.page < results.pages - 1,
|
||||
};
|
||||
}
|
||||
: {
|
||||
images: uploadsAdapter.getSelectors().selectAll(uploads),
|
||||
|
||||
return {
|
||||
images: tempImages.concat(
|
||||
uploadsAdapter.getSelectors().selectAll(uploads)
|
||||
),
|
||||
isLoading: uploads.isLoading,
|
||||
areMoreImagesAvailable: uploads.page < uploads.pages - 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
|
||||
const ImageGalleryContent = () => {
|
||||
@ -108,7 +130,7 @@ const ImageGalleryContent = () => {
|
||||
} = useAppSelector(imageGallerySelector);
|
||||
|
||||
const { images, areMoreImagesAvailable, isLoading } =
|
||||
useAppSelector(gallerySelector);
|
||||
useAppSelector(selector);
|
||||
|
||||
const handleClickLoadMore = () => {
|
||||
if (currentCategory === 'results') {
|
||||
@ -186,8 +208,6 @@ const ImageGalleryContent = () => {
|
||||
h: 'full',
|
||||
w: 'full',
|
||||
borderRadius: 'base',
|
||||
// bg: 'base.850',
|
||||
// p: 2,
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
@ -311,16 +331,24 @@ const ImageGalleryContent = () => {
|
||||
endReached={handleEndReached}
|
||||
scrollerRef={(ref) => setScrollerRef(ref)}
|
||||
itemContent={(index, image) => {
|
||||
const { name } = image;
|
||||
const isSelected = selectedImage?.name === name;
|
||||
const isSelected =
|
||||
image === PROGRESS_IMAGE_PLACEHOLDER
|
||||
? false
|
||||
: selectedImage?.name === image?.name;
|
||||
|
||||
return (
|
||||
<Flex sx={{ pb: 2 }}>
|
||||
{image === PROGRESS_IMAGE_PLACEHOLDER ? (
|
||||
<GalleryProgressImage
|
||||
key={PROGRESS_IMAGE_PLACEHOLDER}
|
||||
/>
|
||||
) : (
|
||||
<HoverableImage
|
||||
key={`${name}-${image.thumbnail}`}
|
||||
key={`${image.name}-${image.thumbnail}`}
|
||||
image={image}
|
||||
isSelected={isSelected}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}}
|
||||
@ -336,12 +364,16 @@ const ImageGalleryContent = () => {
|
||||
}}
|
||||
scrollerRef={setScroller}
|
||||
itemContent={(index, image) => {
|
||||
const { name } = image;
|
||||
const isSelected = selectedImage?.name === name;
|
||||
const isSelected =
|
||||
image === PROGRESS_IMAGE_PLACEHOLDER
|
||||
? false
|
||||
: selectedImage?.name === image?.name;
|
||||
|
||||
return (
|
||||
return image === PROGRESS_IMAGE_PLACEHOLDER ? (
|
||||
<GalleryProgressImage key={PROGRESS_IMAGE_PLACEHOLDER} />
|
||||
) : (
|
||||
<HoverableImage
|
||||
key={`${name}-${image.thumbnail}`}
|
||||
key={`${image.name}-${image.thumbnail}`}
|
||||
image={image}
|
||||
isSelected={isSelected}
|
||||
/>
|
||||
|
@ -28,13 +28,14 @@ export const buildImg2ImgNode = (
|
||||
img2imgStrength: strength,
|
||||
shouldFitToWidthHeight: fit,
|
||||
shouldRandomizeSeed,
|
||||
initialImage,
|
||||
} = generation;
|
||||
|
||||
const initialImage = initialImageSelector(state);
|
||||
// const initialImage = initialImageSelector(state);
|
||||
|
||||
if (!initialImage) {
|
||||
// TODO: handle this
|
||||
// throw 'no initial image';
|
||||
throw 'no initial image';
|
||||
}
|
||||
|
||||
const imageToImageNode: ImageToImageInvocation = {
|
||||
@ -47,12 +48,10 @@ export const buildImg2ImgNode = (
|
||||
cfg_scale: cfgScale,
|
||||
scheduler: sampler as ImageToImageInvocation['scheduler'],
|
||||
model,
|
||||
image: initialImage
|
||||
? {
|
||||
image: {
|
||||
image_name: initialImage.name,
|
||||
image_type: initialImage.type,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
strength,
|
||||
fit,
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ import {
|
||||
} from 'features/system/store/systemSlice';
|
||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||
import {
|
||||
setShouldAutoShowProgressImages,
|
||||
setShouldShowProgressInViewer,
|
||||
setShouldUseCanvasBetaLayout,
|
||||
setShouldUseSliders,
|
||||
} from 'features/ui/store/uiSlice';
|
||||
@ -54,7 +54,7 @@ const selector = createSelector(
|
||||
const {
|
||||
shouldUseCanvasBetaLayout,
|
||||
shouldUseSliders,
|
||||
shouldAutoShowProgressImages,
|
||||
shouldShowProgressInViewer,
|
||||
} = ui;
|
||||
|
||||
return {
|
||||
@ -63,7 +63,7 @@ const selector = createSelector(
|
||||
enableImageDebugging,
|
||||
shouldUseCanvasBetaLayout,
|
||||
shouldUseSliders,
|
||||
shouldAutoShowProgressImages,
|
||||
shouldShowProgressInViewer,
|
||||
consoleLogLevel,
|
||||
shouldLogToConsole,
|
||||
};
|
||||
@ -114,7 +114,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
enableImageDebugging,
|
||||
shouldUseCanvasBetaLayout,
|
||||
shouldUseSliders,
|
||||
shouldAutoShowProgressImages,
|
||||
shouldShowProgressInViewer,
|
||||
consoleLogLevel,
|
||||
shouldLogToConsole,
|
||||
} = useAppSelector(selector);
|
||||
@ -197,10 +197,10 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
}
|
||||
/>
|
||||
<IAISwitch
|
||||
label={t('settings.autoShowProgress')}
|
||||
isChecked={shouldAutoShowProgressImages}
|
||||
label={t('settings.showProgressInViewer')}
|
||||
isChecked={shouldShowProgressInViewer}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldAutoShowProgressImages(e.target.checked))
|
||||
dispatch(setShouldShowProgressInViewer(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
|
@ -9,6 +9,7 @@ import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useMemo, useRef } from 'react';
|
||||
import { FaCircle } from 'react-icons/fa';
|
||||
import { useHoverDirty } from 'react-use';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
|
||||
const statusIndicatorSelector = createSelector(
|
||||
systemSelector,
|
||||
@ -31,9 +32,7 @@ const statusIndicatorSelector = createSelector(
|
||||
currentStatusHasSteps,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: { resultEqualityCheck: isEqual },
|
||||
}
|
||||
defaultSelectorOptions
|
||||
);
|
||||
|
||||
const StatusIndicator = () => {
|
||||
|
@ -354,6 +354,7 @@ export const systemSlice = createSlice({
|
||||
state.currentStep = 0;
|
||||
state.totalSteps = 0;
|
||||
state.statusTranslationKey = 'common.statusProcessingComplete';
|
||||
state.progressImage = null;
|
||||
|
||||
if (state.canceledSession === data.graph_execution_state_id) {
|
||||
state.isProcessing = false;
|
||||
@ -373,6 +374,7 @@ export const systemSlice = createSlice({
|
||||
state.currentStep = 0;
|
||||
state.totalSteps = 0;
|
||||
state.statusTranslationKey = 'common.statusError';
|
||||
state.progressImage = null;
|
||||
|
||||
state.toastQueue.push(
|
||||
makeToast({ title: t('toast.serverError'), status: 'error' })
|
||||
|
@ -23,7 +23,7 @@ export const initialUIState: UIState = {
|
||||
canvasTabAccordionState: [],
|
||||
floatingProgressImageRect: { x: 0, y: 0, width: 0, height: 0 },
|
||||
shouldShowProgressImages: false,
|
||||
shouldAutoShowProgressImages: false,
|
||||
shouldShowProgressInViewer: false,
|
||||
shouldShowImageParameters: false,
|
||||
};
|
||||
|
||||
@ -135,11 +135,8 @@ export const uiSlice = createSlice({
|
||||
setShouldShowProgressImages: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowProgressImages = action.payload;
|
||||
},
|
||||
setShouldAutoShowProgressImages: (
|
||||
state,
|
||||
action: PayloadAction<boolean>
|
||||
) => {
|
||||
state.shouldAutoShowProgressImages = action.payload;
|
||||
setShouldShowProgressInViewer: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowProgressInViewer = action.payload;
|
||||
},
|
||||
shouldShowImageParametersChanged: (
|
||||
state,
|
||||
@ -173,7 +170,7 @@ export const {
|
||||
floatingProgressImageMoved,
|
||||
floatingProgressImageResized,
|
||||
setShouldShowProgressImages,
|
||||
setShouldAutoShowProgressImages,
|
||||
setShouldShowProgressInViewer,
|
||||
shouldShowImageParametersChanged,
|
||||
} = uiSlice.actions;
|
||||
|
||||
|
@ -31,6 +31,6 @@ export interface UIState {
|
||||
canvasTabAccordionState: number[];
|
||||
floatingProgressImageRect: Rect;
|
||||
shouldShowProgressImages: boolean;
|
||||
shouldAutoShowProgressImages: boolean;
|
||||
shouldShowProgressInViewer: boolean;
|
||||
shouldShowImageParameters: boolean;
|
||||
}
|
||||
|
@ -20,9 +20,6 @@ const invokeAIContent = defineStyle((_props) => {
|
||||
minW: 'unset',
|
||||
width: 'unset',
|
||||
p: 4,
|
||||
borderWidth: '2px',
|
||||
borderStyle: 'solid',
|
||||
borderColor: 'base.600',
|
||||
bg: 'base.800',
|
||||
};
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user