mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
infinite grid
This commit is contained in:
@@ -166,8 +166,8 @@ export const createStore = (uniqueStoreKey?: string, persist = true) =>
|
||||
reducer: rememberedRootReducer,
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({
|
||||
serializableCheck: import.meta.env.MODE === 'development',
|
||||
immutableCheck: import.meta.env.MODE === 'development',
|
||||
serializableCheck: false, // import.meta.env.MODE === 'development',
|
||||
immutableCheck: false, // import.meta.env.MODE === 'development',
|
||||
})
|
||||
.concat(api.middleware)
|
||||
.concat(dynamicMiddlewares)
|
||||
|
||||
@@ -4,7 +4,6 @@ import { IAILoadingImageFallback, IAINoContentFallback } from 'common/components
|
||||
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
|
||||
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||
import type { TypesafeDraggableData, TypesafeDroppableData } from 'features/dnd/types';
|
||||
import ImageContextMenu from 'features/gallery/components/ImageContextMenu/ImageContextMenu';
|
||||
import type { MouseEvent, ReactElement, ReactNode, SyntheticEvent } from 'react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { PiImageBold, PiUploadSimpleBold } from 'react-icons/pi';
|
||||
@@ -125,36 +124,6 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
[onMouseOut]
|
||||
);
|
||||
|
||||
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
||||
postUploadAction,
|
||||
isDisabled: isUploadDisabled,
|
||||
});
|
||||
|
||||
const uploadButtonStyles = useMemo<SystemStyleObject>(() => {
|
||||
const styles: SystemStyleObject = {
|
||||
minH: minSize,
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 'base',
|
||||
transitionProperty: 'common',
|
||||
transitionDuration: '0.1s',
|
||||
color: 'base.500',
|
||||
};
|
||||
if (!isUploadDisabled) {
|
||||
Object.assign(styles, {
|
||||
cursor: 'pointer',
|
||||
bg: 'base.700',
|
||||
_hover: {
|
||||
bg: 'base.650',
|
||||
color: 'base.300',
|
||||
},
|
||||
});
|
||||
}
|
||||
return styles;
|
||||
}, [isUploadDisabled, minSize]);
|
||||
|
||||
const openInNewTab = useCallback(
|
||||
(e: MouseEvent) => {
|
||||
if (!imageDTO) {
|
||||
@@ -169,10 +138,10 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<ImageContextMenu imageDTO={imageDTO}>
|
||||
{(ref) => (
|
||||
// <ImageContextMenu imageDTO={imageDTO}>
|
||||
// {(ref) => (
|
||||
<Flex
|
||||
ref={ref}
|
||||
// ref={ref}
|
||||
onMouseOver={handleMouseOver}
|
||||
onMouseOut={handleMouseOut}
|
||||
width="full"
|
||||
@@ -216,12 +185,12 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
</Flex>
|
||||
)}
|
||||
{!imageDTO && !isUploadDisabled && (
|
||||
<>
|
||||
<Flex sx={uploadButtonStyles} {...getUploadButtonProps()}>
|
||||
<input {...getUploadInputProps()} />
|
||||
{uploadElement}
|
||||
</Flex>
|
||||
</>
|
||||
<UploadButton
|
||||
isUploadDisabled={isUploadDisabled}
|
||||
postUploadAction={postUploadAction}
|
||||
uploadElement={uploadElement}
|
||||
minSize={minSize}
|
||||
/>
|
||||
)}
|
||||
{!imageDTO && isUploadDisabled && noContentFallback}
|
||||
{imageDTO && !isDragDisabled && (
|
||||
@@ -235,9 +204,58 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
{children}
|
||||
{!isDropDisabled && <IAIDroppable data={droppableData} disabled={isDropDisabled} dropLabel={dropLabel} />}
|
||||
</Flex>
|
||||
)}
|
||||
</ImageContextMenu>
|
||||
// )}
|
||||
// </ImageContextMenu>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(IAIDndImage);
|
||||
|
||||
const UploadButton = ({
|
||||
isUploadDisabled,
|
||||
postUploadAction,
|
||||
uploadElement,
|
||||
minSize,
|
||||
}: {
|
||||
isUploadDisabled: boolean;
|
||||
postUploadAction?: PostUploadAction;
|
||||
uploadElement: ReactNode;
|
||||
minSize: number;
|
||||
}) => {
|
||||
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
||||
postUploadAction,
|
||||
isDisabled: isUploadDisabled,
|
||||
});
|
||||
|
||||
const uploadButtonStyles = useMemo<SystemStyleObject>(() => {
|
||||
const styles: SystemStyleObject = {
|
||||
minH: minSize,
|
||||
w: 'full',
|
||||
h: 'full',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 'base',
|
||||
transitionProperty: 'common',
|
||||
transitionDuration: '0.1s',
|
||||
color: 'base.500',
|
||||
};
|
||||
if (!isUploadDisabled) {
|
||||
Object.assign(styles, {
|
||||
cursor: 'pointer',
|
||||
bg: 'base.700',
|
||||
_hover: {
|
||||
bg: 'base.650',
|
||||
color: 'base.300',
|
||||
},
|
||||
});
|
||||
}
|
||||
return styles;
|
||||
}, [isUploadDisabled, minSize]);
|
||||
|
||||
return (
|
||||
<Flex sx={uploadButtonStyles} {...getUploadButtonProps()}>
|
||||
<input {...getUploadInputProps()} />
|
||||
{uploadElement}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -161,10 +161,6 @@ const GalleryImageContent = memo(({ index, imageDTO }: GalleryImageContentProps)
|
||||
|
||||
const dataTestId = useMemo(() => getGalleryImageDataTestId(imageDTO.image_name), [imageDTO.image_name]);
|
||||
|
||||
if (!imageDTO) {
|
||||
return <IAIFillSkeleton />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box w="full" h="full" className={GALLERY_IMAGE_CLASS_NAME} data-testid={dataTestId} sx={boxSx}>
|
||||
<Flex
|
||||
@@ -228,7 +224,7 @@ const GalleryImageContent = memo(({ index, imageDTO }: GalleryImageContentProps)
|
||||
|
||||
GalleryImageContent.displayName = 'GalleryImageContent';
|
||||
|
||||
const DeleteIcon = ({ imageDTO }: { imageDTO: ImageDTO }) => {
|
||||
const DeleteIcon = memo(({ imageDTO }: { imageDTO: ImageDTO }) => {
|
||||
const shift = useShiftModifier();
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -257,9 +253,9 @@ const DeleteIcon = ({ imageDTO }: { imageDTO: ImageDTO }) => {
|
||||
insetInlineEnd={2}
|
||||
/>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
const OpenInViewerIconButton = ({ imageDTO }: { imageDTO: ImageDTO }) => {
|
||||
const OpenInViewerIconButton = memo(({ imageDTO }: { imageDTO: ImageDTO }) => {
|
||||
const imageViewer = useImageViewer();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -277,4 +273,4 @@ const OpenInViewerIconButton = ({ imageDTO }: { imageDTO: ImageDTO }) => {
|
||||
insetInlineStart={2}
|
||||
/>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -14,6 +14,16 @@ import type { ImageDTO } from 'services/api/types';
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type TableVirtuosoScrollerRef = (ref: HTMLElement | Window | null) => any;
|
||||
|
||||
const selectors = new Map<string, ReturnType<typeof imagesApi.endpoints.getImageDTO.select>>();
|
||||
const getSelector = (name: string) => {
|
||||
let selector = selectors.get(name);
|
||||
if (!selector) {
|
||||
selector = imagesApi.endpoints.getImageDTO.select(name);
|
||||
selectors.set(name, selector);
|
||||
}
|
||||
return selector;
|
||||
};
|
||||
|
||||
export const GalleryImageListExperiment = memo(() => {
|
||||
const store = useAppStore();
|
||||
const { data } = useGetImageNamesQuery({ starred_first: false });
|
||||
@@ -35,10 +45,10 @@ export const GalleryImageListExperiment = memo(() => {
|
||||
if (imageNames) {
|
||||
// optimisation: we may have already loaded some of these images, so filter out the ones we already have
|
||||
const imageNamesToFetch: string[] = [];
|
||||
const state = store.getState();
|
||||
for (const name of imageNames) {
|
||||
// check if we have this image cached already
|
||||
const { data } = imagesApi.endpoints.getImageDTO.select(name)(store.getState());
|
||||
if (!data) {
|
||||
if (!getSelector(name)(state).data) {
|
||||
// nope, we need to fetch it
|
||||
imageNamesToFetch.push(name);
|
||||
}
|
||||
@@ -89,7 +99,7 @@ export const GalleryImageListExperiment = memo(() => {
|
||||
components={components}
|
||||
itemContent={itemContent}
|
||||
rangeChanged={debouncedOnRangeChanged}
|
||||
overscan={10}
|
||||
overscan={50}
|
||||
// increases teh virual viewport by 200px in each direction, so we fetch a few more images than required
|
||||
scrollerRef={setScroller as TableVirtuosoScrollerRef}
|
||||
/>
|
||||
@@ -115,7 +125,7 @@ const useGetImageDTOCache = (imageName: string): ImageDTO | undefined => {
|
||||
const HEIGHT = 24;
|
||||
|
||||
const ListItem = ({ index, data }: { index: number; data: string }) => {
|
||||
const imageDTO = useGetImageDTOCache(data);
|
||||
const imageDTO = useAppSelector(getSelector(data)).data;
|
||||
|
||||
if (!imageDTO) {
|
||||
return <Skeleton w="full" h={HEIGHT} />;
|
||||
|
||||
Reference in New Issue
Block a user