mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): api layer refactor
*migrate from `openapi-typescript-codegen` to `openapi-typescript` and `openapi-fetch`* `openapi-typescript-codegen` is not very actively maintained - it's been over a year since the last update. `openapi-typescript` and `openapi-fetch` are part of the actively maintained repo. key differences: - provides a `fetch` client instead of `axios`, which means we need to be a bit more verbose with typing thunks - fetch client is created at runtime and has a very nice typescript DX - generates a single file with all types in it, from which we then extract individual types. i don't like how verbose this is, but i do like how it is more explicit. - removed npm api generation scripts - now we have a single `typegen` script overall i have more confidence in this new library. *use nanostores for api base and token* very simple reactive store for api base url and token. this was suggested in the `openapi-fetch` docs and i quite like the strategy. *organise rtk-query api* split out each endpoint (models, images, boards, boardImages) into their own api extensions. tidy!
This commit is contained in:
parent
8137a99981
commit
e386b5dc53
@ -23,8 +23,7 @@
|
||||
"dev": "concurrently \"vite dev\" \"yarn run theme:watch\"",
|
||||
"dev:host": "concurrently \"vite dev --host\" \"yarn run theme:watch\"",
|
||||
"build": "yarn run lint && vite build",
|
||||
"api:web": "openapi -i http://localhost:9090/openapi.json -o src/services/api --client axios --useOptions --useUnionTypes --indent 2 --request src/services/fixtures/request.ts",
|
||||
"api:file": "openapi -i src/services/fixtures/openapi.json -o src/services/api --client axios --useOptions --useUnionTypes --indent 2 --request src/services/fixtures/request.ts",
|
||||
"typegen": "npx openapi-typescript http://localhost:9090/openapi.json --output src/services/schema.d.ts -t",
|
||||
"preview": "vite preview",
|
||||
"lint:madge": "madge --circular src/main.tsx",
|
||||
"lint:eslint": "eslint --max-warnings=0 .",
|
||||
@ -81,6 +80,8 @@
|
||||
"i18next-http-backend": "^2.2.0",
|
||||
"konva": "^9.0.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanostores": "^0.9.2",
|
||||
"openapi-fetch": "^0.4.0",
|
||||
"overlayscrollbars": "^2.1.1",
|
||||
"overlayscrollbars-react": "^0.5.0",
|
||||
"patch-package": "^7.0.0",
|
||||
@ -140,6 +141,7 @@
|
||||
"lint-staged": "^13.2.2",
|
||||
"madge": "^6.0.0",
|
||||
"openapi-types": "^12.1.0",
|
||||
"openapi-typescript": "^6.2.8",
|
||||
"openapi-typescript-codegen": "^0.24.0",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^2.8.8",
|
||||
|
@ -24,7 +24,7 @@ import Toaster from './Toaster';
|
||||
import DeleteImageModal from 'features/gallery/components/DeleteImageModal';
|
||||
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
|
||||
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
||||
import { useListModelsQuery } from 'services/apiSlice';
|
||||
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||
|
||||
const DEFAULT_CONFIG = {};
|
||||
|
||||
|
@ -11,8 +11,8 @@ import {
|
||||
} from '@dnd-kit/core';
|
||||
import { PropsWithChildren, memo, useCallback, useState } from 'react';
|
||||
import OverlayDragImage from './OverlayDragImage';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { isImageDTO } from 'services/types/guards';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { isImageDTO } from 'services/api/guards';
|
||||
import { snapCenterToCursor } from '@dnd-kit/modifiers';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Box, Image } from '@chakra-ui/react';
|
||||
import { memo } from 'react';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
type OverlayDragImageProps = {
|
||||
image: ImageDTO;
|
||||
|
@ -7,7 +7,7 @@ import React, {
|
||||
} from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from 'app/store/store';
|
||||
import { OpenAPI } from 'services/api';
|
||||
// import { OpenAPI } from 'services/api/types';
|
||||
|
||||
import Loading from '../../common/components/Loading/Loading';
|
||||
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
|
||||
@ -23,6 +23,7 @@ import {
|
||||
} from 'app/contexts/DeleteImageContext';
|
||||
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
||||
import { AddImageToBoardContextProvider } from '../contexts/AddImageToBoardContext';
|
||||
import { $authToken, $baseUrl } from 'services/api/client';
|
||||
|
||||
const App = lazy(() => import('./App'));
|
||||
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
|
||||
@ -47,12 +48,12 @@ const InvokeAIUI = ({
|
||||
useEffect(() => {
|
||||
// configure API client token
|
||||
if (token) {
|
||||
OpenAPI.TOKEN = token;
|
||||
$authToken.set(token);
|
||||
}
|
||||
|
||||
// configure API client base url
|
||||
if (apiUrl) {
|
||||
OpenAPI.BASE = apiUrl;
|
||||
$baseUrl.set(apiUrl);
|
||||
}
|
||||
|
||||
// reset dynamically added middlewares
|
||||
@ -69,6 +70,12 @@ const InvokeAIUI = ({
|
||||
} else {
|
||||
addMiddleware(socketMiddleware());
|
||||
}
|
||||
|
||||
return () => {
|
||||
// Reset the API client token and base url on unmount
|
||||
$baseUrl.set(undefined);
|
||||
$authToken.set(undefined);
|
||||
};
|
||||
}, [apiUrl, token, middleware]);
|
||||
|
||||
return (
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useDisclosure } from '@chakra-ui/react';
|
||||
import { PropsWithChildren, createContext, useCallback, useState } from 'react';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { useAddImageToBoardMutation } from 'services/apiSlice';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { useAddImageToBoardMutation } from 'services/api/endpoints/boardImages';
|
||||
|
||||
export type ImageUsage = {
|
||||
isInitialImage: boolean;
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { controlNetSelector } from 'features/controlNet/store/controlNetSlice';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { AnyAction } from '@reduxjs/toolkit';
|
||||
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
||||
import { forEach } from 'lodash-es';
|
||||
import { Graph } from 'services/api';
|
||||
import { Graph } from 'services/api/types';
|
||||
|
||||
export const actionSanitizer = <A extends AnyAction>(action: A): A => {
|
||||
if (isAnyGraphBuilt(action)) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { startAppListening } from '..';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { commitStagingAreaImage } from 'features/canvas/store/canvasSlice';
|
||||
import { sessionCanceled } from 'services/thunks/session';
|
||||
import { sessionCanceled } from 'services/api/thunks/session';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'canvas' });
|
||||
|
||||
@ -10,7 +10,7 @@ export const addCommitStagingAreaImageListener = () => {
|
||||
actionCreator: commitStagingAreaImage,
|
||||
effect: async (action, { dispatch, getState }) => {
|
||||
const state = getState();
|
||||
const { sessionId, isProcessing } = state.system;
|
||||
const { sessionId: session_id, isProcessing } = state.system;
|
||||
const canvasSessionId = action.payload;
|
||||
|
||||
if (!isProcessing) {
|
||||
@ -23,12 +23,12 @@ export const addCommitStagingAreaImageListener = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (canvasSessionId !== sessionId) {
|
||||
if (canvasSessionId !== session_id) {
|
||||
moduleLog.debug(
|
||||
{
|
||||
data: {
|
||||
canvasSessionId,
|
||||
sessionId,
|
||||
session_id,
|
||||
},
|
||||
},
|
||||
'Canvas session does not match global session, skipping cancel'
|
||||
@ -36,7 +36,7 @@ export const addCommitStagingAreaImageListener = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(sessionCanceled({ sessionId }));
|
||||
dispatch(sessionCanceled({ session_id }));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -2,9 +2,12 @@ import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
||||
import { selectImagesAll } from 'features/gallery/store/imagesSlice';
|
||||
import { IMAGES_PER_PAGE, receivedPageOfImages } from 'services/thunks/image';
|
||||
import { api } from 'services/apiSlice';
|
||||
import {
|
||||
IMAGES_PER_PAGE,
|
||||
receivedPageOfImages,
|
||||
} from 'services/api/thunks/image';
|
||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||
import { boardsApi } from 'services/api/endpoints/boards';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'boards' });
|
||||
|
||||
@ -12,14 +15,14 @@ export const addBoardIdSelectedListener = () => {
|
||||
startAppListening({
|
||||
actionCreator: boardIdSelected,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const boardId = action.payload;
|
||||
const board_id = action.payload;
|
||||
|
||||
// we need to check if we need to fetch more images
|
||||
|
||||
const state = getState();
|
||||
const allImages = selectImagesAll(state);
|
||||
|
||||
if (!boardId) {
|
||||
if (!board_id) {
|
||||
// a board was unselected
|
||||
dispatch(imageSelected(allImages[0]?.image_name));
|
||||
return;
|
||||
@ -29,13 +32,14 @@ export const addBoardIdSelectedListener = () => {
|
||||
|
||||
const filteredImages = allImages.filter((i) => {
|
||||
const isInCategory = categories.includes(i.image_category);
|
||||
const isInSelectedBoard = boardId ? i.board_id === boardId : true;
|
||||
const isInSelectedBoard = board_id ? i.board_id === board_id : true;
|
||||
return isInCategory && isInSelectedBoard;
|
||||
});
|
||||
|
||||
// get the board from the cache
|
||||
const { data: boards } = api.endpoints.listAllBoards.select()(state);
|
||||
const board = boards?.find((b) => b.board_id === boardId);
|
||||
const { data: boards } =
|
||||
boardsApi.endpoints.listAllBoards.select()(state);
|
||||
const board = boards?.find((b) => b.board_id === board_id);
|
||||
|
||||
if (!board) {
|
||||
// can't find the board in cache...
|
||||
@ -50,7 +54,7 @@ export const addBoardIdSelectedListener = () => {
|
||||
filteredImages.length < board.image_count &&
|
||||
filteredImages.length < IMAGES_PER_PAGE
|
||||
) {
|
||||
dispatch(receivedPageOfImages({ categories, boardId }));
|
||||
dispatch(receivedPageOfImages({ categories, board_id }));
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -60,13 +64,13 @@ export const addBoardIdSelected_changeSelectedImage_listener = () => {
|
||||
startAppListening({
|
||||
actionCreator: boardIdSelected,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const boardId = action.payload;
|
||||
const board_id = action.payload;
|
||||
|
||||
const state = getState();
|
||||
|
||||
// we need to check if we need to fetch more images
|
||||
|
||||
if (!boardId) {
|
||||
if (!board_id) {
|
||||
// a board was unselected - we don't need to do anything
|
||||
return;
|
||||
}
|
||||
@ -75,13 +79,14 @@ export const addBoardIdSelected_changeSelectedImage_listener = () => {
|
||||
|
||||
const filteredImages = selectImagesAll(state).filter((i) => {
|
||||
const isInCategory = categories.includes(i.image_category);
|
||||
const isInSelectedBoard = boardId ? i.board_id === boardId : true;
|
||||
const isInSelectedBoard = board_id ? i.board_id === board_id : true;
|
||||
return isInCategory && isInSelectedBoard;
|
||||
});
|
||||
|
||||
// get the board from the cache
|
||||
const { data: boards } = api.endpoints.listAllBoards.select()(state);
|
||||
const board = boards?.find((b) => b.board_id === boardId);
|
||||
const { data: boards } =
|
||||
boardsApi.endpoints.listAllBoards.select()(state);
|
||||
const board = boards?.find((b) => b.board_id === board_id);
|
||||
if (!board) {
|
||||
// can't find the board in cache...
|
||||
return;
|
||||
@ -92,7 +97,7 @@ export const addBoardIdSelected_changeSelectedImage_listener = () => {
|
||||
filteredImages.length < board.image_count &&
|
||||
filteredImages.length < IMAGES_PER_PAGE
|
||||
) {
|
||||
dispatch(receivedPageOfImages({ categories, boardId }));
|
||||
dispatch(receivedPageOfImages({ categories, board_id }));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import { canvasMerged } from 'features/canvas/store/actions';
|
||||
import { startAppListening } from '..';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { addToast } from 'features/system/store/systemSlice';
|
||||
import { imageUploaded } from 'services/thunks/image';
|
||||
import { imageUploaded } from 'services/api/thunks/image';
|
||||
import { setMergedCanvas } from 'features/canvas/store/canvasSlice';
|
||||
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
||||
import { getFullBaseLayerBlob } from 'features/canvas/util/getFullBaseLayerBlob';
|
||||
@ -47,13 +47,11 @@ export const addCanvasMergedListener = () => {
|
||||
|
||||
const imageUploadedRequest = dispatch(
|
||||
imageUploaded({
|
||||
formData: {
|
||||
file: new File([blob], 'mergedCanvas.png', {
|
||||
type: 'image/png',
|
||||
}),
|
||||
},
|
||||
imageCategory: 'general',
|
||||
isIntermediate: true,
|
||||
image_category: 'general',
|
||||
is_intermediate: true,
|
||||
postUploadAction: {
|
||||
type: 'TOAST_CANVAS_MERGED',
|
||||
},
|
||||
@ -68,13 +66,13 @@ export const addCanvasMergedListener = () => {
|
||||
uploadedImageAction.meta.requestId === imageUploadedRequest.requestId
|
||||
);
|
||||
|
||||
const mergedCanvasImage = payload;
|
||||
const { image_name } = payload;
|
||||
|
||||
dispatch(
|
||||
setMergedCanvas({
|
||||
kind: 'image',
|
||||
layer: 'base',
|
||||
image: mergedCanvasImage,
|
||||
imageName: image_name,
|
||||
...baseLayerRect,
|
||||
})
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { canvasSavedToGallery } from 'features/canvas/store/actions';
|
||||
import { startAppListening } from '..';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { imageUploaded } from 'services/thunks/image';
|
||||
import { imageUploaded } from 'services/api/thunks/image';
|
||||
import { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
||||
import { addToast } from 'features/system/store/systemSlice';
|
||||
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||
@ -30,13 +30,11 @@ export const addCanvasSavedToGalleryListener = () => {
|
||||
|
||||
const imageUploadedRequest = dispatch(
|
||||
imageUploaded({
|
||||
formData: {
|
||||
file: new File([blob], 'savedCanvas.png', {
|
||||
type: 'image/png',
|
||||
}),
|
||||
},
|
||||
imageCategory: 'general',
|
||||
isIntermediate: false,
|
||||
image_category: 'general',
|
||||
is_intermediate: false,
|
||||
postUploadAction: {
|
||||
type: 'TOAST_CANVAS_SAVED_TO_GALLERY',
|
||||
},
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { startAppListening } from '..';
|
||||
import { imageMetadataReceived } from 'services/thunks/image';
|
||||
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { controlNetImageProcessed } from 'features/controlNet/store/actions';
|
||||
import { Graph } from 'services/api';
|
||||
import { sessionCreated } from 'services/thunks/session';
|
||||
import { Graph } from 'services/api/types';
|
||||
import { sessionCreated } from 'services/api/thunks/session';
|
||||
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||
import { socketInvocationComplete } from 'services/events/actions';
|
||||
import { isImageOutput } from 'services/types/guards';
|
||||
import { isImageOutput } from 'services/api/guards';
|
||||
import { controlNetProcessedImageChanged } from 'features/controlNet/store/controlNetSlice';
|
||||
import { pick } from 'lodash-es';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'controlNet' });
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { imageMetadataReceived } from 'services/thunks/image';
|
||||
import { api } from 'services/apiSlice';
|
||||
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||
import { boardImagesApi } from 'services/api/endpoints/boardImages';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'boards' });
|
||||
|
||||
export const addImageAddedToBoardFulfilledListener = () => {
|
||||
startAppListening({
|
||||
matcher: api.endpoints.addImageToBoard.matchFulfilled,
|
||||
matcher: boardImagesApi.endpoints.addImageToBoard.matchFulfilled,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||
|
||||
@ -18,7 +18,7 @@ export const addImageAddedToBoardFulfilledListener = () => {
|
||||
|
||||
dispatch(
|
||||
imageMetadataReceived({
|
||||
imageName: image_name,
|
||||
image_name,
|
||||
})
|
||||
);
|
||||
},
|
||||
@ -27,7 +27,7 @@ export const addImageAddedToBoardFulfilledListener = () => {
|
||||
|
||||
export const addImageAddedToBoardRejectedListener = () => {
|
||||
startAppListening({
|
||||
matcher: api.endpoints.addImageToBoard.matchRejected,
|
||||
matcher: boardImagesApi.endpoints.addImageToBoard.matchRejected,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { receivedPageOfImages } from 'services/thunks/image';
|
||||
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||
import {
|
||||
imageCategoriesChanged,
|
||||
selectFilteredImagesAsArray,
|
||||
@ -19,7 +19,7 @@ export const addImageCategoriesChangedListener = () => {
|
||||
dispatch(
|
||||
receivedPageOfImages({
|
||||
categories: action.payload,
|
||||
boardId: state.boards.selectedBoardId,
|
||||
board_id: state.boards.selectedBoardId,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { requestedImageDeletion } from 'features/gallery/store/actions';
|
||||
import { startAppListening } from '..';
|
||||
import { imageDeleted } from 'services/thunks/image';
|
||||
import { imageDeleted } from 'services/api/thunks/image';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { clamp } from 'lodash-es';
|
||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||
@ -12,7 +12,7 @@ import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
||||
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
||||
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||
import { api } from 'services/apiSlice';
|
||||
import { api } from 'services/api';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'image' });
|
||||
|
||||
@ -76,7 +76,7 @@ export const addRequestedImageDeletionListener = () => {
|
||||
dispatch(imageRemoved(image_name));
|
||||
|
||||
// Delete from server
|
||||
const { requestId } = dispatch(imageDeleted({ imageName: image_name }));
|
||||
const { requestId } = dispatch(imageDeleted({ image_name }));
|
||||
|
||||
// Wait for successful deletion, then trigger boards to re-fetch
|
||||
const wasImageDeleted = await condition(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { imageMetadataReceived, imageUpdated } from 'services/thunks/image';
|
||||
import { imageMetadataReceived, imageUpdated } from 'services/api/thunks/image';
|
||||
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'image' });
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { imageMetadataReceived } from 'services/thunks/image';
|
||||
import { api } from 'services/apiSlice';
|
||||
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||
import { boardImagesApi } from 'services/api/endpoints/boardImages';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'boards' });
|
||||
|
||||
export const addImageRemovedFromBoardFulfilledListener = () => {
|
||||
startAppListening({
|
||||
matcher: api.endpoints.removeImageFromBoard.matchFulfilled,
|
||||
matcher: boardImagesApi.endpoints.removeImageFromBoard.matchFulfilled,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||
|
||||
@ -18,7 +18,7 @@ export const addImageRemovedFromBoardFulfilledListener = () => {
|
||||
|
||||
dispatch(
|
||||
imageMetadataReceived({
|
||||
imageName: image_name,
|
||||
image_name,
|
||||
})
|
||||
);
|
||||
},
|
||||
@ -27,7 +27,7 @@ export const addImageRemovedFromBoardFulfilledListener = () => {
|
||||
|
||||
export const addImageRemovedFromBoardRejectedListener = () => {
|
||||
startAppListening({
|
||||
matcher: api.endpoints.removeImageFromBoard.matchRejected,
|
||||
matcher: boardImagesApi.endpoints.removeImageFromBoard.matchRejected,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { startAppListening } from '..';
|
||||
import { imageUpdated } from 'services/thunks/image';
|
||||
import { imageUpdated } from 'services/api/thunks/image';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'image' });
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { startAppListening } from '..';
|
||||
import { imageUploaded } from 'services/thunks/image';
|
||||
import { imageUploaded } from 'services/api/thunks/image';
|
||||
import { addToast } from 'features/system/store/systemSlice';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { imageUrlsReceived } from 'services/thunks/image';
|
||||
import { imageUrlsReceived } from 'services/api/thunks/image';
|
||||
import { imageUpdatedOne } from 'features/gallery/store/imagesSlice';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'image' });
|
||||
|
@ -5,7 +5,7 @@ import { startAppListening } from '..';
|
||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||
import { makeToast } from 'app/components/Toaster';
|
||||
import { selectImagesById } from 'features/gallery/store/imagesSlice';
|
||||
import { isImageDTO } from 'services/types/guards';
|
||||
import { isImageDTO } from 'services/api/guards';
|
||||
|
||||
export const addInitialImageSelectedListener = () => {
|
||||
startAppListening({
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { serializeError } from 'serialize-error';
|
||||
import { receivedPageOfImages } from 'services/thunks/image';
|
||||
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'gallery' });
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { sessionCanceled } from 'services/thunks/session';
|
||||
import { sessionCanceled } from 'services/api/thunks/session';
|
||||
import { serializeError } from 'serialize-error';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'session' });
|
||||
@ -18,10 +18,10 @@ export const addSessionCanceledFulfilledListener = () => {
|
||||
startAppListening({
|
||||
actionCreator: sessionCanceled.fulfilled,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const { sessionId } = action.meta.arg;
|
||||
const { session_id } = action.meta.arg;
|
||||
moduleLog.debug(
|
||||
{ data: { sessionId } },
|
||||
`Session canceled (${sessionId})`
|
||||
{ data: { session_id } },
|
||||
`Session canceled (${session_id})`
|
||||
);
|
||||
},
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { sessionCreated } from 'services/thunks/session';
|
||||
import { sessionCreated } from 'services/api/thunks/session';
|
||||
import { serializeError } from 'serialize-error';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'session' });
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { startAppListening } from '..';
|
||||
import { sessionInvoked } from 'services/thunks/session';
|
||||
import { sessionInvoked } from 'services/api/thunks/session';
|
||||
import { serializeError } from 'serialize-error';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'session' });
|
||||
@ -18,10 +18,10 @@ export const addSessionInvokedFulfilledListener = () => {
|
||||
startAppListening({
|
||||
actionCreator: sessionInvoked.fulfilled,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const { sessionId } = action.meta.arg;
|
||||
const { session_id } = action.meta.arg;
|
||||
moduleLog.debug(
|
||||
{ data: { sessionId } },
|
||||
`Session invoked (${sessionId})`
|
||||
{ data: { session_id } },
|
||||
`Session invoked (${session_id})`
|
||||
);
|
||||
},
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { startAppListening } from '..';
|
||||
import { sessionInvoked } from 'services/thunks/session';
|
||||
import { sessionInvoked } from 'services/api/thunks/session';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||
|
||||
@ -9,13 +9,13 @@ export const addSessionReadyToInvokeListener = () => {
|
||||
startAppListening({
|
||||
actionCreator: sessionReadyToInvoke,
|
||||
effect: (action, { getState, dispatch }) => {
|
||||
const { sessionId } = getState().system;
|
||||
if (sessionId) {
|
||||
const { sessionId: session_id } = getState().system;
|
||||
if (session_id) {
|
||||
moduleLog.debug(
|
||||
{ sessionId },
|
||||
`Session ready to invoke (${sessionId})})`
|
||||
{ session_id },
|
||||
`Session ready to invoke (${session_id})})`
|
||||
);
|
||||
dispatch(sessionInvoked({ sessionId }));
|
||||
dispatch(sessionInvoked({ session_id }));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { appSocketConnected, socketConnected } from 'services/events/actions';
|
||||
import { receivedPageOfImages } from 'services/thunks/image';
|
||||
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
||||
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||
import { startAppListening } from '../..';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'socketio' });
|
||||
@ -22,7 +22,7 @@ export const addSocketConnectedEventListener = () => {
|
||||
dispatch(
|
||||
receivedPageOfImages({
|
||||
categories: ['general'],
|
||||
isIntermediate: false,
|
||||
is_intermediate: false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ import {
|
||||
appSocketInvocationComplete,
|
||||
socketInvocationComplete,
|
||||
} from 'services/events/actions';
|
||||
import { imageMetadataReceived } from 'services/thunks/image';
|
||||
import { sessionCanceled } from 'services/thunks/session';
|
||||
import { isImageOutput } from 'services/types/guards';
|
||||
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||
import { sessionCanceled } from 'services/api/thunks/session';
|
||||
import { isImageOutput } from 'services/api/guards';
|
||||
import { progressImageSet } from 'features/system/store/systemSlice';
|
||||
import { api } from 'services/apiSlice';
|
||||
import { api } from 'services/api';
|
||||
|
||||
const moduleLog = log.child({ namespace: 'socketio' });
|
||||
const nodeDenylist = ['dataURL_image'];
|
||||
@ -19,18 +19,18 @@ export const addInvocationCompleteEventListener = () => {
|
||||
actionCreator: socketInvocationComplete,
|
||||
effect: async (action, { dispatch, getState, take }) => {
|
||||
moduleLog.debug(
|
||||
action.payload,
|
||||
{ data: action.payload },
|
||||
`Invocation complete (${action.payload.data.node.type})`
|
||||
);
|
||||
|
||||
const sessionId = action.payload.data.graph_execution_state_id;
|
||||
const session_id = action.payload.data.graph_execution_state_id;
|
||||
|
||||
const { cancelType, isCancelScheduled, boardIdToAddTo } =
|
||||
getState().system;
|
||||
|
||||
// Handle scheduled cancelation
|
||||
if (cancelType === 'scheduled' && isCancelScheduled) {
|
||||
dispatch(sessionCanceled({ sessionId }));
|
||||
dispatch(sessionCanceled({ session_id }));
|
||||
}
|
||||
|
||||
const { data } = action.payload;
|
||||
@ -43,7 +43,7 @@ export const addInvocationCompleteEventListener = () => {
|
||||
// Get its metadata
|
||||
dispatch(
|
||||
imageMetadataReceived({
|
||||
imageName: image_name,
|
||||
image_name,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { stagingAreaImageSaved } from 'features/canvas/store/actions';
|
||||
import { startAppListening } from '..';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { imageUpdated } from 'services/thunks/image';
|
||||
import { imageUpdated } from 'services/api/thunks/image';
|
||||
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||
import { addToast } from 'features/system/store/systemSlice';
|
||||
|
||||
|
@ -5,9 +5,8 @@ import { generationSelector } from 'features/parameters/store/generationSelector
|
||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||
import { nodesSelecter } from 'features/nodes/store/nodesSlice';
|
||||
import { controlNetSelector } from 'features/controlNet/store/controlNetSlice';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { forEach, uniqBy } from 'lodash-es';
|
||||
import { imageUrlsReceived } from 'services/thunks/image';
|
||||
import { imageUrlsReceived } from 'services/api/thunks/image';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { selectImagesEntities } from 'features/gallery/store/imagesSlice';
|
||||
|
||||
@ -83,7 +82,7 @@ export const addUpdateImageUrlsOnConnectListener = () => {
|
||||
allUsedImages.forEach((image_name) => {
|
||||
dispatch(
|
||||
imageUrlsReceived({
|
||||
imageName: image_name,
|
||||
image_name,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { startAppListening } from '..';
|
||||
import { sessionCreated } from 'services/thunks/session';
|
||||
import { sessionCreated } from 'services/api/thunks/session';
|
||||
import { buildCanvasGraph } from 'features/nodes/util/graphBuilders/buildCanvasGraph';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { canvasGraphBuilt } from 'features/nodes/store/actions';
|
||||
import { imageUpdated, imageUploaded } from 'services/thunks/image';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { imageUpdated, imageUploaded } from 'services/api/thunks/image';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import {
|
||||
canvasSessionIdChanged,
|
||||
stagingAreaInitialized,
|
||||
@ -75,13 +75,11 @@ export const addUserInvokedCanvasListener = () => {
|
||||
// upload the image, saving the request id
|
||||
const { requestId: initImageUploadedRequestId } = dispatch(
|
||||
imageUploaded({
|
||||
formData: {
|
||||
file: new File([baseBlob], 'canvasInitImage.png', {
|
||||
type: 'image/png',
|
||||
}),
|
||||
},
|
||||
imageCategory: 'general',
|
||||
isIntermediate: true,
|
||||
image_category: 'general',
|
||||
is_intermediate: true,
|
||||
})
|
||||
);
|
||||
|
||||
@ -100,13 +98,11 @@ export const addUserInvokedCanvasListener = () => {
|
||||
// upload the image, saving the request id
|
||||
const { requestId: maskImageUploadedRequestId } = dispatch(
|
||||
imageUploaded({
|
||||
formData: {
|
||||
file: new File([maskBlob], 'canvasMaskImage.png', {
|
||||
type: 'image/png',
|
||||
}),
|
||||
},
|
||||
imageCategory: 'mask',
|
||||
isIntermediate: true,
|
||||
image_category: 'mask',
|
||||
is_intermediate: true,
|
||||
})
|
||||
);
|
||||
|
||||
@ -149,8 +145,8 @@ export const addUserInvokedCanvasListener = () => {
|
||||
if (['img2img', 'inpaint'].includes(generationMode) && canvasInitImage) {
|
||||
dispatch(
|
||||
imageUpdated({
|
||||
imageName: canvasInitImage.image_name,
|
||||
requestBody: { session_id: sessionId },
|
||||
image_name: canvasInitImage.image_name,
|
||||
session_id: sessionId,
|
||||
})
|
||||
);
|
||||
}
|
||||
@ -159,8 +155,8 @@ export const addUserInvokedCanvasListener = () => {
|
||||
if (['inpaint'].includes(generationMode) && canvasMaskImage) {
|
||||
dispatch(
|
||||
imageUpdated({
|
||||
imageName: canvasMaskImage.image_name,
|
||||
requestBody: { session_id: sessionId },
|
||||
image_name: canvasMaskImage.image_name,
|
||||
session_id: sessionId,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { startAppListening } from '..';
|
||||
import { sessionCreated } from 'services/thunks/session';
|
||||
import { sessionCreated } from 'services/api/thunks/session';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { imageToImageGraphBuilt } from 'features/nodes/store/actions';
|
||||
import { userInvoked } from 'app/store/actions';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { startAppListening } from '..';
|
||||
import { sessionCreated } from 'services/thunks/session';
|
||||
import { sessionCreated } from 'services/api/thunks/session';
|
||||
import { buildNodesGraph } from 'features/nodes/util/graphBuilders/buildNodesGraph';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { nodesGraphBuilt } from 'features/nodes/store/actions';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { startAppListening } from '..';
|
||||
import { sessionCreated } from 'services/thunks/session';
|
||||
import { sessionCreated } from 'services/api/thunks/session';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { textToImageGraphBuilt } from 'features/nodes/store/actions';
|
||||
import { userInvoked } from 'app/store/actions';
|
||||
|
@ -31,7 +31,7 @@ import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
||||
import { LOCALSTORAGE_PREFIX } from './constants';
|
||||
import { serialize } from './enhancers/reduxRemember/serialize';
|
||||
import { unserialize } from './enhancers/reduxRemember/unserialize';
|
||||
import { api } from 'services/apiSlice';
|
||||
import { api } from 'services/api';
|
||||
|
||||
const allReducers = {
|
||||
canvas: canvasReducer,
|
||||
|
@ -15,10 +15,10 @@ import { AnimatePresence } from 'framer-motion';
|
||||
import { ReactElement, SyntheticEvent, useCallback } from 'react';
|
||||
import { memo, useRef } from 'react';
|
||||
import { FaImage, FaTimes, FaUndo, FaUpload } from 'react-icons/fa';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import IAIDropOverlay from './IAIDropOverlay';
|
||||
import { PostUploadAction, imageUploaded } from 'services/thunks/image';
|
||||
import { PostUploadAction, imageUploaded } from 'services/api/thunks/image';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
|
||||
@ -96,9 +96,9 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
||||
|
||||
dispatch(
|
||||
imageUploaded({
|
||||
formData: { file },
|
||||
imageCategory: 'user',
|
||||
isIntermediate: false,
|
||||
file,
|
||||
image_category: 'user',
|
||||
is_intermediate: false,
|
||||
postUploadAction,
|
||||
})
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Badge, Flex } from '@chakra-ui/react';
|
||||
import { isString } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
type ImageMetadataOverlayProps = {
|
||||
image: ImageDTO;
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
} from 'react';
|
||||
import { FileRejection, useDropzone } from 'react-dropzone';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { imageUploaded } from 'services/thunks/image';
|
||||
import { imageUploaded } from 'services/api/thunks/image';
|
||||
import ImageUploadOverlay from './ImageUploadOverlay';
|
||||
import { useAppToaster } from 'app/components/Toaster';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
@ -62,9 +62,9 @@ const ImageUploader = (props: ImageUploaderProps) => {
|
||||
async (file: File) => {
|
||||
dispatch(
|
||||
imageUploaded({
|
||||
formData: { file },
|
||||
imageCategory: 'user',
|
||||
isIntermediate: false,
|
||||
file,
|
||||
image_category: 'user',
|
||||
is_intermediate: false,
|
||||
postUploadAction: { type: 'TOAST_UPLOADED' },
|
||||
})
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||
import { Image, Rect } from 'react-konva';
|
||||
import { useGetImageDTOQuery } from 'services/apiSlice';
|
||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||
import useImage from 'use-image';
|
||||
import { CanvasImage } from '../store/canvasTypes';
|
||||
|
||||
@ -9,7 +9,7 @@ type IAICanvasImageProps = {
|
||||
};
|
||||
const IAICanvasImage = (props: IAICanvasImageProps) => {
|
||||
const { width, height, x, y, imageName } = props.canvasImage;
|
||||
const { data: imageDTO } = useGetImageDTOQuery(imageName ?? skipToken);
|
||||
const { currentData: imageDTO } = useGetImageDTOQuery(imageName ?? skipToken);
|
||||
const [image] = useImage(imageDTO?.image_url ?? '', 'anonymous');
|
||||
|
||||
if (!imageDTO) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
export const canvasSavedToGallery = createAction('canvas/canvasSavedToGallery');
|
||||
|
||||
|
@ -28,13 +28,13 @@ import {
|
||||
isCanvasBaseImage,
|
||||
isCanvasMaskLine,
|
||||
} from './canvasTypes';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { sessionCanceled } from 'services/thunks/session';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { sessionCanceled } from 'services/api/thunks/session';
|
||||
import {
|
||||
setActiveTab,
|
||||
setShouldUseCanvasBetaLayout,
|
||||
} from 'features/ui/store/uiSlice';
|
||||
import { imageUrlsReceived } from 'services/thunks/image';
|
||||
import { imageUrlsReceived } from 'services/api/thunks/image';
|
||||
|
||||
export const initialLayerState: CanvasLayerState = {
|
||||
objects: [],
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as InvokeAI from 'app/types/invokeai';
|
||||
import { IRect, Vector2d } from 'konva/lib/types';
|
||||
import { RgbaColor } from 'react-colorful';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
export const LAYER_NAMES_DICT = [
|
||||
{ label: 'Base', value: 'base' },
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { memo, useCallback, useState } from 'react';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import {
|
||||
ControlNetConfig,
|
||||
controlNetImageChanged,
|
||||
@ -14,7 +14,7 @@ import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { FaUndo } from 'react-icons/fa';
|
||||
import { useGetImageDTOQuery } from 'services/apiSlice';
|
||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||
|
||||
const selector = createSelector(
|
||||
@ -45,14 +45,14 @@ const ControlNetImagePreview = (props: Props) => {
|
||||
const [isMouseOverImage, setIsMouseOverImage] = useState(false);
|
||||
|
||||
const {
|
||||
data: controlImage,
|
||||
currentData: controlImage,
|
||||
isLoading: isLoadingControlImage,
|
||||
isError: isErrorControlImage,
|
||||
isSuccess: isSuccessControlImage,
|
||||
} = useGetImageDTOQuery(controlImageName ?? skipToken);
|
||||
|
||||
const {
|
||||
data: processedControlImage,
|
||||
currentData: processedControlImage,
|
||||
isLoading: isLoadingProcessedControlImage,
|
||||
isError: isErrorProcessedControlImage,
|
||||
isSuccess: isSuccessProcessedControlImage,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import {
|
||||
ControlNetProcessorType,
|
||||
RequiredCannyImageProcessorInvocation,
|
||||
@ -13,9 +13,9 @@ import {
|
||||
ControlNetModelName,
|
||||
} from './constants';
|
||||
import { controlNetImageProcessed } from './actions';
|
||||
import { imageDeleted, imageUrlsReceived } from 'services/thunks/image';
|
||||
import { imageDeleted, imageUrlsReceived } from 'services/api/thunks/image';
|
||||
import { forEach } from 'lodash-es';
|
||||
import { isAnySessionRejected } from 'services/thunks/session';
|
||||
import { isAnySessionRejected } from 'services/api/thunks/session';
|
||||
import { appSocketInvocationError } from 'services/events/actions';
|
||||
|
||||
export const initialControlNet: Omit<ControlNetConfig, 'controlNetId'> = {
|
||||
@ -258,13 +258,13 @@ export const controlNetSlice = createSlice({
|
||||
|
||||
builder.addCase(imageDeleted.pending, (state, action) => {
|
||||
// Preemptively remove the image from the gallery
|
||||
const { imageName } = action.meta.arg;
|
||||
const { image_name } = action.meta.arg;
|
||||
forEach(state.controlNets, (c) => {
|
||||
if (c.controlImage === imageName) {
|
||||
if (c.controlImage === image_name) {
|
||||
c.controlImage = null;
|
||||
c.processedControlImage = null;
|
||||
}
|
||||
if (c.processedControlImage === imageName) {
|
||||
if (c.processedControlImage === image_name) {
|
||||
c.processedControlImage = null;
|
||||
}
|
||||
});
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
OpenposeImageProcessorInvocation,
|
||||
PidiImageProcessorInvocation,
|
||||
ZoeDepthImageProcessorInvocation,
|
||||
} from 'services/api';
|
||||
} from 'services/api/types';
|
||||
import { O } from 'ts-toolbelt';
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import { useCallback } from 'react';
|
||||
import { useCreateBoardMutation } from 'services/apiSlice';
|
||||
import { useCreateBoardMutation } from 'services/api/endpoints/boards';
|
||||
|
||||
const DEFAULT_BOARD_NAME = 'My Board';
|
||||
|
||||
|
@ -6,8 +6,8 @@ import { IAINoImageFallback } from 'common/components/IAIImageFallback';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
import { SelectedItemOverlay } from '../SelectedItemOverlay';
|
||||
import { useCallback } from 'react';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { useRemoveImageFromBoardMutation } from 'services/apiSlice';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
||||
|
||||
|
@ -20,7 +20,7 @@ import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import AddBoardButton from './AddBoardButton';
|
||||
import AllImagesBoard from './AllImagesBoard';
|
||||
import { CloseIcon } from '@chakra-ui/icons';
|
||||
import { useListAllBoardsQuery } from 'services/apiSlice';
|
||||
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||
|
||||
const selector = createSelector(
|
||||
[boardsSelector],
|
||||
|
@ -14,15 +14,16 @@ import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { FaFolder, FaTrash } from 'react-icons/fa';
|
||||
import { ContextMenu } from 'chakra-ui-contextmenu';
|
||||
import { BoardDTO, ImageDTO } from 'services/api';
|
||||
import { BoardDTO, ImageDTO } from 'services/api/types';
|
||||
import { IAINoImageFallback } from 'common/components/IAIImageFallback';
|
||||
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
||||
import { useAddImageToBoardMutation } from 'services/api/endpoints/boardImages';
|
||||
import {
|
||||
useAddImageToBoardMutation,
|
||||
useDeleteBoardMutation,
|
||||
useGetImageDTOQuery,
|
||||
useUpdateBoardMutation,
|
||||
} from 'services/apiSlice';
|
||||
} from 'services/api/endpoints/boards';
|
||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||
|
||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
@ -37,7 +38,7 @@ interface HoverableBoardProps {
|
||||
const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { data: coverImage } = useGetImageDTOQuery(
|
||||
const { currentData: coverImage } = useGetImageDTOQuery(
|
||||
board.cover_image_name ?? skipToken
|
||||
);
|
||||
|
||||
|
@ -15,7 +15,7 @@ import IAIButton from 'common/components/IAIButton';
|
||||
import { memo, useContext, useRef, useState } from 'react';
|
||||
import { AddImageToBoardContext } from '../../../../app/contexts/AddImageToBoardContext';
|
||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||
import { useListAllBoardsQuery } from 'services/apiSlice';
|
||||
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||
|
||||
const UpdateImageBoardModal = () => {
|
||||
// const boards = useSelector(selectBoardsAll);
|
||||
|
@ -11,9 +11,9 @@ import { memo, useCallback } from 'react';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import { imageSelected } from '../store/gallerySlice';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
||||
import { useGetImageDTOQuery } from 'services/apiSlice';
|
||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||
|
||||
export const imagesSelector = createSelector(
|
||||
@ -56,7 +56,7 @@ const CurrentImagePreview = () => {
|
||||
// );
|
||||
|
||||
const {
|
||||
data: image,
|
||||
currentData: image,
|
||||
isLoading,
|
||||
isError,
|
||||
isSuccess,
|
||||
@ -110,14 +110,14 @@ const CurrentImagePreview = () => {
|
||||
}}
|
||||
>
|
||||
<IAIDndImage
|
||||
image={selectedImage && image ? image : undefined}
|
||||
image={image}
|
||||
onDrop={handleDrop}
|
||||
fallback={<IAIImageLoadingFallback sx={{ bg: 'none' }} />}
|
||||
isUploadDisabled={true}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
{shouldShowImageDetails && image && selectedImage && (
|
||||
{shouldShowImageDetails && image && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
@ -131,7 +131,7 @@ const CurrentImagePreview = () => {
|
||||
<ImageMetadataViewer image={image} />
|
||||
</Box>
|
||||
)}
|
||||
{!shouldShowImageDetails && image && selectedImage && (
|
||||
{!shouldShowImageDetails && image && (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
|
@ -31,11 +31,11 @@ import { useRecallParameters } from 'features/parameters/hooks/useRecallParamete
|
||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||
import { sentImageToCanvas, sentImageToImg2Img } from '../store/actions';
|
||||
import { useAppToaster } from 'app/components/Toaster';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { useDraggable } from '@dnd-kit/core';
|
||||
import { DeleteImageContext } from 'app/contexts/DeleteImageContext';
|
||||
import { AddImageToBoardContext } from '../../../app/contexts/AddImageToBoardContext';
|
||||
import { useRemoveImageFromBoardMutation } from 'services/apiSlice';
|
||||
import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages';
|
||||
|
||||
export const selector = createSelector(
|
||||
[gallerySelector, systemSelector, lightboxSelector, activeTabNameSelector],
|
||||
|
@ -56,11 +56,11 @@ import {
|
||||
imageCategoriesChanged,
|
||||
selectImagesAll,
|
||||
} from '../store/imagesSlice';
|
||||
import { receivedPageOfImages } from 'services/thunks/image';
|
||||
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||
import BoardsList from './Boards/BoardsList';
|
||||
import { boardsSelector } from '../store/boardSlice';
|
||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||
import { useListAllBoardsQuery } from 'services/apiSlice';
|
||||
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||
|
||||
const itemSelector = createSelector(
|
||||
[(state: RootState) => state],
|
||||
@ -167,7 +167,7 @@ const ImageGalleryContent = () => {
|
||||
dispatch(
|
||||
receivedPageOfImages({
|
||||
categories,
|
||||
boardId: selectedBoardId,
|
||||
board_id: selectedBoardId,
|
||||
})
|
||||
);
|
||||
}, [categories, dispatch, selectedBoardId]);
|
||||
|
@ -17,7 +17,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaCopy } from 'react-icons/fa';
|
||||
import { IoArrowUndoCircleOutline } from 'react-icons/io5';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
type MetadataItemProps = {
|
||||
isLink?: boolean;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { ImageUsage } from 'app/contexts/DeleteImageContext';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
export type RequestedImageDeletionArg = {
|
||||
image: ImageDTO;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { api } from 'services/apiSlice';
|
||||
import { api } from 'services/api';
|
||||
|
||||
type BoardsState = {
|
||||
searchText: string;
|
||||
|
@ -6,14 +6,14 @@ import {
|
||||
createSlice,
|
||||
} from '@reduxjs/toolkit';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { ImageCategory, ImageDTO } from 'services/api';
|
||||
import { ImageCategory, ImageDTO } from 'services/api/types';
|
||||
import { dateComparator } from 'common/util/dateComparator';
|
||||
import { keyBy } from 'lodash-es';
|
||||
import {
|
||||
imageDeleted,
|
||||
imageUrlsReceived,
|
||||
receivedPageOfImages,
|
||||
} from 'services/thunks/image';
|
||||
} from 'services/api/thunks/image';
|
||||
|
||||
export const imagesAdapter = createEntityAdapter<ImageDTO>({
|
||||
selectId: (image) => image.image_name,
|
||||
@ -73,13 +73,13 @@ const imagesSlice = createSlice({
|
||||
});
|
||||
builder.addCase(receivedPageOfImages.fulfilled, (state, action) => {
|
||||
state.isLoading = false;
|
||||
const { boardId, categories, imageOrigin, isIntermediate } =
|
||||
const { board_id, categories, image_origin, is_intermediate } =
|
||||
action.meta.arg;
|
||||
|
||||
const { items, offset, limit, total } = action.payload;
|
||||
imagesAdapter.upsertMany(state, items);
|
||||
|
||||
if (!categories?.includes('general') || boardId) {
|
||||
if (!categories?.includes('general') || board_id) {
|
||||
// need to skip updating the total images count if the images recieved were for a specific board
|
||||
// TODO: this doesn't work when on the Asset tab/category...
|
||||
return;
|
||||
@ -91,8 +91,8 @@ const imagesSlice = createSlice({
|
||||
});
|
||||
builder.addCase(imageDeleted.pending, (state, action) => {
|
||||
// Image deleted
|
||||
const { imageName } = action.meta.arg;
|
||||
imagesAdapter.removeOne(state, imageName);
|
||||
const { image_name } = action.meta.arg;
|
||||
imagesAdapter.removeOne(state, image_name);
|
||||
});
|
||||
builder.addCase(imageUrlsReceived.fulfilled, (state, action) => {
|
||||
const { image_name, image_url, thumbnail_url } = action.payload;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { TransformComponent, useTransformContext } from 'react-zoom-pan-pinch';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
type ReactPanZoomProps = {
|
||||
image: ImageDTO;
|
||||
|
@ -9,9 +9,9 @@ import { memo, useCallback } from 'react';
|
||||
|
||||
import { FieldComponentProps } from './types';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { useGetImageDTOQuery } from 'services/apiSlice';
|
||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||
|
||||
const ImageInputFieldComponent = (
|
||||
@ -22,7 +22,7 @@ const ImageInputFieldComponent = (
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const {
|
||||
data: image,
|
||||
currentData: image,
|
||||
isLoading,
|
||||
isError,
|
||||
isSuccess,
|
||||
|
@ -12,7 +12,7 @@ import { forEach, isString } from 'lodash-es';
|
||||
import { MODEL_TYPE_MAP as BASE_MODEL_NAME_MAP } from 'features/system/components/ModelSelect';
|
||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useListModelsQuery } from 'services/apiSlice';
|
||||
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||
|
||||
const ModelInputFieldComponent = (
|
||||
props: FieldComponentProps<ModelInputFieldValue, ModelInputFieldTemplate>
|
||||
|
@ -3,7 +3,7 @@ import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { Panel } from 'reactflow';
|
||||
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||
import NodeInvokeButton from '../ui/NodeInvokeButton';
|
||||
|
||||
const TopCenterPanel = () => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createAction, isAnyOf } from '@reduxjs/toolkit';
|
||||
import { Graph } from 'services/api';
|
||||
import { Graph } from 'services/api/types';
|
||||
|
||||
export const textToImageGraphBuilt = createAction<Graph>(
|
||||
'nodes/textToImageGraphBuilt'
|
||||
|
@ -11,14 +11,14 @@ import {
|
||||
NodeChange,
|
||||
OnConnectStartParams,
|
||||
} from 'reactflow';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||
import { InvocationTemplate, InvocationValue } from '../types/types';
|
||||
import { parseSchema } from '../util/parseSchema';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { forEach, size } from 'lodash-es';
|
||||
import { RgbaColor } from 'react-colorful';
|
||||
import { imageUrlsReceived } from 'services/thunks/image';
|
||||
import { imageUrlsReceived } from 'services/api/thunks/image';
|
||||
import { RootState } from 'app/store/store';
|
||||
|
||||
export type NodesState = {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { OpenAPIV3 } from 'openapi-types';
|
||||
import { RgbaColor } from 'react-colorful';
|
||||
import { Graph, ImageDTO } from 'services/api';
|
||||
import { Graph, ImageDTO } from 'services/api/types';
|
||||
import { AnyInvocationType } from 'services/events/types';
|
||||
import { O } from 'ts-toolbelt';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { RootState } from 'app/store/store';
|
||||
import { filter, forEach, size } from 'lodash-es';
|
||||
import { CollectInvocation, ControlNetInvocation } from 'services/api';
|
||||
import { CollectInvocation, ControlNetInvocation } from 'services/api/types';
|
||||
import { NonNullableGraph } from '../types/types';
|
||||
import { CONTROL_NET_COLLECT } from './graphBuilders/constants';
|
||||
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
RandomRangeInvocation,
|
||||
RangeInvocation,
|
||||
TextToImageInvocation,
|
||||
} from 'services/api';
|
||||
} from 'services/api/types';
|
||||
|
||||
export const buildEdges = (
|
||||
baseNode: TextToImageInvocation | ImageToImageInvocation | InpaintInvocation,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { RootState } from 'app/store/store';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { forEach } from 'lodash-es';
|
||||
import { buildCanvasInpaintGraph } from './buildCanvasInpaintGraph';
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
ImageResizeInvocation,
|
||||
RandomIntInvocation,
|
||||
RangeOfSizeInvocation,
|
||||
} from 'services/api';
|
||||
} from 'services/api/types';
|
||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import {
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
InpaintInvocation,
|
||||
RandomIntInvocation,
|
||||
RangeOfSizeInvocation,
|
||||
} from 'services/api';
|
||||
} from 'services/api/types';
|
||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { RootState } from 'app/store/store';
|
||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||
import { RandomIntInvocation, RangeOfSizeInvocation } from 'services/api';
|
||||
import { RandomIntInvocation, RangeOfSizeInvocation } from 'services/api/types';
|
||||
import {
|
||||
ITERATE,
|
||||
LATENTS_TO_IMAGE,
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
ImageResizeInvocation,
|
||||
RandomIntInvocation,
|
||||
RangeOfSizeInvocation,
|
||||
} from 'services/api';
|
||||
} from 'services/api/types';
|
||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import {
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
BaseModelType,
|
||||
RandomIntInvocation,
|
||||
RangeOfSizeInvocation,
|
||||
} from 'services/api';
|
||||
} from 'services/api/types';
|
||||
import {
|
||||
ITERATE,
|
||||
LATENTS_TO_IMAGE,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Graph } from 'services/api';
|
||||
import { Graph } from 'services/api/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { cloneDeep, omit, reduce } from 'lodash-es';
|
||||
import { RootState } from 'app/store/store';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BaseModelType, PipelineModelField } from 'services/api';
|
||||
import { BaseModelType, PipelineModelField } from 'services/api/types';
|
||||
|
||||
/**
|
||||
* Crudely converts a model id to a pipeline model field
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { CompelInvocation } from 'services/api';
|
||||
import { CompelInvocation } from 'services/api/types';
|
||||
import { O } from 'ts-toolbelt';
|
||||
|
||||
export const buildCompelNode = (
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
Edge,
|
||||
ImageToImageInvocation,
|
||||
TextToImageInvocation,
|
||||
} from 'services/api';
|
||||
} from 'services/api/types';
|
||||
import { O } from 'ts-toolbelt';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { InpaintInvocation } from 'services/api';
|
||||
import { InpaintInvocation } from 'services/api/types';
|
||||
import { O } from 'ts-toolbelt';
|
||||
|
||||
export const buildInpaintNode = (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { IterateInvocation } from 'services/api';
|
||||
import { IterateInvocation } from 'services/api/types';
|
||||
|
||||
export const buildIterateNode = (): IterateInvocation => {
|
||||
const nodeId = uuidv4();
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { RootState } from 'app/store/store';
|
||||
import { RandomRangeInvocation, RangeInvocation } from 'services/api';
|
||||
import { RandomRangeInvocation, RangeInvocation } from 'services/api/types';
|
||||
|
||||
export const buildRangeNode = (
|
||||
state: RootState
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { TextToImageInvocation } from 'services/api';
|
||||
import { TextToImageInvocation } from 'services/api/types';
|
||||
import { O } from 'ts-toolbelt';
|
||||
|
||||
export const buildTxt2ImgNode = (
|
||||
|
@ -9,9 +9,9 @@ import { useCallback } from 'react';
|
||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
||||
import { useGetImageDTOQuery } from 'services/apiSlice';
|
||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||
|
||||
const selector = createSelector(
|
||||
@ -30,7 +30,7 @@ const InitialImagePreview = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const {
|
||||
data: image,
|
||||
currentData: image,
|
||||
isLoading,
|
||||
isError,
|
||||
isSuccess,
|
||||
|
@ -26,7 +26,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MdCancel, MdCancelScheduleSend } from 'react-icons/md';
|
||||
|
||||
import { sessionCanceled } from 'services/thunks/session';
|
||||
import { sessionCanceled } from 'services/api/thunks/session';
|
||||
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||
|
||||
const cancelButtonSelector = createSelector(
|
||||
@ -78,7 +78,7 @@ const CancelButton = (
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(sessionCanceled({ sessionId }));
|
||||
dispatch(sessionCanceled({ session_id: sessionId }));
|
||||
}, [dispatch, sessionId, cancelType]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
@ -13,10 +13,10 @@ import {
|
||||
setSteps,
|
||||
setWidth,
|
||||
} from '../store/generationSlice';
|
||||
import { isImageField } from 'services/types/guards';
|
||||
import { isImageField } from 'services/api/guards';
|
||||
import { initialImageSelected } from '../store/actions';
|
||||
import { useAppToaster } from 'app/components/Toaster';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import {
|
||||
isValidCfgScale,
|
||||
isValidHeight,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
|
||||
export const initialImageSelected = createAction<ImageDTO | string | undefined>(
|
||||
'generation/initialImageSelected'
|
||||
|
@ -3,7 +3,7 @@ import { createSlice } from '@reduxjs/toolkit';
|
||||
import { DEFAULT_SCHEDULER_NAME } from 'app/constants';
|
||||
import { configChanged } from 'features/system/store/configSlice';
|
||||
import { clamp } from 'lodash-es';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import {
|
||||
CfgScaleParam,
|
||||
HeightParam,
|
||||
|
@ -8,7 +8,7 @@ import { modelSelected } from 'features/parameters/store/generationSlice';
|
||||
import { forEach, isString } from 'lodash-es';
|
||||
import { SelectItem } from '@mantine/core';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useListModelsQuery } from 'services/apiSlice';
|
||||
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||
|
||||
export const MODEL_TYPE_MAP = {
|
||||
'sd-1': 'Stable Diffusion 1.x',
|
||||
|
@ -19,8 +19,11 @@ import {
|
||||
appSocketUnsubscribed,
|
||||
} from 'services/events/actions';
|
||||
import { ProgressImage } from 'services/events/types';
|
||||
import { imageUploaded } from 'services/thunks/image';
|
||||
import { isAnySessionRejected, sessionCanceled } from 'services/thunks/session';
|
||||
import { imageUploaded } from 'services/api/thunks/image';
|
||||
import {
|
||||
isAnySessionRejected,
|
||||
sessionCanceled,
|
||||
} from 'services/api/thunks/session';
|
||||
import { makeToast } from '../../../app/components/Toaster';
|
||||
import { LANGUAGES } from '../components/LanguagePicker';
|
||||
|
||||
@ -362,7 +365,7 @@ export const systemSlice = createSlice({
|
||||
* Session Canceled - FULFILLED
|
||||
*/
|
||||
builder.addCase(sessionCanceled.fulfilled, (state, action) => {
|
||||
state.canceledSession = action.meta.arg.sessionId;
|
||||
state.canceledSession = action.meta.arg.session_id;
|
||||
state.isProcessing = false;
|
||||
state.isCancelable = false;
|
||||
state.isCancelScheduled = false;
|
||||
|
@ -12,7 +12,7 @@ import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||
import { memo, useCallback, useLayoutEffect } from 'react';
|
||||
import UnifiedCanvasToolbarBeta from './UnifiedCanvasBeta/UnifiedCanvasToolbarBeta';
|
||||
import UnifiedCanvasToolSettingsBeta from './UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta';
|
||||
import { ImageDTO } from 'services/api';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||
import { useDroppable } from '@dnd-kit/core';
|
||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
||||
|
33
invokeai/frontend/web/src/services/api/client.ts
Normal file
33
invokeai/frontend/web/src/services/api/client.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { atom, computed } from 'nanostores';
|
||||
import createClient from 'openapi-fetch';
|
||||
import { paths } from 'services/api/schema';
|
||||
|
||||
/**
|
||||
* We use nanostores to store the token and base url for very simple reactivity
|
||||
*/
|
||||
|
||||
/**
|
||||
* The user's auth token.
|
||||
*/
|
||||
export const $authToken = atom<string | undefined>();
|
||||
|
||||
/**
|
||||
* The OpenAPI base url.
|
||||
*/
|
||||
export const $baseUrl = atom<string | undefined>();
|
||||
|
||||
/**
|
||||
* Autogenerated, type-safe fetch client for the API. Used when RTK Query is not an option.
|
||||
* Dynamically updates when the token or base url changes.
|
||||
* Use `$client.get()` to get the client.
|
||||
*
|
||||
* @example
|
||||
* const { get, post, del } = $client.get();
|
||||
*/
|
||||
export const $client = computed([$authToken, $baseUrl], (authToken, baseUrl) =>
|
||||
createClient<paths>({
|
||||
headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},
|
||||
// do not include `api/v1` in the base url for this client
|
||||
baseUrl: `${baseUrl ?? ''}`,
|
||||
})
|
||||
);
|
@ -1,24 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
import type { ApiResult } from './ApiResult';
|
||||
|
||||
export class ApiError extends Error {
|
||||
public readonly url: string;
|
||||
public readonly status: number;
|
||||
public readonly statusText: string;
|
||||
public readonly body: any;
|
||||
public readonly request: ApiRequestOptions;
|
||||
|
||||
constructor(request: ApiRequestOptions, response: ApiResult, message: string) {
|
||||
super(message);
|
||||
|
||||
this.name = 'ApiError';
|
||||
this.url = response.url;
|
||||
this.status = response.status;
|
||||
this.statusText = response.statusText;
|
||||
this.body = response.body;
|
||||
this.request = request;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type ApiRequestOptions = {
|
||||
readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
|
||||
readonly url: string;
|
||||
readonly path?: Record<string, any>;
|
||||
readonly cookies?: Record<string, any>;
|
||||
readonly headers?: Record<string, any>;
|
||||
readonly query?: Record<string, any>;
|
||||
readonly formData?: Record<string, any>;
|
||||
readonly body?: any;
|
||||
readonly mediaType?: string;
|
||||
readonly responseHeader?: string;
|
||||
readonly errors?: Record<number, string>;
|
||||
};
|
@ -1,10 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export type ApiResult = {
|
||||
readonly url: string;
|
||||
readonly ok: boolean;
|
||||
readonly status: number;
|
||||
readonly statusText: string;
|
||||
readonly body: any;
|
||||
};
|
@ -1,130 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
export class CancelError extends Error {
|
||||
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'CancelError';
|
||||
}
|
||||
|
||||
public get isCancelled(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface OnCancel {
|
||||
readonly isResolved: boolean;
|
||||
readonly isRejected: boolean;
|
||||
readonly isCancelled: boolean;
|
||||
|
||||
(cancelHandler: () => void): void;
|
||||
}
|
||||
|
||||
export class CancelablePromise<T> implements Promise<T> {
|
||||
#isResolved: boolean;
|
||||
#isRejected: boolean;
|
||||
#isCancelled: boolean;
|
||||
readonly #cancelHandlers: (() => void)[];
|
||||
readonly #promise: Promise<T>;
|
||||
#resolve?: (value: T | PromiseLike<T>) => void;
|
||||
#reject?: (reason?: any) => void;
|
||||
|
||||
constructor(
|
||||
executor: (
|
||||
resolve: (value: T | PromiseLike<T>) => void,
|
||||
reject: (reason?: any) => void,
|
||||
onCancel: OnCancel
|
||||
) => void
|
||||
) {
|
||||
this.#isResolved = false;
|
||||
this.#isRejected = false;
|
||||
this.#isCancelled = false;
|
||||
this.#cancelHandlers = [];
|
||||
this.#promise = new Promise<T>((resolve, reject) => {
|
||||
this.#resolve = resolve;
|
||||
this.#reject = reject;
|
||||
|
||||
const onResolve = (value: T | PromiseLike<T>): void => {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#isResolved = true;
|
||||
this.#resolve?.(value);
|
||||
};
|
||||
|
||||
const onReject = (reason?: any): void => {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#isRejected = true;
|
||||
this.#reject?.(reason);
|
||||
};
|
||||
|
||||
const onCancel = (cancelHandler: () => void): void => {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#cancelHandlers.push(cancelHandler);
|
||||
};
|
||||
|
||||
Object.defineProperty(onCancel, 'isResolved', {
|
||||
get: (): boolean => this.#isResolved,
|
||||
});
|
||||
|
||||
Object.defineProperty(onCancel, 'isRejected', {
|
||||
get: (): boolean => this.#isRejected,
|
||||
});
|
||||
|
||||
Object.defineProperty(onCancel, 'isCancelled', {
|
||||
get: (): boolean => this.#isCancelled,
|
||||
});
|
||||
|
||||
return executor(onResolve, onReject, onCancel as OnCancel);
|
||||
});
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag]() {
|
||||
return "Cancellable Promise";
|
||||
}
|
||||
|
||||
public then<TResult1 = T, TResult2 = never>(
|
||||
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
||||
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
||||
): Promise<TResult1 | TResult2> {
|
||||
return this.#promise.then(onFulfilled, onRejected);
|
||||
}
|
||||
|
||||
public catch<TResult = never>(
|
||||
onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
|
||||
): Promise<T | TResult> {
|
||||
return this.#promise.catch(onRejected);
|
||||
}
|
||||
|
||||
public finally(onFinally?: (() => void) | null): Promise<T> {
|
||||
return this.#promise.finally(onFinally);
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
if (this.#isResolved || this.#isRejected || this.#isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.#isCancelled = true;
|
||||
if (this.#cancelHandlers.length) {
|
||||
try {
|
||||
for (const cancelHandler of this.#cancelHandlers) {
|
||||
cancelHandler();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Cancellation threw an error', error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.#cancelHandlers.length = 0;
|
||||
this.#reject?.(new CancelError('Request aborted'));
|
||||
}
|
||||
|
||||
public get isCancelled(): boolean {
|
||||
return this.#isCancelled;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
|
||||
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
|
||||
type Headers = Record<string, string>;
|
||||
|
||||
export type OpenAPIConfig = {
|
||||
BASE: string;
|
||||
VERSION: string;
|
||||
WITH_CREDENTIALS: boolean;
|
||||
CREDENTIALS: 'include' | 'omit' | 'same-origin';
|
||||
TOKEN?: string | Resolver<string>;
|
||||
USERNAME?: string | Resolver<string>;
|
||||
PASSWORD?: string | Resolver<string>;
|
||||
HEADERS?: Headers | Resolver<Headers>;
|
||||
ENCODE_PATH?: (path: string) => string;
|
||||
};
|
||||
|
||||
export const OpenAPI: OpenAPIConfig = {
|
||||
BASE: '',
|
||||
VERSION: '1.0.0',
|
||||
WITH_CREDENTIALS: false,
|
||||
CREDENTIALS: 'include',
|
||||
TOKEN: undefined,
|
||||
USERNAME: undefined,
|
||||
PASSWORD: undefined,
|
||||
HEADERS: undefined,
|
||||
ENCODE_PATH: undefined,
|
||||
};
|
@ -1,353 +0,0 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* DO NOT DELETE EVEN THOUGH IT IS NOT USED!
|
||||
*
|
||||
* Custom `request.ts` file for OpenAPI code generator.
|
||||
*
|
||||
* Patches the request logic in such a way that we can extract headers from requests.
|
||||
*
|
||||
* Copied from https://github.com/ferdikoomen/openapi-typescript-codegen/issues/829#issuecomment-1228224477
|
||||
*
|
||||
* This file should be excluded in `tsconfig.json` and ignored by prettier/eslint!
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import FormData from 'form-data';
|
||||
|
||||
import { ApiError } from './ApiError';
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
import type { ApiResult } from './ApiResult';
|
||||
import { CancelablePromise } from './CancelablePromise';
|
||||
import type { OnCancel } from './CancelablePromise';
|
||||
import type { OpenAPIConfig } from './OpenAPI';
|
||||
|
||||
export const HEADERS = Symbol('HEADERS');
|
||||
|
||||
const isDefined = <T>(
|
||||
value: T | null | undefined
|
||||
): value is Exclude<T, null | undefined> => {
|
||||
return value !== undefined && value !== null;
|
||||
};
|
||||
|
||||
const isString = (value: any): value is string => {
|
||||
return typeof value === 'string';
|
||||
};
|
||||
|
||||
const isStringWithValue = (value: any): value is string => {
|
||||
return isString(value) && value !== '';
|
||||
};
|
||||
|
||||
const isBlob = (value: any): value is Blob => {
|
||||
return (
|
||||
typeof value === 'object' &&
|
||||
typeof value.type === 'string' &&
|
||||
typeof value.stream === 'function' &&
|
||||
typeof value.arrayBuffer === 'function' &&
|
||||
typeof value.constructor === 'function' &&
|
||||
typeof value.constructor.name === 'string' &&
|
||||
/^(Blob|File)$/.test(value.constructor.name) &&
|
||||
/^(Blob|File)$/.test(value[Symbol.toStringTag])
|
||||
);
|
||||
};
|
||||
|
||||
const isFormData = (value: any): value is FormData => {
|
||||
return value instanceof FormData;
|
||||
};
|
||||
|
||||
const isSuccess = (status: number): boolean => {
|
||||
return status >= 200 && status < 300;
|
||||
};
|
||||
|
||||
const base64 = (str: string): string => {
|
||||
try {
|
||||
return btoa(str);
|
||||
} catch (err) {
|
||||
// @ts-ignore
|
||||
return Buffer.from(str).toString('base64');
|
||||
}
|
||||
};
|
||||
|
||||
const getQueryString = (params: Record<string, any>): string => {
|
||||
const qs: string[] = [];
|
||||
|
||||
const append = (key: string, value: any) => {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||
};
|
||||
|
||||
const process = (key: string, value: any) => {
|
||||
if (isDefined(value)) {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((v) => {
|
||||
process(key, v);
|
||||
});
|
||||
} else if (typeof value === 'object') {
|
||||
Object.entries(value).forEach(([k, v]) => {
|
||||
process(`${key}[${k}]`, v);
|
||||
});
|
||||
} else {
|
||||
append(key, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
process(key, value);
|
||||
});
|
||||
|
||||
if (qs.length > 0) {
|
||||
return `?${qs.join('&')}`;
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
|
||||
const encoder = config.ENCODE_PATH || encodeURI;
|
||||
|
||||
const path = options.url
|
||||
.replace('{api-version}', config.VERSION)
|
||||
.replace(/{(.*?)}/g, (substring: string, group: string) => {
|
||||
if (options.path?.hasOwnProperty(group)) {
|
||||
return encoder(String(options.path[group]));
|
||||
}
|
||||
return substring;
|
||||
});
|
||||
|
||||
const url = `${config.BASE}${path}`;
|
||||
if (options.query) {
|
||||
return `${url}${getQueryString(options.query)}`;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
const getFormData = (options: ApiRequestOptions): FormData | undefined => {
|
||||
if (options.formData) {
|
||||
const formData = new FormData();
|
||||
|
||||
const process = (key: string, value: any) => {
|
||||
if (isString(value) || isBlob(value)) {
|
||||
formData.append(key, value);
|
||||
} else {
|
||||
formData.append(key, JSON.stringify(value));
|
||||
}
|
||||
};
|
||||
|
||||
Object.entries(options.formData)
|
||||
.filter(([_, value]) => isDefined(value))
|
||||
.forEach(([key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((v) => process(key, v));
|
||||
} else {
|
||||
process(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
return formData;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
|
||||
|
||||
const resolve = async <T>(
|
||||
options: ApiRequestOptions,
|
||||
resolver?: T | Resolver<T>
|
||||
): Promise<T | undefined> => {
|
||||
if (typeof resolver === 'function') {
|
||||
return (resolver as Resolver<T>)(options);
|
||||
}
|
||||
return resolver;
|
||||
};
|
||||
|
||||
const getHeaders = async (
|
||||
config: OpenAPIConfig,
|
||||
options: ApiRequestOptions,
|
||||
formData?: FormData
|
||||
): Promise<Record<string, string>> => {
|
||||
const token = await resolve(options, config.TOKEN);
|
||||
const username = await resolve(options, config.USERNAME);
|
||||
const password = await resolve(options, config.PASSWORD);
|
||||
const additionalHeaders = await resolve(options, config.HEADERS);
|
||||
const formHeaders =
|
||||
(typeof formData?.getHeaders === 'function' && formData?.getHeaders()) ||
|
||||
{};
|
||||
|
||||
const headers = Object.entries({
|
||||
Accept: 'application/json',
|
||||
...additionalHeaders,
|
||||
...options.headers,
|
||||
...formHeaders,
|
||||
})
|
||||
.filter(([_, value]) => isDefined(value))
|
||||
.reduce(
|
||||
(headers, [key, value]) => ({
|
||||
...headers,
|
||||
[key]: String(value),
|
||||
}),
|
||||
{} as Record<string, string>
|
||||
);
|
||||
|
||||
if (isStringWithValue(token)) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
if (isStringWithValue(username) && isStringWithValue(password)) {
|
||||
const credentials = base64(`${username}:${password}`);
|
||||
headers['Authorization'] = `Basic ${credentials}`;
|
||||
}
|
||||
|
||||
if (options.body) {
|
||||
if (options.mediaType) {
|
||||
headers['Content-Type'] = options.mediaType;
|
||||
} else if (isBlob(options.body)) {
|
||||
headers['Content-Type'] = options.body.type || 'application/octet-stream';
|
||||
} else if (isString(options.body)) {
|
||||
headers['Content-Type'] = 'text/plain';
|
||||
} else if (!isFormData(options.body)) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
const getRequestBody = (options: ApiRequestOptions): any => {
|
||||
if (options.body) {
|
||||
return options.body;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const sendRequest = async <T>(
|
||||
config: OpenAPIConfig,
|
||||
options: ApiRequestOptions,
|
||||
url: string,
|
||||
body: any,
|
||||
formData: FormData | undefined,
|
||||
headers: Record<string, string>,
|
||||
onCancel: OnCancel
|
||||
): Promise<AxiosResponse<T>> => {
|
||||
const source = axios.CancelToken.source();
|
||||
|
||||
const requestConfig: AxiosRequestConfig = {
|
||||
url,
|
||||
headers,
|
||||
data: body ?? formData,
|
||||
method: options.method,
|
||||
withCredentials: config.WITH_CREDENTIALS,
|
||||
cancelToken: source.token,
|
||||
};
|
||||
|
||||
onCancel(() => source.cancel('The user aborted a request.'));
|
||||
|
||||
try {
|
||||
return await axios.request(requestConfig);
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError<T>;
|
||||
if (axiosError.response) {
|
||||
return axiosError.response;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getResponseHeader = (
|
||||
response: AxiosResponse<any>,
|
||||
responseHeader?: string
|
||||
): string | undefined => {
|
||||
if (responseHeader) {
|
||||
const content = response.headers[responseHeader];
|
||||
if (isString(content)) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const getResponseBody = (response: AxiosResponse<any>): any => {
|
||||
if (response.status !== 204) {
|
||||
return response.data;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const catchErrorCodes = (
|
||||
options: ApiRequestOptions,
|
||||
result: ApiResult
|
||||
): void => {
|
||||
const errors: Record<number, string> = {
|
||||
400: 'Bad Request',
|
||||
401: 'Unauthorized',
|
||||
403: 'Forbidden',
|
||||
404: 'Not Found',
|
||||
500: 'Internal Server Error',
|
||||
502: 'Bad Gateway',
|
||||
503: 'Service Unavailable',
|
||||
...options.errors,
|
||||
};
|
||||
|
||||
const error = errors[result.status];
|
||||
if (error) {
|
||||
throw new ApiError(options, result, error);
|
||||
}
|
||||
|
||||
if (!result.ok) {
|
||||
throw new ApiError(options, result, 'Generic Error');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Request method
|
||||
* @param config The OpenAPI configuration object
|
||||
* @param options The request options from the service
|
||||
* @returns CancelablePromise<T>
|
||||
* @throws ApiError
|
||||
*/
|
||||
export const request = <T>(
|
||||
config: OpenAPIConfig,
|
||||
options: ApiRequestOptions
|
||||
): CancelablePromise<T> => {
|
||||
return new CancelablePromise(async (resolve, reject, onCancel) => {
|
||||
try {
|
||||
const url = getUrl(config, options);
|
||||
const formData = getFormData(options);
|
||||
const body = getRequestBody(options);
|
||||
const headers = await getHeaders(config, options, formData);
|
||||
|
||||
if (!onCancel.isCancelled) {
|
||||
const response = await sendRequest<T>(
|
||||
config,
|
||||
options,
|
||||
url,
|
||||
body,
|
||||
formData,
|
||||
headers,
|
||||
onCancel
|
||||
);
|
||||
const responseBody = getResponseBody(response);
|
||||
const responseHeader = getResponseHeader(
|
||||
response,
|
||||
options.responseHeader
|
||||
);
|
||||
|
||||
const result: ApiResult = {
|
||||
url,
|
||||
ok: isSuccess(response.status),
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: responseHeader ?? responseBody,
|
||||
};
|
||||
|
||||
catchErrorCodes(options, result);
|
||||
|
||||
resolve({ ...result.body, [HEADERS]: response.headers });
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
@ -0,0 +1,66 @@
|
||||
import { OffsetPaginatedResults_ImageDTO_ } from 'services/api/types';
|
||||
import { api } from '..';
|
||||
import { paths } from '../schema';
|
||||
|
||||
type ListBoardImagesArg =
|
||||
paths['/api/v1/board_images/{board_id}']['get']['parameters']['path'] &
|
||||
paths['/api/v1/board_images/{board_id}']['get']['parameters']['query'];
|
||||
|
||||
type AddImageToBoardArg =
|
||||
paths['/api/v1/board_images/']['post']['requestBody']['content']['application/json'];
|
||||
|
||||
type RemoveImageFromBoardArg =
|
||||
paths['/api/v1/board_images/']['delete']['requestBody']['content']['application/json'];
|
||||
|
||||
export const boardImagesApi = api.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
/**
|
||||
* Board Images Queries
|
||||
*/
|
||||
|
||||
listBoardImages: build.query<
|
||||
OffsetPaginatedResults_ImageDTO_,
|
||||
ListBoardImagesArg
|
||||
>({
|
||||
query: ({ board_id, offset, limit }) => ({
|
||||
url: `board_images/${board_id}`,
|
||||
method: 'DELETE',
|
||||
body: { offset, limit },
|
||||
}),
|
||||
}),
|
||||
|
||||
/**
|
||||
* Board Images Mutations
|
||||
*/
|
||||
|
||||
addImageToBoard: build.mutation<void, AddImageToBoardArg>({
|
||||
query: ({ board_id, image_name }) => ({
|
||||
url: `board_images/`,
|
||||
method: 'POST',
|
||||
body: { board_id, image_name },
|
||||
}),
|
||||
invalidatesTags: (result, error, arg) => [
|
||||
{ type: 'Board', id: arg.board_id },
|
||||
{ type: 'Image', id: arg.image_name },
|
||||
],
|
||||
}),
|
||||
|
||||
removeImageFromBoard: build.mutation<void, RemoveImageFromBoardArg>({
|
||||
query: ({ board_id, image_name }) => ({
|
||||
url: `board_images/`,
|
||||
method: 'DELETE',
|
||||
body: { board_id, image_name },
|
||||
}),
|
||||
invalidatesTags: (result, error, arg) => [
|
||||
{ type: 'Board', id: arg.board_id },
|
||||
{ type: 'Image', id: arg.image_name },
|
||||
],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const {
|
||||
useAddImageToBoardMutation,
|
||||
useRemoveImageFromBoardMutation,
|
||||
useListBoardImagesQuery,
|
||||
} = boardImagesApi;
|
99
invokeai/frontend/web/src/services/api/endpoints/boards.ts
Normal file
99
invokeai/frontend/web/src/services/api/endpoints/boards.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { BoardDTO, OffsetPaginatedResults_BoardDTO_ } from 'services/api/types';
|
||||
import { ApiFullTagDescription, LIST_TAG, api } from '..';
|
||||
import { paths } from '../schema';
|
||||
|
||||
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'];
|
||||
};
|
||||
|
||||
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[] = [{ id: 'Board', type: 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[] = [{ id: 'Board', type: 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;
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Boards Mutations
|
||||
*/
|
||||
|
||||
createBoard: build.mutation<BoardDTO, string>({
|
||||
query: (board_name) => ({
|
||||
url: `boards/`,
|
||||
method: 'POST',
|
||||
params: { board_name },
|
||||
}),
|
||||
invalidatesTags: [{ id: 'Board', type: 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<void, string>({
|
||||
query: (board_id) => ({ url: `boards/${board_id}`, method: 'DELETE' }),
|
||||
invalidatesTags: (result, error, arg) => [{ type: 'Board', id: arg }],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const {
|
||||
useListBoardsQuery,
|
||||
useListAllBoardsQuery,
|
||||
useCreateBoardMutation,
|
||||
useUpdateBoardMutation,
|
||||
useDeleteBoardMutation,
|
||||
} = boardsApi;
|
22
invokeai/frontend/web/src/services/api/endpoints/images.ts
Normal file
22
invokeai/frontend/web/src/services/api/endpoints/images.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { ApiFullTagDescription, api } from '..';
|
||||
import { ImageDTO } from '../types';
|
||||
|
||||
export const imagesApi = api.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
/**
|
||||
* Image Queries
|
||||
*/
|
||||
getImageDTO: build.query<ImageDTO, string>({
|
||||
query: (image_name) => ({ url: `images/${image_name}/metadata` }),
|
||||
providesTags: (result, error, arg) => {
|
||||
const tags: ApiFullTagDescription[] = [{ type: 'Image', id: arg }];
|
||||
if (result?.board_id) {
|
||||
tags.push({ type: 'Board', id: result.board_id });
|
||||
}
|
||||
return tags;
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const { useGetImageDTOQuery } = imagesApi;
|
52
invokeai/frontend/web/src/services/api/endpoints/models.ts
Normal file
52
invokeai/frontend/web/src/services/api/endpoints/models.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { ModelsList } from 'services/api/types';
|
||||
import { EntityState, createEntityAdapter } from '@reduxjs/toolkit';
|
||||
import { keyBy } from 'lodash-es';
|
||||
|
||||
import { ApiFullTagDescription, LIST_TAG, api } from '..';
|
||||
import { paths } from '../schema';
|
||||
|
||||
type ModelConfig = ModelsList['models'][number];
|
||||
|
||||
type ListModelsArg = NonNullable<
|
||||
paths['/api/v1/models/']['get']['parameters']['query']
|
||||
>;
|
||||
|
||||
const modelsAdapter = createEntityAdapter<ModelConfig>({
|
||||
selectId: (model) => getModelId(model),
|
||||
sortComparer: (a, b) => a.name.localeCompare(b.name),
|
||||
});
|
||||
|
||||
const getModelId = ({ base_model, type, name }: ModelConfig) =>
|
||||
`${base_model}/${type}/${name}`;
|
||||
|
||||
export const modelsApi = api.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
listModels: build.query<EntityState<ModelConfig>, ListModelsArg>({
|
||||
query: (arg) => ({ url: 'models/', params: arg }),
|
||||
providesTags: (result, error, arg) => {
|
||||
// any list of boards
|
||||
const tags: ApiFullTagDescription[] = [{ id: 'Model', type: LIST_TAG }];
|
||||
|
||||
if (result) {
|
||||
// and individual tags for each board
|
||||
tags.push(
|
||||
...result.ids.map((id) => ({
|
||||
type: 'Model' as const,
|
||||
id,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
return tags;
|
||||
},
|
||||
transformResponse: (response: ModelsList, meta, arg) => {
|
||||
return modelsAdapter.setAll(
|
||||
modelsAdapter.getInitialState(),
|
||||
keyBy(response.models, getModelId)
|
||||
);
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const { useListModelsQuery } = modelsApi;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user