diff --git a/invokeai/frontend/web/src/app/types/invokeai.ts b/invokeai/frontend/web/src/app/types/invokeai.ts
index b79504d8f2..d0e5437d36 100644
--- a/invokeai/frontend/web/src/app/types/invokeai.ts
+++ b/invokeai/frontend/web/src/app/types/invokeai.ts
@@ -326,11 +326,11 @@ export type AppFeature =
/**
* A disable-able Stable Diffusion feature
*/
-export type StableDiffusionFeature =
- | 'noiseConfig'
- | 'variations'
+export type SDFeature =
+ | 'noise'
+ | 'variation'
| 'symmetry'
- | 'tiling'
+ | 'seamless'
| 'hires';
/**
@@ -348,6 +348,7 @@ export type AppConfig = {
shouldFetchImages: boolean;
disabledTabs: InvokeTabName[];
disabledFeatures: AppFeature[];
+ disabledSDFeatures: SDFeature[];
canRestoreDeletedImagesFromBin: boolean;
sd: {
iterations: {
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
index 2a3d12ce91..e76f3fa41e 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImageButtons.tsx
@@ -152,6 +152,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
} = useAppSelector(currentImageButtonsSelector);
const isLightboxEnabled = useFeatureStatus('lightbox').isFeatureEnabled;
+ const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled;
const isUpscalingEnabled = useFeatureStatus('upscaling').isFeatureEnabled;
const isFaceRestoreEnabled = useFeatureStatus('faceRestore').isFeatureEnabled;
@@ -429,13 +430,15 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
>
{t('parameters.sendToImg2Img')}
- }
- >
- {t('parameters.sendToUnifiedCanvas')}
-
+ {isCanvasEnabled && (
+ }
+ >
+ {t('parameters.sendToUnifiedCanvas')}
+
+ )}
{/* {
const toast = useToast();
const { t } = useTranslation();
- const { isFeatureEnabled: isLightboxEnabled } = useFeatureStatus('lightbox');
+
+ const isLightboxEnabled = useFeatureStatus('lightbox').isFeatureEnabled;
+ const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled;
+
const { recallSeed, recallPrompt, recallInitialImage, recallAllParameters } =
useParameters();
@@ -250,9 +253,11 @@ const HoverableImage = memo((props: HoverableImageProps) => {
>
{t('parameters.sendToImg2Img')}
- } onClickCapture={handleSendToCanvas}>
- {t('parameters.sendToUnifiedCanvas')}
-
+ {isCanvasEnabled && (
+ } onClickCapture={handleSendToCanvas}>
+ {t('parameters.sendToUnifiedCanvas')}
+
+ )}
} onClickCapture={onDeleteDialogOpen}>
{t('gallery.deleteImage')}
diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Hires/ParamHiresCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Hires/ParamHiresCollapse.tsx
index 9c1f3a3f14..b4b077ad6c 100644
--- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Hires/ParamHiresCollapse.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Hires/ParamHiresCollapse.tsx
@@ -6,6 +6,7 @@ import IAICollapse from 'common/components/IAICollapse';
import { memo } from 'react';
import { ParamHiresStrength } from './ParamHiresStrength';
import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
+import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
const ParamHiresCollapse = () => {
const { t } = useTranslation();
@@ -13,10 +14,16 @@ const ParamHiresCollapse = () => {
(state: RootState) => state.postprocessing.hiresFix
);
+ const isHiresEnabled = useFeatureStatus('hires').isFeatureEnabled;
+
const dispatch = useAppDispatch();
const handleToggle = () => dispatch(setHiresFix(!hiresFix));
+ if (!isHiresEnabled) {
+ return null;
+ }
+
return (
{
const { t } = useTranslation();
+
+ const isNoiseEnabled = useFeatureStatus('noise').isFeatureEnabled;
+
const shouldUseNoiseSettings = useAppSelector(
(state: RootState) => state.generation.shouldUseNoiseSettings
);
@@ -19,6 +23,10 @@ const ParamNoiseCollapse = () => {
const handleToggle = () =>
dispatch(setShouldUseNoiseSettings(!shouldUseNoiseSettings));
+ if (!isNoiseEnabled) {
+ return null;
+ }
+
return (
{
const { t } = useTranslation();
const { shouldUseSeamless } = useAppSelector(selector);
+ const isSeamlessEnabled = useFeatureStatus('seamless').isFeatureEnabled;
+
const dispatch = useAppDispatch();
const handleToggle = () => dispatch(setSeamless(!shouldUseSeamless));
+ if (!isSeamlessEnabled) {
+ return null;
+ }
+
return (
{
const { t } = useTranslation();
@@ -15,10 +16,16 @@ const ParamSymmetryCollapse = () => {
(state: RootState) => state.generation.shouldUseSymmetry
);
+ const isSymmetryEnabled = useFeatureStatus('symmetry').isFeatureEnabled;
+
const dispatch = useAppDispatch();
const handleToggle = () => dispatch(setShouldUseSymmetry(!shouldUseSymmetry));
+ if (!isSymmetryEnabled) {
+ return null;
+ }
+
return (
{
const { t } = useTranslation();
@@ -14,11 +15,17 @@ const ParamVariationCollapse = () => {
(state: RootState) => state.generation.shouldGenerateVariations
);
+ const isVariationEnabled = useFeatureStatus('variation').isFeatureEnabled;
+
const dispatch = useAppDispatch();
const handleToggle = () =>
dispatch(setShouldGenerateVariations(!shouldGenerateVariations));
+ if (!isVariationEnabled) {
+ return null;
+ }
+
return (
{
+ const disabledTabs = useAppSelector(
+ (state: RootState) => state.config.disabledTabs
+ );
-export const useFeatureStatus = (feature: AppFeature) => {
const disabledFeatures = useAppSelector(
(state: RootState) => state.config.disabledFeatures
);
+ const disabledSDFeatures = useAppSelector(
+ (state: RootState) => state.config.disabledSDFeatures
+ );
+
const isFeatureDisabled = useMemo(
- () => disabledFeatures.includes(feature),
- [disabledFeatures, feature]
+ () =>
+ disabledFeatures.includes(feature as AppFeature) ||
+ disabledSDFeatures.includes(feature as SDFeature) ||
+ disabledTabs.includes(feature as InvokeTabName),
+ [disabledFeatures, disabledSDFeatures, disabledTabs, feature]
);
const isFeatureEnabled = useMemo(
- () => !disabledFeatures.includes(feature),
- [disabledFeatures, feature]
+ () =>
+ !(
+ disabledFeatures.includes(feature as AppFeature) ||
+ disabledSDFeatures.includes(feature as SDFeature) ||
+ disabledTabs.includes(feature as InvokeTabName)
+ ),
+ [disabledFeatures, disabledSDFeatures, disabledTabs, feature]
);
return { isFeatureDisabled, isFeatureEnabled };
diff --git a/invokeai/frontend/web/src/features/system/store/configSlice.ts b/invokeai/frontend/web/src/features/system/store/configSlice.ts
index b773692908..7b3a1b1eea 100644
--- a/invokeai/frontend/web/src/features/system/store/configSlice.ts
+++ b/invokeai/frontend/web/src/features/system/store/configSlice.ts
@@ -8,6 +8,7 @@ export const initialConfigState: AppConfig = {
shouldFetchImages: false,
disabledTabs: [],
disabledFeatures: [],
+ disabledSDFeatures: [],
canRestoreDeletedImagesFromBin: true,
sd: {
iterations: {