mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): fix all circular dependencies
This commit is contained in:
parent
5468d9a9fc
commit
6452d0fc28
@ -10,7 +10,7 @@ async function main() {
|
|||||||
);
|
);
|
||||||
const types = await openapiTS(OPENAPI_URL, {
|
const types = await openapiTS(OPENAPI_URL, {
|
||||||
exportType: true,
|
exportType: true,
|
||||||
transform: (schemaObject, metadata) => {
|
transform: (schemaObject) => {
|
||||||
if ('format' in schemaObject && schemaObject.format === 'binary') {
|
if ('format' in schemaObject && schemaObject.format === 'binary') {
|
||||||
return schemaObject.nullable ? 'Blob | null' : 'Blob';
|
return schemaObject.nullable ? 'Blob | null' : 'Blob';
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ const ImageDndContext = (props: ImageDndContextProps) => {
|
|||||||
const handleDragEnd = useCallback(
|
const handleDragEnd = useCallback(
|
||||||
(event: DragEndEvent) => {
|
(event: DragEndEvent) => {
|
||||||
console.log('dragEnd', event.active.data.current);
|
console.log('dragEnd', event.active.data.current);
|
||||||
const activeData = event.active.data.current;
|
|
||||||
const overData = event.over?.data.current;
|
const overData = event.over?.data.current;
|
||||||
if (!activeDragData || !overData) {
|
if (!activeDragData || !overData) {
|
||||||
return;
|
return;
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
useDraggable as useOriginalDraggable,
|
useDraggable as useOriginalDraggable,
|
||||||
useDroppable as useOriginalDroppable,
|
useDroppable as useOriginalDroppable,
|
||||||
} from '@dnd-kit/core';
|
} from '@dnd-kit/core';
|
||||||
import { BoardId } from 'features/gallery/store/gallerySlice';
|
import { BoardId } from 'features/gallery/store/types';
|
||||||
import { ImageDTO } from 'services/api/types';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
type BaseDropData = {
|
type BaseDropData = {
|
||||||
|
@ -1,28 +1,10 @@
|
|||||||
import { useToast, UseToastOptions } from '@chakra-ui/react';
|
import { useToast } from '@chakra-ui/react';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { toastQueueSelector } from 'features/system/store/systemSelectors';
|
import { toastQueueSelector } from 'features/system/store/systemSelectors';
|
||||||
import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
|
import { addToast, clearToastQueue } from 'features/system/store/systemSlice';
|
||||||
|
import { MakeToastArg, makeToast } from 'features/system/util/makeToast';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
export type MakeToastArg = string | UseToastOptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes a toast from a string or a UseToastOptions object.
|
|
||||||
* If a string is passed, the toast will have the status 'info' and will be closable with a duration of 2500ms.
|
|
||||||
*/
|
|
||||||
export const makeToast = (arg: MakeToastArg): UseToastOptions => {
|
|
||||||
if (typeof arg === 'string') {
|
|
||||||
return {
|
|
||||||
title: arg,
|
|
||||||
status: 'info',
|
|
||||||
isClosable: true,
|
|
||||||
duration: 2500,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return { status: 'info', isClosable: true, duration: 2500, ...arg };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logical component. Watches the toast queue and makes toasts when the queue is not empty.
|
* Logical component. Watches the toast queue and makes toasts when the queue is not empty.
|
||||||
* @returns null
|
* @returns null
|
||||||
|
@ -1,66 +1,2 @@
|
|||||||
// zod needs the array to be `as const` to infer the type correctly
|
|
||||||
|
|
||||||
import { SchedulerParam } from 'features/parameters/types/parameterSchemas';
|
|
||||||
|
|
||||||
// this is the source of the `SchedulerParam` type, which is generated by zod
|
|
||||||
export const SCHEDULER_NAMES_AS_CONST = [
|
|
||||||
'euler',
|
|
||||||
'deis',
|
|
||||||
'ddim',
|
|
||||||
'ddpm',
|
|
||||||
'dpmpp_2s',
|
|
||||||
'dpmpp_2m',
|
|
||||||
'dpmpp_2m_sde',
|
|
||||||
'dpmpp_sde',
|
|
||||||
'heun',
|
|
||||||
'kdpm_2',
|
|
||||||
'lms',
|
|
||||||
'pndm',
|
|
||||||
'unipc',
|
|
||||||
'euler_k',
|
|
||||||
'dpmpp_2s_k',
|
|
||||||
'dpmpp_2m_k',
|
|
||||||
'dpmpp_2m_sde_k',
|
|
||||||
'dpmpp_sde_k',
|
|
||||||
'heun_k',
|
|
||||||
'lms_k',
|
|
||||||
'euler_a',
|
|
||||||
'kdpm_2_a',
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
export const DEFAULT_SCHEDULER_NAME = 'euler';
|
|
||||||
|
|
||||||
export const SCHEDULER_NAMES: SchedulerParam[] = [...SCHEDULER_NAMES_AS_CONST];
|
|
||||||
|
|
||||||
export const SCHEDULER_LABEL_MAP: Record<SchedulerParam, string> = {
|
|
||||||
euler: 'Euler',
|
|
||||||
deis: 'DEIS',
|
|
||||||
ddim: 'DDIM',
|
|
||||||
ddpm: 'DDPM',
|
|
||||||
dpmpp_sde: 'DPM++ SDE',
|
|
||||||
dpmpp_2s: 'DPM++ 2S',
|
|
||||||
dpmpp_2m: 'DPM++ 2M',
|
|
||||||
dpmpp_2m_sde: 'DPM++ 2M SDE',
|
|
||||||
heun: 'Heun',
|
|
||||||
kdpm_2: 'KDPM 2',
|
|
||||||
lms: 'LMS',
|
|
||||||
pndm: 'PNDM',
|
|
||||||
unipc: 'UniPC',
|
|
||||||
euler_k: 'Euler Karras',
|
|
||||||
dpmpp_sde_k: 'DPM++ SDE Karras',
|
|
||||||
dpmpp_2s_k: 'DPM++ 2S Karras',
|
|
||||||
dpmpp_2m_k: 'DPM++ 2M Karras',
|
|
||||||
dpmpp_2m_sde_k: 'DPM++ 2M SDE Karras',
|
|
||||||
heun_k: 'Heun Karras',
|
|
||||||
lms_k: 'LMS Karras',
|
|
||||||
euler_a: 'Euler Ancestral',
|
|
||||||
kdpm_2_a: 'KDPM 2 Ancestral',
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Scheduler = (typeof SCHEDULER_NAMES)[number];
|
|
||||||
|
|
||||||
export const NUMPY_RAND_MIN = 0;
|
export const NUMPY_RAND_MIN = 0;
|
||||||
|
|
||||||
export const NUMPY_RAND_MAX = 2147483647;
|
export const NUMPY_RAND_MAX = 2147483647;
|
||||||
|
|
||||||
export const NODE_MIN_WIDTH = 250;
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import {
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
IMAGE_CATEGORIES,
|
import { IMAGE_CATEGORIES } from 'features/gallery/store/types';
|
||||||
imageSelected,
|
|
||||||
} from 'features/gallery/store/gallerySlice';
|
|
||||||
import {
|
import {
|
||||||
ImageCache,
|
ImageCache,
|
||||||
getListImagesUrl,
|
getListImagesUrl,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
||||||
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
||||||
import { getImageUsage } from 'features/imageDeletion/store/imageDeletionSlice';
|
import { getImageUsage } from 'features/imageDeletion/store/imageDeletionSelectors';
|
||||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||||
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import { isAnyOf } from '@reduxjs/toolkit';
|
import { isAnyOf } from '@reduxjs/toolkit';
|
||||||
import {
|
import {
|
||||||
ASSETS_CATEGORIES,
|
|
||||||
IMAGE_CATEGORIES,
|
|
||||||
boardIdSelected,
|
boardIdSelected,
|
||||||
galleryViewChanged,
|
galleryViewChanged,
|
||||||
imageSelected,
|
imageSelected,
|
||||||
} from 'features/gallery/store/gallerySlice';
|
} from 'features/gallery/store/gallerySlice';
|
||||||
|
import {
|
||||||
|
ASSETS_CATEGORIES,
|
||||||
|
IMAGE_CATEGORIES,
|
||||||
|
} from 'features/gallery/store/types';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
|
@ -3,10 +3,8 @@ import { resetCanvas } from 'features/canvas/store/canvasSlice';
|
|||||||
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
||||||
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
||||||
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
import {
|
import { imageDeletionConfirmed } from 'features/imageDeletion/store/actions';
|
||||||
imageDeletionConfirmed,
|
import { isModalOpenChanged } from 'features/imageDeletion/store/imageDeletionSlice';
|
||||||
isModalOpenChanged,
|
|
||||||
} from 'features/imageDeletion/store/imageDeletionSlice';
|
|
||||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||||
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
import { clearInitialImage } from 'features/parameters/store/generationSlice';
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
import { imageDeletionConfirmed } from 'features/imageDeletion/store/actions';
|
||||||
|
import { selectImageUsage } from 'features/imageDeletion/store/imageDeletionSelectors';
|
||||||
import {
|
import {
|
||||||
imageDeletionConfirmed,
|
|
||||||
imageToDeleteSelected,
|
imageToDeleteSelected,
|
||||||
isModalOpenChanged,
|
isModalOpenChanged,
|
||||||
selectImageUsage,
|
|
||||||
} from 'features/imageDeletion/store/imageDeletionSlice';
|
} from 'features/imageDeletion/store/imageDeletionSlice';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { makeToast } from 'app/components/Toaster';
|
|
||||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||||
import { initialImageChanged } from 'features/parameters/store/generationSlice';
|
import { initialImageChanged } from 'features/parameters/store/generationSlice';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { makeToast } from 'app/components/Toaster';
|
import { logger } from 'app/logging/logger';
|
||||||
import { $logger, logger } from 'app/logging/logger';
|
import { controlNetRemoved } from 'features/controlNet/store/controlNetSlice';
|
||||||
import { loraRemoved } from 'features/lora/store/loraSlice';
|
import { loraRemoved } from 'features/lora/store/loraSlice';
|
||||||
import { modelSelected } from 'features/parameters/store/actions';
|
import { modelSelected } from 'features/parameters/store/actions';
|
||||||
import {
|
import {
|
||||||
@ -8,9 +8,9 @@ import {
|
|||||||
} from 'features/parameters/store/generationSlice';
|
} from 'features/parameters/store/generationSlice';
|
||||||
import { zMainModel } from 'features/parameters/types/parameterSchemas';
|
import { zMainModel } from 'features/parameters/types/parameterSchemas';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { forEach } from 'lodash-es';
|
import { forEach } from 'lodash-es';
|
||||||
import { startAppListening } from '..';
|
import { startAppListening } from '..';
|
||||||
import { controlNetRemoved } from 'features/controlNet/store/controlNetSlice';
|
|
||||||
|
|
||||||
export const addModelSelectedListener = () => {
|
export const addModelSelectedListener = () => {
|
||||||
startAppListening({
|
startAppListening({
|
||||||
|
@ -2,11 +2,11 @@ import { logger } from 'app/logging/logger';
|
|||||||
import { parseify } from 'common/util/serialize';
|
import { parseify } from 'common/util/serialize';
|
||||||
import { addImageToStagingArea } from 'features/canvas/store/canvasSlice';
|
import { addImageToStagingArea } from 'features/canvas/store/canvasSlice';
|
||||||
import {
|
import {
|
||||||
IMAGE_CATEGORIES,
|
|
||||||
boardIdSelected,
|
boardIdSelected,
|
||||||
galleryViewChanged,
|
galleryViewChanged,
|
||||||
imageSelected,
|
imageSelected,
|
||||||
} from 'features/gallery/store/gallerySlice';
|
} from 'features/gallery/store/gallerySlice';
|
||||||
|
import { IMAGE_CATEGORIES } from 'features/gallery/store/types';
|
||||||
import { progressImageSet } from 'features/system/store/systemSlice';
|
import { progressImageSet } from 'features/system/store/systemSlice';
|
||||||
import { imagesAdapter, imagesApi } from 'services/api/endpoints/images';
|
import { imagesAdapter, imagesApi } from 'services/api/endpoints/images';
|
||||||
import { isImageOutput } from 'services/api/guards';
|
import { isImageOutput } from 'services/api/guards';
|
||||||
|
@ -4,14 +4,11 @@ import {
|
|||||||
autoBatchEnhancer,
|
autoBatchEnhancer,
|
||||||
combineReducers,
|
combineReducers,
|
||||||
configureStore,
|
configureStore,
|
||||||
|
createAsyncThunk,
|
||||||
} from '@reduxjs/toolkit';
|
} from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import dynamicMiddlewares from 'redux-dynamic-middlewares';
|
|
||||||
import { rememberEnhancer, rememberReducer } from 'redux-remember';
|
|
||||||
|
|
||||||
import canvasReducer from 'features/canvas/store/canvasSlice';
|
import canvasReducer from 'features/canvas/store/canvasSlice';
|
||||||
import controlNetReducer from 'features/controlNet/store/controlNetSlice';
|
import controlNetReducer from 'features/controlNet/store/controlNetSlice';
|
||||||
import dynamicPromptsReducer from 'features/dynamicPrompts/store/slice';
|
import dynamicPromptsReducer from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||||
import boardsReducer from 'features/gallery/store/boardSlice';
|
import boardsReducer from 'features/gallery/store/boardSlice';
|
||||||
import galleryReducer from 'features/gallery/store/gallerySlice';
|
import galleryReducer from 'features/gallery/store/gallerySlice';
|
||||||
import imageDeletionReducer from 'features/imageDeletion/store/imageDeletionSlice';
|
import imageDeletionReducer from 'features/imageDeletion/store/imageDeletionSlice';
|
||||||
@ -24,9 +21,8 @@ import systemReducer from 'features/system/store/systemSlice';
|
|||||||
import modelmanagerReducer from 'features/ui/components/tabs/ModelManager/store/modelManagerSlice';
|
import modelmanagerReducer from 'features/ui/components/tabs/ModelManager/store/modelManagerSlice';
|
||||||
import hotkeysReducer from 'features/ui/store/hotkeysSlice';
|
import hotkeysReducer from 'features/ui/store/hotkeysSlice';
|
||||||
import uiReducer from 'features/ui/store/uiSlice';
|
import uiReducer from 'features/ui/store/uiSlice';
|
||||||
|
import dynamicMiddlewares from 'redux-dynamic-middlewares';
|
||||||
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
import { rememberEnhancer, rememberReducer } from 'redux-remember';
|
||||||
|
|
||||||
import { api } from 'services/api';
|
import { api } from 'services/api';
|
||||||
import { LOCALSTORAGE_PREFIX } from './constants';
|
import { LOCALSTORAGE_PREFIX } from './constants';
|
||||||
import { serialize } from './enhancers/reduxRemember/serialize';
|
import { serialize } from './enhancers/reduxRemember/serialize';
|
||||||
@ -34,6 +30,7 @@ import { unserialize } from './enhancers/reduxRemember/unserialize';
|
|||||||
import { actionSanitizer } from './middleware/devtools/actionSanitizer';
|
import { actionSanitizer } from './middleware/devtools/actionSanitizer';
|
||||||
import { actionsDenylist } from './middleware/devtools/actionsDenylist';
|
import { actionsDenylist } from './middleware/devtools/actionsDenylist';
|
||||||
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
import { stateSanitizer } from './middleware/devtools/stateSanitizer';
|
||||||
|
import { listenerMiddleware } from './middleware/listenerMiddleware';
|
||||||
|
|
||||||
const allReducers = {
|
const allReducers = {
|
||||||
canvas: canvasReducer,
|
canvas: canvasReducer,
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
|
||||||
import { AppDispatch, RootState } from 'app/store/store';
|
|
||||||
|
|
||||||
// https://redux-toolkit.js.org/usage/usage-with-typescript#defining-a-pre-typed-createasyncthunk
|
|
||||||
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
|
|
||||||
state: RootState;
|
|
||||||
dispatch: AppDispatch;
|
|
||||||
}>();
|
|
@ -1,10 +1,10 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
roundDownToMultiple,
|
roundDownToMultiple,
|
||||||
roundToMultiple,
|
roundToMultiple,
|
||||||
} from 'common/util/roundDownToMultiple';
|
} from 'common/util/roundDownToMultiple';
|
||||||
import { canvasSelector } from 'features/canvas/store/canvasSelectors';
|
|
||||||
import {
|
import {
|
||||||
setBoundingBoxCoordinates,
|
setBoundingBoxCoordinates,
|
||||||
setBoundingBoxDimensions,
|
setBoundingBoxDimensions,
|
||||||
@ -13,7 +13,6 @@ import {
|
|||||||
setIsTransformingBoundingBox,
|
setIsTransformingBoundingBox,
|
||||||
setShouldSnapToGrid,
|
setShouldSnapToGrid,
|
||||||
} from 'features/canvas/store/canvasSlice';
|
} from 'features/canvas/store/canvasSlice';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import Konva from 'konva';
|
import Konva from 'konva';
|
||||||
import { GroupConfig } from 'konva/lib/Group';
|
import { GroupConfig } from 'konva/lib/Group';
|
||||||
import { KonvaEventObject } from 'konva/lib/Node';
|
import { KonvaEventObject } from 'konva/lib/Node';
|
||||||
@ -25,8 +24,8 @@ import { useHotkeys } from 'react-hotkeys-hook';
|
|||||||
import { Group, Rect, Transformer } from 'react-konva';
|
import { Group, Rect, Transformer } from 'react-konva';
|
||||||
|
|
||||||
const boundingBoxPreviewSelector = createSelector(
|
const boundingBoxPreviewSelector = createSelector(
|
||||||
[canvasSelector, uiSelector],
|
[stateSelector],
|
||||||
(canvas, ui) => {
|
({ canvas, generation }) => {
|
||||||
const {
|
const {
|
||||||
boundingBoxCoordinates,
|
boundingBoxCoordinates,
|
||||||
boundingBoxDimensions,
|
boundingBoxDimensions,
|
||||||
@ -38,7 +37,7 @@ const boundingBoxPreviewSelector = createSelector(
|
|||||||
shouldSnapToGrid,
|
shouldSnapToGrid,
|
||||||
} = canvas;
|
} = canvas;
|
||||||
|
|
||||||
const { aspectRatio } = ui;
|
const { aspectRatio } = generation;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
boundingBoxCoordinates,
|
boundingBoxCoordinates,
|
||||||
|
@ -4,14 +4,13 @@ import {
|
|||||||
roundDownToMultiple,
|
roundDownToMultiple,
|
||||||
roundToMultiple,
|
roundToMultiple,
|
||||||
} from 'common/util/roundDownToMultiple';
|
} from 'common/util/roundDownToMultiple';
|
||||||
import { IRect, Vector2d } from 'konva/lib/types';
|
import { setAspectRatio } from 'features/parameters/store/generationSlice';
|
||||||
import { clamp, cloneDeep } from 'lodash-es';
|
|
||||||
//
|
|
||||||
import {
|
import {
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
setAspectRatio,
|
|
||||||
setShouldUseCanvasBetaLayout,
|
setShouldUseCanvasBetaLayout,
|
||||||
} from 'features/ui/store/uiSlice';
|
} from 'features/ui/store/uiSlice';
|
||||||
|
import { IRect, Vector2d } from 'konva/lib/types';
|
||||||
|
import { clamp, cloneDeep } from 'lodash-es';
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
import { sessionCanceled } from 'services/api/thunks/session';
|
import { sessionCanceled } from 'services/api/thunks/session';
|
||||||
import { ImageDTO } from 'services/api/types';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { ControlNetModelParam } from 'features/parameters/types/parameterSchemas';
|
import { ControlNetModelParam } from 'features/parameters/types/parameterSchemas';
|
||||||
import { cloneDeep, forEach } from 'lodash-es';
|
import { cloneDeep, forEach } from 'lodash-es';
|
||||||
import { imagesApi } from 'services/api/endpoints/images';
|
import { imagesApi } from 'services/api/endpoints/images';
|
||||||
@ -365,5 +364,3 @@ export const {
|
|||||||
} = controlNetSlice.actions;
|
} = controlNetSlice.actions;
|
||||||
|
|
||||||
export default controlNetSlice.reducer;
|
export default controlNetSlice.reducer;
|
||||||
|
|
||||||
export const controlNetSelector = (state: RootState) => state.controlNet;
|
|
||||||
|
@ -4,7 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { combinatorialToggled } from '../store/slice';
|
import { combinatorialToggled } from '../store/dynamicPromptsSlice';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
|
@ -4,7 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { isEnabledToggled } from '../store/slice';
|
import { isEnabledToggled } from '../store/dynamicPromptsSlice';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
|
@ -4,7 +4,10 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { maxPromptsChanged, maxPromptsReset } from '../store/slice';
|
import {
|
||||||
|
maxPromptsChanged,
|
||||||
|
maxPromptsReset,
|
||||||
|
} from '../store/dynamicPromptsSlice';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
stateSelector,
|
stateSelector,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
|
|
||||||
export interface DynamicPromptsState {
|
export interface DynamicPromptsState {
|
||||||
isEnabled: boolean;
|
isEnabled: boolean;
|
||||||
@ -32,9 +31,6 @@ export const dynamicPromptsSlice = createSlice({
|
|||||||
state.isEnabled = !state.isEnabled;
|
state.isEnabled = !state.isEnabled;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
|
||||||
//
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
@ -45,6 +41,3 @@ export const {
|
|||||||
} = dynamicPromptsSlice.actions;
|
} = dynamicPromptsSlice.actions;
|
||||||
|
|
||||||
export default dynamicPromptsSlice.reducer;
|
export default dynamicPromptsSlice.reducer;
|
||||||
|
|
||||||
export const dynamicPromptsSelector = (state: RootState) =>
|
|
||||||
state.dynamicPrompts;
|
|
@ -2,7 +2,7 @@ import { As, Badge, Flex } from '@chakra-ui/react';
|
|||||||
import { TypesafeDroppableData } from 'app/components/ImageDnd/typesafeDnd';
|
import { TypesafeDroppableData } from 'app/components/ImageDnd/typesafeDnd';
|
||||||
import IAIDroppable from 'common/components/IAIDroppable';
|
import IAIDroppable from 'common/components/IAIDroppable';
|
||||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||||
import { BoardId } from 'features/gallery/store/gallerySlice';
|
import { BoardId } from 'features/gallery/store/types';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import BoardContextMenu from '../BoardContextMenu';
|
import BoardContextMenu from '../BoardContextMenu';
|
||||||
|
|
||||||
|
@ -11,14 +11,12 @@ import {
|
|||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||||
|
import { ImageUsage } from 'app/contexts/AddImageToBoardContext';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import ImageUsageMessage from 'features/imageDeletion/components/ImageUsageMessage';
|
import ImageUsageMessage from 'features/imageDeletion/components/ImageUsageMessage';
|
||||||
import {
|
import { getImageUsage } from 'features/imageDeletion/store/imageDeletionSelectors';
|
||||||
ImageUsage,
|
|
||||||
getImageUsage,
|
|
||||||
} from 'features/imageDeletion/store/imageDeletionSlice';
|
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { memo, useCallback, useMemo, useRef } from 'react';
|
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
@ -2,8 +2,8 @@ import { Box, Flex } from '@chakra-ui/react';
|
|||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||||
import { IMAGE_LIMIT } from 'features/gallery//store/gallerySlice';
|
|
||||||
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
|
||||||
|
import { IMAGE_LIMIT } from 'features/gallery/store/types';
|
||||||
import {
|
import {
|
||||||
UseOverlayScrollbarsParams,
|
UseOverlayScrollbarsParams,
|
||||||
useOverlayScrollbars,
|
useOverlayScrollbars,
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import { imageSelected } from 'features/gallery/store/gallerySlice';
|
||||||
IMAGE_LIMIT,
|
|
||||||
imageSelected,
|
|
||||||
} from 'features/gallery/store/gallerySlice';
|
|
||||||
import { clamp, isEqual } from 'lodash-es';
|
import { clamp, isEqual } from 'lodash-es';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
@ -14,6 +11,7 @@ import {
|
|||||||
useLazyListImagesQuery,
|
useLazyListImagesQuery,
|
||||||
} from 'services/api/endpoints/images';
|
} from 'services/api/endpoints/images';
|
||||||
import { selectListImagesBaseQueryArgs } from '../store/gallerySelectors';
|
import { selectListImagesBaseQueryArgs } from '../store/gallerySelectors';
|
||||||
|
import { IMAGE_LIMIT } from '../store/types';
|
||||||
|
|
||||||
export const nextPrevImageButtonsSelector = createSelector(
|
export const nextPrevImageButtonsSelector = createSelector(
|
||||||
[stateSelector, selectListImagesBaseQueryArgs],
|
[stateSelector, selectListImagesBaseQueryArgs],
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
|
|
||||||
type BoardsState = {
|
type BoardsState = {
|
||||||
searchText: string;
|
searchText: string;
|
||||||
@ -27,6 +26,4 @@ const boardsSlice = createSlice({
|
|||||||
export const { setBoardSearchText, setUpdateBoardModalOpen } =
|
export const { setBoardSearchText, setUpdateBoardModalOpen } =
|
||||||
boardsSlice.actions;
|
boardsSlice.actions;
|
||||||
|
|
||||||
export const boardsSelector = (state: RootState) => state.boards;
|
|
||||||
|
|
||||||
export default boardsSlice.reducer;
|
export default boardsSlice.reducer;
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
ASSETS_CATEGORIES,
|
ASSETS_CATEGORIES,
|
||||||
IMAGE_CATEGORIES,
|
IMAGE_CATEGORIES,
|
||||||
INITIAL_IMAGE_LIMIT,
|
INITIAL_IMAGE_LIMIT,
|
||||||
} from './gallerySlice';
|
} from './types';
|
||||||
|
|
||||||
export const gallerySelector = (state: RootState) => state.gallery;
|
export const gallerySelector = (state: RootState) => state.gallery;
|
||||||
|
|
||||||
|
@ -2,32 +2,7 @@ import type { PayloadAction } from '@reduxjs/toolkit';
|
|||||||
import { createSlice, isAnyOf } from '@reduxjs/toolkit';
|
import { createSlice, isAnyOf } from '@reduxjs/toolkit';
|
||||||
import { uniq } from 'lodash-es';
|
import { uniq } from 'lodash-es';
|
||||||
import { boardsApi } from 'services/api/endpoints/boards';
|
import { boardsApi } from 'services/api/endpoints/boards';
|
||||||
import { ImageCategory } from 'services/api/types';
|
import { BoardId, GalleryState, GalleryView } from './types';
|
||||||
|
|
||||||
export const IMAGE_CATEGORIES: ImageCategory[] = ['general'];
|
|
||||||
export const ASSETS_CATEGORIES: ImageCategory[] = [
|
|
||||||
'control',
|
|
||||||
'mask',
|
|
||||||
'user',
|
|
||||||
'other',
|
|
||||||
];
|
|
||||||
export const INITIAL_IMAGE_LIMIT = 100;
|
|
||||||
export const IMAGE_LIMIT = 20;
|
|
||||||
|
|
||||||
export type GalleryView = 'images' | 'assets';
|
|
||||||
// export type BoardId = 'no_board' | (string & Record<never, never>);
|
|
||||||
export type BoardId = string | undefined;
|
|
||||||
|
|
||||||
type GalleryState = {
|
|
||||||
selection: string[];
|
|
||||||
shouldAutoSwitch: boolean;
|
|
||||||
autoAddBoardId: string | undefined;
|
|
||||||
galleryImageMinimumWidth: number;
|
|
||||||
selectedBoardId: BoardId;
|
|
||||||
galleryView: GalleryView;
|
|
||||||
batchImageNames: string[];
|
|
||||||
isBatchEnabled: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const initialGalleryState: GalleryState = {
|
export const initialGalleryState: GalleryState = {
|
||||||
selection: [],
|
selection: [],
|
||||||
|
26
invokeai/frontend/web/src/features/gallery/store/types.ts
Normal file
26
invokeai/frontend/web/src/features/gallery/store/types.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { ImageCategory } from 'services/api/types';
|
||||||
|
|
||||||
|
export const IMAGE_CATEGORIES: ImageCategory[] = ['general'];
|
||||||
|
export const ASSETS_CATEGORIES: ImageCategory[] = [
|
||||||
|
'control',
|
||||||
|
'mask',
|
||||||
|
'user',
|
||||||
|
'other',
|
||||||
|
];
|
||||||
|
export const INITIAL_IMAGE_LIMIT = 100;
|
||||||
|
export const IMAGE_LIMIT = 20;
|
||||||
|
|
||||||
|
export type GalleryView = 'images' | 'assets';
|
||||||
|
// export type BoardId = 'no_board' | (string & Record<never, never>);
|
||||||
|
export type BoardId = string | undefined;
|
||||||
|
|
||||||
|
export type GalleryState = {
|
||||||
|
selection: string[];
|
||||||
|
shouldAutoSwitch: boolean;
|
||||||
|
autoAddBoardId: string | undefined;
|
||||||
|
galleryImageMinimumWidth: number;
|
||||||
|
selectedBoardId: BoardId;
|
||||||
|
galleryView: GalleryView;
|
||||||
|
batchImageNames: string[];
|
||||||
|
isBatchEnabled: boolean;
|
||||||
|
};
|
@ -1,55 +0,0 @@
|
|||||||
import { isEqual } from 'lodash-es';
|
|
||||||
import { ImageCategory, ImageDTO } from 'services/api/types';
|
|
||||||
import { ASSETS_CATEGORIES, BoardId, IMAGE_CATEGORIES } from './gallerySlice';
|
|
||||||
|
|
||||||
export const getCategoriesQueryParamForBoard = (
|
|
||||||
board_id: BoardId
|
|
||||||
): ImageCategory[] | undefined => {
|
|
||||||
if (board_id === 'assets') {
|
|
||||||
return ASSETS_CATEGORIES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (board_id === 'images') {
|
|
||||||
return IMAGE_CATEGORIES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'no_board' board, 'batch' board, user boards
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getBoardIdQueryParamForBoard = (
|
|
||||||
board_id: BoardId
|
|
||||||
): string | null => {
|
|
||||||
if (board_id === undefined) {
|
|
||||||
return 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
// user boards
|
|
||||||
return board_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getBoardIdFromBoardAndCategoriesQueryParam = (
|
|
||||||
board_id: string | undefined,
|
|
||||||
categories: ImageCategory[] | undefined
|
|
||||||
): BoardId => {
|
|
||||||
if (board_id === undefined && isEqual(categories, IMAGE_CATEGORIES)) {
|
|
||||||
return 'images';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (board_id === undefined && isEqual(categories, ASSETS_CATEGORIES)) {
|
|
||||||
return 'assets';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (board_id === 'none') {
|
|
||||||
return 'no_board';
|
|
||||||
}
|
|
||||||
|
|
||||||
return board_id ?? 'UNKNOWN_BOARD';
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getCategories = (imageDTO: ImageDTO) => {
|
|
||||||
if (IMAGE_CATEGORIES.includes(imageDTO.image_category)) {
|
|
||||||
return IMAGE_CATEGORIES;
|
|
||||||
}
|
|
||||||
return ASSETS_CATEGORIES;
|
|
||||||
};
|
|
@ -16,16 +16,16 @@ import IAIButton from 'common/components/IAIButton';
|
|||||||
import IAISwitch from 'common/components/IAISwitch';
|
import IAISwitch from 'common/components/IAISwitch';
|
||||||
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
||||||
|
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
import { ChangeEvent, memo, useCallback, useRef } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import ImageUsageMessage from './ImageUsageMessage';
|
import { imageDeletionConfirmed } from '../store/actions';
|
||||||
import { stateSelector } from 'app/store/store';
|
import { selectImageUsage } from '../store/imageDeletionSelectors';
|
||||||
import {
|
import {
|
||||||
imageDeletionConfirmed,
|
|
||||||
imageToDeleteCleared,
|
imageToDeleteCleared,
|
||||||
isModalOpenChanged,
|
isModalOpenChanged,
|
||||||
selectImageUsage,
|
|
||||||
} from '../store/imageDeletionSlice';
|
} from '../store/imageDeletionSlice';
|
||||||
|
import ImageUsageMessage from './ImageUsageMessage';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[stateSelector, selectImageUsage],
|
[stateSelector, selectImageUsage],
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
||||||
import { some } from 'lodash-es';
|
import { some } from 'lodash-es';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { ImageUsage } from '../store/imageDeletionSlice';
|
import { ImageUsage } from '../store/types';
|
||||||
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
|
||||||
type Props = {
|
type Props = {
|
||||||
imageUsage?: ImageUsage;
|
imageUsage?: ImageUsage;
|
||||||
topMessage?: string;
|
topMessage?: string;
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
import { ImageUsage } from './types';
|
||||||
|
|
||||||
|
export const imageDeletionConfirmed = createAction<{
|
||||||
|
imageDTO: ImageDTO;
|
||||||
|
imageUsage: ImageUsage;
|
||||||
|
}>('imageDeletion/imageDeletionConfirmed');
|
@ -0,0 +1,55 @@
|
|||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
|
import { some } from 'lodash-es';
|
||||||
|
import { ImageUsage } from './types';
|
||||||
|
|
||||||
|
export const getImageUsage = (state: RootState, image_name: string) => {
|
||||||
|
const { generation, canvas, nodes, controlNet } = state;
|
||||||
|
const isInitialImage = generation.initialImage?.imageName === image_name;
|
||||||
|
|
||||||
|
const isCanvasImage = canvas.layerState.objects.some(
|
||||||
|
(obj) => obj.kind === 'image' && obj.imageName === image_name
|
||||||
|
);
|
||||||
|
|
||||||
|
const isNodesImage = nodes.nodes.some((node) => {
|
||||||
|
return some(
|
||||||
|
node.data.inputs,
|
||||||
|
(input) =>
|
||||||
|
input.type === 'image' && input.value?.image_name === image_name
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const isControlNetImage = some(
|
||||||
|
controlNet.controlNets,
|
||||||
|
(c) =>
|
||||||
|
c.controlImage === image_name || c.processedControlImage === image_name
|
||||||
|
);
|
||||||
|
|
||||||
|
const imageUsage: ImageUsage = {
|
||||||
|
isInitialImage,
|
||||||
|
isCanvasImage,
|
||||||
|
isNodesImage,
|
||||||
|
isControlNetImage,
|
||||||
|
};
|
||||||
|
|
||||||
|
return imageUsage;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const selectImageUsage = createSelector(
|
||||||
|
[(state: RootState) => state],
|
||||||
|
(state) => {
|
||||||
|
const { imageToDelete } = state.imageDeletion;
|
||||||
|
|
||||||
|
if (!imageToDelete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { image_name } = imageToDelete;
|
||||||
|
|
||||||
|
const imageUsage = getImageUsage(state, image_name);
|
||||||
|
|
||||||
|
return imageUsage;
|
||||||
|
},
|
||||||
|
defaultSelectorOptions
|
||||||
|
);
|
@ -1,12 +1,4 @@
|
|||||||
import {
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
PayloadAction,
|
|
||||||
createAction,
|
|
||||||
createSelector,
|
|
||||||
createSlice,
|
|
||||||
} from '@reduxjs/toolkit';
|
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
|
||||||
import { some } from 'lodash-es';
|
|
||||||
import { ImageDTO } from 'services/api/types';
|
import { ImageDTO } from 'services/api/types';
|
||||||
|
|
||||||
type DeleteImageState = {
|
type DeleteImageState = {
|
||||||
@ -43,65 +35,3 @@ export const {
|
|||||||
} = imageDeletion.actions;
|
} = imageDeletion.actions;
|
||||||
|
|
||||||
export default imageDeletion.reducer;
|
export default imageDeletion.reducer;
|
||||||
|
|
||||||
export type ImageUsage = {
|
|
||||||
isInitialImage: boolean;
|
|
||||||
isCanvasImage: boolean;
|
|
||||||
isNodesImage: boolean;
|
|
||||||
isControlNetImage: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getImageUsage = (state: RootState, image_name: string) => {
|
|
||||||
const { generation, canvas, nodes, controlNet } = state;
|
|
||||||
const isInitialImage = generation.initialImage?.imageName === image_name;
|
|
||||||
|
|
||||||
const isCanvasImage = canvas.layerState.objects.some(
|
|
||||||
(obj) => obj.kind === 'image' && obj.imageName === image_name
|
|
||||||
);
|
|
||||||
|
|
||||||
const isNodesImage = nodes.nodes.some((node) => {
|
|
||||||
return some(
|
|
||||||
node.data.inputs,
|
|
||||||
(input) =>
|
|
||||||
input.type === 'image' && input.value?.image_name === image_name
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const isControlNetImage = some(
|
|
||||||
controlNet.controlNets,
|
|
||||||
(c) =>
|
|
||||||
c.controlImage === image_name || c.processedControlImage === image_name
|
|
||||||
);
|
|
||||||
|
|
||||||
const imageUsage: ImageUsage = {
|
|
||||||
isInitialImage,
|
|
||||||
isCanvasImage,
|
|
||||||
isNodesImage,
|
|
||||||
isControlNetImage,
|
|
||||||
};
|
|
||||||
|
|
||||||
return imageUsage;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const selectImageUsage = createSelector(
|
|
||||||
[(state: RootState) => state],
|
|
||||||
(state) => {
|
|
||||||
const { imageToDelete } = state.imageDeletion;
|
|
||||||
|
|
||||||
if (!imageToDelete) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { image_name } = imageToDelete;
|
|
||||||
|
|
||||||
const imageUsage = getImageUsage(state, image_name);
|
|
||||||
|
|
||||||
return imageUsage;
|
|
||||||
},
|
|
||||||
defaultSelectorOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
export const imageDeletionConfirmed = createAction<{
|
|
||||||
imageDTO: ImageDTO;
|
|
||||||
imageUsage: ImageUsage;
|
|
||||||
}>('imageDeletion/imageDeletionConfirmed');
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
export type ImageUsage = {
|
||||||
|
isInitialImage: boolean;
|
||||||
|
isCanvasImage: boolean;
|
||||||
|
isNodesImage: boolean;
|
||||||
|
isControlNetImage: boolean;
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react';
|
import { Flex, Text } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppToaster } from 'app/components/Toaster';
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||||
@ -9,7 +10,7 @@ import { forwardRef, useCallback } from 'react';
|
|||||||
import 'reactflow/dist/style.css';
|
import 'reactflow/dist/style.css';
|
||||||
import { AnyInvocationType } from 'services/events/types';
|
import { AnyInvocationType } from 'services/events/types';
|
||||||
import { useBuildInvocation } from '../hooks/useBuildInvocation';
|
import { useBuildInvocation } from '../hooks/useBuildInvocation';
|
||||||
import { nodeAdded, nodesSelector } from '../store/nodesSlice';
|
import { nodeAdded } from '../store/nodesSlice';
|
||||||
|
|
||||||
type NodeTemplate = {
|
type NodeTemplate = {
|
||||||
label: string;
|
label: string;
|
||||||
@ -18,8 +19,8 @@ type NodeTemplate = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
nodesSelector,
|
[stateSelector],
|
||||||
(nodes) => {
|
({ nodes }) => {
|
||||||
const data: NodeTemplate[] = map(nodes.invocationTemplates, (template) => {
|
const data: NodeTemplate[] = map(nodes.invocationTemplates, (template) => {
|
||||||
return {
|
return {
|
||||||
label: template.title,
|
label: template.title,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NODE_MIN_WIDTH } from 'app/constants';
|
import { NODE_MIN_WIDTH } from 'features/nodes/types/constants';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { NodeResizeControl, NodeResizerProps } from 'reactflow';
|
import { NodeResizeControl, NodeResizerProps } from 'reactflow';
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { Box, useToken } from '@chakra-ui/react';
|
import { Box, useToken } from '@chakra-ui/react';
|
||||||
import { NODE_MIN_WIDTH } from 'app/constants';
|
|
||||||
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { PropsWithChildren } from 'react';
|
import { PropsWithChildren } from 'react';
|
||||||
import { DRAG_HANDLE_CLASSNAME } from '../hooks/useBuildInvocation';
|
import { DRAG_HANDLE_CLASSNAME } from '../hooks/useBuildInvocation';
|
||||||
|
import { NODE_MIN_WIDTH } from '../types/constants';
|
||||||
|
|
||||||
type NodeWrapperProps = PropsWithChildren & {
|
type NodeWrapperProps = PropsWithChildren & {
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
useDisclosure,
|
useDisclosure,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FileButton } from '@mantine/core';
|
import { FileButton } from '@mantine/core';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { loadFileEdges, loadFileNodes } from 'features/nodes/store/nodesSlice';
|
import { loadFileEdges, loadFileNodes } from 'features/nodes/store/nodesSlice';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NodesState } from './nodesSlice';
|
import { NodesState } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Nodes slice persist denylist
|
* Nodes slice persist denylist
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import {
|
import {
|
||||||
ControlNetModelParam,
|
ControlNetModelParam,
|
||||||
LoRAModelParam,
|
LoRAModelParam,
|
||||||
@ -7,7 +6,6 @@ import {
|
|||||||
VaeModelParam,
|
VaeModelParam,
|
||||||
} from 'features/parameters/types/parameterSchemas';
|
} from 'features/parameters/types/parameterSchemas';
|
||||||
import { cloneDeep, uniqBy } from 'lodash-es';
|
import { cloneDeep, uniqBy } from 'lodash-es';
|
||||||
import { OpenAPIV3 } from 'openapi-types';
|
|
||||||
import { RgbaColor } from 'react-colorful';
|
import { RgbaColor } from 'react-colorful';
|
||||||
import {
|
import {
|
||||||
addEdge,
|
addEdge,
|
||||||
@ -19,24 +17,11 @@ import {
|
|||||||
Node,
|
Node,
|
||||||
NodeChange,
|
NodeChange,
|
||||||
OnConnectStartParams,
|
OnConnectStartParams,
|
||||||
ReactFlowInstance,
|
|
||||||
} from 'reactflow';
|
} from 'reactflow';
|
||||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||||
import { ImageField } from 'services/api/types';
|
import { ImageField } from 'services/api/types';
|
||||||
import { InvocationTemplate, InvocationValue } from '../types/types';
|
import { InvocationTemplate, InvocationValue } from '../types/types';
|
||||||
|
import { NodesState } from './types';
|
||||||
export type NodesState = {
|
|
||||||
nodes: Node<InvocationValue>[];
|
|
||||||
edges: Edge[];
|
|
||||||
schema: OpenAPIV3.Document | null;
|
|
||||||
invocationTemplates: Record<string, InvocationTemplate>;
|
|
||||||
connectionStartParams: OnConnectStartParams | null;
|
|
||||||
shouldShowGraphOverlay: boolean;
|
|
||||||
shouldShowFieldTypeLegend: boolean;
|
|
||||||
shouldShowMinimapPanel: boolean;
|
|
||||||
editorInstance: ReactFlowInstance | undefined;
|
|
||||||
progressNodeSize: { width: number; height: number };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const initialNodesState: NodesState = {
|
export const initialNodesState: NodesState = {
|
||||||
nodes: [],
|
nodes: [],
|
||||||
@ -194,5 +179,3 @@ export const {
|
|||||||
} = nodesSlice.actions;
|
} = nodesSlice.actions;
|
||||||
|
|
||||||
export default nodesSlice.reducer;
|
export default nodesSlice.reducer;
|
||||||
|
|
||||||
export const nodesSelector = (state: RootState) => state.nodes;
|
|
||||||
|
16
invokeai/frontend/web/src/features/nodes/store/types.ts
Normal file
16
invokeai/frontend/web/src/features/nodes/store/types.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { OpenAPIV3 } from 'openapi-types';
|
||||||
|
import { Edge, Node, OnConnectStartParams, ReactFlowInstance } from 'reactflow';
|
||||||
|
import { InvocationTemplate, InvocationValue } from '../types/types';
|
||||||
|
|
||||||
|
export type NodesState = {
|
||||||
|
nodes: Node<InvocationValue>[];
|
||||||
|
edges: Edge[];
|
||||||
|
schema: OpenAPIV3.Document | null;
|
||||||
|
invocationTemplates: Record<string, InvocationTemplate>;
|
||||||
|
connectionStartParams: OnConnectStartParams | null;
|
||||||
|
shouldShowGraphOverlay: boolean;
|
||||||
|
shouldShowFieldTypeLegend: boolean;
|
||||||
|
shouldShowMinimapPanel: boolean;
|
||||||
|
editorInstance: ReactFlowInstance | undefined;
|
||||||
|
progressNodeSize: { width: number; height: number };
|
||||||
|
};
|
@ -157,3 +157,5 @@ export const FIELDS: Record<FieldType, FieldUIConfig> = {
|
|||||||
description: 'A RGBA color.',
|
description: 'A RGBA color.',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const NODE_MIN_WIDTH = 250;
|
||||||
|
@ -20,7 +20,7 @@ const selector = createSelector(
|
|||||||
export default function ParamAdvancedCollapse() {
|
export default function ParamAdvancedCollapse() {
|
||||||
const { activeLabel } = useAppSelector(selector);
|
const { activeLabel } = useAppSelector(selector);
|
||||||
const shouldShowAdvancedOptions = useAppSelector(
|
const shouldShowAdvancedOptions = useAppSelector(
|
||||||
(state: RootState) => state.ui.shouldShowAdvancedOptions
|
(state: RootState) => state.generation.shouldShowAdvancedOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!shouldShowAdvancedOptions) {
|
if (!shouldShowAdvancedOptions) {
|
||||||
|
@ -2,28 +2,10 @@ import { RootState } from 'app/store/store';
|
|||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { setClipSkip } from 'features/parameters/store/generationSlice';
|
import { setClipSkip } from 'features/parameters/store/generationSlice';
|
||||||
|
import { clipSkipMap } from 'features/parameters/types/constants';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export const clipSkipMap = {
|
|
||||||
'sd-1': {
|
|
||||||
maxClip: 12,
|
|
||||||
markers: [0, 1, 2, 3, 4, 8, 12],
|
|
||||||
},
|
|
||||||
'sd-2': {
|
|
||||||
maxClip: 24,
|
|
||||||
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
|
|
||||||
},
|
|
||||||
sdxl: {
|
|
||||||
maxClip: 24,
|
|
||||||
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
|
|
||||||
},
|
|
||||||
'sdxl-refiner': {
|
|
||||||
maxClip: 24,
|
|
||||||
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function ParamClipSkip() {
|
export default function ParamClipSkip() {
|
||||||
const clipSkip = useAppSelector(
|
const clipSkip = useAppSelector(
|
||||||
(state: RootState) => state.generation.clipSkip
|
(state: RootState) => state.generation.clipSkip
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[canvasSelector, isStagingSelector, uiSelector],
|
[stateSelector, isStagingSelector],
|
||||||
(canvas, isStaging, ui) => {
|
({ canvas, generation }, isStaging) => {
|
||||||
const { boundingBoxDimensions } = canvas;
|
const { boundingBoxDimensions } = canvas;
|
||||||
const { aspectRatio } = ui;
|
const { aspectRatio } = generation;
|
||||||
return {
|
return {
|
||||||
boundingBoxDimensions,
|
boundingBoxDimensions,
|
||||||
isStaging,
|
isStaging,
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
import {
|
import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
|
||||||
canvasSelector,
|
|
||||||
isStagingSelector,
|
|
||||||
} from 'features/canvas/store/canvasSelectors';
|
|
||||||
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[canvasSelector, isStagingSelector, uiSelector],
|
[stateSelector, isStagingSelector],
|
||||||
(canvas, isStaging, ui) => {
|
({ canvas, generation }, isStaging) => {
|
||||||
const { boundingBoxDimensions } = canvas;
|
const { boundingBoxDimensions } = canvas;
|
||||||
const { aspectRatio } = ui;
|
const { aspectRatio } = generation;
|
||||||
return {
|
return {
|
||||||
boundingBoxDimensions,
|
boundingBoxDimensions,
|
||||||
isStaging,
|
isStaging,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Divider, Flex } from '@chakra-ui/react';
|
import { Divider, Flex } from '@chakra-ui/react';
|
||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAICollapse from 'common/components/IAICollapse';
|
import IAICollapse from 'common/components/IAICollapse';
|
||||||
@ -9,7 +10,6 @@ import ParamControlNetFeatureToggle from 'features/controlNet/components/paramet
|
|||||||
import {
|
import {
|
||||||
controlNetAdded,
|
controlNetAdded,
|
||||||
controlNetModelChanged,
|
controlNetModelChanged,
|
||||||
controlNetSelector,
|
|
||||||
} from 'features/controlNet/store/controlNetSlice';
|
} from 'features/controlNet/store/controlNetSlice';
|
||||||
import { getValidControlNets } from 'features/controlNet/util/getValidControlNets';
|
import { getValidControlNets } from 'features/controlNet/util/getValidControlNets';
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
@ -21,8 +21,8 @@ import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
controlNetSelector,
|
[stateSelector],
|
||||||
(controlNet) => {
|
({ controlNet }) => {
|
||||||
const { controlNets, isEnabled } = controlNet;
|
const { controlNets, isEnabled } = controlNet;
|
||||||
|
|
||||||
const validControlNets = getValidControlNets(controlNets);
|
const validControlNets = getValidControlNets(controlNets);
|
||||||
|
@ -2,7 +2,7 @@ import { ButtonGroup, Flex } from '@chakra-ui/react';
|
|||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import { setAspectRatio } from 'features/ui/store/uiSlice';
|
import { setAspectRatio } from 'features/parameters/store/generationSlice';
|
||||||
import { activeTabNameSelector } from '../../../../ui/store/uiSelectors';
|
import { activeTabNameSelector } from '../../../../ui/store/uiSelectors';
|
||||||
|
|
||||||
const aspectRatios = [
|
const aspectRatios = [
|
||||||
@ -14,7 +14,7 @@ const aspectRatios = [
|
|||||||
|
|
||||||
export default function ParamAspectRatio() {
|
export default function ParamAspectRatio() {
|
||||||
const aspectRatio = useAppSelector(
|
const aspectRatio = useAppSelector(
|
||||||
(state: RootState) => state.ui.aspectRatio
|
(state: RootState) => state.generation.aspectRatio
|
||||||
);
|
);
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAINumberInput from 'common/components/IAINumberInput';
|
import IAINumberInput from 'common/components/IAINumberInput';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
|
||||||
import { setCfgScale } from 'features/parameters/store/generationSlice';
|
import { setCfgScale } from 'features/parameters/store/generationSlice';
|
||||||
import { configSelector } from 'features/system/store/configSelectors';
|
|
||||||
import { hotkeysSelector } from 'features/ui/store/hotkeysSlice';
|
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[generationSelector, configSelector, uiSelector, hotkeysSelector],
|
[stateSelector],
|
||||||
(generation, config, ui, hotkeys) => {
|
({ generation, config, ui, hotkeys }) => {
|
||||||
const { initial, min, sliderMax, inputMax } = config.sd.guidance;
|
const { initial, min, sliderMax, inputMax } = config.sd.guidance;
|
||||||
const { cfgScale } = generation;
|
const { cfgScale } = generation;
|
||||||
const { shouldUseSliders } = ui;
|
const { shouldUseSliders } = ui;
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider';
|
import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider';
|
||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
|
||||||
import { setHeight, setWidth } from 'features/parameters/store/generationSlice';
|
import { setHeight, setWidth } from 'features/parameters/store/generationSlice';
|
||||||
import { configSelector } from 'features/system/store/configSelectors';
|
|
||||||
import { hotkeysSelector } from 'features/ui/store/hotkeysSlice';
|
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[generationSelector, hotkeysSelector, configSelector, uiSelector],
|
[stateSelector],
|
||||||
(generation, hotkeys, config, ui) => {
|
({ generation, hotkeys, config }) => {
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
||||||
config.sd.height;
|
config.sd.height;
|
||||||
const { height } = generation;
|
const { height } = generation;
|
||||||
const { aspectRatio } = ui;
|
const { aspectRatio } = generation;
|
||||||
|
|
||||||
const step = hotkeys.shift ? fineStep : coarseStep;
|
const step = hotkeys.shift ? fineStep : coarseStep;
|
||||||
|
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { SCHEDULER_LABEL_MAP, SCHEDULER_NAMES } from 'app/constants';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
||||||
import { setScheduler } from 'features/parameters/store/generationSlice';
|
import { setScheduler } from 'features/parameters/store/generationSlice';
|
||||||
import { SchedulerParam } from 'features/parameters/types/parameterSchemas';
|
import {
|
||||||
|
SCHEDULER_LABEL_MAP,
|
||||||
|
SchedulerParam,
|
||||||
|
} from 'features/parameters/types/parameterSchemas';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||||
|
import { map } from 'lodash-es';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@ -16,10 +19,10 @@ const selector = createSelector(
|
|||||||
const { scheduler } = generation;
|
const { scheduler } = generation;
|
||||||
const { favoriteSchedulers: enabledSchedulers } = ui;
|
const { favoriteSchedulers: enabledSchedulers } = ui;
|
||||||
|
|
||||||
const data = SCHEDULER_NAMES.map((schedulerName) => ({
|
const data = map(SCHEDULER_LABEL_MAP, (label, name) => ({
|
||||||
value: schedulerName,
|
value: name,
|
||||||
label: SCHEDULER_LABEL_MAP[schedulerName as SchedulerParam],
|
label: label,
|
||||||
group: enabledSchedulers.includes(schedulerName)
|
group: enabledSchedulers.includes(name as SchedulerParam)
|
||||||
? 'Favorites'
|
? 'Favorites'
|
||||||
: undefined,
|
: undefined,
|
||||||
})).sort((a, b) => a.label.localeCompare(b.label));
|
})).sort((a, b) => a.label.localeCompare(b.label));
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAINumberInput from 'common/components/IAINumberInput';
|
import IAINumberInput from 'common/components/IAINumberInput';
|
||||||
|
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
|
||||||
import {
|
import {
|
||||||
clampSymmetrySteps,
|
clampSymmetrySteps,
|
||||||
setSteps,
|
setSteps,
|
||||||
} from 'features/parameters/store/generationSlice';
|
} from 'features/parameters/store/generationSlice';
|
||||||
import { configSelector } from 'features/system/store/configSelectors';
|
|
||||||
import { hotkeysSelector } from 'features/ui/store/hotkeysSlice';
|
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[generationSelector, configSelector, uiSelector, hotkeysSelector],
|
[stateSelector],
|
||||||
(generation, config, ui, hotkeys) => {
|
({ generation, config, ui, hotkeys }) => {
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
||||||
config.sd.steps;
|
config.sd.steps;
|
||||||
const { steps } = generation;
|
const { steps } = generation;
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider';
|
import IAISlider, { IAIFullSliderProps } from 'common/components/IAISlider';
|
||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
|
||||||
import { setHeight, setWidth } from 'features/parameters/store/generationSlice';
|
import { setHeight, setWidth } from 'features/parameters/store/generationSlice';
|
||||||
import { configSelector } from 'features/system/store/configSelectors';
|
|
||||||
import { hotkeysSelector } from 'features/ui/store/hotkeysSlice';
|
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[generationSelector, hotkeysSelector, configSelector, uiSelector],
|
[stateSelector],
|
||||||
(generation, hotkeys, config, ui) => {
|
({ generation, hotkeys, config, ui }) => {
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
||||||
config.sd.width;
|
config.sd.width;
|
||||||
const { width } = generation;
|
const { width, aspectRatio } = generation;
|
||||||
const { aspectRatio } = ui;
|
|
||||||
|
|
||||||
const step = hotkeys.shift ? fineStep : coarseStep;
|
const step = hotkeys.shift ? fineStep : coarseStep;
|
||||||
|
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||||
import IAISlider from 'common/components/IAISlider';
|
import IAISlider from 'common/components/IAISlider';
|
||||||
import { generationSelector } from 'features/parameters/store/generationSelectors';
|
|
||||||
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
|
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
|
||||||
import { configSelector } from 'features/system/store/configSelectors';
|
|
||||||
import { hotkeysSelector } from 'features/ui/store/hotkeysSlice';
|
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[generationSelector, hotkeysSelector, configSelector],
|
[stateSelector],
|
||||||
(generation, hotkeys, config) => {
|
({ generation, hotkeys, config }) => {
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
||||||
config.sd.img2imgStrength;
|
config.sd.img2imgStrength;
|
||||||
const { img2imgStrength } = generation;
|
const { img2imgStrength } = generation;
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import { DEFAULT_SCHEDULER_NAME } from 'app/constants';
|
|
||||||
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
import { roundToMultiple } from 'common/util/roundDownToMultiple';
|
||||||
import { configChanged } from 'features/system/store/configSlice';
|
import { configChanged } from 'features/system/store/configSlice';
|
||||||
import {
|
|
||||||
setAspectRatio,
|
|
||||||
setShouldShowAdvancedOptions,
|
|
||||||
} from 'features/ui/store/uiSlice';
|
|
||||||
import { clamp } from 'lodash-es';
|
import { clamp } from 'lodash-es';
|
||||||
import { ImageDTO, MainModelField } from 'services/api/types';
|
import { ImageDTO, MainModelField } from 'services/api/types';
|
||||||
import { clipSkipMap } from '../components/Parameters/Advanced/ParamClipSkip';
|
import { clipSkipMap } from '../types/constants';
|
||||||
import {
|
import {
|
||||||
CfgScaleParam,
|
CfgScaleParam,
|
||||||
HeightParam,
|
HeightParam,
|
||||||
@ -60,6 +55,8 @@ export interface GenerationState {
|
|||||||
seamlessYAxis: boolean;
|
seamlessYAxis: boolean;
|
||||||
clipSkip: number;
|
clipSkip: number;
|
||||||
shouldUseCpuNoise: boolean;
|
shouldUseCpuNoise: boolean;
|
||||||
|
shouldShowAdvancedOptions: boolean;
|
||||||
|
aspectRatio: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialGenerationState: GenerationState = {
|
export const initialGenerationState: GenerationState = {
|
||||||
@ -71,7 +68,7 @@ export const initialGenerationState: GenerationState = {
|
|||||||
perlin: 0,
|
perlin: 0,
|
||||||
positivePrompt: '',
|
positivePrompt: '',
|
||||||
negativePrompt: '',
|
negativePrompt: '',
|
||||||
scheduler: DEFAULT_SCHEDULER_NAME,
|
scheduler: 'euler',
|
||||||
seamBlur: 16,
|
seamBlur: 16,
|
||||||
seamSize: 96,
|
seamSize: 96,
|
||||||
seamSteps: 30,
|
seamSteps: 30,
|
||||||
@ -96,6 +93,8 @@ export const initialGenerationState: GenerationState = {
|
|||||||
seamlessYAxis: false,
|
seamlessYAxis: false,
|
||||||
clipSkip: 0,
|
clipSkip: 0,
|
||||||
shouldUseCpuNoise: true,
|
shouldUseCpuNoise: true,
|
||||||
|
shouldShowAdvancedOptions: false,
|
||||||
|
aspectRatio: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: GenerationState = initialGenerationState;
|
const initialState: GenerationState = initialGenerationState;
|
||||||
@ -248,6 +247,19 @@ export const generationSlice = createSlice({
|
|||||||
shouldUseCpuNoiseChanged: (state, action: PayloadAction<boolean>) => {
|
shouldUseCpuNoiseChanged: (state, action: PayloadAction<boolean>) => {
|
||||||
state.shouldUseCpuNoise = action.payload;
|
state.shouldUseCpuNoise = action.payload;
|
||||||
},
|
},
|
||||||
|
setShouldShowAdvancedOptions: (state, action: PayloadAction<boolean>) => {
|
||||||
|
state.shouldShowAdvancedOptions = action.payload;
|
||||||
|
if (!action.payload) {
|
||||||
|
state.clipSkip = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setAspectRatio: (state, action: PayloadAction<number | null>) => {
|
||||||
|
const newAspectRatio = action.payload;
|
||||||
|
state.aspectRatio = newAspectRatio;
|
||||||
|
if (newAspectRatio) {
|
||||||
|
state.height = roundToMultiple(state.width / newAspectRatio, 8);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(configChanged, (state, action) => {
|
builder.addCase(configChanged, (state, action) => {
|
||||||
@ -270,12 +282,6 @@ export const generationSlice = createSlice({
|
|||||||
const advancedOptionsStatus = action.payload;
|
const advancedOptionsStatus = action.payload;
|
||||||
if (!advancedOptionsStatus) state.clipSkip = 0;
|
if (!advancedOptionsStatus) state.clipSkip = 0;
|
||||||
});
|
});
|
||||||
builder.addCase(setAspectRatio, (state, action) => {
|
|
||||||
const ratio = action.payload;
|
|
||||||
if (ratio) {
|
|
||||||
state.height = roundToMultiple(state.width / ratio, 8);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -319,6 +325,8 @@ export const {
|
|||||||
setSeamlessYAxis,
|
setSeamlessYAxis,
|
||||||
setClipSkip,
|
setClipSkip,
|
||||||
shouldUseCpuNoiseChanged,
|
shouldUseCpuNoiseChanged,
|
||||||
|
setShouldShowAdvancedOptions,
|
||||||
|
setAspectRatio,
|
||||||
} = generationSlice.actions;
|
} = generationSlice.actions;
|
||||||
|
|
||||||
export default generationSlice.reducer;
|
export default generationSlice.reducer;
|
||||||
|
@ -4,3 +4,22 @@ export const MODEL_TYPE_MAP = {
|
|||||||
sdxl: 'Stable Diffusion XL',
|
sdxl: 'Stable Diffusion XL',
|
||||||
'sdxl-refiner': 'Stable Diffusion XL Refiner',
|
'sdxl-refiner': 'Stable Diffusion XL Refiner',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const clipSkipMap = {
|
||||||
|
'sd-1': {
|
||||||
|
maxClip: 12,
|
||||||
|
markers: [0, 1, 2, 3, 4, 8, 12],
|
||||||
|
},
|
||||||
|
'sd-2': {
|
||||||
|
maxClip: 24,
|
||||||
|
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
|
||||||
|
},
|
||||||
|
sdxl: {
|
||||||
|
maxClip: 24,
|
||||||
|
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
|
||||||
|
},
|
||||||
|
'sdxl-refiner': {
|
||||||
|
maxClip: 24,
|
||||||
|
markers: [0, 1, 2, 3, 5, 10, 15, 20, 24],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { NUMPY_RAND_MAX, SCHEDULER_NAMES_AS_CONST } from 'app/constants';
|
import { NUMPY_RAND_MAX } from 'app/constants';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,7 +73,30 @@ export const isValidCfgScale = (val: unknown): val is CfgScaleParam =>
|
|||||||
/**
|
/**
|
||||||
* Zod schema for scheduler parameter
|
* Zod schema for scheduler parameter
|
||||||
*/
|
*/
|
||||||
export const zScheduler = z.enum(SCHEDULER_NAMES_AS_CONST);
|
export const zScheduler = z.enum([
|
||||||
|
'euler',
|
||||||
|
'deis',
|
||||||
|
'ddim',
|
||||||
|
'ddpm',
|
||||||
|
'dpmpp_2s',
|
||||||
|
'dpmpp_2m',
|
||||||
|
'dpmpp_2m_sde',
|
||||||
|
'dpmpp_sde',
|
||||||
|
'heun',
|
||||||
|
'kdpm_2',
|
||||||
|
'lms',
|
||||||
|
'pndm',
|
||||||
|
'unipc',
|
||||||
|
'euler_k',
|
||||||
|
'dpmpp_2s_k',
|
||||||
|
'dpmpp_2m_k',
|
||||||
|
'dpmpp_2m_sde_k',
|
||||||
|
'dpmpp_sde_k',
|
||||||
|
'heun_k',
|
||||||
|
'lms_k',
|
||||||
|
'euler_a',
|
||||||
|
'kdpm_2_a',
|
||||||
|
]);
|
||||||
/**
|
/**
|
||||||
* Type alias for scheduler parameter, inferred from its zod schema
|
* Type alias for scheduler parameter, inferred from its zod schema
|
||||||
*/
|
*/
|
||||||
@ -84,6 +107,31 @@ export type SchedulerParam = z.infer<typeof zScheduler>;
|
|||||||
export const isValidScheduler = (val: unknown): val is SchedulerParam =>
|
export const isValidScheduler = (val: unknown): val is SchedulerParam =>
|
||||||
zScheduler.safeParse(val).success;
|
zScheduler.safeParse(val).success;
|
||||||
|
|
||||||
|
export const SCHEDULER_LABEL_MAP: Record<SchedulerParam, string> = {
|
||||||
|
euler: 'Euler',
|
||||||
|
deis: 'DEIS',
|
||||||
|
ddim: 'DDIM',
|
||||||
|
ddpm: 'DDPM',
|
||||||
|
dpmpp_sde: 'DPM++ SDE',
|
||||||
|
dpmpp_2s: 'DPM++ 2S',
|
||||||
|
dpmpp_2m: 'DPM++ 2M',
|
||||||
|
dpmpp_2m_sde: 'DPM++ 2M SDE',
|
||||||
|
heun: 'Heun',
|
||||||
|
kdpm_2: 'KDPM 2',
|
||||||
|
lms: 'LMS',
|
||||||
|
pndm: 'PNDM',
|
||||||
|
unipc: 'UniPC',
|
||||||
|
euler_k: 'Euler Karras',
|
||||||
|
dpmpp_sde_k: 'DPM++ SDE Karras',
|
||||||
|
dpmpp_2s_k: 'DPM++ 2S Karras',
|
||||||
|
dpmpp_2m_k: 'DPM++ 2M Karras',
|
||||||
|
dpmpp_2m_sde_k: 'DPM++ 2M SDE Karras',
|
||||||
|
heun_k: 'Heun Karras',
|
||||||
|
lms_k: 'LMS Karras',
|
||||||
|
euler_a: 'Euler Ancestral',
|
||||||
|
kdpm_2_a: 'KDPM 2 Ancestral',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zod schema for seed parameter
|
* Zod schema for seed parameter
|
||||||
*/
|
*/
|
||||||
|
@ -7,32 +7,13 @@ import {
|
|||||||
MenuOptionGroup,
|
MenuOptionGroup,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import i18n from 'i18n';
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import { map } from 'lodash-es';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { IoLanguage } from 'react-icons/io5';
|
||||||
|
import { LANGUAGES } from '../store/constants';
|
||||||
import { languageSelector } from '../store/systemSelectors';
|
import { languageSelector } from '../store/systemSelectors';
|
||||||
import { languageChanged } from '../store/systemSlice';
|
import { languageChanged } from '../store/systemSlice';
|
||||||
import { map } from 'lodash-es';
|
|
||||||
import { IoLanguage } from 'react-icons/io5';
|
|
||||||
|
|
||||||
export const LANGUAGES = {
|
|
||||||
ar: i18n.t('common.langArabic', { lng: 'ar' }),
|
|
||||||
nl: i18n.t('common.langDutch', { lng: 'nl' }),
|
|
||||||
en: i18n.t('common.langEnglish', { lng: 'en' }),
|
|
||||||
fr: i18n.t('common.langFrench', { lng: 'fr' }),
|
|
||||||
de: i18n.t('common.langGerman', { lng: 'de' }),
|
|
||||||
he: i18n.t('common.langHebrew', { lng: 'he' }),
|
|
||||||
it: i18n.t('common.langItalian', { lng: 'it' }),
|
|
||||||
ja: i18n.t('common.langJapanese', { lng: 'ja' }),
|
|
||||||
ko: i18n.t('common.langKorean', { lng: 'ko' }),
|
|
||||||
pl: i18n.t('common.langPolish', { lng: 'pl' }),
|
|
||||||
pt_BR: i18n.t('common.langBrPortuguese', { lng: 'pt_BR' }),
|
|
||||||
pt: i18n.t('common.langPortuguese', { lng: 'pt' }),
|
|
||||||
ru: i18n.t('common.langRussian', { lng: 'ru' }),
|
|
||||||
zh_CN: i18n.t('common.langSimplifiedChinese', { lng: 'zh_CN' }),
|
|
||||||
es: i18n.t('common.langSpanish', { lng: 'es' }),
|
|
||||||
uk: i18n.t('common.langUkranian', { lng: 'ua' }),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function LanguagePicker() {
|
export default function LanguagePicker() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Heading, Text } from '@chakra-ui/react';
|
import { Heading, Text } from '@chakra-ui/react';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import IAIButton from '../../../../common/components/IAIButton';
|
import IAIButton from '../../../../common/components/IAIButton';
|
||||||
import {
|
import {
|
||||||
@ -8,8 +9,7 @@ import {
|
|||||||
} from '../../../../services/api/endpoints/images';
|
} from '../../../../services/api/endpoints/images';
|
||||||
import { resetCanvas } from '../../../canvas/store/canvasSlice';
|
import { resetCanvas } from '../../../canvas/store/canvasSlice';
|
||||||
import { addToast } from '../../store/systemSlice';
|
import { addToast } from '../../store/systemSlice';
|
||||||
import { StyledFlex } from './SettingsModal';
|
import StyledFlex from './StyledFlex';
|
||||||
import { controlNetReset } from 'features/controlNet/store/controlNetSlice';
|
|
||||||
|
|
||||||
export default function SettingsClearIntermediates() {
|
export default function SettingsClearIntermediates() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -14,12 +14,12 @@ import {
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { VALID_LOG_LEVELS } from 'app/logging/logger';
|
import { VALID_LOG_LEVELS } from 'app/logging/logger';
|
||||||
import { LOCALSTORAGE_KEYS, LOCALSTORAGE_PREFIX } from 'app/store/constants';
|
import { LOCALSTORAGE_KEYS, LOCALSTORAGE_PREFIX } from 'app/store/constants';
|
||||||
|
import { stateSelector } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
import IAIMantineSelect from 'common/components/IAIMantineSelect';
|
||||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
import { setShouldShowAdvancedOptions } from 'features/parameters/store/generationSlice';
|
||||||
import {
|
import {
|
||||||
SystemState,
|
|
||||||
consoleLogLevelChanged,
|
consoleLogLevelChanged,
|
||||||
setEnableImageDebugging,
|
setEnableImageDebugging,
|
||||||
setIsNodesEnabled,
|
setIsNodesEnabled,
|
||||||
@ -27,18 +27,14 @@ import {
|
|||||||
shouldAntialiasProgressImageChanged,
|
shouldAntialiasProgressImageChanged,
|
||||||
shouldLogToConsoleChanged,
|
shouldLogToConsoleChanged,
|
||||||
} from 'features/system/store/systemSlice';
|
} from 'features/system/store/systemSlice';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import {
|
import {
|
||||||
setShouldShowAdvancedOptions,
|
|
||||||
setShouldShowProgressInViewer,
|
setShouldShowProgressInViewer,
|
||||||
setShouldUseCanvasBetaLayout,
|
setShouldUseCanvasBetaLayout,
|
||||||
setShouldUseSliders,
|
setShouldUseSliders,
|
||||||
} from 'features/ui/store/uiSlice';
|
} from 'features/ui/store/uiSlice';
|
||||||
import { UIState } from 'features/ui/store/uiTypes';
|
|
||||||
import { isEqual } from 'lodash-es';
|
import { isEqual } from 'lodash-es';
|
||||||
import {
|
import {
|
||||||
ChangeEvent,
|
ChangeEvent,
|
||||||
PropsWithChildren,
|
|
||||||
ReactElement,
|
ReactElement,
|
||||||
cloneElement,
|
cloneElement,
|
||||||
useCallback,
|
useCallback,
|
||||||
@ -49,10 +45,11 @@ import { LogLevelName } from 'roarr';
|
|||||||
import SettingSwitch from './SettingSwitch';
|
import SettingSwitch from './SettingSwitch';
|
||||||
import SettingsClearIntermediates from './SettingsClearIntermediates';
|
import SettingsClearIntermediates from './SettingsClearIntermediates';
|
||||||
import SettingsSchedulers from './SettingsSchedulers';
|
import SettingsSchedulers from './SettingsSchedulers';
|
||||||
|
import StyledFlex from './StyledFlex';
|
||||||
|
|
||||||
const selector = createSelector(
|
const selector = createSelector(
|
||||||
[systemSelector, uiSelector],
|
[stateSelector],
|
||||||
(system: SystemState, ui: UIState) => {
|
({ system, ui, generation }) => {
|
||||||
const {
|
const {
|
||||||
shouldConfirmOnDelete,
|
shouldConfirmOnDelete,
|
||||||
enableImageDebugging,
|
enableImageDebugging,
|
||||||
@ -66,9 +63,10 @@ const selector = createSelector(
|
|||||||
shouldUseCanvasBetaLayout,
|
shouldUseCanvasBetaLayout,
|
||||||
shouldUseSliders,
|
shouldUseSliders,
|
||||||
shouldShowProgressInViewer,
|
shouldShowProgressInViewer,
|
||||||
shouldShowAdvancedOptions,
|
|
||||||
} = ui;
|
} = ui;
|
||||||
|
|
||||||
|
const { shouldShowAdvancedOptions } = generation;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
shouldConfirmOnDelete,
|
shouldConfirmOnDelete,
|
||||||
enableImageDebugging,
|
enableImageDebugging,
|
||||||
@ -349,22 +347,3 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default SettingsModal;
|
export default SettingsModal;
|
||||||
|
|
||||||
export const StyledFlex = (props: PropsWithChildren) => {
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: 2,
|
|
||||||
p: 4,
|
|
||||||
borderRadius: 'base',
|
|
||||||
bg: 'base.100',
|
|
||||||
_dark: {
|
|
||||||
bg: 'base.900',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import { SCHEDULER_LABEL_MAP, SCHEDULER_NAMES } from 'app/constants';
|
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIMantineMultiSelect from 'common/components/IAIMantineMultiSelect';
|
import IAIMantineMultiSelect from 'common/components/IAIMantineMultiSelect';
|
||||||
import { SchedulerParam } from 'features/parameters/types/parameterSchemas';
|
import {
|
||||||
|
SCHEDULER_LABEL_MAP,
|
||||||
|
SchedulerParam,
|
||||||
|
} from 'features/parameters/types/parameterSchemas';
|
||||||
import { favoriteSchedulersChanged } from 'features/ui/store/uiSlice';
|
import { favoriteSchedulersChanged } from 'features/ui/store/uiSlice';
|
||||||
import { map } from 'lodash-es';
|
import { map } from 'lodash-es';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const data = map(SCHEDULER_NAMES, (s) => ({
|
const data = map(SCHEDULER_LABEL_MAP, (value, label) => ({
|
||||||
value: s,
|
value,
|
||||||
label: SCHEDULER_LABEL_MAP[s],
|
label,
|
||||||
})).sort((a, b) => a.label.localeCompare(b.label));
|
})).sort((a, b) => a.label.localeCompare(b.label));
|
||||||
|
|
||||||
export default function SettingsSchedulers() {
|
export default function SettingsSchedulers() {
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
|
const StyledFlex = (props: PropsWithChildren) => {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: 2,
|
||||||
|
p: 4,
|
||||||
|
borderRadius: 'base',
|
||||||
|
bg: 'base.100',
|
||||||
|
_dark: {
|
||||||
|
bg: 'base.900',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StyledFlex;
|
20
invokeai/frontend/web/src/features/system/store/constants.ts
Normal file
20
invokeai/frontend/web/src/features/system/store/constants.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import i18n from 'i18n';
|
||||||
|
|
||||||
|
export const LANGUAGES = {
|
||||||
|
ar: i18n.t('common.langArabic', { lng: 'ar' }),
|
||||||
|
nl: i18n.t('common.langDutch', { lng: 'nl' }),
|
||||||
|
en: i18n.t('common.langEnglish', { lng: 'en' }),
|
||||||
|
fr: i18n.t('common.langFrench', { lng: 'fr' }),
|
||||||
|
de: i18n.t('common.langGerman', { lng: 'de' }),
|
||||||
|
he: i18n.t('common.langHebrew', { lng: 'he' }),
|
||||||
|
it: i18n.t('common.langItalian', { lng: 'it' }),
|
||||||
|
ja: i18n.t('common.langJapanese', { lng: 'ja' }),
|
||||||
|
ko: i18n.t('common.langKorean', { lng: 'ko' }),
|
||||||
|
pl: i18n.t('common.langPolish', { lng: 'pl' }),
|
||||||
|
pt_BR: i18n.t('common.langBrPortuguese', { lng: 'pt_BR' }),
|
||||||
|
pt: i18n.t('common.langPortuguese', { lng: 'pt' }),
|
||||||
|
ru: i18n.t('common.langRussian', { lng: 'ru' }),
|
||||||
|
zh_CN: i18n.t('common.langSimplifiedChinese', { lng: 'zh_CN' }),
|
||||||
|
es: i18n.t('common.langSpanish', { lng: 'es' }),
|
||||||
|
uk: i18n.t('common.langUkranian', { lng: 'ua' }),
|
||||||
|
};
|
@ -1,6 +1,5 @@
|
|||||||
import { UseToastOptions } from '@chakra-ui/react';
|
import { UseToastOptions } from '@chakra-ui/react';
|
||||||
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import { InvokeLogLevel } from 'app/logging/logger';
|
import { InvokeLogLevel } from 'app/logging/logger';
|
||||||
import { userInvoked } from 'app/store/actions';
|
import { userInvoked } from 'app/store/actions';
|
||||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
||||||
@ -22,8 +21,8 @@ import {
|
|||||||
appSocketUnsubscribed,
|
appSocketUnsubscribed,
|
||||||
} from 'services/events/actions';
|
} from 'services/events/actions';
|
||||||
import { ProgressImage } from 'services/events/types';
|
import { ProgressImage } from 'services/events/types';
|
||||||
import { makeToast } from '../../../app/components/Toaster';
|
import { makeToast } from '../util/makeToast';
|
||||||
import { LANGUAGES } from '../components/LanguagePicker';
|
import { LANGUAGES } from './constants';
|
||||||
|
|
||||||
export type CancelStrategy = 'immediate' | 'scheduled';
|
export type CancelStrategy = 'immediate' | 'scheduled';
|
||||||
|
|
||||||
|
20
invokeai/frontend/web/src/features/system/util/makeToast.ts
Normal file
20
invokeai/frontend/web/src/features/system/util/makeToast.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { UseToastOptions } from '@chakra-ui/react';
|
||||||
|
|
||||||
|
export type MakeToastArg = string | UseToastOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a toast from a string or a UseToastOptions object.
|
||||||
|
* If a string is passed, the toast will have the status 'info' and will be closable with a duration of 2500ms.
|
||||||
|
*/
|
||||||
|
export const makeToast = (arg: MakeToastArg): UseToastOptions => {
|
||||||
|
if (typeof arg === 'string') {
|
||||||
|
return {
|
||||||
|
title: arg,
|
||||||
|
status: 'info',
|
||||||
|
isClosable: true,
|
||||||
|
duration: 2500,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { status: 'info', isClosable: true, duration: 2500, ...arg };
|
||||||
|
};
|
@ -1,6 +1,6 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react';
|
import { Flex, Text } from '@chakra-ui/react';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
|
|
||||||
import { SelectItem } from '@mantine/core';
|
import { SelectItem } from '@mantine/core';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { RootState } from 'app/store/store';
|
import { RootState } from 'app/store/store';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Flex, Radio, RadioGroup, Text, Tooltip } from '@chakra-ui/react';
|
import { Flex, Radio, RadioGroup, Text, Tooltip } from '@chakra-ui/react';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIInput from 'common/components/IAIInput';
|
import IAIInput from 'common/components/IAIInput';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Badge, Divider, Flex, Text } from '@chakra-ui/react';
|
import { Badge, Divider, Flex, Text } from '@chakra-ui/react';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Divider, Flex, Text } from '@chakra-ui/react';
|
import { Divider, Flex, Text } from '@chakra-ui/react';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
import IAIMantineTextInput from 'common/components/IAIMantineInput';
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
UnorderedList,
|
UnorderedList,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
// import { convertToDiffusers } from 'app/socketio/actions';
|
// import { convertToDiffusers } from 'app/socketio/actions';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { DeleteIcon } from '@chakra-ui/icons';
|
import { DeleteIcon } from '@chakra-ui/icons';
|
||||||
import { Badge, Flex, Text, Tooltip } from '@chakra-ui/react';
|
import { Badge, Flex, Text, Tooltip } from '@chakra-ui/react';
|
||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { makeToast } from 'app/components/Toaster';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
|
|
||||||
type HotkeysState = {
|
type HotkeysState = {
|
||||||
shift: boolean;
|
shift: boolean;
|
||||||
@ -23,5 +22,3 @@ export const hotkeysSlice = createSlice({
|
|||||||
export const { shiftKeyPressed } = hotkeysSlice.actions;
|
export const { shiftKeyPressed } = hotkeysSlice.actions;
|
||||||
|
|
||||||
export default hotkeysSlice.reducer;
|
export default hotkeysSlice.reducer;
|
||||||
|
|
||||||
export const hotkeysSelector = (state: RootState) => state.hotkeys;
|
|
||||||
|
@ -19,8 +19,6 @@ export const initialUIState: UIState = {
|
|||||||
shouldHidePreview: false,
|
shouldHidePreview: false,
|
||||||
shouldShowProgressInViewer: true,
|
shouldShowProgressInViewer: true,
|
||||||
shouldShowEmbeddingPicker: false,
|
shouldShowEmbeddingPicker: false,
|
||||||
shouldShowAdvancedOptions: false,
|
|
||||||
aspectRatio: null,
|
|
||||||
favoriteSchedulers: [],
|
favoriteSchedulers: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,12 +96,6 @@ export const uiSlice = createSlice({
|
|||||||
toggleEmbeddingPicker: (state) => {
|
toggleEmbeddingPicker: (state) => {
|
||||||
state.shouldShowEmbeddingPicker = !state.shouldShowEmbeddingPicker;
|
state.shouldShowEmbeddingPicker = !state.shouldShowEmbeddingPicker;
|
||||||
},
|
},
|
||||||
setShouldShowAdvancedOptions: (state, action: PayloadAction<boolean>) => {
|
|
||||||
state.shouldShowAdvancedOptions = action.payload;
|
|
||||||
},
|
|
||||||
setAspectRatio: (state, action: PayloadAction<number | null>) => {
|
|
||||||
state.aspectRatio = action.payload;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
extraReducers(builder) {
|
extraReducers(builder) {
|
||||||
builder.addCase(initialImageChanged, (state) => {
|
builder.addCase(initialImageChanged, (state) => {
|
||||||
@ -130,8 +122,6 @@ export const {
|
|||||||
setShouldShowProgressInViewer,
|
setShouldShowProgressInViewer,
|
||||||
favoriteSchedulersChanged,
|
favoriteSchedulersChanged,
|
||||||
toggleEmbeddingPicker,
|
toggleEmbeddingPicker,
|
||||||
setShouldShowAdvancedOptions,
|
|
||||||
setAspectRatio,
|
|
||||||
} = uiSlice.actions;
|
} = uiSlice.actions;
|
||||||
|
|
||||||
export default uiSlice.reducer;
|
export default uiSlice.reducer;
|
||||||
|
@ -25,7 +25,5 @@ export interface UIState {
|
|||||||
shouldShowGallery: boolean;
|
shouldShowGallery: boolean;
|
||||||
shouldShowProgressInViewer: boolean;
|
shouldShowProgressInViewer: boolean;
|
||||||
shouldShowEmbeddingPicker: boolean;
|
shouldShowEmbeddingPicker: boolean;
|
||||||
shouldShowAdvancedOptions: boolean;
|
|
||||||
aspectRatio: number | null;
|
|
||||||
favoriteSchedulers: SchedulerParam[];
|
favoriteSchedulers: SchedulerParam[];
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,7 @@ import { Update } from '@reduxjs/toolkit';
|
|||||||
import {
|
import {
|
||||||
ASSETS_CATEGORIES,
|
ASSETS_CATEGORIES,
|
||||||
IMAGE_CATEGORIES,
|
IMAGE_CATEGORIES,
|
||||||
boardIdSelected,
|
} from 'features/gallery/store/types';
|
||||||
} from 'features/gallery/store/gallerySlice';
|
|
||||||
import {
|
import {
|
||||||
BoardDTO,
|
BoardDTO,
|
||||||
ImageDTO,
|
ImageDTO,
|
||||||
|
@ -5,8 +5,7 @@ import {
|
|||||||
ASSETS_CATEGORIES,
|
ASSETS_CATEGORIES,
|
||||||
BoardId,
|
BoardId,
|
||||||
IMAGE_CATEGORIES,
|
IMAGE_CATEGORIES,
|
||||||
} from 'features/gallery/store/gallerySlice';
|
} from 'features/gallery/store/types';
|
||||||
import { getCategories } from 'features/gallery/store/util';
|
|
||||||
import queryString from 'query-string';
|
import queryString from 'query-string';
|
||||||
import { ApiFullTagDescription, api } from '..';
|
import { ApiFullTagDescription, api } from '..';
|
||||||
import { components, paths } from '../schema';
|
import { components, paths } from '../schema';
|
||||||
@ -16,7 +15,37 @@ import {
|
|||||||
OffsetPaginatedResults_ImageDTO_,
|
OffsetPaginatedResults_ImageDTO_,
|
||||||
PostUploadAction,
|
PostUploadAction,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { getIsImageInDateRange } from './util';
|
|
||||||
|
const getIsImageInDateRange = (
|
||||||
|
data: ImageCache | undefined,
|
||||||
|
imageDTO: ImageDTO
|
||||||
|
) => {
|
||||||
|
if (!data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const cacheImageDTOS = imagesSelectors.selectAll(data);
|
||||||
|
|
||||||
|
if (cacheImageDTOS.length > 1) {
|
||||||
|
// Images are sorted by `created_at` DESC
|
||||||
|
// check if the image is newer than the oldest image in the cache
|
||||||
|
const createdDate = new Date(imageDTO.created_at);
|
||||||
|
const oldestDate = new Date(
|
||||||
|
cacheImageDTOS[cacheImageDTOS.length - 1].created_at
|
||||||
|
);
|
||||||
|
return createdDate >= oldestDate;
|
||||||
|
} else if ([0, 1].includes(cacheImageDTOS.length)) {
|
||||||
|
// if there are only 1 or 0 images in the cache, we consider the image to be in the date range
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCategories = (imageDTO: ImageDTO) => {
|
||||||
|
if (IMAGE_CATEGORIES.includes(imageDTO.image_category)) {
|
||||||
|
return IMAGE_CATEGORIES;
|
||||||
|
}
|
||||||
|
return ASSETS_CATEGORIES;
|
||||||
|
};
|
||||||
|
|
||||||
export type ListImagesArgs = NonNullable<
|
export type ListImagesArgs = NonNullable<
|
||||||
paths['/api/v1/images/']['get']['parameters']['query']
|
paths['/api/v1/images/']['get']['parameters']['query']
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
import { ImageDTO } from '../types';
|
|
||||||
import { ImageCache, imagesSelectors } from './images';
|
|
||||||
|
|
||||||
export const getIsImageInDateRange = (
|
|
||||||
data: ImageCache | undefined,
|
|
||||||
imageDTO: ImageDTO
|
|
||||||
) => {
|
|
||||||
if (!data) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const cacheImageDTOS = imagesSelectors.selectAll(data);
|
|
||||||
|
|
||||||
if (cacheImageDTOS.length > 1) {
|
|
||||||
// Images are sorted by `created_at` DESC
|
|
||||||
// check if the image is newer than the oldest image in the cache
|
|
||||||
const createdDate = new Date(imageDTO.created_at);
|
|
||||||
const oldestDate = new Date(
|
|
||||||
cacheImageDTOS[cacheImageDTOS.length - 1].created_at
|
|
||||||
);
|
|
||||||
return createdDate >= oldestDate;
|
|
||||||
} else if ([0, 1].includes(cacheImageDTOS.length)) {
|
|
||||||
// if there are only 1 or 0 images in the cache, we consider the image to be in the date range
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Determines the action we should take when an image may need to be added or updated in a cache.
|
|
||||||
// */
|
|
||||||
// export const getCacheAction = (
|
|
||||||
// data: ImageCache | undefined,
|
|
||||||
// imageDTO: ImageDTO
|
|
||||||
// ): 'add' | 'update' | 'none' => {
|
|
||||||
// const isInDateRange = getIsImageInDateRange(data, imageDTO);
|
|
||||||
// const isCacheFullyPopulated = data && data.total === data.ids.length;
|
|
||||||
// const shouldUpdateCache =
|
|
||||||
// Boolean(isInDateRange) || Boolean(isCacheFullyPopulated);
|
|
||||||
|
|
||||||
// const isImageInCache = data && data.ids.includes(imageDTO.image_name);
|
|
||||||
|
|
||||||
// if (shouldUpdateCache && isImageInCache) {
|
|
||||||
// return 'update';
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (shouldUpdateCache && !isImageInCache) {
|
|
||||||
// return 'add';
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return 'none';
|
|
||||||
// };
|
|
@ -1,4 +1,4 @@
|
|||||||
import { BoardId } from 'features/gallery/store/gallerySlice';
|
import { BoardId } from 'features/gallery/store/types';
|
||||||
import { useListAllBoardsQuery } from '../endpoints/boards';
|
import { useListAllBoardsQuery } from '../endpoints/boards';
|
||||||
|
|
||||||
export const useBoardName = (board_id: BoardId | null | undefined) => {
|
export const useBoardName = (board_id: BoardId | null | undefined) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { BoardId } from 'features/gallery/store/gallerySlice';
|
import { BoardId } from 'features/gallery/store/types';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
useGetBoardAssetsTotalQuery,
|
useGetBoardAssetsTotalQuery,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { isAnyOf } from '@reduxjs/toolkit';
|
import { createAsyncThunk, isAnyOf } from '@reduxjs/toolkit';
|
||||||
import { createAppAsyncThunk } from 'app/store/storeUtils';
|
|
||||||
import { isObject } from 'lodash-es';
|
import { isObject } from 'lodash-es';
|
||||||
import { $client } from 'services/api/client';
|
import { $client } from 'services/api/client';
|
||||||
import { paths } from 'services/api/schema';
|
import { paths } from 'services/api/schema';
|
||||||
@ -25,7 +24,7 @@ type CreateSessionThunkConfig = {
|
|||||||
/**
|
/**
|
||||||
* `SessionsService.createSession()` thunk
|
* `SessionsService.createSession()` thunk
|
||||||
*/
|
*/
|
||||||
export const sessionCreated = createAppAsyncThunk<
|
export const sessionCreated = createAsyncThunk<
|
||||||
CreateSessionResponse,
|
CreateSessionResponse,
|
||||||
CreateSessionArg,
|
CreateSessionArg,
|
||||||
CreateSessionThunkConfig
|
CreateSessionThunkConfig
|
||||||
@ -63,7 +62,7 @@ const isErrorWithStatus = (error: unknown): error is { status: number } =>
|
|||||||
/**
|
/**
|
||||||
* `SessionsService.invokeSession()` thunk
|
* `SessionsService.invokeSession()` thunk
|
||||||
*/
|
*/
|
||||||
export const sessionInvoked = createAppAsyncThunk<
|
export const sessionInvoked = createAsyncThunk<
|
||||||
InvokedSessionResponse,
|
InvokedSessionResponse,
|
||||||
InvokedSessionArg,
|
InvokedSessionArg,
|
||||||
InvokedSessionThunkConfig
|
InvokedSessionThunkConfig
|
||||||
@ -101,7 +100,7 @@ type CancelSessionThunkConfig = {
|
|||||||
/**
|
/**
|
||||||
* `SessionsService.cancelSession()` thunk
|
* `SessionsService.cancelSession()` thunk
|
||||||
*/
|
*/
|
||||||
export const sessionCanceled = createAppAsyncThunk<
|
export const sessionCanceled = createAsyncThunk<
|
||||||
CancelSessionResponse,
|
CancelSessionResponse,
|
||||||
CancelSessionArg,
|
CancelSessionArg,
|
||||||
CancelSessionThunkConfig
|
CancelSessionThunkConfig
|
||||||
@ -141,7 +140,7 @@ type ListSessionsThunkConfig = {
|
|||||||
/**
|
/**
|
||||||
* `SessionsService.listSessions()` thunk
|
* `SessionsService.listSessions()` thunk
|
||||||
*/
|
*/
|
||||||
export const listedSessions = createAppAsyncThunk<
|
export const listedSessions = createAsyncThunk<
|
||||||
ListSessionsResponse,
|
ListSessionsResponse,
|
||||||
ListSessionsArg,
|
ListSessionsArg,
|
||||||
ListSessionsThunkConfig
|
ListSessionsThunkConfig
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { MiddlewareAPI } from '@reduxjs/toolkit';
|
import { MiddlewareAPI } from '@reduxjs/toolkit';
|
||||||
import { logger } from 'app/logging/logger';
|
import { logger } from 'app/logging/logger';
|
||||||
import { AppDispatch, RootState } from 'app/store/store';
|
import { AppDispatch, RootState } from 'app/store/store';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { Socket } from 'socket.io-client';
|
import { Socket } from 'socket.io-client';
|
||||||
import { makeToast } from '../../../app/components/Toaster';
|
|
||||||
import { addToast } from '../../../features/system/store/systemSlice';
|
|
||||||
import {
|
import {
|
||||||
socketConnected,
|
socketConnected,
|
||||||
socketDisconnected,
|
socketDisconnected,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user