diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx
index cfac6a728a..e751a5e5fb 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryPagination.tsx
@@ -1,10 +1,23 @@
-import { Button, Flex, IconButton, Text } from '@invoke-ai/ui-library';
-import { useGalleryPagination } from '../../hooks/useGalleryPagination';
-import { PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi';
+import { Button, Flex, IconButton, Spacer, Text } from '@invoke-ai/ui-library';
+import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination';
+import { PiCaretDoubleLeftBold, PiCaretDoubleRightBold, PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi';
export const GalleryPagination = () => {
- const { goPrev, goNext, isPrevEnabled, isNextEnabled, pageButtons, goToPage, currentPage, rangeDisplay, total } =
- useGalleryPagination();
+ const {
+ goPrev,
+ goNext,
+ goToFirst,
+ goToLast,
+ isFirstEnabled,
+ isLastEnabled,
+ isPrevEnabled,
+ isNextEnabled,
+ pageButtons,
+ goToPage,
+ currentPage,
+ rangeDisplay,
+ total,
+ } = useGalleryPagination();
if (!total) {
return ;
@@ -12,7 +25,14 @@ export const GalleryPagination = () => {
return (
-
+
+ }
+ onClick={goToFirst}
+ isDisabled={!isFirstEnabled}
+ />
{
onClick={goPrev}
isDisabled={!isPrevEnabled}
/>
- {pageButtons.map((page) =>
- typeof page === 'number' ? (
-
- ) : (
- ...
- )
- )}
+
+ {pageButtons.map((page) => (
+
+ ))}
+
{
onClick={goNext}
isDisabled={!isNextEnabled}
/>
+ }
+ onClick={goToLast}
+ isDisabled={!isLastEnabled}
+ />
{rangeDisplay} Images
diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts
index 43777c5606..0045afeab6 100644
--- a/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts
+++ b/invokeai/frontend/web/src/features/gallery/hooks/useGalleryPagination.ts
@@ -1,133 +1,119 @@
-import { useMemo, useCallback } from "react";
-import { useAppDispatch, useAppSelector } from "../../../app/store/storeHooks";
-import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from "../../../services/api/endpoints/boards";
-import { useListImagesQuery } from "../../../services/api/endpoints/images";
-import { selectListImagesQueryArgs } from "../store/gallerySelectors";
-import { offsetChanged } from "../store/gallerySlice";
+import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
+import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
+import { offsetChanged } from 'features/gallery/store/gallerySlice';
+import { useCallback, useMemo } from 'react';
+import { useListImagesQuery } from 'services/api/endpoints/images';
-export const useGalleryPagination = () => {
- const dispatch = useAppDispatch();
- const { offset, limit } = useAppSelector((s) => s.gallery);
- const queryArgs = useAppSelector(selectListImagesQueryArgs);
+export const useGalleryPagination = (pageButtonsPerSide: number = 2) => {
+ const dispatch = useAppDispatch();
+ const { offset, limit } = useAppSelector((s) => s.gallery);
+ const queryArgs = useAppSelector(selectListImagesQueryArgs);
- const { count, total } = useListImagesQuery(queryArgs, {
- selectFromResult: ({ data }) => ({ count: data?.items.length ?? 0, total: data?.total ?? 0 }),
- });
+ const { count, total } = useListImagesQuery(queryArgs, {
+ selectFromResult: ({ data }) => ({ count: data?.items.length ?? 0, total: data?.total ?? 0 }),
+ });
- const currentPage = useMemo(() => Math.ceil(offset / (limit || 0)), [offset, limit]);
- const pages = useMemo(() => Math.ceil(total / (limit || 0)), [total, limit]);
+ const currentPage = useMemo(() => Math.ceil(offset / (limit || 0)), [offset, limit]);
+ const pages = useMemo(() => Math.ceil(total / (limit || 0)), [total, limit]);
- const isNextEnabled = useMemo(() => {
- if (!count) {
- return false;
- }
- return currentPage + 1 < pages;
- }, [count, currentPage, pages]);
- const isPrevEnabled = useMemo(() => {
- if (!count) {
- return false;
- }
- return offset > 0;
- }, [count, offset]);
+ const isNextEnabled = useMemo(() => {
+ if (!count) {
+ return false;
+ }
+ return currentPage + 1 < pages;
+ }, [count, currentPage, pages]);
+ const isPrevEnabled = useMemo(() => {
+ if (!count) {
+ return false;
+ }
+ return offset > 0;
+ }, [count, offset]);
- const goNext = useCallback(() => {
- dispatch(offsetChanged(offset + (limit || 0)));
- }, [dispatch, offset, limit]);
+ const goNext = useCallback(() => {
+ dispatch(offsetChanged(offset + (limit || 0)));
+ }, [dispatch, offset, limit]);
- const goPrev = useCallback(() => {
- dispatch(offsetChanged(Math.max(offset - (limit || 0), 0)));
- }, [dispatch, offset, limit]);
+ const goPrev = useCallback(() => {
+ dispatch(offsetChanged(Math.max(offset - (limit || 0), 0)));
+ }, [dispatch, offset, limit]);
- const goToPage = useCallback(
- (page: number) => {
- const p = Math.max(0, Math.min(page, pages - 1));
- dispatch(offsetChanged(page * (limit || 0)));
- },
- [dispatch, pages, limit]
- );
- const goToFirst = useCallback(() => {
- dispatch(offsetChanged(0));
- }, [dispatch]);
- const goToLast = useCallback(() => {
- dispatch(offsetChanged(pages * (limit || 0)));
- }, [dispatch, pages, limit]);
+ const goToPage = useCallback(
+ (page: number) => {
+ const p = Math.max(0, Math.min(page, pages - 1));
+ dispatch(offsetChanged(page * (limit || 0)));
+ },
+ [dispatch, pages, limit]
+ );
+ const goToFirst = useCallback(() => {
+ dispatch(offsetChanged(0));
+ }, [dispatch]);
+ const goToLast = useCallback(() => {
+ dispatch(offsetChanged((pages - 1) * (limit || 0)));
+ }, [dispatch, pages, limit]);
- // calculate the page buttons to display - current page with 3 around it
- const pageButtons = useMemo(() => {
- const buttons = [];
- const maxPageButtons = 3;
- let startPage = Math.max(currentPage - (Math.floor(maxPageButtons / 2)), 0);
- let endPage = Math.min(startPage + maxPageButtons - 1, pages - 1);
+ // calculate the page buttons to display - current page with 3 around it
+ const pageButtons = useMemo(() => {
+ const buttons = [];
+ const maxPageButtons = pageButtonsPerSide * 2 + 1;
+ let startPage = Math.max(currentPage - Math.floor(maxPageButtons / 2), 0);
+ const endPage = Math.min(startPage + maxPageButtons - 1, pages - 1);
- if (endPage - startPage < maxPageButtons - 1) {
- startPage = Math.max(endPage - maxPageButtons + 1, 0);
- }
+ if (endPage - startPage < maxPageButtons - 1) {
+ startPage = Math.max(endPage - maxPageButtons + 1, 0);
+ }
- if (startPage > 0) {
- buttons.push(0);
- if (startPage > 1) {
- buttons.push('...');
- }
- }
+ for (let i = startPage; i <= endPage; i++) {
+ buttons.push(i);
+ }
- for (let i = startPage; i <= endPage; i++) {
- buttons.push(i);
- }
+ return buttons;
+ }, [currentPage, pageButtonsPerSide, pages]);
- if (endPage < pages - 1) {
- if (endPage < pages - 2) {
- buttons.push('...');
- }
- buttons.push(pages - 1);
- }
+ const isFirstEnabled = useMemo(() => currentPage > 0, [currentPage]);
+ const isLastEnabled = useMemo(() => currentPage < pages - 1, [currentPage, pages]);
- return buttons;
- }, [currentPage, pages]);
+ const rangeDisplay = useMemo(() => {
+ const startItem = currentPage * (limit || 0) + 1;
+ const endItem = Math.min((currentPage + 1) * (limit || 0), total);
+ return `${startItem}-${endItem} of ${total}`;
+ }, [total, currentPage, limit]);
- const isFirstEnabled = useMemo(() => currentPage > 0, [currentPage]);
- const isLastEnabled = useMemo(() => currentPage < pages - 1, [currentPage, pages]);
+ const api = useMemo(
+ () => ({
+ count,
+ total,
+ currentPage,
+ pages,
+ isNextEnabled,
+ isPrevEnabled,
+ goNext,
+ goPrev,
+ goToPage,
+ goToFirst,
+ goToLast,
+ pageButtons,
+ isFirstEnabled,
+ isLastEnabled,
+ rangeDisplay,
+ }),
+ [
+ count,
+ total,
+ currentPage,
+ pages,
+ isNextEnabled,
+ isPrevEnabled,
+ goNext,
+ goPrev,
+ goToPage,
+ goToFirst,
+ goToLast,
+ pageButtons,
+ isFirstEnabled,
+ isLastEnabled,
+ rangeDisplay,
+ ]
+ );
- const rangeDisplay = useMemo(() => {
- const startItem = currentPage * (limit || 0) + 1;
- const endItem = Math.min((currentPage + 1) * (limit || 0), total);
- return `${startItem}-${endItem} of ${total}`;
- }, [total, currentPage, limit]);
-
- const api = useMemo(
- () => ({
- count,
- total,
- currentPage,
- pages,
- isNextEnabled,
- isPrevEnabled,
- goNext,
- goPrev,
- goToPage,
- goToFirst,
- goToLast,
- pageButtons,
- isFirstEnabled,
- isLastEnabled,
- rangeDisplay
- }),
- [
- count,
- total,
- currentPage,
- pages,
- isNextEnabled,
- isPrevEnabled,
- goNext,
- goPrev,
- goToPage,
- goToFirst,
- goToLast,
- pageButtons,
- isFirstEnabled,
- isLastEnabled,
- rangeDisplay
- ]
- );
- return api;
-};
\ No newline at end of file
+ return api;
+};