feat(ui): disable control adapter buttons if no models available

This commit is contained in:
psychedelicious 2023-10-07 17:07:32 +11:00
parent 078c9b6964
commit ed82bf6bb8
14 changed files with 927 additions and 1868 deletions

View File

@ -49,9 +49,10 @@
"cancel": "Cancel",
"close": "Close",
"communityLabel": "Community",
"controlNet": "Controlnet",
"controlNet": "ControlNet",
"controlAdapter": "Control Adapter",
"ipAdapter": "IP Adapter",
"t2iAdapter": "T2I Adapter",
"darkMode": "Dark Mode",
"discordLabel": "Discord",
"dontAskMeAgain": "Don't ask me again",
@ -132,9 +133,12 @@
},
"controlnet": {
"controlAdapter": "Control Adapter",
"controlnet": "$t(controlnet.controlAdapter) #{{number}} (Control Net)",
"ip_adapter": "$t(controlnet.controlAdapter) #{{number}} (IP Adapter)",
"t2i_adapter": "$t(controlnet.controlAdapter) #{{number}} (T2I Adapter)",
"controlnet": "$t(controlnet.controlAdapter) #{{number}} ($t(common.controlNet))",
"ip_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.ipAdapter))",
"t2i_adapter": "$t(controlnet.controlAdapter) #{{number}} ($t(common.t2iAdapter))",
"addControlNet": "Add $t(common.controlNet)",
"addIPAdapter": "Add $t(common.ipAdapter)",
"addT2IAdapter": "Add $t(common.t2iAdapter)",
"amult": "a_mult",
"autoConfigure": "Auto configure processor",
"balanced": "Balanced",

View File

@ -1,7 +1,7 @@
import { logger } from 'app/logging/logger';
import { setBoundingBoxDimensions } from 'features/canvas/store/canvasSlice';
import {
controlAdapterRemoved,
controlAdapterModelCleared,
selectControlAdapterAll,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { loraRemoved } from 'features/lora/store/loraSlice';
@ -15,9 +15,9 @@ import {
import { zMainOrOnnxModel } from 'features/parameters/types/parameterSchemas';
import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast';
import { t } from 'i18next';
import { forEach } from 'lodash-es';
import { startAppListening } from '..';
import { t } from 'i18next';
export const addModelSelectedListener = () => {
startAppListening({
@ -62,7 +62,7 @@ export const addModelSelectedListener = () => {
// handle incompatible controlnets
selectControlAdapterAll(state.controlAdapters).forEach((ca) => {
if (ca.model?.base_model !== base_model) {
dispatch(controlAdapterRemoved({ id: ca.id }));
dispatch(controlAdapterModelCleared({ id: ca.id }));
modelsCleared += 1;
}
});

View File

@ -6,9 +6,6 @@ import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIButton from 'common/components/IAIButton';
import IAICollapse from 'common/components/IAICollapse';
import ControlAdapterConfig from 'features/controlAdapters/components/ControlAdapterConfig';
import { useAddControlNet } from 'features/controlAdapters/hooks/useAddControlNet';
import { useAddIPAdapter } from 'features/controlAdapters/hooks/useAddIPAdapter';
import { useAddT2IAdapter } from 'features/controlAdapters/hooks/useAddT2IAdapter';
import {
selectAllControlNets,
selectAllIPAdapters,
@ -18,6 +15,8 @@ import {
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { Fragment, memo } from 'react';
import { FaPlus } from 'react-icons/fa';
import { useAddControlAdapter } from '../hooks/useAddControlAdapter';
import { useTranslation } from 'react-i18next';
const selector = createSelector(
[stateSelector],
@ -50,12 +49,17 @@ const selector = createSelector(
defaultSelectorOptions
);
const ParamControlAdaptersCollapse = () => {
const ControlAdaptersCollapse = () => {
const { t } = useTranslation();
const { controlAdapterIds, activeLabel } = useAppSelector(selector);
const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled;
const { addControlNet } = useAddControlNet();
const { addIPAdapter } = useAddIPAdapter();
const { addT2IAdapter } = useAddT2IAdapter();
const [addControlNet, isAddControlNetDisabled] =
useAddControlAdapter('controlnet');
const [addIPAdapter, isAddIPAdapterDisabled] =
useAddControlAdapter('ip_adapter');
const [addT2IAdapter, isAddT2IAdapterDisabled] =
useAddControlAdapter('t2i_adapter');
if (isControlNetDisabled) {
return null;
@ -66,28 +70,34 @@ const ParamControlAdaptersCollapse = () => {
<Flex sx={{ flexDir: 'column', gap: 2 }}>
<ButtonGroup size="sm" w="full" justifyContent="space-between">
<IAIButton
tooltip={t('controlnet.addControlNet')}
leftIcon={<FaPlus />}
onClick={addControlNet}
data-testid="add controlnet"
flexGrow={1}
isDisabled={isAddControlNetDisabled}
>
ControlNet
{t('common.controlNet')}
</IAIButton>
<IAIButton
tooltip={t('controlnet.addIPAdapter')}
leftIcon={<FaPlus />}
onClick={addIPAdapter}
data-testid="add ip adapter"
flexGrow={1}
isDisabled={isAddIPAdapterDisabled}
>
IP Adapter
{t('common.ipAdapter')}
</IAIButton>
<IAIButton
tooltip={t('controlnet.addT2IAdapter')}
leftIcon={<FaPlus />}
onClick={addT2IAdapter}
data-testid="add t2i adapter"
flexGrow={1}
isDisabled={isAddT2IAdapterDisabled}
>
T2I Adapter
{t('common.t2iAdapter')}
</IAIButton>
</ButtonGroup>
{controlAdapterIds.map((id, i) => (
@ -101,4 +111,4 @@ const ParamControlAdaptersCollapse = () => {
);
};
export default memo(ParamControlAdaptersCollapse);
export default memo(ControlAdaptersCollapse);

View File

@ -0,0 +1,43 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { controlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice';
import { useCallback, useMemo } from 'react';
import { ControlAdapterType } from '../store/types';
import { useControlAdapterModels } from './useControlAdapterModels';
export const useAddControlAdapter = (type: ControlAdapterType) => {
const baseModel = useAppSelector(
(state) => state.generation.model?.base_model
);
const dispatch = useAppDispatch();
const models = useControlAdapterModels(type);
const firstModel = useMemo(() => {
// prefer to use a model that matches the base model
const firstCompatibleModel = models.filter((m) =>
baseModel ? m.base_model === baseModel : true
)[0];
if (firstCompatibleModel) {
return firstCompatibleModel;
}
return models[0];
}, [baseModel, models]);
const isDisabled = useMemo(() => !firstModel, [firstModel]);
const addControlAdapter = useCallback(() => {
if (isDisabled) {
return;
}
dispatch(
controlAdapterAdded({
type,
overrides: { model: firstModel },
})
);
}, [dispatch, firstModel, isDisabled, type]);
return [addControlAdapter, isDisabled] as const;
};

View File

@ -1,45 +0,0 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { controlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice';
import { useCallback, useMemo } from 'react';
import {
controlNetModelsAdapter,
useGetControlNetModelsQuery,
} from 'services/api/endpoints/models';
export const useAddControlNet = () => {
const dispatch = useAppDispatch();
const baseModel = useAppSelector(
(state) => state.generation.model?.base_model
);
const { data: controlNetModels } = useGetControlNetModelsQuery();
const firstControlNetModel = useMemo(
() =>
controlNetModels
? controlNetModelsAdapter
.getSelectors()
.selectAll(controlNetModels)
.filter((m) => (baseModel ? m.base_model === baseModel : true))[0]
: undefined,
[baseModel, controlNetModels]
);
const isDisabled = useMemo(
() => !firstControlNetModel,
[firstControlNetModel]
);
const addControlNet = useCallback(() => {
if (isDisabled) {
return;
}
dispatch(
controlAdapterAdded({
type: 'controlnet',
overrides: { model: firstControlNetModel },
})
);
}, [dispatch, firstControlNetModel, isDisabled]);
return {
addControlNet,
isDisabled,
};
};

View File

@ -1,63 +0,0 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import {
controlAdapterAdded,
selectAllIPAdapters,
} from 'features/controlAdapters/store/controlAdaptersSlice';
import { useCallback, useMemo } from 'react';
import {
ipAdapterModelsAdapter,
useGetIPAdapterModelsQuery,
} from 'services/api/endpoints/models';
const selector = createSelector(
[stateSelector],
({ controlAdapters, generation }) => {
const ipAdapterCount = selectAllIPAdapters(controlAdapters).length;
const { model } = generation;
return {
ipAdapterCount,
baseModel: model?.base_model,
};
},
defaultSelectorOptions
);
export const useAddIPAdapter = () => {
const { ipAdapterCount, baseModel } = useAppSelector(selector);
const dispatch = useAppDispatch();
const { data: ipAdapterModels } = useGetIPAdapterModelsQuery();
const firstIPAdapterModel = useMemo(
() =>
ipAdapterModels
? ipAdapterModelsAdapter
.getSelectors()
.selectAll(ipAdapterModels)
.filter((m) => (baseModel ? m.base_model === baseModel : true))[0]
: undefined,
[baseModel, ipAdapterModels]
);
const isDisabled = useMemo(
() => !firstIPAdapterModel && ipAdapterCount === 0,
[firstIPAdapterModel, ipAdapterCount]
);
const addIPAdapter = useCallback(() => {
if (isDisabled) {
return;
}
dispatch(
controlAdapterAdded({
type: 'ip_adapter',
overrides: { model: firstIPAdapterModel },
})
);
}, [dispatch, firstIPAdapterModel, isDisabled]);
return {
addIPAdapter,
isDisabled,
};
};

View File

@ -1,45 +0,0 @@
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { controlAdapterAdded } from 'features/controlAdapters/store/controlAdaptersSlice';
import { useCallback, useMemo } from 'react';
import {
t2iAdapterModelsAdapter,
useGetT2IAdapterModelsQuery,
} from 'services/api/endpoints/models';
export const useAddT2IAdapter = () => {
const dispatch = useAppDispatch();
const baseModel = useAppSelector(
(state) => state.generation.model?.base_model
);
const { data: t2iAdapterModels } = useGetT2IAdapterModelsQuery();
const firstT2IAdapterModel = useMemo(
() =>
t2iAdapterModels
? t2iAdapterModelsAdapter
.getSelectors()
.selectAll(t2iAdapterModels)
.filter((m) => (baseModel ? m.base_model === baseModel : true))[0]
: undefined,
[baseModel, t2iAdapterModels]
);
const isDisabled = useMemo(
() => !firstT2IAdapterModel,
[firstT2IAdapterModel]
);
const addT2IAdapter = useCallback(() => {
if (isDisabled) {
return;
}
dispatch(
controlAdapterAdded({
type: 't2i_adapter',
overrides: { model: firstT2IAdapterModel },
})
);
}, [dispatch, firstT2IAdapterModel, isDisabled]);
return {
addT2IAdapter,
isDisabled,
};
};

View File

@ -1,7 +1,7 @@
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamControlAdaptersCollapse from 'features/parameters/components/Parameters/ControlAdapters/ParamControlAdaptersCollapse';
import ControlAdaptersCollapse from 'features/controlAdapters/components/ControlAdaptersCollapse';
import { memo } from 'react';
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse';
@ -13,7 +13,7 @@ const SDXLImageToImageTabParameters = () => {
<ParamSDXLPromptArea />
<SDXLImageToImageTabCoreParameters />
<ParamSDXLRefinerCollapse />
<ParamControlAdaptersCollapse />
<ControlAdaptersCollapse />
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamAdvancedCollapse />

View File

@ -1,7 +1,7 @@
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamControlAdaptersCollapse from 'features/parameters/components/Parameters/ControlAdapters/ParamControlAdaptersCollapse';
import ControlAdaptersCollapse from 'features/controlAdapters/components/ControlAdaptersCollapse';
import TextToImageTabCoreParameters from 'features/ui/components/tabs/TextToImage/TextToImageTabCoreParameters';
import { memo } from 'react';
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
@ -13,7 +13,7 @@ const SDXLTextToImageTabParameters = () => {
<ParamSDXLPromptArea />
<TextToImageTabCoreParameters />
<ParamSDXLRefinerCollapse />
<ParamControlAdaptersCollapse />
<ControlAdaptersCollapse />
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamAdvancedCollapse />

View File

@ -3,7 +3,7 @@ import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamCompositingSettingsCollapse from 'features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse';
import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse';
import ParamControlAdaptersCollapse from 'features/parameters/components/Parameters/ControlAdapters/ParamControlAdaptersCollapse';
import ControlAdaptersCollapse from 'features/controlAdapters/components/ControlAdaptersCollapse';
import ParamSDXLPromptArea from './ParamSDXLPromptArea';
import ParamSDXLRefinerCollapse from './ParamSDXLRefinerCollapse';
import SDXLUnifiedCanvasTabCoreParameters from './SDXLUnifiedCanvasTabCoreParameters';
@ -14,7 +14,7 @@ export default function SDXLUnifiedCanvasTabParameters() {
<ParamSDXLPromptArea />
<SDXLUnifiedCanvasTabCoreParameters />
<ParamSDXLRefinerCollapse />
<ParamControlAdaptersCollapse />
<ControlAdaptersCollapse />
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamInfillAndScalingCollapse />

View File

@ -1,7 +1,7 @@
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamControlAdaptersCollapse from 'features/parameters/components/Parameters/ControlAdapters/ParamControlAdaptersCollapse';
import ControlAdaptersCollapse from 'features/controlAdapters/components/ControlAdaptersCollapse';
import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
import { memo } from 'react';
@ -12,7 +12,7 @@ const ImageToImageTabParameters = () => {
<>
<ParamPromptArea />
<ImageToImageTabCoreParameters />
<ParamControlAdaptersCollapse />
<ControlAdaptersCollapse />
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamSymmetryCollapse />

View File

@ -1,7 +1,7 @@
import ParamDynamicPromptsCollapse from 'features/dynamicPrompts/components/ParamDynamicPromptsCollapse';
import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamControlAdaptersCollapse from 'features/parameters/components/Parameters/ControlAdapters/ParamControlAdaptersCollapse';
import ControlAdaptersCollapse from 'features/controlAdapters/components/ControlAdaptersCollapse';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
import { memo } from 'react';
import ParamPromptArea from '../../../../parameters/components/Parameters/Prompt/ParamPromptArea';
@ -12,7 +12,7 @@ const TextToImageTabParameters = () => {
<>
<ParamPromptArea />
<TextToImageTabCoreParameters />
<ParamControlAdaptersCollapse />
<ControlAdaptersCollapse />
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamSymmetryCollapse />

View File

@ -3,7 +3,7 @@ import ParamLoraCollapse from 'features/lora/components/ParamLoraCollapse';
import ParamAdvancedCollapse from 'features/parameters/components/Parameters/Advanced/ParamAdvancedCollapse';
import ParamCompositingSettingsCollapse from 'features/parameters/components/Parameters/Canvas/Compositing/ParamCompositingSettingsCollapse';
import ParamInfillAndScalingCollapse from 'features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillAndScalingCollapse';
import ParamControlAdaptersCollapse from 'features/parameters/components/Parameters/ControlAdapters/ParamControlAdaptersCollapse';
import ControlAdaptersCollapse from 'features/controlAdapters/components/ControlAdaptersCollapse';
import ParamPromptArea from 'features/parameters/components/Parameters/Prompt/ParamPromptArea';
import ParamSymmetryCollapse from 'features/parameters/components/Parameters/Symmetry/ParamSymmetryCollapse';
import { memo } from 'react';
@ -14,7 +14,7 @@ const UnifiedCanvasParameters = () => {
<>
<ParamPromptArea />
<UnifiedCanvasCoreParameters />
<ParamControlAdaptersCollapse />
<ControlAdaptersCollapse />
<ParamLoraCollapse />
<ParamDynamicPromptsCollapse />
<ParamSymmetryCollapse />

File diff suppressed because one or more lines are too long