diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTotalsTooltip.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTotalsTooltip.tsx index b4c89a002d..01d6c226dd 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTotalsTooltip.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardTotalsTooltip.tsx @@ -1,22 +1,12 @@ import { useTranslation } from 'react-i18next'; -import { useGetBoardAssetsTotalQuery, useGetBoardImagesTotalQuery } from 'services/api/endpoints/boards'; type Props = { - board_id: string; + imageCount: number; + assetCount: number; isArchived: boolean; }; -export const BoardTotalsTooltip = ({ board_id, isArchived }: Props) => { +export const BoardTotalsTooltip = ({ imageCount, assetCount, isArchived }: Props) => { const { t } = useTranslation(); - const { imagesTotal } = useGetBoardImagesTotalQuery(board_id, { - selectFromResult: ({ data }) => { - return { imagesTotal: data?.total ?? 0 }; - }, - }); - const { assetsTotal } = useGetBoardAssetsTotalQuery(board_id, { - selectFromResult: ({ data }) => { - return { assetsTotal: data?.total ?? 0 }; - }, - }); - return `${t('boards.imagesWithCount', { count: imagesTotal })}, ${t('boards.assetsWithCount', { count: assetsTotal })}${isArchived ? ` (${t('boards.archived')})` : ''}`; + return `${t('boards.imagesWithCount', { count: imageCount })}, ${t('boards.assetsWithCount', { count: assetCount })}${isArchived ? ` (${t('boards.archived')})` : ''}`; }; diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx index 8f348b5c41..584372d70a 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx @@ -116,7 +116,13 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps <BoardContextMenu board={board} setBoardToDelete={setBoardToDelete}> {(ref) => ( <Tooltip - label={<BoardTotalsTooltip board_id={board.board_id} isArchived={Boolean(board.archived)} />} + label={ + <BoardTotalsTooltip + imageCount={board.image_count} + assetCount={board.asset_count} + isArchived={Boolean(board.archived)} + /> + } openDelay={1000} placement="left" closeOnScroll @@ -166,7 +172,7 @@ const GalleryBoard = ({ board, isSelected, setBoardToDelete }: GalleryBoardProps </Editable> {autoAddBoardId === board.board_id && !editingDisclosure.isOpen && <AutoAddBadge />} {board.archived && !editingDisclosure.isOpen && <Icon as={PiArchiveBold} fill="base.300" />} - {!editingDisclosure.isOpen && <Text variant="subtext">{board.image_count}</Text>} + {!editingDisclosure.isOpen && <Text variant="subtext">{board.image_count + board.asset_count}</Text>} <IAIDroppable data={droppableData} dropLabel={<Text fontSize="md">{t('unifiedCanvas.move')}</Text>} /> </Flex> diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx index 14bf3d5742..5ab53b78d5 100644 --- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx +++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/NoBoardBoard.tsx @@ -9,7 +9,7 @@ import NoBoardBoardContextMenu from 'features/gallery/components/Boards/NoBoardB import { autoAddBoardIdChanged, boardIdSelected } from 'features/gallery/store/gallerySlice'; import { memo, useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { useGetBoardImagesTotalQuery } from 'services/api/endpoints/boards'; +import { useGetUncategorizedImageCountsQuery } from 'services/api/endpoints/boards'; import { useBoardName } from 'services/api/hooks/useBoardName'; interface Props { @@ -22,11 +22,7 @@ const _hover: SystemStyleObject = { const NoBoardBoard = memo(({ isSelected }: Props) => { const dispatch = useAppDispatch(); - const { imagesTotal } = useGetBoardImagesTotalQuery('none', { - selectFromResult: ({ data }) => { - return { imagesTotal: data?.total ?? 0 }; - }, - }); + const { data } = useGetUncategorizedImageCountsQuery(); const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId); const autoAssignBoardOnClick = useAppSelector((s) => s.gallery.autoAssignBoardOnClick); const boardSearchText = useAppSelector((s) => s.gallery.boardSearchText); @@ -60,7 +56,13 @@ const NoBoardBoard = memo(({ isSelected }: Props) => { <NoBoardBoardContextMenu> {(ref) => ( <Tooltip - label={<BoardTotalsTooltip board_id="none" isArchived={false} />} + label={ + <BoardTotalsTooltip + imageCount={data?.image_count ?? 0} + assetCount={data?.asset_count ?? 0} + isArchived={false} + /> + } openDelay={1000} placement="left" closeOnScroll @@ -99,7 +101,7 @@ const NoBoardBoard = memo(({ isSelected }: Props) => { {boardName} </Text> {autoAddBoardId === 'none' && <AutoAddBadge />} - <Text variant="subtext">{imagesTotal}</Text> + <Text variant="subtext">{(data?.image_count ?? 0) + (data?.asset_count ?? 0)}</Text> <IAIDroppable data={droppableData} dropLabel={<Text fontSize="md">{t('unifiedCanvas.move')}</Text>} /> </Flex> </Tooltip> diff --git a/invokeai/frontend/web/src/services/api/endpoints/boards.ts b/invokeai/frontend/web/src/services/api/endpoints/boards.ts index 55ebeab318..dfae9a871a 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/boards.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/boards.ts @@ -4,6 +4,7 @@ import type { CreateBoardArg, ListBoardsArgs, OffsetPaginatedResults_ImageDTO_, + S, UpdateBoardArg, } from 'services/api/types'; import { getListImagesUrl } from 'services/api/util'; @@ -55,6 +56,13 @@ export const boardsApi = api.injectEndpoints({ keepUnusedDataFor: 0, }), + getUncategorizedImageCounts: build.query<S['UncategorizedImageCounts'], void>({ + query: () => ({ + url: buildBoardsUrl('uncategorized/counts'), + }), + providesTags: ['UncategorizedImageCounts', { type: 'Board', id: LIST_TAG }, { type: 'Board', id: 'none' }], + }), + getBoardImagesTotal: build.query<{ total: number }, string | undefined>({ query: (board_id) => ({ url: getListImagesUrl({ @@ -129,4 +137,5 @@ export const { useCreateBoardMutation, useUpdateBoardMutation, useListAllImageNamesForBoardQuery, + useGetUncategorizedImageCountsQuery, } = boardsApi; diff --git a/invokeai/frontend/web/src/services/api/index.ts b/invokeai/frontend/web/src/services/api/index.ts index 79ea662717..e9db2b4caa 100644 --- a/invokeai/frontend/web/src/services/api/index.ts +++ b/invokeai/frontend/web/src/services/api/index.ts @@ -44,6 +44,7 @@ const tagTypes = [ // This is invalidated on reconnect. It should be used for queries that have changing data, // especially related to the queue and generation. 'FetchOnReconnect', + 'UncategorizedImageCounts', ] as const; export type ApiTagDescription = TagDescription<(typeof tagTypes)[number]>; export const LIST_TAG = 'LIST';