mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Merge branch 'main' into lstein/installer-for-new-model-layout
This commit is contained in:
commit
d5f742620f
@ -543,6 +543,7 @@ class LatentsToImageInvocation(BaseInvocation):
|
|||||||
image_category=ImageCategory.GENERAL,
|
image_category=ImageCategory.GENERAL,
|
||||||
node_id=self.id,
|
node_id=self.id,
|
||||||
session_id=context.graph_execution_state_id,
|
session_id=context.graph_execution_state_id,
|
||||||
|
is_intermediate=self.is_intermediate
|
||||||
)
|
)
|
||||||
|
|
||||||
return ImageOutput(
|
return ImageOutput(
|
||||||
|
@ -23,8 +23,7 @@
|
|||||||
"dev": "concurrently \"vite dev\" \"yarn run theme:watch\"",
|
"dev": "concurrently \"vite dev\" \"yarn run theme:watch\"",
|
||||||
"dev:host": "concurrently \"vite dev --host\" \"yarn run theme:watch\"",
|
"dev:host": "concurrently \"vite dev --host\" \"yarn run theme:watch\"",
|
||||||
"build": "yarn run lint && vite build",
|
"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",
|
"typegen": "npx openapi-typescript http://localhost:9090/openapi.json --output src/services/schema.d.ts -t",
|
||||||
"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",
|
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint:madge": "madge --circular src/main.tsx",
|
"lint:madge": "madge --circular src/main.tsx",
|
||||||
"lint:eslint": "eslint --max-warnings=0 .",
|
"lint:eslint": "eslint --max-warnings=0 .",
|
||||||
@ -81,9 +80,12 @@
|
|||||||
"i18next-http-backend": "^2.2.0",
|
"i18next-http-backend": "^2.2.0",
|
||||||
"konva": "^9.0.1",
|
"konva": "^9.0.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
|
"nanostores": "^0.9.2",
|
||||||
|
"openapi-fetch": "^0.4.0",
|
||||||
"overlayscrollbars": "^2.1.1",
|
"overlayscrollbars": "^2.1.1",
|
||||||
"overlayscrollbars-react": "^0.5.0",
|
"overlayscrollbars-react": "^0.5.0",
|
||||||
"patch-package": "^7.0.0",
|
"patch-package": "^7.0.0",
|
||||||
|
"query-string": "^8.1.0",
|
||||||
"re-resizable": "^6.9.9",
|
"re-resizable": "^6.9.9",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-colorful": "^5.6.1",
|
"react-colorful": "^5.6.1",
|
||||||
@ -140,6 +142,7 @@
|
|||||||
"lint-staged": "^13.2.2",
|
"lint-staged": "^13.2.2",
|
||||||
"madge": "^6.0.0",
|
"madge": "^6.0.0",
|
||||||
"openapi-types": "^12.1.0",
|
"openapi-types": "^12.1.0",
|
||||||
|
"openapi-typescript": "^6.2.8",
|
||||||
"openapi-typescript-codegen": "^0.24.0",
|
"openapi-typescript-codegen": "^0.24.0",
|
||||||
"postinstall-postinstall": "^2.1.0",
|
"postinstall-postinstall": "^2.1.0",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
|
55
invokeai/frontend/web/patches/openapi-fetch+0.4.0.patch
Normal file
55
invokeai/frontend/web/patches/openapi-fetch+0.4.0.patch
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
diff --git a/node_modules/openapi-fetch/dist/index.js b/node_modules/openapi-fetch/dist/index.js
|
||||||
|
index cd4528a..8976b51 100644
|
||||||
|
--- a/node_modules/openapi-fetch/dist/index.js
|
||||||
|
+++ b/node_modules/openapi-fetch/dist/index.js
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
// settings & const
|
||||||
|
-const DEFAULT_HEADERS = {
|
||||||
|
+const CONTENT_TYPE_APPLICATION_JSON = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
};
|
||||||
|
const TRAILING_SLASH_RE = /\/*$/;
|
||||||
|
@@ -29,18 +29,29 @@ export function createFinalURL(url, options) {
|
||||||
|
}
|
||||||
|
return finalURL;
|
||||||
|
}
|
||||||
|
+function stringifyBody(body) {
|
||||||
|
+ if (body instanceof ArrayBuffer || body instanceof File || body instanceof DataView || body instanceof Blob || ArrayBuffer.isView(body) || body instanceof URLSearchParams || body instanceof FormData) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (typeof body === "string") {
|
||||||
|
+ return body;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return JSON.stringify(body);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
export default function createClient(clientOptions = {}) {
|
||||||
|
const { fetch = globalThis.fetch, ...options } = clientOptions;
|
||||||
|
- const defaultHeaders = new Headers({
|
||||||
|
- ...DEFAULT_HEADERS,
|
||||||
|
- ...(options.headers ?? {}),
|
||||||
|
- });
|
||||||
|
+ const defaultHeaders = new Headers(options.headers ?? {});
|
||||||
|
async function coreFetch(url, fetchOptions) {
|
||||||
|
const { headers, body: requestBody, params = {}, parseAs = "json", querySerializer = defaultSerializer, ...init } = fetchOptions || {};
|
||||||
|
// URL
|
||||||
|
const finalURL = createFinalURL(url, { baseUrl: options.baseUrl, params, querySerializer });
|
||||||
|
+ // Stringify body if needed
|
||||||
|
+ const stringifiedBody = stringifyBody(requestBody);
|
||||||
|
// headers
|
||||||
|
- const baseHeaders = new Headers(defaultHeaders); // clone defaults (don’t overwrite!)
|
||||||
|
+ const baseHeaders = new Headers(stringifiedBody ? { ...CONTENT_TYPE_APPLICATION_JSON, ...defaultHeaders } : defaultHeaders); // clone defaults (don’t overwrite!)
|
||||||
|
const headerOverrides = new Headers(headers);
|
||||||
|
for (const [k, v] of headerOverrides.entries()) {
|
||||||
|
if (v === undefined || v === null)
|
||||||
|
@@ -54,7 +65,7 @@ export default function createClient(clientOptions = {}) {
|
||||||
|
...options,
|
||||||
|
...init,
|
||||||
|
headers: baseHeaders,
|
||||||
|
- body: typeof requestBody === "string" ? requestBody : JSON.stringify(requestBody),
|
||||||
|
+ body: stringifiedBody ?? requestBody,
|
||||||
|
});
|
||||||
|
// handle empty content
|
||||||
|
// note: we return `{}` because we want user truthy checks for `.data` or `.error` to succeed
|
@ -24,7 +24,7 @@ import Toaster from './Toaster';
|
|||||||
import DeleteImageModal from 'features/gallery/components/DeleteImageModal';
|
import DeleteImageModal from 'features/gallery/components/DeleteImageModal';
|
||||||
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
|
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
|
||||||
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
||||||
import { useListModelsQuery } from 'services/apiSlice';
|
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
const DEFAULT_CONFIG = {};
|
const DEFAULT_CONFIG = {};
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@ import {
|
|||||||
} from '@dnd-kit/core';
|
} from '@dnd-kit/core';
|
||||||
import { PropsWithChildren, memo, useCallback, useState } from 'react';
|
import { PropsWithChildren, memo, useCallback, useState } from 'react';
|
||||||
import OverlayDragImage from './OverlayDragImage';
|
import OverlayDragImage from './OverlayDragImage';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { isImageDTO } from 'services/types/guards';
|
import { isImageDTO } from 'services/api/guards';
|
||||||
import { snapCenterToCursor } from '@dnd-kit/modifiers';
|
import { snapCenterToCursor } from '@dnd-kit/modifiers';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Box, Image } from '@chakra-ui/react';
|
import { Box, Image } from '@chakra-ui/react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
type OverlayDragImageProps = {
|
type OverlayDragImageProps = {
|
||||||
image: ImageDTO;
|
image: ImageDTO;
|
||||||
|
@ -7,7 +7,7 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { store } from 'app/store/store';
|
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 Loading from '../../common/components/Loading/Loading';
|
||||||
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
|
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
|
||||||
@ -23,6 +23,7 @@ import {
|
|||||||
} from 'app/contexts/DeleteImageContext';
|
} from 'app/contexts/DeleteImageContext';
|
||||||
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
import UpdateImageBoardModal from '../../features/gallery/components/Boards/UpdateImageBoardModal';
|
||||||
import { AddImageToBoardContextProvider } from '../contexts/AddImageToBoardContext';
|
import { AddImageToBoardContextProvider } from '../contexts/AddImageToBoardContext';
|
||||||
|
import { $authToken, $baseUrl } from 'services/api/client';
|
||||||
|
|
||||||
const App = lazy(() => import('./App'));
|
const App = lazy(() => import('./App'));
|
||||||
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
|
const ThemeLocaleProvider = lazy(() => import('./ThemeLocaleProvider'));
|
||||||
@ -47,12 +48,12 @@ const InvokeAIUI = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// configure API client token
|
// configure API client token
|
||||||
if (token) {
|
if (token) {
|
||||||
OpenAPI.TOKEN = token;
|
$authToken.set(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure API client base url
|
// configure API client base url
|
||||||
if (apiUrl) {
|
if (apiUrl) {
|
||||||
OpenAPI.BASE = apiUrl;
|
$baseUrl.set(apiUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset dynamically added middlewares
|
// reset dynamically added middlewares
|
||||||
@ -69,6 +70,12 @@ const InvokeAIUI = ({
|
|||||||
} else {
|
} else {
|
||||||
addMiddleware(socketMiddleware());
|
addMiddleware(socketMiddleware());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// Reset the API client token and base url on unmount
|
||||||
|
$baseUrl.set(undefined);
|
||||||
|
$authToken.set(undefined);
|
||||||
|
};
|
||||||
}, [apiUrl, token, middleware]);
|
}, [apiUrl, token, middleware]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useDisclosure } from '@chakra-ui/react';
|
import { useDisclosure } from '@chakra-ui/react';
|
||||||
import { PropsWithChildren, createContext, useCallback, useState } from 'react';
|
import { PropsWithChildren, createContext, useCallback, useState } from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { useAddImageToBoardMutation } from 'services/apiSlice';
|
import { useAddImageToBoardMutation } from 'services/api/endpoints/boardImages';
|
||||||
|
|
||||||
export type ImageUsage = {
|
export type ImageUsage = {
|
||||||
isInitialImage: boolean;
|
isInitialImage: boolean;
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
useEffect,
|
useEffect,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
import { controlNetSelector } from 'features/controlNet/store/controlNetSlice';
|
import { controlNetSelector } from 'features/controlNet/store/controlNetSlice';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { AnyAction } from '@reduxjs/toolkit';
|
import { AnyAction } from '@reduxjs/toolkit';
|
||||||
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { forEach } from 'lodash-es';
|
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 => {
|
export const actionSanitizer = <A extends AnyAction>(action: A): A => {
|
||||||
if (isAnyGraphBuilt(action)) {
|
if (isAnyGraphBuilt(action)) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { commitStagingAreaImage } from 'features/canvas/store/canvasSlice';
|
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' });
|
const moduleLog = log.child({ namespace: 'canvas' });
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ export const addCommitStagingAreaImageListener = () => {
|
|||||||
actionCreator: commitStagingAreaImage,
|
actionCreator: commitStagingAreaImage,
|
||||||
effect: async (action, { dispatch, getState }) => {
|
effect: async (action, { dispatch, getState }) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const { sessionId, isProcessing } = state.system;
|
const { sessionId: session_id, isProcessing } = state.system;
|
||||||
const canvasSessionId = action.payload;
|
const canvasSessionId = action.payload;
|
||||||
|
|
||||||
if (!isProcessing) {
|
if (!isProcessing) {
|
||||||
@ -23,12 +23,12 @@ export const addCommitStagingAreaImageListener = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canvasSessionId !== sessionId) {
|
if (canvasSessionId !== session_id) {
|
||||||
moduleLog.debug(
|
moduleLog.debug(
|
||||||
{
|
{
|
||||||
data: {
|
data: {
|
||||||
canvasSessionId,
|
canvasSessionId,
|
||||||
sessionId,
|
session_id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Canvas session does not match global session, skipping cancel'
|
'Canvas session does not match global session, skipping cancel'
|
||||||
@ -36,7 +36,7 @@ export const addCommitStagingAreaImageListener = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(sessionCanceled({ sessionId }));
|
dispatch(sessionCanceled({ session_id }));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -2,9 +2,12 @@ import { log } from 'app/logging/useLogger';
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
||||||
import { selectImagesAll } from 'features/gallery/store/imagesSlice';
|
import { selectImagesAll } from 'features/gallery/store/imagesSlice';
|
||||||
import { IMAGES_PER_PAGE, receivedPageOfImages } from 'services/thunks/image';
|
import {
|
||||||
import { api } from 'services/apiSlice';
|
IMAGES_PER_PAGE,
|
||||||
|
receivedPageOfImages,
|
||||||
|
} from 'services/api/thunks/image';
|
||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
|
import { boardsApi } from 'services/api/endpoints/boards';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'boards' });
|
const moduleLog = log.child({ namespace: 'boards' });
|
||||||
|
|
||||||
@ -12,14 +15,14 @@ export const addBoardIdSelectedListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: boardIdSelected,
|
actionCreator: boardIdSelected,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const boardId = action.payload;
|
const board_id = action.payload;
|
||||||
|
|
||||||
// we need to check if we need to fetch more images
|
// we need to check if we need to fetch more images
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const allImages = selectImagesAll(state);
|
const allImages = selectImagesAll(state);
|
||||||
|
|
||||||
if (!boardId) {
|
if (!board_id) {
|
||||||
// a board was unselected
|
// a board was unselected
|
||||||
dispatch(imageSelected(allImages[0]?.image_name));
|
dispatch(imageSelected(allImages[0]?.image_name));
|
||||||
return;
|
return;
|
||||||
@ -29,13 +32,14 @@ export const addBoardIdSelectedListener = () => {
|
|||||||
|
|
||||||
const filteredImages = allImages.filter((i) => {
|
const filteredImages = allImages.filter((i) => {
|
||||||
const isInCategory = categories.includes(i.image_category);
|
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;
|
return isInCategory && isInSelectedBoard;
|
||||||
});
|
});
|
||||||
|
|
||||||
// get the board from the cache
|
// get the board from the cache
|
||||||
const { data: boards } = api.endpoints.listAllBoards.select()(state);
|
const { data: boards } =
|
||||||
const board = boards?.find((b) => b.board_id === boardId);
|
boardsApi.endpoints.listAllBoards.select()(state);
|
||||||
|
const board = boards?.find((b) => b.board_id === board_id);
|
||||||
|
|
||||||
if (!board) {
|
if (!board) {
|
||||||
// can't find the board in cache...
|
// can't find the board in cache...
|
||||||
@ -50,7 +54,9 @@ export const addBoardIdSelectedListener = () => {
|
|||||||
filteredImages.length < board.image_count &&
|
filteredImages.length < board.image_count &&
|
||||||
filteredImages.length < IMAGES_PER_PAGE
|
filteredImages.length < IMAGES_PER_PAGE
|
||||||
) {
|
) {
|
||||||
dispatch(receivedPageOfImages({ categories, boardId }));
|
dispatch(
|
||||||
|
receivedPageOfImages({ categories, board_id, is_intermediate: false })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -60,13 +66,13 @@ export const addBoardIdSelected_changeSelectedImage_listener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: boardIdSelected,
|
actionCreator: boardIdSelected,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const boardId = action.payload;
|
const board_id = action.payload;
|
||||||
|
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
// we need to check if we need to fetch more images
|
// 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
|
// a board was unselected - we don't need to do anything
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -75,13 +81,14 @@ export const addBoardIdSelected_changeSelectedImage_listener = () => {
|
|||||||
|
|
||||||
const filteredImages = selectImagesAll(state).filter((i) => {
|
const filteredImages = selectImagesAll(state).filter((i) => {
|
||||||
const isInCategory = categories.includes(i.image_category);
|
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;
|
return isInCategory && isInSelectedBoard;
|
||||||
});
|
});
|
||||||
|
|
||||||
// get the board from the cache
|
// get the board from the cache
|
||||||
const { data: boards } = api.endpoints.listAllBoards.select()(state);
|
const { data: boards } =
|
||||||
const board = boards?.find((b) => b.board_id === boardId);
|
boardsApi.endpoints.listAllBoards.select()(state);
|
||||||
|
const board = boards?.find((b) => b.board_id === board_id);
|
||||||
if (!board) {
|
if (!board) {
|
||||||
// can't find the board in cache...
|
// can't find the board in cache...
|
||||||
return;
|
return;
|
||||||
@ -92,7 +99,9 @@ export const addBoardIdSelected_changeSelectedImage_listener = () => {
|
|||||||
filteredImages.length < board.image_count &&
|
filteredImages.length < board.image_count &&
|
||||||
filteredImages.length < IMAGES_PER_PAGE
|
filteredImages.length < IMAGES_PER_PAGE
|
||||||
) {
|
) {
|
||||||
dispatch(receivedPageOfImages({ categories, boardId }));
|
dispatch(
|
||||||
|
receivedPageOfImages({ categories, board_id, is_intermediate: false })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@ import { canvasMerged } from 'features/canvas/store/actions';
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
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 { setMergedCanvas } from 'features/canvas/store/canvasSlice';
|
||||||
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
import { getCanvasBaseLayer } from 'features/canvas/util/konvaInstanceProvider';
|
||||||
import { getFullBaseLayerBlob } from 'features/canvas/util/getFullBaseLayerBlob';
|
import { getFullBaseLayerBlob } from 'features/canvas/util/getFullBaseLayerBlob';
|
||||||
@ -47,13 +47,11 @@ export const addCanvasMergedListener = () => {
|
|||||||
|
|
||||||
const imageUploadedRequest = dispatch(
|
const imageUploadedRequest = dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
formData: {
|
file: new File([blob], 'mergedCanvas.png', {
|
||||||
file: new File([blob], 'mergedCanvas.png', {
|
type: 'image/png',
|
||||||
type: 'image/png',
|
}),
|
||||||
}),
|
image_category: 'general',
|
||||||
},
|
is_intermediate: true,
|
||||||
imageCategory: 'general',
|
|
||||||
isIntermediate: true,
|
|
||||||
postUploadAction: {
|
postUploadAction: {
|
||||||
type: 'TOAST_CANVAS_MERGED',
|
type: 'TOAST_CANVAS_MERGED',
|
||||||
},
|
},
|
||||||
@ -68,13 +66,13 @@ export const addCanvasMergedListener = () => {
|
|||||||
uploadedImageAction.meta.requestId === imageUploadedRequest.requestId
|
uploadedImageAction.meta.requestId === imageUploadedRequest.requestId
|
||||||
);
|
);
|
||||||
|
|
||||||
const mergedCanvasImage = payload;
|
const { image_name } = payload;
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
setMergedCanvas({
|
setMergedCanvas({
|
||||||
kind: 'image',
|
kind: 'image',
|
||||||
layer: 'base',
|
layer: 'base',
|
||||||
image: mergedCanvasImage,
|
imageName: image_name,
|
||||||
...baseLayerRect,
|
...baseLayerRect,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { canvasSavedToGallery } from 'features/canvas/store/actions';
|
import { canvasSavedToGallery } from 'features/canvas/store/actions';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { log } from 'app/logging/useLogger';
|
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 { getBaseLayerBlob } from 'features/canvas/util/getBaseLayerBlob';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||||
@ -30,13 +30,11 @@ export const addCanvasSavedToGalleryListener = () => {
|
|||||||
|
|
||||||
const imageUploadedRequest = dispatch(
|
const imageUploadedRequest = dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
formData: {
|
file: new File([blob], 'savedCanvas.png', {
|
||||||
file: new File([blob], 'savedCanvas.png', {
|
type: 'image/png',
|
||||||
type: 'image/png',
|
}),
|
||||||
}),
|
image_category: 'general',
|
||||||
},
|
is_intermediate: false,
|
||||||
imageCategory: 'general',
|
|
||||||
isIntermediate: false,
|
|
||||||
postUploadAction: {
|
postUploadAction: {
|
||||||
type: 'TOAST_CANVAS_SAVED_TO_GALLERY',
|
type: 'TOAST_CANVAS_SAVED_TO_GALLERY',
|
||||||
},
|
},
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imageMetadataReceived } from 'services/thunks/image';
|
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { controlNetImageProcessed } from 'features/controlNet/store/actions';
|
import { controlNetImageProcessed } from 'features/controlNet/store/actions';
|
||||||
import { Graph } from 'services/api';
|
import { Graph } from 'services/api/types';
|
||||||
import { sessionCreated } from 'services/thunks/session';
|
import { sessionCreated } from 'services/api/thunks/session';
|
||||||
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||||
import { socketInvocationComplete } from 'services/events/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 { controlNetProcessedImageChanged } from 'features/controlNet/store/controlNetSlice';
|
||||||
import { pick } from 'lodash-es';
|
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'controlNet' });
|
const moduleLog = log.child({ namespace: 'controlNet' });
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imageMetadataReceived } from 'services/thunks/image';
|
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||||
import { api } from 'services/apiSlice';
|
import { boardImagesApi } from 'services/api/endpoints/boardImages';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'boards' });
|
const moduleLog = log.child({ namespace: 'boards' });
|
||||||
|
|
||||||
export const addImageAddedToBoardFulfilledListener = () => {
|
export const addImageAddedToBoardFulfilledListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
matcher: api.endpoints.addImageToBoard.matchFulfilled,
|
matcher: boardImagesApi.endpoints.addImageToBoard.matchFulfilled,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ export const addImageAddedToBoardFulfilledListener = () => {
|
|||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
imageMetadataReceived({
|
imageMetadataReceived({
|
||||||
imageName: image_name,
|
image_name,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -27,7 +27,7 @@ export const addImageAddedToBoardFulfilledListener = () => {
|
|||||||
|
|
||||||
export const addImageAddedToBoardRejectedListener = () => {
|
export const addImageAddedToBoardRejectedListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
matcher: api.endpoints.addImageToBoard.matchRejected,
|
matcher: boardImagesApi.endpoints.addImageToBoard.matchRejected,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { receivedPageOfImages } from 'services/thunks/image';
|
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||||
import {
|
import {
|
||||||
imageCategoriesChanged,
|
imageCategoriesChanged,
|
||||||
selectFilteredImagesAsArray,
|
selectFilteredImagesAsArray,
|
||||||
@ -19,7 +19,8 @@ export const addImageCategoriesChangedListener = () => {
|
|||||||
dispatch(
|
dispatch(
|
||||||
receivedPageOfImages({
|
receivedPageOfImages({
|
||||||
categories: action.payload,
|
categories: action.payload,
|
||||||
boardId: state.boards.selectedBoardId,
|
board_id: state.boards.selectedBoardId,
|
||||||
|
is_intermediate: false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { requestedImageDeletion } from 'features/gallery/store/actions';
|
import { requestedImageDeletion } from 'features/gallery/store/actions';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imageDeleted } from 'services/thunks/image';
|
import { imageDeleted } from 'services/api/thunks/image';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
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 { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
||||||
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
||||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||||
import { api } from 'services/apiSlice';
|
import { api } from 'services/api';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'image' });
|
const moduleLog = log.child({ namespace: 'image' });
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ export const addRequestedImageDeletionListener = () => {
|
|||||||
dispatch(imageRemoved(image_name));
|
dispatch(imageRemoved(image_name));
|
||||||
|
|
||||||
// Delete from server
|
// 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
|
// Wait for successful deletion, then trigger boards to re-fetch
|
||||||
const wasImageDeleted = await condition(
|
const wasImageDeleted = await condition(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
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';
|
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'image' });
|
const moduleLog = log.child({ namespace: 'image' });
|
||||||
@ -19,8 +19,8 @@ export const addImageMetadataReceivedFulfilledListener = () => {
|
|||||||
) {
|
) {
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUpdated({
|
imageUpdated({
|
||||||
imageName: image.image_name,
|
image_name: image.image_name,
|
||||||
requestBody: { is_intermediate: false },
|
is_intermediate: image.is_intermediate,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else if (image.is_intermediate) {
|
} else if (image.is_intermediate) {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imageMetadataReceived } from 'services/thunks/image';
|
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||||
import { api } from 'services/apiSlice';
|
import { boardImagesApi } from 'services/api/endpoints/boardImages';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'boards' });
|
const moduleLog = log.child({ namespace: 'boards' });
|
||||||
|
|
||||||
export const addImageRemovedFromBoardFulfilledListener = () => {
|
export const addImageRemovedFromBoardFulfilledListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
matcher: api.endpoints.removeImageFromBoard.matchFulfilled,
|
matcher: boardImagesApi.endpoints.removeImageFromBoard.matchFulfilled,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ export const addImageRemovedFromBoardFulfilledListener = () => {
|
|||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
imageMetadataReceived({
|
imageMetadataReceived({
|
||||||
imageName: image_name,
|
image_name,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -27,7 +27,7 @@ export const addImageRemovedFromBoardFulfilledListener = () => {
|
|||||||
|
|
||||||
export const addImageRemovedFromBoardRejectedListener = () => {
|
export const addImageRemovedFromBoardRejectedListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
matcher: api.endpoints.removeImageFromBoard.matchRejected,
|
matcher: boardImagesApi.endpoints.removeImageFromBoard.matchRejected,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const { board_id, image_name } = action.meta.arg.originalArgs;
|
const { board_id, image_name } = action.meta.arg.originalArgs;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imageUpdated } from 'services/thunks/image';
|
import { imageUpdated } from 'services/api/thunks/image';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'image' });
|
const moduleLog = log.child({ namespace: 'image' });
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imageUploaded } from 'services/thunks/image';
|
import { imageUploaded } from 'services/api/thunks/image';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
import { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { imageUrlsReceived } from 'services/thunks/image';
|
import { imageUrlsReceived } from 'services/api/thunks/image';
|
||||||
import { imageUpdatedOne } from 'features/gallery/store/imagesSlice';
|
import { imageUpdatedOne } from 'features/gallery/store/imagesSlice';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'image' });
|
const moduleLog = log.child({ namespace: 'image' });
|
||||||
|
@ -5,7 +5,7 @@ import { startAppListening } from '..';
|
|||||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'app/components/Toaster';
|
||||||
import { selectImagesById } from 'features/gallery/store/imagesSlice';
|
import { selectImagesById } from 'features/gallery/store/imagesSlice';
|
||||||
import { isImageDTO } from 'services/types/guards';
|
import { isImageDTO } from 'services/api/guards';
|
||||||
|
|
||||||
export const addInitialImageSelectedListener = () => {
|
export const addInitialImageSelectedListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { serializeError } from 'serialize-error';
|
import { serializeError } from 'serialize-error';
|
||||||
import { receivedPageOfImages } from 'services/thunks/image';
|
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'gallery' });
|
const moduleLog = log.child({ namespace: 'gallery' });
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { sessionCanceled } from 'services/thunks/session';
|
import { sessionCanceled } from 'services/api/thunks/session';
|
||||||
import { serializeError } from 'serialize-error';
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'session' });
|
const moduleLog = log.child({ namespace: 'session' });
|
||||||
@ -18,10 +18,10 @@ export const addSessionCanceledFulfilledListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: sessionCanceled.fulfilled,
|
actionCreator: sessionCanceled.fulfilled,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const { sessionId } = action.meta.arg;
|
const { session_id } = action.meta.arg;
|
||||||
moduleLog.debug(
|
moduleLog.debug(
|
||||||
{ data: { sessionId } },
|
{ data: { session_id } },
|
||||||
`Session canceled (${sessionId})`
|
`Session canceled (${session_id})`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { sessionCreated } from 'services/thunks/session';
|
import { sessionCreated } from 'services/api/thunks/session';
|
||||||
import { serializeError } from 'serialize-error';
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'session' });
|
const moduleLog = log.child({ namespace: 'session' });
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { sessionInvoked } from 'services/thunks/session';
|
import { sessionInvoked } from 'services/api/thunks/session';
|
||||||
import { serializeError } from 'serialize-error';
|
import { serializeError } from 'serialize-error';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'session' });
|
const moduleLog = log.child({ namespace: 'session' });
|
||||||
@ -18,10 +18,10 @@ export const addSessionInvokedFulfilledListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: sessionInvoked.fulfilled,
|
actionCreator: sessionInvoked.fulfilled,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const { sessionId } = action.meta.arg;
|
const { session_id } = action.meta.arg;
|
||||||
moduleLog.debug(
|
moduleLog.debug(
|
||||||
{ data: { sessionId } },
|
{ data: { session_id } },
|
||||||
`Session invoked (${sessionId})`
|
`Session invoked (${session_id})`
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { sessionInvoked } from 'services/thunks/session';
|
import { sessionInvoked } from 'services/api/thunks/session';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
import { sessionReadyToInvoke } from 'features/system/store/actions';
|
||||||
|
|
||||||
@ -9,13 +9,13 @@ export const addSessionReadyToInvokeListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: sessionReadyToInvoke,
|
actionCreator: sessionReadyToInvoke,
|
||||||
effect: (action, { getState, dispatch }) => {
|
effect: (action, { getState, dispatch }) => {
|
||||||
const { sessionId } = getState().system;
|
const { sessionId: session_id } = getState().system;
|
||||||
if (sessionId) {
|
if (session_id) {
|
||||||
moduleLog.debug(
|
moduleLog.debug(
|
||||||
{ sessionId },
|
{ session_id },
|
||||||
`Session ready to invoke (${sessionId})})`
|
`Session ready to invoke (${session_id})})`
|
||||||
);
|
);
|
||||||
dispatch(sessionInvoked({ sessionId }));
|
dispatch(sessionInvoked({ session_id }));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { appSocketConnected, socketConnected } from 'services/events/actions';
|
import { appSocketConnected, socketConnected } from 'services/events/actions';
|
||||||
import { receivedPageOfImages } from 'services/thunks/image';
|
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||||
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||||
import { startAppListening } from '../..';
|
import { startAppListening } from '../..';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'socketio' });
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
@ -22,7 +22,7 @@ export const addSocketConnectedEventListener = () => {
|
|||||||
dispatch(
|
dispatch(
|
||||||
receivedPageOfImages({
|
receivedPageOfImages({
|
||||||
categories: ['general'],
|
categories: ['general'],
|
||||||
isIntermediate: false,
|
is_intermediate: false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ import {
|
|||||||
appSocketInvocationComplete,
|
appSocketInvocationComplete,
|
||||||
socketInvocationComplete,
|
socketInvocationComplete,
|
||||||
} from 'services/events/actions';
|
} from 'services/events/actions';
|
||||||
import { imageMetadataReceived } from 'services/thunks/image';
|
import { imageMetadataReceived } from 'services/api/thunks/image';
|
||||||
import { sessionCanceled } from 'services/thunks/session';
|
import { sessionCanceled } from 'services/api/thunks/session';
|
||||||
import { isImageOutput } from 'services/types/guards';
|
import { isImageOutput } from 'services/api/guards';
|
||||||
import { progressImageSet } from 'features/system/store/systemSlice';
|
import { progressImageSet } from 'features/system/store/systemSlice';
|
||||||
import { api } from 'services/apiSlice';
|
import { boardImagesApi } from 'services/api/endpoints/boardImages';
|
||||||
|
|
||||||
const moduleLog = log.child({ namespace: 'socketio' });
|
const moduleLog = log.child({ namespace: 'socketio' });
|
||||||
const nodeDenylist = ['dataURL_image'];
|
const nodeDenylist = ['dataURL_image'];
|
||||||
@ -19,18 +19,18 @@ export const addInvocationCompleteEventListener = () => {
|
|||||||
actionCreator: socketInvocationComplete,
|
actionCreator: socketInvocationComplete,
|
||||||
effect: async (action, { dispatch, getState, take }) => {
|
effect: async (action, { dispatch, getState, take }) => {
|
||||||
moduleLog.debug(
|
moduleLog.debug(
|
||||||
action.payload,
|
{ data: action.payload },
|
||||||
`Invocation complete (${action.payload.data.node.type})`
|
`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 } =
|
const { cancelType, isCancelScheduled, boardIdToAddTo } =
|
||||||
getState().system;
|
getState().system;
|
||||||
|
|
||||||
// Handle scheduled cancelation
|
// Handle scheduled cancelation
|
||||||
if (cancelType === 'scheduled' && isCancelScheduled) {
|
if (cancelType === 'scheduled' && isCancelScheduled) {
|
||||||
dispatch(sessionCanceled({ sessionId }));
|
dispatch(sessionCanceled({ session_id }));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = action.payload;
|
const { data } = action.payload;
|
||||||
@ -43,7 +43,7 @@ export const addInvocationCompleteEventListener = () => {
|
|||||||
// Get its metadata
|
// Get its metadata
|
||||||
dispatch(
|
dispatch(
|
||||||
imageMetadataReceived({
|
imageMetadataReceived({
|
||||||
imageName: image_name,
|
image_name,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ export const addInvocationCompleteEventListener = () => {
|
|||||||
|
|
||||||
if (boardIdToAddTo && !imageDTO.is_intermediate) {
|
if (boardIdToAddTo && !imageDTO.is_intermediate) {
|
||||||
dispatch(
|
dispatch(
|
||||||
api.endpoints.addImageToBoard.initiate({
|
boardImagesApi.endpoints.addImageToBoard.initiate({
|
||||||
board_id: boardIdToAddTo,
|
board_id: boardIdToAddTo,
|
||||||
image_name,
|
image_name,
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { stagingAreaImageSaved } from 'features/canvas/store/actions';
|
import { stagingAreaImageSaved } from 'features/canvas/store/actions';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { log } from 'app/logging/useLogger';
|
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 { imageUpserted } from 'features/gallery/store/imagesSlice';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
|
||||||
@ -11,14 +11,12 @@ export const addStagingAreaImageSavedListener = () => {
|
|||||||
startAppListening({
|
startAppListening({
|
||||||
actionCreator: stagingAreaImageSaved,
|
actionCreator: stagingAreaImageSaved,
|
||||||
effect: async (action, { dispatch, getState, take }) => {
|
effect: async (action, { dispatch, getState, take }) => {
|
||||||
const { image_name } = action.payload;
|
const { imageName } = action.payload;
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUpdated({
|
imageUpdated({
|
||||||
imageName: image_name,
|
image_name: imageName,
|
||||||
requestBody: {
|
is_intermediate: false,
|
||||||
is_intermediate: false,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -26,7 +24,7 @@ export const addStagingAreaImageSavedListener = () => {
|
|||||||
(action) =>
|
(action) =>
|
||||||
(imageUpdated.fulfilled.match(action) ||
|
(imageUpdated.fulfilled.match(action) ||
|
||||||
imageUpdated.rejected.match(action)) &&
|
imageUpdated.rejected.match(action)) &&
|
||||||
action.meta.arg.imageName === image_name
|
action.meta.arg.image_name === imageName
|
||||||
);
|
);
|
||||||
|
|
||||||
if (imageUpdated.rejected.match(imageUpdatedAction)) {
|
if (imageUpdated.rejected.match(imageUpdatedAction)) {
|
||||||
|
@ -5,9 +5,8 @@ import { generationSelector } from 'features/parameters/store/generationSelector
|
|||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
import { nodesSelecter } from 'features/nodes/store/nodesSlice';
|
import { nodesSelecter } from 'features/nodes/store/nodesSlice';
|
||||||
import { controlNetSelector } from 'features/controlNet/store/controlNetSlice';
|
import { controlNetSelector } from 'features/controlNet/store/controlNetSlice';
|
||||||
import { ImageDTO } from 'services/api';
|
|
||||||
import { forEach, uniqBy } from 'lodash-es';
|
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 { log } from 'app/logging/useLogger';
|
||||||
import { selectImagesEntities } from 'features/gallery/store/imagesSlice';
|
import { selectImagesEntities } from 'features/gallery/store/imagesSlice';
|
||||||
|
|
||||||
@ -83,7 +82,7 @@ export const addUpdateImageUrlsOnConnectListener = () => {
|
|||||||
allUsedImages.forEach((image_name) => {
|
allUsedImages.forEach((image_name) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUrlsReceived({
|
imageUrlsReceived({
|
||||||
imageName: image_name,
|
image_name,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { startAppListening } from '..';
|
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 { buildCanvasGraph } from 'features/nodes/util/graphBuilders/buildCanvasGraph';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { canvasGraphBuilt } from 'features/nodes/store/actions';
|
import { canvasGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { imageUpdated, imageUploaded } from 'services/thunks/image';
|
import { imageUpdated, imageUploaded } from 'services/api/thunks/image';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
canvasSessionIdChanged,
|
canvasSessionIdChanged,
|
||||||
stagingAreaInitialized,
|
stagingAreaInitialized,
|
||||||
@ -75,13 +75,11 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
// upload the image, saving the request id
|
// upload the image, saving the request id
|
||||||
const { requestId: initImageUploadedRequestId } = dispatch(
|
const { requestId: initImageUploadedRequestId } = dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
formData: {
|
file: new File([baseBlob], 'canvasInitImage.png', {
|
||||||
file: new File([baseBlob], 'canvasInitImage.png', {
|
type: 'image/png',
|
||||||
type: 'image/png',
|
}),
|
||||||
}),
|
image_category: 'general',
|
||||||
},
|
is_intermediate: true,
|
||||||
imageCategory: 'general',
|
|
||||||
isIntermediate: true,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -100,13 +98,11 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
// upload the image, saving the request id
|
// upload the image, saving the request id
|
||||||
const { requestId: maskImageUploadedRequestId } = dispatch(
|
const { requestId: maskImageUploadedRequestId } = dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
formData: {
|
file: new File([maskBlob], 'canvasMaskImage.png', {
|
||||||
file: new File([maskBlob], 'canvasMaskImage.png', {
|
type: 'image/png',
|
||||||
type: 'image/png',
|
}),
|
||||||
}),
|
image_category: 'mask',
|
||||||
},
|
is_intermediate: true,
|
||||||
imageCategory: 'mask',
|
|
||||||
isIntermediate: true,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -149,8 +145,8 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
if (['img2img', 'inpaint'].includes(generationMode) && canvasInitImage) {
|
if (['img2img', 'inpaint'].includes(generationMode) && canvasInitImage) {
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUpdated({
|
imageUpdated({
|
||||||
imageName: canvasInitImage.image_name,
|
image_name: canvasInitImage.image_name,
|
||||||
requestBody: { session_id: sessionId },
|
session_id: sessionId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -159,8 +155,8 @@ export const addUserInvokedCanvasListener = () => {
|
|||||||
if (['inpaint'].includes(generationMode) && canvasMaskImage) {
|
if (['inpaint'].includes(generationMode) && canvasMaskImage) {
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUpdated({
|
imageUpdated({
|
||||||
imageName: canvasMaskImage.image_name,
|
image_name: canvasMaskImage.image_name,
|
||||||
requestBody: { session_id: sessionId },
|
session_id: sessionId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { sessionCreated } from 'services/thunks/session';
|
import { sessionCreated } from 'services/api/thunks/session';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { imageToImageGraphBuilt } from 'features/nodes/store/actions';
|
import { imageToImageGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { userInvoked } from 'app/store/actions';
|
import { userInvoked } from 'app/store/actions';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { startAppListening } from '..';
|
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 { buildNodesGraph } from 'features/nodes/util/graphBuilders/buildNodesGraph';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { nodesGraphBuilt } from 'features/nodes/store/actions';
|
import { nodesGraphBuilt } from 'features/nodes/store/actions';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { sessionCreated } from 'services/thunks/session';
|
import { sessionCreated } from 'services/api/thunks/session';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { textToImageGraphBuilt } from 'features/nodes/store/actions';
|
import { textToImageGraphBuilt } from 'features/nodes/store/actions';
|
||||||
import { userInvoked } from 'app/store/actions';
|
import { userInvoked } from 'app/store/actions';
|
||||||
|
@ -31,7 +31,7 @@ import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
|||||||
import { LOCALSTORAGE_PREFIX } from './constants';
|
import { LOCALSTORAGE_PREFIX } from './constants';
|
||||||
import { serialize } from './enhancers/reduxRemember/serialize';
|
import { serialize } from './enhancers/reduxRemember/serialize';
|
||||||
import { unserialize } from './enhancers/reduxRemember/unserialize';
|
import { unserialize } from './enhancers/reduxRemember/unserialize';
|
||||||
import { api } from 'services/apiSlice';
|
import { api } from 'services/api';
|
||||||
|
|
||||||
const allReducers = {
|
const allReducers = {
|
||||||
canvas: canvasReducer,
|
canvas: canvasReducer,
|
||||||
|
@ -12,15 +12,14 @@ import IAIIconButton from 'common/components/IAIIconButton';
|
|||||||
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
||||||
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
|
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import { ReactElement, SyntheticEvent, useCallback } from 'react';
|
import { ReactElement, SyntheticEvent } from 'react';
|
||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { FaImage, FaTimes, FaUndo, FaUpload } from 'react-icons/fa';
|
import { FaImage, FaUndo, FaUpload } from 'react-icons/fa';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import IAIDropOverlay from './IAIDropOverlay';
|
import IAIDropOverlay from './IAIDropOverlay';
|
||||||
import { PostUploadAction, imageUploaded } from 'services/thunks/image';
|
import { PostUploadAction } from 'services/api/thunks/image';
|
||||||
import { useDropzone } from 'react-dropzone';
|
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
|
||||||
|
|
||||||
type IAIDndImageProps = {
|
type IAIDndImageProps = {
|
||||||
image: ImageDTO | null | undefined;
|
image: ImageDTO | null | undefined;
|
||||||
@ -39,6 +38,7 @@ type IAIDndImageProps = {
|
|||||||
minSize?: number;
|
minSize?: number;
|
||||||
postUploadAction?: PostUploadAction;
|
postUploadAction?: PostUploadAction;
|
||||||
imageSx?: ChakraProps['sx'];
|
imageSx?: ChakraProps['sx'];
|
||||||
|
fitContainer?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IAIDndImage = (props: IAIDndImageProps) => {
|
const IAIDndImage = (props: IAIDndImageProps) => {
|
||||||
@ -58,8 +58,9 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
|||||||
minSize = 24,
|
minSize = 24,
|
||||||
postUploadAction,
|
postUploadAction,
|
||||||
imageSx,
|
imageSx,
|
||||||
|
fitContainer = false,
|
||||||
} = props;
|
} = props;
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const dndId = useRef(uuidv4());
|
const dndId = useRef(uuidv4());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -87,31 +88,9 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
|||||||
disabled: isDragDisabled || !image,
|
disabled: isDragDisabled || !image,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleOnDropAccepted = useCallback(
|
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
||||||
(files: Array<File>) => {
|
postUploadAction,
|
||||||
const file = files[0];
|
isDisabled: isUploadDisabled,
|
||||||
if (!file) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(
|
|
||||||
imageUploaded({
|
|
||||||
formData: { file },
|
|
||||||
imageCategory: 'user',
|
|
||||||
isIntermediate: false,
|
|
||||||
postUploadAction,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[dispatch, postUploadAction]
|
|
||||||
);
|
|
||||||
|
|
||||||
const { getRootProps, getInputProps } = useDropzone({
|
|
||||||
accept: { 'image/png': ['.png'], 'image/jpeg': ['.jpg', '.jpeg', '.png'] },
|
|
||||||
onDropAccepted: handleOnDropAccepted,
|
|
||||||
noDrag: true,
|
|
||||||
multiple: false,
|
|
||||||
disabled: isUploadDisabled,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const setNodeRef = useCombinedRefs(setDroppableRef, setDraggableRef);
|
const setNodeRef = useCombinedRefs(setDroppableRef, setDraggableRef);
|
||||||
@ -149,13 +128,13 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
|||||||
sx={{
|
sx={{
|
||||||
w: 'full',
|
w: 'full',
|
||||||
h: 'full',
|
h: 'full',
|
||||||
|
position: fitContainer ? 'absolute' : 'relative',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src={image.image_url}
|
src={image.image_url}
|
||||||
fallbackStrategy="beforeLoadOrError"
|
|
||||||
fallback={fallback}
|
fallback={fallback}
|
||||||
onError={onError}
|
onError={onError}
|
||||||
objectFit="contain"
|
objectFit="contain"
|
||||||
@ -205,9 +184,9 @@ const IAIDndImage = (props: IAIDndImageProps) => {
|
|||||||
color: 'base.500',
|
color: 'base.500',
|
||||||
...uploadButtonStyles,
|
...uploadButtonStyles,
|
||||||
}}
|
}}
|
||||||
{...getRootProps()}
|
{...getUploadButtonProps()}
|
||||||
>
|
>
|
||||||
<input {...getInputProps()} />
|
<input {...getUploadInputProps()} />
|
||||||
<Icon
|
<Icon
|
||||||
as={isUploadDisabled ? FaImage : FaUpload}
|
as={isUploadDisabled ? FaImage : FaUpload}
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Badge, Flex } from '@chakra-ui/react';
|
import { Badge, Flex } from '@chakra-ui/react';
|
||||||
import { isString } from 'lodash-es';
|
import { isString } from 'lodash-es';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
type ImageMetadataOverlayProps = {
|
type ImageMetadataOverlayProps = {
|
||||||
image: ImageDTO;
|
image: ImageDTO;
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { FileRejection, useDropzone } from 'react-dropzone';
|
import { FileRejection, useDropzone } from 'react-dropzone';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { imageUploaded } from 'services/thunks/image';
|
import { imageUploaded } from 'services/api/thunks/image';
|
||||||
import ImageUploadOverlay from './ImageUploadOverlay';
|
import ImageUploadOverlay from './ImageUploadOverlay';
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
@ -62,9 +62,9 @@ const ImageUploader = (props: ImageUploaderProps) => {
|
|||||||
async (file: File) => {
|
async (file: File) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
imageUploaded({
|
imageUploaded({
|
||||||
formData: { file },
|
file,
|
||||||
imageCategory: 'user',
|
image_category: 'user',
|
||||||
isIntermediate: false,
|
is_intermediate: false,
|
||||||
postUploadAction: { type: 'TOAST_UPLOADED' },
|
postUploadAction: { type: 'TOAST_UPLOADED' },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useDropzone } from 'react-dropzone';
|
||||||
|
import { PostUploadAction, imageUploaded } from 'services/api/thunks/image';
|
||||||
|
|
||||||
|
type UseImageUploadButtonArgs = {
|
||||||
|
postUploadAction?: PostUploadAction;
|
||||||
|
isDisabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides image uploader functionality to any component.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
||||||
|
* postUploadAction: {
|
||||||
|
* type: 'SET_CONTROLNET_IMAGE',
|
||||||
|
* controlNetId: '12345',
|
||||||
|
* },
|
||||||
|
* isDisabled: getIsUploadDisabled(),
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* // in the render function
|
||||||
|
* <Button {...getUploadButtonProps()} /> // will open the file dialog on click
|
||||||
|
* <input {...getUploadInputProps()} /> // hidden, handles native upload functionality
|
||||||
|
*/
|
||||||
|
export const useImageUploadButton = ({
|
||||||
|
postUploadAction,
|
||||||
|
isDisabled,
|
||||||
|
}: UseImageUploadButtonArgs) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const onDropAccepted = useCallback(
|
||||||
|
(files: File[]) => {
|
||||||
|
const file = files[0];
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
imageUploaded({
|
||||||
|
file,
|
||||||
|
image_category: 'user',
|
||||||
|
is_intermediate: false,
|
||||||
|
postUploadAction,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[dispatch, postUploadAction]
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
getRootProps: getUploadButtonProps,
|
||||||
|
getInputProps: getUploadInputProps,
|
||||||
|
open: openUploader,
|
||||||
|
} = useDropzone({
|
||||||
|
accept: { 'image/png': ['.png'], 'image/jpeg': ['.jpg', '.jpeg', '.png'] },
|
||||||
|
onDropAccepted,
|
||||||
|
disabled: isDisabled,
|
||||||
|
noDrag: true,
|
||||||
|
multiple: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { getUploadButtonProps, getUploadInputProps, openUploader };
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
import { Image, Rect } from 'react-konva';
|
import { Image, Rect } from 'react-konva';
|
||||||
import { useGetImageDTOQuery } from 'services/apiSlice';
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
import useImage from 'use-image';
|
import useImage from 'use-image';
|
||||||
import { CanvasImage } from '../store/canvasTypes';
|
import { CanvasImage } from '../store/canvasTypes';
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ type IAICanvasImageProps = {
|
|||||||
};
|
};
|
||||||
const IAICanvasImage = (props: IAICanvasImageProps) => {
|
const IAICanvasImage = (props: IAICanvasImageProps) => {
|
||||||
const { width, height, x, y, imageName } = props.canvasImage;
|
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');
|
const [image] = useImage(imageDTO?.image_url ?? '', 'anonymous');
|
||||||
|
|
||||||
if (!imageDTO) {
|
if (!imageDTO) {
|
||||||
|
@ -175,7 +175,11 @@ const IAICanvasStagingAreaToolbar = () => {
|
|||||||
aria-label={t('unifiedCanvas.saveToGallery')}
|
aria-label={t('unifiedCanvas.saveToGallery')}
|
||||||
icon={<FaSave />}
|
icon={<FaSave />}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
dispatch(stagingAreaImageSaved(currentStagingAreaImage.image))
|
dispatch(
|
||||||
|
stagingAreaImageSaved({
|
||||||
|
imageName: currentStagingAreaImage.imageName,
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
colorScheme="accent"
|
colorScheme="accent"
|
||||||
/>
|
/>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { ImageDTO } from 'services/api';
|
|
||||||
|
|
||||||
export const canvasSavedToGallery = createAction('canvas/canvasSavedToGallery');
|
export const canvasSavedToGallery = createAction('canvas/canvasSavedToGallery');
|
||||||
|
|
||||||
@ -13,6 +12,6 @@ export const canvasDownloadedAsImage = createAction(
|
|||||||
|
|
||||||
export const canvasMerged = createAction('canvas/canvasMerged');
|
export const canvasMerged = createAction('canvas/canvasMerged');
|
||||||
|
|
||||||
export const stagingAreaImageSaved = createAction<ImageDTO>(
|
export const stagingAreaImageSaved = createAction<{ imageName: string }>(
|
||||||
'canvas/stagingAreaImageSaved'
|
'canvas/stagingAreaImageSaved'
|
||||||
);
|
);
|
||||||
|
@ -28,13 +28,13 @@ import {
|
|||||||
isCanvasBaseImage,
|
isCanvasBaseImage,
|
||||||
isCanvasMaskLine,
|
isCanvasMaskLine,
|
||||||
} from './canvasTypes';
|
} from './canvasTypes';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { sessionCanceled } from 'services/thunks/session';
|
import { sessionCanceled } from 'services/api/thunks/session';
|
||||||
import {
|
import {
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
setShouldUseCanvasBetaLayout,
|
setShouldUseCanvasBetaLayout,
|
||||||
} from 'features/ui/store/uiSlice';
|
} from 'features/ui/store/uiSlice';
|
||||||
import { imageUrlsReceived } from 'services/thunks/image';
|
import { imageUrlsReceived } from 'services/api/thunks/image';
|
||||||
|
|
||||||
export const initialLayerState: CanvasLayerState = {
|
export const initialLayerState: CanvasLayerState = {
|
||||||
objects: [],
|
objects: [],
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import * as InvokeAI from 'app/types/invokeai';
|
import * as InvokeAI from 'app/types/invokeai';
|
||||||
import { IRect, Vector2d } from 'konva/lib/types';
|
import { IRect, Vector2d } from 'konva/lib/types';
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
export const LAYER_NAMES_DICT = [
|
export const LAYER_NAMES_DICT = [
|
||||||
{ label: 'Base', value: 'base' },
|
{ label: 'Base', value: 'base' },
|
||||||
|
@ -172,7 +172,10 @@ const ControlNet = (props: ControlNetProps) => {
|
|||||||
aspectRatio: '1/1',
|
aspectRatio: '1/1',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ControlNetImagePreview controlNet={props.controlNet} />
|
<ControlNetImagePreview
|
||||||
|
controlNet={props.controlNet}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -181,7 +184,7 @@ const ControlNet = (props: ControlNetProps) => {
|
|||||||
<Box mt={2}>
|
<Box mt={2}>
|
||||||
<ControlNetImagePreview
|
<ControlNetImagePreview
|
||||||
controlNet={props.controlNet}
|
controlNet={props.controlNet}
|
||||||
imageSx={expandedControlImageSx}
|
height={96}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<ParamControlNetProcessorSelect
|
<ParamControlNetProcessorSelect
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
import { memo, useCallback, useState } from 'react';
|
import { memo, useCallback, useState } from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
ControlNetConfig,
|
ControlNetConfig,
|
||||||
controlNetImageChanged,
|
controlNetImageChanged,
|
||||||
controlNetSelector,
|
controlNetSelector,
|
||||||
} from '../store/controlNetSlice';
|
} from '../store/controlNetSlice';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { Box, ChakraProps, Flex } from '@chakra-ui/react';
|
import { Box, Flex, SystemStyleObject } from '@chakra-ui/react';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
|
||||||
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { FaUndo } from 'react-icons/fa';
|
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';
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
@ -28,11 +27,11 @@ const selector = createSelector(
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
controlNet: ControlNetConfig;
|
controlNet: ControlNetConfig;
|
||||||
imageSx?: ChakraProps['sx'];
|
height: SystemStyleObject['h'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const ControlNetImagePreview = (props: Props) => {
|
const ControlNetImagePreview = (props: Props) => {
|
||||||
const { imageSx } = props;
|
const { height } = props;
|
||||||
const {
|
const {
|
||||||
controlNetId,
|
controlNetId,
|
||||||
controlImage: controlImageName,
|
controlImage: controlImageName,
|
||||||
@ -45,14 +44,14 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
const [isMouseOverImage, setIsMouseOverImage] = useState(false);
|
const [isMouseOverImage, setIsMouseOverImage] = useState(false);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: controlImage,
|
currentData: controlImage,
|
||||||
isLoading: isLoadingControlImage,
|
isLoading: isLoadingControlImage,
|
||||||
isError: isErrorControlImage,
|
isError: isErrorControlImage,
|
||||||
isSuccess: isSuccessControlImage,
|
isSuccess: isSuccessControlImage,
|
||||||
} = useGetImageDTOQuery(controlImageName ?? skipToken);
|
} = useGetImageDTOQuery(controlImageName ?? skipToken);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: processedControlImage,
|
currentData: processedControlImage,
|
||||||
isLoading: isLoadingProcessedControlImage,
|
isLoading: isLoadingProcessedControlImage,
|
||||||
isError: isErrorProcessedControlImage,
|
isError: isErrorProcessedControlImage,
|
||||||
isSuccess: isSuccessProcessedControlImage,
|
isSuccess: isSuccessProcessedControlImage,
|
||||||
@ -85,10 +84,6 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
setIsMouseOverImage(false);
|
setIsMouseOverImage(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const shouldShowProcessedImageBackdrop =
|
|
||||||
Number(controlImage?.width) > Number(processedControlImage?.width) ||
|
|
||||||
Number(controlImage?.height) > Number(processedControlImage?.height);
|
|
||||||
|
|
||||||
const shouldShowProcessedImage =
|
const shouldShowProcessedImage =
|
||||||
controlImage &&
|
controlImage &&
|
||||||
processedControlImage &&
|
processedControlImage &&
|
||||||
@ -97,72 +92,51 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
processorType !== 'none';
|
processorType !== 'none';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Flex
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
sx={{ position: 'relative', w: 'full', h: 'full' }}
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
w: 'full',
|
||||||
|
h: height,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<IAIDndImage
|
<IAIDndImage
|
||||||
image={controlImage}
|
image={controlImage}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
isDropDisabled={Boolean(
|
isDropDisabled={shouldShowProcessedImage}
|
||||||
processedControlImage && processorType !== 'none'
|
|
||||||
)}
|
|
||||||
isUploadDisabled={Boolean(controlImage)}
|
|
||||||
postUploadAction={{ type: 'SET_CONTROLNET_IMAGE', controlNetId }}
|
postUploadAction={{ type: 'SET_CONTROLNET_IMAGE', controlNetId }}
|
||||||
imageSx={imageSx}
|
imageSx={{
|
||||||
|
w: 'full',
|
||||||
|
h: 'full',
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<AnimatePresence>
|
<Box
|
||||||
{shouldShowProcessedImage && (
|
sx={{
|
||||||
<motion.div
|
position: 'absolute',
|
||||||
style={{ width: '100%' }}
|
top: 0,
|
||||||
initial={{
|
insetInlineStart: 0,
|
||||||
opacity: 0,
|
w: 'full',
|
||||||
}}
|
h: 'full',
|
||||||
animate={{
|
opacity: shouldShowProcessedImage ? 1 : 0,
|
||||||
opacity: 1,
|
transitionProperty: 'common',
|
||||||
transition: { duration: 0.1 },
|
transitionDuration: 'normal',
|
||||||
}}
|
pointerEvents: 'none',
|
||||||
exit={{
|
}}
|
||||||
opacity: 0,
|
>
|
||||||
transition: { duration: 0.1 },
|
<IAIDndImage
|
||||||
}}
|
image={processedControlImage}
|
||||||
>
|
onDrop={handleDrop}
|
||||||
<>
|
payloadImage={controlImage}
|
||||||
{shouldShowProcessedImageBackdrop && (
|
isUploadDisabled={true}
|
||||||
<Box
|
imageSx={{
|
||||||
sx={{
|
w: 'full',
|
||||||
position: 'absolute',
|
h: 'full',
|
||||||
top: 0,
|
}}
|
||||||
insetInlineStart: 0,
|
/>
|
||||||
w: 'full',
|
</Box>
|
||||||
h: 'full',
|
|
||||||
bg: 'base.900',
|
|
||||||
opacity: 0.7,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
insetInlineStart: 0,
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IAIDndImage
|
|
||||||
image={processedControlImage}
|
|
||||||
onDrop={handleDrop}
|
|
||||||
payloadImage={controlImage}
|
|
||||||
isUploadDisabled={true}
|
|
||||||
imageSx={imageSx}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
</>
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
|
||||||
{pendingControlImages.includes(controlNetId) && (
|
{pendingControlImages.includes(controlNetId) && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -192,7 +166,7 @@ const ControlNetImagePreview = (props: Props) => {
|
|||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { PayloadAction } from '@reduxjs/toolkit';
|
import { PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
ControlNetProcessorType,
|
ControlNetProcessorType,
|
||||||
RequiredCannyImageProcessorInvocation,
|
RequiredCannyImageProcessorInvocation,
|
||||||
@ -13,9 +13,9 @@ import {
|
|||||||
ControlNetModelName,
|
ControlNetModelName,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { controlNetImageProcessed } from './actions';
|
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 { forEach } from 'lodash-es';
|
||||||
import { isAnySessionRejected } from 'services/thunks/session';
|
import { isAnySessionRejected } from 'services/api/thunks/session';
|
||||||
import { appSocketInvocationError } from 'services/events/actions';
|
import { appSocketInvocationError } from 'services/events/actions';
|
||||||
|
|
||||||
export const initialControlNet: Omit<ControlNetConfig, 'controlNetId'> = {
|
export const initialControlNet: Omit<ControlNetConfig, 'controlNetId'> = {
|
||||||
@ -258,13 +258,13 @@ export const controlNetSlice = createSlice({
|
|||||||
|
|
||||||
builder.addCase(imageDeleted.pending, (state, action) => {
|
builder.addCase(imageDeleted.pending, (state, action) => {
|
||||||
// Preemptively remove the image from the gallery
|
// Preemptively remove the image from the gallery
|
||||||
const { imageName } = action.meta.arg;
|
const { image_name } = action.meta.arg;
|
||||||
forEach(state.controlNets, (c) => {
|
forEach(state.controlNets, (c) => {
|
||||||
if (c.controlImage === imageName) {
|
if (c.controlImage === image_name) {
|
||||||
c.controlImage = null;
|
c.controlImage = null;
|
||||||
c.processedControlImage = null;
|
c.processedControlImage = null;
|
||||||
}
|
}
|
||||||
if (c.processedControlImage === imageName) {
|
if (c.processedControlImage === image_name) {
|
||||||
c.processedControlImage = null;
|
c.processedControlImage = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
OpenposeImageProcessorInvocation,
|
OpenposeImageProcessorInvocation,
|
||||||
PidiImageProcessorInvocation,
|
PidiImageProcessorInvocation,
|
||||||
ZoeDepthImageProcessorInvocation,
|
ZoeDepthImageProcessorInvocation,
|
||||||
} from 'services/api';
|
} from 'services/api/types';
|
||||||
import { O } from 'ts-toolbelt';
|
import { O } from 'ts-toolbelt';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useCreateBoardMutation } from 'services/apiSlice';
|
import { useCreateBoardMutation } from 'services/api/endpoints/boards';
|
||||||
|
|
||||||
const DEFAULT_BOARD_NAME = 'My Board';
|
const DEFAULT_BOARD_NAME = 'My Board';
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ import { IAINoImageFallback } from 'common/components/IAIImageFallback';
|
|||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import { SelectedItemOverlay } from '../SelectedItemOverlay';
|
import { SelectedItemOverlay } from '../SelectedItemOverlay';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { useRemoveImageFromBoardMutation } from 'services/apiSlice';
|
import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages';
|
||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDroppable } from '@dnd-kit/core';
|
||||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
|||||||
import AddBoardButton from './AddBoardButton';
|
import AddBoardButton from './AddBoardButton';
|
||||||
import AllImagesBoard from './AllImagesBoard';
|
import AllImagesBoard from './AllImagesBoard';
|
||||||
import { CloseIcon } from '@chakra-ui/icons';
|
import { CloseIcon } from '@chakra-ui/icons';
|
||||||
import { useListAllBoardsQuery } from 'services/apiSlice';
|
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[boardsSelector],
|
[boardsSelector],
|
||||||
|
@ -14,15 +14,16 @@ import { useAppDispatch } from 'app/store/storeHooks';
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { FaFolder, FaTrash } from 'react-icons/fa';
|
import { FaFolder, FaTrash } from 'react-icons/fa';
|
||||||
import { ContextMenu } from 'chakra-ui-contextmenu';
|
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 { IAINoImageFallback } from 'common/components/IAIImageFallback';
|
||||||
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
import { boardIdSelected } from 'features/gallery/store/boardSlice';
|
||||||
|
import { useAddImageToBoardMutation } from 'services/api/endpoints/boardImages';
|
||||||
import {
|
import {
|
||||||
useAddImageToBoardMutation,
|
|
||||||
useDeleteBoardMutation,
|
useDeleteBoardMutation,
|
||||||
useGetImageDTOQuery,
|
|
||||||
useUpdateBoardMutation,
|
useUpdateBoardMutation,
|
||||||
} from 'services/apiSlice';
|
} from 'services/api/endpoints/boards';
|
||||||
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDroppable } from '@dnd-kit/core';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
@ -37,7 +38,7 @@ interface HoverableBoardProps {
|
|||||||
const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
const HoverableBoard = memo(({ board, isSelected }: HoverableBoardProps) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const { data: coverImage } = useGetImageDTOQuery(
|
const { currentData: coverImage } = useGetImageDTOQuery(
|
||||||
board.cover_image_name ?? skipToken
|
board.cover_image_name ?? skipToken
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import IAIButton from 'common/components/IAIButton';
|
|||||||
import { memo, useContext, useRef, useState } from 'react';
|
import { memo, useContext, useRef, useState } from 'react';
|
||||||
import { AddImageToBoardContext } from '../../../../app/contexts/AddImageToBoardContext';
|
import { AddImageToBoardContext } from '../../../../app/contexts/AddImageToBoardContext';
|
||||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
import { useListAllBoardsQuery } from 'services/apiSlice';
|
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||||
|
|
||||||
const UpdateImageBoardModal = () => {
|
const UpdateImageBoardModal = () => {
|
||||||
// const boards = useSelector(selectBoardsAll);
|
// const boards = useSelector(selectBoardsAll);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { Box, Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||||
import { isEqual } from 'lodash-es';
|
|
||||||
|
|
||||||
import { gallerySelector } from '../store/gallerySelectors';
|
import { gallerySelector } from '../store/gallerySelectors';
|
||||||
import CurrentImageButtons from './CurrentImageButtons';
|
import CurrentImageButtons from './CurrentImageButtons';
|
||||||
@ -22,13 +21,8 @@ export const currentImageDisplaySelector = createSelector(
|
|||||||
defaultSelectorOptions
|
defaultSelectorOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays the current image if there is one, plus associated actions.
|
|
||||||
*/
|
|
||||||
const CurrentImageDisplay = () => {
|
const CurrentImageDisplay = () => {
|
||||||
const { hasSelectedImage, hasProgressImage } = useAppSelector(
|
const { hasSelectedImage } = useAppSelector(currentImageDisplaySelector);
|
||||||
currentImageDisplaySelector
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
@ -43,24 +37,8 @@ const CurrentImageDisplay = () => {
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Flex
|
{hasSelectedImage && <CurrentImageButtons />}
|
||||||
flexDirection="column"
|
<CurrentImagePreview />
|
||||||
sx={{
|
|
||||||
w: 'full',
|
|
||||||
h: 'full',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
gap: 4,
|
|
||||||
position: 'absolute',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CurrentImagePreview />
|
|
||||||
</Flex>
|
|
||||||
{hasSelectedImage && (
|
|
||||||
<Box sx={{ position: 'absolute', top: 0 }}>
|
|
||||||
<CurrentImageButtons />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -11,9 +11,9 @@ import { memo, useCallback } from 'react';
|
|||||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||||
import { imageSelected } from '../store/gallerySlice';
|
import { imageSelected } from '../store/gallerySlice';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
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';
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
|
|
||||||
export const imagesSelector = createSelector(
|
export const imagesSelector = createSelector(
|
||||||
@ -51,12 +51,8 @@ const CurrentImagePreview = () => {
|
|||||||
shouldAntialiasProgressImage,
|
shouldAntialiasProgressImage,
|
||||||
} = useAppSelector(imagesSelector);
|
} = useAppSelector(imagesSelector);
|
||||||
|
|
||||||
// const image = useAppSelector((state: RootState) =>
|
|
||||||
// selectImagesById(state, selectedImage ?? '')
|
|
||||||
// );
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: image,
|
currentData: image,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
isSuccess,
|
isSuccess,
|
||||||
@ -79,9 +75,9 @@ const CurrentImagePreview = () => {
|
|||||||
sx={{
|
sx={{
|
||||||
width: 'full',
|
width: 'full',
|
||||||
height: 'full',
|
height: 'full',
|
||||||
position: 'relative',
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{progressImage && shouldShowProgressInViewer ? (
|
{progressImage && shouldShowProgressInViewer ? (
|
||||||
@ -101,23 +97,15 @@ const CurrentImagePreview = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Flex
|
<IAIDndImage
|
||||||
sx={{
|
image={image}
|
||||||
width: 'full',
|
onDrop={handleDrop}
|
||||||
height: 'full',
|
fallback={<IAIImageLoadingFallback sx={{ bg: 'none' }} />}
|
||||||
alignItems: 'center',
|
isUploadDisabled={true}
|
||||||
justifyContent: 'center',
|
fitContainer
|
||||||
}}
|
/>
|
||||||
>
|
|
||||||
<IAIDndImage
|
|
||||||
image={selectedImage && image ? image : undefined}
|
|
||||||
onDrop={handleDrop}
|
|
||||||
fallback={<IAIImageLoadingFallback sx={{ bg: 'none' }} />}
|
|
||||||
isUploadDisabled={true}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
)}
|
)}
|
||||||
{shouldShowImageDetails && image && selectedImage && (
|
{shouldShowImageDetails && image && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@ -131,7 +119,7 @@ const CurrentImagePreview = () => {
|
|||||||
<ImageMetadataViewer image={image} />
|
<ImageMetadataViewer image={image} />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{!shouldShowImageDetails && image && selectedImage && (
|
{!shouldShowImageDetails && image && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
@ -31,11 +31,11 @@ import { useRecallParameters } from 'features/parameters/hooks/useRecallParamete
|
|||||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||||
import { sentImageToCanvas, sentImageToImg2Img } from '../store/actions';
|
import { sentImageToCanvas, sentImageToImg2Img } from '../store/actions';
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { useDraggable } from '@dnd-kit/core';
|
import { useDraggable } from '@dnd-kit/core';
|
||||||
import { DeleteImageContext } from 'app/contexts/DeleteImageContext';
|
import { DeleteImageContext } from 'app/contexts/DeleteImageContext';
|
||||||
import { AddImageToBoardContext } from '../../../app/contexts/AddImageToBoardContext';
|
import { AddImageToBoardContext } from '../../../app/contexts/AddImageToBoardContext';
|
||||||
import { useRemoveImageFromBoardMutation } from 'services/apiSlice';
|
import { useRemoveImageFromBoardMutation } from 'services/api/endpoints/boardImages';
|
||||||
|
|
||||||
export const selector = createSelector(
|
export const selector = createSelector(
|
||||||
[gallerySelector, systemSelector, lightboxSelector, activeTabNameSelector],
|
[gallerySelector, systemSelector, lightboxSelector, activeTabNameSelector],
|
||||||
|
@ -56,11 +56,11 @@ import {
|
|||||||
imageCategoriesChanged,
|
imageCategoriesChanged,
|
||||||
selectImagesAll,
|
selectImagesAll,
|
||||||
} from '../store/imagesSlice';
|
} from '../store/imagesSlice';
|
||||||
import { receivedPageOfImages } from 'services/thunks/image';
|
import { receivedPageOfImages } from 'services/api/thunks/image';
|
||||||
import BoardsList from './Boards/BoardsList';
|
import BoardsList from './Boards/BoardsList';
|
||||||
import { boardsSelector } from '../store/boardSlice';
|
import { boardsSelector } from '../store/boardSlice';
|
||||||
import { ChevronUpIcon } from '@chakra-ui/icons';
|
import { ChevronUpIcon } from '@chakra-ui/icons';
|
||||||
import { useListAllBoardsQuery } from 'services/apiSlice';
|
import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
|
||||||
|
|
||||||
const itemSelector = createSelector(
|
const itemSelector = createSelector(
|
||||||
[(state: RootState) => state],
|
[(state: RootState) => state],
|
||||||
@ -167,7 +167,8 @@ const ImageGalleryContent = () => {
|
|||||||
dispatch(
|
dispatch(
|
||||||
receivedPageOfImages({
|
receivedPageOfImages({
|
||||||
categories,
|
categories,
|
||||||
boardId: selectedBoardId,
|
board_id: selectedBoardId,
|
||||||
|
is_intermediate: false,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}, [categories, dispatch, selectedBoardId]);
|
}, [categories, dispatch, selectedBoardId]);
|
||||||
|
@ -17,7 +17,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaCopy } from 'react-icons/fa';
|
import { FaCopy } from 'react-icons/fa';
|
||||||
import { IoArrowUndoCircleOutline } from 'react-icons/io5';
|
import { IoArrowUndoCircleOutline } from 'react-icons/io5';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
type MetadataItemProps = {
|
type MetadataItemProps = {
|
||||||
isLink?: boolean;
|
isLink?: boolean;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { ImageUsage } from 'app/contexts/DeleteImageContext';
|
import { ImageUsage } from 'app/contexts/DeleteImageContext';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
export type RequestedImageDeletionArg = {
|
export type RequestedImageDeletionArg = {
|
||||||
image: ImageDTO;
|
image: ImageDTO;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { api } from 'services/apiSlice';
|
import { boardsApi } from 'services/api/endpoints/boards';
|
||||||
|
|
||||||
type BoardsState = {
|
type BoardsState = {
|
||||||
searchText: string;
|
searchText: string;
|
||||||
@ -29,7 +29,7 @@ const boardsSlice = createSlice({
|
|||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addMatcher(
|
builder.addMatcher(
|
||||||
api.endpoints.deleteBoard.matchFulfilled,
|
boardsApi.endpoints.deleteBoard.matchFulfilled,
|
||||||
(state, action) => {
|
(state, action) => {
|
||||||
if (action.meta.arg.originalArgs === state.selectedBoardId) {
|
if (action.meta.arg.originalArgs === state.selectedBoardId) {
|
||||||
state.selectedBoardId = undefined;
|
state.selectedBoardId = undefined;
|
||||||
|
@ -6,14 +6,14 @@ import {
|
|||||||
createSlice,
|
createSlice,
|
||||||
} from '@reduxjs/toolkit';
|
} from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
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 { dateComparator } from 'common/util/dateComparator';
|
||||||
import { keyBy } from 'lodash-es';
|
import { keyBy } from 'lodash-es';
|
||||||
import {
|
import {
|
||||||
imageDeleted,
|
imageDeleted,
|
||||||
imageUrlsReceived,
|
imageUrlsReceived,
|
||||||
receivedPageOfImages,
|
receivedPageOfImages,
|
||||||
} from 'services/thunks/image';
|
} from 'services/api/thunks/image';
|
||||||
|
|
||||||
export const imagesAdapter = createEntityAdapter<ImageDTO>({
|
export const imagesAdapter = createEntityAdapter<ImageDTO>({
|
||||||
selectId: (image) => image.image_name,
|
selectId: (image) => image.image_name,
|
||||||
@ -73,13 +73,13 @@ const imagesSlice = createSlice({
|
|||||||
});
|
});
|
||||||
builder.addCase(receivedPageOfImages.fulfilled, (state, action) => {
|
builder.addCase(receivedPageOfImages.fulfilled, (state, action) => {
|
||||||
state.isLoading = false;
|
state.isLoading = false;
|
||||||
const { boardId, categories, imageOrigin, isIntermediate } =
|
const { board_id, categories, image_origin, is_intermediate } =
|
||||||
action.meta.arg;
|
action.meta.arg;
|
||||||
|
|
||||||
const { items, offset, limit, total } = action.payload;
|
const { items, offset, limit, total } = action.payload;
|
||||||
imagesAdapter.upsertMany(state, items);
|
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
|
// 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...
|
// TODO: this doesn't work when on the Asset tab/category...
|
||||||
return;
|
return;
|
||||||
@ -91,8 +91,8 @@ const imagesSlice = createSlice({
|
|||||||
});
|
});
|
||||||
builder.addCase(imageDeleted.pending, (state, action) => {
|
builder.addCase(imageDeleted.pending, (state, action) => {
|
||||||
// Image deleted
|
// Image deleted
|
||||||
const { imageName } = action.meta.arg;
|
const { image_name } = action.meta.arg;
|
||||||
imagesAdapter.removeOne(state, imageName);
|
imagesAdapter.removeOne(state, image_name);
|
||||||
});
|
});
|
||||||
builder.addCase(imageUrlsReceived.fulfilled, (state, action) => {
|
builder.addCase(imageUrlsReceived.fulfilled, (state, action) => {
|
||||||
const { image_name, image_url, thumbnail_url } = action.payload;
|
const { image_name, image_url, thumbnail_url } = action.payload;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { TransformComponent, useTransformContext } from 'react-zoom-pan-pinch';
|
import { TransformComponent, useTransformContext } from 'react-zoom-pan-pinch';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
type ReactPanZoomProps = {
|
type ReactPanZoomProps = {
|
||||||
image: ImageDTO;
|
image: ImageDTO;
|
||||||
|
@ -9,9 +9,9 @@ import { memo, useCallback } from 'react';
|
|||||||
|
|
||||||
import { FieldComponentProps } from './types';
|
import { FieldComponentProps } from './types';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { Flex } from '@chakra-ui/react';
|
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';
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
|
|
||||||
const ImageInputFieldComponent = (
|
const ImageInputFieldComponent = (
|
||||||
@ -22,15 +22,15 @@ const ImageInputFieldComponent = (
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: image,
|
currentData: image,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
isSuccess,
|
isSuccess,
|
||||||
} = useGetImageDTOQuery(field.value ?? skipToken);
|
} = useGetImageDTOQuery(field.value?.image_name ?? skipToken);
|
||||||
|
|
||||||
const handleDrop = useCallback(
|
const handleDrop = useCallback(
|
||||||
(droppedImage: ImageDTO) => {
|
({ image_name }: ImageDTO) => {
|
||||||
if (field.value === droppedImage.image_name) {
|
if (field.value?.image_name === image_name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ const ImageInputFieldComponent = (
|
|||||||
fieldValueChanged({
|
fieldValueChanged({
|
||||||
nodeId,
|
nodeId,
|
||||||
fieldName: field.name,
|
fieldName: field.name,
|
||||||
value: droppedImage.image_name,
|
value: { image_name },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -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 { MODEL_TYPE_MAP as BASE_MODEL_NAME_MAP } from 'features/system/components/ModelSelect';
|
||||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useListModelsQuery } from 'services/apiSlice';
|
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
const ModelInputFieldComponent = (
|
const ModelInputFieldComponent = (
|
||||||
props: FieldComponentProps<ModelInputFieldValue, ModelInputFieldTemplate>
|
props: FieldComponentProps<ModelInputFieldValue, ModelInputFieldTemplate>
|
||||||
|
@ -3,7 +3,7 @@ import { useAppDispatch } from 'app/store/storeHooks';
|
|||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { Panel } from 'reactflow';
|
import { Panel } from 'reactflow';
|
||||||
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||||
import NodeInvokeButton from '../ui/NodeInvokeButton';
|
import NodeInvokeButton from '../ui/NodeInvokeButton';
|
||||||
|
|
||||||
const TopCenterPanel = () => {
|
const TopCenterPanel = () => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createAction, isAnyOf } from '@reduxjs/toolkit';
|
import { createAction, isAnyOf } from '@reduxjs/toolkit';
|
||||||
import { Graph } from 'services/api';
|
import { Graph } from 'services/api/types';
|
||||||
|
|
||||||
export const textToImageGraphBuilt = createAction<Graph>(
|
export const textToImageGraphBuilt = createAction<Graph>(
|
||||||
'nodes/textToImageGraphBuilt'
|
'nodes/textToImageGraphBuilt'
|
||||||
|
@ -11,14 +11,13 @@ import {
|
|||||||
NodeChange,
|
NodeChange,
|
||||||
OnConnectStartParams,
|
OnConnectStartParams,
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageField } from 'services/api/types';
|
||||||
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||||
import { InvocationTemplate, InvocationValue } from '../types/types';
|
import { InvocationTemplate, InvocationValue } from '../types/types';
|
||||||
import { parseSchema } from '../util/parseSchema';
|
import { parseSchema } from '../util/parseSchema';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { forEach, size } from 'lodash-es';
|
import { size } from 'lodash-es';
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
import { imageUrlsReceived } from 'services/thunks/image';
|
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
|
|
||||||
export type NodesState = {
|
export type NodesState = {
|
||||||
@ -66,7 +65,7 @@ const nodesSlice = createSlice({
|
|||||||
action: PayloadAction<{
|
action: PayloadAction<{
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
fieldName: string;
|
fieldName: string;
|
||||||
value: string | number | boolean | ImageDTO | RgbaColor | undefined;
|
value: string | number | boolean | ImageField | RgbaColor | undefined;
|
||||||
}>
|
}>
|
||||||
) => {
|
) => {
|
||||||
const { nodeId, fieldName, value } = action.payload;
|
const { nodeId, fieldName, value } = action.payload;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { OpenAPIV3 } from 'openapi-types';
|
import { OpenAPIV3 } from 'openapi-types';
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
import { Graph, ImageDTO } from 'services/api';
|
import { Graph, ImageDTO, ImageField } from 'services/api/types';
|
||||||
import { AnyInvocationType } from 'services/events/types';
|
import { AnyInvocationType } from 'services/events/types';
|
||||||
import { O } from 'ts-toolbelt';
|
import { O } from 'ts-toolbelt';
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ export type VaeInputFieldValue = FieldValueBase & {
|
|||||||
|
|
||||||
export type ImageInputFieldValue = FieldValueBase & {
|
export type ImageInputFieldValue = FieldValueBase & {
|
||||||
type: 'image';
|
type: 'image';
|
||||||
value?: string;
|
value?: ImageField;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ModelInputFieldValue = FieldValueBase & {
|
export type ModelInputFieldValue = FieldValueBase & {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { filter, forEach, size } from 'lodash-es';
|
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 { NonNullableGraph } from '../types/types';
|
||||||
import { CONTROL_NET_COLLECT } from './graphBuilders/constants';
|
import { CONTROL_NET_COLLECT } from './graphBuilders/constants';
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
RandomRangeInvocation,
|
RandomRangeInvocation,
|
||||||
RangeInvocation,
|
RangeInvocation,
|
||||||
TextToImageInvocation,
|
TextToImageInvocation,
|
||||||
} from 'services/api';
|
} from 'services/api/types';
|
||||||
|
|
||||||
export const buildEdges = (
|
export const buildEdges = (
|
||||||
baseNode: TextToImageInvocation | ImageToImageInvocation | InpaintInvocation,
|
baseNode: TextToImageInvocation | ImageToImageInvocation | InpaintInvocation,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import { forEach } from 'lodash-es';
|
import { forEach } from 'lodash-es';
|
||||||
import { buildCanvasInpaintGraph } from './buildCanvasInpaintGraph';
|
import { buildCanvasInpaintGraph } from './buildCanvasInpaintGraph';
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
ImageResizeInvocation,
|
ImageResizeInvocation,
|
||||||
RandomIntInvocation,
|
RandomIntInvocation,
|
||||||
RangeOfSizeInvocation,
|
RangeOfSizeInvocation,
|
||||||
} from 'services/api';
|
} from 'services/api/types';
|
||||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import {
|
import {
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
InpaintInvocation,
|
InpaintInvocation,
|
||||||
RandomIntInvocation,
|
RandomIntInvocation,
|
||||||
RangeOfSizeInvocation,
|
RangeOfSizeInvocation,
|
||||||
} from 'services/api';
|
} from 'services/api/types';
|
||||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import {
|
import {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||||
import { RandomIntInvocation, RangeOfSizeInvocation } from 'services/api';
|
import { RandomIntInvocation, RangeOfSizeInvocation } from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
ITERATE,
|
ITERATE,
|
||||||
LATENTS_TO_IMAGE,
|
LATENTS_TO_IMAGE,
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
ImageResizeInvocation,
|
ImageResizeInvocation,
|
||||||
RandomIntInvocation,
|
RandomIntInvocation,
|
||||||
RangeOfSizeInvocation,
|
RangeOfSizeInvocation,
|
||||||
} from 'services/api';
|
} from 'services/api/types';
|
||||||
import { NonNullableGraph } from 'features/nodes/types/types';
|
import { NonNullableGraph } from 'features/nodes/types/types';
|
||||||
import { log } from 'app/logging/useLogger';
|
import { log } from 'app/logging/useLogger';
|
||||||
import {
|
import {
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
BaseModelType,
|
BaseModelType,
|
||||||
RandomIntInvocation,
|
RandomIntInvocation,
|
||||||
RangeOfSizeInvocation,
|
RangeOfSizeInvocation,
|
||||||
} from 'services/api';
|
} from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
ITERATE,
|
ITERATE,
|
||||||
LATENTS_TO_IMAGE,
|
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 { v4 as uuidv4 } from 'uuid';
|
||||||
import { cloneDeep, omit, reduce } from 'lodash-es';
|
import { cloneDeep, omit, reduce } from 'lodash-es';
|
||||||
import { RootState } from 'app/store/store';
|
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
|
* Crudely converts a model id to a pipeline model field
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { CompelInvocation } from 'services/api';
|
import { CompelInvocation } from 'services/api/types';
|
||||||
import { O } from 'ts-toolbelt';
|
import { O } from 'ts-toolbelt';
|
||||||
|
|
||||||
export const buildCompelNode = (
|
export const buildCompelNode = (
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
Edge,
|
Edge,
|
||||||
ImageToImageInvocation,
|
ImageToImageInvocation,
|
||||||
TextToImageInvocation,
|
TextToImageInvocation,
|
||||||
} from 'services/api';
|
} from 'services/api/types';
|
||||||
import { O } from 'ts-toolbelt';
|
import { O } from 'ts-toolbelt';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { InpaintInvocation } from 'services/api';
|
import { InpaintInvocation } from 'services/api/types';
|
||||||
import { O } from 'ts-toolbelt';
|
import { O } from 'ts-toolbelt';
|
||||||
|
|
||||||
export const buildInpaintNode = (
|
export const buildInpaintNode = (
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { IterateInvocation } from 'services/api';
|
import { IterateInvocation } from 'services/api/types';
|
||||||
|
|
||||||
export const buildIterateNode = (): IterateInvocation => {
|
export const buildIterateNode = (): IterateInvocation => {
|
||||||
const nodeId = uuidv4();
|
const nodeId = uuidv4();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { RandomRangeInvocation, RangeInvocation } from 'services/api';
|
import { RandomRangeInvocation, RangeInvocation } from 'services/api/types';
|
||||||
|
|
||||||
export const buildRangeNode = (
|
export const buildRangeNode = (
|
||||||
state: RootState
|
state: RootState
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { TextToImageInvocation } from 'services/api';
|
import { TextToImageInvocation } from 'services/api/types';
|
||||||
import { O } from 'ts-toolbelt';
|
import { O } from 'ts-toolbelt';
|
||||||
|
|
||||||
export const buildTxt2ImgNode = (
|
export const buildTxt2ImgNode = (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex, Spacer, Text } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
@ -9,10 +9,14 @@ import { useCallback } from 'react';
|
|||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAIDndImage from 'common/components/IAIDndImage';
|
import IAIDndImage from 'common/components/IAIDndImage';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { IAIImageLoadingFallback } from 'common/components/IAIImageFallback';
|
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';
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import { FaUndo, FaUpload } from 'react-icons/fa';
|
||||||
|
import useImageUploader from 'common/hooks/useImageUploader';
|
||||||
|
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[generationSelector],
|
[generationSelector],
|
||||||
@ -28,14 +32,19 @@ const selector = createSelector(
|
|||||||
const InitialImagePreview = () => {
|
const InitialImagePreview = () => {
|
||||||
const { initialImage } = useAppSelector(selector);
|
const { initialImage } = useAppSelector(selector);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
const { openUploader } = useImageUploader();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: image,
|
currentData: image,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError,
|
isError,
|
||||||
isSuccess,
|
isSuccess,
|
||||||
} = useGetImageDTOQuery(initialImage?.imageName ?? skipToken);
|
} = useGetImageDTOQuery(initialImage?.imageName ?? skipToken);
|
||||||
|
|
||||||
|
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
||||||
|
postUploadAction: { type: 'SET_INITIAL_IMAGE' },
|
||||||
|
});
|
||||||
|
|
||||||
const handleDrop = useCallback(
|
const handleDrop = useCallback(
|
||||||
(droppedImage: ImageDTO) => {
|
(droppedImage: ImageDTO) => {
|
||||||
if (droppedImage.image_name === initialImage?.imageName) {
|
if (droppedImage.image_name === initialImage?.imageName) {
|
||||||
@ -50,25 +59,66 @@ const InitialImagePreview = () => {
|
|||||||
dispatch(clearInitialImage());
|
dispatch(clearInitialImage());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
|
const handleUpload = useCallback(() => {
|
||||||
|
openUploader();
|
||||||
|
}, [openUploader]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
sx={{
|
sx={{
|
||||||
|
flexDir: 'column',
|
||||||
width: 'full',
|
width: 'full',
|
||||||
height: 'full',
|
height: 'full',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
p: 4,
|
p: 4,
|
||||||
|
gap: 4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
w: 'full',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
sx={{
|
||||||
|
color: 'base.200',
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: 'sm',
|
||||||
|
userSelect: 'none',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Initial Image
|
||||||
|
</Text>
|
||||||
|
<Spacer />
|
||||||
|
<IAIIconButton
|
||||||
|
tooltip="Upload Initial Image"
|
||||||
|
aria-label="Upload Initial Image"
|
||||||
|
icon={<FaUpload />}
|
||||||
|
onClick={handleUpload}
|
||||||
|
{...getUploadButtonProps()}
|
||||||
|
/>
|
||||||
|
<IAIIconButton
|
||||||
|
tooltip="Reset Initial Image"
|
||||||
|
aria-label="Reset Initial Image"
|
||||||
|
icon={<FaUndo />}
|
||||||
|
onClick={handleReset}
|
||||||
|
isDisabled={!initialImage}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
<IAIDndImage
|
<IAIDndImage
|
||||||
image={image}
|
image={image}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
onReset={handleReset}
|
|
||||||
fallback={<IAIImageLoadingFallback sx={{ bg: 'none' }} />}
|
fallback={<IAIImageLoadingFallback sx={{ bg: 'none' }} />}
|
||||||
postUploadAction={{ type: 'SET_INITIAL_IMAGE' }}
|
isUploadDisabled={true}
|
||||||
withResetIcon
|
fitContainer
|
||||||
/>
|
/>
|
||||||
|
<input {...getUploadInputProps()} />
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { MdCancel, MdCancelScheduleSend } from 'react-icons/md';
|
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';
|
import { ChevronDownIcon } from '@chakra-ui/icons';
|
||||||
|
|
||||||
const cancelButtonSelector = createSelector(
|
const cancelButtonSelector = createSelector(
|
||||||
@ -78,7 +78,7 @@ const CancelButton = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(sessionCanceled({ sessionId }));
|
dispatch(sessionCanceled({ session_id: sessionId }));
|
||||||
}, [dispatch, sessionId, cancelType]);
|
}, [dispatch, sessionId, cancelType]);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -13,10 +13,10 @@ import {
|
|||||||
setSteps,
|
setSteps,
|
||||||
setWidth,
|
setWidth,
|
||||||
} from '../store/generationSlice';
|
} from '../store/generationSlice';
|
||||||
import { isImageField } from 'services/types/guards';
|
import { isImageField } from 'services/api/guards';
|
||||||
import { initialImageSelected } from '../store/actions';
|
import { initialImageSelected } from '../store/actions';
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
isValidCfgScale,
|
isValidCfgScale,
|
||||||
isValidHeight,
|
isValidHeight,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
export const initialImageSelected = createAction<ImageDTO | string | undefined>(
|
export const initialImageSelected = createAction<ImageDTO | string | undefined>(
|
||||||
'generation/initialImageSelected'
|
'generation/initialImageSelected'
|
||||||
|
@ -3,7 +3,7 @@ import { createSlice } from '@reduxjs/toolkit';
|
|||||||
import { DEFAULT_SCHEDULER_NAME } from 'app/constants';
|
import { DEFAULT_SCHEDULER_NAME } from 'app/constants';
|
||||||
import { configChanged } from 'features/system/store/configSlice';
|
import { configChanged } from 'features/system/store/configSlice';
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import {
|
import {
|
||||||
CfgScaleParam,
|
CfgScaleParam,
|
||||||
HeightParam,
|
HeightParam,
|
||||||
|
@ -8,7 +8,7 @@ import { modelSelected } from 'features/parameters/store/generationSlice';
|
|||||||
import { forEach, isString } from 'lodash-es';
|
import { forEach, isString } from 'lodash-es';
|
||||||
import { SelectItem } from '@mantine/core';
|
import { SelectItem } from '@mantine/core';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { useListModelsQuery } from 'services/apiSlice';
|
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
export const MODEL_TYPE_MAP = {
|
export const MODEL_TYPE_MAP = {
|
||||||
'sd-1': 'Stable Diffusion 1.x',
|
'sd-1': 'Stable Diffusion 1.x',
|
||||||
|
@ -19,8 +19,11 @@ import {
|
|||||||
appSocketUnsubscribed,
|
appSocketUnsubscribed,
|
||||||
} from 'services/events/actions';
|
} from 'services/events/actions';
|
||||||
import { ProgressImage } from 'services/events/types';
|
import { ProgressImage } from 'services/events/types';
|
||||||
import { imageUploaded } from 'services/thunks/image';
|
import { imageUploaded } from 'services/api/thunks/image';
|
||||||
import { isAnySessionRejected, sessionCanceled } from 'services/thunks/session';
|
import {
|
||||||
|
isAnySessionRejected,
|
||||||
|
sessionCanceled,
|
||||||
|
} from 'services/api/thunks/session';
|
||||||
import { makeToast } from '../../../app/components/Toaster';
|
import { makeToast } from '../../../app/components/Toaster';
|
||||||
import { LANGUAGES } from '../components/LanguagePicker';
|
import { LANGUAGES } from '../components/LanguagePicker';
|
||||||
|
|
||||||
@ -362,7 +365,7 @@ export const systemSlice = createSlice({
|
|||||||
* Session Canceled - FULFILLED
|
* Session Canceled - FULFILLED
|
||||||
*/
|
*/
|
||||||
builder.addCase(sessionCanceled.fulfilled, (state, action) => {
|
builder.addCase(sessionCanceled.fulfilled, (state, action) => {
|
||||||
state.canceledSession = action.meta.arg.sessionId;
|
state.canceledSession = action.meta.arg.session_id;
|
||||||
state.isProcessing = false;
|
state.isProcessing = false;
|
||||||
state.isCancelable = false;
|
state.isCancelable = false;
|
||||||
state.isCancelScheduled = false;
|
state.isCancelScheduled = false;
|
||||||
|
@ -12,7 +12,7 @@ import { uiSelector } from 'features/ui/store/uiSelectors';
|
|||||||
import { memo, useCallback, useLayoutEffect } from 'react';
|
import { memo, useCallback, useLayoutEffect } from 'react';
|
||||||
import UnifiedCanvasToolbarBeta from './UnifiedCanvasBeta/UnifiedCanvasToolbarBeta';
|
import UnifiedCanvasToolbarBeta from './UnifiedCanvasBeta/UnifiedCanvasToolbarBeta';
|
||||||
import UnifiedCanvasToolSettingsBeta from './UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta';
|
import UnifiedCanvasToolSettingsBeta from './UnifiedCanvasBeta/UnifiedCanvasToolSettingsBeta';
|
||||||
import { ImageDTO } from 'services/api';
|
import { ImageDTO } from 'services/api/types';
|
||||||
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice';
|
||||||
import { useDroppable } from '@dnd-kit/core';
|
import { useDroppable } from '@dnd-kit/core';
|
||||||
import IAIDropOverlay from 'common/components/IAIDropOverlay';
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user