mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): update most other selectors
Just a few stragglers left. Good enough for now.
This commit is contained in:
parent
b71b14d582
commit
3c4150d153
@ -1,7 +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 { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
|
|
||||||
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';
|
||||||
import type { Accept, FileRejection } from 'react-dropzone';
|
import type { Accept, FileRejection } from 'react-dropzone';
|
||||||
@ -15,9 +14,9 @@ const accept: Accept = {
|
|||||||
'image/jpeg': ['.jpg', '.jpeg', '.png'],
|
'image/jpeg': ['.jpg', '.jpeg', '.png'],
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selectPostUploadAction = createMemoizedSelector(
|
||||||
[selectGallerySlice, activeTabNameSelector],
|
activeTabNameSelector,
|
||||||
(gallery, activeTabName) => {
|
(activeTabName) => {
|
||||||
let postUploadAction: PostUploadAction = { type: 'TOAST' };
|
let postUploadAction: PostUploadAction = { type: 'TOAST' };
|
||||||
|
|
||||||
if (activeTabName === 'unifiedCanvas') {
|
if (activeTabName === 'unifiedCanvas') {
|
||||||
@ -28,19 +27,15 @@ const selector = createMemoizedSelector(
|
|||||||
postUploadAction = { type: 'SET_INITIAL_IMAGE' };
|
postUploadAction = { type: 'SET_INITIAL_IMAGE' };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { autoAddBoardId } = gallery;
|
return postUploadAction;
|
||||||
|
|
||||||
return {
|
|
||||||
autoAddBoardId,
|
|
||||||
postUploadAction,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const useFullscreenDropzone = () => {
|
export const useFullscreenDropzone = () => {
|
||||||
const { autoAddBoardId, postUploadAction } = useAppSelector(selector);
|
|
||||||
const toaster = useAppToaster();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const toaster = useAppToaster();
|
||||||
|
const postUploadAction = useAppSelector(selectPostUploadAction);
|
||||||
|
const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId);
|
||||||
const [isHandlingUpload, setIsHandlingUpload] = useState<boolean>(false);
|
const [isHandlingUpload, setIsHandlingUpload] = useState<boolean>(false);
|
||||||
|
|
||||||
const [uploadImage] = useUploadImageMutation();
|
const [uploadImage] = useUploadImageMutation();
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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, selectCanvasSlice } from 'features/canvas/store/canvasSlice';
|
import { addLine } 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 type Konva from 'konva';
|
import type Konva from 'konva';
|
||||||
import type { KonvaEventObject } from 'konva/lib/Node';
|
import type { KonvaEventObject } from 'konva/lib/Node';
|
||||||
import type { MutableRefObject } from 'react';
|
import type { MutableRefObject } from 'react';
|
||||||
@ -15,20 +13,10 @@ import { useCallback } from 'react';
|
|||||||
|
|
||||||
import useColorPicker from './useColorUnderCursor';
|
import useColorPicker from './useColorUnderCursor';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
[activeTabNameSelector, selectCanvasSlice, isStagingSelector],
|
|
||||||
(activeTabName, canvas, isStaging) => {
|
|
||||||
return {
|
|
||||||
tool: canvas.tool,
|
|
||||||
activeTabName,
|
|
||||||
isStaging,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const useCanvasMouseDown = (stageRef: MutableRefObject<Konva.Stage | null>) => {
|
const useCanvasMouseDown = (stageRef: MutableRefObject<Konva.Stage | null>) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { tool, isStaging } = useAppSelector(selector);
|
const tool = useAppSelector((s) => s.canvas.tool);
|
||||||
|
const isStaging = useAppSelector(isStagingSelector);
|
||||||
const { commitColorUnderCursor } = useColorPicker();
|
const { commitColorUnderCursor } = useColorPicker();
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
|
@ -5,9 +5,7 @@ import {
|
|||||||
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 {
|
import { addPointToCurrentLine } from 'features/canvas/store/canvasSlice';
|
||||||
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 { Vector2d } from 'konva/lib/types';
|
import type { Vector2d } from 'konva/lib/types';
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||||
import type { RootState } from 'app/store/store';
|
|
||||||
|
|
||||||
import { selectCanvasSlice } from './canvasSlice';
|
import { selectCanvasSlice } from './canvasSlice';
|
||||||
import type { CanvasImage } from './canvasTypes';
|
|
||||||
import { isCanvasBaseImage } from './canvasTypes';
|
import { isCanvasBaseImage } from './canvasTypes';
|
||||||
|
|
||||||
export const isStagingSelector = createMemoizedSelector(
|
export const isStagingSelector = createSelector(
|
||||||
selectCanvasSlice,
|
selectCanvasSlice,
|
||||||
(canvas) =>
|
(canvas) =>
|
||||||
canvas.batchIds.length > 0 ||
|
canvas.batchIds.length > 0 ||
|
||||||
canvas.layerState.stagingArea.images.length > 0
|
canvas.layerState.stagingArea.images.length > 0
|
||||||
);
|
);
|
||||||
|
|
||||||
export const initialCanvasImageSelector = (
|
export const initialCanvasImageSelector = createMemoizedSelector(
|
||||||
state: RootState
|
selectCanvasSlice,
|
||||||
): CanvasImage | undefined =>
|
(canvas) => canvas.layerState.objects.find(isCanvasBaseImage)
|
||||||
state.canvas.layerState.objects.find(isCanvasBaseImage);
|
);
|
||||||
|
@ -22,23 +22,17 @@ import {
|
|||||||
useRemoveImagesFromBoardMutation,
|
useRemoveImagesFromBoardMutation,
|
||||||
} from 'services/api/endpoints/images';
|
} from 'services/api/endpoints/images';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selectImagesToChange = createMemoizedSelector(
|
||||||
selectChangeBoardModalSlice,
|
selectChangeBoardModalSlice,
|
||||||
(changeBoardModal) => {
|
(changeBoardModal) => changeBoardModal.imagesToChange
|
||||||
const { isModalOpen, imagesToChange } = changeBoardModal;
|
|
||||||
|
|
||||||
return {
|
|
||||||
isModalOpen,
|
|
||||||
imagesToChange,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ChangeBoardModal = () => {
|
const ChangeBoardModal = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [selectedBoard, setSelectedBoard] = useState<string | null>();
|
const [selectedBoard, setSelectedBoard] = useState<string | null>();
|
||||||
const { data: boards, isFetching } = useListAllBoardsQuery();
|
const { data: boards, isFetching } = useListAllBoardsQuery();
|
||||||
const { imagesToChange, isModalOpen } = useAppSelector(selector);
|
const isModalOpen = useAppSelector((s) => s.changeBoardModal.isModalOpen);
|
||||||
|
const imagesToChange = useAppSelector(selectImagesToChange);
|
||||||
const [addImagesToBoard] = useAddImagesToBoardMutation();
|
const [addImagesToBoard] = useAddImagesToBoardMutation();
|
||||||
const [removeImagesFromBoard] = useRemoveImagesFromBoardMutation();
|
const [removeImagesFromBoard] = useRemoveImagesFromBoardMutation();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -17,14 +17,11 @@ 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 { 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';
|
||||||
import { FaRulerVertical, FaSave, FaUndo } from 'react-icons/fa';
|
import { FaRulerVertical, FaSave, FaUndo } from 'react-icons/fa';
|
||||||
@ -41,42 +38,22 @@ type Props = {
|
|||||||
isSmall?: boolean;
|
isSmall?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selectPendingControlImages = createMemoizedSelector(
|
||||||
[
|
selectControlAdaptersSlice,
|
||||||
selectControlAdaptersSlice,
|
(controlAdapters) => controlAdapters.pendingControlImages
|
||||||
selectGallerySlice,
|
|
||||||
selectSystemSlice,
|
|
||||||
activeTabNameSelector,
|
|
||||||
selectOptimalDimension,
|
|
||||||
],
|
|
||||||
(controlAdapters, gallery, system, activeTabName, optimalDimension) => {
|
|
||||||
const { pendingControlImages } = controlAdapters;
|
|
||||||
const { autoAddBoardId } = gallery;
|
|
||||||
const { isConnected } = system;
|
|
||||||
|
|
||||||
return {
|
|
||||||
pendingControlImages,
|
|
||||||
autoAddBoardId,
|
|
||||||
isConnected,
|
|
||||||
activeTabName,
|
|
||||||
optimalDimension,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
const ControlAdapterImagePreview = ({ isSmall, id }: Props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
const controlImageName = useControlAdapterControlImage(id);
|
const controlImageName = useControlAdapterControlImage(id);
|
||||||
const processedControlImageName = useControlAdapterProcessedControlImage(id);
|
const processedControlImageName = useControlAdapterProcessedControlImage(id);
|
||||||
const processorType = useControlAdapterProcessorType(id);
|
const processorType = useControlAdapterProcessorType(id);
|
||||||
const dispatch = useAppDispatch();
|
const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId);
|
||||||
const { t } = useTranslation();
|
const isConnected = useAppSelector((s) => s.system.isConnected);
|
||||||
const {
|
const activeTabName = useAppSelector(selectActiveTabname);
|
||||||
pendingControlImages,
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
autoAddBoardId,
|
const pendingControlImages = useAppSelector(selectPendingControlImages);
|
||||||
isConnected,
|
|
||||||
activeTabName,
|
|
||||||
optimalDimension,
|
|
||||||
} = useAppSelector(selector);
|
|
||||||
|
|
||||||
const [isMouseOverImage, setIsMouseOverImage] = useState(false);
|
const [isMouseOverImage, setIsMouseOverImage] = useState(false);
|
||||||
|
|
||||||
|
@ -24,9 +24,10 @@ type ParamControlAdapterModelProps = {
|
|||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectGenerationSlice, (generation) => {
|
const selectMainModel = createMemoizedSelector(
|
||||||
return { mainModel: generation.model };
|
selectGenerationSlice,
|
||||||
});
|
(generation) => generation.model
|
||||||
|
);
|
||||||
|
|
||||||
const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
|
const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
|
||||||
const isEnabled = useControlAdapterIsEnabled(id);
|
const isEnabled = useControlAdapterIsEnabled(id);
|
||||||
@ -36,7 +37,7 @@ const ParamControlAdapterModel = ({ id }: ParamControlAdapterModelProps) => {
|
|||||||
const currentBaseModel = useAppSelector(
|
const currentBaseModel = useAppSelector(
|
||||||
(s) => s.generation.model?.base_model
|
(s) => s.generation.model?.base_model
|
||||||
);
|
);
|
||||||
const { mainModel } = useAppSelector(selector);
|
const { mainModel } = useAppSelector(selectMainModel);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const models = useControlAdapterModelEntities(controlAdapterType);
|
const models = useControlAdapterModelEntities(controlAdapterType);
|
||||||
|
@ -20,7 +20,7 @@ type Props = {
|
|||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createMemoizedSelector(configSelector, (config) => {
|
const selectOptions = createMemoizedSelector(configSelector, (config) => {
|
||||||
const options: InvSelectOption[] = map(CONTROLNET_PROCESSORS, (p) => ({
|
const options: InvSelectOption[] = map(CONTROLNET_PROCESSORS, (p) => ({
|
||||||
value: p.type,
|
value: p.type,
|
||||||
label: p.label,
|
label: p.label,
|
||||||
@ -47,7 +47,7 @@ const ParamControlAdapterProcessorSelect = ({ id }: Props) => {
|
|||||||
const isEnabled = useControlAdapterIsEnabled(id);
|
const isEnabled = useControlAdapterIsEnabled(id);
|
||||||
const processorNode = useControlAdapterProcessorNode(id);
|
const processorNode = useControlAdapterProcessorNode(id);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const options = useAppSelector(selector);
|
const options = useAppSelector(selectOptions);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const onChange = useCallback<InvSelectOnChange>(
|
const onChange = useCallback<InvSelectOnChange>(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
@ -9,7 +9,7 @@ import { useMemo } from 'react';
|
|||||||
export const useControlAdapterControlImage = (id: string) => {
|
export const useControlAdapterControlImage = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectControlAdaptersSlice,
|
selectControlAdaptersSlice,
|
||||||
(controlAdapters) =>
|
(controlAdapters) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.controlImage
|
selectControlAdapterById(controlAdapters, id)?.controlImage
|
||||||
@ -17,7 +17,7 @@ export const useControlAdapterControlImage = (id: string) => {
|
|||||||
[id]
|
[id]
|
||||||
);
|
);
|
||||||
|
|
||||||
const weight = useAppSelector(selector);
|
const controlImageName = useAppSelector(selector);
|
||||||
|
|
||||||
return weight;
|
return controlImageName;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
@ -10,7 +10,7 @@ import { useMemo } from 'react';
|
|||||||
export const useControlAdapterControlMode = (id: string) => {
|
export const useControlAdapterControlMode = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
createSelector(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;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
@ -9,7 +9,7 @@ import { useMemo } from 'react';
|
|||||||
export const useControlAdapterIsEnabled = (id: string) => {
|
export const useControlAdapterIsEnabled = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectControlAdaptersSlice,
|
selectControlAdaptersSlice,
|
||||||
(controlAdapters) =>
|
(controlAdapters) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.isEnabled ?? false
|
selectControlAdapterById(controlAdapters, id)?.isEnabled ?? false
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
@ -10,7 +10,7 @@ import { useMemo } from 'react';
|
|||||||
export const useControlAdapterProcessedControlImage = (id: string) => {
|
export const useControlAdapterProcessedControlImage = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
createSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
|
|
||||||
return ca && isControlNetOrT2IAdapter(ca)
|
return ca && isControlNetOrT2IAdapter(ca)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
@ -10,7 +10,7 @@ import { useMemo } from 'react';
|
|||||||
export const useControlAdapterProcessorType = (id: string) => {
|
export const useControlAdapterProcessorType = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
createSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
||||||
const ca = selectControlAdapterById(controlAdapters, id);
|
const ca = selectControlAdapterById(controlAdapters, id);
|
||||||
|
|
||||||
return ca && isControlNetOrT2IAdapter(ca)
|
return ca && isControlNetOrT2IAdapter(ca)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
@ -10,7 +10,7 @@ import { useMemo } from 'react';
|
|||||||
export const useControlAdapterShouldAutoConfig = (id: string) => {
|
export const useControlAdapterShouldAutoConfig = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectControlAdaptersSlice, (controlAdapters) => {
|
createSelector(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;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import {
|
import {
|
||||||
selectControlAdapterById,
|
selectControlAdapterById,
|
||||||
@ -9,7 +9,7 @@ import { useMemo } from 'react';
|
|||||||
export const useControlAdapterWeight = (id: string) => {
|
export const useControlAdapterWeight = (id: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectControlAdaptersSlice,
|
selectControlAdaptersSlice,
|
||||||
(controlAdapters) =>
|
(controlAdapters) =>
|
||||||
selectControlAdapterById(controlAdapters, id)?.weight
|
selectControlAdapterById(controlAdapters, id)?.weight
|
||||||
|
@ -20,11 +20,7 @@ import {
|
|||||||
import type { ImageUsage } from 'features/deleteImageModal/store/types';
|
import type { ImageUsage } from 'features/deleteImageModal/store/types';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
import { setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
||||||
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';
|
||||||
@ -32,10 +28,8 @@ import { useTranslation } from 'react-i18next';
|
|||||||
|
|
||||||
import ImageUsageMessage from './ImageUsageMessage';
|
import ImageUsageMessage from './ImageUsageMessage';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selectImageUsages = createMemoizedSelector(
|
||||||
[
|
[
|
||||||
selectSystemSlice,
|
|
||||||
selectConfigSlice,
|
|
||||||
selectDeleteImageModalSlice,
|
selectDeleteImageModalSlice,
|
||||||
selectGenerationSlice,
|
selectGenerationSlice,
|
||||||
selectCanvasSlice,
|
selectCanvasSlice,
|
||||||
@ -44,8 +38,6 @@ const selector = createMemoizedSelector(
|
|||||||
selectImageUsage,
|
selectImageUsage,
|
||||||
],
|
],
|
||||||
(
|
(
|
||||||
system,
|
|
||||||
config,
|
|
||||||
deleteImageModal,
|
deleteImageModal,
|
||||||
generation,
|
generation,
|
||||||
canvas,
|
canvas,
|
||||||
@ -53,9 +45,7 @@ const selector = createMemoizedSelector(
|
|||||||
controlAdapters,
|
controlAdapters,
|
||||||
imagesUsage
|
imagesUsage
|
||||||
) => {
|
) => {
|
||||||
const { shouldConfirmOnDelete } = system;
|
const { imagesToDelete } = deleteImageModal;
|
||||||
const { canRestoreDeletedImagesFromBin } = config;
|
|
||||||
const { imagesToDelete, isModalOpen } = deleteImageModal;
|
|
||||||
|
|
||||||
const allImageUsage = (imagesToDelete ?? []).map(({ image_name }) =>
|
const allImageUsage = (imagesToDelete ?? []).map(({ image_name }) =>
|
||||||
getImageUsage(generation, canvas, nodes, controlAdapters, image_name)
|
getImageUsage(generation, canvas, nodes, controlAdapters, image_name)
|
||||||
@ -69,11 +59,8 @@ const selector = createMemoizedSelector(
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
shouldConfirmOnDelete,
|
|
||||||
canRestoreDeletedImagesFromBin,
|
|
||||||
imagesToDelete,
|
imagesToDelete,
|
||||||
imagesUsage,
|
imagesUsage,
|
||||||
isModalOpen,
|
|
||||||
imageUsageSummary,
|
imageUsageSummary,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -82,15 +69,15 @@ const selector = createMemoizedSelector(
|
|||||||
const DeleteImageModal = () => {
|
const DeleteImageModal = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const shouldConfirmOnDelete = useAppSelector(
|
||||||
const {
|
(s) => s.system.shouldConfirmOnDelete
|
||||||
shouldConfirmOnDelete,
|
);
|
||||||
canRestoreDeletedImagesFromBin,
|
const canRestoreDeletedImagesFromBin = useAppSelector(
|
||||||
imagesToDelete,
|
(s) => s.config.canRestoreDeletedImagesFromBin
|
||||||
imagesUsage,
|
);
|
||||||
isModalOpen,
|
const isModalOpen = useAppSelector((s) => s.deleteImageModal.isModalOpen);
|
||||||
imageUsageSummary,
|
const { imagesToDelete, imagesUsage, imageUsageSummary } =
|
||||||
} = useAppSelector(selector);
|
useAppSelector(selectImageUsages);
|
||||||
|
|
||||||
const handleChangeShouldConfirmOnDelete = useCallback(
|
const handleChangeShouldConfirmOnDelete = useCallback(
|
||||||
(e: ChangeEvent<HTMLInputElement>) =>
|
(e: ChangeEvent<HTMLInputElement>) =>
|
||||||
|
@ -1,37 +1,23 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 {
|
import { maxPromptsChanged } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||||
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(
|
|
||||||
selectDynamicPromptsSlice,
|
|
||||||
selectConfigSlice,
|
|
||||||
(dynamicPrompts, config) => {
|
|
||||||
const { maxPrompts, combinatorial } = dynamicPrompts;
|
|
||||||
const { min, sliderMax, inputMax, initial } =
|
|
||||||
config.sd.dynamicPrompts.maxPrompts;
|
|
||||||
|
|
||||||
return {
|
|
||||||
maxPrompts,
|
|
||||||
min,
|
|
||||||
sliderMax,
|
|
||||||
inputMax,
|
|
||||||
initial,
|
|
||||||
isDisabled: !combinatorial,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamDynamicPromptsMaxPrompts = () => {
|
const ParamDynamicPromptsMaxPrompts = () => {
|
||||||
const { maxPrompts, min, sliderMax, inputMax, initial, isDisabled } =
|
const maxPrompts = useAppSelector((s) => s.dynamicPrompts.maxPrompts);
|
||||||
useAppSelector(selector);
|
const min = useAppSelector((s) => s.config.sd.dynamicPrompts.maxPrompts.min);
|
||||||
|
const sliderMax = useAppSelector(
|
||||||
|
(s) => s.config.sd.dynamicPrompts.maxPrompts.sliderMax
|
||||||
|
);
|
||||||
|
const inputMax = useAppSelector(
|
||||||
|
(s) => s.config.sd.dynamicPrompts.maxPrompts.inputMax
|
||||||
|
);
|
||||||
|
const initial = useAppSelector(
|
||||||
|
(s) => s.config.sd.dynamicPrompts.maxPrompts.initial
|
||||||
|
);
|
||||||
|
const isDisabled = useAppSelector((s) => !s.dynamicPrompts.combinatorial);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -11,18 +11,9 @@ 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(
|
const selectPrompts = createMemoizedSelector(
|
||||||
selectDynamicPromptsSlice,
|
selectDynamicPromptsSlice,
|
||||||
(dynamicPrompts) => {
|
(dynamicPrompts) => dynamicPrompts.prompts
|
||||||
const { isLoading, isError, prompts, parsingError } = dynamicPrompts;
|
|
||||||
|
|
||||||
return {
|
|
||||||
prompts,
|
|
||||||
parsingError,
|
|
||||||
isError,
|
|
||||||
isLoading,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const listItemStyles: ChakraProps['sx'] = {
|
const listItemStyles: ChakraProps['sx'] = {
|
||||||
@ -31,8 +22,10 @@ const listItemStyles: ChakraProps['sx'] = {
|
|||||||
|
|
||||||
const ParamDynamicPromptsPreview = () => {
|
const ParamDynamicPromptsPreview = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { prompts, parsingError, isLoading, isError } =
|
const parsingError = useAppSelector((s) => s.dynamicPrompts.parsingError);
|
||||||
useAppSelector(selector);
|
const isError = useAppSelector((s) => s.dynamicPrompts.isError);
|
||||||
|
const isLoading = useAppSelector((s) => s.dynamicPrompts.isLoading);
|
||||||
|
const prompts = useAppSelector(selectPrompts);
|
||||||
|
|
||||||
const label = useMemo(() => {
|
const label = useMemo(() => {
|
||||||
let _label = `${t('dynamicPrompts.promptsPreview')} (${prompts.length})`;
|
let _label = `${t('dynamicPrompts.promptsPreview')} (${prompts.length})`;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
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';
|
||||||
@ -37,18 +37,19 @@ const BoardContextMenu = ({
|
|||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
const autoAssignBoardOnClick = useAppSelector(
|
||||||
const selector = useMemo(
|
(s) => s.gallery.autoAssignBoardOnClick
|
||||||
|
);
|
||||||
|
const selectIsSelectedForAutoAdd = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectGallerySlice, (gallery) => {
|
createSelector(
|
||||||
const isAutoAdd = gallery.autoAddBoardId === board_id;
|
selectGallerySlice,
|
||||||
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
(gallery) => board && board.board_id === gallery.autoAddBoardId
|
||||||
return { isAutoAdd, autoAssignBoardOnClick };
|
),
|
||||||
}),
|
[board]
|
||||||
[board_id]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isAutoAdd, autoAssignBoardOnClick } = useAppSelector(selector);
|
const isSelectedForAutoAdd = useAppSelector(selectIsSelectedForAutoAdd);
|
||||||
const boardName = useBoardName(board_id);
|
const boardName = useBoardName(board_id);
|
||||||
const isBulkDownloadEnabled =
|
const isBulkDownloadEnabled =
|
||||||
useFeatureStatus('bulkDownload').isFeatureEnabled;
|
useFeatureStatus('bulkDownload').isFeatureEnabled;
|
||||||
@ -99,7 +100,7 @@ const BoardContextMenu = ({
|
|||||||
<InvMenuGroup title={boardName}>
|
<InvMenuGroup title={boardName}>
|
||||||
<InvMenuItem
|
<InvMenuItem
|
||||||
icon={<FaPlus />}
|
icon={<FaPlus />}
|
||||||
isDisabled={isAutoAdd || autoAssignBoardOnClick}
|
isDisabled={isSelectedForAutoAdd || autoAssignBoardOnClick}
|
||||||
onClick={handleSetAutoAdd}
|
onClick={handleSetAutoAdd}
|
||||||
>
|
>
|
||||||
{t('boards.menuItemAutoAdd')}
|
{t('boards.menuItemAutoAdd')}
|
||||||
@ -127,8 +128,8 @@ const BoardContextMenu = ({
|
|||||||
boardName,
|
boardName,
|
||||||
handleBulkDownload,
|
handleBulkDownload,
|
||||||
handleSetAutoAdd,
|
handleSetAutoAdd,
|
||||||
isAutoAdd,
|
|
||||||
isBulkDownloadEnabled,
|
isBulkDownloadEnabled,
|
||||||
|
isSelectedForAutoAdd,
|
||||||
setBoardToDelete,
|
setBoardToDelete,
|
||||||
skipEvent,
|
skipEvent,
|
||||||
t,
|
t,
|
||||||
|
@ -8,8 +8,8 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
Image,
|
Image,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { skipToken } from '@reduxjs/toolkit/query';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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';
|
||||||
@ -54,22 +54,19 @@ const GalleryBoard = ({
|
|||||||
setBoardToDelete,
|
setBoardToDelete,
|
||||||
}: GalleryBoardProps) => {
|
}: GalleryBoardProps) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const selector = useMemo(
|
const autoAssignBoardOnClick = useAppSelector(
|
||||||
|
(s) => s.gallery.autoAssignBoardOnClick
|
||||||
|
);
|
||||||
|
const selectIsSelectedForAutoAdd = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectGallerySlice, (gallery) => {
|
createSelector(
|
||||||
const isSelectedForAutoAdd = board.board_id === gallery.autoAddBoardId;
|
selectGallerySlice,
|
||||||
const autoAssignBoardOnClick = gallery.autoAssignBoardOnClick;
|
(gallery) => board.board_id === gallery.autoAddBoardId
|
||||||
|
),
|
||||||
return {
|
|
||||||
isSelectedForAutoAdd,
|
|
||||||
autoAssignBoardOnClick,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
[board.board_id]
|
[board.board_id]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isSelectedForAutoAdd, autoAssignBoardOnClick } =
|
const isSelectedForAutoAdd = useAppSelector(selectIsSelectedForAutoAdd);
|
||||||
useAppSelector(selector);
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const handleMouseOver = useCallback(() => {
|
const handleMouseOver = useCallback(() => {
|
||||||
setIsHovered(true);
|
setIsHovered(true);
|
||||||
|
@ -63,7 +63,8 @@ const DeleteBoardModal = (props: Props) => {
|
|||||||
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]
|
||||||
@ -75,7 +76,7 @@ const DeleteBoardModal = (props: Props) => {
|
|||||||
const [deleteBoardAndImages, { isLoading: isDeleteBoardAndImagesLoading }] =
|
const [deleteBoardAndImages, { isLoading: isDeleteBoardAndImagesLoading }] =
|
||||||
useDeleteBoardAndImagesMutation();
|
useDeleteBoardAndImagesMutation();
|
||||||
|
|
||||||
const { imageUsageSummary } = useAppSelector(selectImageUsageSummary);
|
const imageUsageSummary = useAppSelector(selectImageUsageSummary);
|
||||||
|
|
||||||
const handleDeleteBoardOnly = useCallback(() => {
|
const handleDeleteBoardOnly = useCallback(() => {
|
||||||
if (!boardToDelete) {
|
if (!boardToDelete) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { skipToken } from '@reduxjs/toolkit/query';
|
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 { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested';
|
import { upscaleRequested } from 'app/store/middleware/listenerMiddleware/listeners/upscaleRequested';
|
||||||
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';
|
||||||
@ -12,17 +12,15 @@ 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 { selectLastSelectedImage } from 'features/gallery/store/gallerySelectors';
|
||||||
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
|
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 { selectSystemSlice } from 'features/system/store/systemSlice';
|
||||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
|
||||||
import {
|
import {
|
||||||
selectUiSlice,
|
|
||||||
setShouldShowImageDetails,
|
setShouldShowImageDetails,
|
||||||
setShouldShowProgressInViewer,
|
setShouldShowProgressInViewer,
|
||||||
} from 'features/ui/store/uiSlice';
|
} from 'features/ui/store/uiSlice';
|
||||||
@ -42,51 +40,29 @@ import { FaCircleNodes, FaEllipsis } from 'react-icons/fa6';
|
|||||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
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 selectShouldDisableToolbarButtons = createSelector(
|
||||||
[
|
selectSystemSlice,
|
||||||
selectGallerySlice,
|
selectGallerySlice,
|
||||||
selectSystemSlice,
|
selectLastSelectedImage,
|
||||||
selectUiSlice,
|
(system, gallery, lastSelectedImage) => {
|
||||||
selectConfigSlice,
|
const hasProgressImage = Boolean(system.denoiseProgress?.progress_image);
|
||||||
activeTabNameSelector,
|
return hasProgressImage || !lastSelectedImage;
|
||||||
],
|
|
||||||
(gallery, system, ui, config, activeTabName) => {
|
|
||||||
const { isConnected, shouldConfirmOnDelete, denoiseProgress } = system;
|
|
||||||
|
|
||||||
const {
|
|
||||||
shouldShowImageDetails,
|
|
||||||
shouldHidePreview,
|
|
||||||
shouldShowProgressInViewer,
|
|
||||||
} = ui;
|
|
||||||
|
|
||||||
const { shouldFetchMetadataFromApi } = config;
|
|
||||||
|
|
||||||
const lastSelectedImage = gallery.selection[gallery.selection.length - 1];
|
|
||||||
|
|
||||||
return {
|
|
||||||
shouldConfirmOnDelete,
|
|
||||||
isConnected,
|
|
||||||
shouldDisableToolbarButtons:
|
|
||||||
Boolean(denoiseProgress?.progress_image) || !lastSelectedImage,
|
|
||||||
shouldShowImageDetails,
|
|
||||||
activeTabName,
|
|
||||||
shouldHidePreview,
|
|
||||||
shouldShowProgressInViewer,
|
|
||||||
lastSelectedImage,
|
|
||||||
shouldFetchMetadataFromApi,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const CurrentImageButtons = () => {
|
const CurrentImageButtons = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const {
|
const isConnected = useAppSelector((s) => s.system.isConnected);
|
||||||
isConnected,
|
const shouldShowImageDetails = useAppSelector(
|
||||||
shouldDisableToolbarButtons,
|
(s) => s.ui.shouldShowImageDetails
|
||||||
shouldShowImageDetails,
|
);
|
||||||
lastSelectedImage,
|
const shouldShowProgressInViewer = useAppSelector(
|
||||||
shouldShowProgressInViewer,
|
(s) => s.ui.shouldShowProgressInViewer
|
||||||
} = useAppSelector(currentImageButtonsSelector);
|
);
|
||||||
|
const lastSelectedImage = useAppSelector(selectLastSelectedImage);
|
||||||
|
const shouldDisableToolbarButtons = useAppSelector(
|
||||||
|
selectShouldDisableToolbarButtons
|
||||||
|
);
|
||||||
|
|
||||||
const isUpscalingEnabled = useFeatureStatus('upscaling').isFeatureEnabled;
|
const isUpscalingEnabled = useFeatureStatus('upscaling').isFeatureEnabled;
|
||||||
const isQueueMutationInProgress = useIsQueueMutationInProgress();
|
const isQueueMutationInProgress = useIsQueueMutationInProgress();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Box, Flex } from '@chakra-ui/react';
|
import { Box, Flex } from '@chakra-ui/react';
|
||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { skipToken } from '@reduxjs/toolkit/query';
|
import { skipToken } from '@reduxjs/toolkit/query';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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';
|
||||||
@ -13,8 +13,6 @@ 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,34 +22,22 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { FaImage } from 'react-icons/fa';
|
import { FaImage } from 'react-icons/fa';
|
||||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
export const imagesSelector = createMemoizedSelector(
|
const selectLastSelectedImageName = createSelector(
|
||||||
selectUiSlice,
|
|
||||||
selectSystemSlice,
|
|
||||||
selectLastSelectedImage,
|
selectLastSelectedImage,
|
||||||
(ui, system, lastSelectedImage) => {
|
(lastSelectedImage) => lastSelectedImage?.image_name
|
||||||
const {
|
|
||||||
shouldShowImageDetails,
|
|
||||||
shouldHidePreview,
|
|
||||||
shouldShowProgressInViewer,
|
|
||||||
} = ui;
|
|
||||||
const { denoiseProgress } = system;
|
|
||||||
return {
|
|
||||||
shouldShowImageDetails,
|
|
||||||
shouldHidePreview,
|
|
||||||
imageName: lastSelectedImage?.image_name,
|
|
||||||
hasDenoiseProgress: Boolean(denoiseProgress),
|
|
||||||
shouldShowProgressInViewer,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const CurrentImagePreview = () => {
|
const CurrentImagePreview = () => {
|
||||||
const {
|
const shouldShowImageDetails = useAppSelector(
|
||||||
shouldShowImageDetails,
|
(s) => s.ui.shouldShowImageDetails
|
||||||
imageName,
|
);
|
||||||
hasDenoiseProgress,
|
const imageName = useAppSelector(selectLastSelectedImageName);
|
||||||
shouldShowProgressInViewer,
|
const hasDenoiseProgress = useAppSelector((s) =>
|
||||||
} = useAppSelector(imagesSelector);
|
Boolean(s.system.denoiseProgress)
|
||||||
|
);
|
||||||
|
const shouldShowProgressInViewer = useAppSelector(
|
||||||
|
(s) => s.ui.shouldShowProgressInViewer
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handlePrevImage,
|
handlePrevImage,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Flex } from '@chakra-ui/react';
|
import { Flex } from '@chakra-ui/react';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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';
|
||||||
@ -14,7 +13,6 @@ 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,23 +23,16 @@ import { FaWrench } from 'react-icons/fa';
|
|||||||
|
|
||||||
import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
|
import BoardAutoAddSelect from './Boards/BoardAutoAddSelect';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectGallerySlice, (gallery) => {
|
|
||||||
const { galleryImageMinimumWidth, shouldAutoSwitch, autoAssignBoardOnClick } =
|
|
||||||
gallery;
|
|
||||||
|
|
||||||
return {
|
|
||||||
galleryImageMinimumWidth,
|
|
||||||
shouldAutoSwitch,
|
|
||||||
autoAssignBoardOnClick,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const GallerySettingsPopover = () => {
|
const GallerySettingsPopover = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const galleryImageMinimumWidth = useAppSelector(
|
||||||
const { galleryImageMinimumWidth, shouldAutoSwitch, autoAssignBoardOnClick } =
|
(s) => s.gallery.galleryImageMinimumWidth
|
||||||
useAppSelector(selector);
|
);
|
||||||
|
const shouldAutoSwitch = useAppSelector((s) => s.gallery.shouldAutoSwitch);
|
||||||
|
const autoAssignBoardOnClick = useAppSelector(
|
||||||
|
(s) => s.gallery.autoAssignBoardOnClick
|
||||||
|
);
|
||||||
|
|
||||||
const handleChangeGalleryImageMinimumWidth = useCallback(
|
const handleChangeGalleryImageMinimumWidth = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
|
@ -1,39 +1,21 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 { selectHrfSlice, setHrfStrength } from 'features/hrf/store/hrfSlice';
|
import { 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(
|
|
||||||
selectHrfSlice,
|
|
||||||
selectConfigSlice,
|
|
||||||
(hrf, config) => {
|
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
|
||||||
config.sd.hrfStrength;
|
|
||||||
const { hrfStrength } = hrf;
|
|
||||||
|
|
||||||
return {
|
|
||||||
hrfStrength,
|
|
||||||
initial,
|
|
||||||
min,
|
|
||||||
sliderMax,
|
|
||||||
inputMax,
|
|
||||||
step: coarseStep,
|
|
||||||
fineStep,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamHrfStrength = () => {
|
const ParamHrfStrength = () => {
|
||||||
const { hrfStrength, initial, min, sliderMax, step, fineStep } =
|
const hrfStrength = useAppSelector((s) => s.hrf.hrfStrength);
|
||||||
useAppSelector(selector);
|
const initial = useAppSelector((s) => s.config.sd.hrfStrength.initial);
|
||||||
|
const min = useAppSelector((s) => s.config.sd.hrfStrength.min);
|
||||||
|
const sliderMax = useAppSelector((s) => s.config.sd.hrfStrength.sliderMax);
|
||||||
|
const coarseStep = useAppSelector((s) => s.config.sd.hrfStrength.coarseStep);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.hrfStrength.fineStep);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleHrfStrengthChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
dispatch(setHrfStrength(v));
|
dispatch(setHrfStrength(v));
|
||||||
},
|
},
|
||||||
@ -45,11 +27,11 @@ const ParamHrfStrength = () => {
|
|||||||
<InvSlider
|
<InvSlider
|
||||||
min={min}
|
min={min}
|
||||||
max={sliderMax}
|
max={sliderMax}
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
value={hrfStrength}
|
value={hrfStrength}
|
||||||
defaultValue={initial}
|
defaultValue={initial}
|
||||||
onChange={handleHrfStrengthChange}
|
onChange={onChange}
|
||||||
marks
|
marks
|
||||||
withNumberInput
|
withNumberInput
|
||||||
/>
|
/>
|
||||||
|
@ -6,12 +6,12 @@ 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(selectLoraSlice, (lora) => {
|
const selectLoRAsArray = createMemoizedSelector(selectLoraSlice, (lora) =>
|
||||||
return { lorasArray: map(lora.loras) };
|
map(lora.loras)
|
||||||
});
|
);
|
||||||
|
|
||||||
export const LoRAList = memo(() => {
|
export const LoRAList = memo(() => {
|
||||||
const { lorasArray } = useAppSelector(selector);
|
const lorasArray = useAppSelector(selectLoRAsArray);
|
||||||
|
|
||||||
if (!lorasArray.length) {
|
if (!lorasArray.length) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -10,15 +10,16 @@ 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(selectLoraSlice, (lora) => ({
|
const selectAddedLoRAs = createMemoizedSelector(
|
||||||
addedLoRAs: lora.loras,
|
selectLoraSlice,
|
||||||
}));
|
(lora) => lora.loras
|
||||||
|
);
|
||||||
|
|
||||||
const LoRASelect = () => {
|
const LoRASelect = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { data, isLoading } = useGetLoRAModelsQuery();
|
const { data, isLoading } = useGetLoRAModelsQuery();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { addedLoRAs } = useAppSelector(selector);
|
const addedLoRAs = useAppSelector(selectAddedLoRAs);
|
||||||
const currentBaseModel = useAppSelector(
|
const currentBaseModel = useAppSelector(
|
||||||
(s) => s.generation.model?.base_model
|
(s) => s.generation.model?.base_model
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
||||||
import { getFieldColor } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
import { getFieldColor } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
||||||
@ -8,25 +8,17 @@ import { memo } from 'react';
|
|||||||
import type { ConnectionLineComponentProps } from 'reactflow';
|
import type { ConnectionLineComponentProps } from 'reactflow';
|
||||||
import { getBezierPath } from 'reactflow';
|
import { getBezierPath } from 'reactflow';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectNodesSlice, (nodes) => {
|
const selectStroke = createSelector(selectNodesSlice, (nodes) =>
|
||||||
const { shouldAnimateEdges, connectionStartFieldType, shouldColorEdges } =
|
nodes.shouldColorEdges
|
||||||
nodes;
|
? getFieldColor(nodes.connectionStartFieldType)
|
||||||
|
: colorTokenToCssVar('base.500')
|
||||||
|
);
|
||||||
|
|
||||||
const stroke = shouldColorEdges
|
const selectClassName = createSelector(selectNodesSlice, (nodes) =>
|
||||||
? getFieldColor(connectionStartFieldType)
|
nodes.shouldAnimateEdges
|
||||||
: colorTokenToCssVar('base.500');
|
? 'react-flow__custom_connection-path animated'
|
||||||
|
: 'react-flow__custom_connection-path'
|
||||||
let className = 'react-flow__custom_connection-path';
|
);
|
||||||
|
|
||||||
if (shouldAnimateEdges) {
|
|
||||||
className = className.concat(' animated');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
stroke,
|
|
||||||
className,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const pathStyles: CSSProperties = { opacity: 0.8 };
|
const pathStyles: CSSProperties = { opacity: 0.8 };
|
||||||
|
|
||||||
@ -38,7 +30,8 @@ const CustomConnectionLine = ({
|
|||||||
toY,
|
toY,
|
||||||
toPosition,
|
toPosition,
|
||||||
}: ConnectionLineComponentProps) => {
|
}: ConnectionLineComponentProps) => {
|
||||||
const { stroke, className } = useAppSelector(selector);
|
const stroke = useAppSelector(selectStroke);
|
||||||
|
const className = useAppSelector(selectClassName);
|
||||||
|
|
||||||
const pathParams = {
|
const pathParams = {
|
||||||
sourceX: fromX,
|
sourceX: fromX,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import InvocationNode from 'features/nodes/components/flow/nodes/Invocation/InvocationNode';
|
import InvocationNode from 'features/nodes/components/flow/nodes/Invocation/InvocationNode';
|
||||||
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
||||||
@ -14,15 +14,15 @@ const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => {
|
|||||||
|
|
||||||
const hasTemplateSelector = useMemo(
|
const hasTemplateSelector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodeTemplatesSlice, (nodeTemplates) =>
|
createSelector(selectNodeTemplatesSlice, (nodeTemplates) =>
|
||||||
Boolean(nodeTemplates.templates[type])
|
Boolean(nodeTemplates.templates[type])
|
||||||
),
|
),
|
||||||
[type]
|
[type]
|
||||||
);
|
);
|
||||||
|
|
||||||
const nodeTemplate = useAppSelector(hasTemplateSelector);
|
const hasTemplate = useAppSelector(hasTemplateSelector);
|
||||||
|
|
||||||
if (!nodeTemplate) {
|
if (!hasTemplate) {
|
||||||
return (
|
return (
|
||||||
<InvocationNodeUnknownFallback
|
<InvocationNodeUnknownFallback
|
||||||
nodeId={nodeId}
|
nodeId={nodeId}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
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';
|
||||||
@ -36,16 +36,14 @@ const FieldContextMenu = ({ nodeId, fieldName, kind, children }: Props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const selector = useMemo(
|
const selectIsExposed = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectWorkflowSlice, (workflow) => {
|
createSelector(selectWorkflowSlice, (workflow) => {
|
||||||
const isExposed = Boolean(
|
return Boolean(
|
||||||
workflow.exposedFields.find(
|
workflow.exposedFields.find(
|
||||||
(f) => f.nodeId === nodeId && f.fieldName === fieldName
|
(f) => f.nodeId === nodeId && f.fieldName === fieldName
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return { isExposed };
|
|
||||||
}),
|
}),
|
||||||
[fieldName, nodeId]
|
[fieldName, nodeId]
|
||||||
);
|
);
|
||||||
@ -55,7 +53,7 @@ const FieldContextMenu = ({ nodeId, fieldName, kind, children }: Props) => {
|
|||||||
[input]
|
[input]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { isExposed } = useAppSelector(selector);
|
const isExposed = useAppSelector(selectIsExposed);
|
||||||
|
|
||||||
const handleExposeField = useCallback(() => {
|
const handleExposeField = useCallback(() => {
|
||||||
dispatch(workflowExposedFieldAdded({ nodeId, fieldName }));
|
dispatch(workflowExposedFieldAdded({ nodeId, fieldName }));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { ChakraProps } from '@chakra-ui/react';
|
import type { ChakraProps } from '@chakra-ui/react';
|
||||||
import { Box, useToken } from '@chakra-ui/react';
|
import { Box, useToken } from '@chakra-ui/react';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
import NodeSelectionOverlay from 'common/components/NodeSelectionOverlay';
|
import NodeSelectionOverlay from 'common/components/NodeSelectionOverlay';
|
||||||
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
|
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
|
||||||
@ -30,7 +30,7 @@ const NodeWrapper = (props: NodeWrapperProps) => {
|
|||||||
|
|
||||||
const selectIsInProgress = useMemo(
|
const selectIsInProgress = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectNodesSlice,
|
selectNodesSlice,
|
||||||
(nodes) =>
|
(nodes) =>
|
||||||
nodes.nodeExecutionStates[nodeId]?.status ===
|
nodes.nodeExecutionStates[nodeId]?.status ===
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { makeConnectionErrorSelector } from 'features/nodes/store/util/makeIsConnectionValidSelector';
|
import { makeConnectionErrorSelector } from 'features/nodes/store/util/makeIsConnectionValidSelector';
|
||||||
@ -6,7 +6,7 @@ import { useMemo } from 'react';
|
|||||||
|
|
||||||
import { useFieldType } from './useFieldType.ts';
|
import { useFieldType } from './useFieldType.ts';
|
||||||
|
|
||||||
const selectIsConnectionInProgress = createMemoizedSelector(
|
const selectIsConnectionInProgress = createSelector(
|
||||||
selectNodesSlice,
|
selectNodesSlice,
|
||||||
(nodes) =>
|
(nodes) =>
|
||||||
nodes.connectionStartFieldType !== null &&
|
nodes.connectionStartFieldType !== null &&
|
||||||
@ -28,7 +28,7 @@ export const useConnectionState = ({
|
|||||||
|
|
||||||
const selectIsConnected = useMemo(
|
const selectIsConnected = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodesSlice, (nodes) =>
|
createSelector(selectNodesSlice, (nodes) =>
|
||||||
Boolean(
|
Boolean(
|
||||||
nodes.edges.filter((edge) => {
|
nodes.edges.filter((edge) => {
|
||||||
return (
|
return (
|
||||||
@ -55,7 +55,7 @@ export const useConnectionState = ({
|
|||||||
|
|
||||||
const selectIsConnectionStartField = useMemo(
|
const selectIsConnectionStartField = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodesSlice, (nodes) =>
|
createSelector(selectNodesSlice, (nodes) =>
|
||||||
Boolean(
|
Boolean(
|
||||||
nodes.connectionStartParams?.nodeId === nodeId &&
|
nodes.connectionStartParams?.nodeId === nodeId &&
|
||||||
nodes.connectionStartParams?.handleId === fieldName &&
|
nodes.connectionStartParams?.handleId === fieldName &&
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { compareVersions } from 'compare-versions';
|
import { compareVersions } from 'compare-versions';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
@ -9,7 +9,7 @@ import { useMemo } from 'react';
|
|||||||
export const useDoNodeVersionsMatch = (nodeId: string) => {
|
export const useDoNodeVersionsMatch = (nodeId: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectNodesSlice,
|
selectNodesSlice,
|
||||||
selectNodeTemplatesSlice,
|
selectNodeTemplatesSlice,
|
||||||
(nodes, nodeTemplates) => {
|
(nodes, nodeTemplates) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
||||||
@ -8,7 +8,7 @@ import { useMemo } from 'react';
|
|||||||
export const useFieldInputKind = (nodeId: string, fieldName: string) => {
|
export const useFieldInputKind = (nodeId: string, fieldName: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectNodesSlice,
|
selectNodesSlice,
|
||||||
selectNodeTemplatesSlice,
|
selectNodeTemplatesSlice,
|
||||||
(nodes, nodeTemplates) => {
|
(nodes, nodeTemplates) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
@ -7,7 +7,7 @@ import { useMemo } from 'react';
|
|||||||
export const useFieldLabel = (nodeId: string, fieldName: string) => {
|
export const useFieldLabel = (nodeId: string, fieldName: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodesSlice, (nodes) => {
|
createSelector(selectNodesSlice, (nodes) => {
|
||||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
||||||
@ -13,7 +13,7 @@ export const useFieldTemplateTitle = (
|
|||||||
) => {
|
) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectNodesSlice,
|
selectNodesSlice,
|
||||||
selectNodeTemplatesSlice,
|
selectNodeTemplatesSlice,
|
||||||
(nodes, nodeTemplates) => {
|
(nodes, nodeTemplates) => {
|
||||||
@ -28,7 +28,7 @@ export const useFieldTemplateTitle = (
|
|||||||
[fieldName, kind, nodeId]
|
[fieldName, kind, nodeId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const fieldTemplate = useAppSelector(selector);
|
const fieldTemplateTitle = useAppSelector(selector);
|
||||||
|
|
||||||
return fieldTemplate;
|
return fieldTemplateTitle;
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selector = createSelector(
|
||||||
selectNodesSlice,
|
selectNodesSlice,
|
||||||
selectNodeTemplatesSlice,
|
selectNodeTemplatesSlice,
|
||||||
(nodes, nodeTemplates) =>
|
(nodes, nodeTemplates) =>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
@ -7,7 +7,7 @@ import { useMemo } from 'react';
|
|||||||
export const useIsIntermediate = (nodeId: string) => {
|
export const useIsIntermediate = (nodeId: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodesSlice, (nodes) => {
|
createSelector(selectNodesSlice, (nodes) => {
|
||||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
return false;
|
return false;
|
||||||
@ -17,6 +17,6 @@ export const useIsIntermediate = (nodeId: string) => {
|
|||||||
[nodeId]
|
[nodeId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const is_intermediate = useAppSelector(selector);
|
const isIntermediate = useAppSelector(selector);
|
||||||
return is_intermediate;
|
return isIntermediate;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
@ -7,7 +7,7 @@ import { useMemo } from 'react';
|
|||||||
export const useNodeLabel = (nodeId: string) => {
|
export const useNodeLabel = (nodeId: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodesSlice, (nodes) => {
|
createSelector(selectNodesSlice, (nodes) => {
|
||||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
@ -7,7 +7,7 @@ import { useMemo } from 'react';
|
|||||||
export const useNodePack = (nodeId: string) => {
|
export const useNodePack = (nodeId: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodesSlice, (nodes) => {
|
createSelector(selectNodesSlice, (nodes) => {
|
||||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
return false;
|
return false;
|
||||||
@ -17,6 +17,6 @@ export const useNodePack = (nodeId: string) => {
|
|||||||
[nodeId]
|
[nodeId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const title = useAppSelector(selector);
|
const nodePack = useAppSelector(selector);
|
||||||
return title;
|
return nodePack;
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
import { selectNodeTemplatesSlice } from 'features/nodes/store/nodeTemplatesSlice';
|
||||||
@ -8,7 +8,7 @@ import { useMemo } from 'react';
|
|||||||
export const useNodeTemplateTitle = (nodeId: string) => {
|
export const useNodeTemplateTitle = (nodeId: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(
|
createSelector(
|
||||||
selectNodesSlice,
|
selectNodesSlice,
|
||||||
selectNodeTemplatesSlice,
|
selectNodeTemplatesSlice,
|
||||||
(nodes, nodeTemplates) => {
|
(nodes, nodeTemplates) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||||
@ -7,13 +7,11 @@ import { useMemo } from 'react';
|
|||||||
export const useUseCache = (nodeId: string) => {
|
export const useUseCache = (nodeId: string) => {
|
||||||
const selector = useMemo(
|
const selector = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createMemoizedSelector(selectNodesSlice, (nodes) => {
|
createSelector(selectNodesSlice, (nodes) => {
|
||||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||||
if (!isInvocationNode(node)) {
|
if (!isInvocationNode(node)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// cast to boolean to support older workflows that didn't have useCache
|
|
||||||
// TODO: handle this better somehow
|
|
||||||
return node.data.useCache;
|
return node.data.useCache;
|
||||||
}),
|
}),
|
||||||
[nodeId]
|
[nodeId]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||||
import type { FieldType } from 'features/nodes/types/field';
|
import type { FieldType } from 'features/nodes/types/field';
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
@ -18,7 +18,7 @@ export const makeConnectionErrorSelector = (
|
|||||||
handleType: HandleType,
|
handleType: HandleType,
|
||||||
fieldType?: FieldType
|
fieldType?: FieldType
|
||||||
) => {
|
) => {
|
||||||
return createMemoizedSelector(selectNodesSlice, (nodesSlice) => {
|
return createSelector(selectNodesSlice, (nodesSlice) => {
|
||||||
if (!fieldType) {
|
if (!fieldType) {
|
||||||
return i18n.t('nodes.noFieldType');
|
return i18n.t('nodes.noFieldType');
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { 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';
|
||||||
@ -12,18 +11,9 @@ import { selectOptimalDimension } from 'features/parameters/store/generationSlic
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
[selectOptimalDimension, isStagingSelector],
|
|
||||||
(optimalDimension, isStaging) => {
|
|
||||||
return {
|
|
||||||
initial: optimalDimension,
|
|
||||||
isStaging,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamBoundingBoxWidth = () => {
|
const ParamBoundingBoxWidth = () => {
|
||||||
const { isStaging, initial } = useAppSelector(selector);
|
const isStaging = useAppSelector(isStagingSelector);
|
||||||
|
const initial = useAppSelector(selectOptimalDimension);
|
||||||
const ctx = useImageSizeContext();
|
const ctx = useImageSizeContext();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { 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';
|
||||||
@ -12,18 +11,9 @@ import { selectOptimalDimension } from 'features/parameters/store/generationSlic
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
[selectOptimalDimension, isStagingSelector],
|
|
||||||
(optimalDimension, isStaging) => {
|
|
||||||
return {
|
|
||||||
initial: optimalDimension,
|
|
||||||
isStaging,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamBoundingBoxWidth = () => {
|
const ParamBoundingBoxWidth = () => {
|
||||||
const { isStaging, initial } = useAppSelector(selector);
|
const isStaging = useAppSelector(isStagingSelector);
|
||||||
|
const initial = useAppSelector(selectOptimalDimension);
|
||||||
const ctx = useImageSizeContext();
|
const ctx = useImageSizeContext();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 {
|
import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||||
selectCanvasSlice,
|
|
||||||
setScaledBoundingBoxDimensions,
|
|
||||||
} from 'features/canvas/store/canvasSlice';
|
|
||||||
import {
|
import {
|
||||||
CANVAS_GRID_SIZE_COARSE,
|
CANVAS_GRID_SIZE_COARSE,
|
||||||
CANVAS_GRID_SIZE_FINE,
|
CANVAS_GRID_SIZE_FINE,
|
||||||
@ -14,34 +10,26 @@ import { selectOptimalDimension } from 'features/parameters/store/generationSlic
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
[selectCanvasSlice, selectOptimalDimension],
|
|
||||||
(canvas, optimalDimension) => {
|
|
||||||
const { scaledBoundingBoxDimensions, boundingBoxScaleMethod } = canvas;
|
|
||||||
|
|
||||||
return {
|
|
||||||
optimalDimension,
|
|
||||||
scaledBoundingBoxDimensions,
|
|
||||||
isManual: boundingBoxScaleMethod === 'manual',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamScaledHeight = () => {
|
const ParamScaledHeight = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { isManual, scaledBoundingBoxDimensions, optimalDimension } =
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
useAppSelector(selector);
|
const isManual = useAppSelector(
|
||||||
|
(s) => s.canvas.boundingBoxScaleMethod === 'manual'
|
||||||
|
);
|
||||||
|
const height = useAppSelector(
|
||||||
|
(s) => s.canvas.scaledBoundingBoxDimensions.height
|
||||||
|
);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleChangeScaledHeight = useCallback(
|
const onChange = useCallback(
|
||||||
(height: number) => {
|
(height: number) => {
|
||||||
dispatch(setScaledBoundingBoxDimensions({ height }));
|
dispatch(setScaledBoundingBoxDimensions({ height }));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleResetScaledHeight = useCallback(() => {
|
const onReset = useCallback(() => {
|
||||||
dispatch(setScaledBoundingBoxDimensions({ height: optimalDimension }));
|
dispatch(setScaledBoundingBoxDimensions({ height: optimalDimension }));
|
||||||
}, [dispatch, optimalDimension]);
|
}, [dispatch, optimalDimension]);
|
||||||
|
|
||||||
@ -52,12 +40,12 @@ const ParamScaledHeight = () => {
|
|||||||
max={1536}
|
max={1536}
|
||||||
step={CANVAS_GRID_SIZE_COARSE}
|
step={CANVAS_GRID_SIZE_COARSE}
|
||||||
fineStep={CANVAS_GRID_SIZE_FINE}
|
fineStep={CANVAS_GRID_SIZE_FINE}
|
||||||
value={scaledBoundingBoxDimensions.height}
|
value={height}
|
||||||
onChange={handleChangeScaledHeight}
|
onChange={onChange}
|
||||||
marks
|
marks
|
||||||
withNumberInput
|
withNumberInput
|
||||||
numberInputMax={4096}
|
numberInputMax={4096}
|
||||||
onReset={handleResetScaledHeight}
|
onReset={onReset}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 {
|
import { setScaledBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
|
||||||
selectCanvasSlice,
|
|
||||||
setScaledBoundingBoxDimensions,
|
|
||||||
} from 'features/canvas/store/canvasSlice';
|
|
||||||
import {
|
import {
|
||||||
CANVAS_GRID_SIZE_COARSE,
|
CANVAS_GRID_SIZE_COARSE,
|
||||||
CANVAS_GRID_SIZE_FINE,
|
CANVAS_GRID_SIZE_FINE,
|
||||||
@ -14,34 +10,25 @@ import { selectOptimalDimension } from 'features/parameters/store/generationSlic
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
[selectCanvasSlice, selectOptimalDimension],
|
|
||||||
(canvas, optimalDimension) => {
|
|
||||||
const { boundingBoxScaleMethod, scaledBoundingBoxDimensions } = canvas;
|
|
||||||
|
|
||||||
return {
|
|
||||||
optimalDimension,
|
|
||||||
scaledBoundingBoxDimensions,
|
|
||||||
isManual: boundingBoxScaleMethod === 'manual',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamScaledWidth = () => {
|
const ParamScaledWidth = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { optimalDimension, isManual, scaledBoundingBoxDimensions } =
|
|
||||||
useAppSelector(selector);
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
|
const isManual = useAppSelector(
|
||||||
|
(s) => s.canvas.boundingBoxScaleMethod === 'manual'
|
||||||
|
);
|
||||||
|
const width = useAppSelector(
|
||||||
|
(s) => s.canvas.scaledBoundingBoxDimensions.width
|
||||||
|
);
|
||||||
|
|
||||||
const handleChangeScaledWidth = useCallback(
|
const onChange = useCallback(
|
||||||
(width: number) => {
|
(width: number) => {
|
||||||
dispatch(setScaledBoundingBoxDimensions({ width }));
|
dispatch(setScaledBoundingBoxDimensions({ width }));
|
||||||
},
|
},
|
||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleResetScaledWidth = useCallback(() => {
|
const onReset = useCallback(() => {
|
||||||
dispatch(setScaledBoundingBoxDimensions({ width: optimalDimension }));
|
dispatch(setScaledBoundingBoxDimensions({ width: optimalDimension }));
|
||||||
}, [dispatch, optimalDimension]);
|
}, [dispatch, optimalDimension]);
|
||||||
|
|
||||||
@ -52,12 +39,12 @@ const ParamScaledWidth = () => {
|
|||||||
max={1536}
|
max={1536}
|
||||||
step={CANVAS_GRID_SIZE_COARSE}
|
step={CANVAS_GRID_SIZE_COARSE}
|
||||||
fineStep={CANVAS_GRID_SIZE_FINE}
|
fineStep={CANVAS_GRID_SIZE_FINE}
|
||||||
value={scaledBoundingBoxDimensions.width}
|
value={width}
|
||||||
onChange={handleChangeScaledWidth}
|
onChange={onChange}
|
||||||
numberInputMax={4096}
|
numberInputMax={4096}
|
||||||
marks
|
marks
|
||||||
withNumberInput
|
withNumberInput
|
||||||
onReset={handleResetScaledWidth}
|
onReset={onReset}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
);
|
);
|
||||||
|
@ -1,50 +1,24 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 {
|
import { setCfgScale } from 'features/parameters/store/generationSlice';
|
||||||
selectGenerationSlice,
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
setCfgScale,
|
|
||||||
} from 'features/parameters/store/generationSlice';
|
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
selectGenerationSlice,
|
|
||||||
selectConfigSlice,
|
|
||||||
(generation, config) => {
|
|
||||||
const { min, inputMax, sliderMax, coarseStep, fineStep, initial } =
|
|
||||||
config.sd.guidance;
|
|
||||||
const { cfgScale } = generation;
|
|
||||||
|
|
||||||
return {
|
|
||||||
marks: [min, Math.floor(sliderMax / 2), sliderMax],
|
|
||||||
cfgScale,
|
|
||||||
min,
|
|
||||||
inputMax,
|
|
||||||
sliderMax,
|
|
||||||
coarseStep,
|
|
||||||
fineStep,
|
|
||||||
initial,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamCFGScale = () => {
|
const ParamCFGScale = () => {
|
||||||
const {
|
const cfgScale = useAppSelector((s) => s.generation.cfgScale);
|
||||||
cfgScale,
|
const min = useAppSelector((s) => s.config.sd.guidance.min);
|
||||||
min,
|
const inputMax = useAppSelector((s) => s.config.sd.guidance.inputMax);
|
||||||
inputMax,
|
const sliderMax = useAppSelector((s) => s.config.sd.guidance.sliderMax);
|
||||||
sliderMax,
|
const coarseStep = useAppSelector((s) => s.config.sd.guidance.coarseStep);
|
||||||
coarseStep,
|
const fineStep = useAppSelector((s) => s.config.sd.guidance.fineStep);
|
||||||
fineStep,
|
const initial = useAppSelector((s) => s.config.sd.guidance.initial);
|
||||||
initial,
|
|
||||||
marks,
|
|
||||||
} = useAppSelector(selector);
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const marks = useMemo(
|
||||||
|
() => [min, Math.floor(sliderMax / 2), sliderMax],
|
||||||
|
[sliderMax, min]
|
||||||
|
);
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => dispatch(setCfgScale(v)),
|
(v: number) => dispatch(setCfgScale(v)),
|
||||||
[dispatch]
|
[dispatch]
|
||||||
|
@ -1,35 +1,21 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InvControl } from 'common/components/InvControl/InvControl';
|
import { InvControl } from 'common/components/InvControl/InvControl';
|
||||||
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
||||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
||||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
[selectConfigSlice, selectOptimalDimension],
|
|
||||||
(config, optimalDimension) => {
|
|
||||||
const { min, sliderMax, inputMax, fineStep, coarseStep } = config.sd.height;
|
|
||||||
|
|
||||||
return {
|
|
||||||
initial: optimalDimension,
|
|
||||||
min,
|
|
||||||
max: sliderMax,
|
|
||||||
inputMax,
|
|
||||||
step: coarseStep,
|
|
||||||
fineStep,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const ParamHeight = memo(() => {
|
export const ParamHeight = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const ctx = useImageSizeContext();
|
const ctx = useImageSizeContext();
|
||||||
const { initial, min, max, inputMax, step, fineStep } =
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
useAppSelector(selector);
|
const min = useAppSelector((s) => s.config.sd.height.min);
|
||||||
|
const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
|
||||||
|
const inputMax = useAppSelector((s) => s.config.sd.height.inputMax);
|
||||||
|
const coarseStep = useAppSelector((s) => s.config.sd.height.coarseStep);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.height.fineStep);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
@ -38,17 +24,20 @@ export const ParamHeight = memo(() => {
|
|||||||
[ctx]
|
[ctx]
|
||||||
);
|
);
|
||||||
|
|
||||||
const marks = useMemo(() => [min, initial, max], [min, initial, max]);
|
const marks = useMemo(
|
||||||
|
() => [min, optimalDimension, sliderMax],
|
||||||
|
[min, optimalDimension, sliderMax]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvControl label={t('parameters.height')}>
|
<InvControl label={t('parameters.height')}>
|
||||||
<InvSlider
|
<InvSlider
|
||||||
value={ctx.height}
|
value={ctx.height}
|
||||||
defaultValue={initial}
|
defaultValue={optimalDimension}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={sliderMax}
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
marks={marks}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
@ -57,9 +46,9 @@ export const ParamHeight = memo(() => {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
min={min}
|
min={min}
|
||||||
max={inputMax}
|
max={inputMax}
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
defaultValue={initial}
|
defaultValue={optimalDimension}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
);
|
);
|
||||||
|
@ -1,43 +1,27 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 {
|
import {
|
||||||
clampSymmetrySteps,
|
clampSymmetrySteps,
|
||||||
selectGenerationSlice,
|
|
||||||
setSteps,
|
setSteps,
|
||||||
} from 'features/parameters/store/generationSlice';
|
} from 'features/parameters/store/generationSlice';
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
selectGenerationSlice,
|
|
||||||
selectConfigSlice,
|
|
||||||
(generation, config) => {
|
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
|
||||||
config.sd.steps;
|
|
||||||
const { steps } = generation;
|
|
||||||
|
|
||||||
return {
|
|
||||||
marks: [min, Math.floor(sliderMax / 2), sliderMax],
|
|
||||||
steps,
|
|
||||||
initial,
|
|
||||||
min,
|
|
||||||
sliderMax,
|
|
||||||
inputMax,
|
|
||||||
step: coarseStep,
|
|
||||||
fineStep,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const ParamSteps = () => {
|
const ParamSteps = () => {
|
||||||
const { steps, initial, min, sliderMax, inputMax, step, fineStep, marks } =
|
const steps = useAppSelector((s) => s.generation.steps);
|
||||||
useAppSelector(selector);
|
const initial = useAppSelector((s) => s.config.sd.steps.initial);
|
||||||
|
const min = useAppSelector((s) => s.config.sd.steps.min);
|
||||||
|
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
|
||||||
|
const inputMax = useAppSelector((s) => s.config.sd.steps.inputMax);
|
||||||
|
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const marks = useMemo(
|
||||||
|
() => [min, Math.floor(sliderMax / 2), sliderMax],
|
||||||
|
[sliderMax, min]
|
||||||
|
);
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
dispatch(setSteps(v));
|
dispatch(setSteps(v));
|
||||||
@ -56,7 +40,7 @@ const ParamSteps = () => {
|
|||||||
defaultValue={initial}
|
defaultValue={initial}
|
||||||
min={min}
|
min={min}
|
||||||
max={sliderMax}
|
max={sliderMax}
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
|
@ -1,34 +1,21 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InvControl } from 'common/components/InvControl/InvControl';
|
import { InvControl } from 'common/components/InvControl/InvControl';
|
||||||
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
||||||
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
import { InvSlider } from 'common/components/InvSlider/InvSlider';
|
||||||
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
import { useImageSizeContext } from 'features/parameters/components/ImageSize/ImageSizeContext';
|
||||||
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
import { selectOptimalDimension } from 'features/parameters/store/generationSlice';
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
|
||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
[selectConfigSlice, selectOptimalDimension],
|
|
||||||
(config, optimalDimension) => {
|
|
||||||
const { min, sliderMax, inputMax, fineStep, coarseStep } = config.sd.width;
|
|
||||||
|
|
||||||
return {
|
|
||||||
initial: optimalDimension,
|
|
||||||
min,
|
|
||||||
max: sliderMax,
|
|
||||||
step: coarseStep,
|
|
||||||
inputMax,
|
|
||||||
fineStep,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
export const ParamWidth = memo(() => {
|
export const ParamWidth = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const ctx = useImageSizeContext();
|
const ctx = useImageSizeContext();
|
||||||
const { initial, min, max, inputMax, step, fineStep } =
|
const optimalDimension = useAppSelector(selectOptimalDimension);
|
||||||
useAppSelector(selector);
|
const min = useAppSelector((s) => s.config.sd.width.min);
|
||||||
|
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);
|
||||||
|
const inputMax = useAppSelector((s) => s.config.sd.width.inputMax);
|
||||||
|
const coarseStep = useAppSelector((s) => s.config.sd.width.coarseStep);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.width.fineStep);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
@ -37,17 +24,20 @@ export const ParamWidth = memo(() => {
|
|||||||
[ctx]
|
[ctx]
|
||||||
);
|
);
|
||||||
|
|
||||||
const marks = useMemo(() => [min, initial, max], [min, initial, max]);
|
const marks = useMemo(
|
||||||
|
() => [min, optimalDimension, sliderMax],
|
||||||
|
[min, optimalDimension, sliderMax]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InvControl label={t('parameters.width')}>
|
<InvControl label={t('parameters.width')}>
|
||||||
<InvSlider
|
<InvSlider
|
||||||
value={ctx.width}
|
value={ctx.width}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
defaultValue={initial}
|
defaultValue={optimalDimension}
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={sliderMax}
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
marks={marks}
|
marks={marks}
|
||||||
/>
|
/>
|
||||||
@ -56,9 +46,9 @@ export const ParamWidth = memo(() => {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
min={min}
|
min={min}
|
||||||
max={inputMax}
|
max={inputMax}
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
defaultValue={initial}
|
defaultValue={optimalDimension}
|
||||||
/>
|
/>
|
||||||
</InvControl>
|
</InvControl>
|
||||||
);
|
);
|
||||||
|
@ -1,40 +1,24 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 {
|
import { setImg2imgStrength } from 'features/parameters/store/generationSlice';
|
||||||
selectGenerationSlice,
|
|
||||||
setImg2imgStrength,
|
|
||||||
} from 'features/parameters/store/generationSlice';
|
|
||||||
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(
|
|
||||||
selectGenerationSlice,
|
|
||||||
selectConfigSlice,
|
|
||||||
(generation, config) => {
|
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
|
||||||
config.sd.img2imgStrength;
|
|
||||||
const { img2imgStrength } = generation;
|
|
||||||
|
|
||||||
return {
|
|
||||||
img2imgStrength,
|
|
||||||
initial,
|
|
||||||
min,
|
|
||||||
sliderMax,
|
|
||||||
inputMax,
|
|
||||||
step: coarseStep,
|
|
||||||
fineStep,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const marks = [0, 0.5, 1];
|
const marks = [0, 0.5, 1];
|
||||||
|
|
||||||
const ImageToImageStrength = () => {
|
const ImageToImageStrength = () => {
|
||||||
const { img2imgStrength, initial, min, sliderMax, inputMax, step, fineStep } =
|
const img2imgStrength = useAppSelector((s) => s.generation.img2imgStrength);
|
||||||
useAppSelector(selector);
|
const initial = useAppSelector((s) => s.config.sd.img2imgStrength.initial);
|
||||||
|
const min = useAppSelector((s) => s.config.sd.img2imgStrength.min);
|
||||||
|
const sliderMax = useAppSelector(
|
||||||
|
(s) => s.config.sd.img2imgStrength.sliderMax
|
||||||
|
);
|
||||||
|
const inputMax = useAppSelector((s) => s.config.sd.img2imgStrength.inputMax);
|
||||||
|
const coarseStep = useAppSelector(
|
||||||
|
(s) => s.config.sd.img2imgStrength.coarseStep
|
||||||
|
);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.img2imgStrength.fineStep);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@ -49,7 +33,7 @@ const ImageToImageStrength = () => {
|
|||||||
feature="paramDenoisingStrength"
|
feature="paramDenoisingStrength"
|
||||||
>
|
>
|
||||||
<InvSlider
|
<InvSlider
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
min={min}
|
min={min}
|
||||||
max={sliderMax}
|
max={sliderMax}
|
||||||
|
@ -11,28 +11,18 @@ import {
|
|||||||
clearInitialImage,
|
clearInitialImage,
|
||||||
selectGenerationSlice,
|
selectGenerationSlice,
|
||||||
} from 'features/parameters/store/generationSlice';
|
} from 'features/parameters/store/generationSlice';
|
||||||
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
|
||||||
import { memo, useEffect, useMemo } from 'react';
|
import { memo, useEffect, useMemo } from 'react';
|
||||||
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selectInitialImage = createMemoizedSelector(
|
||||||
selectGenerationSlice,
|
selectGenerationSlice,
|
||||||
selectSystemSlice,
|
(generation) => generation.initialImage
|
||||||
(generation, system) => {
|
|
||||||
const { initialImage } = generation;
|
|
||||||
const { isConnected } = system;
|
|
||||||
|
|
||||||
return {
|
|
||||||
initialImage,
|
|
||||||
isResetButtonDisabled: !initialImage,
|
|
||||||
isConnected,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const InitialImage = () => {
|
const InitialImage = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { initialImage, isConnected } = useAppSelector(selector);
|
const initialImage = useAppSelector(selectInitialImage);
|
||||||
|
const isConnected = useAppSelector((s) => s.system.isConnected);
|
||||||
|
|
||||||
const { currentData: imageDTO, isError } = useGetImageDTOQuery(
|
const { currentData: imageDTO, isError } = useGetImageDTOQuery(
|
||||||
initialImage?.imageName ?? skipToken
|
initialImage?.imageName ?? skipToken
|
||||||
|
@ -17,13 +17,10 @@ import type { PostUploadAction } from 'services/api/types';
|
|||||||
|
|
||||||
import InitialImage from './InitialImage';
|
import InitialImage from './InitialImage';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectGenerationSlice, (generation) => {
|
const selectInitialImage = createMemoizedSelector(
|
||||||
const { initialImage } = generation;
|
selectGenerationSlice,
|
||||||
return {
|
(generation) => generation.initialImage
|
||||||
isResetButtonDisabled: !initialImage,
|
);
|
||||||
initialImage,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const postUploadAction: PostUploadAction = {
|
const postUploadAction: PostUploadAction = {
|
||||||
type: 'SET_INITIAL_IMAGE',
|
type: 'SET_INITIAL_IMAGE',
|
||||||
@ -32,7 +29,7 @@ const postUploadAction: PostUploadAction = {
|
|||||||
const InitialImageDisplay = () => {
|
const InitialImageDisplay = () => {
|
||||||
const { recallWidthAndHeight } = useRecallParameters();
|
const { recallWidthAndHeight } = useRecallParameters();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isResetButtonDisabled, initialImage } = useAppSelector(selector);
|
const initialImage = useAppSelector(selectInitialImage);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
|
||||||
@ -91,14 +88,14 @@ const InitialImageDisplay = () => {
|
|||||||
aria-label={`${t('parameters.useSize')} (Shift+D)`}
|
aria-label={`${t('parameters.useSize')} (Shift+D)`}
|
||||||
icon={<FaRulerVertical />}
|
icon={<FaRulerVertical />}
|
||||||
onClick={handleUseSizeInitialImage}
|
onClick={handleUseSizeInitialImage}
|
||||||
isDisabled={isResetButtonDisabled}
|
isDisabled={!initialImage}
|
||||||
/>
|
/>
|
||||||
<InvIconButton
|
<InvIconButton
|
||||||
tooltip="Reset Initial Image"
|
tooltip="Reset Initial Image"
|
||||||
aria-label="Reset Initial Image"
|
aria-label="Reset Initial Image"
|
||||||
icon={<FaUndo />}
|
icon={<FaUndo />}
|
||||||
onClick={handleReset}
|
onClick={handleReset}
|
||||||
isDisabled={isResetButtonDisabled}
|
isDisabled={!initialImage}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
<InitialImage />
|
<InitialImage />
|
||||||
|
@ -12,17 +12,15 @@ import { NON_REFINER_BASE_MODELS } from 'services/api/constants';
|
|||||||
import type { MainModelConfigEntity } from 'services/api/endpoints/models';
|
import type { MainModelConfigEntity } from 'services/api/endpoints/models';
|
||||||
import { useGetMainModelsQuery } from 'services/api/endpoints/models';
|
import { useGetMainModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selectModel = createMemoizedSelector(
|
||||||
selectGenerationSlice,
|
selectGenerationSlice,
|
||||||
(generation) => ({
|
(generation) => generation.model
|
||||||
model: generation.model,
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ParamMainModelSelect = () => {
|
const ParamMainModelSelect = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { model } = useAppSelector(selector);
|
const model = useAppSelector(selectModel);
|
||||||
const { data, isLoading } = useGetMainModelsQuery(NON_REFINER_BASE_MODELS);
|
const { data, isLoading } = useGetMainModelsQuery(NON_REFINER_BASE_MODELS);
|
||||||
const _onChange = useCallback(
|
const _onChange = useCallback(
|
||||||
(model: MainModelConfigEntity | null) => {
|
(model: MainModelConfigEntity | null) => {
|
||||||
|
@ -23,11 +23,14 @@ const ParamVAEModelSelect = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { model, vae } = useAppSelector(selector);
|
const { model, vae } = useAppSelector(selector);
|
||||||
const { data, isLoading } = useGetVaeModelsQuery();
|
const { data, isLoading } = useGetVaeModelsQuery();
|
||||||
const getIsDisabled = (vae: VaeModelConfigEntity): boolean => {
|
const getIsDisabled = useCallback(
|
||||||
const isCompatible = model?.base_model === vae.base_model;
|
(vae: VaeModelConfigEntity): boolean => {
|
||||||
const hasMainModel = Boolean(model?.base_model);
|
const isCompatible = model?.base_model === vae.base_model;
|
||||||
return !hasMainModel || !isCompatible;
|
const hasMainModel = Boolean(model?.base_model);
|
||||||
};
|
return !hasMainModel || !isCompatible;
|
||||||
|
},
|
||||||
|
[model?.base_model]
|
||||||
|
);
|
||||||
const _onChange = useCallback(
|
const _onChange = useCallback(
|
||||||
(vae: VaeModelConfigEntity | null) => {
|
(vae: VaeModelConfigEntity | null) => {
|
||||||
dispatch(vaeSelected(vae ? pick(vae, 'base_model', 'model_name') : null));
|
dispatch(vaeSelected(vae ? pick(vae, 'base_model', 'model_name') : null));
|
||||||
|
@ -99,7 +99,7 @@ import {
|
|||||||
import type { ImageDTO } from 'services/api/types';
|
import type { ImageDTO } from 'services/api/types';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
const selectModel = createMemoizedSelector(
|
||||||
selectGenerationSlice,
|
selectGenerationSlice,
|
||||||
(generation) => generation.model
|
(generation) => generation.model
|
||||||
);
|
);
|
||||||
@ -108,7 +108,7 @@ export const useRecallParameters = () => {
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const toaster = useAppToaster();
|
const toaster = useAppToaster();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const model = useAppSelector(selector);
|
const model = useAppSelector(selectModel);
|
||||||
|
|
||||||
const parameterSetToast = useCallback(() => {
|
const parameterSetToast = useCallback(() => {
|
||||||
toaster({
|
toaster({
|
||||||
|
@ -1,89 +1,24 @@
|
|||||||
import { Flex, Spacer } from '@chakra-ui/layout';
|
import { Flex, Spacer } from '@chakra-ui/layout';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
|
|
||||||
import { InvButton } from 'common/components/InvButton/InvButton';
|
import { InvButton } from 'common/components/InvButton/InvButton';
|
||||||
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
import { QueueIterationsNumberInput } from 'features/queue/components/QueueIterationsNumberInput';
|
||||||
import type { InvNumberInputFieldProps } from 'common/components/InvNumberInput/types';
|
|
||||||
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
|
||||||
import {
|
|
||||||
selectGenerationSlice,
|
|
||||||
setIterations,
|
|
||||||
} from 'features/parameters/store/generationSlice';
|
|
||||||
import { useQueueBack } from 'features/queue/hooks/useQueueBack';
|
import { useQueueBack } from 'features/queue/hooks/useQueueBack';
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
import { memo } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import { IoSparkles } from 'react-icons/io5';
|
import { IoSparkles } from 'react-icons/io5';
|
||||||
|
|
||||||
import { QueueButtonTooltip } from './QueueButtonTooltip';
|
import { QueueButtonTooltip } from './QueueButtonTooltip';
|
||||||
|
|
||||||
const invoke = 'Invoke';
|
const invoke = 'Invoke';
|
||||||
|
|
||||||
const numberInputFieldProps: InvNumberInputFieldProps = {
|
|
||||||
ps: 6,
|
|
||||||
borderInlineStartRadius: 'base',
|
|
||||||
h: 'full',
|
|
||||||
textAlign: 'center',
|
|
||||||
fontSize: 'md',
|
|
||||||
fontWeight: 'semibold',
|
|
||||||
};
|
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
selectConfigSlice,
|
|
||||||
selectGenerationSlice,
|
|
||||||
selectDynamicPromptsSlice,
|
|
||||||
(config, generation, dynamicPrompts) => {
|
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
|
||||||
config.sd.iterations;
|
|
||||||
const { iterations } = generation;
|
|
||||||
const isLoadingDynamicPrompts = dynamicPrompts.isLoading;
|
|
||||||
|
|
||||||
return {
|
|
||||||
iterations,
|
|
||||||
initial,
|
|
||||||
min,
|
|
||||||
sliderMax,
|
|
||||||
inputMax,
|
|
||||||
step: coarseStep,
|
|
||||||
fineStep,
|
|
||||||
isLoadingDynamicPrompts,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const InvokeQueueBackButton = memo(() => {
|
export const InvokeQueueBackButton = memo(() => {
|
||||||
const { queueBack, isLoading, isDisabled } = useQueueBack();
|
const { queueBack, isLoading, isDisabled } = useQueueBack();
|
||||||
const { iterations, step, fineStep, isLoadingDynamicPrompts } =
|
const isLoadingDynamicPrompts = useAppSelector(
|
||||||
useAppSelector(selector);
|
(s) => s.dynamicPrompts.isLoading
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const handleChange = useCallback(
|
|
||||||
(v: number) => {
|
|
||||||
dispatch(setIterations(v));
|
|
||||||
},
|
|
||||||
[dispatch]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex pos="relative" flexGrow={1} minW="240px">
|
<Flex pos="relative" flexGrow={1} minW="240px">
|
||||||
<IAIInformationalPopover feature="paramIterations">
|
<QueueIterationsNumberInput />
|
||||||
<InvNumberInput
|
|
||||||
step={step}
|
|
||||||
fineStep={fineStep}
|
|
||||||
min={1}
|
|
||||||
max={999}
|
|
||||||
onChange={handleChange}
|
|
||||||
value={iterations}
|
|
||||||
defaultValue={1}
|
|
||||||
numberInputFieldProps={numberInputFieldProps}
|
|
||||||
pos="absolute"
|
|
||||||
insetInlineEnd={0}
|
|
||||||
h="full"
|
|
||||||
ps={0}
|
|
||||||
w="72px"
|
|
||||||
flexShrink={0}
|
|
||||||
variant="darkFilled"
|
|
||||||
/>
|
|
||||||
</IAIInformationalPopover>
|
|
||||||
<InvButton
|
<InvButton
|
||||||
onClick={queueBack}
|
onClick={queueBack}
|
||||||
isLoading={isLoading || isLoadingDynamicPrompts}
|
isLoading={isLoading || isLoadingDynamicPrompts}
|
||||||
|
@ -1,35 +1,23 @@
|
|||||||
import { Divider, Flex, ListItem, UnorderedList } from '@chakra-ui/react';
|
import { Divider, Flex, ListItem, UnorderedList } from '@chakra-ui/react';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { InvText } from 'common/components/InvText/wrapper';
|
import { InvText } from 'common/components/InvText/wrapper';
|
||||||
import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
|
import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
|
||||||
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||||
import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt';
|
import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt';
|
||||||
import { selectGallerySlice } from 'features/gallery/store/gallerySlice';
|
|
||||||
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
import { selectGenerationSlice } from 'features/parameters/store/generationSlice';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useEnqueueBatchMutation } from 'services/api/endpoints/queue';
|
import { useEnqueueBatchMutation } from 'services/api/endpoints/queue';
|
||||||
import { useBoardName } from 'services/api/hooks/useBoardName';
|
import { useBoardName } from 'services/api/hooks/useBoardName';
|
||||||
|
|
||||||
const StyledDivider = () => <Divider opacity={0.2} borderColor="base.900" />;
|
const selectPromptsCount = createSelector(
|
||||||
|
|
||||||
const tooltipSelector = createMemoizedSelector(
|
|
||||||
selectGallerySlice,
|
|
||||||
selectDynamicPromptsSlice,
|
|
||||||
selectGenerationSlice,
|
selectGenerationSlice,
|
||||||
(gallery, dynamicPrompts, generation) => {
|
selectDynamicPromptsSlice,
|
||||||
const { autoAddBoardId } = gallery;
|
(generation, dynamicPrompts) =>
|
||||||
const { iterations, positivePrompt } = generation;
|
getShouldProcessPrompt(generation.positivePrompt)
|
||||||
const promptsCount = getShouldProcessPrompt(positivePrompt)
|
|
||||||
? dynamicPrompts.prompts.length
|
? dynamicPrompts.prompts.length
|
||||||
: 1;
|
: 1
|
||||||
return {
|
|
||||||
autoAddBoardId,
|
|
||||||
promptsCount,
|
|
||||||
iterations,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -42,8 +30,9 @@ export const QueueButtonTooltip = memo(({ prepend = false }: Props) => {
|
|||||||
const isLoadingDynamicPrompts = useAppSelector(
|
const isLoadingDynamicPrompts = useAppSelector(
|
||||||
(s) => s.dynamicPrompts.isLoading
|
(s) => s.dynamicPrompts.isLoading
|
||||||
);
|
);
|
||||||
const { autoAddBoardId, promptsCount, iterations } =
|
const promptsCount = useAppSelector(selectPromptsCount);
|
||||||
useAppSelector(tooltipSelector);
|
const iterations = useAppSelector((s) => s.generation.iterations);
|
||||||
|
const autoAddBoardId = useAppSelector((s) => s.gallery.autoAddBoardId);
|
||||||
const autoAddBoardName = useBoardName(autoAddBoardId);
|
const autoAddBoardName = useBoardName(autoAddBoardId);
|
||||||
const [_, { isLoading }] = useEnqueueBatchMutation({
|
const [_, { isLoading }] = useEnqueueBatchMutation({
|
||||||
fixedCacheKey: 'enqueueBatch',
|
fixedCacheKey: 'enqueueBatch',
|
||||||
@ -77,7 +66,7 @@ export const QueueButtonTooltip = memo(({ prepend = false }: Props) => {
|
|||||||
</InvText>
|
</InvText>
|
||||||
{reasons.length > 0 && (
|
{reasons.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<StyledDivider />
|
<Divider opacity={0.2} borderColor="base.900" />
|
||||||
<UnorderedList>
|
<UnorderedList>
|
||||||
{reasons.map((reason, i) => (
|
{reasons.map((reason, i) => (
|
||||||
<ListItem key={`${reason}.${i}`}>
|
<ListItem key={`${reason}.${i}`}>
|
||||||
@ -87,7 +76,7 @@ export const QueueButtonTooltip = memo(({ prepend = false }: Props) => {
|
|||||||
</UnorderedList>
|
</UnorderedList>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<StyledDivider />
|
<Divider opacity={0.2} borderColor="base.900" />
|
||||||
<InvText fontStyle="oblique 10deg">
|
<InvText fontStyle="oblique 10deg">
|
||||||
{t('parameters.invoke.addingImagesTo')}{' '}
|
{t('parameters.invoke.addingImagesTo')}{' '}
|
||||||
<InvText as="span" fontWeight="semibold">
|
<InvText as="span" fontWeight="semibold">
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIInformationalPopover from 'common/components/IAIInformationalPopover/IAIInformationalPopover';
|
||||||
|
import { InvNumberInput } from 'common/components/InvNumberInput/InvNumberInput';
|
||||||
|
import type { InvNumberInputFieldProps } from 'common/components/InvNumberInput/types';
|
||||||
|
import { setIterations } from 'features/parameters/store/generationSlice';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
|
||||||
|
const numberInputFieldProps: InvNumberInputFieldProps = {
|
||||||
|
ps: 6,
|
||||||
|
borderInlineStartRadius: 'base',
|
||||||
|
h: 'full',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: 'md',
|
||||||
|
fontWeight: 'semibold',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const QueueIterationsNumberInput = memo(() => {
|
||||||
|
const iterations = useAppSelector((s) => s.generation.iterations);
|
||||||
|
const coarseStep = useAppSelector((s) => s.config.sd.iterations.coarseStep);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.iterations.fineStep);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(v: number) => {
|
||||||
|
dispatch(setIterations(v));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IAIInformationalPopover feature="paramIterations">
|
||||||
|
<InvNumberInput
|
||||||
|
step={coarseStep}
|
||||||
|
fineStep={fineStep}
|
||||||
|
min={1}
|
||||||
|
max={999}
|
||||||
|
onChange={handleChange}
|
||||||
|
value={iterations}
|
||||||
|
defaultValue={1}
|
||||||
|
numberInputFieldProps={numberInputFieldProps}
|
||||||
|
pos="absolute"
|
||||||
|
insetInlineEnd={0}
|
||||||
|
h="full"
|
||||||
|
ps={0}
|
||||||
|
w="72px"
|
||||||
|
flexShrink={0}
|
||||||
|
variant="darkFilled"
|
||||||
|
/>
|
||||||
|
</IAIInformationalPopover>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
QueueIterationsNumberInput.displayName = 'QueueIterationsNumberInput';
|
@ -1,33 +1,24 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 { setRefinerCFGScale } from 'features/sdxl/store/sdxlSlice';
|
import { setRefinerCFGScale } from 'features/sdxl/store/sdxlSlice';
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectConfigSlice, (config) => {
|
|
||||||
const { min, inputMax, sliderMax, coarseStep, fineStep, initial } =
|
|
||||||
config.sd.guidance;
|
|
||||||
|
|
||||||
return {
|
|
||||||
marks: [min, Math.floor(sliderMax / 2), sliderMax],
|
|
||||||
min,
|
|
||||||
inputMax,
|
|
||||||
sliderMax,
|
|
||||||
coarseStep,
|
|
||||||
fineStep,
|
|
||||||
initial,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const ParamSDXLRefinerCFGScale = () => {
|
const ParamSDXLRefinerCFGScale = () => {
|
||||||
const refinerCFGScale = useAppSelector((s) => s.sdxl.refinerCFGScale);
|
|
||||||
const { marks, min, inputMax, sliderMax, coarseStep, fineStep, initial } =
|
|
||||||
useAppSelector(selector);
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const refinerCFGScale = useAppSelector((s) => s.sdxl.refinerCFGScale);
|
||||||
|
const min = useAppSelector((s) => s.config.sd.guidance.min);
|
||||||
|
const inputMax = useAppSelector((s) => s.config.sd.guidance.inputMax);
|
||||||
|
const sliderMax = useAppSelector((s) => s.config.sd.guidance.sliderMax);
|
||||||
|
const coarseStep = useAppSelector((s) => s.config.sd.guidance.coarseStep);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.guidance.fineStep);
|
||||||
|
const initial = useAppSelector((s) => s.config.sd.guidance.initial);
|
||||||
|
const marks = useMemo(
|
||||||
|
() => [min, Math.floor(sliderMax / 2), sliderMax],
|
||||||
|
[sliderMax, min]
|
||||||
|
);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => dispatch(setRefinerCFGScale(v)),
|
(v: number) => dispatch(setRefinerCFGScale(v)),
|
||||||
|
@ -13,16 +13,17 @@ import { REFINER_BASE_MODELS } from 'services/api/constants';
|
|||||||
import type { MainModelConfigEntity } from 'services/api/endpoints/models';
|
import type { MainModelConfigEntity } from 'services/api/endpoints/models';
|
||||||
import { useGetMainModelsQuery } from 'services/api/endpoints/models';
|
import { useGetMainModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectSdxlSlice, (sdxl) => ({
|
const selectModel = createMemoizedSelector(
|
||||||
model: sdxl.refinerModel,
|
selectSdxlSlice,
|
||||||
}));
|
(sdxl) => sdxl.refinerModel
|
||||||
|
);
|
||||||
|
|
||||||
const optionsFilter = (model: MainModelConfigEntity) =>
|
const optionsFilter = (model: MainModelConfigEntity) =>
|
||||||
model.base_model === 'sdxl-refiner';
|
model.base_model === 'sdxl-refiner';
|
||||||
|
|
||||||
const ParamSDXLRefinerModelSelect = () => {
|
const ParamSDXLRefinerModelSelect = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { model } = useAppSelector(selector);
|
const model = useAppSelector(selectModel);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data, isLoading } = useGetMainModelsQuery(REFINER_BASE_MODELS);
|
const { data, isLoading } = useGetMainModelsQuery(REFINER_BASE_MODELS);
|
||||||
const _onChange = useCallback(
|
const _onChange = useCallback(
|
||||||
|
@ -1,32 +1,25 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 { setRefinerSteps } from 'features/sdxl/store/sdxlSlice';
|
import { setRefinerSteps } from 'features/sdxl/store/sdxlSlice';
|
||||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { memo, useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectConfigSlice, (config) => {
|
|
||||||
const { initial, min, sliderMax, inputMax, fineStep, coarseStep } =
|
|
||||||
config.sd.steps;
|
|
||||||
|
|
||||||
return {
|
|
||||||
marks: [min, Math.floor(sliderMax / 2), sliderMax],
|
|
||||||
initial,
|
|
||||||
min,
|
|
||||||
sliderMax,
|
|
||||||
inputMax,
|
|
||||||
step: coarseStep,
|
|
||||||
fineStep,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const ParamSDXLRefinerSteps = () => {
|
const ParamSDXLRefinerSteps = () => {
|
||||||
const { initial, min, sliderMax, inputMax, step, fineStep, marks } =
|
|
||||||
useAppSelector(selector);
|
|
||||||
const refinerSteps = useAppSelector((s) => s.sdxl.refinerSteps);
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const refinerSteps = useAppSelector((s) => s.sdxl.refinerSteps);
|
||||||
|
const initial = useAppSelector((s) => s.config.sd.steps.initial);
|
||||||
|
const min = useAppSelector((s) => s.config.sd.steps.min);
|
||||||
|
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
|
||||||
|
const inputMax = useAppSelector((s) => s.config.sd.steps.inputMax);
|
||||||
|
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
|
||||||
|
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
|
||||||
|
|
||||||
|
const marks = useMemo(
|
||||||
|
() => [min, Math.floor(sliderMax / 2), sliderMax],
|
||||||
|
[sliderMax, min]
|
||||||
|
);
|
||||||
|
|
||||||
const onChange = useCallback(
|
const onChange = useCallback(
|
||||||
(v: number) => {
|
(v: number) => {
|
||||||
@ -42,7 +35,7 @@ const ParamSDXLRefinerSteps = () => {
|
|||||||
defaultValue={initial}
|
defaultValue={initial}
|
||||||
min={min}
|
min={min}
|
||||||
max={sliderMax}
|
max={sliderMax}
|
||||||
step={step}
|
step={coarseStep}
|
||||||
fineStep={fineStep}
|
fineStep={fineStep}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
withNumberInput
|
withNumberInput
|
||||||
|
@ -61,8 +61,7 @@ const selector = createMemoizedSelector(
|
|||||||
isError = true;
|
isError = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const controlAdapterIds =
|
const controlAdapterIds = selectControlAdapterIds(controlAdapters);
|
||||||
selectControlAdapterIds(controlAdapters).map(String);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
controlAdapterIds,
|
controlAdapterIds,
|
||||||
|
@ -26,16 +26,14 @@ const stepsScaleLabelProps: InvLabelProps = {
|
|||||||
minW: '5rem',
|
minW: '5rem',
|
||||||
};
|
};
|
||||||
|
|
||||||
const selector = createMemoizedSelector(selectSdxlSlice, (sdxl) => {
|
const selectBadges = createMemoizedSelector(selectSdxlSlice, (sdxl) =>
|
||||||
return {
|
sdxl.refinerModel ? ['Enabled'] : undefined
|
||||||
badges: sdxl.refinerModel ? ['Enabled'] : undefined,
|
);
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const RefinerSettingsAccordion: React.FC = memo(() => {
|
export const RefinerSettingsAccordion: React.FC = memo(() => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const isRefinerAvailable = useIsRefinerAvailable();
|
const isRefinerAvailable = useIsRefinerAvailable();
|
||||||
const { badges } = useAppSelector(selector);
|
const badges = useAppSelector(selectBadges);
|
||||||
|
|
||||||
if (!isRefinerAvailable) {
|
if (!isRefinerAvailable) {
|
||||||
return (
|
return (
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
import { Progress } from '@chakra-ui/react';
|
import { Progress } from '@chakra-ui/react';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
|
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
|
||||||
const progressBarSelector = createMemoizedSelector(
|
|
||||||
|
const selectProgressValue = createSelector(
|
||||||
selectSystemSlice,
|
selectSystemSlice,
|
||||||
(system) => {
|
(system) => (system.denoiseProgress?.percentage ?? 0) * 100
|
||||||
return {
|
|
||||||
isConnected: system.isConnected,
|
|
||||||
hasSteps: Boolean(system.denoiseProgress),
|
|
||||||
value: (system.denoiseProgress?.percentage ?? 0) * 100,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const ProgressBar = () => {
|
const ProgressBar = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { data: queueStatus } = useGetQueueStatusQuery();
|
const { data: queueStatus } = useGetQueueStatusQuery();
|
||||||
const { hasSteps, value, isConnected } = useAppSelector(progressBarSelector);
|
const isConnected = useAppSelector((s) => s.system.isConnected);
|
||||||
|
const hasSteps = useAppSelector((s) => Boolean(s.system.denoiseProgress));
|
||||||
|
const value = useAppSelector(selectProgressValue);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Progress
|
<Progress
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Flex, useDisclosure } from '@chakra-ui/react';
|
import { Flex, useDisclosure } from '@chakra-ui/react';
|
||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
|
||||||
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 { InvControl } from 'common/components/InvControl/InvControl';
|
import { InvControl } from 'common/components/InvControl/InvControl';
|
||||||
@ -16,14 +15,10 @@ import { InvSwitch } from 'common/components/InvSwitch/wrapper';
|
|||||||
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 { useClearStorage } from 'common/hooks/useClearStorage';
|
import { useClearStorage } from 'common/hooks/useClearStorage';
|
||||||
import {
|
import { shouldUseCpuNoiseChanged } from 'features/parameters/store/generationSlice';
|
||||||
selectGenerationSlice,
|
|
||||||
shouldUseCpuNoiseChanged,
|
|
||||||
} from 'features/parameters/store/generationSlice';
|
|
||||||
import { useClearIntermediates } from 'features/system/components/SettingsModal/useClearIntermediates';
|
import { useClearIntermediates } from 'features/system/components/SettingsModal/useClearIntermediates';
|
||||||
import { StickyScrollable } from 'features/system/components/StickyScrollable';
|
import { StickyScrollable } from 'features/system/components/StickyScrollable';
|
||||||
import {
|
import {
|
||||||
selectSystemSlice,
|
|
||||||
setEnableImageDebugging,
|
setEnableImageDebugging,
|
||||||
setShouldConfirmOnDelete,
|
setShouldConfirmOnDelete,
|
||||||
setShouldEnableInformationalPopovers,
|
setShouldEnableInformationalPopovers,
|
||||||
@ -32,10 +27,7 @@ import {
|
|||||||
shouldUseNSFWCheckerChanged,
|
shouldUseNSFWCheckerChanged,
|
||||||
shouldUseWatermarkerChanged,
|
shouldUseWatermarkerChanged,
|
||||||
} from 'features/system/store/systemSlice';
|
} from 'features/system/store/systemSlice';
|
||||||
import {
|
import { setShouldShowProgressInViewer } from 'features/ui/store/uiSlice';
|
||||||
selectUiSlice,
|
|
||||||
setShouldShowProgressInViewer,
|
|
||||||
} from 'features/ui/store/uiSlice';
|
|
||||||
import type { ChangeEvent, ReactElement } from 'react';
|
import type { ChangeEvent, ReactElement } from 'react';
|
||||||
import { cloneElement, memo, useCallback, useEffect, useState } from 'react';
|
import { cloneElement, memo, useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -44,37 +36,6 @@ import { useGetAppConfigQuery } from 'services/api/endpoints/appInfo';
|
|||||||
import { SettingsLanguageSelect } from './SettingsLanguageSelect';
|
import { SettingsLanguageSelect } from './SettingsLanguageSelect';
|
||||||
import { SettingsLogLevelSelect } from './SettingsLogLevelSelect';
|
import { SettingsLogLevelSelect } from './SettingsLogLevelSelect';
|
||||||
|
|
||||||
const selector = createMemoizedSelector(
|
|
||||||
selectSystemSlice,
|
|
||||||
selectUiSlice,
|
|
||||||
selectGenerationSlice,
|
|
||||||
(system, ui, generation) => {
|
|
||||||
const {
|
|
||||||
shouldConfirmOnDelete,
|
|
||||||
enableImageDebugging,
|
|
||||||
shouldLogToConsole,
|
|
||||||
shouldAntialiasProgressImage,
|
|
||||||
shouldUseNSFWChecker,
|
|
||||||
shouldUseWatermarker,
|
|
||||||
shouldEnableInformationalPopovers,
|
|
||||||
} = system;
|
|
||||||
const { shouldUseCpuNoise } = generation;
|
|
||||||
const { shouldShowProgressInViewer } = ui;
|
|
||||||
|
|
||||||
return {
|
|
||||||
shouldUseCpuNoise,
|
|
||||||
shouldConfirmOnDelete,
|
|
||||||
enableImageDebugging,
|
|
||||||
shouldShowProgressInViewer,
|
|
||||||
shouldLogToConsole,
|
|
||||||
shouldAntialiasProgressImage,
|
|
||||||
shouldUseNSFWChecker,
|
|
||||||
shouldUseWatermarker,
|
|
||||||
shouldEnableInformationalPopovers,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
type ConfigOptions = {
|
type ConfigOptions = {
|
||||||
shouldShowDeveloperSettings: boolean;
|
shouldShowDeveloperSettings: boolean;
|
||||||
shouldShowResetWebUiText: boolean;
|
shouldShowResetWebUiText: boolean;
|
||||||
@ -137,17 +98,31 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
|
|||||||
onClose: onRefreshModalClose,
|
onClose: onRefreshModalClose,
|
||||||
} = useDisclosure();
|
} = useDisclosure();
|
||||||
|
|
||||||
const {
|
const shouldUseCpuNoise = useAppSelector(
|
||||||
shouldUseCpuNoise,
|
(s) => s.generation.shouldUseCpuNoise
|
||||||
shouldConfirmOnDelete,
|
);
|
||||||
enableImageDebugging,
|
const shouldConfirmOnDelete = useAppSelector(
|
||||||
shouldShowProgressInViewer,
|
(s) => s.system.shouldConfirmOnDelete
|
||||||
shouldLogToConsole,
|
);
|
||||||
shouldAntialiasProgressImage,
|
const enableImageDebugging = useAppSelector(
|
||||||
shouldUseNSFWChecker,
|
(s) => s.system.enableImageDebugging
|
||||||
shouldUseWatermarker,
|
);
|
||||||
shouldEnableInformationalPopovers,
|
const shouldShowProgressInViewer = useAppSelector(
|
||||||
} = useAppSelector(selector);
|
(s) => s.ui.shouldShowProgressInViewer
|
||||||
|
);
|
||||||
|
const shouldLogToConsole = useAppSelector((s) => s.system.shouldLogToConsole);
|
||||||
|
const shouldAntialiasProgressImage = useAppSelector(
|
||||||
|
(s) => s.system.shouldAntialiasProgressImage
|
||||||
|
);
|
||||||
|
const shouldUseNSFWChecker = useAppSelector(
|
||||||
|
(s) => s.system.shouldUseNSFWChecker
|
||||||
|
);
|
||||||
|
const shouldUseWatermarker = useAppSelector(
|
||||||
|
(s) => s.system.shouldUseWatermarker
|
||||||
|
);
|
||||||
|
const shouldEnableInformationalPopovers = useAppSelector(
|
||||||
|
(s) => s.system.shouldEnableInformationalPopovers
|
||||||
|
);
|
||||||
|
|
||||||
const clearStorage = useClearStorage();
|
const clearStorage = useClearStorage();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
||||||
|
|
||||||
export const languageSelector = createMemoizedSelector(
|
export const languageSelector = createSelector(
|
||||||
selectSystemSlice,
|
selectSystemSlice,
|
||||||
(system) => system.language
|
(system) => system.language
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user