fix(ui): do not use state => state as an input selector

This is a no-no, whoops!
This commit is contained in:
psychedelicious 2024-01-05 19:44:22 +11:00
parent ce64dbefce
commit a23502f7ff
235 changed files with 1087 additions and 951 deletions

View File

@ -167,10 +167,5 @@
"vite-plugin-dts": "^3.7.0", "vite-plugin-dts": "^3.7.0",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
"vite-tsconfig-paths": "^4.2.3" "vite-tsconfig-paths": "^4.2.3"
},
"pnpm": {
"patchedDependencies": {
"reselect@5.0.1": "patches/reselect@5.0.1.patch"
}
} }
} }

View File

@ -4,11 +4,6 @@ settings:
autoInstallPeers: true autoInstallPeers: true
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
patchedDependencies:
reselect@5.0.1:
hash: kvbgwzjyy4x4fnh7znyocvb75q
path: patches/reselect@5.0.1.patch
dependencies: dependencies:
'@chakra-ui/anatomy': '@chakra-ui/anatomy':
specifier: ^2.2.2 specifier: ^2.2.2
@ -4570,7 +4565,7 @@ packages:
react-redux: 9.0.4(@types/react@18.2.46)(react@18.2.0)(redux@5.0.1) react-redux: 9.0.4(@types/react@18.2.46)(react@18.2.0)(redux@5.0.1)
redux: 5.0.1 redux: 5.0.1
redux-thunk: 3.1.0(redux@5.0.1) redux-thunk: 3.1.0(redux@5.0.1)
reselect: 5.0.1(patch_hash=kvbgwzjyy4x4fnh7znyocvb75q) reselect: 5.0.1
dev: false dev: false
/@roarr/browser-log-writer@1.3.0: /@roarr/browser-log-writer@1.3.0:
@ -11937,10 +11932,9 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/reselect@5.0.1(patch_hash=kvbgwzjyy4x4fnh7znyocvb75q): /reselect@5.0.1:
resolution: {integrity: sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==} resolution: {integrity: sha512-D72j2ubjgHpvuCiORWkOUxndHJrxDaSolheiz5CO+roz8ka97/4msh2E8F5qay4GawR5vzBt5MkbDHT+Rdy/Wg==}
dev: false dev: false
patched: true
/resize-observer-polyfill@1.5.1: /resize-observer-polyfill@1.5.1:
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}

View File

@ -11,7 +11,7 @@ import { memo, useCallback, useEffect } from 'react';
*/ */
const Toaster = () => { const Toaster = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const toastQueue = useAppSelector((state) => state.system.toastQueue); const toastQueue = useAppSelector((s) => s.system.toastQueue);
const toast = useToast(); const toast = useToast();
useEffect(() => { useEffect(() => {
toastQueue.forEach((t) => { toastQueue.forEach((t) => {

View File

@ -1,6 +1,6 @@
import { createLogWriter } from '@roarr/browser-log-writer'; import { createLogWriter } from '@roarr/browser-log-writer';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store'; import type { RootState} from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { ROARR, Roarr } from 'roarr'; import { ROARR, Roarr } from 'roarr';
@ -8,14 +8,17 @@ import { ROARR, Roarr } from 'roarr';
import type { LoggerNamespace } from './logger'; import type { LoggerNamespace } from './logger';
import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP, logger } from './logger'; import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP, logger } from './logger';
const selector = createMemoizedSelector(stateSelector, ({ system }) => { const selector = createMemoizedSelector(
const { consoleLogLevel, shouldLogToConsole } = system; (state: RootState) => state.system,
(system) => {
const { consoleLogLevel, shouldLogToConsole } = system;
return { return {
consoleLogLevel, consoleLogLevel,
shouldLogToConsole, shouldLogToConsole,
}; };
}); }
);
export const useLogger = (namespace: LoggerNamespace) => { export const useLogger = (namespace: LoggerNamespace) => {
const { consoleLogLevel, shouldLogToConsole } = useAppSelector(selector); const { consoleLogLevel, shouldLogToConsole } = useAppSelector(selector);

View File

@ -1,33 +1,32 @@
import { import {
createDraftSafeSelectorCreator, createDraftSafeSelectorCreator,
createSelectorCreator, createSelectorCreator,
lruMemoize, weakMapMemoize,
} from '@reduxjs/toolkit'; } from '@reduxjs/toolkit';
import type { GetSelectorsOptions } from '@reduxjs/toolkit/dist/entities/state_selectors'; import type { GetSelectorsOptions } from '@reduxjs/toolkit/dist/entities/state_selectors';
import { isEqual } from 'lodash-es';
/** /**
* A memoized selector creator that uses LRU cache and lodash's isEqual for equality check. * A memoized selector creator that uses LRU cache and lodash's isEqual for equality check.
*/ */
export const createMemoizedSelector = createSelectorCreator({ export const createMemoizedSelector = createSelectorCreator({
memoize: lruMemoize, memoize: weakMapMemoize,
memoizeOptions: { // memoizeOptions: {
resultEqualityCheck: isEqual, // resultEqualityCheck: isEqual,
}, // },
argsMemoize: lruMemoize, argsMemoize: weakMapMemoize,
}); });
/** /**
* A memoized selector creator that uses LRU cache default shallow equality check. * A memoized selector creator that uses LRU cache default shallow equality check.
*/ */
export const createLruSelector = createSelectorCreator({ export const createLruSelector = createSelectorCreator({
memoize: lruMemoize, memoize: weakMapMemoize,
argsMemoize: lruMemoize, argsMemoize: weakMapMemoize,
}); });
export const createLruDraftSafeSelector = createDraftSafeSelectorCreator({ export const createLruDraftSafeSelector = createDraftSafeSelectorCreator({
memoize: lruMemoize, memoize: weakMapMemoize,
argsMemoize: lruMemoize, argsMemoize: weakMapMemoize,
}); });
export const getSelectorsOptions: GetSelectorsOptions = { export const getSelectorsOptions: GetSelectorsOptions = {

View File

@ -8,7 +8,6 @@ import { initialPostprocessingState } from 'features/parameters/store/postproces
import { initialSDXLState } from 'features/sdxl/store/sdxlSlice'; import { initialSDXLState } from 'features/sdxl/store/sdxlSlice';
import { initialConfigState } from 'features/system/store/configSlice'; import { initialConfigState } from 'features/system/store/configSlice';
import { initialSystemState } from 'features/system/store/systemSlice'; import { initialSystemState } from 'features/system/store/systemSlice';
import { initialHotkeysState } from 'features/ui/store/hotkeysSlice';
import { initialUIState } from 'features/ui/store/uiSlice'; import { initialUIState } from 'features/ui/store/uiSlice';
import { defaultsDeep } from 'lodash-es'; import { defaultsDeep } from 'lodash-es';
import type { UnserializeFunction } from 'redux-remember'; import type { UnserializeFunction } from 'redux-remember';
@ -24,7 +23,6 @@ const initialStates: {
system: initialSystemState, system: initialSystemState,
config: initialConfigState, config: initialConfigState,
ui: initialUIState, ui: initialUIState,
hotkeys: initialHotkeysState,
controlAdapters: initialControlAdapterState, controlAdapters: initialControlAdapterState,
dynamicPrompts: initialDynamicPromptsState, dynamicPrompts: initialDynamicPromptsState,
sdxl: initialSDXLState, sdxl: initialSDXLState,

View File

@ -20,9 +20,15 @@ export const addDeleteBoardAndImagesFulfilledListener = () => {
let wasNodeEditorReset = false; let wasNodeEditorReset = false;
let wereControlAdaptersReset = false; let wereControlAdaptersReset = false;
const state = getState(); const { generation, canvas, nodes, controlAdapters } = getState();
deleted_images.forEach((image_name) => { deleted_images.forEach((image_name) => {
const imageUsage = getImageUsage(state, image_name); const imageUsage = getImageUsage(
generation,
canvas,
nodes,
controlAdapters,
image_name
);
if (imageUsage.isInitialImage && !wasInitialImageReset) { if (imageUsage.isInitialImage && !wasInitialImageReset) {
dispatch(clearInitialImage()); dispatch(clearInitialImage());

View File

@ -151,6 +151,3 @@ export type RootState = ReturnType<ReturnType<typeof createStore>['getState']>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AppThunkDispatch = ThunkDispatch<RootState, any, UnknownAction>; export type AppThunkDispatch = ThunkDispatch<RootState, any, UnknownAction>;
export type AppDispatch = ReturnType<typeof createStore>['dispatch']; export type AppDispatch = ReturnType<typeof createStore>['dispatch'];
export function stateSelector(state: RootState) {
return state;
}

View File

@ -32,7 +32,7 @@ const IAIInformationalPopover = ({
...rest ...rest
}: Props) => { }: Props) => {
const shouldEnableInformationalPopovers = useAppSelector( const shouldEnableInformationalPopovers = useAppSelector(
(state) => state.system.shouldEnableInformationalPopovers (s) => s.system.shouldEnableInformationalPopovers
); );
const data = useMemo(() => POPOVER_DATA[feature], [feature]); const data = useMemo(() => POPOVER_DATA[feature], [feature]);

View File

@ -13,7 +13,7 @@ export const InvLabel = memo(
ref ref
) => { ) => {
const shouldEnableInformationalPopovers = useAppSelector( const shouldEnableInformationalPopovers = useAppSelector(
(state) => state.system.shouldEnableInformationalPopovers (s) => s.system.shouldEnableInformationalPopovers
); );
const ctx = useContext(InvControlGroupContext); const ctx = useContext(InvControlGroupContext);

View File

@ -30,7 +30,7 @@ export const useGroupedModelInvSelect = <T extends AnyModelConfigEntity>(
): UseGroupedModelInvSelectReturn => { ): UseGroupedModelInvSelectReturn => {
const { t } = useTranslation(); const { t } = useTranslation();
const base_model = useAppSelector( const base_model = useAppSelector(
(state) => state.generation.model?.base_model ?? 'sdxl' (s) => s.generation.model?.base_model ?? 'sdxl'
); );
const { modelEntities, selectedModel, getIsDisabled, onChange, isLoading } = const { modelEntities, selectedModel, getIsDisabled, onChange, isLoading } =
arg; arg;

View File

@ -1,6 +1,6 @@
import { useAppToaster } from 'app/components/Toaster'; import { useAppToaster } from 'app/components/Toaster';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store'; import type { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
@ -16,8 +16,8 @@ const accept: Accept = {
}; };
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector, activeTabNameSelector], [(state: RootState) => state.gallery, activeTabNameSelector],
({ gallery }, activeTabName) => { (gallery, activeTabName) => {
let postUploadAction: PostUploadAction = { type: 'TOAST' }; let postUploadAction: PostUploadAction = { type: 'TOAST' };
if (activeTabName === 'unifiedCanvas') { if (activeTabName === 'unifiedCanvas') {

View File

@ -33,7 +33,7 @@ export const useImageUploadButton = ({
isDisabled, isDisabled,
}: UseImageUploadButtonArgs) => { }: UseImageUploadButtonArgs) => {
const autoAddBoardId = useAppSelector( const autoAddBoardId = useAppSelector(
(state) => state.gallery.autoAddBoardId (s) => s.gallery.autoAddBoardId
); );
const [uploadImage] = useUploadImageMutation(); const [uploadImage] = useUploadImageMutation();
const onDropAccepted = useCallback( const onDropAccepted = useCallback(

View File

@ -1,5 +1,5 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store'; import type { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice'; import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
@ -11,16 +11,22 @@ import { forEach } from 'lodash-es';
import { getConnectedEdges } from 'reactflow'; import { getConnectedEdges } from 'reactflow';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector, activeTabNameSelector], [
(state: RootState) => state.controlAdapters,
(state: RootState) => state.generation,
(state: RootState) => state.system,
(state: RootState) => state.nodes,
(state: RootState) => state.nodeTemplates,
(state: RootState) => state.dynamicPrompts,
activeTabNameSelector,
],
( (
{ controlAdapters,
controlAdapters, generation,
generation, system,
system, nodes,
nodes, nodeTemplates,
nodeTemplates, dynamicPrompts,
dynamicPrompts,
},
activeTabName activeTabName
) => { ) => {
const { initialImage, model, positivePrompt } = generation; const { initialImage, model, positivePrompt } = generation;

View File

@ -1,7 +1,6 @@
import { Box, chakra, Flex } from '@chakra-ui/react'; import { Box, chakra, Flex } from '@chakra-ui/react';
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import useCanvasDragMove from 'features/canvas/hooks/useCanvasDragMove'; import useCanvasDragMove from 'features/canvas/hooks/useCanvasDragMove';
import useCanvasHotkeys from 'features/canvas/hooks/useCanvasHotkeys'; import useCanvasHotkeys from 'features/canvas/hooks/useCanvasHotkeys';
@ -17,7 +16,10 @@ import {
$isTransformingBoundingBox, $isTransformingBoundingBox,
} from 'features/canvas/store/canvasNanostore'; } from 'features/canvas/store/canvasNanostore';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { canvasResized } from 'features/canvas/store/canvasSlice'; import {
canvasResized,
selectCanvasSlice,
} from 'features/canvas/store/canvasSlice';
import { import {
setCanvasBaseLayer, setCanvasBaseLayer,
setCanvasStage, setCanvasStage,
@ -41,8 +43,8 @@ import IAICanvasBoundingBox from './IAICanvasToolbar/IAICanvasBoundingBox';
import IAICanvasToolPreview from './IAICanvasToolPreview'; import IAICanvasToolPreview from './IAICanvasToolPreview';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector, isStagingSelector], [selectCanvasSlice, isStagingSelector],
({ canvas }, isStaging) => { (canvas, isStaging) => {
const { const {
isMaskEnabled, isMaskEnabled,
stageScale, stageScale,

View File

@ -1,10 +1,10 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { memo } from 'react'; import { memo } from 'react';
import { Group, Rect } from 'react-konva'; import { Group, Rect } from 'react-konva';
const selector = createMemoizedSelector(stateSelector, ({ canvas }) => { const selector = createMemoizedSelector(selectCanvasSlice, (canvas) => {
const { const {
boundingBoxCoordinates, boundingBoxCoordinates,
boundingBoxDimensions, boundingBoxDimensions,

View File

@ -1,13 +1,13 @@
// Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/ // Grid drawing adapted from https://longviewcoder.com/2021/12/08/konva-a-better-grid/
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import type { ReactElement } from 'react'; import type { ReactElement } from 'react';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { Group, Line as KonvaLine } from 'react-konva'; import { Group, Line as KonvaLine } from 'react-konva';
import { getArbitraryBaseColor } from 'theme/colors'; import { getArbitraryBaseColor } from 'theme/colors';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => { const selector = createMemoizedSelector([selectCanvasSlice], (canvas) => {
const { stageScale, stageCoordinates, stageDimensions } = canvas; const { stageScale, stageCoordinates, stageDimensions } = canvas;
return { stageScale, stageCoordinates, stageDimensions }; return { stageScale, stageCoordinates, stageDimensions };
}); });

View File

@ -2,14 +2,15 @@ import {
createLruSelector, createLruSelector,
createMemoizedSelector, createMemoizedSelector,
} from 'app/store/createMemoizedSelector'; } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { selectSystemSlice } from 'features/system/store/systemSlice';
import { memo, useEffect, useState } from 'react'; import { memo, useEffect, useState } from 'react';
import { Image as KonvaImage } from 'react-konva'; import { Image as KonvaImage } from 'react-konva';
const progressImageSelector = createLruSelector( const progressImageSelector = createLruSelector(
[stateSelector], [selectSystemSlice, selectCanvasSlice],
({ system, canvas }) => { (system, canvas) => {
const { denoiseProgress } = system; const { denoiseProgress } = system;
const { batchIds } = canvas; const { batchIds } = canvas;
@ -20,8 +21,8 @@ const progressImageSelector = createLruSelector(
); );
const boundingBoxSelector = createMemoizedSelector( const boundingBoxSelector = createMemoizedSelector(
[stateSelector], [selectCanvasSlice],
({ canvas }) => canvas.layerState.stagingArea.boundingBox (canvas) => canvas.layerState.stagingArea.boundingBox
); );
const IAICanvasIntermediateImage = () => { const IAICanvasIntermediateImage = () => {

View File

@ -1,6 +1,6 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { rgbaColorToString } from 'features/canvas/util/colorToString'; import { rgbaColorToString } from 'features/canvas/util/colorToString';
import type Konva from 'konva'; import type Konva from 'konva';
import type { RectConfig } from 'konva/lib/shapes/Rect'; import type { RectConfig } from 'konva/lib/shapes/Rect';
@ -9,8 +9,8 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Rect } from 'react-konva'; import { Rect } from 'react-konva';
export const canvasMaskCompositerSelector = createMemoizedSelector( export const canvasMaskCompositerSelector = createMemoizedSelector(
stateSelector, selectCanvasSlice,
({ canvas }) => { (canvas) => {
const { maskColor, stageCoordinates, stageDimensions, stageScale } = canvas; const { maskColor, stageCoordinates, stageDimensions, stageScale } = canvas;
return { return {

View File

@ -1,18 +1,9 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { isCanvasMaskLine } from 'features/canvas/store/canvasTypes'; import { isCanvasMaskLine } from 'features/canvas/store/canvasTypes';
import type { GroupConfig } from 'konva/lib/Group'; import type { GroupConfig } from 'konva/lib/Group';
import { memo } from 'react'; import { memo } from 'react';
import { Group, Line } from 'react-konva'; import { Group, Line } from 'react-konva';
export const canvasLinesSelector = createMemoizedSelector(
[stateSelector],
({ canvas }) => {
return canvas.layerState.objects.filter(isCanvasMaskLine);
}
);
type InpaintingCanvasLinesProps = GroupConfig; type InpaintingCanvasLinesProps = GroupConfig;
/** /**
@ -21,7 +12,7 @@ type InpaintingCanvasLinesProps = GroupConfig;
* Uses globalCompositeOperation to handle the brush and eraser tools. * Uses globalCompositeOperation to handle the brush and eraser tools.
*/ */
const IAICanvasLines = (props: InpaintingCanvasLinesProps) => { const IAICanvasLines = (props: InpaintingCanvasLinesProps) => {
const objects = useAppSelector((state) => state.canvas.layerState.objects); const objects = useAppSelector((s) => s.canvas.layerState.objects);
return ( return (
<Group listening={false} {...props}> <Group listening={false} {...props}>

View File

@ -12,7 +12,7 @@ import { Group, Line, Rect } from 'react-konva';
import IAICanvasImage from './IAICanvasImage'; import IAICanvasImage from './IAICanvasImage';
const IAICanvasObjectRenderer = () => { const IAICanvasObjectRenderer = () => {
const objects = useAppSelector((state) => state.canvas.layerState.objects); const objects = useAppSelector((s) => s.canvas.layerState.objects);
return ( return (
<Group name="outpainting-objects" listening={false}> <Group name="outpainting-objects" listening={false}>

View File

@ -1,6 +1,6 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import type { GroupConfig } from 'konva/lib/Group'; import type { GroupConfig } from 'konva/lib/Group';
import { memo } from 'react'; import { memo } from 'react';
import { Group, Rect } from 'react-konva'; import { Group, Rect } from 'react-konva';
@ -9,7 +9,7 @@ import IAICanvasImage from './IAICanvasImage';
const dash = [4, 4]; const dash = [4, 4];
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => { const selector = createMemoizedSelector(selectCanvasSlice, (canvas) => {
const { const {
layerState, layerState,
shouldShowStagingImage, shouldShowStagingImage,

View File

@ -1,7 +1,6 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvButton } from 'common/components/InvButton/InvButton'; import { InvButton } from 'common/components/InvButton/InvButton';
import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup'; import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
@ -11,6 +10,7 @@ import {
discardStagedImages, discardStagedImages,
nextStagingAreaImage, nextStagingAreaImage,
prevStagingAreaImage, prevStagingAreaImage,
selectCanvasSlice,
setShouldShowStagingImage, setShouldShowStagingImage,
setShouldShowStagingOutline, setShouldShowStagingOutline,
} from 'features/canvas/store/canvasSlice'; } from 'features/canvas/store/canvasSlice';
@ -29,7 +29,7 @@ import {
} from 'react-icons/fa'; } from 'react-icons/fa';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => { const selector = createMemoizedSelector(selectCanvasSlice, (canvas) => {
const { const {
layerState: { layerState: {
stagingArea: { images, selectedImageIndex }, stagingArea: { images, selectedImageIndex },

View File

@ -1,7 +1,7 @@
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import roundToHundreth from 'features/canvas/util/roundToHundreth'; import roundToHundreth from 'features/canvas/util/roundToHundreth';
import GenerationModeStatusText from 'features/parameters/components/Canvas/GenerationModeStatusText'; import GenerationModeStatusText from 'features/parameters/components/Canvas/GenerationModeStatusText';
import { memo } from 'react'; import { memo } from 'react';
@ -11,7 +11,7 @@ import IAICanvasStatusTextCursorPos from './IAICanvasStatusText/IAICanvasStatusT
const warningColor = 'var(--invokeai-colors-warning-500)'; const warningColor = 'var(--invokeai-colors-warning-500)';
const selector = createMemoizedSelector([stateSelector], ({ canvas }) => { const selector = createMemoizedSelector(selectCanvasSlice, (canvas) => {
const { const {
stageDimensions: { width: stageWidth, height: stageHeight }, stageDimensions: { width: stageWidth, height: stageHeight },
stageCoordinates: { x: stageX, y: stageY }, stageCoordinates: { x: stageX, y: stageY },

View File

@ -1,12 +1,12 @@
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { import {
$cursorPosition, $cursorPosition,
$isMovingBoundingBox, $isMovingBoundingBox,
$isTransformingBoundingBox, $isTransformingBoundingBox,
} from 'features/canvas/store/canvasNanostore'; } from 'features/canvas/store/canvasNanostore';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { rgbaColorToString } from 'features/canvas/util/colorToString'; import { rgbaColorToString } from 'features/canvas/util/colorToString';
import { import {
COLOR_PICKER_SIZE, COLOR_PICKER_SIZE,
@ -17,8 +17,8 @@ import { memo, useMemo } from 'react';
import { Circle, Group } from 'react-konva'; import { Circle, Group } from 'react-konva';
const canvasBrushPreviewSelector = createMemoizedSelector( const canvasBrushPreviewSelector = createMemoizedSelector(
stateSelector, selectCanvasSlice,
({ canvas }) => { (canvas) => {
const { const {
brushSize, brushSize,
colorPickerColor, colorPickerColor,

View File

@ -1,6 +1,5 @@
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { $shift } from 'common/hooks/useGlobalModifiers'; import { $shift } from 'common/hooks/useGlobalModifiers';
import { import {
@ -18,6 +17,7 @@ import {
} from 'features/canvas/store/canvasNanostore'; } from 'features/canvas/store/canvasNanostore';
import { import {
aspectRatioChanged, aspectRatioChanged,
selectCanvasSlice,
setBoundingBoxCoordinates, setBoundingBoxCoordinates,
setBoundingBoxDimensions, setBoundingBoxDimensions,
setShouldSnapToGrid, setShouldSnapToGrid,
@ -39,8 +39,8 @@ import { Group, Rect, Transformer } from 'react-konva';
const borderDash = [4, 4]; const borderDash = [4, 4];
const boundingBoxPreviewSelector = createMemoizedSelector( const boundingBoxPreviewSelector = createMemoizedSelector(
[stateSelector, selectOptimalDimension], [selectCanvasSlice, selectOptimalDimension],
({ canvas }, optimalDimension) => { (canvas, optimalDimension) => {
const { const {
boundingBoxCoordinates, boundingBoxCoordinates,
boundingBoxDimensions, boundingBoxDimensions,

View File

@ -1,6 +1,5 @@
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIColorPicker from 'common/components/IAIColorPicker'; import IAIColorPicker from 'common/components/IAIColorPicker';
import { InvButton } from 'common/components/InvButton/InvButton'; import { InvButton } from 'common/components/InvButton/InvButton';
@ -17,6 +16,7 @@ import { canvasMaskSavedToGallery } from 'features/canvas/store/actions';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { import {
clearMask, clearMask,
selectCanvasSlice,
setIsMaskEnabled, setIsMaskEnabled,
setLayer, setLayer,
setMaskColor, setMaskColor,
@ -31,8 +31,8 @@ import { useTranslation } from 'react-i18next';
import { FaMask, FaSave, FaTrash } from 'react-icons/fa'; import { FaMask, FaSave, FaTrash } from 'react-icons/fa';
export const selector = createMemoizedSelector( export const selector = createMemoizedSelector(
[stateSelector, isStagingSelector], [selectCanvasSlice, isStagingSelector],
({ canvas }, isStaging) => { (canvas, isStaging) => {
const { maskColor, layer, isMaskEnabled, shouldPreserveMaskedArea } = const { maskColor, layer, isMaskEnabled, shouldPreserveMaskedArea } =
canvas; canvas;

View File

@ -1,8 +1,7 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton'; import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import { redo } from 'features/canvas/store/canvasSlice'; import { redo, selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
@ -10,8 +9,8 @@ import { useTranslation } from 'react-i18next';
import { FaRedo } from 'react-icons/fa'; import { FaRedo } from 'react-icons/fa';
const canvasRedoSelector = createMemoizedSelector( const canvasRedoSelector = createMemoizedSelector(
[stateSelector, activeTabNameSelector], [selectCanvasSlice, activeTabNameSelector],
({ canvas }, activeTabName) => { (canvas, activeTabName) => {
const { futureLayerStates } = canvas; const { futureLayerStates } = canvas;
return { return {

View File

@ -1,6 +1,5 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvCheckbox } from 'common/components/InvCheckbox/wrapper'; import { InvCheckbox } from 'common/components/InvCheckbox/wrapper';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
@ -11,6 +10,7 @@ import {
} from 'common/components/InvPopover/wrapper'; } from 'common/components/InvPopover/wrapper';
import ClearCanvasHistoryButtonModal from 'features/canvas/components/ClearCanvasHistoryButtonModal'; import ClearCanvasHistoryButtonModal from 'features/canvas/components/ClearCanvasHistoryButtonModal';
import { import {
selectCanvasSlice,
setShouldAntialias, setShouldAntialias,
setShouldAutoSave, setShouldAutoSave,
setShouldCropToBoundingBoxOnSave, setShouldCropToBoundingBoxOnSave,
@ -29,8 +29,8 @@ import { useTranslation } from 'react-i18next';
import { FaWrench } from 'react-icons/fa'; import { FaWrench } from 'react-icons/fa';
export const canvasControlsSelector = createMemoizedSelector( export const canvasControlsSelector = createMemoizedSelector(
[stateSelector], [selectCanvasSlice],
({ canvas }) => { (canvas) => {
const { const {
shouldAutoSave, shouldAutoSave,
shouldCropToBoundingBoxOnSave, shouldCropToBoundingBoxOnSave,

View File

@ -1,6 +1,5 @@
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIColorPicker from 'common/components/IAIColorPicker'; import IAIColorPicker from 'common/components/IAIColorPicker';
import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup'; import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
@ -17,6 +16,7 @@ import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { import {
addEraseRect, addEraseRect,
addFillRect, addFillRect,
selectCanvasSlice,
setBrushColor, setBrushColor,
setBrushSize, setBrushSize,
setTool, setTool,
@ -37,8 +37,8 @@ import {
} from 'react-icons/fa'; } from 'react-icons/fa';
export const selector = createMemoizedSelector( export const selector = createMemoizedSelector(
[stateSelector, isStagingSelector], [selectCanvasSlice, isStagingSelector],
({ canvas }, isStaging) => { (canvas, isStaging) => {
const { tool, brushColor, brushSize } = canvas; const { tool, brushColor, brushSize } = canvas;
return { return {

View File

@ -1,6 +1,5 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup'; import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
@ -20,6 +19,7 @@ import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { import {
resetCanvas, resetCanvas,
resetCanvasView, resetCanvasView,
selectCanvasSlice,
setIsMaskEnabled, setIsMaskEnabled,
setLayer, setLayer,
setTool, setTool,
@ -49,8 +49,8 @@ import IAICanvasToolChooserOptions from './IAICanvasToolChooserOptions';
import IAICanvasUndoButton from './IAICanvasUndoButton'; import IAICanvasUndoButton from './IAICanvasUndoButton';
export const selector = createMemoizedSelector( export const selector = createMemoizedSelector(
[stateSelector, isStagingSelector], [selectCanvasSlice, isStagingSelector],
({ canvas }, isStaging) => { (canvas, isStaging) => {
const { tool, shouldCropToBoundingBoxOnSave, layer, isMaskEnabled } = const { tool, shouldCropToBoundingBoxOnSave, layer, isMaskEnabled } =
canvas; canvas;

View File

@ -1,8 +1,7 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton'; import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import { undo } from 'features/canvas/store/canvasSlice'; import { selectCanvasSlice,undo } from 'features/canvas/store/canvasSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
@ -10,8 +9,8 @@ import { useTranslation } from 'react-i18next';
import { FaUndo } from 'react-icons/fa'; import { FaUndo } from 'react-icons/fa';
const canvasUndoSelector = createMemoizedSelector( const canvasUndoSelector = createMemoizedSelector(
[stateSelector, activeTabNameSelector], [selectCanvasSlice, activeTabNameSelector],
({ canvas }, activeTabName) => { (canvas, activeTabName) => {
const { pastLayerStates } = canvas; const { pastLayerStates } = canvas;
return { return {

View File

@ -12,7 +12,7 @@ import { useCallback } from 'react';
const useCanvasDrag = () => { const useCanvasDrag = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isStaging = useAppSelector(isStagingSelector); const isStaging = useAppSelector(isStagingSelector);
const tool = useAppSelector((state) => state.canvas.tool); const tool = useAppSelector((s) => s.canvas.tool);
const isMovingBoundingBox = useStore($isMovingBoundingBox); const isMovingBoundingBox = useStore($isMovingBoundingBox);
const handleDragStart = useCallback(() => { const handleDragStart = useCallback(() => {
if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) { if (!((tool === 'move' || isStaging) && !isMovingBoundingBox)) {

View File

@ -6,18 +6,18 @@ import { useEffect, useState } from 'react';
import { useDebounce } from 'react-use'; import { useDebounce } from 'react-use';
export const useCanvasGenerationMode = () => { export const useCanvasGenerationMode = () => {
const layerState = useAppSelector((state) => state.canvas.layerState); const layerState = useAppSelector((s) => s.canvas.layerState);
const boundingBoxCoordinates = useAppSelector( const boundingBoxCoordinates = useAppSelector(
(state) => state.canvas.boundingBoxCoordinates (s) => s.canvas.boundingBoxCoordinates
); );
const boundingBoxDimensions = useAppSelector( const boundingBoxDimensions = useAppSelector(
(state) => state.canvas.boundingBoxDimensions (s) => s.canvas.boundingBoxDimensions
); );
const isMaskEnabled = useAppSelector((state) => state.canvas.isMaskEnabled); const isMaskEnabled = useAppSelector((s) => s.canvas.isMaskEnabled);
const shouldPreserveMaskedArea = useAppSelector( const shouldPreserveMaskedArea = useAppSelector(
(state) => state.canvas.shouldPreserveMaskedArea (s) => s.canvas.shouldPreserveMaskedArea
); );
const [generationMode, setGenerationMode] = useState< const [generationMode, setGenerationMode] = useState<
GenerationMode | undefined GenerationMode | undefined

View File

@ -1,5 +1,4 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { import {
resetCanvasInteractionState, resetCanvasInteractionState,
@ -8,6 +7,7 @@ import {
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { import {
clearMask, clearMask,
selectCanvasSlice,
setIsMaskEnabled, setIsMaskEnabled,
setShouldShowBoundingBox, setShouldShowBoundingBox,
setShouldSnapToGrid, setShouldSnapToGrid,
@ -20,8 +20,8 @@ import { useRef } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector, activeTabNameSelector, isStagingSelector], [selectCanvasSlice, activeTabNameSelector, isStagingSelector],
({ canvas }, activeTabName, isStaging) => { (canvas, activeTabName, isStaging) => {
const { const {
shouldLockBoundingBox, shouldLockBoundingBox,
shouldShowBoundingBox, shouldShowBoundingBox,

View File

@ -1,12 +1,11 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { import {
setIsDrawing, setIsDrawing,
setIsMovingStage, setIsMovingStage,
} from 'features/canvas/store/canvasNanostore'; } from 'features/canvas/store/canvasNanostore';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { addLine } from 'features/canvas/store/canvasSlice'; import { addLine, selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition'; import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import type Konva from 'konva'; import type Konva from 'konva';
@ -17,11 +16,10 @@ import { useCallback } from 'react';
import useColorPicker from './useColorUnderCursor'; import useColorPicker from './useColorUnderCursor';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[activeTabNameSelector, stateSelector, isStagingSelector], [activeTabNameSelector, selectCanvasSlice, isStagingSelector],
(activeTabName, { canvas }, isStaging) => { (activeTabName, canvas, isStaging) => {
const { tool } = canvas;
return { return {
tool, tool: canvas.tool,
activeTabName, activeTabName,
isStaging, isStaging,
}; };

View File

@ -1,13 +1,15 @@
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { import {
$isDrawing, $isDrawing,
setCursorPosition, setCursorPosition,
} from 'features/canvas/store/canvasNanostore'; } from 'features/canvas/store/canvasNanostore';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { addPointToCurrentLine } from 'features/canvas/store/canvasSlice'; import {
addPointToCurrentLine,
selectCanvasSlice,
} from 'features/canvas/store/canvasSlice';
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition'; import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import type Konva from 'konva'; import type Konva from 'konva';
@ -18,11 +20,10 @@ import { useCallback } from 'react';
import useColorPicker from './useColorUnderCursor'; import useColorPicker from './useColorUnderCursor';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[activeTabNameSelector, stateSelector, isStagingSelector], [activeTabNameSelector, selectCanvasSlice, isStagingSelector],
(activeTabName, { canvas }, isStaging) => { (activeTabName, canvas, isStaging) => {
const { tool } = canvas;
return { return {
tool, tool: canvas.tool,
activeTabName, activeTabName,
isStaging, isStaging,
}; };

View File

@ -1,6 +1,4 @@
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { import {
$isDrawing, $isDrawing,
@ -8,32 +6,20 @@ import {
setIsMovingStage, setIsMovingStage,
} from 'features/canvas/store/canvasNanostore'; } from 'features/canvas/store/canvasNanostore';
import { isStagingSelector } from 'features/canvas/store/canvasSelectors'; import { isStagingSelector } from 'features/canvas/store/canvasSelectors';
import { import { addPointToCurrentLine } from 'features/canvas/store/canvasSlice';
// addPointToCurrentEraserLine,
addPointToCurrentLine,
} from 'features/canvas/store/canvasSlice';
import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition'; import getScaledCursorPosition from 'features/canvas/util/getScaledCursorPosition';
import type Konva from 'konva'; import type Konva from 'konva';
import type { MutableRefObject } from 'react'; import type { MutableRefObject } from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
const selector = createMemoizedSelector(
[stateSelector, isStagingSelector],
({ canvas }, isStaging) => {
return {
tool: canvas.tool,
isStaging,
};
}
);
const useCanvasMouseUp = ( const useCanvasMouseUp = (
stageRef: MutableRefObject<Konva.Stage | null>, stageRef: MutableRefObject<Konva.Stage | null>,
didMouseMoveRef: MutableRefObject<boolean> didMouseMoveRef: MutableRefObject<boolean>
) => { ) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const isDrawing = useStore($isDrawing); const isDrawing = useStore($isDrawing);
const { tool, isStaging } = useAppSelector(selector); const tool = useAppSelector((s) => s.canvas.tool);
const isStaging = useAppSelector(isStagingSelector);
return useCallback(() => { return useCallback(() => {
if (tool === 'move' || isStaging) { if (tool === 'move' || isStaging) {

View File

@ -1,6 +1,4 @@
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { $isMoveStageKeyHeld } from 'features/canvas/store/canvasNanostore'; import { $isMoveStageKeyHeld } from 'features/canvas/store/canvasNanostore';
import { import {
@ -18,14 +16,9 @@ import { clamp } from 'lodash-es';
import type { MutableRefObject } from 'react'; import type { MutableRefObject } from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
const selector = createMemoizedSelector(
[stateSelector],
(state) => state.canvas.stageScale
);
const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => { const useCanvasWheel = (stageRef: MutableRefObject<Konva.Stage | null>) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const stageScale = useAppSelector(selector); const stageScale = useAppSelector((s) => s.canvas.stageScale);
const isMoveStageKeyHeld = useStore($isMoveStageKeyHeld); const isMoveStageKeyHeld = useStore($isMoveStageKeyHeld);
return useCallback( return useCallback(

View File

@ -1,13 +1,13 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import type { RootState } from 'app/store/store'; import type { RootState } from 'app/store/store';
import { stateSelector } from 'app/store/store';
import { selectCanvasSlice } from './canvasSlice';
import type { CanvasImage } from './canvasTypes'; import type { CanvasImage } from './canvasTypes';
import { isCanvasBaseImage } from './canvasTypes'; import { isCanvasBaseImage } from './canvasTypes';
export const isStagingSelector = createMemoizedSelector( export const isStagingSelector = createMemoizedSelector(
[stateSelector], selectCanvasSlice,
({ canvas }) => (canvas) =>
canvas.batchIds.length > 0 || canvas.batchIds.length > 0 ||
canvas.layerState.stagingArea.images.length > 0 canvas.layerState.stagingArea.images.length > 0
); );

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import { import {
roundDownToMultiple, roundDownToMultiple,
roundToMultiple, roundToMultiple,
@ -781,3 +782,5 @@ export const {
} = canvasSlice.actions; } = canvasSlice.actions;
export default canvasSlice.reducer; export default canvasSlice.reducer;
export const selectCanvasSlice = (state: RootState) => state.canvas;

View File

@ -1,6 +1,5 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvConfirmationAlertDialog } from 'common/components/InvConfirmationAlertDialog/InvConfirmationAlertDialog'; import { InvConfirmationAlertDialog } from 'common/components/InvConfirmationAlertDialog/InvConfirmationAlertDialog';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
@ -13,6 +12,7 @@ import { InvText } from 'common/components/InvText/wrapper';
import { import {
changeBoardReset, changeBoardReset,
isModalOpenChanged, isModalOpenChanged,
selectChangeBoardModalSlice,
} from 'features/changeBoardModal/store/slice'; } from 'features/changeBoardModal/store/slice';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -23,8 +23,8 @@ import {
} from 'services/api/endpoints/images'; } from 'services/api/endpoints/images';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector], selectChangeBoardModalSlice,
({ changeBoardModal }) => { (changeBoardModal) => {
const { isModalOpen, imagesToChange } = changeBoardModal; const { isModalOpen, imagesToChange } = changeBoardModal;
return { return {

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import type { ImageDTO } from 'services/api/types'; import type { ImageDTO } from 'services/api/types';
import { initialState } from './initialState'; import { initialState } from './initialState';
@ -25,3 +26,6 @@ export const { isModalOpenChanged, imagesToChangeSelected, changeBoardReset } =
changeBoardModal.actions; changeBoardModal.actions;
export default changeBoardModal.reducer; export default changeBoardModal.reducer;
export const selectChangeBoardModalSlice = (state: RootState) =>
state.changeBoardModal;

View File

@ -2,7 +2,6 @@ import type { SystemStyleObject } from '@chakra-ui/react';
import { Box, Flex, Spinner } from '@chakra-ui/react'; import { Box, Flex, Spinner } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImage from 'common/components/IAIDndImage';
import IAIDndImageIcon from 'common/components/IAIDndImageIcon'; import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
@ -10,16 +9,21 @@ import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
import { useControlAdapterControlImage } from 'features/controlAdapters/hooks/useControlAdapterControlImage'; import { useControlAdapterControlImage } from 'features/controlAdapters/hooks/useControlAdapterControlImage';
import { useControlAdapterProcessedControlImage } from 'features/controlAdapters/hooks/useControlAdapterProcessedControlImage'; import { useControlAdapterProcessedControlImage } from 'features/controlAdapters/hooks/useControlAdapterProcessedControlImage';
import { useControlAdapterProcessorType } from 'features/controlAdapters/hooks/useControlAdapterProcessorType'; import { useControlAdapterProcessorType } from 'features/controlAdapters/hooks/useControlAdapterProcessorType';
import { controlAdapterImageChanged } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
controlAdapterImageChanged,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import type { import type {
TypesafeDraggableData, TypesafeDraggableData,
TypesafeDroppableData, TypesafeDroppableData,
} from 'features/dnd/types'; } from 'features/dnd/types';
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
import { import {
heightChanged, heightChanged,
selectOptimalDimension, selectOptimalDimension,
widthChanged, widthChanged,
} from 'features/parameters/store/generationSlice'; } from 'features/parameters/store/generationSlice';
import { selectSystemSlice } from 'features/system/store/systemSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -38,8 +42,14 @@ type Props = {
}; };
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector, activeTabNameSelector, selectOptimalDimension], [
({ controlAdapters, gallery, system }, activeTabName, optimalDimension) => { selectControlAdaptersSlice,
selectGallerySlice,
selectSystemSlice,
activeTabNameSelector,
selectOptimalDimension,
],
(controlAdapters, gallery, system, activeTabName, optimalDimension) => {
const { pendingControlImages } = controlAdapters; const { pendingControlImages } = controlAdapters;
const { autoAddBoardId } = gallery; const { autoAddBoardId } = gallery;
const { isConnected } = system; const { isConnected } = system;

View File

@ -1,5 +1,4 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSelect } from 'common/components/InvSelect/InvSelect'; import { InvSelect } from 'common/components/InvSelect/InvSelect';
@ -10,6 +9,7 @@ import { useControlAdapterModel } from 'features/controlAdapters/hooks/useContro
import { useControlAdapterModelEntities } from 'features/controlAdapters/hooks/useControlAdapterModelEntities'; import { useControlAdapterModelEntities } from 'features/controlAdapters/hooks/useControlAdapterModelEntities';
import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType'; import { useControlAdapterType } from 'features/controlAdapters/hooks/useControlAdapterType';
import { controlAdapterModelChanged } from 'features/controlAdapters/store/controlAdaptersSlice'; import { controlAdapterModelChanged } from 'features/controlAdapters/store/controlAdaptersSlice';
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
import { pick } from 'lodash-es'; import { pick } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -24,9 +24,8 @@ type ParamControlAdapterModelProps = {
id: string; id: string;
}; };
const selector = createMemoizedSelector(stateSelector, ({ generation }) => { const selector = createMemoizedSelector(selectGenerationSlice, (generation) => {
const { model } = generation; return { mainModel: generation.model };
return { mainModel: model };
}); });
const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => { const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
@ -35,7 +34,7 @@ const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
const model = useControlAdapterModel(id); const model = useControlAdapterModel(id);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const currentBaseModel = useAppSelector( const currentBaseModel = useAppSelector(
(state) => state.generation.model?.base_model (s) => s.generation.model?.base_model
); );
const { mainModel } = useAppSelector(selector); const { mainModel } = useAppSelector(selector);
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -7,7 +7,7 @@ import { useControlAdapterModels } from './useControlAdapterModels';
export const useAddControlAdapter = (type: ControlAdapterType) => { export const useAddControlAdapter = (type: ControlAdapterType) => {
const baseModel = useAppSelector( const baseModel = useAppSelector(
(state) => state.generation.model?.base_model (s) => s.generation.model?.base_model
); );
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();

View File

@ -1,13 +1,15 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapter = (id: string) => { export const useControlAdapter = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) =>
selectControlAdapterById(controlAdapters, id) selectControlAdapterById(controlAdapters, id)
), ),
[id] [id]

View File

@ -1,13 +1,15 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterBeginEndStepPct = (id: string) => { export const useControlAdapterBeginEndStepPct = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => { createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
const cn = selectControlAdapterById(controlAdapters, id); const cn = selectControlAdapterById(controlAdapters, id);
return cn return cn
? { ? {

View File

@ -1,15 +1,17 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterControlImage = (id: string) => { export const useControlAdapterControlImage = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector( createMemoizedSelector(
stateSelector, selectControlAdaptersSlice,
({ controlAdapters }) => (controlAdapters) =>
selectControlAdapterById(controlAdapters, id)?.controlImage selectControlAdapterById(controlAdapters, id)?.controlImage
), ),
[id] [id]

View File

@ -1,14 +1,16 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNet } from 'features/controlAdapters/store/types'; import { isControlNet } from 'features/controlAdapters/store/types';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterControlMode = (id: string) => { export const useControlAdapterControlMode = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => { createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
const ca = selectControlAdapterById(controlAdapters, id); const ca = selectControlAdapterById(controlAdapters, id);
if (ca && isControlNet(ca)) { if (ca && isControlNet(ca)) {
return ca.controlMode; return ca.controlMode;

View File

@ -1,15 +1,17 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterIsEnabled = (id: string) => { export const useControlAdapterIsEnabled = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector( createMemoizedSelector(
stateSelector, selectControlAdaptersSlice,
({ controlAdapters }) => (controlAdapters) =>
selectControlAdapterById(controlAdapters, id)?.isEnabled ?? false selectControlAdapterById(controlAdapters, id)?.isEnabled ?? false
), ),
[id] [id]

View File

@ -1,15 +1,17 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterModel = (id: string) => { export const useControlAdapterModel = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector( createMemoizedSelector(
stateSelector, selectControlAdaptersSlice,
({ controlAdapters }) => (controlAdapters) =>
selectControlAdapterById(controlAdapters, id)?.model selectControlAdapterById(controlAdapters, id)?.model
), ),
[id] [id]

View File

@ -1,14 +1,16 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterProcessedControlImage = (id: string) => { export const useControlAdapterProcessedControlImage = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => { createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
const ca = selectControlAdapterById(controlAdapters, id); const ca = selectControlAdapterById(controlAdapters, id);
return ca && isControlNetOrT2IAdapter(ca) return ca && isControlNetOrT2IAdapter(ca)

View File

@ -1,14 +1,16 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterProcessorNode = (id: string) => { export const useControlAdapterProcessorNode = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => { createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
const ca = selectControlAdapterById(controlAdapters, id); const ca = selectControlAdapterById(controlAdapters, id);
return ca && isControlNetOrT2IAdapter(ca) return ca && isControlNetOrT2IAdapter(ca)

View File

@ -1,14 +1,16 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterProcessorType = (id: string) => { export const useControlAdapterProcessorType = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => { createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
const ca = selectControlAdapterById(controlAdapters, id); const ca = selectControlAdapterById(controlAdapters, id);
return ca && isControlNetOrT2IAdapter(ca) return ca && isControlNetOrT2IAdapter(ca)

View File

@ -1,14 +1,16 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterResizeMode = (id: string) => { export const useControlAdapterResizeMode = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => { createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
const ca = selectControlAdapterById(controlAdapters, id); const ca = selectControlAdapterById(controlAdapters, id);
if (ca && isControlNetOrT2IAdapter(ca)) { if (ca && isControlNetOrT2IAdapter(ca)) {
return ca.resizeMode; return ca.resizeMode;

View File

@ -1,14 +1,16 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterShouldAutoConfig = (id: string) => { export const useControlAdapterShouldAutoConfig = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ controlAdapters }) => { createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
const ca = selectControlAdapterById(controlAdapters, id); const ca = selectControlAdapterById(controlAdapters, id);
if (ca && isControlNetOrT2IAdapter(ca)) { if (ca && isControlNetOrT2IAdapter(ca)) {
return ca.shouldAutoConfig; return ca.shouldAutoConfig;

View File

@ -1,16 +1,17 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterType = (id: string) => { export const useControlAdapterType = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector( createMemoizedSelector(
stateSelector, selectControlAdaptersSlice,
({ controlAdapters }) => (controlAdapters) => selectControlAdapterById(controlAdapters, id)?.type
selectControlAdapterById(controlAdapters, id)?.type
), ),
[id] [id]
); );

View File

@ -1,15 +1,17 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectControlAdapterById } from 'features/controlAdapters/store/controlAdaptersSlice'; import {
selectControlAdapterById,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useMemo } from 'react'; import { useMemo } from 'react';
export const useControlAdapterWeight = (id: string) => { export const useControlAdapterWeight = (id: string) => {
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector( createMemoizedSelector(
stateSelector, selectControlAdaptersSlice,
({ controlAdapters }) => (controlAdapters) =>
selectControlAdapterById(controlAdapters, id)?.weight selectControlAdapterById(controlAdapters, id)?.weight
), ),
[id] [id]

View File

@ -1,6 +1,7 @@
import type { PayloadAction, Update } from '@reduxjs/toolkit'; import type { PayloadAction, Update } from '@reduxjs/toolkit';
import { createEntityAdapter, createSlice, isAnyOf } from '@reduxjs/toolkit'; import { createEntityAdapter, createSlice, isAnyOf } from '@reduxjs/toolkit';
import { getSelectorsOptions } from 'app/store/createMemoizedSelector'; import { getSelectorsOptions } from 'app/store/createMemoizedSelector';
import type { RootState } from 'app/store/store';
import { buildControlAdapter } from 'features/controlAdapters/util/buildControlAdapter'; import { buildControlAdapter } from 'features/controlAdapters/util/buildControlAdapter';
import type { import type {
ParameterControlNetModel, ParameterControlNetModel,
@ -489,3 +490,6 @@ export const isAnyControlAdapterAdded = isAnyOf(
controlAdapterAddedFromImage, controlAdapterAddedFromImage,
controlAdapterRecalled controlAdapterRecalled
); );
export const selectControlAdaptersSlice = (state: RootState) =>
state.controlAdapters;

View File

@ -12,7 +12,7 @@ type DeleteImageButtonProps = Omit<InvIconButtonProps, 'aria-label'> & {
export const DeleteImageButton = memo((props: DeleteImageButtonProps) => { export const DeleteImageButton = memo((props: DeleteImageButtonProps) => {
const { onClick, isDisabled } = props; const { onClick, isDisabled } = props;
const { t } = useTranslation(); const { t } = useTranslation();
const isConnected = useAppSelector((state) => state.system.isConnected); const isConnected = useAppSelector((s) => s.system.isConnected);
return ( return (
<InvIconButton <InvIconButton

View File

@ -1,11 +1,12 @@
import { Divider, Flex } from '@chakra-ui/react'; import { Divider, Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvConfirmationAlertDialog } from 'common/components/InvConfirmationAlertDialog/InvConfirmationAlertDialog'; import { InvConfirmationAlertDialog } from 'common/components/InvConfirmationAlertDialog/InvConfirmationAlertDialog';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSwitch } from 'common/components/InvSwitch/wrapper'; import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { InvText } from 'common/components/InvText/wrapper'; import { InvText } from 'common/components/InvText/wrapper';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { selectControlAdaptersSlice } from 'features/controlAdapters/store/controlAdaptersSlice';
import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions'; import { imageDeletionConfirmed } from 'features/deleteImageModal/store/actions';
import { import {
getImageUsage, getImageUsage,
@ -14,9 +15,16 @@ import {
import { import {
imageDeletionCanceled, imageDeletionCanceled,
isModalOpenChanged, isModalOpenChanged,
selectDeleteImageModalSlice,
} from 'features/deleteImageModal/store/slice'; } from 'features/deleteImageModal/store/slice';
import type { ImageUsage } from 'features/deleteImageModal/store/types'; import type { ImageUsage } from 'features/deleteImageModal/store/types';
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice'; import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
import { selectConfigSlice } from 'features/system/store/configSlice';
import {
selectSystemSlice,
setShouldConfirmOnDelete,
} from 'features/system/store/systemSlice';
import { some } from 'lodash-es'; import { some } from 'lodash-es';
import type { ChangeEvent } from 'react'; import type { ChangeEvent } from 'react';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
@ -25,15 +33,32 @@ import { useTranslation } from 'react-i18next';
import ImageUsageMessage from './ImageUsageMessage'; import ImageUsageMessage from './ImageUsageMessage';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector, selectImageUsage], [
(state, imagesUsage) => { selectSystemSlice,
const { system, config, deleteImageModal } = state; selectConfigSlice,
selectDeleteImageModalSlice,
selectGenerationSlice,
selectCanvasSlice,
selectNodesSlice,
selectControlAdaptersSlice,
selectImageUsage,
],
(
system,
config,
deleteImageModal,
generation,
canvas,
nodes,
controlAdapters,
imagesUsage
) => {
const { shouldConfirmOnDelete } = system; const { shouldConfirmOnDelete } = system;
const { canRestoreDeletedImagesFromBin } = config; const { canRestoreDeletedImagesFromBin } = config;
const { imagesToDelete, isModalOpen } = deleteImageModal; const { imagesToDelete, isModalOpen } = deleteImageModal;
const allImageUsage = (imagesToDelete ?? []).map(({ image_name }) => const allImageUsage = (imagesToDelete ?? []).map(({ image_name }) =>
getImageUsage(state, image_name) getImageUsage(generation, canvas, nodes, controlAdapters, image_name)
); );
const imageUsageSummary: ImageUsage = { const imageUsageSummary: ImageUsage = {

View File

@ -1,15 +1,30 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import type { RootState } from 'app/store/store'; import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { selectControlAdapterAll } from 'features/controlAdapters/store/controlAdaptersSlice'; import type { CanvasState } from 'features/canvas/store/canvasTypes';
import {
selectControlAdapterAll,
selectControlAdaptersSlice,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import type { ControlAdaptersState } from 'features/controlAdapters/store/types';
import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types'; import { isControlNetOrT2IAdapter } from 'features/controlAdapters/store/types';
import { selectDeleteImageModalSlice } from 'features/deleteImageModal/store/slice';
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
import type { NodesState } from 'features/nodes/store/types';
import { isImageFieldInputInstance } from 'features/nodes/types/field'; import { isImageFieldInputInstance } from 'features/nodes/types/field';
import { isInvocationNode } from 'features/nodes/types/invocation'; import { isInvocationNode } from 'features/nodes/types/invocation';
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
import type { GenerationState } from 'features/parameters/store/types';
import { some } from 'lodash-es'; import { some } from 'lodash-es';
import type { ImageUsage } from './types'; import type { ImageUsage } from './types';
export const getImageUsage = (state: RootState, image_name: string) => { export const getImageUsage = (
const { generation, canvas, nodes, controlAdapters } = state; generation: GenerationState,
canvas: CanvasState,
nodes: NodesState,
controlAdapters: ControlAdaptersState,
image_name: string
) => {
const isInitialImage = generation.initialImage?.imageName === image_name; const isInitialImage = generation.initialImage?.imageName === image_name;
const isCanvasImage = canvas.layerState.objects.some( const isCanvasImage = canvas.layerState.objects.some(
@ -42,16 +57,20 @@ export const getImageUsage = (state: RootState, image_name: string) => {
}; };
export const selectImageUsage = createMemoizedSelector( export const selectImageUsage = createMemoizedSelector(
[(state: RootState) => state], selectDeleteImageModalSlice,
(state) => { selectGenerationSlice,
const { imagesToDelete } = state.deleteImageModal; selectCanvasSlice,
selectNodesSlice,
selectControlAdaptersSlice,
(deleteImageModal, generation, canvas, nodes, controlAdapters) => {
const { imagesToDelete } = deleteImageModal;
if (!imagesToDelete.length) { if (!imagesToDelete.length) {
return []; return [];
} }
const imagesUsage = imagesToDelete.map((i) => const imagesUsage = imagesToDelete.map((i) =>
getImageUsage(state, i.image_name) getImageUsage(generation, canvas, nodes, controlAdapters, i.image_name)
); );
return imagesUsage; return imagesUsage;

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import type { ImageDTO } from 'services/api/types'; import type { ImageDTO } from 'services/api/types';
import { initialDeleteImageState } from './initialState'; import { initialDeleteImageState } from './initialState';
@ -28,3 +29,6 @@ export const {
} = deleteImageModal.actions; } = deleteImageModal.actions;
export default deleteImageModal.reducer; export default deleteImageModal.reducer;
export const selectDeleteImageModalSlice = (state: RootState) =>
state.deleteImageModal;

View File

@ -1,14 +1,14 @@
import type { Modifier } from '@dnd-kit/core'; import type { Modifier } from '@dnd-kit/core';
import { getEventCoordinates } from '@dnd-kit/utilities'; import { getEventCoordinates } from '@dnd-kit/utilities';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback } from 'react'; import { useCallback } from 'react';
const selectZoom = createMemoizedSelector( const selectZoom = createMemoizedSelector(
[stateSelector, activeTabNameSelector], [selectNodesSlice, activeTabNameSelector],
({ nodes }, activeTabName) => (nodes, activeTabName) =>
activeTabName === 'nodes' ? nodes.viewport.zoom : 1 activeTabName === 'nodes' ? nodes.viewport.zoom : 1
); );

View File

@ -1,5 +1,3 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSwitch } from 'common/components/InvSwitch/wrapper'; import { InvSwitch } from 'common/components/InvSwitch/wrapper';
@ -7,14 +5,8 @@ import { combinatorialToggled } from 'features/dynamicPrompts/store/dynamicPromp
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const selector = createMemoizedSelector(stateSelector, (state) => {
const { combinatorial } = state.dynamicPrompts;
return { combinatorial };
});
const ParamDynamicPromptsCombinatorial = () => { const ParamDynamicPromptsCombinatorial = () => {
const { combinatorial } = useAppSelector(selector); const combinatorial = useAppSelector((s) => s.dynamicPrompts.combinatorial);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -1,26 +1,33 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider'; import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { maxPromptsChanged } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; import {
maxPromptsChanged,
selectDynamicPromptsSlice,
} from 'features/dynamicPrompts/store/dynamicPromptsSlice';
import { selectConfigSlice } from 'features/system/store/configSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const selector = createMemoizedSelector(stateSelector, (state) => { const selector = createMemoizedSelector(
const { maxPrompts, combinatorial } = state.dynamicPrompts; selectDynamicPromptsSlice,
const { min, sliderMax, inputMax, initial } = selectConfigSlice,
state.config.sd.dynamicPrompts.maxPrompts; (dynamicPrompts, config) => {
const { maxPrompts, combinatorial } = dynamicPrompts;
const { min, sliderMax, inputMax, initial } =
config.sd.dynamicPrompts.maxPrompts;
return { return {
maxPrompts, maxPrompts,
min, min,
sliderMax, sliderMax,
inputMax, inputMax,
initial, initial,
isDisabled: !combinatorial, isDisabled: !combinatorial,
}; };
}); }
);
const ParamDynamicPromptsMaxPrompts = () => { const ParamDynamicPromptsMaxPrompts = () => {
const { maxPrompts, min, sliderMax, inputMax, initial, isDisabled } = const { maxPrompts, min, sliderMax, inputMax, initial, isDisabled } =

View File

@ -1,26 +1,29 @@
import type { ChakraProps } from '@chakra-ui/react'; import type { ChakraProps } from '@chakra-ui/react';
import { Flex, ListItem, OrderedList, Spinner } from '@chakra-ui/react'; import { Flex, ListItem, OrderedList, Spinner } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover'; import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
import { InvText } from 'common/components/InvText/wrapper'; import { InvText } from 'common/components/InvText/wrapper';
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FaCircleExclamation } from 'react-icons/fa6'; import { FaCircleExclamation } from 'react-icons/fa6';
const selector = createMemoizedSelector(stateSelector, (state) => { const selector = createMemoizedSelector(
const { isLoading, isError, prompts, parsingError } = state.dynamicPrompts; selectDynamicPromptsSlice,
(dynamicPrompts) => {
const { isLoading, isError, prompts, parsingError } = dynamicPrompts;
return { return {
prompts, prompts,
parsingError, parsingError,
isError, isError,
isLoading, isLoading,
}; };
}); }
);
const listItemStyles: ChakraProps['sx'] = { const listItemStyles: ChakraProps['sx'] = {
'&::marker': { color: 'base.500' }, '&::marker': { color: 'base.500' },

View File

@ -16,7 +16,7 @@ const ParamDynamicPromptsSeedBehaviour = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const seedBehaviour = useAppSelector( const seedBehaviour = useAppSelector(
(state) => state.dynamicPrompts.seedBehaviour (s) => s.dynamicPrompts.seedBehaviour
); );
const options = useMemo<InvSelectOption[]>(() => { const options = useMemo<InvSelectOption[]>(() => {

View File

@ -14,7 +14,7 @@ const loadingStyles: SystemStyleObject = {
export const ShowDynamicPromptsPreviewButton = memo(() => { export const ShowDynamicPromptsPreviewButton = memo(() => {
const { t } = useTranslation(); const { t } = useTranslation();
const isLoading = useAppSelector((state) => state.dynamicPrompts.isLoading); const isLoading = useAppSelector((s) => s.dynamicPrompts.isLoading);
const { isOpen, onOpen } = useDynamicPromptsModal(); const { isOpen, onOpen } = useDynamicPromptsModal();
return ( return (
<InvTooltip <InvTooltip

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import { z } from 'zod'; import { z } from 'zod';
export const zSeedBehaviour = z.enum(['PER_ITERATION', 'PER_PROMPT']); export const zSeedBehaviour = z.enum(['PER_ITERATION', 'PER_PROMPT']);
@ -74,3 +75,6 @@ export const {
} = dynamicPromptsSlice.actions; } = dynamicPromptsSlice.actions;
export default dynamicPromptsSlice.reducer; export default dynamicPromptsSlice.reducer;
export const selectDynamicPromptsSlice = (state: RootState) =>
state.dynamicPrompts;

View File

@ -18,7 +18,7 @@ export const EmbeddingSelect = memo(
const { t } = useTranslation(); const { t } = useTranslation();
const currentBaseModel = useAppSelector( const currentBaseModel = useAppSelector(
(state) => state.generation.model?.base_model (s) => s.generation.model?.base_model
); );
const getIsDisabled = useCallback( const getIsDisabled = useCallback(

View File

@ -1,5 +1,3 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSelect } from 'common/components/InvSelect/InvSelect'; import { InvSelect } from 'common/components/InvSelect/InvSelect';
@ -7,24 +5,22 @@ import type {
InvSelectOnChange, InvSelectOnChange,
InvSelectOption, InvSelectOption,
} from 'common/components/InvSelect/types'; } from 'common/components/InvSelect/types';
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice'; import {
autoAddBoardIdChanged,
} from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useListAllBoardsQuery } from 'services/api/endpoints/boards'; import { useListAllBoardsQuery } from 'services/api/endpoints/boards';
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
return {
autoAddBoardId,
autoAssignBoardOnClick,
};
});
const BoardAutoAddSelect = () => { const BoardAutoAddSelect = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const { autoAddBoardId, autoAssignBoardOnClick } = useAppSelector(selector); const autoAddBoardId = useAppSelector(
(s) => s.gallery.autoAddBoardId
);
const autoAssignBoardOnClick = useAppSelector(
(s) => s.gallery.autoAssignBoardOnClick
);
const { options, hasBoards } = useListAllBoardsQuery(undefined, { const { options, hasBoards } = useListAllBoardsQuery(undefined, {
selectFromResult: ({ data }) => { selectFromResult: ({ data }) => {
const options: InvSelectOption[] = [ const options: InvSelectOption[] = [

View File

@ -1,12 +1,14 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import type { InvContextMenuProps } from 'common/components/InvContextMenu/InvContextMenu'; import type { InvContextMenuProps } from 'common/components/InvContextMenu/InvContextMenu';
import { InvContextMenu } from 'common/components/InvContextMenu/InvContextMenu'; import { InvContextMenu } from 'common/components/InvContextMenu/InvContextMenu';
import { InvMenuItem } from 'common/components/InvMenu/InvMenuItem'; import { InvMenuItem } from 'common/components/InvMenu/InvMenuItem';
import { InvMenuList } from 'common/components/InvMenu/InvMenuList'; import { InvMenuList } from 'common/components/InvMenu/InvMenuList';
import { InvMenuGroup } from 'common/components/InvMenu/wrapper'; import { InvMenuGroup } from 'common/components/InvMenu/wrapper';
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice'; import {
autoAddBoardIdChanged,
selectGallerySlice,
} from 'features/gallery/store/gallerySlice';
import type { BoardId } from 'features/gallery/store/types'; import type { BoardId } from 'features/gallery/store/types';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { addToast } from 'features/system/store/systemSlice'; import { addToast } from 'features/system/store/systemSlice';
@ -38,7 +40,7 @@ const BoardContextMenu = ({
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ gallery }) => { createMemoizedSelector(selectGallerySlice, (gallery) => {
const isAutoAdd = gallery.autoAddBoardId === board_id; const isAutoAdd = gallery.autoAddBoardId === board_id;
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick; const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
return { isAutoAdd, autoAssignBoardOnClick }; return { isAutoAdd, autoAssignBoardOnClick };

View File

@ -1,6 +1,4 @@
import { Collapse, Flex, Grid, GridItem } from '@chakra-ui/react'; import { Collapse, Flex, Grid, GridItem } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants'; import { overlayScrollbarsParams } from 'common/components/OverlayScrollbars/constants';
import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal'; import DeleteBoardModal from 'features/gallery/components/Boards/DeleteBoardModal';
@ -20,18 +18,18 @@ const overlayScrollbarsStyles: CSSProperties = {
width: '100%', width: '100%',
}; };
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
const { selectedBoardId, boardSearchText } = gallery;
return { selectedBoardId, boardSearchText };
});
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
}; };
const BoardsList = (props: Props) => { const BoardsList = (props: Props) => {
const { isOpen } = props; const { isOpen } = props;
const { selectedBoardId, boardSearchText } = useAppSelector(selector); const selectedBoardId = useAppSelector(
(s) => s.gallery.selectedBoardId
);
const boardSearchText = useAppSelector(
(s) => s.gallery.boardSearchText
);
const { data: boards } = useListAllBoardsQuery(); const { data: boards } = useListAllBoardsQuery();
const filteredBoards = boardSearchText const filteredBoards = boardSearchText
? boards?.filter((board) => ? boards?.filter((board) =>

View File

@ -1,7 +1,5 @@
import { CloseIcon } from '@chakra-ui/icons'; import { CloseIcon } from '@chakra-ui/icons';
import { Input, InputGroup, InputRightElement } from '@chakra-ui/react'; import { Input, InputGroup, InputRightElement } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton'; import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import { boardSearchTextChanged } from 'features/gallery/store/gallerySlice'; import { boardSearchTextChanged } from 'features/gallery/store/gallerySlice';
@ -9,14 +7,9 @@ import type { ChangeEvent, KeyboardEvent } from 'react';
import { memo, useCallback, useEffect, useRef } from 'react'; import { memo, useCallback, useEffect, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
const { boardSearchText } = gallery;
return { boardSearchText };
});
const BoardsSearch = () => { const BoardsSearch = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { boardSearchText } = useAppSelector(selector); const boardSearchText = useAppSelector((s) => s.gallery.boardSearchText);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -10,7 +10,6 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIDroppable from 'common/components/IAIDroppable'; import IAIDroppable from 'common/components/IAIDroppable';
import { InvText } from 'common/components/InvText/wrapper'; import { InvText } from 'common/components/InvText/wrapper';
@ -22,6 +21,7 @@ import BoardContextMenu from 'features/gallery/components/Boards/BoardContextMen
import { import {
autoAddBoardIdChanged, autoAddBoardIdChanged,
boardIdSelected, boardIdSelected,
selectGallerySlice,
} from 'features/gallery/store/gallerySlice'; } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -56,7 +56,7 @@ const GalleryBoard = ({
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const selector = useMemo( const selector = useMemo(
() => () =>
createMemoizedSelector(stateSelector, ({ gallery }) => { createMemoizedSelector(selectGallerySlice, (gallery) => {
const isSelectedForAutoAdd = board.board_id === gallery.autoAddBoardId; const isSelectedForAutoAdd = board.board_id === gallery.autoAddBoardId;
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick; const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;

View File

@ -1,6 +1,4 @@
import { Box, Flex, Image } from '@chakra-ui/react'; import { Box, Flex, Image } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import InvokeAILogoImage from 'assets/images/logo.png'; import InvokeAILogoImage from 'assets/images/logo.png';
import IAIDroppable from 'common/components/IAIDroppable'; import IAIDroppable from 'common/components/IAIDroppable';
@ -26,14 +24,12 @@ interface Props {
isSelected: boolean; isSelected: boolean;
} }
const selector = createMemoizedSelector(stateSelector, ({ gallery }) => {
const { autoAddBoardId, autoAssignBoardOnClick } = gallery;
return { autoAddBoardId, autoAssignBoardOnClick };
});
const NoBoardBoard = memo(({ isSelected }: Props) => { const NoBoardBoard = memo(({ isSelected }: Props) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { autoAddBoardId, autoAssignBoardOnClick } = useAppSelector(selector); const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId);
const autoAssignBoardOnClick = useAppSelector(
(s) => s.gallery.autoAssignBoardOnClick
);
const boardName = useBoardName('none'); const boardName = useBoardName('none');
const handleSelectBoard = useCallback(() => { const handleSelectBoard = useCallback(() => {
dispatch(boardIdSelected({ boardId: 'none' })); dispatch(boardIdSelected({ boardId: 'none' }));

View File

@ -1,7 +1,6 @@
import { Flex, Skeleton } from '@chakra-ui/react'; import { Flex, Skeleton } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { import {
InvAlertDialog, InvAlertDialog,
@ -13,9 +12,13 @@ import {
} from 'common/components/InvAlertDialog/wrapper'; } from 'common/components/InvAlertDialog/wrapper';
import { InvButton } from 'common/components/InvButton/InvButton'; import { InvButton } from 'common/components/InvButton/InvButton';
import { InvText } from 'common/components/InvText/wrapper'; import { InvText } from 'common/components/InvText/wrapper';
import { selectCanvasSlice } from 'features/canvas/store/canvasSlice';
import { selectControlAdaptersSlice } from 'features/controlAdapters/store/controlAdaptersSlice';
import ImageUsageMessage from 'features/deleteImageModal/components/ImageUsageMessage'; import ImageUsageMessage from 'features/deleteImageModal/components/ImageUsageMessage';
import { getImageUsage } from 'features/deleteImageModal/store/selectors'; import { getImageUsage } from 'features/deleteImageModal/store/selectors';
import type { ImageUsage } from 'features/deleteImageModal/store/types'; import type { ImageUsage } from 'features/deleteImageModal/store/types';
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
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';
@ -35,26 +38,34 @@ const DeleteBoardModal = (props: Props) => {
const { boardToDelete, setBoardToDelete } = props; const { boardToDelete, setBoardToDelete } = props;
const { t } = useTranslation(); const { t } = useTranslation();
const canRestoreDeletedImagesFromBin = useAppSelector( const canRestoreDeletedImagesFromBin = useAppSelector(
(state) => state.config.canRestoreDeletedImagesFromBin (s) => s.config.canRestoreDeletedImagesFromBin
); );
const { currentData: boardImageNames, isFetching: isFetchingBoardNames } = const { currentData: boardImageNames, isFetching: isFetchingBoardNames } =
useListAllImageNamesForBoardQuery(boardToDelete?.board_id ?? skipToken); useListAllImageNamesForBoardQuery(boardToDelete?.board_id ?? skipToken);
const selectImageUsageSummary = useMemo( const selectImageUsageSummary = useMemo(
() => () =>
createMemoizedSelector([stateSelector], (state) => { createMemoizedSelector(
const allImageUsage = (boardImageNames ?? []).map((imageName) => [
getImageUsage(state, imageName) selectGenerationSlice,
); selectCanvasSlice,
selectNodesSlice,
selectControlAdaptersSlice,
],
(generation, canvas, nodes, controlAdapters) => {
const allImageUsage = (boardImageNames ?? []).map((imageName) =>
getImageUsage(generation, canvas, nodes, controlAdapters, imageName)
);
const imageUsageSummary: ImageUsage = { const imageUsageSummary: ImageUsage = {
isInitialImage: some(allImageUsage, (i) => i.isInitialImage), isInitialImage: some(allImageUsage, (i) => i.isInitialImage),
isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage), isCanvasImage: some(allImageUsage, (i) => i.isCanvasImage),
isNodesImage: some(allImageUsage, (i) => i.isNodesImage), isNodesImage: some(allImageUsage, (i) => i.isNodesImage),
isControlImage: some(allImageUsage, (i) => i.isControlImage), isControlImage: some(allImageUsage, (i) => i.isControlImage),
}; };
return { imageUsageSummary }; return { imageUsageSummary };
}), }
),
[boardImageNames] [boardImageNames]
); );

View File

@ -3,7 +3,6 @@ import { skipToken } from '@reduxjs/toolkit/query';
import { useAppToaster } from 'app/components/Toaster'; import { useAppToaster } from 'app/components/Toaster';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested'; import { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup'; import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton'; import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
@ -13,13 +12,17 @@ import { DeleteImageButton } from 'features/deleteImageModal/components/DeleteIm
import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice'; import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice';
import SingleSelectionMenuItems from 'features/gallery/components/ImageContextMenu/SingleSelectionMenuItems'; import SingleSelectionMenuItems from 'features/gallery/components/ImageContextMenu/SingleSelectionMenuItems';
import { sentImageToImg2Img } from 'features/gallery/store/actions'; import { sentImageToImg2Img } from 'features/gallery/store/actions';
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
import ParamUpscalePopover from 'features/parameters/components/Upscale/ParamUpscaleSettings'; import ParamUpscalePopover from 'features/parameters/components/Upscale/ParamUpscaleSettings';
import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters'; import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters';
import { initialImageSelected } from 'features/parameters/store/actions'; import { initialImageSelected } from 'features/parameters/store/actions';
import { useIsQueueMutationInProgress } from 'features/queue/hooks/useIsQueueMutationInProgress'; import { useIsQueueMutationInProgress } from 'features/queue/hooks/useIsQueueMutationInProgress';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { selectConfigSlice } from 'features/system/store/configSlice';
import { selectSystemSlice } from 'features/system/store/systemSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { import {
selectUiSlice,
setShouldShowImageDetails, setShouldShowImageDetails,
setShouldShowProgressInViewer, setShouldShowProgressInViewer,
} from 'features/ui/store/uiSlice'; } from 'features/ui/store/uiSlice';
@ -40,8 +43,14 @@ import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata'; import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata';
const currentImageButtonsSelector = createMemoizedSelector( const currentImageButtonsSelector = createMemoizedSelector(
[stateSelector, activeTabNameSelector], [
({ gallery, system, ui, config }, activeTabName) => { selectGallerySlice,
selectSystemSlice,
selectUiSlice,
selectConfigSlice,
activeTabNameSelector,
],
(gallery, system, ui, config, activeTabName) => {
const { isConnected, shouldConfirmOnDelete, denoiseProgress } = system; const { isConnected, shouldConfirmOnDelete, denoiseProgress } = system;
const { const {

View File

@ -1,7 +1,6 @@
import { Box, Flex } from '@chakra-ui/react'; import { Box, Flex } from '@chakra-ui/react';
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import IAIDndImage from 'common/components/IAIDndImage'; import IAIDndImage from 'common/components/IAIDndImage';
import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import { IAINoContentFallback } from 'common/components/IAIImageFallback';
@ -14,6 +13,8 @@ import ImageMetadataViewer from 'features/gallery/components/ImageMetadataViewer
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons'; import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
import { useNextPrevImage } from 'features/gallery/hooks/useNextPrevImage'; import { useNextPrevImage } from 'features/gallery/hooks/useNextPrevImage';
import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors'; import { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
import { selectSystemSlice } from 'features/system/store/systemSlice';
import { selectUiSlice } from 'features/ui/store/uiSlice';
import type { AnimationProps } from 'framer-motion'; import type { AnimationProps } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import type { CSSProperties } from 'react'; import type { CSSProperties } from 'react';
@ -24,8 +25,10 @@ import { FaImage } from 'react-icons/fa';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
export const imagesSelector = createMemoizedSelector( export const imagesSelector = createMemoizedSelector(
[stateSelector, selectLastSelectedImage], selectUiSlice,
({ ui, system }, lastSelectedImage) => { selectSystemSlice,
selectLastSelectedImage,
(ui, system, lastSelectedImage) => {
const { const {
shouldShowImageDetails, shouldShowImageDetails,
shouldHidePreview, shouldHidePreview,

View File

@ -5,10 +5,10 @@ import { memo, useMemo } from 'react';
const CurrentImagePreview = () => { const CurrentImagePreview = () => {
const progress_image = useAppSelector( const progress_image = useAppSelector(
(state) => state.system.denoiseProgress?.progress_image (s) => s.system.denoiseProgress?.progress_image
); );
const shouldAntialiasProgressImage = useAppSelector( const shouldAntialiasProgressImage = useAppSelector(
(state) => state.system.shouldAntialiasProgressImage (s) => s.system.shouldAntialiasProgressImage
); );
const sx = useMemo<SystemStyleObject>( const sx = useMemo<SystemStyleObject>(

View File

@ -1,17 +1,9 @@
import { ChevronUpIcon } from '@chakra-ui/icons'; import { ChevronUpIcon } from '@chakra-ui/icons';
import { Button, Flex, Spacer } from '@chakra-ui/react'; import { Button, Flex, Spacer } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useBoardName } from 'services/api/hooks/useBoardName'; import { useBoardName } from 'services/api/hooks/useBoardName';
const selector = createMemoizedSelector([stateSelector], (state) => {
const { selectedBoardId } = state.gallery;
return { selectedBoardId };
});
type Props = { type Props = {
isOpen: boolean; isOpen: boolean;
onToggle: () => void; onToggle: () => void;
@ -19,7 +11,7 @@ type Props = {
const GalleryBoardName = (props: Props) => { const GalleryBoardName = (props: Props) => {
const { isOpen, onToggle } = props; const { isOpen, onToggle } = props;
const { selectedBoardId } = useAppSelector(selector); const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId);
const boardName = useBoardName(selectedBoardId); const boardName = useBoardName(selectedBoardId);
const formattedBoardName = useMemo(() => { const formattedBoardName = useMemo(() => {

View File

@ -1,6 +1,5 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvCheckbox } from 'common/components/InvCheckbox/wrapper'; import { InvCheckbox } from 'common/components/InvCheckbox/wrapper';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
@ -15,6 +14,7 @@ import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { InvSwitch } from 'common/components/InvSwitch/wrapper'; import { InvSwitch } from 'common/components/InvSwitch/wrapper';
import { import {
autoAssignBoardOnClickChanged, autoAssignBoardOnClickChanged,
selectGallerySlice,
setGalleryImageMinimumWidth, setGalleryImageMinimumWidth,
shouldAutoSwitchChanged, shouldAutoSwitchChanged,
} from 'features/gallery/store/gallerySlice'; } from 'features/gallery/store/gallerySlice';
@ -25,9 +25,9 @@ import { FaWrench } from 'react-icons/fa';
import BoardAutoAddSelect from './Boards/BoardAutoAddSelect'; import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
const selector = createMemoizedSelector([stateSelector], (state) => { const selector = createMemoizedSelector(selectGallerySlice, (gallery) => {
const { galleryImageMinimumWidth, shouldAutoSwitch, autoAssignBoardOnClick } = const { galleryImageMinimumWidth, shouldAutoSwitch, autoAssignBoardOnClick } =
state.gallery; gallery;
return { return {
galleryImageMinimumWidth, galleryImageMinimumWidth,

View File

@ -1,5 +1,3 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import type { InvContextMenuProps } from 'common/components/InvContextMenu/InvContextMenu'; import type { InvContextMenuProps } from 'common/components/InvContextMenu/InvContextMenu';
import { InvContextMenu } from 'common/components/InvContextMenu/InvContextMenu'; import { InvContextMenu } from 'common/components/InvContextMenu/InvContextMenu';
@ -16,14 +14,8 @@ type Props = {
children: InvContextMenuProps<HTMLDivElement>['children']; children: InvContextMenuProps<HTMLDivElement>['children'];
}; };
const selector = createMemoizedSelector([stateSelector], ({ gallery }) => {
const selectionCount = gallery.selection.length;
return { selectionCount };
});
const ImageContextMenu = ({ imageDTO, children }: Props) => { const ImageContextMenu = ({ imageDTO, children }: Props) => {
const { selectionCount } = useAppSelector(selector); const selectionCount = useAppSelector((s) => s.gallery.selection.length);
const skipEvent = useCallback((e: MouseEvent<HTMLDivElement>) => { const skipEvent = useCallback((e: MouseEvent<HTMLDivElement>) => {
e.preventDefault(); e.preventDefault();

View File

@ -22,7 +22,7 @@ import {
const MultipleSelectionMenuItems = () => { const MultipleSelectionMenuItems = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const selection = useAppSelector((state) => state.gallery.selection); const selection = useAppSelector((s) => s.gallery.selection);
const customStarUi = useStore($customStarUI); const customStarUi = useStore($customStarUI);
const isBulkDownloadEnabled = const isBulkDownloadEnabled =

View File

@ -8,9 +8,7 @@ import {
VStack, VStack,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { $galleryHeader } from 'app/store/nanostores/galleryHeader'; import { $galleryHeader } from 'app/store/nanostores/galleryHeader';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvButton } from 'common/components/InvButton/InvButton'; import { InvButton } from 'common/components/InvButton/InvButton';
import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup'; import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup';
@ -24,19 +22,11 @@ import GalleryBoardName from './GalleryBoardName';
import GallerySettingsPopover from './GallerySettingsPopover'; import GallerySettingsPopover from './GallerySettingsPopover';
import GalleryImageGrid from './ImageGrid/GalleryImageGrid'; import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
const selector = createMemoizedSelector([stateSelector], (state) => {
const { galleryView } = state.gallery;
return {
galleryView,
};
});
const ImageGalleryContent = () => { const ImageGalleryContent = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const resizeObserverRef = useRef<HTMLDivElement>(null); const resizeObserverRef = useRef<HTMLDivElement>(null);
const galleryGridRef = useRef<HTMLDivElement>(null); const galleryGridRef = useRef<HTMLDivElement>(null);
const { galleryView } = useAppSelector(selector); const galleryView = useAppSelector((s) => s.gallery.galleryView);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const galleryHeader = useStore($galleryHeader); const galleryHeader = useStore($galleryHeader);
const { isOpen: isBoardListOpen, onToggle: onToggleBoardList } = const { isOpen: isBoardListOpen, onToggle: onToggleBoardList } =

View File

@ -45,7 +45,7 @@ const GalleryImageGrid = () => {
overlayScrollbarsParams overlayScrollbarsParams
); );
const selectedBoardId = useAppSelector( const selectedBoardId = useAppSelector(
(state) => state.gallery.selectedBoardId (s) => s.gallery.selectedBoardId
); );
const { currentViewTotal } = useBoardTotal(selectedBoardId); const { currentViewTotal } = useBoardTotal(selectedBoardId);
const queryArgs = useAppSelector(selectListImagesBaseQueryArgs); const queryArgs = useAppSelector(selectListImagesBaseQueryArgs);

View File

@ -1,8 +1,7 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors'; import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
import { selectionChanged } from 'features/gallery/store/gallerySlice'; import { selectGallerySlice, selectionChanged } from 'features/gallery/store/gallerySlice';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
@ -11,13 +10,11 @@ import type { ImageDTO } from 'services/api/types';
import { imagesSelectors } from 'services/api/util'; import { imagesSelectors } from 'services/api/util';
const selector = createMemoizedSelector( const selector = createMemoizedSelector(
[stateSelector, selectListImagesBaseQueryArgs], [selectGallerySlice, selectListImagesBaseQueryArgs],
({ gallery }, queryArgs) => { (gallery, queryArgs) => {
const selection = gallery.selection;
return { return {
queryArgs, queryArgs,
selection, selection: gallery.selection,
}; };
} }
); );

View File

@ -1,5 +1,5 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store'; import type { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
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';
@ -29,7 +29,7 @@ export const $useNextPrevImageState = map<UseNextPrevImageState>({
}); });
export const nextPrevImageButtonsSelector = createMemoizedSelector( export const nextPrevImageButtonsSelector = createMemoizedSelector(
[stateSelector, selectListImagesBaseQueryArgs], [(state: RootState) => state, selectListImagesBaseQueryArgs],
(state, baseQueryArgs) => { (state, baseQueryArgs) => {
const { data, status } = const { data, status } =
imagesApi.endpoints.listImages.select(baseQueryArgs)(state); imagesApi.endpoints.listImages.select(baseQueryArgs)(state);

View File

@ -12,7 +12,7 @@ export const gallerySelector = (state: RootState) => state.gallery;
export const selectLastSelectedImage = createMemoizedSelector( export const selectLastSelectedImage = createMemoizedSelector(
(state: RootState) => state, (state: RootState) => state,
(state) => state.gallery.selection[state.gallery.selection.length - 1] (s) => s.gallery.selection[state.gallery.selection.length - 1]
); );
export const selectListImagesBaseQueryArgs = createMemoizedSelector( export const selectListImagesBaseQueryArgs = createMemoizedSelector(

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice, isAnyOf } from '@reduxjs/toolkit'; import { createSlice, isAnyOf } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import { uniqBy } from 'lodash-es'; import { uniqBy } from 'lodash-es';
import { boardsApi } from 'services/api/endpoints/boards'; import { boardsApi } from 'services/api/endpoints/boards';
import { imagesApi } from 'services/api/endpoints/images'; import { imagesApi } from 'services/api/endpoints/images';
@ -103,3 +104,5 @@ const isAnyBoardDeleted = isAnyOf(
imagesApi.endpoints.deleteBoard.matchFulfilled, imagesApi.endpoints.deleteBoard.matchFulfilled,
imagesApi.endpoints.deleteBoardAndImages.matchFulfilled imagesApi.endpoints.deleteBoardAndImages.matchFulfilled
); );
export const selectGallerySlice = (state: RootState) => state.gallery;

View File

@ -9,7 +9,7 @@ import ParamHrfToggle from './ParamHrfToggle';
export const HrfSettings = memo(() => { export const HrfSettings = memo(() => {
const isHRFFeatureEnabled = useFeatureStatus('hrf').isFeatureEnabled; const isHRFFeatureEnabled = useFeatureStatus('hrf').isFeatureEnabled;
const hrfEnabled = useAppSelector((state) => state.hrf.hrfEnabled); const hrfEnabled = useAppSelector((s) => s.hrf.hrfEnabled);
if (!isHRFFeatureEnabled) { if (!isHRFFeatureEnabled) {
return null; return null;

View File

@ -18,7 +18,7 @@ const options: InvSelectOption[] = [
const ParamHrfMethodSelect = () => { const ParamHrfMethodSelect = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const hrfMethod = useAppSelector((state) => state.hrf.hrfMethod); const hrfMethod = useAppSelector((s) => s.hrf.hrfMethod);
const onChange = useCallback<InvSelectOnChange>( const onChange = useCallback<InvSelectOnChange>(
(v) => { (v) => {

View File

@ -1,27 +1,31 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSlider } from 'common/components/InvSlider/InvSlider'; import { InvSlider } from 'common/components/InvSlider/InvSlider';
import { setHrfStrength } from 'features/hrf/store/hrfSlice'; import { selectHrfSlice, setHrfStrength } from 'features/hrf/store/hrfSlice';
import { selectConfigSlice } from 'features/system/store/configSlice';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
const selector = createMemoizedSelector([stateSelector], ({ hrf, config }) => { const selector = createMemoizedSelector(
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } = selectHrfSlice,
config.sd.hrfStrength; selectConfigSlice,
const { hrfStrength } = hrf; (hrf, config) => {
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
config.sd.hrfStrength;
const { hrfStrength } = hrf;
return { return {
hrfStrength, hrfStrength,
initial, initial,
min, min,
sliderMax, sliderMax,
inputMax, inputMax,
step: coarseStep, step: coarseStep,
fineStep, fineStep,
}; };
}); }
);
const ParamHrfStrength = () => { const ParamHrfStrength = () => {
const { hrfStrength, initial, min, sliderMax, step, fineStep } = const { hrfStrength, initial, min, sliderMax, step, fineStep } =

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import type { import type {
ParameterHRFMethod, ParameterHRFMethod,
ParameterStrength, ParameterStrength,
@ -38,3 +39,5 @@ export const hrfSlice = createSlice({
export const { setHrfEnabled, setHrfStrength, setHrfMethod } = hrfSlice.actions; export const { setHrfEnabled, setHrfStrength, setHrfMethod } = hrfSlice.actions;
export default hrfSlice.reducer; export default hrfSlice.reducer;
export const selectHrfSlice = (state: RootState) => state.hrf;

View File

@ -1,12 +1,12 @@
import { Flex } from '@chakra-ui/layout'; import { Flex } from '@chakra-ui/layout';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { LoRACard } from 'features/lora/components/LoRACard'; import { LoRACard } from 'features/lora/components/LoRACard';
import { selectLoraSlice } from 'features/lora/store/loraSlice';
import { map } from 'lodash-es'; import { map } from 'lodash-es';
import { memo } from 'react'; import { memo } from 'react';
const selector = createMemoizedSelector(stateSelector, ({ lora }) => { const selector = createMemoizedSelector(selectLoraSlice, (lora) => {
return { lorasArray: map(lora.loras) }; return { lorasArray: map(lora.loras) };
}); });

View File

@ -1,17 +1,16 @@
import type { ChakraProps } from '@chakra-ui/react'; import type { ChakraProps } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { InvControl } from 'common/components/InvControl/InvControl'; import { InvControl } from 'common/components/InvControl/InvControl';
import { InvSelect } from 'common/components/InvSelect/InvSelect'; import { InvSelect } from 'common/components/InvSelect/InvSelect';
import { useGroupedModelInvSelect } from 'common/components/InvSelect/useGroupedModelInvSelect'; import { useGroupedModelInvSelect } from 'common/components/InvSelect/useGroupedModelInvSelect';
import { loraAdded } from 'features/lora/store/loraSlice'; import { loraAdded, selectLoraSlice } from 'features/lora/store/loraSlice';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import type { LoRAModelConfigEntity } from 'services/api/endpoints/models'; import type { LoRAModelConfigEntity } from 'services/api/endpoints/models';
import { useGetLoRAModelsQuery } from 'services/api/endpoints/models'; import { useGetLoRAModelsQuery } from 'services/api/endpoints/models';
const selector = createMemoizedSelector(stateSelector, ({ lora }) => ({ const selector = createMemoizedSelector(selectLoraSlice, (lora) => ({
addedLoRAs: lora.loras, addedLoRAs: lora.loras,
})); }));
@ -21,7 +20,7 @@ const LoRASelect = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { addedLoRAs } = useAppSelector(selector); const { addedLoRAs } = useAppSelector(selector);
const currentBaseModel = useAppSelector( const currentBaseModel = useAppSelector(
(state) => state.generation.model?.base_model (s) => s.generation.model?.base_model
); );
const getIsDisabled = (lora: LoRAModelConfigEntity): boolean => { const getIsDisabled = (lora: LoRAModelConfigEntity): boolean => {

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
import type { ParameterLoRAModel } from 'features/parameters/types/parameterSchemas'; import type { ParameterLoRAModel } from 'features/parameters/types/parameterSchemas';
import type { LoRAModelConfigEntity } from 'services/api/endpoints/models'; import type { LoRAModelConfigEntity } from 'services/api/endpoints/models';
@ -74,3 +75,5 @@ export const {
} = loraSlice.actions; } = loraSlice.actions;
export default loraSlice.reducer; export default loraSlice.reducer;
export const selectLoraSlice = (state: RootState) => state.lora;

View File

@ -1,5 +1,6 @@
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { RootState } from 'app/store/store';
type ModelManagerState = { type ModelManagerState = {
searchFolder: string | null; searchFolder: string | null;
@ -28,3 +29,5 @@ export const { setSearchFolder, setAdvancedAddScanModel } =
modelManagerSlice.actions; modelManagerSlice.actions;
export default modelManagerSlice.reducer; export default modelManagerSlice.reducer;
export const selectModelManagerSlice = (state: RootState) => state.modelmanager;

Some files were not shown because too many files have changed in this diff Show More