From b508945b110ac731ab3f8875c57cef85b16ece65 Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Mon, 15 Apr 2024 19:26:29 +1000
Subject: [PATCH 1/5] feat(ui): edge labels
Add setting to render labels with format `Source Node label -> Target Node label` on edges.
---
invokeai/frontend/web/public/locales/en.json | 2 +
.../flow/edges/InvocationDefaultEdge.tsx | 36 +++++++++++--
.../flow/edges/util/makeEdgeSelector.ts | 50 +++++++++++--------
.../TopRightPanel/WorkflowEditorSettings.tsx | 36 +++++++++++--
.../src/features/nodes/store/nodesSlice.ts | 5 ++
.../web/src/features/nodes/store/types.ts | 1 +
6 files changed, 103 insertions(+), 27 deletions(-)
diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json
index 2f4e70005f..1adac4c5dc 100644
--- a/invokeai/frontend/web/public/locales/en.json
+++ b/invokeai/frontend/web/public/locales/en.json
@@ -770,6 +770,8 @@
"float": "Float",
"fullyContainNodes": "Fully Contain Nodes to Select",
"fullyContainNodesHelp": "Nodes must be fully inside the selection box to be selected",
+ "showEdgeLabels": "Show Edge Labels",
+ "showEdgeLabelsHelp": "Show labels on edges, indicating the connected nodes",
"hideLegendNodes": "Hide Field Type Legend",
"hideMinimapnodes": "Hide MiniMap",
"inputMayOnlyHaveOneConnection": "Input may only have one connection",
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationDefaultEdge.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationDefaultEdge.tsx
index 0a18c2a959..77be60a945 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationDefaultEdge.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/edges/InvocationDefaultEdge.tsx
@@ -1,8 +1,9 @@
+import { Flex, Text } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import type { CSSProperties } from 'react';
import { memo, useMemo } from 'react';
import type { EdgeProps } from 'reactflow';
-import { BaseEdge, getBezierPath } from 'reactflow';
+import { BaseEdge, EdgeLabelRenderer, getBezierPath } from 'reactflow';
import { makeEdgeSelector } from './util/makeEdgeSelector';
@@ -25,9 +26,10 @@ const InvocationDefaultEdge = ({
[source, sourceHandleId, target, targetHandleId, selected]
);
- const { isSelected, shouldAnimate, stroke } = useAppSelector(selector);
+ const { isSelected, shouldAnimate, stroke, label } = useAppSelector(selector);
+ const shouldShowEdgeLabels = useAppSelector((s) => s.nodes.shouldShowEdgeLabels);
- const [edgePath] = getBezierPath({
+ const [edgePath, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
@@ -47,7 +49,33 @@ const InvocationDefaultEdge = ({
[isSelected, shouldAnimate, stroke]
);
- return ;
+ return (
+ <>
+
+ {label && shouldShowEdgeLabels && (
+
+
+
+ {label}
+
+
+
+ )}
+ >
+ );
};
export default memo(InvocationDefaultEdge);
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts b/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts
index ba40b4984c..a485bf64c1 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/edges/util/makeEdgeSelector.ts
@@ -1,7 +1,7 @@
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
-import { selectFieldOutputTemplate } from 'features/nodes/store/selectors';
+import { selectFieldOutputTemplate, selectNodeTemplate } from 'features/nodes/store/selectors';
import { isInvocationNode } from 'features/nodes/types/invocation';
import { getFieldColor } from './getEdgeColor';
@@ -10,6 +10,7 @@ const defaultReturnValue = {
isSelected: false,
shouldAnimate: false,
stroke: colorTokenToCssVar('base.500'),
+ label: '',
};
export const makeEdgeSelector = (
@@ -19,25 +20,34 @@ export const makeEdgeSelector = (
targetHandleId: string | null | undefined,
selected?: boolean
) =>
- createMemoizedSelector(selectNodesSlice, (nodes): { isSelected: boolean; shouldAnimate: boolean; stroke: string } => {
- const sourceNode = nodes.nodes.find((node) => node.id === source);
- const targetNode = nodes.nodes.find((node) => node.id === target);
+ createMemoizedSelector(
+ selectNodesSlice,
+ (nodes): { isSelected: boolean; shouldAnimate: boolean; stroke: string; label: string } => {
+ const sourceNode = nodes.nodes.find((node) => node.id === source);
+ const targetNode = nodes.nodes.find((node) => node.id === target);
- const isInvocationToInvocationEdge = isInvocationNode(sourceNode) && isInvocationNode(targetNode);
+ const isInvocationToInvocationEdge = isInvocationNode(sourceNode) && isInvocationNode(targetNode);
- const isSelected = Boolean(sourceNode?.selected || targetNode?.selected || selected);
- if (!sourceNode || !sourceHandleId) {
- return defaultReturnValue;
+ const isSelected = Boolean(sourceNode?.selected || targetNode?.selected || selected);
+ if (!sourceNode || !sourceHandleId || !targetNode || !targetHandleId) {
+ return defaultReturnValue;
+ }
+
+ const outputFieldTemplate = selectFieldOutputTemplate(nodes, sourceNode.id, sourceHandleId);
+ const sourceType = isInvocationToInvocationEdge ? outputFieldTemplate?.type : undefined;
+
+ const stroke = sourceType && nodes.shouldColorEdges ? getFieldColor(sourceType) : colorTokenToCssVar('base.500');
+
+ const sourceNodeTemplate = selectNodeTemplate(nodes, sourceNode.id);
+ const targetNodeTemplate = selectNodeTemplate(nodes, targetNode.id);
+
+ const label = `${sourceNodeTemplate?.title || sourceNode.data?.label} -> ${targetNodeTemplate?.title || targetNode.data?.label}`;
+
+ return {
+ isSelected,
+ shouldAnimate: nodes.shouldAnimateEdges && isSelected,
+ stroke,
+ label,
+ };
}
-
- const outputFieldTemplate = selectFieldOutputTemplate(nodes, sourceNode.id, sourceHandleId);
- const sourceType = isInvocationToInvocationEdge ? outputFieldTemplate?.type : undefined;
-
- const stroke = sourceType && nodes.shouldColorEdges ? getFieldColor(sourceType) : colorTokenToCssVar('base.500');
-
- return {
- isSelected,
- shouldAnimate: nodes.shouldAnimateEdges && isSelected,
- stroke,
- };
- });
+ );
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx
index cfb6c99043..b366737e59 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings.tsx
@@ -24,6 +24,7 @@ import {
selectNodesSlice,
shouldAnimateEdgesChanged,
shouldColorEdgesChanged,
+ shouldShowEdgeLabelsChanged,
shouldSnapToGridChanged,
shouldValidateGraphChanged,
} from 'features/nodes/store/nodesSlice';
@@ -35,12 +36,20 @@ import { SelectionMode } from 'reactflow';
const formLabelProps: FormLabelProps = { flexGrow: 1 };
const selector = createMemoizedSelector(selectNodesSlice, (nodes) => {
- const { shouldAnimateEdges, shouldValidateGraph, shouldSnapToGrid, shouldColorEdges, selectionMode } = nodes;
+ const {
+ shouldAnimateEdges,
+ shouldValidateGraph,
+ shouldSnapToGrid,
+ shouldColorEdges,
+ shouldShowEdgeLabels,
+ selectionMode,
+ } = nodes;
return {
shouldAnimateEdges,
shouldValidateGraph,
shouldSnapToGrid,
shouldColorEdges,
+ shouldShowEdgeLabels,
selectionModeIsChecked: selectionMode === SelectionMode.Full,
};
});
@@ -52,8 +61,14 @@ type Props = {
const WorkflowEditorSettings = ({ children }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const dispatch = useAppDispatch();
- const { shouldAnimateEdges, shouldValidateGraph, shouldSnapToGrid, shouldColorEdges, selectionModeIsChecked } =
- useAppSelector(selector);
+ const {
+ shouldAnimateEdges,
+ shouldValidateGraph,
+ shouldSnapToGrid,
+ shouldColorEdges,
+ shouldShowEdgeLabels,
+ selectionModeIsChecked,
+ } = useAppSelector(selector);
const handleChangeShouldValidate = useCallback(
(e: ChangeEvent) => {
@@ -90,6 +105,13 @@ const WorkflowEditorSettings = ({ children }: Props) => {
[dispatch]
);
+ const handleChangeShouldShowEdgeLabels = useCallback(
+ (e: ChangeEvent) => {
+ dispatch(shouldShowEdgeLabelsChanged(e.target.checked));
+ },
+ [dispatch]
+ );
+
const { t } = useTranslation();
return (
@@ -137,6 +159,14 @@ const WorkflowEditorSettings = ({ children }: Props) => {
{t('nodes.fullyContainNodesHelp')}
+
+
+ {t('nodes.showEdgeLabels')}
+
+
+ {t('nodes.showEdgeLabelsHelp')}
+
+
{t('common.advanced')}
diff --git a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
index 4a1b438271..0f0417cf71 100644
--- a/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
+++ b/invokeai/frontend/web/src/features/nodes/store/nodesSlice.ts
@@ -103,6 +103,7 @@ const initialNodesState: NodesState = {
shouldAnimateEdges: true,
shouldSnapToGrid: false,
shouldColorEdges: true,
+ shouldShowEdgeLabels: false,
isAddNodePopoverOpen: false,
nodeOpacity: 1,
selectedNodes: [],
@@ -549,6 +550,9 @@ export const nodesSlice = createSlice({
shouldAnimateEdgesChanged: (state, action: PayloadAction) => {
state.shouldAnimateEdges = action.payload;
},
+ shouldShowEdgeLabelsChanged: (state, action: PayloadAction) => {
+ state.shouldShowEdgeLabels = action.payload;
+ },
shouldSnapToGridChanged: (state, action: PayloadAction) => {
state.shouldSnapToGrid = action.payload;
},
@@ -831,6 +835,7 @@ export const {
viewportChanged,
edgeAdded,
nodeTemplatesBuilt,
+ shouldShowEdgeLabelsChanged,
} = nodesSlice.actions;
// This is used for tracking `state.workflow.isTouched`
diff --git a/invokeai/frontend/web/src/features/nodes/store/types.ts b/invokeai/frontend/web/src/features/nodes/store/types.ts
index 3f7d210dcb..2074f1f342 100644
--- a/invokeai/frontend/web/src/features/nodes/store/types.ts
+++ b/invokeai/frontend/web/src/features/nodes/store/types.ts
@@ -32,6 +32,7 @@ export type NodesState = {
isAddNodePopoverOpen: boolean;
addNewNodePosition: XYPosition | null;
selectionMode: SelectionMode;
+ shouldShowEdgeLabels: boolean;
};
export type WorkflowMode = 'edit' | 'view';
From 7a92afc1177719d64a6a4b7d4940b93d1275c217 Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Mon, 15 Apr 2024 22:22:25 +1000
Subject: [PATCH 2/5] perf(ui): fix rerenders in nodes
Unmemoized selector tanking perf
---
.../web/src/features/nodes/hooks/useOutputFieldNames.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts
index e16b329c22..54c092370b 100644
--- a/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts
+++ b/invokeai/frontend/web/src/features/nodes/hooks/useOutputFieldNames.ts
@@ -1,5 +1,5 @@
-import { createSelector } from '@reduxjs/toolkit';
import { EMPTY_ARRAY } from 'app/store/constants';
+import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { useAppSelector } from 'app/store/storeHooks';
import { selectNodesSlice } from 'features/nodes/store/nodesSlice';
import { selectNodeTemplate } from 'features/nodes/store/selectors';
@@ -10,7 +10,7 @@ import { useMemo } from 'react';
export const useOutputFieldNames = (nodeId: string) => {
const selector = useMemo(
() =>
- createSelector(selectNodesSlice, (nodes) => {
+ createMemoizedSelector(selectNodesSlice, (nodes) => {
const template = selectNodeTemplate(nodes, nodeId);
if (!template) {
return EMPTY_ARRAY;
From a24c9d0f7ab1384c70c0950cce7a224c360f4953 Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Mon, 15 Apr 2024 22:25:08 +1000
Subject: [PATCH 3/5] perf(ui): optimize useFeatureStatus
---
.../web/src/common/hooks/useGlobalHotkeys.ts | 2 +-
.../components/Boards/BoardContextMenu.tsx | 2 +-
.../CurrentImage/CurrentImageButtons.tsx | 2 +-
.../MultipleSelectionMenuItems.tsx | 2 +-
.../SingleSelectionMenuItems.tsx | 2 +-
.../features/gallery/hooks/useMultiselect.ts | 2 +-
.../features/hrf/components/HrfSettings.tsx | 2 +-
.../hooks/useStarterModelsToast.tsx | 2 +-
.../nodes/Invocation/InvocationNodeFooter.tsx | 2 +-
.../src/features/nodes/hooks/useWithFooter.ts | 3 +-
.../components/QueueActionsMenuButton.tsx | 4 +--
.../queue/components/QueueControls.tsx | 2 +-
.../queue/components/QueueTabContent.tsx | 2 +-
.../components/QueueTabQueueControls.tsx | 4 +--
.../src/features/queue/hooks/useQueueFront.ts | 2 +-
.../ControlSettingsAccordion.tsx | 4 +--
.../SettingsModal/SettingsLanguageSelect.tsx | 2 +-
.../components/SettingsModal/SettingsMenu.tsx | 6 ++--
.../features/system/hooks/useFeatureStatus.ts | 34 +++++++------------
19 files changed, 36 insertions(+), 45 deletions(-)
diff --git a/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts b/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts
index 372452ce99..bbb7897575 100644
--- a/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts
+++ b/invokeai/frontend/web/src/common/hooks/useGlobalHotkeys.ts
@@ -9,7 +9,7 @@ import { useHotkeys } from 'react-hotkeys-hook';
export const useGlobalHotkeys = () => {
const dispatch = useAppDispatch();
- const isModelManagerEnabled = useFeatureStatus('modelManager').isFeatureEnabled;
+ const isModelManagerEnabled = useFeatureStatus('modelManager');
const { queueBack, isDisabled: isDisabledQueueBack, isLoading: isLoadingQueueBack } = useQueueBack();
useHotkeys(
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx
index ad6c37532e..a67fd5f82d 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardContextMenu.tsx
@@ -32,7 +32,7 @@ const BoardContextMenu = ({ board, board_id, setBoardToDelete, children }: Props
const isSelectedForAutoAdd = useAppSelector(selectIsSelectedForAutoAdd);
const boardName = useBoardName(board_id);
- const isBulkDownloadEnabled = useFeatureStatus('bulkDownload').isFeatureEnabled;
+ const isBulkDownloadEnabled = useFeatureStatus('bulkDownload');
const [bulkDownload] = useBulkDownloadImagesMutation();
diff --git a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx
index 15ab74f44d..880fdbca6c 100644
--- a/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/CurrentImage/CurrentImageButtons.tsx
@@ -54,7 +54,7 @@ const CurrentImageButtons = () => {
const selection = useAppSelector((s) => s.gallery.selection);
const shouldDisableToolbarButtons = useAppSelector(selectShouldDisableToolbarButtons);
- const isUpscalingEnabled = useFeatureStatus('upscaling').isFeatureEnabled;
+ const isUpscalingEnabled = useFeatureStatus('upscaling');
const isQueueMutationInProgress = useIsQueueMutationInProgress();
const toaster = useAppToaster();
const { t } = useTranslation();
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx
index 7b1fa73472..54fb19c844 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/MultipleSelectionMenuItems.tsx
@@ -20,7 +20,7 @@ const MultipleSelectionMenuItems = () => {
const selection = useAppSelector((s) => s.gallery.selection);
const customStarUi = useStore($customStarUI);
- const isBulkDownloadEnabled = useFeatureStatus('bulkDownload').isFeatureEnabled;
+ const isBulkDownloadEnabled = useFeatureStatus('bulkDownload');
const [starImages] = useStarImagesMutation();
const [unstarImages] = useUnstarImagesMutation();
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx
index 7f43ab3671..aff74481ca 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageContextMenu/SingleSelectionMenuItems.tsx
@@ -45,7 +45,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const toaster = useAppToaster();
- const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled;
+ const isCanvasEnabled = useFeatureStatus('unifiedCanvas');
const customStarUi = useStore($customStarUI);
const { downloadImage } = useDownloadImage();
diff --git a/invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts b/invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts
index 05e7d075e5..f84a349d2a 100644
--- a/invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts
+++ b/invokeai/frontend/web/src/features/gallery/hooks/useMultiselect.ts
@@ -18,7 +18,7 @@ export const useMultiselect = (imageDTO?: ImageDTO) => {
[imageDTO?.image_name]
);
const isSelected = useAppSelector(selectIsSelected);
- const isMultiSelectEnabled = useFeatureStatus('multiselect').isFeatureEnabled;
+ const isMultiSelectEnabled = useFeatureStatus('multiselect');
const handleClick = useCallback(
(e: MouseEvent) => {
diff --git a/invokeai/frontend/web/src/features/hrf/components/HrfSettings.tsx b/invokeai/frontend/web/src/features/hrf/components/HrfSettings.tsx
index 2cb96a935f..eaa6d60dda 100644
--- a/invokeai/frontend/web/src/features/hrf/components/HrfSettings.tsx
+++ b/invokeai/frontend/web/src/features/hrf/components/HrfSettings.tsx
@@ -8,7 +8,7 @@ import ParamHrfStrength from './ParamHrfStrength';
import ParamHrfToggle from './ParamHrfToggle';
export const HrfSettings = memo(() => {
- const isHRFFeatureEnabled = useFeatureStatus('hrf').isFeatureEnabled;
+ const isHRFFeatureEnabled = useFeatureStatus('hrf');
const hrfEnabled = useAppSelector((s) => s.hrf.hrfEnabled);
if (!isHRFFeatureEnabled) {
diff --git a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx
index 0ee06f19dd..6abc633ac8 100644
--- a/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx
+++ b/invokeai/frontend/web/src/features/modelManagerV2/hooks/useStarterModelsToast.tsx
@@ -10,7 +10,7 @@ const TOAST_ID = 'starterModels';
export const useStarterModelsToast = () => {
const { t } = useTranslation();
- const isEnabled = useFeatureStatus('starterModels').isFeatureEnabled;
+ const isEnabled = useFeatureStatus('starterModels');
const [didToast, setDidToast] = useState(false);
const [mainModels, { data }] = useMainModels();
const toast = useToast();
diff --git a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx
index 1b93c0fdd3..c1ff625d25 100644
--- a/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx
+++ b/invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/InvocationNodeFooter.tsx
@@ -16,7 +16,7 @@ const props: ChakraProps = { w: 'unset' };
const InvocationNodeFooter = ({ nodeId }: Props) => {
const hasImageOutput = useHasImageOutput(nodeId);
- const isCacheEnabled = useFeatureStatus('invocationCache').isFeatureEnabled;
+ const isCacheEnabled = useFeatureStatus('invocationCache');
return (
{
const hasImageOutput = useHasImageOutput(nodeId);
- const isCacheEnabled = useFeatureStatus('invocationCache').isFeatureEnabled;
-
+ const isCacheEnabled = useFeatureStatus('invocationCache');
const withFooter = useMemo(() => hasImageOutput || isCacheEnabled, [hasImageOutput, isCacheEnabled]);
return withFooter;
};
diff --git a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx
index 37b6318a53..101c82376c 100644
--- a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx
@@ -27,8 +27,8 @@ export const QueueActionsMenuButton = memo(() => {
const dispatch = useAppDispatch();
const { t } = useTranslation();
const clearQueueDisclosure = useDisclosure();
- const isPauseEnabled = useFeatureStatus('pauseQueue').isFeatureEnabled;
- const isResumeEnabled = useFeatureStatus('resumeQueue').isFeatureEnabled;
+ const isPauseEnabled = useFeatureStatus('pauseQueue');
+ const isResumeEnabled = useFeatureStatus('resumeQueue');
const { queueSize } = useGetQueueStatusQuery(undefined, {
selectFromResult: (res) => ({
queueSize: res.data ? res.data.queue.pending + res.data.queue.in_progress : 0,
diff --git a/invokeai/frontend/web/src/features/queue/components/QueueControls.tsx b/invokeai/frontend/web/src/features/queue/components/QueueControls.tsx
index 5499ecccfc..28a12808ea 100644
--- a/invokeai/frontend/web/src/features/queue/components/QueueControls.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/QueueControls.tsx
@@ -9,7 +9,7 @@ import { InvokeQueueBackButton } from './InvokeQueueBackButton';
import { QueueActionsMenuButton } from './QueueActionsMenuButton';
const QueueControls = () => {
- const isPrependEnabled = useFeatureStatus('prependQueue').isFeatureEnabled;
+ const isPrependEnabled = useFeatureStatus('prependQueue');
return (
diff --git a/invokeai/frontend/web/src/features/queue/components/QueueTabContent.tsx b/invokeai/frontend/web/src/features/queue/components/QueueTabContent.tsx
index d7c27d54fc..2dae5e6ebe 100644
--- a/invokeai/frontend/web/src/features/queue/components/QueueTabContent.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/QueueTabContent.tsx
@@ -8,7 +8,7 @@ import QueueStatus from './QueueStatus';
import QueueTabQueueControls from './QueueTabQueueControls';
const QueueTabContent = () => {
- const isInvocationCacheEnabled = useFeatureStatus('invocationCache').isFeatureEnabled;
+ const isInvocationCacheEnabled = useFeatureStatus('invocationCache');
return (
diff --git a/invokeai/frontend/web/src/features/queue/components/QueueTabQueueControls.tsx b/invokeai/frontend/web/src/features/queue/components/QueueTabQueueControls.tsx
index b42fc04e4d..3aed2f237a 100644
--- a/invokeai/frontend/web/src/features/queue/components/QueueTabQueueControls.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/QueueTabQueueControls.tsx
@@ -8,8 +8,8 @@ import PruneQueueButton from './PruneQueueButton';
import ResumeProcessorButton from './ResumeProcessorButton';
const QueueTabQueueControls = () => {
- const isPauseEnabled = useFeatureStatus('pauseQueue').isFeatureEnabled;
- const isResumeEnabled = useFeatureStatus('resumeQueue').isFeatureEnabled;
+ const isPauseEnabled = useFeatureStatus('pauseQueue');
+ const isResumeEnabled = useFeatureStatus('resumeQueue');
return (
{isPauseEnabled || isResumeEnabled ? (
diff --git a/invokeai/frontend/web/src/features/queue/hooks/useQueueFront.ts b/invokeai/frontend/web/src/features/queue/hooks/useQueueFront.ts
index d39ac96566..f6c71dbc5a 100644
--- a/invokeai/frontend/web/src/features/queue/hooks/useQueueFront.ts
+++ b/invokeai/frontend/web/src/features/queue/hooks/useQueueFront.ts
@@ -13,7 +13,7 @@ export const useQueueFront = () => {
const [_, { isLoading }] = useEnqueueBatchMutation({
fixedCacheKey: 'enqueueBatch',
});
- const prependEnabled = useFeatureStatus('prependQueue').isFeatureEnabled;
+ const prependEnabled = useFeatureStatus('prependQueue');
const isDisabled = useMemo(() => {
return !isReady || !prependEnabled;
diff --git a/invokeai/frontend/web/src/features/settingsAccordions/components/ControlSettingsAccordion/ControlSettingsAccordion.tsx b/invokeai/frontend/web/src/features/settingsAccordions/components/ControlSettingsAccordion/ControlSettingsAccordion.tsx
index 3cddc927e9..ec81b0b211 100644
--- a/invokeai/frontend/web/src/features/settingsAccordions/components/ControlSettingsAccordion/ControlSettingsAccordion.tsx
+++ b/invokeai/frontend/web/src/features/settingsAccordions/components/ControlSettingsAccordion/ControlSettingsAccordion.tsx
@@ -62,7 +62,7 @@ const selector = createMemoizedSelector(selectControlAdaptersSlice, (controlAdap
export const ControlSettingsAccordion: React.FC = memo(() => {
const { t } = useTranslation();
const { controlAdapterIds, badges } = useAppSelector(selector);
- const isControlNetDisabled = useFeatureStatus('controlNet').isFeatureDisabled;
+ const isControlNetEnabled = useFeatureStatus('controlNet');
const { isOpen, onToggle } = useStandaloneAccordionToggle({
id: 'control-settings',
defaultIsOpen: true,
@@ -71,7 +71,7 @@ export const ControlSettingsAccordion: React.FC = memo(() => {
const [addIPAdapter, isAddIPAdapterDisabled] = useAddControlAdapter('ip_adapter');
const [addT2IAdapter, isAddT2IAdapterDisabled] = useAddControlAdapter('t2i_adapter');
- if (isControlNetDisabled) {
+ if (!isControlNetEnabled) {
return null;
}
diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx
index eceba85b5a..bee5940530 100644
--- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx
+++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsLanguageSelect.tsx
@@ -40,7 +40,7 @@ export const SettingsLanguageSelect = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const language = useAppSelector((s) => s.system.language);
- const isLocalizationEnabled = useFeatureStatus('localization').isFeatureEnabled;
+ const isLocalizationEnabled = useFeatureStatus('localization');
const value = useMemo(() => options.find((o) => o.value === language), [language]);
diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx
index 6cf37334e7..b424a129ee 100644
--- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx
+++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsMenu.tsx
@@ -23,9 +23,9 @@ const SettingsMenu = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
useGlobalMenuClose(onClose);
- const isBugLinkEnabled = useFeatureStatus('bugLink').isFeatureEnabled;
- const isDiscordLinkEnabled = useFeatureStatus('discordLink').isFeatureEnabled;
- const isGithubLinkEnabled = useFeatureStatus('githubLink').isFeatureEnabled;
+ const isBugLinkEnabled = useFeatureStatus('bugLink');
+ const isDiscordLinkEnabled = useFeatureStatus('discordLink');
+ const isGithubLinkEnabled = useFeatureStatus('githubLink');
return (