mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-14 17:35:11 -05:00
281 lines
8.3 KiB
TypeScript
281 lines
8.3 KiB
TypeScript
import { Update } from '@reduxjs/toolkit';
|
|
import {
|
|
ASSETS_CATEGORIES,
|
|
IMAGE_CATEGORIES,
|
|
} from 'features/gallery/store/types';
|
|
import {
|
|
BoardDTO,
|
|
ImageDTO,
|
|
OffsetPaginatedResults_BoardDTO_,
|
|
} from 'services/api/types';
|
|
import { ApiFullTagDescription, LIST_TAG, api } from '..';
|
|
import { paths } from '../schema';
|
|
import { getListImagesUrl, imagesAdapter, imagesApi } from './images';
|
|
|
|
type ListBoardsArg = NonNullable<
|
|
paths['/api/v1/boards/']['get']['parameters']['query']
|
|
>;
|
|
|
|
type UpdateBoardArg =
|
|
paths['/api/v1/boards/{board_id}']['patch']['parameters']['path'] & {
|
|
changes: paths['/api/v1/boards/{board_id}']['patch']['requestBody']['content']['application/json'];
|
|
};
|
|
|
|
type DeleteBoardResult =
|
|
paths['/api/v1/boards/{board_id}']['delete']['responses']['200']['content']['application/json'];
|
|
|
|
export const boardsApi = api.injectEndpoints({
|
|
endpoints: (build) => ({
|
|
/**
|
|
* Boards Queries
|
|
*/
|
|
listBoards: build.query<OffsetPaginatedResults_BoardDTO_, ListBoardsArg>({
|
|
query: (arg) => ({ url: 'boards/', params: arg }),
|
|
providesTags: (result, error, arg) => {
|
|
// any list of boards
|
|
const tags: ApiFullTagDescription[] = [{ type: 'Board', id: LIST_TAG }];
|
|
|
|
if (result) {
|
|
// and individual tags for each board
|
|
tags.push(
|
|
...result.items.map(({ board_id }) => ({
|
|
type: 'Board' as const,
|
|
id: board_id,
|
|
}))
|
|
);
|
|
}
|
|
|
|
return tags;
|
|
},
|
|
}),
|
|
|
|
listAllBoards: build.query<Array<BoardDTO>, void>({
|
|
query: () => ({
|
|
url: 'boards/',
|
|
params: { all: true },
|
|
}),
|
|
providesTags: (result, error, arg) => {
|
|
// any list of boards
|
|
const tags: ApiFullTagDescription[] = [{ type: 'Board', id: LIST_TAG }];
|
|
|
|
if (result) {
|
|
// and individual tags for each board
|
|
tags.push(
|
|
...result.map(({ board_id }) => ({
|
|
type: 'Board' as const,
|
|
id: board_id,
|
|
}))
|
|
);
|
|
}
|
|
|
|
return tags;
|
|
},
|
|
}),
|
|
|
|
listAllImageNamesForBoard: build.query<Array<string>, string>({
|
|
query: (board_id) => ({
|
|
url: `boards/${board_id}/image_names`,
|
|
}),
|
|
providesTags: (result, error, arg) => [
|
|
{ type: 'ImageNameList', id: arg },
|
|
],
|
|
keepUnusedDataFor: 0,
|
|
}),
|
|
|
|
/**
|
|
* Boards Mutations
|
|
*/
|
|
|
|
createBoard: build.mutation<BoardDTO, string>({
|
|
query: (board_name) => ({
|
|
url: `boards/`,
|
|
method: 'POST',
|
|
params: { board_name },
|
|
}),
|
|
invalidatesTags: [{ type: 'Board', id: LIST_TAG }],
|
|
}),
|
|
|
|
updateBoard: build.mutation<BoardDTO, UpdateBoardArg>({
|
|
query: ({ board_id, changes }) => ({
|
|
url: `boards/${board_id}`,
|
|
method: 'PATCH',
|
|
body: changes,
|
|
}),
|
|
invalidatesTags: (result, error, arg) => [
|
|
{ type: 'Board', id: arg.board_id },
|
|
],
|
|
}),
|
|
|
|
deleteBoard: build.mutation<DeleteBoardResult, string>({
|
|
query: (board_id) => ({ url: `boards/${board_id}`, method: 'DELETE' }),
|
|
invalidatesTags: (result, error, board_id) => [
|
|
{ type: 'Board', id: LIST_TAG },
|
|
// invalidate the 'No Board' cache
|
|
{
|
|
type: 'ImageList',
|
|
id: getListImagesUrl({
|
|
board_id: 'none',
|
|
categories: IMAGE_CATEGORIES,
|
|
}),
|
|
},
|
|
{
|
|
type: 'ImageList',
|
|
id: getListImagesUrl({
|
|
board_id: 'none',
|
|
categories: ASSETS_CATEGORIES,
|
|
}),
|
|
},
|
|
{ type: 'BoardImagesTotal', id: 'none' },
|
|
{ type: 'BoardAssetsTotal', id: 'none' },
|
|
],
|
|
async onQueryStarted(board_id, { dispatch, queryFulfilled, getState }) {
|
|
/**
|
|
* Cache changes for deleteBoard:
|
|
* - Update every image in the 'getImageDTO' cache that has the board_id
|
|
* - Update every image in the 'All Images' cache that has the board_id
|
|
* - Update every image in the 'All Assets' cache that has the board_id
|
|
* - Invalidate the 'No Board' cache:
|
|
* Ideally we'd be able to insert all deleted images into the cache, but we don't
|
|
* have access to the deleted images DTOs - only the names, and a network request
|
|
* for all of a board's DTOs could be very large. Instead, we invalidate the 'No Board'
|
|
* cache.
|
|
*/
|
|
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const { deleted_board_images } = data;
|
|
|
|
// update getImageDTO caches
|
|
deleted_board_images.forEach((image_id) => {
|
|
dispatch(
|
|
imagesApi.util.updateQueryData(
|
|
'getImageDTO',
|
|
image_id,
|
|
(draft) => {
|
|
draft.board_id = undefined;
|
|
}
|
|
)
|
|
);
|
|
});
|
|
|
|
// update 'All Images' & 'All Assets' caches
|
|
const queryArgsToUpdate = [
|
|
{
|
|
categories: IMAGE_CATEGORIES,
|
|
},
|
|
{
|
|
categories: ASSETS_CATEGORIES,
|
|
},
|
|
];
|
|
|
|
const updates: Update<ImageDTO>[] = deleted_board_images.map(
|
|
(image_name) => ({
|
|
id: image_name,
|
|
changes: { board_id: undefined },
|
|
})
|
|
);
|
|
|
|
queryArgsToUpdate.forEach((queryArgs) => {
|
|
dispatch(
|
|
imagesApi.util.updateQueryData(
|
|
'listImages',
|
|
queryArgs,
|
|
(draft) => {
|
|
const oldTotal = draft.total;
|
|
const newState = imagesAdapter.updateMany(draft, updates);
|
|
const delta = newState.total - oldTotal;
|
|
draft.total = draft.total + delta;
|
|
}
|
|
)
|
|
);
|
|
});
|
|
} catch {
|
|
//no-op
|
|
}
|
|
},
|
|
}),
|
|
|
|
deleteBoardAndImages: build.mutation<DeleteBoardResult, string>({
|
|
query: (board_id) => ({
|
|
url: `boards/${board_id}`,
|
|
method: 'DELETE',
|
|
params: { include_images: true },
|
|
}),
|
|
invalidatesTags: (result, error, board_id) => [
|
|
{ type: 'Board', id: LIST_TAG },
|
|
{
|
|
type: 'ImageList',
|
|
id: getListImagesUrl({
|
|
board_id: 'none',
|
|
categories: IMAGE_CATEGORIES,
|
|
}),
|
|
},
|
|
{
|
|
type: 'ImageList',
|
|
id: getListImagesUrl({
|
|
board_id: 'none',
|
|
categories: ASSETS_CATEGORIES,
|
|
}),
|
|
},
|
|
{ type: 'BoardImagesTotal', id: 'none' },
|
|
{ type: 'BoardAssetsTotal', id: 'none' },
|
|
],
|
|
async onQueryStarted(board_id, { dispatch, queryFulfilled, getState }) {
|
|
/**
|
|
* Cache changes for deleteBoardAndImages:
|
|
* - ~~Remove every image in the 'getImageDTO' cache that has the board_id~~
|
|
* This isn't actually possible, you cannot remove cache entries with RTK Query.
|
|
* Instead, we rely on the UI to remove all components that use the deleted images.
|
|
* - Remove every image in the 'All Images' cache that has the board_id
|
|
* - Remove every image in the 'All Assets' cache that has the board_id
|
|
*/
|
|
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const { deleted_images } = data;
|
|
|
|
// update 'All Images' & 'All Assets' caches
|
|
const queryArgsToUpdate = [
|
|
{
|
|
categories: IMAGE_CATEGORIES,
|
|
},
|
|
{
|
|
categories: ASSETS_CATEGORIES,
|
|
},
|
|
];
|
|
|
|
queryArgsToUpdate.forEach((queryArgs) => {
|
|
dispatch(
|
|
imagesApi.util.updateQueryData(
|
|
'listImages',
|
|
queryArgs,
|
|
(draft) => {
|
|
const oldTotal = draft.total;
|
|
const newState = imagesAdapter.removeMany(
|
|
draft,
|
|
deleted_images
|
|
);
|
|
const delta = newState.total - oldTotal;
|
|
draft.total = draft.total + delta;
|
|
}
|
|
)
|
|
);
|
|
});
|
|
} catch {
|
|
//no-op
|
|
}
|
|
},
|
|
}),
|
|
}),
|
|
});
|
|
|
|
export const {
|
|
useListBoardsQuery,
|
|
useListAllBoardsQuery,
|
|
useCreateBoardMutation,
|
|
useUpdateBoardMutation,
|
|
useDeleteBoardMutation,
|
|
useDeleteBoardAndImagesMutation,
|
|
useListAllImageNamesForBoardQuery,
|
|
} = boardsApi;
|