Compare commits

...

3 Commits

Author SHA1 Message Date
Mary Hipp
0060024f24 translation 2025-02-25 11:48:37 -05:00
Mary Hipp
633c418202 feat(api): allow image list endpoint to accept a null limit to return all 2025-02-25 11:43:30 -05:00
Mary Hipp
00e6d7c6f0 feat(ui): add option to select all for a given board and category (image/asset) 2025-02-25 11:42:38 -05:00
11 changed files with 61 additions and 12 deletions

View File

@@ -323,7 +323,7 @@ async def list_image_dtos(
description="The board id to filter by. Use 'none' to find images without a board.",
),
offset: int = Query(default=0, description="The page offset"),
limit: int = Query(default=10, description="The number of images per page"),
limit: Optional[int] = Query(default=None, description="The number of images per page"),
order_dir: SQLiteDirection = Query(default=SQLiteDirection.Descending, description="The order of sort"),
starred_first: bool = Query(default=True, description="Whether to sort by starred images first"),
search_term: Optional[str] = Query(default=None, description="The term to search for"),

View File

@@ -41,7 +41,7 @@ class ImageRecordStorageBase(ABC):
def get_many(
self,
offset: int = 0,
limit: int = 10,
limit: Optional[int] = None,
starred_first: bool = True,
order_dir: SQLiteDirection = SQLiteDirection.Descending,
image_origin: Optional[ResourceOrigin] = None,

View File

@@ -143,7 +143,7 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
def get_many(
self,
offset: int = 0,
limit: int = 10,
limit: Optional[int] = None,
starred_first: bool = True,
order_dir: SQLiteDirection = SQLiteDirection.Descending,
image_origin: Optional[ResourceOrigin] = None,
@@ -232,7 +232,8 @@ class SqliteImageRecordStorage(ImageRecordStorageBase):
# Add all the parameters
images_params = query_params.copy()
# Add the pagination parameters
images_params.extend([limit, offset])
sql_limit = -1 if limit is None else limit
images_params.extend([sql_limit, offset])
# Build the list of images, deserializing each row
self._cursor.execute(images_query, images_params)

View File

@@ -116,7 +116,7 @@ class ImageServiceABC(ABC):
def get_many(
self,
offset: int = 0,
limit: int = 10,
limit: Optional[int] = None,
starred_first: bool = True,
order_dir: SQLiteDirection = SQLiteDirection.Descending,
image_origin: Optional[ResourceOrigin] = None,

View File

@@ -206,7 +206,7 @@ class ImageService(ImageServiceABC):
def get_many(
self,
offset: int = 0,
limit: int = 10,
limit: Optional[int] = None,
starred_first: bool = True,
order_dir: SQLiteDirection = SQLiteDirection.Descending,
image_origin: Optional[ResourceOrigin] = None,

View File

@@ -1,4 +1,4 @@
from typing import Generic, TypeVar
from typing import Generic, Optional, TypeVar
from pydantic import BaseModel, Field
@@ -22,7 +22,7 @@ class OffsetPaginatedResults(BaseModel, Generic[GenericBaseModel]):
Generic must be a Pydantic model
"""
limit: int = Field(description="Limit of items to get")
limit: Optional[int] = Field(description="Limit of items to get")
offset: int = Field(description="Offset from which to retrieve items")
total: int = Field(description="Total number of items in result")
items: list[GenericBaseModel] = Field(description="Items")

View File

@@ -358,6 +358,7 @@
"compareImage": "Compare Image",
"openInViewer": "Open in Viewer",
"searchImages": "Search by Metadata",
"selectAll": "Select All",
"selectAllOnPage": "Select All On Page",
"showArchivedBoards": "Show Archived Boards",
"selectForCompare": "Select for Compare",

View File

@@ -1,11 +1,16 @@
import { Button, Flex, IconButton, Spacer } from '@invoke-ai/ui-library';
import { Button, Flex, IconButton, Spacer, Tooltip } from '@invoke-ai/ui-library';
import { ELLIPSIS, useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination';
import { useSelectAll } from 'features/gallery/hooks/useSelectAll';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { BiSelectMultiple } from 'react-icons/bi';
import { PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi';
import { JumpTo } from './JumpTo';
export const GalleryPagination = memo(() => {
const { t } = useTranslation();
const selectAll = useSelectAll();
const { goPrev, goNext, isPrevEnabled, isNextEnabled, pageButtons, goToPage, currentPage, total } =
useGalleryPagination();
@@ -45,6 +50,15 @@ export const GalleryPagination = memo(() => {
variant="ghost"
/>
<JumpTo />
<Tooltip label={`${t('gallery.selectAll')} (${total})`}>
<IconButton
variant="outline"
size="sm"
icon={<BiSelectMultiple />}
aria-label={t('gallery.selectAll')}
onClick={selectAll}
/>
</Tooltip>
</Flex>
);
});

View File

@@ -0,0 +1,17 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { selectListAllImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
import { selectionChanged } from 'features/gallery/store/gallerySlice';
import { useCallback } from 'react';
import { useListImagesQuery } from 'services/api/endpoints/images';
export const useSelectAll = () => {
const dispatch = useAppDispatch();
const queryArgs = useAppSelector(selectListAllImagesQueryArgs);
const { data } = useListImagesQuery(queryArgs);
return useCallback(() => {
if (data) {
dispatch(selectionChanged(data.items));
}
}, [dispatch, data]);
};

View File

@@ -31,6 +31,22 @@ export const selectListImagesQueryArgs = createMemoizedSelector(
: skipToken
);
export const selectListAllImagesQueryArgs = createMemoizedSelector(
selectGallerySlice,
(gallery): ListImagesArgs | SkipToken =>
gallery.limit
? {
board_id: gallery.selectedBoardId,
categories: gallery.galleryView === 'images' ? IMAGE_CATEGORIES : ASSETS_CATEGORIES,
offset: 0,
limit: undefined,
is_intermediate: false,
starred_first: gallery.starredFirst,
order_dir: gallery.orderDir,
}
: skipToken
);
export const selectListBoardsQueryArgs = createMemoizedSelector(
selectGallerySlice,
(gallery): ListBoardsArgs => ({

View File

@@ -14773,7 +14773,7 @@ export type components = {
* Limit
* @description Limit of items to get
*/
limit: number;
limit: number | null;
/**
* Offset
* @description Offset from which to retrieve items
@@ -14796,7 +14796,7 @@ export type components = {
* Limit
* @description Limit of items to get
*/
limit: number;
limit: number | null;
/**
* Offset
* @description Offset from which to retrieve items
@@ -21189,7 +21189,7 @@ export interface operations {
/** @description The page offset */
offset?: number;
/** @description The number of images per page */
limit?: number;
limit?: number | null;
/** @description The order of sort */
order_dir?: components["schemas"]["SQLiteDirection"];
/** @description Whether to sort by starred images first */