mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
perf(ui): optimize all selectors 2
Mostly selector optimization. Still a few places to tidy up but I'll get to that later.
This commit is contained in:
parent
a41406ca9a
commit
dbef1a9e06
@ -18,7 +18,7 @@ import { ClearQueueConfirmationsAlertDialog } from 'features/queue/components/Cl
|
||||
import { StylePresetModal } from 'features/stylePresets/components/StylePresetForm/StylePresetModal';
|
||||
import { activeStylePresetIdChanged } from 'features/stylePresets/store/stylePresetSlice';
|
||||
import { configChanged } from 'features/system/store/configSlice';
|
||||
import { languageSelector } from 'features/system/store/systemSelectors';
|
||||
import { selectLanguage } from 'features/system/store/systemSelectors';
|
||||
import { AppContent } from 'features/ui/components/AppContent';
|
||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||
import type { TabName } from 'features/ui/store/uiTypes';
|
||||
@ -53,7 +53,7 @@ const App = ({
|
||||
selectedStylePresetId,
|
||||
destination,
|
||||
}: Props) => {
|
||||
const language = useAppSelector(languageSelector);
|
||||
const language = useAppSelector(selectLanguage);
|
||||
const logger = useLogger('system');
|
||||
const dispatch = useAppDispatch();
|
||||
const clearStorage = useClearStorage();
|
||||
|
@ -1,21 +1,20 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createLogWriter } from '@roarr/browser-log-writer';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectSystemSlice } from 'features/system/store/systemSlice';
|
||||
import {
|
||||
selectSystemLogIsEnabled,
|
||||
selectSystemLogLevel,
|
||||
selectSystemLogNamespaces,
|
||||
} from 'features/system/store/systemSlice';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { ROARR, Roarr } from 'roarr';
|
||||
|
||||
import type { LogNamespace } from './logger';
|
||||
import { $logger, BASE_CONTEXT, LOG_LEVEL_MAP, logger } from './logger';
|
||||
|
||||
const selectLogLevel = createSelector(selectSystemSlice, (system) => system.logLevel);
|
||||
const selectLogNamespaces = createSelector(selectSystemSlice, (system) => system.logNamespaces);
|
||||
const selectLogIsEnabled = createSelector(selectSystemSlice, (system) => system.logIsEnabled);
|
||||
|
||||
export const useLogger = (namespace: LogNamespace) => {
|
||||
const logLevel = useAppSelector(selectLogLevel);
|
||||
const logNamespaces = useAppSelector(selectLogNamespaces);
|
||||
const logIsEnabled = useAppSelector(selectLogIsEnabled);
|
||||
const logLevel = useAppSelector(selectSystemLogLevel);
|
||||
const logNamespaces = useAppSelector(selectSystemLogNamespaces);
|
||||
const logIsEnabled = useAppSelector(selectSystemLogIsEnabled);
|
||||
|
||||
// The provided Roarr browser log writer uses localStorage to config logging to console
|
||||
useEffect(() => {
|
||||
|
@ -1,2 +1,3 @@
|
||||
export const STORAGE_PREFIX = '@@invokeai-';
|
||||
export const EMPTY_ARRAY = [];
|
||||
export const EMPTY_OBJECT = {};
|
||||
|
@ -1,7 +1,8 @@
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
|
||||
import { getImageUsage } from 'features/deleteImageModal/store/selectors';
|
||||
import { nodeEditorReset, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { imagesApi } from 'services/api/endpoints/images';
|
||||
|
||||
export const addDeleteBoardAndImagesFulfilledListener = (startAppListening: AppStartListening) => {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { enqueueRequested } from 'app/store/actions';
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { buildNodesGraph } from 'features/nodes/util/graph/buildNodesGraph';
|
||||
import { buildWorkflowWithValidation } from 'features/nodes/util/workflow/buildWorkflow';
|
||||
import { queueApi } from 'services/api/endpoints/queue';
|
||||
@ -11,12 +12,12 @@ export const addEnqueueRequestedNodes = (startAppListening: AppStartListening) =
|
||||
enqueueRequested.match(action) && action.payload.tabName === 'workflows',
|
||||
effect: async (action, { getState, dispatch }) => {
|
||||
const state = getState();
|
||||
const { nodes, edges } = state.nodes.present;
|
||||
const nodes = selectNodesSlice(state);
|
||||
const workflow = state.workflow;
|
||||
const graph = buildNodesGraph(state.nodes.present);
|
||||
const graph = buildNodesGraph(nodes);
|
||||
const builtWorkflow = buildWorkflowWithValidation({
|
||||
nodes,
|
||||
edges,
|
||||
nodes: nodes.nodes,
|
||||
edges: nodes.edges,
|
||||
workflow,
|
||||
});
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { logger } from 'app/logging/logger';
|
||||
import type { AppStartListening } from 'app/store/middleware/listenerMiddleware';
|
||||
import { updateAllNodesRequested } from 'features/nodes/store/actions';
|
||||
import { $templates, nodesChanged } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodes } from 'features/nodes/store/selectors';
|
||||
import { NodeUpdateError } from 'features/nodes/types/error';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getNeedsUpdate, updateNode } from 'features/nodes/util/node/nodeUpdate';
|
||||
@ -14,7 +15,7 @@ export const addUpdateAllNodesRequestedListener = (startAppListening: AppStartLi
|
||||
startAppListening({
|
||||
actionCreator: updateAllNodesRequested,
|
||||
effect: (action, { dispatch, getState }) => {
|
||||
const { nodes } = getState().nodes.present;
|
||||
const nodes = selectNodes(getState());
|
||||
const templates = $templates.get();
|
||||
|
||||
let unableToUpdateCount = 0;
|
||||
|
@ -32,7 +32,10 @@ type Props = {
|
||||
children: ReactElement;
|
||||
};
|
||||
|
||||
const selectShouldEnableInformationalPopovers = createSelector(selectSystemSlice, system => system.shouldEnableInformationalPopovers);
|
||||
const selectShouldEnableInformationalPopovers = createSelector(
|
||||
selectSystemSlice,
|
||||
(system) => system.shouldEnableInformationalPopovers
|
||||
);
|
||||
|
||||
export const InformationalPopover = memo(({ feature, children, inPortal = true, ...rest }: Props) => {
|
||||
const shouldEnableInformationalPopovers = useAppSelector(selectShouldEnableInformationalPopovers);
|
||||
|
@ -6,7 +6,8 @@ import { selectParamsSlice } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
|
||||
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { Templates } from 'features/nodes/store/types';
|
||||
import { selectWorkflowSettingsSlice } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSelector, createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import type { LoRA } from 'features/controlLayers/store/types';
|
||||
import { zModelIdentifierField } from 'features/nodes/types/common';
|
||||
@ -65,8 +65,6 @@ export const lorasSlice = createSlice({
|
||||
export const { loraAdded, loraRecalled, loraDeleted, loraWeightChanged, loraIsEnabledChanged, loraAllDeleted } =
|
||||
lorasSlice.actions;
|
||||
|
||||
export const selectLoRAsSlice = (state: RootState) => state.loras;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrate = (state: any): any => {
|
||||
return state;
|
||||
@ -78,3 +76,6 @@ export const lorasPersistConfig: PersistConfig<LoRAsState> = {
|
||||
migrate,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
||||
export const selectLoRAsSlice = (state: RootState) => state.loras;
|
||||
export const selectAddedLoRAs = createSelector(selectLoRAsSlice, (loras) => loras.loras);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { createSelector, createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
||||
import type { PayloadAction, Selector } from '@reduxjs/toolkit';
|
||||
import { createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import type { RgbaColor } from 'features/controlLayers/store/types';
|
||||
import { CLIP_SKIP_MAP } from 'features/parameters/types/constants';
|
||||
@ -270,9 +271,6 @@ export const {
|
||||
modelChanged,
|
||||
} = paramsSlice.actions;
|
||||
|
||||
export const selectParamsSlice = (state: RootState) => state.params;
|
||||
export const selectBase = createSelector(selectParamsSlice, (params) => params.model?.base);
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrate = (state: any): any => {
|
||||
return state;
|
||||
@ -284,3 +282,55 @@ export const paramsPersistConfig: PersistConfig<ParamsState> = {
|
||||
migrate,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
||||
export const selectParamsSlice = (state: RootState) => state.params;
|
||||
export const createParamsSelector = <T>(selector: Selector<ParamsState, T>) =>
|
||||
createSelector(selectParamsSlice, selector);
|
||||
|
||||
export const selectBase = createParamsSelector((params) => params.model?.base);
|
||||
export const selectIsSDXL = createParamsSelector((params) => params.model?.base === 'sdxl');
|
||||
export const selectModel = createParamsSelector((params) => params.model);
|
||||
export const selectModelKey = createParamsSelector((params) => params.model?.key);
|
||||
export const selectVAE = createParamsSelector((params) => params.vae);
|
||||
export const selectVAEKey = createParamsSelector((params) => params.vae?.key);
|
||||
export const selectCFGScale = createParamsSelector((params) => params.cfgScale);
|
||||
export const selectSteps = createParamsSelector((params) => params.steps);
|
||||
export const selectCFGRescaleMultiplier = createParamsSelector((params) => params.cfgRescaleMultiplier);
|
||||
export const selectCLIPSKip = createParamsSelector((params) => params.clipSkip);
|
||||
export const selectCanvasCoherenceEdgeSize = createParamsSelector((params) => params.canvasCoherenceEdgeSize);
|
||||
export const selectCanvasCoherenceMinDenoise = createParamsSelector((params) => params.canvasCoherenceMinDenoise);
|
||||
export const selectCanvasCoherenceMode = createParamsSelector((params) => params.canvasCoherenceMode);
|
||||
export const selectMaskBlur = createParamsSelector((params) => params.maskBlur);
|
||||
export const selectInfillMethod = createParamsSelector((params) => params.infillMethod);
|
||||
export const selectInfillTileSize = createParamsSelector((params) => params.infillTileSize);
|
||||
export const selectInfillPatchmatchDownscaleSize = createParamsSelector(
|
||||
(params) => params.infillPatchmatchDownscaleSize
|
||||
);
|
||||
export const selectInfillColorValue = createParamsSelector((params) => params.infillColorValue);
|
||||
export const selectImg2imgStrength = createParamsSelector((params) => params.img2imgStrength);
|
||||
export const selectPositivePrompt = createParamsSelector((params) => params.positivePrompt);
|
||||
export const selectNegativePrompt = createParamsSelector((params) => params.negativePrompt);
|
||||
export const selectPositivePrompt2 = createParamsSelector((params) => params.positivePrompt2);
|
||||
export const selectNegativePrompt2 = createParamsSelector((params) => params.negativePrompt2);
|
||||
export const selectShouldConcatPrompts = createParamsSelector((params) => params.shouldConcatPrompts);
|
||||
export const selectScheduler = createParamsSelector((params) => params.scheduler);
|
||||
export const selectSeamlessXAxis = createParamsSelector((params) => params.seamlessXAxis);
|
||||
export const selectSeamlessYAxis = createParamsSelector((params) => params.seamlessYAxis);
|
||||
export const selectSeed = createParamsSelector((params) => params.seed);
|
||||
export const selectShouldRandomizeSeed = createParamsSelector((params) => params.shouldConcatPrompts);
|
||||
export const selectVAEPrecision = createParamsSelector((params) => params.vaePrecision);
|
||||
export const selectIterations = createParamsSelector((params) => params.iterations);
|
||||
export const selectShouldUseCPUNoise = createParamsSelector((params) => params.shouldUseCpuNoise);
|
||||
|
||||
export const selectRefinerCFGScale = createParamsSelector((params) => params.refinerCFGScale);
|
||||
export const selectRefinerModel = createParamsSelector((params) => params.refinerModel);
|
||||
export const selectIsRefinerModelSelected = createParamsSelector((params) => Boolean(params.refinerModel));
|
||||
export const selectRefinerPositiveAestheticScore = createParamsSelector(
|
||||
(params) => params.refinerPositiveAestheticScore
|
||||
);
|
||||
export const selectRefinerNegativeAestheticScore = createParamsSelector(
|
||||
(params) => params.refinerNegativeAestheticScore
|
||||
);
|
||||
export const selectRefinerScheduler = createParamsSelector((params) => params.refinerScheduler);
|
||||
export const selectRefinerStart = createParamsSelector((params) => params.refinerStart);
|
||||
export const selectRefinerSteps = createParamsSelector((params) => params.refinerSteps);
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
selectDeleteImageModalSlice,
|
||||
} from 'features/deleteImageModal/store/slice';
|
||||
import type { ImageUsage } from 'features/deleteImageModal/store/types';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { selectSystemSlice, setShouldConfirmOnDelete } from 'features/system/store/systemSlice';
|
||||
import { some } from 'lodash-es';
|
||||
import type { ChangeEvent } from 'react';
|
||||
|
@ -2,7 +2,7 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
|
||||
import type { CanvasState } from 'features/controlLayers/store/types';
|
||||
import { selectDeleteImageModalSlice } from 'features/deleteImageModal/store/slice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { NodesState } from 'features/nodes/store/types';
|
||||
import { isImageFieldInputInstance } from 'features/nodes/types/field';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
|
@ -1,20 +1,19 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { maxPromptsChanged, selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import { selectConfigSlice } from 'features/system/store/configSlice';
|
||||
import {
|
||||
maxPromptsChanged,
|
||||
selectDynamicPromptsCombinatorial,
|
||||
selectDynamicPromptsMaxPrompts,
|
||||
} from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import { selectMaxPromptsConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selectMaxPrompts = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => dynamicPrompts.maxPrompts);
|
||||
const selectMaxPromptsConfig = createSelector(selectConfigSlice, (config) => config.sd.dynamicPrompts.maxPrompts);
|
||||
const selectIsDisabled = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => !dynamicPrompts.combinatorial);
|
||||
|
||||
const ParamDynamicPromptsMaxPrompts = () => {
|
||||
const maxPrompts = useAppSelector(selectMaxPrompts);
|
||||
const maxPrompts = useAppSelector(selectDynamicPromptsMaxPrompts);
|
||||
const config = useAppSelector(selectMaxPromptsConfig);
|
||||
const isDisabled = useAppSelector(selectIsDisabled);
|
||||
const combinatorial = useAppSelector(selectDynamicPromptsCombinatorial);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -26,7 +25,7 @@ const ParamDynamicPromptsMaxPrompts = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<FormControl isDisabled={isDisabled}>
|
||||
<FormControl isDisabled={!combinatorial}>
|
||||
<InformationalPopover feature="dynamicPromptsMaxPrompts" inPortal={false}>
|
||||
<FormLabel>{t('dynamicPrompts.maxPrompts')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
|
@ -1,11 +1,15 @@
|
||||
import type { ChakraProps } from '@invoke-ai/ui-library';
|
||||
import { Flex, FormControl, FormLabel, ListItem, OrderedList, Spinner, Text } from '@invoke-ai/ui-library';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import {
|
||||
selectDynamicPromptsIsError,
|
||||
selectDynamicPromptsIsLoading,
|
||||
selectDynamicPromptsParsingError,
|
||||
selectDynamicPromptsPrompts,
|
||||
} from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiWarningCircleBold } from 'react-icons/pi';
|
||||
@ -14,17 +18,12 @@ const listItemStyles: ChakraProps['sx'] = {
|
||||
'&::marker': { color: 'base.500' },
|
||||
};
|
||||
|
||||
const selectPrompts = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => dynamicPrompts.prompts);
|
||||
const selectParsingError = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => dynamicPrompts.parsingError);
|
||||
const selectIsError = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => dynamicPrompts.isError);
|
||||
const selectIsLoading = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => dynamicPrompts.isLoading);
|
||||
|
||||
const ParamDynamicPromptsPreview = () => {
|
||||
const { t } = useTranslation();
|
||||
const parsingError = useAppSelector(selectParsingError);
|
||||
const isError = useAppSelector(selectIsError);
|
||||
const isLoading = useAppSelector(selectIsLoading);
|
||||
const prompts = useAppSelector(selectPrompts);
|
||||
const parsingError = useAppSelector(selectDynamicPromptsParsingError);
|
||||
const isError = useAppSelector(selectDynamicPromptsIsError);
|
||||
const isLoading = useAppSelector(selectDynamicPromptsIsLoading);
|
||||
const prompts = useAppSelector(selectDynamicPromptsPrompts);
|
||||
|
||||
const label = useMemo(() => {
|
||||
let _label = `${t('dynamicPrompts.promptsPreview')} (${prompts.length})`;
|
||||
|
@ -1,22 +1,19 @@
|
||||
import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import {
|
||||
isSeedBehaviour,
|
||||
seedBehaviourChanged,
|
||||
selectDynamicPromptsSlice,
|
||||
selectDynamicPromptsSeedBehaviour,
|
||||
} from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selectSeedBehaviour = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => dynamicPrompts.seedBehaviour);
|
||||
|
||||
const ParamDynamicPromptsSeedBehaviour = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const seedBehaviour = useAppSelector(selectSeedBehaviour);
|
||||
const seedBehaviour = useAppSelector(selectDynamicPromptsSeedBehaviour);
|
||||
|
||||
const options = useMemo<ComboboxOption[]>(() => {
|
||||
return [
|
||||
|
@ -1,9 +1,11 @@
|
||||
import type { SystemStyleObject } from '@invoke-ai/ui-library';
|
||||
import { IconButton, spinAnimation, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useDynamicPromptsModal } from 'features/dynamicPrompts/hooks/useDynamicPromptsModal';
|
||||
import { selectDynamicPromptsSlice } from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import {
|
||||
selectDynamicPromptsIsError,
|
||||
selectDynamicPromptsIsLoading,
|
||||
} from 'features/dynamicPrompts/store/dynamicPromptsSlice';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { BsBracesAsterisk } from 'react-icons/bs';
|
||||
@ -12,15 +14,10 @@ const loadingStyles: SystemStyleObject = {
|
||||
svg: { animation: spinAnimation },
|
||||
};
|
||||
|
||||
const selectIsError = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) =>
|
||||
Boolean(dynamicPrompts.isError || dynamicPrompts.parsingError)
|
||||
);
|
||||
const selectIsLoading = createSelector(selectDynamicPromptsSlice, (dynamicPrompts) => dynamicPrompts.isLoading);
|
||||
|
||||
export const ShowDynamicPromptsPreviewButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isLoading = useAppSelector(selectIsLoading);
|
||||
const isError = useAppSelector(selectIsError);
|
||||
const isLoading = useAppSelector(selectDynamicPromptsIsLoading);
|
||||
const isError = useAppSelector(selectDynamicPromptsIsError);
|
||||
const { isOpen, onOpen } = useDynamicPromptsModal();
|
||||
|
||||
return (
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import type { PayloadAction, Selector } from '@reduxjs/toolkit';
|
||||
import { createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import { z } from 'zod';
|
||||
|
||||
@ -72,8 +72,6 @@ export const {
|
||||
seedBehaviourChanged,
|
||||
} = dynamicPromptsSlice.actions;
|
||||
|
||||
export const selectDynamicPromptsSlice = (state: RootState) => state.dynamicPrompts;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateDynamicPromptsState = (state: any): any => {
|
||||
if (!('_version' in state)) {
|
||||
@ -88,3 +86,23 @@ export const dynamicPromptsPersistConfig: PersistConfig<DynamicPromptsState> = {
|
||||
migrate: migrateDynamicPromptsState,
|
||||
persistDenylist: ['prompts'],
|
||||
};
|
||||
|
||||
export const selectDynamicPromptsSlice = (state: RootState) => state.dynamicPrompts;
|
||||
const createDynamicPromptsSelector = <T>(selector: Selector<DynamicPromptsState, T>) =>
|
||||
createSelector(selectDynamicPromptsSlice, selector);
|
||||
|
||||
export const selectDynamicPromptsMaxPrompts = createDynamicPromptsSelector(
|
||||
(dynamicPrompts) => dynamicPrompts.maxPrompts
|
||||
);
|
||||
export const selectDynamicPromptsCombinatorial = createDynamicPromptsSelector(
|
||||
(dynamicPrompts) => dynamicPrompts.combinatorial
|
||||
);
|
||||
export const selectDynamicPromptsPrompts = createDynamicPromptsSelector((dynamicPrompts) => dynamicPrompts.prompts);
|
||||
export const selectDynamicPromptsParsingError = createDynamicPromptsSelector(
|
||||
(dynamicPrompts) => dynamicPrompts.parsingError
|
||||
);
|
||||
export const selectDynamicPromptsIsError = createDynamicPromptsSelector((dynamicPrompts) => dynamicPrompts.isError);
|
||||
export const selectDynamicPromptsIsLoading = createDynamicPromptsSelector((dynamicPrompts) => dynamicPrompts.isLoading);
|
||||
export const selectDynamicPromptsSeedBehaviour = createDynamicPromptsSelector(
|
||||
(dynamicPrompts) => dynamicPrompts.seedBehaviour
|
||||
);
|
||||
|
@ -22,7 +22,6 @@ type Props = {
|
||||
setBoardToDelete: (board?: BoardDTO) => void;
|
||||
};
|
||||
|
||||
|
||||
export const BoardsList = ({ isPrivate, setBoardToDelete }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const selectedBoardId = useAppSelector(selectSelectedBoardId);
|
||||
|
@ -17,7 +17,7 @@ import { selectCanvasSlice } from 'features/controlLayers/store/selectors';
|
||||
import ImageUsageMessage from 'features/deleteImageModal/components/ImageUsageMessage';
|
||||
import { getImageUsage } from 'features/deleteImageModal/store/selectors';
|
||||
import type { ImageUsage } from 'features/deleteImageModal/store/types';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { some } from 'lodash-es';
|
||||
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -2,7 +2,10 @@ import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { handlers, parseAndRecallAllMetadata, parseAndRecallPrompts } from 'features/metadata/util/handlers';
|
||||
import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
|
||||
import { activeStylePresetIdChanged, selectActivePresetId } from 'features/stylePresets/store/stylePresetSlice';
|
||||
import {
|
||||
activeStylePresetIdChanged,
|
||||
selectStylePresetActivePresetId,
|
||||
} from 'features/stylePresets/store/stylePresetSlice';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { selectActiveTab } from 'features/ui/store/uiSelectors';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
@ -13,7 +16,7 @@ import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata';
|
||||
export const useImageActions = (image_name?: string) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const activeStylePresetId = useAppSelector(selectActivePresetId);
|
||||
const activeStylePresetId = useAppSelector(selectStylePresetActivePresetId);
|
||||
const activeTabName = useAppSelector(selectActiveTab);
|
||||
const { metadata, isLoading: isLoadingMetadata } = useDebouncedMetadata(image_name);
|
||||
const [hasMetadata, setHasMetadata] = useState(false);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import type { ModelType } from 'services/api/types';
|
||||
|
||||
@ -50,8 +50,6 @@ export const modelManagerV2Slice = createSlice({
|
||||
export const { setSelectedModelKey, setSearchTerm, setFilteredModelType, setSelectedModelMode, setScanPath } =
|
||||
modelManagerV2Slice.actions;
|
||||
|
||||
export const selectModelManagerV2Slice = (state: RootState) => state.modelmanagerV2;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateModelManagerState = (state: any): any => {
|
||||
if (!('_version' in state)) {
|
||||
@ -66,3 +64,13 @@ export const modelManagerV2PersistConfig: PersistConfig<ModelManagerState> = {
|
||||
migrate: migrateModelManagerState,
|
||||
persistDenylist: ['selectedModelKey', 'selectedModelMode', 'filteredModelType', 'searchTerm'],
|
||||
};
|
||||
|
||||
export const selectModelManagerV2Slice = (state: RootState) => state.modelmanagerV2;
|
||||
|
||||
export const createModelManagerSelector = <T>(selector: (state: ModelManagerState) => T) =>
|
||||
createSelector(selectModelManagerV2Slice, selector);
|
||||
|
||||
export const selectSelectedModelKey = createModelManagerSelector((modelManager) => modelManager.selectedModelKey);
|
||||
export const selectSelectedModelMode = createModelManagerSelector((modelManager) => modelManager.selectedModelMode);
|
||||
export const selectSearchTerm = createModelManagerSelector((mm) => mm.searchTerm);
|
||||
export const selectFilteredModelType = createModelManagerSelector((mm) => mm.filteredModelType);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Button, Flex, FormControl, FormErrorMessage, FormHelperText, FormLabel, Input } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setScanPath } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { createModelManagerSelector, setScanPath } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import { memo, useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -8,8 +8,10 @@ import { useLazyScanFolderQuery } from 'services/api/endpoints/models';
|
||||
|
||||
import { ScanModelsResults } from './ScanFolderResults';
|
||||
|
||||
const selectScanPath = createModelManagerSelector((mm) => mm.scanPath);
|
||||
|
||||
export const ScanModelsForm = memo(() => {
|
||||
const scanPath = useAppSelector((state) => state.modelmanagerV2.scanPath);
|
||||
const scanPath = useAppSelector(selectScanPath);
|
||||
const dispatch = useAppDispatch();
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const { t } = useTranslation();
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { Flex, Text } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import type { FilterableModelType } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import {
|
||||
type FilterableModelType,
|
||||
selectFilteredModelType,
|
||||
selectSearchTerm,
|
||||
} from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@ -23,8 +27,8 @@ import { FetchingModelsLoader } from './FetchingModelsLoader';
|
||||
import { ModelListWrapper } from './ModelListWrapper';
|
||||
|
||||
const ModelList = () => {
|
||||
const filteredModelType = useAppSelector((s) => s.modelmanagerV2.filteredModelType);
|
||||
const searchTerm = useAppSelector((s) => s.modelmanagerV2.searchTerm);
|
||||
const filteredModelType = useAppSelector(selectFilteredModelType);
|
||||
const searchTerm = useAppSelector(selectSearchTerm);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [mainModels, { isLoading: isLoadingMainModels }] = useMainModels();
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Flex, IconButton, Input, InputGroup, InputRightElement, Spacer } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setSearchTerm } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { selectSearchTerm, setSearchTerm } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { t } from 'i18next';
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
@ -10,7 +10,7 @@ import { ModelTypeFilter } from './ModelTypeFilter';
|
||||
|
||||
export const ModelListNavigation = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const searchTerm = useAppSelector((s) => s.modelmanagerV2.searchTerm);
|
||||
const searchTerm = useAppSelector(selectSearchTerm);
|
||||
|
||||
const handleSearch: ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||
(event) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Button, Menu, MenuButton, MenuItem, MenuList } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import type { FilterableModelType } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { setFilteredModelType } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { selectFilteredModelType, setFilteredModelType } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiFunnelBold } from 'react-icons/pi';
|
||||
@ -26,7 +26,7 @@ export const ModelTypeFilter = memo(() => {
|
||||
}),
|
||||
[t]
|
||||
);
|
||||
const filteredModelType = useAppSelector((s) => s.modelmanagerV2.filteredModelType);
|
||||
const filteredModelType = useAppSelector(selectFilteredModelType);
|
||||
|
||||
const selectModelType = useCallback(
|
||||
(option: FilterableModelType) => {
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { Box } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { InstallModels } from './InstallModels';
|
||||
import { Model } from './ModelPanel/Model';
|
||||
|
||||
export const ModelPane = memo(() => {
|
||||
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
|
||||
const selectedModelKey = useAppSelector(selectSelectedModelKey);
|
||||
return (
|
||||
<Box layerStyle="first" p={4} borderRadius="base" w="50%" h="full">
|
||||
{selectedModelKey ? <Model key={selectedModelKey} /> : <InstallModels />}
|
||||
|
@ -2,6 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
|
||||
import { selectCFGRescaleMultiplierConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import type { UseControllerProps } from 'react-hook-form';
|
||||
import { useController } from 'react-hook-form';
|
||||
@ -14,14 +15,12 @@ type DefaultCfgRescaleMultiplierType = MainModelDefaultSettingsFormData['cfgResc
|
||||
export const DefaultCfgRescaleMultiplier = memo((props: UseControllerProps<MainModelDefaultSettingsFormData>) => {
|
||||
const { field } = useController(props);
|
||||
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.fineStep);
|
||||
const config = useAppSelector(selectCFGRescaleMultiplierConfig);
|
||||
const { t } = useTranslation();
|
||||
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||
const marks = useMemo(
|
||||
() => [config.sliderMin, Math.floor(config.sliderMax / 2), config.sliderMax],
|
||||
[config.sliderMax, config.sliderMin]
|
||||
);
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
@ -54,20 +53,20 @@ export const DefaultCfgRescaleMultiplier = memo((props: UseControllerProps<MainM
|
||||
<Flex w="full" gap={4}>
|
||||
<CompositeSlider
|
||||
value={value}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
marks={marks}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={value}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
|
@ -2,6 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
|
||||
import { selectCFGScaleConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import type { UseControllerProps } from 'react-hook-form';
|
||||
import { useController } from 'react-hook-form';
|
||||
@ -14,14 +15,12 @@ type DefaultCfgType = MainModelDefaultSettingsFormData['cfgScale'];
|
||||
export const DefaultCfgScale = memo((props: UseControllerProps<MainModelDefaultSettingsFormData>) => {
|
||||
const { field } = useController(props);
|
||||
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.guidance.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.guidance.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.guidance.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.guidance.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.guidance.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.guidance.fineStep);
|
||||
const config = useAppSelector(selectCFGScaleConfig);
|
||||
const { t } = useTranslation();
|
||||
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||
const marks = useMemo(
|
||||
() => [config.sliderMin, Math.floor(config.sliderMax / 2), config.sliderMax],
|
||||
[config.sliderMax, config.sliderMin]
|
||||
);
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
@ -54,20 +53,20 @@ export const DefaultCfgScale = memo((props: UseControllerProps<MainModelDefaultS
|
||||
<Flex w="full" gap={4}>
|
||||
<CompositeSlider
|
||||
value={value}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
marks={marks}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={value}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
|
@ -2,6 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
|
||||
import { selectHeightConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import type { UseControllerProps } from 'react-hook-form';
|
||||
import { useController } from 'react-hook-form';
|
||||
@ -18,14 +19,12 @@ type Props = {
|
||||
|
||||
export const DefaultHeight = memo(({ control, optimalDimension }: Props) => {
|
||||
const { field } = useController({ control, name: 'height' });
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.height.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.height.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.height.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.height.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.height.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.height.fineStep);
|
||||
const config = useAppSelector(selectHeightConfig);
|
||||
const { t } = useTranslation();
|
||||
const marks = useMemo(() => [sliderMin, optimalDimension, sliderMax], [sliderMin, optimalDimension, sliderMax]);
|
||||
const marks = useMemo(
|
||||
() => [config.sliderMin, optimalDimension, config.sliderMax],
|
||||
[config.sliderMin, optimalDimension, config.sliderMax]
|
||||
);
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
@ -58,20 +57,20 @@ export const DefaultHeight = memo(({ control, optimalDimension }: Props) => {
|
||||
<Flex w="full" gap={4}>
|
||||
<CompositeSlider
|
||||
value={value}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
marks={marks}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={value}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
|
@ -2,6 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
|
||||
import { selectStepsConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import type { UseControllerProps } from 'react-hook-form';
|
||||
import { useController } from 'react-hook-form';
|
||||
@ -14,14 +15,12 @@ type DefaultSteps = MainModelDefaultSettingsFormData['steps'];
|
||||
export const DefaultSteps = memo((props: UseControllerProps<MainModelDefaultSettingsFormData>) => {
|
||||
const { field } = useController(props);
|
||||
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.steps.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.steps.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
|
||||
const config = useAppSelector(selectStepsConfig);
|
||||
const { t } = useTranslation();
|
||||
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||
const marks = useMemo(
|
||||
() => [config.sliderMin, Math.floor(config.sliderMax / 2), config.sliderMax],
|
||||
[config.sliderMax, config.sliderMin]
|
||||
);
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
@ -54,20 +53,20 @@ export const DefaultSteps = memo((props: UseControllerProps<MainModelDefaultSett
|
||||
<Flex w="full" gap={4}>
|
||||
<CompositeSlider
|
||||
value={value}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
marks={marks}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={value}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
|
@ -3,6 +3,7 @@ import { Combobox, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { selectSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import type { UseControllerProps } from 'react-hook-form';
|
||||
@ -18,7 +19,7 @@ type DefaultVaeType = MainModelDefaultSettingsFormData['vae'];
|
||||
export const DefaultVae = memo((props: UseControllerProps<MainModelDefaultSettingsFormData>) => {
|
||||
const { t } = useTranslation();
|
||||
const { field } = useController(props);
|
||||
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
|
||||
const selectedModelKey = useAppSelector(selectSelectedModelKey);
|
||||
const { data: modelData } = useGetModelConfigQuery(selectedModelKey ?? skipToken);
|
||||
|
||||
const [vaeModels] = useVAEModels();
|
||||
|
@ -2,6 +2,7 @@ import { CompositeNumberInput, CompositeSlider, Flex, FormControl, FormLabel } f
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { SettingToggle } from 'features/modelManagerV2/subpanels/ModelPanel/SettingToggle';
|
||||
import { selectWidthConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import type { UseControllerProps } from 'react-hook-form';
|
||||
import { useController } from 'react-hook-form';
|
||||
@ -18,14 +19,12 @@ type Props = {
|
||||
|
||||
export const DefaultWidth = memo(({ control, optimalDimension }: Props) => {
|
||||
const { field } = useController({ control, name: 'width' });
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.width.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.width.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.width.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.width.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.width.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.width.fineStep);
|
||||
const config = useAppSelector(selectWidthConfig);
|
||||
const { t } = useTranslation();
|
||||
const marks = useMemo(() => [sliderMin, optimalDimension, sliderMax], [sliderMin, optimalDimension, sliderMax]);
|
||||
const marks = useMemo(
|
||||
() => [config.sliderMin, optimalDimension, config.sliderMax],
|
||||
[config.sliderMin, optimalDimension, config.sliderMax]
|
||||
);
|
||||
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
@ -58,20 +57,20 @@ export const DefaultWidth = memo(({ control, optimalDimension }: Props) => {
|
||||
<Flex w="full" gap={4}>
|
||||
<CompositeSlider
|
||||
value={value}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
marks={marks}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={value}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Button, Flex, Heading, SimpleGrid } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useMainModelDefaultSettings } from 'features/modelManagerV2/hooks/useMainModelDefaultSettings';
|
||||
import { selectSelectedModelKey } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { DefaultHeight } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultHeight';
|
||||
import { DefaultWidth } from 'features/modelManagerV2/subpanels/ModelPanel/MainModelDefaultSettings/DefaultWidth';
|
||||
import type { ParameterScheduler } from 'features/parameters/types/parameterSchemas';
|
||||
@ -42,7 +43,7 @@ type Props = {
|
||||
};
|
||||
|
||||
export const MainModelDefaultSettings = memo(({ modelConfig }: Props) => {
|
||||
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
|
||||
const selectedModelKey = useAppSelector(selectSelectedModelKey);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const defaultSettingsDefaults = useMainModelDefaultSettings(modelConfig);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { IAINoContentFallback, IAINoContentFallbackWithSpinner } from 'common/components/IAIImageFallback';
|
||||
import { selectSelectedModelKey, selectSelectedModelMode } from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiExclamationMarkBold } from 'react-icons/pi';
|
||||
@ -10,8 +11,8 @@ import { ModelView } from './ModelView';
|
||||
|
||||
export const Model = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const selectedModelMode = useAppSelector((s) => s.modelmanagerV2.selectedModelMode);
|
||||
const selectedModelKey = useAppSelector((s) => s.modelmanagerV2.selectedModelKey);
|
||||
const selectedModelMode = useAppSelector(selectSelectedModelMode);
|
||||
const selectedModelKey = useAppSelector(selectSelectedModelKey);
|
||||
const { data: modelConfigs, isLoading } = useGetModelConfigsQuery();
|
||||
const modelConfig = useMemo(() => {
|
||||
if (!modelConfigs) {
|
||||
|
@ -18,6 +18,7 @@ import {
|
||||
nodesChanged,
|
||||
openAddNodePopover,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { findUnoccupiedPosition } from 'features/nodes/store/util/findUnoccupiedPosition';
|
||||
import { getFirstValidConnection } from 'features/nodes/store/util/getFirstValidConnection';
|
||||
import { connectionToEdge } from 'features/nodes/store/util/reactFlowUtil';
|
||||
@ -137,7 +138,7 @@ const AddNodePopover = () => {
|
||||
|
||||
// Find a cozy spot for the node
|
||||
const cursorPos = $cursorPos.get();
|
||||
const { nodes, edges } = store.getState().nodes.present;
|
||||
const { nodes, edges } = selectNodesSlice(store.getState());
|
||||
node.position = findUnoccupiedPosition(nodes, cursorPos?.x ?? node.position.x, cursorPos?.y ?? node.position.y);
|
||||
node.selected = true;
|
||||
|
||||
@ -184,7 +185,7 @@ const AddNodePopover = () => {
|
||||
const target = handleType === 'target' ? pendingConnection.nodeId : node.id;
|
||||
const targetHandle = handleType === 'target' ? pendingConnection.handleId : null;
|
||||
|
||||
const { nodes, edges } = store.getState().nodes.present;
|
||||
const { nodes, edges } = selectNodesSlice(store.getState());
|
||||
const connection = getFirstValidConnection(
|
||||
source,
|
||||
sourceHandle,
|
||||
|
@ -21,7 +21,15 @@ import {
|
||||
undo,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { $flow, $needsFit } from 'features/nodes/store/reactFlowInstance';
|
||||
import {
|
||||
selectEdges,
|
||||
selectMayRedo,
|
||||
selectMayUndo,
|
||||
selectNodes,
|
||||
selectNodesSlice,
|
||||
} from 'features/nodes/store/selectors';
|
||||
import { connectionToEdge } from 'features/nodes/store/util/reactFlowUtil';
|
||||
import { selectSelectionMode, selectShouldSnapToGrid } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import type { CSSProperties, MouseEvent } from 'react';
|
||||
import { memo, useCallback, useMemo, useRef } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
@ -66,14 +74,14 @@ const selectCancelConnection = (state: ReactFlowState) => state.cancelConnection
|
||||
|
||||
export const Flow = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const nodes = useAppSelector((s) => s.nodes.present.nodes);
|
||||
const edges = useAppSelector((s) => s.nodes.present.edges);
|
||||
const nodes = useAppSelector(selectNodes);
|
||||
const edges = useAppSelector(selectEdges);
|
||||
const viewport = useStore($viewport);
|
||||
const needsFit = useStore($needsFit);
|
||||
const mayUndo = useAppSelector((s) => s.nodes.past.length > 0);
|
||||
const mayRedo = useAppSelector((s) => s.nodes.future.length > 0);
|
||||
const shouldSnapToGrid = useAppSelector((s) => s.workflowSettings.shouldSnapToGrid);
|
||||
const selectionMode = useAppSelector((s) => s.workflowSettings.selectionMode);
|
||||
const mayUndo = useAppSelector(selectMayUndo);
|
||||
const mayRedo = useAppSelector(selectMayRedo);
|
||||
const shouldSnapToGrid = useAppSelector(selectShouldSnapToGrid);
|
||||
const selectionMode = useAppSelector(selectSelectionMode);
|
||||
const { onConnectStart, onConnect, onConnectEnd } = useConnection();
|
||||
const flowWrapper = useRef<HTMLDivElement>(null);
|
||||
const isValidConnection = useIsValidConnection();
|
||||
@ -214,7 +222,7 @@ export const Flow = memo(() => {
|
||||
const onSelectAllHotkey = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
const { nodes, edges } = store.getState().nodes.present;
|
||||
const { nodes, edges } = selectNodesSlice(store.getState());
|
||||
const nodeChanges: NodeChange[] = [];
|
||||
const edgeChanges: EdgeChange[] = [];
|
||||
nodes.forEach(({ id, selected }) => {
|
||||
@ -280,7 +288,7 @@ export const Flow = memo(() => {
|
||||
useHotkeys('esc', onEscapeHotkey);
|
||||
|
||||
const onDeleteHotkey = useCallback(() => {
|
||||
const { nodes, edges } = store.getState().nodes.present;
|
||||
const { nodes, edges } = selectNodesSlice(store.getState());
|
||||
const nodeChanges: NodeChange[] = [];
|
||||
const edgeChanges: EdgeChange[] = [];
|
||||
nodes
|
||||
|
@ -3,6 +3,7 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
||||
import { getFieldColor } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
||||
import { $pendingConnection } from 'features/nodes/store/nodesSlice';
|
||||
import { selectShouldAnimateEdges, selectShouldColorEdges } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import type { ConnectionLineComponentProps } from 'reactflow';
|
||||
@ -12,8 +13,8 @@ const pathStyles: CSSProperties = { opacity: 0.8 };
|
||||
|
||||
const CustomConnectionLine = ({ fromX, fromY, fromPosition, toX, toY, toPosition }: ConnectionLineComponentProps) => {
|
||||
const pendingConnection = useStore($pendingConnection);
|
||||
const shouldColorEdges = useAppSelector((state) => state.workflowSettings.shouldColorEdges);
|
||||
const shouldAnimateEdges = useAppSelector((state) => state.workflowSettings.shouldAnimateEdges);
|
||||
const shouldColorEdges = useAppSelector(selectShouldColorEdges);
|
||||
const shouldAnimateEdges = useAppSelector(selectShouldAnimateEdges);
|
||||
const stroke = useMemo(() => {
|
||||
if (shouldColorEdges && pendingConnection) {
|
||||
return getFieldColor(pendingConnection.fieldTemplate.type);
|
||||
|
@ -3,6 +3,7 @@ import { useStore } from '@nanostores/react';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { getEdgeStyles } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectShouldShowEdgeLabels } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { memo, useMemo } from 'react';
|
||||
import type { EdgeProps } from 'reactflow';
|
||||
import { BaseEdge, EdgeLabelRenderer, getBezierPath } from 'reactflow';
|
||||
@ -30,7 +31,7 @@ const InvocationDefaultEdge = ({
|
||||
);
|
||||
|
||||
const { shouldAnimateEdges, areConnectedNodesSelected, stroke, label } = useAppSelector(selector);
|
||||
const shouldShowEdgeLabels = useAppSelector((s) => s.workflowSettings.shouldShowEdgeLabels);
|
||||
const shouldShowEdgeLabels = useAppSelector(selectShouldShowEdgeLabels);
|
||||
|
||||
const [edgePath, labelX, labelY] = getBezierPath({
|
||||
sourceX,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { Templates } from 'features/nodes/store/types';
|
||||
import { selectWorkflowSettingsSlice } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import InvocationNode from 'features/nodes/components/flow/nodes/Invocation/InvocationNode';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodes } from 'features/nodes/store/selectors';
|
||||
import type { InvocationNodeData } from 'features/nodes/types/invocation';
|
||||
import { memo, useMemo } from 'react';
|
||||
import type { NodeProps } from 'reactflow';
|
||||
@ -13,7 +15,11 @@ const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => {
|
||||
const { id: nodeId, type, isOpen, label } = data;
|
||||
const templates = useStore($templates);
|
||||
const hasTemplate = useMemo(() => Boolean(templates[type]), [templates, type]);
|
||||
const nodeExists = useAppSelector((s) => Boolean(s.nodes.present.nodes.find((n) => n.id === nodeId)));
|
||||
const selectNodeExists = useMemo(
|
||||
() => createSelector(selectNodes, (nodes) => Boolean(nodes.find((n) => n.id === nodeId))),
|
||||
[nodeId]
|
||||
);
|
||||
const nodeExists = useAppSelector(selectNodeExists);
|
||||
|
||||
if (!nodeExists) {
|
||||
return null;
|
||||
|
@ -2,8 +2,8 @@ import { Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectInvocationNode } from 'features/nodes/store/selectors';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectInvocationNode, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -3,6 +3,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useGroupedModelCombobox } from 'common/hooks/useGroupedModelCombobox';
|
||||
import { fieldT5EncoderValueChanged } from 'features/nodes/store/nodesSlice';
|
||||
import type { T5EncoderModelFieldInputInstance, T5EncoderModelFieldInputTemplate } from 'features/nodes/types/field';
|
||||
import { selectIsModelsTabDisabled } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useT5EncoderModels } from 'services/api/hooks/modelsByType';
|
||||
@ -15,7 +16,7 @@ type Props = FieldComponentProps<T5EncoderModelFieldInputInstance, T5EncoderMode
|
||||
const T5EncoderModelFieldInputComponent = (props: Props) => {
|
||||
const { nodeId, field } = props;
|
||||
const { t } = useTranslation();
|
||||
const disabledTabs = useAppSelector((s) => s.config.disabledTabs);
|
||||
const isModelsTabDisabled = useAppSelector(selectIsModelsTabDisabled);
|
||||
const dispatch = useAppDispatch();
|
||||
const [modelConfigs, { isLoading }] = useT5EncoderModels();
|
||||
const _onChange = useCallback(
|
||||
@ -42,7 +43,7 @@ const T5EncoderModelFieldInputComponent = (props: Props) => {
|
||||
|
||||
return (
|
||||
<Flex w="full" alignItems="center" gap={2}>
|
||||
<Tooltip label={!disabledTabs.includes('models') && t('modelManager.starterModelsInModelManager')}>
|
||||
<Tooltip label={!isModelsTabDisabled && t('modelManager.starterModelsInModelManager')}>
|
||||
<FormControl className="nowheel nodrag" isDisabled={!options.length} isInvalid={!value}>
|
||||
<Combobox
|
||||
value={value}
|
||||
|
@ -5,6 +5,8 @@ import NodeSelectionOverlay from 'common/components/NodeSelectionOverlay';
|
||||
import { useExecutionState } from 'features/nodes/hooks/useExecutionState';
|
||||
import { useMouseOverNode } from 'features/nodes/hooks/useMouseOverNode';
|
||||
import { nodesChanged } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodes } from 'features/nodes/store/selectors';
|
||||
import { selectNodeOpacity } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { DRAG_HANDLE_CLASSNAME, NODE_WIDTH } from 'features/nodes/types/constants';
|
||||
import { zNodeStatus } from 'features/nodes/types/invocation';
|
||||
import type { MouseEvent, PropsWithChildren } from 'react';
|
||||
@ -33,13 +35,13 @@ const NodeWrapper = (props: NodeWrapperProps) => {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const opacity = useAppSelector((s) => s.workflowSettings.nodeOpacity);
|
||||
const opacity = useAppSelector(selectNodeOpacity);
|
||||
const { onCloseGlobal } = useGlobalMenuClose();
|
||||
|
||||
const handleClick = useCallback(
|
||||
(e: MouseEvent<HTMLDivElement>) => {
|
||||
if (!e.ctrlKey && !e.altKey && !e.metaKey && !e.shiftKey) {
|
||||
const { nodes } = store.getState().nodes.present;
|
||||
const nodes = selectNodes(store.getState());
|
||||
const nodeChanges: NodeChange[] = [];
|
||||
nodes.forEach(({ id, selected }) => {
|
||||
if (selected !== (id === nodeId)) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { CompositeSlider, Flex } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { nodeOpacityChanged } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { nodeOpacityChanged, selectNodeOpacity } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const NodeOpacitySlider = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const nodeOpacity = useAppSelector((s) => s.workflowSettings.nodeOpacity);
|
||||
const nodeOpacity = useAppSelector(selectNodeOpacity);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChange = useCallback(
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { ButtonGroup, IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { shouldShowMinimapPanelChanged } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import {
|
||||
selectShouldShowMinimapPanel,
|
||||
shouldShowMinimapPanelChanged,
|
||||
} from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@ -15,7 +18,7 @@ const ViewportControls = () => {
|
||||
const { t } = useTranslation();
|
||||
const { zoomIn, zoomOut, fitView } = useReactFlow();
|
||||
const dispatch = useAppDispatch();
|
||||
const shouldShowMinimapPanel = useAppSelector((s) => s.workflowSettings.shouldShowMinimapPanel);
|
||||
const shouldShowMinimapPanel = useAppSelector(selectShouldShowMinimapPanel);
|
||||
|
||||
const handleClickedZoomIn = useCallback(() => {
|
||||
zoomIn({ duration: 300 });
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { SystemStyleObject } from '@invoke-ai/ui-library';
|
||||
import { chakra, Flex } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectShouldShowMinimapPanel } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { memo } from 'react';
|
||||
import { MiniMap } from 'reactflow';
|
||||
|
||||
@ -16,7 +17,7 @@ const minimapStyles: SystemStyleObject = {
|
||||
};
|
||||
|
||||
const MinimapPanel = () => {
|
||||
const shouldShowMinimapPanel = useAppSelector((s) => s.workflowSettings.shouldShowMinimapPanel);
|
||||
const shouldShowMinimapPanel = useAppSelector(selectShouldShowMinimapPanel);
|
||||
|
||||
return (
|
||||
<Flex gap={2} position="absolute" bottom={0} insetInlineEnd={0}>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { ConfirmationAlertDialog, Flex, IconButton, Text, useDisclosure } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { nodeEditorReset } from 'features/nodes/store/nodesSlice';
|
||||
import { selectWorkflowIsTouched } from 'features/nodes/store/workflowSlice';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -10,7 +11,7 @@ const ClearFlowButton = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const isTouched = useAppSelector((s) => s.workflow.isTouched);
|
||||
const isTouched = useAppSelector(selectWorkflowIsTouched);
|
||||
|
||||
const handleNewWorkflow = useCallback(() => {
|
||||
dispatch(nodeEditorReset());
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $builtWorkflow } from 'features/nodes/hooks/useWorkflowWatcher';
|
||||
import { selectWorkflowIsTouched } from 'features/nodes/store/workflowSlice';
|
||||
import { useSaveWorkflowAsDialog } from 'features/workflowLibrary/components/SaveWorkflowAsDialog/useSaveWorkflowAsDialog';
|
||||
import { isWorkflowWithID, useSaveLibraryWorkflow } from 'features/workflowLibrary/hooks/useSaveWorkflow';
|
||||
import { memo, useCallback } from 'react';
|
||||
@ -9,7 +10,7 @@ import { PiFloppyDiskBold } from 'react-icons/pi';
|
||||
|
||||
const SaveWorkflowButton = () => {
|
||||
const { t } = useTranslation();
|
||||
const isTouched = useAppSelector((s) => s.workflow.isTouched);
|
||||
const isTouched = useAppSelector(selectWorkflowIsTouched);
|
||||
const { onOpen } = useSaveWorkflowAsDialog();
|
||||
const { saveWorkflow } = useSaveLibraryWorkflow();
|
||||
|
||||
|
@ -5,11 +5,12 @@ import ClearFlowButton from 'features/nodes/components/flow/panels/TopPanel/Clea
|
||||
import SaveWorkflowButton from 'features/nodes/components/flow/panels/TopPanel/SaveWorkflowButton';
|
||||
import UpdateNodesButton from 'features/nodes/components/flow/panels/TopPanel/UpdateNodesButton';
|
||||
import { WorkflowName } from 'features/nodes/components/sidePanel/WorkflowName';
|
||||
import { selectWorkflowName } from 'features/nodes/store/workflowSlice';
|
||||
import WorkflowLibraryMenu from 'features/workflowLibrary/components/WorkflowLibraryMenu/WorkflowLibraryMenu';
|
||||
import { memo } from 'react';
|
||||
|
||||
const TopCenterPanel = () => {
|
||||
const name = useAppSelector((s) => s.workflow.name);
|
||||
const name = useAppSelector(selectWorkflowName);
|
||||
return (
|
||||
<Flex gap={2} top={0} left={0} right={0} position="absolute" alignItems="flex-start" pointerEvents="none">
|
||||
<Flex gap="2">
|
||||
|
@ -16,12 +16,16 @@ import {
|
||||
Switch,
|
||||
useDisclosure,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import ReloadNodeTemplatesButton from 'features/nodes/components/flow/panels/TopRightPanel/ReloadSchemaButton';
|
||||
import {
|
||||
selectionModeChanged,
|
||||
selectWorkflowSettingsSlice,
|
||||
selectSelectionMode,
|
||||
selectShouldAnimateEdges,
|
||||
selectShouldColorEdges,
|
||||
selectShouldShouldValidateGraph,
|
||||
selectShouldShowEdgeLabels,
|
||||
selectShouldSnapToGrid,
|
||||
shouldAnimateEdgesChanged,
|
||||
shouldColorEdgesChanged,
|
||||
shouldShowEdgeLabelsChanged,
|
||||
@ -35,25 +39,6 @@ import { SelectionMode } from 'reactflow';
|
||||
|
||||
const formLabelProps: FormLabelProps = { flexGrow: 1 };
|
||||
|
||||
const selector = createMemoizedSelector(selectWorkflowSettingsSlice, (workflowSettings) => {
|
||||
const {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
shouldShowEdgeLabels,
|
||||
selectionMode,
|
||||
} = workflowSettings;
|
||||
return {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
shouldShowEdgeLabels,
|
||||
selectionModeIsChecked: selectionMode === SelectionMode.Full,
|
||||
};
|
||||
});
|
||||
|
||||
type Props = {
|
||||
children: (props: { onOpen: () => void }) => ReactNode;
|
||||
};
|
||||
@ -61,14 +46,13 @@ type Props = {
|
||||
const WorkflowEditorSettings = ({ children }: Props) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
shouldShowEdgeLabels,
|
||||
selectionModeIsChecked,
|
||||
} = useAppSelector(selector);
|
||||
|
||||
const shouldSnapToGrid = useAppSelector(selectShouldSnapToGrid);
|
||||
const selectionMode = useAppSelector(selectSelectionMode);
|
||||
const shouldColorEdges = useAppSelector(selectShouldColorEdges);
|
||||
const shouldAnimateEdges = useAppSelector(selectShouldAnimateEdges);
|
||||
const shouldShowEdgeLabels = useAppSelector(selectShouldShowEdgeLabels);
|
||||
const shouldValidateGraph = useAppSelector(selectShouldShouldValidateGraph);
|
||||
|
||||
const handleChangeShouldValidate = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
@ -154,7 +138,7 @@ const WorkflowEditorSettings = ({ children }: Props) => {
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.fullyContainNodes')}</FormLabel>
|
||||
<Switch isChecked={selectionModeIsChecked} onChange={handleChangeSelectionMode} />
|
||||
<Switch isChecked={selectionMode === SelectionMode.Full} onChange={handleChangeSelectionMode} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.fullyContainNodesHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { Flex, IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { workflowModeChanged } from 'features/nodes/store/workflowSlice';
|
||||
import { selectWorkflowMode, workflowModeChanged } from 'features/nodes/store/workflowSlice';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiEyeBold, PiPencilBold } from 'react-icons/pi';
|
||||
|
||||
export const ModeToggle = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const mode = useAppSelector((s) => s.workflow.mode);
|
||||
const mode = useAppSelector(selectWorkflowMode);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onClickEdit = useCallback(() => {
|
||||
|
@ -2,6 +2,7 @@ import 'reactflow/dist/style.css';
|
||||
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectWorkflowMode } from 'features/nodes/store/workflowSlice';
|
||||
import QueueControls from 'features/queue/components/QueueControls';
|
||||
import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
|
||||
import { usePanelStorage } from 'features/ui/hooks/usePanelStorage';
|
||||
@ -20,7 +21,7 @@ import { WorkflowName } from './WorkflowName';
|
||||
const panelGroupStyles: CSSProperties = { height: '100%', width: '100%' };
|
||||
|
||||
const NodeEditorPanelGroup = () => {
|
||||
const mode = useAppSelector((s) => s.workflow.mode);
|
||||
const mode = useAppSelector(selectWorkflowMode);
|
||||
const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
|
||||
const panelStorage = usePanelStorage();
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { Flex } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import SaveWorkflowButton from 'features/nodes/components/flow/panels/TopPanel/SaveWorkflowButton';
|
||||
import { selectWorkflowMode } from 'features/nodes/store/workflowSlice';
|
||||
import { NewWorkflowButton } from 'features/workflowLibrary/components/NewWorkflowButton';
|
||||
|
||||
import { ModeToggle } from './ModeToggle';
|
||||
|
||||
export const WorkflowMenu = () => {
|
||||
const mode = useAppSelector((s) => s.workflow.mode);
|
||||
const mode = useAppSelector(selectWorkflowMode);
|
||||
|
||||
return (
|
||||
<Flex gap="2" alignItems="center">
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Flex, Icon, Text, Tooltip } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectWorkflowIsTouched, selectWorkflowMode, selectWorkflowName } from 'features/nodes/store/workflowSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiDotOutlineFill } from 'react-icons/pi';
|
||||
|
||||
@ -8,9 +9,9 @@ import { WorkflowWarning } from './viewMode/WorkflowWarning';
|
||||
|
||||
export const WorkflowName = () => {
|
||||
const { t } = useTranslation();
|
||||
const name = useAppSelector((s) => s.workflow.name);
|
||||
const isTouched = useAppSelector((s) => s.workflow.isTouched);
|
||||
const mode = useAppSelector((s) => s.workflow.mode);
|
||||
const name = useAppSelector(selectWorkflowName);
|
||||
const isTouched = useAppSelector(selectWorkflowIsTouched);
|
||||
const mode = useAppSelector(selectWorkflowMode);
|
||||
|
||||
return (
|
||||
<Flex gap="1" alignItems="center">
|
||||
|
@ -2,8 +2,7 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectLastSelectedNode } from 'features/nodes/store/selectors';
|
||||
import { selectLastSelectedNode, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -6,8 +6,8 @@ import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import NotesTextarea from 'features/nodes/components/flow/nodes/Invocation/NotesTextarea';
|
||||
import { useNodeNeedsUpdate } from 'features/nodes/hooks/useNodeNeedsUpdate';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectLastSelectedNode } from 'features/nodes/store/selectors';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectLastSelectedNode, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -6,8 +6,8 @@ import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||
import { useExecutionState } from 'features/nodes/hooks/useExecutionState';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectLastSelectedNode } from 'features/nodes/store/selectors';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectLastSelectedNode, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
@ -3,8 +3,8 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectLastSelectedNode } from 'features/nodes/store/selectors';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectLastSelectedNode, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
$templates,
|
||||
edgesChanged,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodes, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { getFirstValidConnection } from 'features/nodes/store/util/getFirstValidConnection';
|
||||
import { connectionToEdge } from 'features/nodes/store/util/reactFlowUtil';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
@ -24,7 +25,7 @@ export const useConnection = () => {
|
||||
const onConnectStart = useCallback<OnConnectStart>(
|
||||
(event, { nodeId, handleId, handleType }) => {
|
||||
assert(nodeId && handleId && handleType, 'Invalid connection start event');
|
||||
const nodes = store.getState().nodes.present.nodes;
|
||||
const nodes = selectNodes(store.getState());
|
||||
|
||||
const node = nodes.find((n) => n.id === nodeId);
|
||||
if (!node) {
|
||||
@ -72,7 +73,7 @@ export const useConnection = () => {
|
||||
if (!pendingConnection) {
|
||||
return;
|
||||
}
|
||||
const { nodes, edges } = store.getState().nodes.present;
|
||||
const { nodes, edges } = selectNodesSlice(store.getState());
|
||||
if (mouseOverNodeId) {
|
||||
const { handleType } = pendingConnection;
|
||||
const source = handleType === 'source' ? pendingConnection.nodeId : mouseOverNodeId;
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $edgePendingUpdate, $pendingConnection, $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { $edgePendingUpdate, $pendingConnection, $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { makeConnectionErrorSelector } from 'features/nodes/store/util/makeConnectionErrorSelector';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
|
@ -7,8 +7,8 @@ import {
|
||||
$edgesToCopiedNodes,
|
||||
edgesChanged,
|
||||
nodesChanged,
|
||||
selectNodesSlice,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { findUnoccupiedPosition } from 'features/nodes/store/util/findUnoccupiedPosition';
|
||||
import { isEqual, uniqWith } from 'lodash-es';
|
||||
import type { EdgeChange, NodeChange } from 'reactflow';
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodeData } from 'features/nodes/store/selectors';
|
||||
import { selectNodeData, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useDoesInputHaveValue = (nodeId: string, fieldName: string): boolean => {
|
||||
|
@ -2,7 +2,7 @@ import { useStore } from '@nanostores/react';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { NodeExecutionStates } from 'features/nodes/store/types';
|
||||
import type { NodeExecutionState } from 'features/nodes/types/invocation';
|
||||
import { zNodeStatus } from 'features/nodes/types/invocation';
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectFieldInputInstance } from 'features/nodes/store/selectors';
|
||||
import { selectFieldInputInstance, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { FieldInputInstance } from 'features/nodes/types/field';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectFieldInputInstance } from 'features/nodes/store/selectors';
|
||||
import { selectFieldInputInstance, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldLabel = (nodeId: string, fieldName: string): string | null => {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectInvocationNodeType } from 'features/nodes/store/selectors';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectInvocationNodeType, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { FieldInputTemplate, FieldOutputTemplate } from 'features/nodes/types/field';
|
||||
import { useMemo } from 'react';
|
||||
import { assert } from 'tsafe';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
||||
import { useMemo } from 'react';
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodeData } from 'features/nodes/store/selectors';
|
||||
import { selectNodeData, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useIsIntermediate = (nodeId: string): boolean => {
|
||||
|
@ -2,7 +2,9 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useAppSelector, useAppStore } from 'app/store/storeHooks';
|
||||
import { $edgePendingUpdate, $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { validateConnection } from 'features/nodes/store/util/validateConnection';
|
||||
import { selectShouldShouldValidateGraph } from 'features/nodes/store/workflowSettingsSlice';
|
||||
import { useCallback } from 'react';
|
||||
import type { Connection } from 'reactflow';
|
||||
|
||||
@ -14,7 +16,7 @@ import type { Connection } from 'reactflow';
|
||||
export const useIsValidConnection = () => {
|
||||
const store = useAppStore();
|
||||
const templates = useStore($templates);
|
||||
const shouldValidateGraph = useAppSelector((s) => s.workflowSettings.shouldValidateGraph);
|
||||
const shouldValidateGraph = useAppSelector(selectShouldShouldValidateGraph);
|
||||
const isValidConnection = useCallback(
|
||||
({ source, sourceHandle, target, targetHandle }: Connection): boolean => {
|
||||
// Connection must have valid targets
|
||||
@ -22,7 +24,7 @@ export const useIsValidConnection = () => {
|
||||
return false;
|
||||
}
|
||||
const edgePendingUpdate = $edgePendingUpdate.get();
|
||||
const { nodes, edges } = store.getState().nodes.present;
|
||||
const { nodes, edges } = selectNodesSlice(store.getState());
|
||||
|
||||
const validationResult = validateConnection(
|
||||
{ source, sourceHandle, target, targetHandle },
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodeData } from 'features/nodes/store/selectors';
|
||||
import { selectNodeData, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { InvocationNodeData } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodeLabel = (nodeId: string) => {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodeData } from 'features/nodes/store/selectors';
|
||||
import { selectNodeData, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodePack = (nodeId: string): string | null => {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectInvocationNodeType } from 'features/nodes/store/selectors';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectInvocationNodeType, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { InvocationTemplate } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
import { assert } from 'tsafe';
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { $templates, selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodeData } from 'features/nodes/store/selectors';
|
||||
import { selectNodeData, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useUseCache = (nodeId: string) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { selectWorkflowSlice } from 'features/nodes/store/workflowSlice';
|
||||
import type { WorkflowV3 } from 'features/nodes/types/workflow';
|
||||
import type { BuildWorkflowArg } from 'features/nodes/util/workflow/buildWorkflow';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { PayloadAction, UnknownAction } from '@reduxjs/toolkit';
|
||||
import { createSlice, isAnyOf } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import type { PersistConfig } from 'app/store/store';
|
||||
import { workflowLoaded } from 'features/nodes/store/actions';
|
||||
import { SHARED_NODE_PROPERTIES } from 'features/nodes/types/constants';
|
||||
import type {
|
||||
@ -452,8 +452,6 @@ export const openAddNodePopover = () => {
|
||||
$isAddNodePopoverOpen.set(true);
|
||||
};
|
||||
|
||||
export const selectNodesSlice = (state: RootState) => state.nodes.present;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateNodesState = (state: any): any => {
|
||||
if (!('_version' in state)) {
|
||||
|
@ -1,3 +1,6 @@
|
||||
import type { Selector } from '@reduxjs/toolkit';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import type { RootState } from 'app/store/store';
|
||||
import type { NodesState } from 'features/nodes/store/types';
|
||||
import type { FieldInputInstance } from 'features/nodes/types/field';
|
||||
import type { InvocationNode, InvocationNodeData } from 'features/nodes/types/invocation';
|
||||
@ -36,3 +39,17 @@ export const selectLastSelectedNode = (nodesSlice: NodesState) => {
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const selectNodesSlice = (state: RootState) => state.nodes.present;
|
||||
|
||||
const createNodesSelector = <T>(selector: Selector<NodesState, T>) => createSelector(selectNodesSlice, selector);
|
||||
export const selectNodes = createNodesSelector((nodes) => nodes.nodes);
|
||||
export const selectEdges = createNodesSelector((nodes) => nodes.edges);
|
||||
export const selectMayUndo = createSelector(
|
||||
(state: RootState) => state.nodes,
|
||||
(nodes) => nodes.past.length > 0
|
||||
);
|
||||
export const selectMayRedo = createSelector(
|
||||
(state: RootState) => state.nodes,
|
||||
(nodes) => nodes.future.length > 0
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import type { RootState } from 'app/store/store';
|
||||
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import type { NodesState, PendingConnection, Templates } from 'features/nodes/store/types';
|
||||
import { buildRejectResult, validateConnection } from 'features/nodes/store/util/validateConnection';
|
||||
import type { Edge, HandleType } from 'reactflow';
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import type { Selector } from 'react-redux';
|
||||
import { SelectionMode } from 'reactflow';
|
||||
|
||||
type WorkflowSettingsState = {
|
||||
@ -69,8 +70,6 @@ export const {
|
||||
selectionModeChanged,
|
||||
} = workflowSettingsSlice.actions;
|
||||
|
||||
export const selectWorkflowSettingsSlice = (state: RootState) => state.workflowSettings;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateWorkflowSettingsState = (state: any): any => {
|
||||
if (!('_version' in state)) {
|
||||
@ -85,3 +84,15 @@ export const workflowSettingsPersistConfig: PersistConfig<WorkflowSettingsState>
|
||||
migrate: migrateWorkflowSettingsState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
||||
export const selectWorkflowSettingsSlice = (state: RootState) => state.workflowSettings;
|
||||
const createWorkflowSettingsSelector = <T>(selector: Selector<WorkflowSettingsState, T>) =>
|
||||
createSelector(selectWorkflowSettingsSlice, selector);
|
||||
export const selectShouldSnapToGrid = createWorkflowSettingsSelector((s) => s.shouldSnapToGrid);
|
||||
export const selectSelectionMode = createWorkflowSettingsSelector((s) => s.selectionMode);
|
||||
export const selectShouldColorEdges = createWorkflowSettingsSelector((s) => s.shouldColorEdges);
|
||||
export const selectShouldAnimateEdges = createWorkflowSettingsSelector((s) => s.shouldAnimateEdges);
|
||||
export const selectShouldShowEdgeLabels = createWorkflowSettingsSelector((s) => s.shouldShowEdgeLabels);
|
||||
export const selectNodeOpacity = createWorkflowSettingsSelector((s) => s.nodeOpacity);
|
||||
export const selectShouldShowMinimapPanel = createWorkflowSettingsSelector((s) => s.shouldShowMinimapPanel);
|
||||
export const selectShouldShouldValidateGraph = createWorkflowSettingsSelector((s) => s.shouldValidateGraph);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import type { PayloadAction, Selector } from '@reduxjs/toolkit';
|
||||
import { createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import type { PersistConfig, RootState } from 'app/store/store';
|
||||
import { deepClone } from 'common/util/deepClone';
|
||||
import { workflowLoaded } from 'features/nodes/store/actions';
|
||||
@ -209,8 +209,6 @@ export const {
|
||||
workflowSaved,
|
||||
} = workflowSlice.actions;
|
||||
|
||||
export const selectWorkflowSlice = (state: RootState) => state.workflow;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateWorkflowState = (state: any): any => {
|
||||
if (!('_version' in state)) {
|
||||
@ -225,3 +223,12 @@ export const workflowPersistConfig: PersistConfig<WorkflowState> = {
|
||||
migrate: migrateWorkflowState,
|
||||
persistDenylist: [],
|
||||
};
|
||||
|
||||
export const selectWorkflowSlice = (state: RootState) => state.workflow;
|
||||
const createWorkflowSelector = <T>(selector: Selector<WorkflowState, T>) =>
|
||||
createSelector(selectWorkflowSlice, selector);
|
||||
|
||||
export const selectWorkflowName = createWorkflowSelector((workflow) => workflow.name);
|
||||
export const selectWorkflowId = createWorkflowSelector((workflow) => workflow.id);
|
||||
export const selectWorkflowMode = createWorkflowSelector((workflow) => workflow.mode);
|
||||
export const selectWorkflowIsTouched = createWorkflowSelector((workflow) => workflow.isTouched);
|
||||
|
@ -1,19 +1,14 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCfgRescaleMultiplier } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCFGRescaleMultiplier, setCfgRescaleMultiplier } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCFGRescaleMultiplierConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCFGRescaleMultiplier = () => {
|
||||
const cfgRescaleMultiplier = useAppSelector((s) => s.params.cfgRescaleMultiplier);
|
||||
const initial = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.cfgRescaleMultiplier.fineStep);
|
||||
const cfgRescaleMultiplier = useAppSelector(selectCFGRescaleMultiplier);
|
||||
const config = useAppSelector(selectCFGRescaleMultiplierConfig);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
@ -27,21 +22,21 @@ const ParamCFGRescaleMultiplier = () => {
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
value={cfgRescaleMultiplier}
|
||||
defaultValue={initial}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={handleChange}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={cfgRescaleMultiplier}
|
||||
defaultValue={initial}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</FormControl>
|
||||
|
@ -1,19 +1,16 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setClipSkip } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCLIPSKip, selectModel, setClipSkip } from 'features/controlLayers/store/paramsSlice';
|
||||
import { CLIP_SKIP_MAP } from 'features/parameters/types/constants';
|
||||
import { selectCLIPSkipConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamClipSkip = () => {
|
||||
const clipSkip = useAppSelector((s) => s.params.clipSkip);
|
||||
const initial = useAppSelector((s) => s.config.sd.clipSkip.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.clipSkip.sliderMin);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.clipSkip.numberInputMin);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.clipSkip.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.clipSkip.fineStep);
|
||||
const model = useAppSelector((s) => s.params.model);
|
||||
const clipSkip = useAppSelector(selectCLIPSKip);
|
||||
const config = useAppSelector(selectCLIPSkipConfig);
|
||||
const model = useAppSelector(selectModel);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
@ -50,21 +47,21 @@ const ParamClipSkip = () => {
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
value={clipSkip}
|
||||
defaultValue={initial}
|
||||
min={sliderMin}
|
||||
defaultValue={config.initial}
|
||||
min={config.sliderMin}
|
||||
max={max}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={handleClipSkipChange}
|
||||
marks={sliderMarks}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={clipSkip}
|
||||
defaultValue={initial}
|
||||
min={numberInputMin}
|
||||
defaultValue={config.initial}
|
||||
min={config.numberInputMin}
|
||||
max={max}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={handleClipSkipChange}
|
||||
/>
|
||||
</FormControl>
|
||||
|
@ -1,20 +1,15 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCanvasCoherenceEdgeSize } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCanvasCoherenceEdgeSize, setCanvasCoherenceEdgeSize } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCanvasCoherenceEdgeSizeConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCanvasCoherenceEdgeSize = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const canvasCoherenceEdgeSize = useAppSelector((s) => s.params.canvasCoherenceEdgeSize);
|
||||
const initial = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.canvasCoherenceEdgeSize.fineStep);
|
||||
const canvasCoherenceEdgeSize = useAppSelector(selectCanvasCoherenceEdgeSize);
|
||||
const config = useAppSelector(selectCanvasCoherenceEdgeSizeConfig);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -31,22 +26,22 @@ const ParamCanvasCoherenceEdgeSize = () => {
|
||||
<FormLabel>{t('parameters.coherenceEdgeSize')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
value={canvasCoherenceEdgeSize}
|
||||
defaultValue={initial}
|
||||
defaultValue={config.initial}
|
||||
onChange={handleChange}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
value={canvasCoherenceEdgeSize}
|
||||
defaultValue={initial}
|
||||
defaultValue={config.initial}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</FormControl>
|
||||
|
@ -1,13 +1,16 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCanvasCoherenceMinDenoise } from 'features/controlLayers/store/paramsSlice';
|
||||
import {
|
||||
selectCanvasCoherenceMinDenoise,
|
||||
setCanvasCoherenceMinDenoise,
|
||||
} from 'features/controlLayers/store/paramsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCanvasCoherenceMinDenoise = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const canvasCoherenceMinDenoise = useAppSelector((s) => s.params.canvasCoherenceMinDenoise);
|
||||
const canvasCoherenceMinDenoise = useAppSelector(selectCanvasCoherenceMinDenoise);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChange = useCallback(
|
||||
|
@ -2,14 +2,14 @@ import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCanvasCoherenceMode } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCanvasCoherenceMode, setCanvasCoherenceMode } from 'features/controlLayers/store/paramsSlice';
|
||||
import { isParameterCanvasCoherenceMode } from 'features/parameters/types/parameterSchemas';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCanvasCoherenceMode = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const canvasCoherenceMode = useAppSelector((s) => s.params.canvasCoherenceMode);
|
||||
const canvasCoherenceMode = useAppSelector(selectCanvasCoherenceMode);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const options = useMemo<ComboboxOption[]>(
|
||||
|
@ -1,21 +1,16 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setMaskBlur } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectMaskBlur, setMaskBlur } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectMaskBlurConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamMaskBlur = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const maskBlur = useAppSelector((s) => s.params.maskBlur);
|
||||
const initial = useAppSelector((s) => s.config.sd.maskBlur.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.maskBlur.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.maskBlur.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.maskBlur.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.maskBlur.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.maskBlur.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.maskBlur.fineStep);
|
||||
const maskBlur = useAppSelector(selectMaskBlur);
|
||||
const config = useAppSelector(selectMaskBlurConfig);
|
||||
|
||||
const handleChange = useCallback(
|
||||
(v: number) => {
|
||||
@ -30,23 +25,23 @@ const ParamMaskBlur = () => {
|
||||
<FormLabel>{t('parameters.maskBlur')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
value={maskBlur}
|
||||
defaultValue={initial}
|
||||
onChange={handleChange}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
defaultValue={config.initial}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
value={maskBlur}
|
||||
defaultValue={initial}
|
||||
onChange={handleChange}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { Box, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIColorPicker from 'common/components/IAIColorPicker';
|
||||
import { setInfillColorValue } from 'features/controlLayers/store/paramsSlice';
|
||||
import {
|
||||
selectInfillColorValue,
|
||||
selectInfillMethod,
|
||||
setInfillColorValue,
|
||||
} from 'features/controlLayers/store/paramsSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import type { RgbaColor } from 'react-colorful';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -9,8 +13,8 @@ import { useTranslation } from 'react-i18next';
|
||||
const ParamInfillColorOptions = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const infillColor = useAppSelector((s) => s.params.infillColorValue);
|
||||
const infillMethod = useAppSelector((s) => s.params.infillMethod);
|
||||
const infillColor = useAppSelector(selectInfillColorValue);
|
||||
const infillMethod = useAppSelector(selectInfillMethod);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
@ -2,7 +2,7 @@ import type { ComboboxOnChange, ComboboxOption } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setInfillMethod } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectInfillMethod, setInfillMethod } from 'features/controlLayers/store/paramsSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useGetAppConfigQuery } from 'services/api/endpoints/appInfo';
|
||||
@ -10,7 +10,7 @@ import { useGetAppConfigQuery } from 'services/api/endpoints/appInfo';
|
||||
const ParamInfillMethod = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const infillMethod = useAppSelector((s) => s.params.infillMethod);
|
||||
const infillMethod = useAppSelector(selectInfillMethod);
|
||||
const { data: appConfigData } = useGetAppConfigQuery();
|
||||
const options = useMemo<ComboboxOption[]>(
|
||||
() =>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { selectInfillMethod } from 'features/controlLayers/store/paramsSlice';
|
||||
import { memo } from 'react';
|
||||
|
||||
import ParamInfillColorOptions from './ParamInfillColorOptions';
|
||||
@ -6,7 +7,7 @@ import ParamInfillPatchmatchDownscaleSize from './ParamInfillPatchmatchDownscale
|
||||
import ParamInfillTilesize from './ParamInfillTilesize';
|
||||
|
||||
const ParamInfillOptions = () => {
|
||||
const infillMethod = useAppSelector((s) => s.params.infillMethod);
|
||||
const infillMethod = useAppSelector(selectInfillMethod);
|
||||
if (infillMethod === 'tile') {
|
||||
return <ParamInfillTilesize />;
|
||||
}
|
||||
|
@ -1,21 +1,20 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setInfillPatchmatchDownscaleSize } from 'features/controlLayers/store/paramsSlice';
|
||||
import {
|
||||
selectInfillMethod,
|
||||
selectInfillPatchmatchDownscaleSize,
|
||||
setInfillPatchmatchDownscaleSize,
|
||||
} from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectInfillPatchmatchDownscaleSizeConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamInfillPatchmatchDownscaleSize = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const infillMethod = useAppSelector((s) => s.params.infillMethod);
|
||||
const infillPatchmatchDownscaleSize = useAppSelector((s) => s.params.infillPatchmatchDownscaleSize);
|
||||
const initial = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.infillPatchmatchDownscaleSize.fineStep);
|
||||
const infillMethod = useAppSelector(selectInfillMethod);
|
||||
const infillPatchmatchDownscaleSize = useAppSelector(selectInfillPatchmatchDownscaleSize);
|
||||
const config = useAppSelector(selectInfillPatchmatchDownscaleSizeConfig);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -32,23 +31,23 @@ const ParamInfillPatchmatchDownscaleSize = () => {
|
||||
<FormLabel>{t('parameters.patchmatchDownScaleSize')}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
value={infillPatchmatchDownscaleSize}
|
||||
defaultValue={initial}
|
||||
onChange={handleChange}
|
||||
marks
|
||||
defaultValue={config.initial}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
value={infillPatchmatchDownscaleSize}
|
||||
defaultValue={initial}
|
||||
onChange={handleChange}
|
||||
defaultValue={config.initial}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
|
@ -1,21 +1,15 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setInfillTileSize } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectInfillMethod, selectInfillTileSize, setInfillTileSize } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectInfillTileSizeConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamInfillTileSize = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const infillTileSize = useAppSelector((s) => s.params.infillTileSize);
|
||||
const initial = useAppSelector((s) => s.config.sd.infillTileSize.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.infillTileSize.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.infillTileSize.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.infillTileSize.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.infillTileSize.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.infillTileSize.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.infillTileSize.fineStep);
|
||||
|
||||
const infillMethod = useAppSelector((s) => s.params.infillMethod);
|
||||
const infillTileSize = useAppSelector(selectInfillTileSize);
|
||||
const config = useAppSelector(selectInfillTileSizeConfig);
|
||||
const infillMethod = useAppSelector(selectInfillMethod);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@ -30,23 +24,23 @@ const ParamInfillTileSize = () => {
|
||||
<FormControl isDisabled={infillMethod !== 'tile'}>
|
||||
<FormLabel>{t('parameters.tileSize')}</FormLabel>
|
||||
<CompositeSlider
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
value={infillTileSize}
|
||||
defaultValue={initial}
|
||||
onChange={handleChange}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
marks
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
value={infillTileSize}
|
||||
defaultValue={initial}
|
||||
onChange={handleChange}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { setImg2imgStrength } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectImg2imgStrength, setImg2imgStrength } from 'features/controlLayers/store/paramsSlice';
|
||||
import ImageToImageStrength from 'features/parameters/components/ImageToImage/ImageToImageStrength';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
const ParamImageToImageStrength = () => {
|
||||
const img2imgStrength = useAppSelector((s) => s.params.img2imgStrength);
|
||||
const img2imgStrength = useAppSelector(selectImg2imgStrength);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onChange = useCallback(
|
||||
|
@ -1,22 +1,20 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setCfgScale } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCFGScale, setCfgScale } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectCFGScaleConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamCFGScale = () => {
|
||||
const cfgScale = useAppSelector((s) => s.params.cfgScale);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.guidance.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.guidance.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.guidance.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.guidance.numberInputMax);
|
||||
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 cfgScale = useAppSelector(selectCFGScale);
|
||||
const config = useAppSelector(selectCFGScaleConfig);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||
const marks = useMemo(
|
||||
() => [config.sliderMin, Math.floor(config.sliderMax / 2), config.sliderMax],
|
||||
[config.sliderMax, config.sliderMin]
|
||||
);
|
||||
const onChange = useCallback((v: number) => dispatch(setCfgScale(v)), [dispatch]);
|
||||
|
||||
return (
|
||||
@ -26,21 +24,21 @@ const ParamCFGScale = () => {
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
value={cfgScale}
|
||||
defaultValue={initial}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
marks={marks}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={cfgScale}
|
||||
defaultValue={initial}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
|
@ -1,21 +1,25 @@
|
||||
import { Box, Textarea } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { negativePromptChanged } from 'features/controlLayers/store/paramsSlice';
|
||||
import { negativePromptChanged, selectNegativePrompt } from 'features/controlLayers/store/paramsSlice';
|
||||
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
|
||||
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
|
||||
import { ViewModePrompt } from 'features/parameters/components/Prompts/ViewModePrompt';
|
||||
import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
|
||||
import { PromptPopover } from 'features/prompt/PromptPopover';
|
||||
import { usePrompt } from 'features/prompt/usePrompt';
|
||||
import {
|
||||
selectStylePresetActivePresetId,
|
||||
selectStylePresetViewMode,
|
||||
} from 'features/stylePresets/store/stylePresetSlice';
|
||||
import { memo, useCallback, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
export const ParamNegativePrompt = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const prompt = useAppSelector((s) => s.params.negativePrompt);
|
||||
const viewMode = useAppSelector((s) => s.stylePreset.viewMode);
|
||||
const activeStylePresetId = useAppSelector((s) => s.stylePreset.activeStylePresetId);
|
||||
const prompt = useAppSelector(selectNegativePrompt);
|
||||
const viewMode = useAppSelector(selectStylePresetViewMode);
|
||||
const activeStylePresetId = useAppSelector(selectStylePresetActivePresetId);
|
||||
|
||||
const { activeStylePreset } = useListStylePresetsQuery(undefined, {
|
||||
selectFromResult: ({ data }) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Box, Textarea } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { positivePromptChanged } from 'features/controlLayers/store/paramsSlice';
|
||||
import { positivePromptChanged, selectBase, selectPositivePrompt } from 'features/controlLayers/store/paramsSlice';
|
||||
import { ShowDynamicPromptsPreviewButton } from 'features/dynamicPrompts/components/ShowDynamicPromptsPreviewButton';
|
||||
import { PromptLabel } from 'features/parameters/components/Prompts/PromptLabel';
|
||||
import { PromptOverlayButtonWrapper } from 'features/parameters/components/Prompts/PromptOverlayButtonWrapper';
|
||||
@ -9,6 +9,10 @@ import { AddPromptTriggerButton } from 'features/prompt/AddPromptTriggerButton';
|
||||
import { PromptPopover } from 'features/prompt/PromptPopover';
|
||||
import { usePrompt } from 'features/prompt/usePrompt';
|
||||
import { SDXLConcatButton } from 'features/sdxl/components/SDXLPrompts/SDXLConcatButton';
|
||||
import {
|
||||
selectStylePresetActivePresetId,
|
||||
selectStylePresetViewMode,
|
||||
} from 'features/stylePresets/store/stylePresetSlice';
|
||||
import { memo, useCallback, useRef } from 'react';
|
||||
import type { HotkeyCallback } from 'react-hotkeys-hook';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
@ -17,10 +21,10 @@ import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
export const ParamPositivePrompt = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const prompt = useAppSelector((s) => s.params.positivePrompt);
|
||||
const baseModel = useAppSelector((s) => s.params.model)?.base;
|
||||
const viewMode = useAppSelector((s) => s.stylePreset.viewMode);
|
||||
const activeStylePresetId = useAppSelector((s) => s.stylePreset.activeStylePresetId);
|
||||
const prompt = useAppSelector(selectPositivePrompt);
|
||||
const baseModel = useAppSelector(selectBase);
|
||||
const viewMode = useAppSelector(selectStylePresetViewMode);
|
||||
const activeStylePresetId = useAppSelector(selectStylePresetActivePresetId);
|
||||
|
||||
const { activeStylePreset } = useListStylePresetsQuery(undefined, {
|
||||
selectFromResult: ({ data }) => {
|
||||
|
@ -2,7 +2,7 @@ import type { ComboboxOnChange } from '@invoke-ai/ui-library';
|
||||
import { Combobox, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setScheduler } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectScheduler, setScheduler } from 'features/controlLayers/store/paramsSlice';
|
||||
import { SCHEDULER_OPTIONS } from 'features/parameters/types/constants';
|
||||
import { isParameterScheduler } from 'features/parameters/types/parameterSchemas';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
|
||||
const ParamScheduler = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const scheduler = useAppSelector((s) => s.params.scheduler);
|
||||
const scheduler = useAppSelector(selectScheduler);
|
||||
|
||||
const onChange = useCallback<ComboboxOnChange>(
|
||||
(v) => {
|
||||
|
@ -1,22 +1,20 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { setSteps } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectSteps, setSteps } from 'features/controlLayers/store/paramsSlice';
|
||||
import { selectStepsConfig } from 'features/system/store/configSlice';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const ParamSteps = () => {
|
||||
const steps = useAppSelector((s) => s.params.steps);
|
||||
const initial = useAppSelector((s) => s.config.sd.steps.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.steps.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.steps.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.steps.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.steps.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.steps.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.steps.fineStep);
|
||||
const steps = useAppSelector(selectSteps);
|
||||
const config = useAppSelector(selectStepsConfig);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const marks = useMemo(() => [sliderMin, Math.floor(sliderMax / 2), sliderMax], [sliderMax, sliderMin]);
|
||||
const marks = useMemo(
|
||||
() => [config.sliderMin, Math.floor(config.sliderMax / 2), config.sliderMax],
|
||||
[config.sliderMax, config.sliderMin]
|
||||
);
|
||||
const onChange = useCallback(
|
||||
(v: number) => {
|
||||
dispatch(setSteps(v));
|
||||
@ -31,21 +29,21 @@ const ParamSteps = () => {
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
value={steps}
|
||||
defaultValue={initial}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
marks={marks}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
value={steps}
|
||||
defaultValue={initial}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
defaultValue={config.initial}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { CompositeNumberInput, CompositeSlider, FormControl, FormLabel } from '@invoke-ai/ui-library';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import { selectImg2imgStrengthConfig } from 'features/system/store/configSlice';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@ -12,13 +13,7 @@ type Props = {
|
||||
};
|
||||
|
||||
const ImageToImageStrength = ({ value, onChange }: Props) => {
|
||||
const initial = useAppSelector((s) => s.config.sd.img2imgStrength.initial);
|
||||
const sliderMin = useAppSelector((s) => s.config.sd.img2imgStrength.sliderMin);
|
||||
const sliderMax = useAppSelector((s) => s.config.sd.img2imgStrength.sliderMax);
|
||||
const numberInputMin = useAppSelector((s) => s.config.sd.img2imgStrength.numberInputMin);
|
||||
const numberInputMax = useAppSelector((s) => s.config.sd.img2imgStrength.numberInputMax);
|
||||
const coarseStep = useAppSelector((s) => s.config.sd.img2imgStrength.coarseStep);
|
||||
const fineStep = useAppSelector((s) => s.config.sd.img2imgStrength.fineStep);
|
||||
const config = useAppSelector(selectImg2imgStrengthConfig);
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
@ -27,23 +22,23 @@ const ImageToImageStrength = ({ value, onChange }: Props) => {
|
||||
<FormLabel>{`${t('parameters.denoisingStrength')}`}</FormLabel>
|
||||
</InformationalPopover>
|
||||
<CompositeSlider
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={sliderMin}
|
||||
max={sliderMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
min={config.sliderMin}
|
||||
max={config.sliderMax}
|
||||
defaultValue={config.initial}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
defaultValue={initial}
|
||||
marks={marks}
|
||||
/>
|
||||
<CompositeNumberInput
|
||||
step={coarseStep}
|
||||
fineStep={fineStep}
|
||||
min={numberInputMin}
|
||||
max={numberInputMax}
|
||||
step={config.coarseStep}
|
||||
fineStep={config.fineStep}
|
||||
min={config.numberInputMin}
|
||||
max={config.numberInputMax}
|
||||
defaultValue={config.initial}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
defaultValue={initial}
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user