fix(ui): fix all circular dependencies

This commit is contained in:
psychedelicious 2023-07-22 22:48:39 +10:00
parent 5468d9a9fc
commit 6452d0fc28
89 changed files with 446 additions and 588 deletions

View File

@ -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';
} }

View File

@ -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;

View File

@ -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 = {

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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 '..';

View File

@ -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 '..';

View File

@ -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';

View File

@ -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 '..';

View File

@ -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 '..';

View File

@ -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({

View File

@ -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';

View File

@ -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,

View File

@ -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;
}>();

View File

@ -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,

View File

@ -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';

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -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,

View File

@ -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],

View File

@ -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;

View File

@ -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;

View File

@ -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: [],

View 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;
};

View File

@ -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;
};

View File

@ -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],

View File

@ -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;

View File

@ -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');

View File

@ -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
);

View File

@ -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');

View File

@ -0,0 +1,6 @@
export type ImageUsage = {
isInitialImage: boolean;
isCanvasImage: boolean;
isNodesImage: boolean;
isControlNetImage: boolean;
};

View File

@ -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,

View File

@ -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';

View File

@ -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;

View File

@ -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';

View File

@ -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';

View File

@ -1,4 +1,4 @@
import { NodesState } from './nodesSlice'; import { NodesState } from './types';
/** /**
* Nodes slice persist denylist * Nodes slice persist denylist

View File

@ -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;

View 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 };
};

View File

@ -157,3 +157,5 @@ export const FIELDS: Record<FieldType, FieldUIConfig> = {
description: 'A RGBA color.', description: 'A RGBA color.',
}, },
}; };
export const NODE_MIN_WIDTH = 250;

View File

@ -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) {

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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));

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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],
},
};

View File

@ -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
*/ */

View File

@ -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();

View File

@ -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();

View File

@ -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>
);
};

View File

@ -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() {

View File

@ -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;

View 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' }),
};

View File

@ -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';

View 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 };
};

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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;

View File

@ -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;

View File

@ -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[];
} }

View File

@ -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,

View File

@ -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']

View File

@ -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';
// };

View File

@ -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) => {

View File

@ -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,

View File

@ -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

View File

@ -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,