This commit is contained in:
Mary Hipp 2024-06-23 20:11:05 -04:00 committed by psychedelicious
parent 7bbe236107
commit f01df49128
16 changed files with 52 additions and 77 deletions

View File

@ -4,7 +4,6 @@ import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelecto
import { imageToCompareChanged, selectionChanged } from 'features/gallery/store/gallerySlice'; import { imageToCompareChanged, selectionChanged } from 'features/gallery/store/gallerySlice';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
import type { ImageDTO } from 'services/api/types'; import type { ImageDTO } from 'services/api/types';
import { imagesSelectors } from 'services/api/util';
export const galleryImageClicked = createAction<{ export const galleryImageClicked = createAction<{
imageDTO: ImageDTO; imageDTO: ImageDTO;
@ -39,7 +38,7 @@ export const addGalleryImageClickedListener = (startAppListening: AppStartListen
return; return;
} }
const imageDTOs = queryResult.data.items const imageDTOs = queryResult.data.items;
const selection = state.gallery.selection; const selection = state.gallery.selection;
if (altKey) { if (altKey) {

View File

@ -15,7 +15,7 @@ import { zNodeStatus } from 'features/nodes/types/invocation';
import { CANVAS_OUTPUT } from 'features/nodes/util/graph/constants'; import { CANVAS_OUTPUT } from 'features/nodes/util/graph/constants';
import { boardsApi } from 'services/api/endpoints/boards'; import { boardsApi } from 'services/api/endpoints/boards';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
import { imageListDefaultSort, imagesAdapter } from 'services/api/util'; import { imageListDefaultSort } from 'services/api/util';
import { socketInvocationComplete } from 'services/events/actions'; import { socketInvocationComplete } from 'services/events/actions';
// These nodes output an image, but do not actually *save* an image, so we don't want to handle the gallery logic on them // These nodes output an image, but do not actually *save* an image, so we don't want to handle the gallery logic on them
@ -65,13 +65,13 @@ export const addInvocationCompleteEventListener = (startAppListening: AppStartLi
categories: IMAGE_CATEGORIES, categories: IMAGE_CATEGORIES,
offset: gallery.offset, offset: gallery.offset,
limit: gallery.limit, limit: gallery.limit,
is_intermediate: false is_intermediate: false,
}, },
(draft) => { (draft) => {
const updatedListLength = draft.items.unshift(imageDTO); const updatedListLength = draft.items.unshift(imageDTO);
draft.items.sort(imageListDefaultSort()) draft.items.sort(imageListDefaultSort());
if (updatedListLength > IMAGE_LIMIT) { if (updatedListLength > IMAGE_LIMIT) {
draft.items.pop() draft.items.pop();
} }
draft.total += 1; draft.total += 1;
} }

View File

@ -1,6 +1,6 @@
import type { IconButtonProps, SystemStyleObject } from '@invoke-ai/ui-library'; import type { IconButtonProps, SystemStyleObject } from '@invoke-ai/ui-library';
import { IconButton } from '@invoke-ai/ui-library'; import { IconButton } from '@invoke-ai/ui-library';
import type { MouseEvent, ReactElement } from 'react'; import type { MouseEvent } from 'react';
import { memo } from 'react'; import { memo } from 'react';
const sx: SystemStyleObject = { const sx: SystemStyleObject = {

View File

@ -1,4 +1,3 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Box, Flex, Spinner } from '@invoke-ai/ui-library'; import { Box, Flex, Spinner } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';

View File

@ -1,4 +1,3 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Box, Flex, Spinner, useShiftModifier } from '@invoke-ai/ui-library'; import { Box, Flex, Spinner, useShiftModifier } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';

View File

@ -1,4 +1,3 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Flex, useShiftModifier } from '@invoke-ai/ui-library'; import { Flex, useShiftModifier } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';

View File

@ -1,4 +1,3 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { Flex, useShiftModifier } from '@invoke-ai/ui-library'; import { Flex, useShiftModifier } from '@invoke-ai/ui-library';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';

View File

@ -19,7 +19,7 @@ const GalleryImageGrid = () => {
useGalleryHotkeys(); useGalleryHotkeys();
const { t } = useTranslation(); const { t } = useTranslation();
const queryArgs = useAppSelector(selectListImagesQueryArgs); const queryArgs = useAppSelector(selectListImagesQueryArgs);
const { imageDTOs, isLoading, isSuccess, isError } = useListImagesQuery(queryArgs, { const { imageDTOs, isLoading, isError } = useListImagesQuery(queryArgs, {
selectFromResult: ({ data, isLoading, isSuccess, isError }) => ({ selectFromResult: ({ data, isLoading, isSuccess, isError }) => ({
imageDTOs: data?.items ?? EMPTY_ARRAY, imageDTOs: data?.items ?? EMPTY_ARRAY,
isLoading, isLoading,

View File

@ -67,7 +67,7 @@ export const GalleryPagination = () => {
isDisabled={!isLastEnabled} isDisabled={!isLastEnabled}
/> />
</Flex> </Flex>
<Text>{rangeDisplay} Images</Text> <Text>{rangeDisplay}</Text>
</Flex> </Flex>
); );
}; };

View File

@ -2,10 +2,10 @@ import type { ChakraProps } from '@invoke-ai/ui-library';
import { Box, Flex, IconButton, Spinner } from '@invoke-ai/ui-library'; import { Box, Flex, IconButton, Spinner } from '@invoke-ai/ui-library';
import { useGalleryImages } from 'features/gallery/hooks/useGalleryImages'; import { useGalleryImages } from 'features/gallery/hooks/useGalleryImages';
import { useGalleryNavigation } from 'features/gallery/hooks/useGalleryNavigation'; import { useGalleryNavigation } from 'features/gallery/hooks/useGalleryNavigation';
import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PiCaretDoubleRightBold, PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi'; import { PiCaretDoubleRightBold, PiCaretLeftBold, PiCaretRightBold } from 'react-icons/pi';
import { useGalleryPagination } from '../hooks/useGalleryPagination';
const nextPrevButtonStyles: ChakraProps['sx'] = { const nextPrevButtonStyles: ChakraProps['sx'] = {
color: 'base.100', color: 'base.100',

View File

@ -1,12 +1,12 @@
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination';
import { useGalleryNavigation } from 'features/gallery/hooks/useGalleryNavigation'; import { useGalleryNavigation } from 'features/gallery/hooks/useGalleryNavigation';
import { useGalleryPagination } from 'features/gallery/hooks/useGalleryPagination';
import { selectListImagesQueryArgs } from 'features/gallery/store/gallerySelectors';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { useListImagesQuery } from '../../../services/api/endpoints/images'; import { useListImagesQuery } from 'services/api/endpoints/images';
import { selectListImagesQueryArgs } from '../store/gallerySelectors';
/** /**
* Registers gallery hotkeys. This hook is a singleton. * Registers gallery hotkeys. This hook is a singleton.

View File

@ -13,4 +13,3 @@ export const useGalleryImages = () => {
queryResult, queryResult,
}; };
}; };

View File

@ -39,10 +39,9 @@ export const useGalleryPagination = (pageButtonsPerSide: number = 2) => {
const goToPage = useCallback( const goToPage = useCallback(
(page: number) => { (page: number) => {
const p = Math.max(0, Math.min(page, pages - 1));
dispatch(offsetChanged(page * (limit || 0))); dispatch(offsetChanged(page * (limit || 0)));
}, },
[dispatch, pages, limit] [dispatch, limit]
); );
const goToFirst = useCallback(() => { const goToFirst = useCallback(() => {
dispatch(offsetChanged(0)); dispatch(offsetChanged(0));

View File

@ -1,4 +1,5 @@
import { SkipToken, skipToken } from '@reduxjs/toolkit/query'; import type { SkipToken } from '@reduxjs/toolkit/query';
import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { selectGallerySlice } from 'features/gallery/store/gallerySlice'; import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types'; import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types';
@ -11,11 +12,14 @@ export const selectLastSelectedImage = createMemoizedSelector(
export const selectListImagesQueryArgs = createMemoizedSelector( export const selectListImagesQueryArgs = createMemoizedSelector(
selectGallerySlice, selectGallerySlice,
(gallery): ListImagesArgs | SkipToken => (gallery.limit ? { (gallery): ListImagesArgs | SkipToken =>
gallery.limit
? {
board_id: gallery.selectedBoardId, board_id: gallery.selectedBoardId,
categories: gallery.galleryView === 'images' ? IMAGE_CATEGORIES : ASSETS_CATEGORIES, categories: gallery.galleryView === 'images' ? IMAGE_CATEGORIES : ASSETS_CATEGORIES,
offset: gallery.offset, offset: gallery.offset,
limit: gallery.limit, limit: gallery.limit,
is_intermediate: false, is_intermediate: false,
} : skipToken) }
: skipToken
); );

View File

@ -1,4 +1,3 @@
import { getStore } from 'app/store/nanostores/store'; import { getStore } from 'app/store/nanostores/store';
import type { JSONObject } from 'common/types'; import type { JSONObject } from 'common/types';
import type { BoardId } from 'features/gallery/store/types'; import type { BoardId } from 'features/gallery/store/types';
@ -13,10 +12,7 @@ import type {
ListImagesResponse, ListImagesResponse,
PostUploadAction, PostUploadAction,
} from 'services/api/types'; } from 'services/api/types';
import { import { getCategories, getListImagesUrl } from 'services/api/util';
getCategories,
getListImagesUrl,
} from 'services/api/util';
import type { ApiTagDescription } from '..'; import type { ApiTagDescription } from '..';
import { api, buildV1Url, LIST_TAG } from '..'; import { api, buildV1Url, LIST_TAG } from '..';
@ -54,7 +50,7 @@ export const imagesApi = api.injectEndpoints({
// Make the tags the same as the cache key // Make the tags the same as the cache key
{ type: 'ImageList', id: getListImagesUrl({ board_id, categories }) }, { type: 'ImageList', id: getListImagesUrl({ board_id, categories }) },
'FetchOnReconnect', 'FetchOnReconnect',
] ];
}, },
}), }),
getIntermediatesCount: build.query<number, void>({ getIntermediatesCount: build.query<number, void>({
@ -102,12 +98,9 @@ export const imagesApi = api.injectEndpoints({
id: boardId, id: boardId,
}, },
]; ];
}, },
}), }),
deleteImages: build.mutation<components['schemas']['DeleteImagesFromListResult'], { imageDTOs: ImageDTO[] }>({ deleteImages: build.mutation<components['schemas']['DeleteImagesFromListResult'], { imageDTOs: ImageDTO[] }>({
query: ({ imageDTOs }) => { query: ({ imageDTOs }) => {
const image_names = imageDTOs.map((imageDTO) => imageDTO.image_name); const image_names = imageDTOs.map((imageDTO) => imageDTO.image_name);
@ -118,17 +111,11 @@ export const imagesApi = api.injectEndpoints({
image_names, image_names,
}, },
}; };
}, },
invalidatesTags: (result, error, { imageDTOs }) => { invalidatesTags: (result, error, { imageDTOs }) => {
if (imageDTOs[0]) { if (imageDTOs[0]) {
const categories = getCategories(imageDTOs[0]); const categories = getCategories(imageDTOs[0]);
const boardId = imageDTOs[0].board_id ?? "none"; const boardId = imageDTOs[0].board_id ?? 'none';
console.log(getListImagesUrl({
board_id: boardId,
categories,
}),)
return [ return [
{ {
@ -144,9 +131,7 @@ export const imagesApi = api.injectEndpoints({
}, },
]; ];
} }
return [] return [];
}, },
}), }),
/** /**
@ -159,7 +144,6 @@ export const imagesApi = api.injectEndpoints({
body: { is_intermediate }, body: { is_intermediate },
}), }),
invalidatesTags: (result, error, { imageDTO }) => { invalidatesTags: (result, error, { imageDTO }) => {
const categories = getCategories(imageDTO); const categories = getCategories(imageDTO);
const boardId = imageDTO.board_id ?? undefined; const boardId = imageDTO.board_id ?? undefined;
@ -176,7 +160,7 @@ export const imagesApi = api.injectEndpoints({
id: boardId, id: boardId,
}, },
]; ];
} },
}), }),
/** /**
* Star a list of images. * Star a list of images.
@ -281,7 +265,6 @@ export const imagesApi = api.injectEndpoints({
}; };
}, },
invalidatesTags: (result) => { invalidatesTags: (result) => {
if (!result || result.is_intermediate) { if (!result || result.is_intermediate) {
// Don't add it to anything // Don't add it to anything
return []; return [];
@ -301,7 +284,7 @@ export const imagesApi = api.injectEndpoints({
type: 'Board', type: 'Board',
id: boardId, id: boardId,
}, },
] ];
}, },
}), }),
@ -333,9 +316,7 @@ export const imagesApi = api.injectEndpoints({
method: 'DELETE', method: 'DELETE',
params: { include_images: true }, params: { include_images: true },
}), }),
invalidatesTags: () => [ invalidatesTags: () => [{ type: 'Board', id: LIST_TAG }],
{ type: 'Board', id: LIST_TAG },
],
}), }),
addImageToBoard: build.mutation<void, { board_id: BoardId; imageDTO: ImageDTO }>({ addImageToBoard: build.mutation<void, { board_id: BoardId; imageDTO: ImageDTO }>({
query: ({ board_id, imageDTO }) => { query: ({ board_id, imageDTO }) => {
@ -359,13 +340,13 @@ export const imagesApi = api.injectEndpoints({
{ {
type: 'ImageList', type: 'ImageList',
id: getListImagesUrl({ id: getListImagesUrl({
board_id: imageDTO.board_id ?? "none", board_id: imageDTO.board_id ?? 'none',
categories: getCategories(imageDTO), categories: getCategories(imageDTO),
}), }),
}, },
{ type: 'Board', id: board_id }, { type: 'Board', id: board_id },
{ type: 'Board', id: imageDTO.board_id ?? "none" }, { type: 'Board', id: imageDTO.board_id ?? 'none' },
] ];
}, },
}), }),
removeImageFromBoard: build.mutation<void, { imageDTO: ImageDTO }>({ removeImageFromBoard: build.mutation<void, { imageDTO: ImageDTO }>({
@ -390,13 +371,13 @@ export const imagesApi = api.injectEndpoints({
{ {
type: 'ImageList', type: 'ImageList',
id: getListImagesUrl({ id: getListImagesUrl({
board_id: "none", board_id: 'none',
categories: getCategories(imageDTO), categories: getCategories(imageDTO),
}), }),
}, },
{ type: 'Board', id: imageDTO.board_id ?? "none" }, { type: 'Board', id: imageDTO.board_id ?? 'none' },
{ type: 'Board', id: "none" }, { type: 'Board', id: 'none' },
] ];
}, },
}), }),
addImagesToBoard: build.mutation< addImagesToBoard: build.mutation<
@ -415,30 +396,28 @@ export const imagesApi = api.injectEndpoints({
}, },
}), }),
invalidatesTags: (result, error, { board_id, imageDTOs }) => { invalidatesTags: (result, error, { board_id, imageDTOs }) => {
const tags: ApiTagDescription[] = [] const tags: ApiTagDescription[] = [];
console.log(imageDTOs[0])
if (imageDTOs[0]) { if (imageDTOs[0]) {
tags.push({ tags.push({
type: 'ImageList', type: 'ImageList',
id: getListImagesUrl({ id: getListImagesUrl({
board_id: imageDTOs[0].board_id ?? "none", board_id: imageDTOs[0].board_id ?? 'none',
categories: getCategories(imageDTOs[0]), categories: getCategories(imageDTOs[0]),
}), }),
}) });
tags.push({ tags.push({
type: 'ImageList', type: 'ImageList',
id: getListImagesUrl({ id: getListImagesUrl({
board_id: board_id, board_id: board_id,
categories: getCategories(imageDTOs[0]), categories: getCategories(imageDTOs[0]),
}), }),
}) });
tags.push({ type: "Board", id: imageDTOs[0].board_id ?? "none" }) tags.push({ type: 'Board', id: imageDTOs[0].board_id ?? 'none' });
} }
tags.push({ type: "Board", id: board_id }) tags.push({ type: 'Board', id: board_id });
return tags; return tags;
}, },
}), }),
removeImagesFromBoard: build.mutation< removeImagesFromBoard: build.mutation<
components['schemas']['RemoveImagesFromBoardResult'], components['schemas']['RemoveImagesFromBoardResult'],
@ -464,22 +443,22 @@ export const imagesApi = api.injectEndpoints({
board_id: imageDTOs[0].board_id, board_id: imageDTOs[0].board_id,
categories: getCategories(imageDTOs[0]), categories: getCategories(imageDTOs[0]),
}), }),
}) });
tags.push({ tags.push({
type: 'ImageList', type: 'ImageList',
id: getListImagesUrl({ id: getListImagesUrl({
board_id: "none", board_id: 'none',
categories: getCategories(imageDTOs[0]), categories: getCategories(imageDTOs[0]),
}), }),
}) });
} }
result?.removed_image_names.forEach((image_name) => { result?.removed_image_names.forEach((image_name) => {
const board_id = imageDTOs.find((i) => i.image_name === image_name)?.board_id; const board_id = imageDTOs.find((i) => i.image_name === image_name)?.board_id;
if (!board_id || touchedBoardIds.includes(board_id)) { if (!board_id || touchedBoardIds.includes(board_id)) {
tags.push({ type: 'Board', id: "none" }); tags.push({ type: 'Board', id: 'none' });
return return;
} }
tags.push({ type: 'Board', id: board_id }); tags.push({ type: 'Board', id: board_id });

View File

@ -84,9 +84,8 @@ export const imageListDefaultSort = () => {
return 1; return 1;
} }
return dateComparator(b.created_at, a.created_at); return dateComparator(b.created_at, a.created_at);
} };
};
}
// Create selectors for the adapter. // Create selectors for the adapter.
export const imagesSelectors = imagesAdapter.getSelectors(undefined, getSelectorsOptions); export const imagesSelectors = imagesAdapter.getSelectors(undefined, getSelectorsOptions);