refactor: gallery scroll

This commit is contained in:
psychedelicious
2025-06-24 15:51:28 +10:00
parent 049a8d8144
commit bee4cf41b4
13 changed files with 928 additions and 17 deletions

View File

@@ -77,7 +77,12 @@ export const imagesApi = api.injectEndpoints({
}),
clearIntermediates: build.mutation<number, void>({
query: () => ({ url: buildImagesUrl('intermediates'), method: 'DELETE' }),
invalidatesTags: ['IntermediatesCount', 'InvocationCacheStatus'],
invalidatesTags: [
'IntermediatesCount',
'InvocationCacheStatus',
'ImageCollectionCounts',
{ type: 'ImageCollection', id: LIST_TAG },
],
}),
getImageDTO: build.query<ImageDTO, string>({
query: (image_name) => ({ url: buildImagesUrl(`i/${image_name}`) }),
@@ -106,7 +111,11 @@ export const imagesApi = api.injectEndpoints({
// We ignore the deleted images when getting tags to invalidate. If we did not, we will invalidate the queries
// that fetch image DTOs, metadata, and workflows. But we have just deleted those images! Invalidating the tags
// will force those queries to re-fetch, and the requests will of course 404.
return getTagsToInvalidateForBoardAffectingMutation(result.affected_boards);
return [
...getTagsToInvalidateForBoardAffectingMutation(result.affected_boards),
'ImageCollectionCounts',
{ type: 'ImageCollection', id: LIST_TAG },
];
},
}),
deleteImages: build.mutation<
@@ -125,7 +134,11 @@ export const imagesApi = api.injectEndpoints({
// We ignore the deleted images when getting tags to invalidate. If we did not, we will invalidate the queries
// that fetch image DTOs, metadata, and workflows. But we have just deleted those images! Invalidating the tags
// will force those queries to re-fetch, and the requests will of course 404.
return getTagsToInvalidateForBoardAffectingMutation(result.affected_boards);
return [
...getTagsToInvalidateForBoardAffectingMutation(result.affected_boards),
'ImageCollectionCounts',
{ type: 'ImageCollection', id: LIST_TAG },
];
},
}),
deleteUncategorizedImages: build.mutation<
@@ -140,7 +153,11 @@ export const imagesApi = api.injectEndpoints({
// We ignore the deleted images when getting tags to invalidate. If we did not, we will invalidate the queries
// that fetch image DTOs, metadata, and workflows. But we have just deleted those images! Invalidating the tags
// will force those queries to re-fetch, and the requests will of course 404.
return getTagsToInvalidateForBoardAffectingMutation(result.affected_boards);
return [
...getTagsToInvalidateForBoardAffectingMutation(result.affected_boards),
'ImageCollectionCounts',
{ type: 'ImageCollection', id: LIST_TAG },
];
},
}),
/**
@@ -184,6 +201,8 @@ export const imagesApi = api.injectEndpoints({
return [
...getTagsToInvalidateForImageMutation(result.starred_images),
...getTagsToInvalidateForBoardAffectingMutation(result.affected_boards),
'ImageCollectionCounts',
{ type: 'ImageCollection', id: LIST_TAG },
];
},
}),
@@ -206,6 +225,8 @@ export const imagesApi = api.injectEndpoints({
return [
...getTagsToInvalidateForImageMutation(result.unstarred_images),
...getTagsToInvalidateForBoardAffectingMutation(result.affected_boards),
'ImageCollectionCounts',
{ type: 'ImageCollection', id: LIST_TAG },
];
},
}),
@@ -399,6 +420,52 @@ export const imagesApi = api.injectEndpoints({
},
}),
}),
/**
* Get counts for starred and unstarred image collections
*/
getImageCollectionCounts: build.query<
paths['/api/v1/images/collections/counts']['get']['responses']['200']['content']['application/json'],
paths['/api/v1/images/collections/counts']['get']['parameters']['query']
>({
query: (queryArgs) => ({
url: buildImagesUrl('collections/counts'),
method: 'GET',
params: queryArgs,
}),
providesTags: ['ImageCollectionCounts', 'FetchOnReconnect'],
}),
/**
* Get images from a specific collection (starred or unstarred)
*/
getImageCollection: build.query<
paths['/api/v1/images/collections/{collection}']['get']['responses']['200']['content']['application/json'],
paths['/api/v1/images/collections/{collection}']['get']['parameters']['path'] &
paths['/api/v1/images/collections/{collection}']['get']['parameters']['query']
>({
query: ({ collection, ...queryArgs }) => ({
url: buildImagesUrl(`collections/${collection}`),
method: 'GET',
params: queryArgs,
}),
providesTags: (result, error, { collection, board_id, categories }) => {
const cacheKey = `${collection}-${board_id || 'all'}-${categories?.join(',') || 'all'}`;
return [{ type: 'ImageCollection', id: cacheKey }, 'FetchOnReconnect'];
},
async onQueryStarted(_, { dispatch, queryFulfilled }) {
// Populate the getImageDTO cache with these images, similar to listImages
const res = await queryFulfilled;
const imageDTOs = res.data.items;
const updates: Param0<typeof imagesApi.util.upsertQueryEntries> = [];
for (const imageDTO of imageDTOs) {
updates.push({
endpointName: 'getImageDTO',
arg: imageDTO.image_name,
value: imageDTO,
});
}
dispatch(imagesApi.util.upsertQueryEntries(updates));
},
}),
}),
});
@@ -420,6 +487,9 @@ export const {
useStarImagesMutation,
useUnstarImagesMutation,
useBulkDownloadImagesMutation,
useGetImageCollectionCountsQuery,
useGetImageCollectionQuery,
useLazyGetImageCollectionQuery,
} = imagesApi;
/**

View File

@@ -23,6 +23,8 @@ const tagTypes = [
'ImageList',
'ImageMetadata',
'ImageWorkflow',
'ImageCollectionCounts',
'ImageCollection',
'ImageMetadataFromFile',
'IntermediatesCount',
'SessionQueueItem',

View File

@@ -752,6 +752,46 @@ export type paths = {
patch?: never;
trace?: never;
};
"/api/v1/images/collections/counts": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get Image Collection Counts
* @description Gets counts for starred and unstarred image collections
*/
get: operations["get_image_collection_counts"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/images/collections/{collection}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get Image Collection
* @description Gets images from a specific collection (starred or unstarred)
*/
get: operations["get_image_collection"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/boards/": {
parameters: {
query?: never;
@@ -23675,6 +23715,97 @@ export interface operations {
};
};
};
get_image_collection_counts: {
parameters: {
query?: {
/** @description The origin of images to count. */
image_origin?: components["schemas"]["ResourceOrigin"] | null;
/** @description The categories of image to include. */
categories?: components["schemas"]["ImageCategory"][] | null;
/** @description Whether to include intermediate images. */
is_intermediate?: boolean | null;
/** @description The board id to filter by. Use 'none' to find images without a board. */
board_id?: string | null;
/** @description The term to search for */
search_term?: string | null;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": {
[key: string]: number;
};
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_image_collection: {
parameters: {
query?: {
/** @description The origin of images to list. */
image_origin?: components["schemas"]["ResourceOrigin"] | null;
/** @description The categories of image to include. */
categories?: components["schemas"]["ImageCategory"][] | null;
/** @description Whether to list intermediate images. */
is_intermediate?: boolean | null;
/** @description The board id to filter by. Use 'none' to find images without a board. */
board_id?: string | null;
/** @description The offset within the collection */
offset?: number;
/** @description The number of images to return */
limit?: number;
/** @description The order of sort */
order_dir?: components["schemas"]["SQLiteDirection"];
/** @description The term to search for */
search_term?: string | null;
};
header?: never;
path: {
/** @description The collection to retrieve from */
collection: "starred" | "unstarred";
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["OffsetPaginatedResults_ImageDTO_"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
list_boards: {
parameters: {
query?: {