refactor(ui): url builders for each router

The MM2 router is at `api/v2/models`. URL builder utils make this a bit easier to manage.
This commit is contained in:
psychedelicious 2024-02-16 21:57:30 +11:00 committed by Brandon Rising
parent 527f76250a
commit eb27951b8c
12 changed files with 177 additions and 102 deletions

View File

@ -3,27 +3,35 @@ import type { OpenAPIV3_1 } from 'openapi-types';
import type { paths } from 'services/api/schema'; import type { paths } from 'services/api/schema';
import type { AppConfig, AppDependencyVersions, AppVersion } from 'services/api/types'; import type { AppConfig, AppDependencyVersions, AppVersion } from 'services/api/types';
import { api } from '..'; import { api, buildV1Url } from '..';
/**
* Builds an endpoint URL for the app router
* @example
* buildAppInfoUrl('some-path')
* // '/api/v1/app/some-path'
*/
const buildAppInfoUrl = (path: string = '') => buildV1Url(`app/${path}`);
export const appInfoApi = api.injectEndpoints({ export const appInfoApi = api.injectEndpoints({
endpoints: (build) => ({ endpoints: (build) => ({
getAppVersion: build.query<AppVersion, void>({ getAppVersion: build.query<AppVersion, void>({
query: () => ({ query: () => ({
url: `app/version`, url: buildAppInfoUrl('version'),
method: 'GET', method: 'GET',
}), }),
providesTags: ['FetchOnReconnect'], providesTags: ['FetchOnReconnect'],
}), }),
getAppDeps: build.query<AppDependencyVersions, void>({ getAppDeps: build.query<AppDependencyVersions, void>({
query: () => ({ query: () => ({
url: `app/app_deps`, url: buildAppInfoUrl('app_deps'),
method: 'GET', method: 'GET',
}), }),
providesTags: ['FetchOnReconnect'], providesTags: ['FetchOnReconnect'],
}), }),
getAppConfig: build.query<AppConfig, void>({ getAppConfig: build.query<AppConfig, void>({
query: () => ({ query: () => ({
url: `app/config`, url: buildAppInfoUrl('config'),
method: 'GET', method: 'GET',
}), }),
providesTags: ['FetchOnReconnect'], providesTags: ['FetchOnReconnect'],
@ -33,28 +41,28 @@ export const appInfoApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `app/invocation_cache/status`, url: buildAppInfoUrl('invocation_cache/status'),
method: 'GET', method: 'GET',
}), }),
providesTags: ['InvocationCacheStatus', 'FetchOnReconnect'], providesTags: ['InvocationCacheStatus', 'FetchOnReconnect'],
}), }),
clearInvocationCache: build.mutation<void, void>({ clearInvocationCache: build.mutation<void, void>({
query: () => ({ query: () => ({
url: `app/invocation_cache`, url: buildAppInfoUrl('invocation_cache'),
method: 'DELETE', method: 'DELETE',
}), }),
invalidatesTags: ['InvocationCacheStatus'], invalidatesTags: ['InvocationCacheStatus'],
}), }),
enableInvocationCache: build.mutation<void, void>({ enableInvocationCache: build.mutation<void, void>({
query: () => ({ query: () => ({
url: `app/invocation_cache/enable`, url: buildAppInfoUrl('invocation_cache/enable'),
method: 'PUT', method: 'PUT',
}), }),
invalidatesTags: ['InvocationCacheStatus'], invalidatesTags: ['InvocationCacheStatus'],
}), }),
disableInvocationCache: build.mutation<void, void>({ disableInvocationCache: build.mutation<void, void>({
query: () => ({ query: () => ({
url: `app/invocation_cache/disable`, url: buildAppInfoUrl('invocation_cache/disable'),
method: 'PUT', method: 'PUT',
}), }),
invalidatesTags: ['InvocationCacheStatus'], invalidatesTags: ['InvocationCacheStatus'],

View File

@ -9,7 +9,15 @@ import type {
import { getListImagesUrl } from 'services/api/util'; import { getListImagesUrl } from 'services/api/util';
import type { ApiTagDescription } from '..'; import type { ApiTagDescription } from '..';
import { api, LIST_TAG } from '..'; import { api, buildV1Url, LIST_TAG } from '..';
/**
* Builds an endpoint URL for the boards router
* @example
* buildBoardsUrl('some-path')
* // '/api/v1/boards/some-path'
*/
export const buildBoardsUrl = (path: string = '') => buildV1Url(`boards/${path}`);
export const boardsApi = api.injectEndpoints({ export const boardsApi = api.injectEndpoints({
endpoints: (build) => ({ endpoints: (build) => ({
@ -17,7 +25,7 @@ export const boardsApi = api.injectEndpoints({
* Boards Queries * Boards Queries
*/ */
listBoards: build.query<OffsetPaginatedResults_BoardDTO_, ListBoardsArg>({ listBoards: build.query<OffsetPaginatedResults_BoardDTO_, ListBoardsArg>({
query: (arg) => ({ url: 'boards/', params: arg }), query: (arg) => ({ url: buildBoardsUrl(), params: arg }),
providesTags: (result) => { providesTags: (result) => {
// any list of boards // any list of boards
const tags: ApiTagDescription[] = [{ type: 'Board', id: LIST_TAG }, 'FetchOnReconnect']; const tags: ApiTagDescription[] = [{ type: 'Board', id: LIST_TAG }, 'FetchOnReconnect'];
@ -38,7 +46,7 @@ export const boardsApi = api.injectEndpoints({
listAllBoards: build.query<Array<BoardDTO>, void>({ listAllBoards: build.query<Array<BoardDTO>, void>({
query: () => ({ query: () => ({
url: 'boards/', url: buildBoardsUrl(),
params: { all: true }, params: { all: true },
}), }),
providesTags: (result) => { providesTags: (result) => {
@ -61,7 +69,7 @@ export const boardsApi = api.injectEndpoints({
listAllImageNamesForBoard: build.query<Array<string>, string>({ listAllImageNamesForBoard: build.query<Array<string>, string>({
query: (board_id) => ({ query: (board_id) => ({
url: `boards/${board_id}/image_names`, url: buildBoardsUrl(`${board_id}/image_names`),
}), }),
providesTags: (result, error, arg) => [{ type: 'ImageNameList', id: arg }, 'FetchOnReconnect'], providesTags: (result, error, arg) => [{ type: 'ImageNameList', id: arg }, 'FetchOnReconnect'],
keepUnusedDataFor: 0, keepUnusedDataFor: 0,
@ -107,7 +115,7 @@ export const boardsApi = api.injectEndpoints({
createBoard: build.mutation<BoardDTO, string>({ createBoard: build.mutation<BoardDTO, string>({
query: (board_name) => ({ query: (board_name) => ({
url: `boards/`, url: buildBoardsUrl(),
method: 'POST', method: 'POST',
params: { board_name }, params: { board_name },
}), }),
@ -116,7 +124,7 @@ export const boardsApi = api.injectEndpoints({
updateBoard: build.mutation<BoardDTO, UpdateBoardArg>({ updateBoard: build.mutation<BoardDTO, UpdateBoardArg>({
query: ({ board_id, changes }) => ({ query: ({ board_id, changes }) => ({
url: `boards/${board_id}`, url: buildBoardsUrl(board_id),
method: 'PATCH', method: 'PATCH',
body: changes, body: changes,
}), }),

View File

@ -26,8 +26,24 @@ import {
} from 'services/api/util'; } from 'services/api/util';
import type { ApiTagDescription } from '..'; import type { ApiTagDescription } from '..';
import { api, LIST_TAG } from '..'; import { api, buildV1Url, LIST_TAG } from '..';
import { boardsApi } from './boards'; import { boardsApi, buildBoardsUrl } from './boards';
/**
* Builds an endpoint URL for the images router
* @example
* buildImagesUrl('some-path')
* // '/api/v1/images/some-path'
*/
const buildImagesUrl = (path: string = '') => buildV1Url(`images/${path}`);
/**
* Builds an endpoint URL for the board_images router
* @example
* buildBoardImagesUrl('some-path')
* // '/api/v1/board_images/some-path'
*/
const buildBoardImagesUrl = (path: string = '') => buildV1Url(`board_images/${path}`);
export const imagesApi = api.injectEndpoints({ export const imagesApi = api.injectEndpoints({
endpoints: (build) => ({ endpoints: (build) => ({
@ -90,20 +106,20 @@ export const imagesApi = api.injectEndpoints({
keepUnusedDataFor: 86400, keepUnusedDataFor: 86400,
}), }),
getIntermediatesCount: build.query<number, void>({ getIntermediatesCount: build.query<number, void>({
query: () => ({ url: 'images/intermediates' }), query: () => ({ url: buildImagesUrl('intermediates') }),
providesTags: ['IntermediatesCount', 'FetchOnReconnect'], providesTags: ['IntermediatesCount', 'FetchOnReconnect'],
}), }),
clearIntermediates: build.mutation<number, void>({ clearIntermediates: build.mutation<number, void>({
query: () => ({ url: `images/intermediates`, method: 'DELETE' }), query: () => ({ url: buildImagesUrl('intermediates'), method: 'DELETE' }),
invalidatesTags: ['IntermediatesCount'], invalidatesTags: ['IntermediatesCount'],
}), }),
getImageDTO: build.query<ImageDTO, string>({ getImageDTO: build.query<ImageDTO, string>({
query: (image_name) => ({ url: `images/i/${image_name}` }), query: (image_name) => ({ url: buildImagesUrl(`i/${image_name}`) }),
providesTags: (result, error, image_name) => [{ type: 'Image', id: image_name }], providesTags: (result, error, image_name) => [{ type: 'Image', id: image_name }],
keepUnusedDataFor: 86400, // 24 hours keepUnusedDataFor: 86400, // 24 hours
}), }),
getImageMetadata: build.query<CoreMetadata | undefined, string>({ getImageMetadata: build.query<CoreMetadata | undefined, string>({
query: (image_name) => ({ url: `images/i/${image_name}/metadata` }), query: (image_name) => ({ url: buildImagesUrl(`i/${image_name}/metadata`) }),
providesTags: (result, error, image_name) => [{ type: 'ImageMetadata', id: image_name }], providesTags: (result, error, image_name) => [{ type: 'ImageMetadata', id: image_name }],
transformResponse: ( transformResponse: (
response: paths['/api/v1/images/i/{image_name}/metadata']['get']['responses']['200']['content']['application/json'] response: paths['/api/v1/images/i/{image_name}/metadata']['get']['responses']['200']['content']['application/json']
@ -130,7 +146,7 @@ export const imagesApi = api.injectEndpoints({
}), }),
deleteImage: build.mutation<void, ImageDTO>({ deleteImage: build.mutation<void, ImageDTO>({
query: ({ image_name }) => ({ query: ({ image_name }) => ({
url: `images/i/${image_name}`, url: buildImagesUrl(`i/${image_name}`),
method: 'DELETE', method: 'DELETE',
}), }),
async onQueryStarted(imageDTO, { dispatch, queryFulfilled }) { async onQueryStarted(imageDTO, { dispatch, queryFulfilled }) {
@ -185,7 +201,7 @@ export const imagesApi = api.injectEndpoints({
query: ({ imageDTOs }) => { query: ({ imageDTOs }) => {
const image_names = imageDTOs.map((imageDTO) => imageDTO.image_name); const image_names = imageDTOs.map((imageDTO) => imageDTO.image_name);
return { return {
url: `images/delete`, url: buildImagesUrl('delete'),
method: 'POST', method: 'POST',
body: { body: {
image_names, image_names,
@ -258,7 +274,7 @@ export const imagesApi = api.injectEndpoints({
*/ */
changeImageIsIntermediate: build.mutation<ImageDTO, { imageDTO: ImageDTO; is_intermediate: boolean }>({ changeImageIsIntermediate: build.mutation<ImageDTO, { imageDTO: ImageDTO; is_intermediate: boolean }>({
query: ({ imageDTO, is_intermediate }) => ({ query: ({ imageDTO, is_intermediate }) => ({
url: `images/i/${imageDTO.image_name}`, url: buildImagesUrl(`i/${imageDTO.image_name}`),
method: 'PATCH', method: 'PATCH',
body: { is_intermediate }, body: { is_intermediate },
}), }),
@ -380,7 +396,7 @@ export const imagesApi = api.injectEndpoints({
*/ */
changeImageSessionId: build.mutation<ImageDTO, { imageDTO: ImageDTO; session_id: string }>({ changeImageSessionId: build.mutation<ImageDTO, { imageDTO: ImageDTO; session_id: string }>({
query: ({ imageDTO, session_id }) => ({ query: ({ imageDTO, session_id }) => ({
url: `images/i/${imageDTO.image_name}`, url: buildImagesUrl(`i/${imageDTO.image_name}`),
method: 'PATCH', method: 'PATCH',
body: { session_id }, body: { session_id },
}), }),
@ -417,7 +433,7 @@ export const imagesApi = api.injectEndpoints({
{ imageDTOs: ImageDTO[] } { imageDTOs: ImageDTO[] }
>({ >({
query: ({ imageDTOs: images }) => ({ query: ({ imageDTOs: images }) => ({
url: `images/star`, url: buildImagesUrl('star'),
method: 'POST', method: 'POST',
body: { image_names: images.map((img) => img.image_name) }, body: { image_names: images.map((img) => img.image_name) },
}), }),
@ -511,7 +527,7 @@ export const imagesApi = api.injectEndpoints({
{ imageDTOs: ImageDTO[] } { imageDTOs: ImageDTO[] }
>({ >({
query: ({ imageDTOs: images }) => ({ query: ({ imageDTOs: images }) => ({
url: `images/unstar`, url: buildImagesUrl('unstar'),
method: 'POST', method: 'POST',
body: { image_names: images.map((img) => img.image_name) }, body: { image_names: images.map((img) => img.image_name) },
}), }),
@ -611,7 +627,7 @@ export const imagesApi = api.injectEndpoints({
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
return { return {
url: `images/upload`, url: buildImagesUrl('upload'),
method: 'POST', method: 'POST',
body: formData, body: formData,
params: { params: {
@ -674,7 +690,7 @@ export const imagesApi = api.injectEndpoints({
}), }),
deleteBoard: build.mutation<DeleteBoardResult, string>({ deleteBoard: build.mutation<DeleteBoardResult, string>({
query: (board_id) => ({ url: `boards/${board_id}`, method: 'DELETE' }), query: (board_id) => ({ url: buildBoardsUrl(board_id), method: 'DELETE' }),
invalidatesTags: () => [ invalidatesTags: () => [
{ type: 'Board', id: LIST_TAG }, { type: 'Board', id: LIST_TAG },
// invalidate the 'No Board' cache // invalidate the 'No Board' cache
@ -764,7 +780,7 @@ export const imagesApi = api.injectEndpoints({
deleteBoardAndImages: build.mutation<DeleteBoardResult, string>({ deleteBoardAndImages: build.mutation<DeleteBoardResult, string>({
query: (board_id) => ({ query: (board_id) => ({
url: `boards/${board_id}`, url: buildBoardsUrl(board_id),
method: 'DELETE', method: 'DELETE',
params: { include_images: true }, params: { include_images: true },
}), }),
@ -840,7 +856,7 @@ export const imagesApi = api.injectEndpoints({
query: ({ board_id, imageDTO }) => { query: ({ board_id, imageDTO }) => {
const { image_name } = imageDTO; const { image_name } = imageDTO;
return { return {
url: `board_images/`, url: buildBoardImagesUrl(),
method: 'POST', method: 'POST',
body: { board_id, image_name }, body: { board_id, image_name },
}; };
@ -961,7 +977,7 @@ export const imagesApi = api.injectEndpoints({
query: ({ imageDTO }) => { query: ({ imageDTO }) => {
const { image_name } = imageDTO; const { image_name } = imageDTO;
return { return {
url: `board_images/`, url: buildBoardImagesUrl(),
method: 'DELETE', method: 'DELETE',
body: { image_name }, body: { image_name },
}; };
@ -1080,7 +1096,7 @@ export const imagesApi = api.injectEndpoints({
} }
>({ >({
query: ({ board_id, imageDTOs }) => ({ query: ({ board_id, imageDTOs }) => ({
url: `board_images/batch`, url: buildBoardImagesUrl('batch'),
method: 'POST', method: 'POST',
body: { body: {
image_names: imageDTOs.map((i) => i.image_name), image_names: imageDTOs.map((i) => i.image_name),
@ -1197,7 +1213,7 @@ export const imagesApi = api.injectEndpoints({
} }
>({ >({
query: ({ imageDTOs }) => ({ query: ({ imageDTOs }) => ({
url: `board_images/batch/delete`, url: buildBoardImagesUrl('batch/delete'),
method: 'POST', method: 'POST',
body: { body: {
image_names: imageDTOs.map((i) => i.image_name), image_names: imageDTOs.map((i) => i.image_name),
@ -1321,7 +1337,7 @@ export const imagesApi = api.injectEndpoints({
components['schemas']['Body_download_images_from_list'] components['schemas']['Body_download_images_from_list']
>({ >({
query: ({ image_names, board_id }) => ({ query: ({ image_names, board_id }) => ({
url: `images/download`, url: buildImagesUrl('download'),
method: 'POST', method: 'POST',
body: { body: {
image_names, image_names,

View File

@ -19,7 +19,10 @@ import type {
} from 'services/api/types'; } from 'services/api/types';
import type { ApiTagDescription, tagTypes } from '..'; import type { ApiTagDescription, tagTypes } from '..';
import { api, LIST_TAG } from '..'; import { api, buildV2Url, LIST_TAG } from '..';
/* eslint-disable @typescript-eslint/no-explicit-any */
export const getModelId = (input: any): any => input;
type UpdateMainModelArg = { type UpdateMainModelArg = {
base_model: BaseModelType; base_model: BaseModelType;
@ -36,6 +39,8 @@ type UpdateLoRAModelArg = {
type UpdateMainModelResponse = type UpdateMainModelResponse =
paths['/api/v2/models/i/{key}']['patch']['responses']['200']['content']['application/json']; paths['/api/v2/models/i/{key}']['patch']['responses']['200']['content']['application/json'];
type ListModelsArg = NonNullable<paths['/api/models_v2/']['get']['parameters']['query']>;
type UpdateLoRAModelResponse = UpdateMainModelResponse; type UpdateLoRAModelResponse = UpdateMainModelResponse;
type DeleteMainModelArg = { type DeleteMainModelArg = {
@ -152,17 +157,25 @@ const buildTransformResponse =
return adapter.setAll(adapter.getInitialState(), response.models); return adapter.setAll(adapter.getInitialState(), response.models);
}; };
/**
* Builds an endpoint URL for the models router
* @example
* buildModelsUrl('some-path')
* // '/api/v1/models/some-path'
*/
const buildModelsUrl = (path: string = '') => buildV2Url(`models/${path}`);
export const modelsApi = api.injectEndpoints({ export const modelsApi = api.injectEndpoints({
endpoints: (build) => ({ endpoints: (build) => ({
getMainModels: build.query<EntityState<MainModelConfig, string>, BaseModelType[]>({ getMainModels: build.query<EntityState<MainModelConfig, string>, BaseModelType[]>({
query: (base_models) => { query: (base_models) => {
const params = { const params: ListModelsArg = {
model_type: 'main', model_type: 'main',
base_models, base_models,
}; };
const query = queryString.stringify(params, { arrayFormat: 'none' }); const query = queryString.stringify(params, { arrayFormat: 'none' });
return `models/?${query}`; return buildModelsUrl(`?${query}`);
}, },
providesTags: buildProvidesTags<MainModelConfig>('MainModel'), providesTags: buildProvidesTags<MainModelConfig>('MainModel'),
transformResponse: buildTransformResponse<MainModelConfig>(mainModelsAdapter), transformResponse: buildTransformResponse<MainModelConfig>(mainModelsAdapter),
@ -170,7 +183,7 @@ export const modelsApi = api.injectEndpoints({
updateMainModels: build.mutation<UpdateMainModelResponse, UpdateMainModelArg>({ updateMainModels: build.mutation<UpdateMainModelResponse, UpdateMainModelArg>({
query: ({ base_model, model_name, body }) => { query: ({ base_model, model_name, body }) => {
return { return {
url: `models/${base_model}/main/${model_name}`, url: buildModelsUrl(`${base_model}/main/${model_name}`),
method: 'PATCH', method: 'PATCH',
body: body, body: body,
}; };
@ -180,7 +193,7 @@ export const modelsApi = api.injectEndpoints({
importMainModels: build.mutation<ImportMainModelResponse, ImportMainModelArg>({ importMainModels: build.mutation<ImportMainModelResponse, ImportMainModelArg>({
query: ({ body }) => { query: ({ body }) => {
return { return {
url: `models/import`, url: buildModelsUrl('import'),
method: 'POST', method: 'POST',
body: body, body: body,
}; };
@ -190,7 +203,7 @@ export const modelsApi = api.injectEndpoints({
addMainModels: build.mutation<AddMainModelResponse, AddMainModelArg>({ addMainModels: build.mutation<AddMainModelResponse, AddMainModelArg>({
query: ({ body }) => { query: ({ body }) => {
return { return {
url: `models/add`, url: buildModelsUrl('add'),
method: 'POST', method: 'POST',
body: body, body: body,
}; };
@ -200,7 +213,7 @@ export const modelsApi = api.injectEndpoints({
deleteMainModels: build.mutation<DeleteMainModelResponse, DeleteMainModelArg>({ deleteMainModels: build.mutation<DeleteMainModelResponse, DeleteMainModelArg>({
query: ({ base_model, model_name, model_type }) => { query: ({ base_model, model_name, model_type }) => {
return { return {
url: `models/${base_model}/${model_type}/${model_name}`, url: buildModelsUrl(`${base_model}/${model_type}/${model_name}`),
method: 'DELETE', method: 'DELETE',
}; };
}, },
@ -209,7 +222,7 @@ export const modelsApi = api.injectEndpoints({
convertMainModels: build.mutation<ConvertMainModelResponse, ConvertMainModelArg>({ convertMainModels: build.mutation<ConvertMainModelResponse, ConvertMainModelArg>({
query: ({ base_model, model_name, convert_dest_directory }) => { query: ({ base_model, model_name, convert_dest_directory }) => {
return { return {
url: `models/convert/${base_model}/main/${model_name}`, url: buildModelsUrl(`convert/${base_model}/main/${model_name}`),
method: 'PUT', method: 'PUT',
params: { convert_dest_directory }, params: { convert_dest_directory },
}; };
@ -219,7 +232,7 @@ export const modelsApi = api.injectEndpoints({
mergeMainModels: build.mutation<MergeMainModelResponse, MergeMainModelArg>({ mergeMainModels: build.mutation<MergeMainModelResponse, MergeMainModelArg>({
query: ({ base_model, body }) => { query: ({ base_model, body }) => {
return { return {
url: `models/merge/${base_model}`, url: buildModelsUrl(`merge/${base_model}`),
method: 'PUT', method: 'PUT',
body: body, body: body,
}; };
@ -229,21 +242,21 @@ export const modelsApi = api.injectEndpoints({
syncModels: build.mutation<SyncModelsResponse, void>({ syncModels: build.mutation<SyncModelsResponse, void>({
query: () => { query: () => {
return { return {
url: `models/sync`, url: buildModelsUrl('sync'),
method: 'POST', method: 'POST',
}; };
}, },
invalidatesTags: ['Model'], invalidatesTags: ['Model'],
}), }),
getLoRAModels: build.query<EntityState<LoRAConfig, string>, void>({ getLoRAModels: build.query<EntityState<LoRAConfig, string>, void>({
query: () => ({ url: 'models/', params: { model_type: 'lora' } }), query: () => ({ url: buildModelsUrl(), params: { model_type: 'lora' } }),
providesTags: buildProvidesTags<LoRAConfig>('LoRAModel'), providesTags: buildProvidesTags<LoRAConfig>('LoRAModel'),
transformResponse: buildTransformResponse<LoRAConfig>(loraModelsAdapter), transformResponse: buildTransformResponse<LoRAConfig>(loraModelsAdapter),
}), }),
updateLoRAModels: build.mutation<UpdateLoRAModelResponse, UpdateLoRAModelArg>({ updateLoRAModels: build.mutation<UpdateLoRAModelResponse, UpdateLoRAModelArg>({
query: ({ base_model, model_name, body }) => { query: ({ base_model, model_name, body }) => {
return { return {
url: `models/${base_model}/lora/${model_name}`, url: buildModelsUrl(`${base_model}/lora/${model_name}`),
method: 'PATCH', method: 'PATCH',
body: body, body: body,
}; };
@ -253,34 +266,34 @@ export const modelsApi = api.injectEndpoints({
deleteLoRAModels: build.mutation<DeleteLoRAModelResponse, DeleteLoRAModelArg>({ deleteLoRAModels: build.mutation<DeleteLoRAModelResponse, DeleteLoRAModelArg>({
query: ({ base_model, model_name }) => { query: ({ base_model, model_name }) => {
return { return {
url: `models/${base_model}/lora/${model_name}`, url: buildModelsUrl(`${base_model}/lora/${model_name}`),
method: 'DELETE', method: 'DELETE',
}; };
}, },
invalidatesTags: [{ type: 'LoRAModel', id: LIST_TAG }], invalidatesTags: [{ type: 'LoRAModel', id: LIST_TAG }],
}), }),
getControlNetModels: build.query<EntityState<ControlNetConfig, string>, void>({ getControlNetModels: build.query<EntityState<ControlNetConfig, string>, void>({
query: () => ({ url: 'models/', params: { model_type: 'controlnet' } }), query: () => ({ url: buildModelsUrl(), params: { model_type: 'controlnet' } }),
providesTags: buildProvidesTags<ControlNetConfig>('ControlNetModel'), providesTags: buildProvidesTags<ControlNetConfig>('ControlNetModel'),
transformResponse: buildTransformResponse<ControlNetConfig>(controlNetModelsAdapter), transformResponse: buildTransformResponse<ControlNetConfig>(controlNetModelsAdapter),
}), }),
getIPAdapterModels: build.query<EntityState<IPAdapterConfig, string>, void>({ getIPAdapterModels: build.query<EntityState<IPAdapterConfig, string>, void>({
query: () => ({ url: 'models/', params: { model_type: 'ip_adapter' } }), query: () => ({ url: buildModelsUrl(), params: { model_type: 'ip_adapter' } }),
providesTags: buildProvidesTags<IPAdapterConfig>('IPAdapterModel'), providesTags: buildProvidesTags<IPAdapterConfig>('IPAdapterModel'),
transformResponse: buildTransformResponse<IPAdapterConfig>(ipAdapterModelsAdapter), transformResponse: buildTransformResponse<IPAdapterConfig>(ipAdapterModelsAdapter),
}), }),
getT2IAdapterModels: build.query<EntityState<T2IAdapterConfig, string>, void>({ getT2IAdapterModels: build.query<EntityState<T2IAdapterConfig, string>, void>({
query: () => ({ url: 'models/', params: { model_type: 't2i_adapter' } }), query: () => ({ url: buildModelsUrl(), params: { model_type: 't2i_adapter' } }),
providesTags: buildProvidesTags<T2IAdapterConfig>('T2IAdapterModel'), providesTags: buildProvidesTags<T2IAdapterConfig>('T2IAdapterModel'),
transformResponse: buildTransformResponse<T2IAdapterConfig>(t2iAdapterModelsAdapter), transformResponse: buildTransformResponse<T2IAdapterConfig>(t2iAdapterModelsAdapter),
}), }),
getVaeModels: build.query<EntityState<VAEConfig, string>, void>({ getVaeModels: build.query<EntityState<VAEConfig, string>, void>({
query: () => ({ url: 'models/', params: { model_type: 'vae' } }), query: () => ({ url: buildModelsUrl(), params: { model_type: 'vae' } }),
providesTags: buildProvidesTags<VAEConfig>('VaeModel'), providesTags: buildProvidesTags<VAEConfig>('VaeModel'),
transformResponse: buildTransformResponse<VAEConfig>(vaeModelsAdapter), transformResponse: buildTransformResponse<VAEConfig>(vaeModelsAdapter),
}), }),
getTextualInversionModels: build.query<EntityState<TextualInversionConfig, string>, void>({ getTextualInversionModels: build.query<EntityState<TextualInversionConfig, string>, void>({
query: () => ({ url: 'models/', params: { model_type: 'embedding' } }), query: () => ({ url: buildModelsUrl(), params: { model_type: 'embedding' } }),
providesTags: buildProvidesTags<TextualInversionConfig>('TextualInversionModel'), providesTags: buildProvidesTags<TextualInversionConfig>('TextualInversionModel'),
transformResponse: buildTransformResponse<TextualInversionConfig>(textualInversionModelsAdapter), transformResponse: buildTransformResponse<TextualInversionConfig>(textualInversionModelsAdapter),
}), }),
@ -288,14 +301,14 @@ export const modelsApi = api.injectEndpoints({
query: (arg) => { query: (arg) => {
const folderQueryStr = queryString.stringify(arg, {}); const folderQueryStr = queryString.stringify(arg, {});
return { return {
url: `/models/search?${folderQueryStr}`, url: buildModelsUrl(`search?${folderQueryStr}`),
}; };
}, },
}), }),
getCheckpointConfigs: build.query<CheckpointConfigsResponse, void>({ getCheckpointConfigs: build.query<CheckpointConfigsResponse, void>({
query: () => { query: () => {
return { return {
url: `/models/ckpt_confs`, url: buildModelsUrl(`ckpt_confs`),
}; };
}, },
}), }),

View File

@ -7,7 +7,15 @@ import queryString from 'query-string';
import type { components, paths } from 'services/api/schema'; import type { components, paths } from 'services/api/schema';
import type { ApiTagDescription } from '..'; import type { ApiTagDescription } from '..';
import { api } from '..'; import { api, buildV1Url } from '..';
/**
* Builds an endpoint URL for the queue router
* @example
* buildQueueUrl('some-path')
* // '/api/v1/queue/queue_id/some-path'
*/
const buildQueueUrl = (path: string = '') => buildV1Url(`queue/${$queueId.get()}/${path}`);
const getListQueueItemsUrl = (queryArgs?: paths['/api/v1/queue/{queue_id}/list']['get']['parameters']['query']) => { const getListQueueItemsUrl = (queryArgs?: paths['/api/v1/queue/{queue_id}/list']['get']['parameters']['query']) => {
const query = queryArgs const query = queryArgs
@ -17,10 +25,10 @@ const getListQueueItemsUrl = (queryArgs?: paths['/api/v1/queue/{queue_id}/list']
: undefined; : undefined;
if (query) { if (query) {
return `queue/${$queueId.get()}/list?${query}`; return buildQueueUrl(`list?${query}`);
} }
return `queue/${$queueId.get()}/list`; return buildQueueUrl('list');
}; };
export type SessionQueueItemStatus = NonNullable< export type SessionQueueItemStatus = NonNullable<
@ -58,7 +66,7 @@ export const queueApi = api.injectEndpoints({
paths['/api/v1/queue/{queue_id}/enqueue_batch']['post']['requestBody']['content']['application/json'] paths['/api/v1/queue/{queue_id}/enqueue_batch']['post']['requestBody']['content']['application/json']
>({ >({
query: (arg) => ({ query: (arg) => ({
url: `queue/${$queueId.get()}/enqueue_batch`, url: buildQueueUrl('enqueue_batch'),
body: arg, body: arg,
method: 'POST', method: 'POST',
}), }),
@ -78,7 +86,7 @@ export const queueApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `queue/${$queueId.get()}/processor/resume`, url: buildQueueUrl('processor/resume'),
method: 'PUT', method: 'PUT',
}), }),
invalidatesTags: ['CurrentSessionQueueItem', 'SessionQueueStatus'], invalidatesTags: ['CurrentSessionQueueItem', 'SessionQueueStatus'],
@ -88,7 +96,7 @@ export const queueApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `queue/${$queueId.get()}/processor/pause`, url: buildQueueUrl('processor/pause'),
method: 'PUT', method: 'PUT',
}), }),
invalidatesTags: ['CurrentSessionQueueItem', 'SessionQueueStatus'], invalidatesTags: ['CurrentSessionQueueItem', 'SessionQueueStatus'],
@ -98,7 +106,7 @@ export const queueApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `queue/${$queueId.get()}/prune`, url: buildQueueUrl('prune'),
method: 'PUT', method: 'PUT',
}), }),
invalidatesTags: ['SessionQueueStatus', 'BatchStatus'], invalidatesTags: ['SessionQueueStatus', 'BatchStatus'],
@ -117,7 +125,7 @@ export const queueApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `queue/${$queueId.get()}/clear`, url: buildQueueUrl('clear'),
method: 'PUT', method: 'PUT',
}), }),
invalidatesTags: [ invalidatesTags: [
@ -142,7 +150,7 @@ export const queueApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `queue/${$queueId.get()}/current`, url: buildQueueUrl('current'),
method: 'GET', method: 'GET',
}), }),
providesTags: (result) => { providesTags: (result) => {
@ -158,7 +166,7 @@ export const queueApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `queue/${$queueId.get()}/next`, url: buildQueueUrl('next'),
method: 'GET', method: 'GET',
}), }),
providesTags: (result) => { providesTags: (result) => {
@ -174,7 +182,7 @@ export const queueApi = api.injectEndpoints({
void void
>({ >({
query: () => ({ query: () => ({
url: `queue/${$queueId.get()}/status`, url: buildQueueUrl('status'),
method: 'GET', method: 'GET',
}), }),
providesTags: ['SessionQueueStatus', 'FetchOnReconnect'], providesTags: ['SessionQueueStatus', 'FetchOnReconnect'],
@ -184,7 +192,7 @@ export const queueApi = api.injectEndpoints({
{ batch_id: string } { batch_id: string }
>({ >({
query: ({ batch_id }) => ({ query: ({ batch_id }) => ({
url: `queue/${$queueId.get()}/b/${batch_id}/status`, url: buildQueueUrl(`/b/${batch_id}/status`),
method: 'GET', method: 'GET',
}), }),
providesTags: (result) => { providesTags: (result) => {
@ -200,7 +208,7 @@ export const queueApi = api.injectEndpoints({
number number
>({ >({
query: (item_id) => ({ query: (item_id) => ({
url: `queue/${$queueId.get()}/i/${item_id}`, url: buildQueueUrl(`i/${item_id}`),
method: 'GET', method: 'GET',
}), }),
providesTags: (result) => { providesTags: (result) => {
@ -216,7 +224,7 @@ export const queueApi = api.injectEndpoints({
number number
>({ >({
query: (item_id) => ({ query: (item_id) => ({
url: `queue/${$queueId.get()}/i/${item_id}/cancel`, url: buildQueueUrl(`i/${item_id}/cancel`),
method: 'PUT', method: 'PUT',
}), }),
onQueryStarted: async (item_id, { dispatch, queryFulfilled }) => { onQueryStarted: async (item_id, { dispatch, queryFulfilled }) => {
@ -253,7 +261,7 @@ export const queueApi = api.injectEndpoints({
paths['/api/v1/queue/{queue_id}/cancel_by_batch_ids']['put']['requestBody']['content']['application/json'] paths['/api/v1/queue/{queue_id}/cancel_by_batch_ids']['put']['requestBody']['content']['application/json']
>({ >({
query: (body) => ({ query: (body) => ({
url: `queue/${$queueId.get()}/cancel_by_batch_ids`, url: buildQueueUrl('cancel_by_batch_ids'),
method: 'PUT', method: 'PUT',
body, body,
}), }),
@ -279,7 +287,7 @@ export const queueApi = api.injectEndpoints({
method: 'GET', method: 'GET',
}), }),
serializeQueryArgs: () => { serializeQueryArgs: () => {
return `queue/${$queueId.get()}/list`; return buildQueueUrl('list');
}, },
transformResponse: (response: components['schemas']['CursorPaginatedResults_SessionQueueItemDTO_']) => transformResponse: (response: components['schemas']['CursorPaginatedResults_SessionQueueItemDTO_']) =>
queueItemsAdapter.addMany( queueItemsAdapter.addMany(

View File

@ -1,6 +1,14 @@
import type { components } from 'services/api/schema'; import type { components } from 'services/api/schema';
import { api } from '..'; import { api, buildV1Url } from '..';
/**
* Builds an endpoint URL for the utilities router
* @example
* buildUtilitiesUrl('some-path')
* // '/api/v1/utilities/some-path'
*/
const buildUtilitiesUrl = (path: string = '') => buildV1Url(`utilities/${path}`);
export const utilitiesApi = api.injectEndpoints({ export const utilitiesApi = api.injectEndpoints({
endpoints: (build) => ({ endpoints: (build) => ({
@ -9,7 +17,7 @@ export const utilitiesApi = api.injectEndpoints({
{ prompt: string; max_prompts: number } { prompt: string; max_prompts: number }
>({ >({
query: (arg) => ({ query: (arg) => ({
url: 'utilities/dynamicprompts', url: buildUtilitiesUrl('dynamicprompts'),
body: arg, body: arg,
method: 'POST', method: 'POST',
}), }),

View File

@ -1,6 +1,14 @@
import type { paths } from 'services/api/schema'; import type { paths } from 'services/api/schema';
import { api, LIST_TAG } from '..'; import { api, buildV1Url, LIST_TAG } from '..';
/**
* Builds an endpoint URL for the workflows router
* @example
* buildWorkflowsUrl('some-path')
* // '/api/v1/workflows/some-path'
*/
const buildWorkflowsUrl = (path: string = '') => buildV1Url(`workflows/${path}`);
export const workflowsApi = api.injectEndpoints({ export const workflowsApi = api.injectEndpoints({
endpoints: (build) => ({ endpoints: (build) => ({
@ -8,7 +16,7 @@ export const workflowsApi = api.injectEndpoints({
paths['/api/v1/workflows/i/{workflow_id}']['get']['responses']['200']['content']['application/json'], paths['/api/v1/workflows/i/{workflow_id}']['get']['responses']['200']['content']['application/json'],
string string
>({ >({
query: (workflow_id) => `workflows/i/${workflow_id}`, query: (workflow_id) => buildWorkflowsUrl(`i/${workflow_id}`),
providesTags: (result, error, workflow_id) => [{ type: 'Workflow', id: workflow_id }, 'FetchOnReconnect'], providesTags: (result, error, workflow_id) => [{ type: 'Workflow', id: workflow_id }, 'FetchOnReconnect'],
onQueryStarted: async (arg, api) => { onQueryStarted: async (arg, api) => {
const { dispatch, queryFulfilled } = api; const { dispatch, queryFulfilled } = api;
@ -22,7 +30,7 @@ export const workflowsApi = api.injectEndpoints({
}), }),
deleteWorkflow: build.mutation<void, string>({ deleteWorkflow: build.mutation<void, string>({
query: (workflow_id) => ({ query: (workflow_id) => ({
url: `workflows/i/${workflow_id}`, url: buildWorkflowsUrl(`i/${workflow_id}`),
method: 'DELETE', method: 'DELETE',
}), }),
invalidatesTags: (result, error, workflow_id) => [ invalidatesTags: (result, error, workflow_id) => [
@ -36,7 +44,7 @@ export const workflowsApi = api.injectEndpoints({
paths['/api/v1/workflows/']['post']['requestBody']['content']['application/json']['workflow'] paths['/api/v1/workflows/']['post']['requestBody']['content']['application/json']['workflow']
>({ >({
query: (workflow) => ({ query: (workflow) => ({
url: 'workflows/', url: buildWorkflowsUrl(),
method: 'POST', method: 'POST',
body: { workflow }, body: { workflow },
}), }),
@ -50,7 +58,7 @@ export const workflowsApi = api.injectEndpoints({
paths['/api/v1/workflows/i/{workflow_id}']['patch']['requestBody']['content']['application/json']['workflow'] paths['/api/v1/workflows/i/{workflow_id}']['patch']['requestBody']['content']['application/json']['workflow']
>({ >({
query: (workflow) => ({ query: (workflow) => ({
url: `workflows/i/${workflow.id}`, url: buildWorkflowsUrl(`i/${workflow.id}`),
method: 'PATCH', method: 'PATCH',
body: { workflow }, body: { workflow },
}), }),
@ -65,7 +73,7 @@ export const workflowsApi = api.injectEndpoints({
NonNullable<paths['/api/v1/workflows/']['get']['parameters']['query']> NonNullable<paths['/api/v1/workflows/']['get']['parameters']['query']>
>({ >({
query: (params) => ({ query: (params) => ({
url: 'workflows/', url: buildWorkflowsUrl(),
params, params,
}), }),
providesTags: ['FetchOnReconnect', { type: 'Workflow', id: LIST_TAG }], providesTags: ['FetchOnReconnect', { type: 'Workflow', id: LIST_TAG }],

View File

@ -112,3 +112,6 @@ function getCircularReplacer() {
return value; return value;
}; };
} }
export const buildV1Url = (path: string): string => `api/v1/${path}`;
export const buildV2Url = (path: string): string => `api/v2/${path}`;

File diff suppressed because one or more lines are too long

View File

@ -61,11 +61,13 @@ export type IPAdapterField = S['IPAdapterField'];
// Model Configs // Model Configs
// TODO(MM2): Can we make key required in the pydantic model? // TODO(MM2): Can we make key required in the pydantic model?
type KeyRequired<T extends {key?: string}> = SetRequired<T, 'key'>; type KeyRequired<T extends { key?: string }> = SetRequired<T, 'key'>;
export type LoRAConfig = KeyRequired<S['LoRAConfig']>; export type LoRAConfig = KeyRequired<S['LoRAConfig']>;
// TODO(MM2): Can we rename this from Vae -> VAE // TODO(MM2): Can we rename this from Vae -> VAE
export type VAEConfig = KeyRequired<S['VaeCheckpointConfig']> | KeyRequired<S['VaeDiffusersConfig']>; export type VAEConfig = KeyRequired<S['VaeCheckpointConfig']> | KeyRequired<S['VaeDiffusersConfig']>;
export type ControlNetConfig = KeyRequired<S['ControlNetDiffusersConfig']> | KeyRequired<S['ControlNetCheckpointConfig']>; export type ControlNetConfig =
| KeyRequired<S['ControlNetDiffusersConfig']>
| KeyRequired<S['ControlNetCheckpointConfig']>;
export type IPAdapterConfig = KeyRequired<S['IPAdapterConfig']>; export type IPAdapterConfig = KeyRequired<S['IPAdapterConfig']>;
// TODO(MM2): Can we rename this to T2IAdapterConfig // TODO(MM2): Can we rename this to T2IAdapterConfig
export type T2IAdapterConfig = KeyRequired<S['T2IConfig']>; export type T2IAdapterConfig = KeyRequired<S['T2IConfig']>;

View File

@ -3,6 +3,7 @@ import { getSelectorsOptions } from 'app/store/createMemoizedSelector';
import { dateComparator } from 'common/util/dateComparator'; import { dateComparator } from 'common/util/dateComparator';
import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types'; import { ASSETS_CATEGORIES, IMAGE_CATEGORIES } from 'features/gallery/store/types';
import queryString from 'query-string'; import queryString from 'query-string';
import { buildV1Url } from 'services/api';
import type { ImageCache, ImageDTO, ListImagesArgs } from './types'; import type { ImageCache, ImageDTO, ListImagesArgs } from './types';
@ -79,4 +80,4 @@ export const imagesSelectors = imagesAdapter.getSelectors(undefined, getSelector
// Helper to create the url for the listImages endpoint. Also we use it to create the cache key. // Helper to create the url for the listImages endpoint. Also we use it to create the cache key.
export const getListImagesUrl = (queryArgs: ListImagesArgs) => export const getListImagesUrl = (queryArgs: ListImagesArgs) =>
`images/?${queryString.stringify(queryArgs, { arrayFormat: 'none' })}`; buildV1Url(`images/?${queryString.stringify(queryArgs, { arrayFormat: 'none' })}`);

View File

@ -76,9 +76,9 @@ export default defineConfig(({ mode }) => {
changeOrigin: true, changeOrigin: true,
}, },
// proxy nodes api // proxy nodes api
'/api/v1': { '/api/': {
target: 'http://127.0.0.1:9090/api/v1', target: 'http://127.0.0.1:9090/api/',
rewrite: (path) => path.replace(/^\/api\/v1/, ''), rewrite: (path) => path.replace(/^\/api/, ''),
changeOrigin: true, changeOrigin: true,
}, },
}, },