mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-17 05:53:47 -05:00
feat(ui): debounced gallery search
This commit is contained in:
committed by
psychedelicious
parent
d579aefb3e
commit
da05034e20
@@ -13,6 +13,7 @@ import GalleryBoardName from './GalleryBoardName';
|
||||
import GallerySettingsPopover from './GallerySettingsPopover/GallerySettingsPopover';
|
||||
import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
|
||||
import { GalleryPagination } from './ImageGrid/GalleryPagination';
|
||||
import { GallerySearch } from './ImageGrid/GallerySearch';
|
||||
|
||||
const ImageGalleryContent = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -81,6 +82,7 @@ const ImageGalleryContent = () => {
|
||||
</Tabs>
|
||||
</Flex>
|
||||
|
||||
<GallerySearch />
|
||||
<GalleryImageGrid />
|
||||
<GalleryPagination />
|
||||
</Flex>
|
||||
|
||||
@@ -19,10 +19,11 @@ const GalleryImageGrid = () => {
|
||||
useGalleryHotkeys();
|
||||
const { t } = useTranslation();
|
||||
const queryArgs = useAppSelector(selectListImagesQueryArgs);
|
||||
const { imageDTOs, isLoading, isError } = useListImagesQuery(queryArgs, {
|
||||
selectFromResult: ({ data, isLoading, isSuccess, isError }) => ({
|
||||
const { imageDTOs, isLoading, isFetching, isError } = useListImagesQuery(queryArgs, {
|
||||
selectFromResult: ({ data, isLoading, isFetching, isSuccess, isError }) => ({
|
||||
imageDTOs: data?.items ?? EMPTY_ARRAY,
|
||||
isLoading,
|
||||
isFetching,
|
||||
isSuccess,
|
||||
isError,
|
||||
}),
|
||||
@@ -36,7 +37,7 @@ const GalleryImageGrid = () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
if (isLoading || isFetching) {
|
||||
return (
|
||||
<Flex w="full" h="full" alignItems="center" justifyContent="center">
|
||||
<IAINoContentFallback label={t('gallery.loading')} icon={PiImageBold} />
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { IconButton, Input, InputGroup, InputRightElement } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { searchTermChanged } from 'features/gallery/store/gallerySlice';
|
||||
import { debounce } from 'lodash-es';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiXBold } from 'react-icons/pi';
|
||||
|
||||
export const GallerySearch = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { searchTerm } = useAppSelector((s) => s.gallery);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [searchTermInput, setSearchTermInput] = useState(searchTerm);
|
||||
|
||||
const debouncedSetSearchTerm = useMemo(() => {
|
||||
return debounce((value: string) => {
|
||||
dispatch(searchTermChanged(value));
|
||||
}, 1000);
|
||||
}, [dispatch]);
|
||||
|
||||
const handleChangeInput = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setSearchTermInput(e.target.value);
|
||||
debouncedSetSearchTerm(e.target.value);
|
||||
},
|
||||
[debouncedSetSearchTerm]
|
||||
);
|
||||
|
||||
const handleClearInput = useCallback(() => {
|
||||
setSearchTermInput('');
|
||||
dispatch(searchTermChanged(''));
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<InputGroup>
|
||||
<Input
|
||||
placeholder={t('gallery.searchImages')}
|
||||
value={searchTermInput}
|
||||
onChange={handleChangeInput}
|
||||
data-testid="image-search-input"
|
||||
/>
|
||||
{searchTermInput && searchTermInput.length && (
|
||||
<InputRightElement h="full" pe={2}>
|
||||
<IconButton
|
||||
onClick={handleClearInput}
|
||||
size="sm"
|
||||
variant="link"
|
||||
aria-label={t('boards.clearSearch')}
|
||||
icon={<PiXBold />}
|
||||
/>
|
||||
</InputRightElement>
|
||||
)}
|
||||
</InputGroup>
|
||||
);
|
||||
};
|
||||
@@ -22,6 +22,7 @@ export const selectListImagesQueryArgs = createMemoizedSelector(
|
||||
is_intermediate: false,
|
||||
starred_first: gallery.starredFirst,
|
||||
order_dir: gallery.orderDir,
|
||||
search_term: gallery.searchTerm,
|
||||
}
|
||||
: skipToken
|
||||
);
|
||||
|
||||
@@ -118,6 +118,9 @@ export const gallerySlice = createSlice({
|
||||
orderDirChanged: (state, action: PayloadAction<OrderDir>) => {
|
||||
state.orderDir = action.payload;
|
||||
},
|
||||
searchTermChanged: (state, action: PayloadAction<string | undefined>) => {
|
||||
state.searchTerm = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -143,6 +146,7 @@ export const {
|
||||
orderDirChanged,
|
||||
starredFirstChanged,
|
||||
shouldShowArchivedBoardsChanged,
|
||||
searchTermChanged,
|
||||
} = gallerySlice.actions;
|
||||
|
||||
export const selectGallerySlice = (state: RootState) => state.gallery;
|
||||
|
||||
@@ -22,6 +22,7 @@ export type GalleryState = {
|
||||
limit: number;
|
||||
starredFirst: boolean;
|
||||
orderDir: OrderDir;
|
||||
searchTerm?: string;
|
||||
alwaysShowImageSizeBadge: boolean;
|
||||
imageToCompare: ImageDTO | null;
|
||||
comparisonMode: ComparisonMode;
|
||||
|
||||
Reference in New Issue
Block a user