feat(ui): rerender mitigation sweep

This commit is contained in:
psychedelicious 2023-04-27 17:30:21 +10:00
parent 5d8728c7ef
commit ca1cc0e2c2
16 changed files with 98 additions and 138 deletions

View File

@ -28,11 +28,13 @@ import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
import { configChanged } from 'features/system/store/configSlice'; import { configChanged } from 'features/system/store/configSlice';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
const DEFAULT_CONFIG = {};
interface Props extends PropsWithChildren { interface Props extends PropsWithChildren {
config?: PartialAppConfig; config?: PartialAppConfig;
} }
const App = ({ config = {}, children }: Props) => { const App = ({ config = DEFAULT_CONFIG, children }: Props) => {
useToastWatcher(); useToastWatcher();
useGlobalHotkeys(); useGlobalHotkeys();

View File

@ -1,5 +1,6 @@
import { Flex, Image, Spinner } from '@chakra-ui/react'; import { Flex, Image, Spinner } from '@chakra-ui/react';
import InvokeAILogoImage from 'assets/images/logo.png'; import InvokeAILogoImage from 'assets/images/logo.png';
import { memo } from 'react';
// This component loads before the theme so we cannot use theme tokens here // This component loads before the theme so we cannot use theme tokens here
@ -29,4 +30,4 @@ const Loading = () => {
); );
}; };
export default Loading; export default memo(Loading);

View File

@ -1,5 +1,6 @@
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { useCallback } from 'react';
import { OpenAPI } from 'services/api'; import { OpenAPI } from 'services/api';
export const getUrlAlt = (url: string, shouldTransformUrls: boolean) => { export const getUrlAlt = (url: string, shouldTransformUrls: boolean) => {
@ -15,14 +16,19 @@ export const useGetUrl = () => {
(state: RootState) => state.config.shouldTransformUrls (state: RootState) => state.config.shouldTransformUrls
); );
return { const getUrl = useCallback(
shouldTransformUrls, (url?: string) => {
getUrl: (url?: string) => {
if (OpenAPI.BASE && shouldTransformUrls) { if (OpenAPI.BASE && shouldTransformUrls) {
return [OpenAPI.BASE, url].join('/'); return [OpenAPI.BASE, url].join('/');
} }
return url; return url;
}, },
[shouldTransformUrls]
);
return {
shouldTransformUrls,
getUrl,
}; };
}; };

View File

@ -163,16 +163,16 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const setBothPrompts = useSetBothPrompts(); const setBothPrompts = useSetBothPrompts();
const handleClickUseAsInitialImage = () => { const handleClickUseAsInitialImage = useCallback(() => {
if (!image) return; if (!image) return;
if (isLightboxOpen) dispatch(setIsLightboxOpen(false)); if (isLightboxOpen) dispatch(setIsLightboxOpen(false));
dispatch(initialImageSelected(image.name)); dispatch(initialImageSelected(image.name));
// dispatch(setInitialImage(currentImage)); // dispatch(setInitialImage(currentImage));
// dispatch(setActiveTab('img2img')); // dispatch(setActiveTab('img2img'));
}; }, [dispatch, image, isLightboxOpen]);
const handleCopyImage = async () => { const handleCopyImage = useCallback(async () => {
if (!image?.url) { if (!image?.url) {
return; return;
} }
@ -194,9 +194,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
duration: 2500, duration: 2500,
isClosable: true, isClosable: true,
}); });
}; }, [getUrl, t, image?.url, toast]);
const handleCopyImageLink = () => { const handleCopyImageLink = useCallback(() => {
const url = image const url = image
? shouldTransformUrls ? shouldTransformUrls
? getUrl(image.url) ? getUrl(image.url)
@ -215,7 +215,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
isClosable: true, isClosable: true,
}); });
}); });
}; }, [toast, shouldTransformUrls, getUrl, t, image]);
useHotkeys( useHotkeys(
'shift+i', 'shift+i',
@ -241,11 +241,11 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
[image] [image]
); );
const handlePreviewVisibility = () => { const handlePreviewVisibility = useCallback(() => {
dispatch(setShouldHidePreview(!shouldHidePreview)); dispatch(setShouldHidePreview(!shouldHidePreview));
}; }, [dispatch, shouldHidePreview]);
const handleClickUseAllParameters = () => { const handleClickUseAllParameters = useCallback(() => {
if (!image) return; if (!image) return;
// selectedImage.metadata && // selectedImage.metadata &&
// dispatch(setAllParameters(selectedImage.metadata)); // dispatch(setAllParameters(selectedImage.metadata));
@ -254,7 +254,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
// } else if (selectedImage.metadata?.image.type === 'txt2img') { // } else if (selectedImage.metadata?.image.type === 'txt2img') {
// dispatch(setActiveTab('txt2img')); // dispatch(setActiveTab('txt2img'));
// } // }
}; }, [image]);
useHotkeys( useHotkeys(
'a', 'a',
@ -338,9 +338,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
[image] [image]
); );
const handleClickUpscale = () => { const handleClickUpscale = useCallback(() => {
// selectedImage && dispatch(runESRGAN(selectedImage)); // selectedImage && dispatch(runESRGAN(selectedImage));
}; }, []);
useHotkeys( useHotkeys(
'Shift+U', 'Shift+U',
@ -369,9 +369,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
] ]
); );
const handleClickFixFaces = () => { const handleClickFixFaces = useCallback(() => {
// selectedImage && dispatch(runFacetool(selectedImage)); // selectedImage && dispatch(runFacetool(selectedImage));
}; }, []);
useHotkeys( useHotkeys(
'Shift+R', 'Shift+R',
@ -401,10 +401,12 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
] ]
); );
const handleClickShowImageDetails = () => const handleClickShowImageDetails = useCallback(
dispatch(setShouldShowImageDetails(!shouldShowImageDetails)); () => dispatch(setShouldShowImageDetails(!shouldShowImageDetails)),
[dispatch, shouldShowImageDetails]
);
const handleSendToCanvas = () => { const handleSendToCanvas = useCallback(() => {
if (!image) return; if (!image) return;
if (isLightboxOpen) dispatch(setIsLightboxOpen(false)); if (isLightboxOpen) dispatch(setIsLightboxOpen(false));
@ -421,7 +423,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
duration: 2500, duration: 2500,
isClosable: true, isClosable: true,
}); });
}; }, [image, isLightboxOpen, dispatch, activeTabName, toast, t]);
useHotkeys( useHotkeys(
'i', 'i',
@ -440,19 +442,19 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
[image, shouldShowImageDetails] [image, shouldShowImageDetails]
); );
const handleInitiateDelete = () => { const handleDelete = useCallback(() => {
if (canDeleteImage && image) {
dispatch(imageDeleted({ imageType: image.type, imageName: image.name }));
}
}, [image, canDeleteImage, dispatch]);
const handleInitiateDelete = useCallback(() => {
if (shouldConfirmOnDelete) { if (shouldConfirmOnDelete) {
onDeleteDialogOpen(); onDeleteDialogOpen();
} else { } else {
handleDelete(); handleDelete();
} }
}; }, [shouldConfirmOnDelete, onDeleteDialogOpen, handleDelete]);
const handleDelete = () => {
if (canDeleteImage && image) {
dispatch(imageDeleted({ imageType: image.type, imageName: image.name }));
}
};
useHotkeys('delete', handleInitiateDelete, [ useHotkeys('delete', handleInitiateDelete, [
image, image,
@ -461,9 +463,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
isProcessing, isProcessing,
]); ]);
const handleLightBox = () => { const handleLightBox = useCallback(() => {
dispatch(setIsLightboxOpen(!isLightboxOpen)); dispatch(setIsLightboxOpen(!isLightboxOpen));
}; }, [dispatch, isLightboxOpen]);
return ( return (
<> <>

View File

@ -11,6 +11,7 @@ import CurrentImageFallback from './CurrentImageFallback';
import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer'; import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer';
import NextPrevImageButtons from './NextPrevImageButtons'; import NextPrevImageButtons from './NextPrevImageButtons';
import CurrentImageHidden from './CurrentImageHidden'; import CurrentImageHidden from './CurrentImageHidden';
import { memo } from 'react';
export const imagesSelector = createSelector( export const imagesSelector = createSelector(
[uiSelector, selectedImageSelector, systemSelector], [uiSelector, selectedImageSelector, systemSelector],
@ -50,7 +51,7 @@ export const imagesSelector = createSelector(
} }
); );
export default function CurrentImagePreview() { const CurrentImagePreview = () => {
const { shouldShowImageDetails, imageToDisplay, shouldHidePreview } = const { shouldShowImageDetails, imageToDisplay, shouldHidePreview } =
useAppSelector(imagesSelector); useAppSelector(imagesSelector);
const { getUrl } = useGetUrl(); const { getUrl } = useGetUrl();
@ -115,4 +116,6 @@ export default function CurrentImagePreview() {
)} )}
</Flex> </Flex>
); );
} };
export default memo(CurrentImagePreview);

View File

@ -28,6 +28,7 @@ import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvas
import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors'; import { lightboxSelector } from 'features/lightbox/store/lightboxSelectors';
import useResolution from 'common/hooks/useResolution'; import useResolution from 'common/hooks/useResolution';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { memo } from 'react';
const GALLERY_TAB_WIDTHS: Record< const GALLERY_TAB_WIDTHS: Record<
InvokeTabName, InvokeTabName,
@ -72,7 +73,7 @@ const galleryPanelSelector = createSelector(
} }
); );
export default function ImageGalleryPanel() { export const ImageGalleryPanel = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { const {
shouldPinGallery, shouldPinGallery,
@ -232,4 +233,6 @@ export default function ImageGalleryPanel() {
}; };
return renderImageGallery(); return renderImageGallery();
} };
export default memo(ImageGalleryPanel);

View File

@ -6,14 +6,12 @@ import IAIIconButton, {
import { systemSelector } from 'features/system/store/systemSelectors'; import { systemSelector } from 'features/system/store/systemSelectors';
import { import {
SystemState, SystemState,
setCancelAfter,
setCancelType,
cancelScheduled, cancelScheduled,
cancelTypeChanged, cancelTypeChanged,
CancelType, CancelType,
} from 'features/system/store/systemSlice'; } from 'features/system/store/systemSlice';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { useEffect, useCallback, memo } from 'react'; import { useCallback, memo } from 'react';
import { import {
ButtonSpinner, ButtonSpinner,
ButtonGroup, ButtonGroup,
@ -27,16 +25,9 @@ import {
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import { MdCancel, MdCancelScheduleSend } from 'react-icons/md';
MdArrowDropDown,
MdArrowDropUp,
MdCancel,
MdCancelScheduleSend,
} from 'react-icons/md';
import IAISimpleMenu from 'common/components/IAISimpleMenu';
import { sessionCanceled } from 'services/thunks/session'; import { sessionCanceled } from 'services/thunks/session';
import { FaChevronDown } from 'react-icons/fa';
import { BiChevronDown } from 'react-icons/bi'; import { BiChevronDown } from 'react-icons/bi';
const cancelButtonSelector = createSelector( const cancelButtonSelector = createSelector(
@ -48,8 +39,6 @@ const cancelButtonSelector = createSelector(
isCancelable: system.isCancelable, isCancelable: system.isCancelable,
currentIteration: system.currentIteration, currentIteration: system.currentIteration,
totalIterations: system.totalIterations, totalIterations: system.totalIterations,
// cancelType: system.cancelOptions.cancelType,
// cancelAfter: system.cancelOptions.cancelAfter,
sessionId: system.sessionId, sessionId: system.sessionId,
cancelType: system.cancelType, cancelType: system.cancelType,
isCancelScheduled: system.isCancelScheduled, isCancelScheduled: system.isCancelScheduled,
@ -75,11 +64,8 @@ const CancelButton = (
isProcessing, isProcessing,
isConnected, isConnected,
isCancelable, isCancelable,
currentIteration,
totalIterations,
cancelType, cancelType,
isCancelScheduled, isCancelScheduled,
// cancelAfter,
sessionId, sessionId,
} = useAppSelector(cancelButtonSelector); } = useAppSelector(cancelButtonSelector);
@ -105,7 +91,6 @@ const CancelButton = (
}, },
[dispatch] [dispatch]
); );
// const isCancelScheduled = cancelAfter === null ? false : true;
useHotkeys( useHotkeys(
'shift+x', 'shift+x',
@ -117,23 +102,6 @@ const CancelButton = (
[isConnected, isProcessing, isCancelable] [isConnected, isProcessing, isCancelable]
); );
// useEffect(() => {
// if (cancelAfter !== null && cancelAfter < currentIteration) {
// handleClickCancel();
// }
// }, [cancelAfter, currentIteration, handleClickCancel]);
// const cancelMenuItems = [
// {
// item: t('parameters.cancel.immediate'),
// onClick: () => dispatch(cancelTypeChanged('immediate')),
// },
// {
// item: t('parameters.cancel.schedule'),
// onClick: () => dispatch(cancelTypeChanged('scheduled')),
// },
// ];
return ( return (
<ButtonGroup isAttached width={btnGroupWidth}> <ButtonGroup isAttached width={btnGroupWidth}>
{cancelType === 'immediate' ? ( {cancelType === 'immediate' ? (

View File

@ -4,23 +4,27 @@ import * as InvokeAI from 'app/types/invokeai';
import promptToString from 'common/util/promptToString'; import promptToString from 'common/util/promptToString';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { setNegativePrompt, setPrompt } from '../store/generationSlice'; import { setNegativePrompt, setPrompt } from '../store/generationSlice';
import { useCallback } from 'react';
// TECHDEBT: We have two metadata prompt formats and need to handle recalling either of them. // TECHDEBT: We have two metadata prompt formats and need to handle recalling either of them.
// This hook provides a function to do that. // This hook provides a function to do that.
const useSetBothPrompts = () => { const useSetBothPrompts = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
return (inputPrompt: InvokeAI.Prompt) => { return useCallback(
const promptString = (inputPrompt: InvokeAI.Prompt) => {
typeof inputPrompt === 'string' const promptString =
? inputPrompt typeof inputPrompt === 'string'
: promptToString(inputPrompt); ? inputPrompt
: promptToString(inputPrompt);
const [prompt, negativePrompt] = getPromptAndNegative(promptString); const [prompt, negativePrompt] = getPromptAndNegative(promptString);
dispatch(setPrompt(prompt)); dispatch(setPrompt(prompt));
dispatch(setNegativePrompt(negativePrompt)); dispatch(setNegativePrompt(negativePrompt));
}; },
[dispatch]
);
}; };
export default useSetBothPrompts; export default useSetBothPrompts;

View File

@ -9,7 +9,7 @@ import {
} from 'features/system/store/systemSlice'; } from 'features/system/store/systemSlice';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { Resizable } from 're-resizable'; import { Resizable } from 're-resizable';
import { useLayoutEffect, useRef, useState } from 'react'; import { memo, useLayoutEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FaAngleDoubleDown, FaCode, FaMinus } from 'react-icons/fa'; import { FaAngleDoubleDown, FaCode, FaMinus } from 'react-icons/fa';
@ -194,4 +194,4 @@ const Console = () => {
); );
}; };
export default Console; export default memo(Console);

View File

@ -3,6 +3,7 @@ import { createSelector } from '@reduxjs/toolkit';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { SystemState } from 'features/system/store/systemSlice'; import { SystemState } from 'features/system/store/systemSlice';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PROGRESS_BAR_THICKNESS } from 'theme/util/constants'; import { PROGRESS_BAR_THICKNESS } from 'theme/util/constants';
import { systemSelector } from '../store/systemSelectors'; import { systemSelector } from '../store/systemSelectors';
@ -40,4 +41,4 @@ const ProgressBar = () => {
); );
}; };
export default ProgressBar; export default memo(ProgressBar);

View File

@ -1,5 +1,5 @@
import { Flex, Grid } from '@chakra-ui/react'; import { Flex, Grid } from '@chakra-ui/react';
import { useState } from 'react'; import { memo, useState } from 'react';
import ModelSelect from './ModelSelect'; import ModelSelect from './ModelSelect';
import StatusIndicator from './StatusIndicator'; import StatusIndicator from './StatusIndicator';
@ -65,5 +65,4 @@ const SiteHeader = () => {
); );
}; };
SiteHeader.displayName = 'SiteHeader'; export default memo(SiteHeader);
export default SiteHeader;

View File

@ -17,7 +17,7 @@ const itemsToDenylist: (keyof SystemState)[] = [
'totalSteps', 'totalSteps',
'openModel', 'openModel',
'isCancelScheduled', 'isCancelScheduled',
'sessionId', // 'sessionId',
'progressImage', 'progressImage',
'wereModelsReceived', 'wereModelsReceived',
'wasSchemaParsed', 'wasSchemaParsed',

View File

@ -89,18 +89,6 @@ export interface SystemState
* Array of node IDs that we want to handle when events received * Array of node IDs that we want to handle when events received
*/ */
subscribedNodeIds: string[]; subscribedNodeIds: string[];
// /**
// * Whether or not URLs should be transformed to use a different host
// */
// shouldTransformUrls: boolean;
// /**
// * Array of disabled tabs
// */
// disabledTabs: InvokeTabName[];
// /**
// * Array of disabled features
// */
// disabledFeatures: InvokeAI.AppFeature[];
/** /**
* Whether or not the available models were received * Whether or not the available models were received
*/ */
@ -358,27 +346,6 @@ export const systemSlice = createSlice({
subscribedNodeIdsSet: (state, action: PayloadAction<string[]>) => { subscribedNodeIdsSet: (state, action: PayloadAction<string[]>) => {
state.subscribedNodeIds = action.payload; state.subscribedNodeIds = action.payload;
}, },
// /**
// * `shouldTransformUrls` was changed
// */
// shouldTransformUrlsChanged: (state, action: PayloadAction<boolean>) => {
// state.shouldTransformUrls = action.payload;
// },
// /**
// * `disabledTabs` was changed
// */
// disabledTabsChanged: (state, action: PayloadAction<InvokeTabName[]>) => {
// state.disabledTabs = action.payload;
// },
// /**
// * `disabledFeatures` was changed
// */
// disabledFeaturesChanged: (
// state,
// action: PayloadAction<InvokeAI.AppFeature[]>
// ) => {
// state.disabledFeatures = action.payload;
// },
}, },
extraReducers(builder) { extraReducers(builder) {
/** /**
@ -386,6 +353,7 @@ export const systemSlice = createSlice({
*/ */
builder.addCase(socketSubscribed, (state, action) => { builder.addCase(socketSubscribed, (state, action) => {
state.sessionId = action.payload.sessionId; state.sessionId = action.payload.sessionId;
console.log(`Subscribed to session ${action.payload.sessionId}`);
}); });
/** /**
@ -594,9 +562,6 @@ export const {
scheduledCancelAborted, scheduledCancelAborted,
cancelTypeChanged, cancelTypeChanged,
subscribedNodeIdsSet, subscribedNodeIdsSet,
// shouldTransformUrlsChanged,
// disabledTabsChanged,
// disabledFeaturesChanged,
} = systemSlice.actions; } = systemSlice.actions;
export default systemSlice.reducer; export default systemSlice.reducer;

View File

@ -7,6 +7,7 @@ import { setShouldShowGallery } from 'features/ui/store/uiSlice';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { MdPhotoLibrary } from 'react-icons/md'; import { MdPhotoLibrary } from 'react-icons/md';
import { activeTabNameSelector, uiSelector } from '../store/uiSelectors'; import { activeTabNameSelector, uiSelector } from '../store/uiSelectors';
import { memo } from 'react';
const floatingGalleryButtonSelector = createSelector( const floatingGalleryButtonSelector = createSelector(
[activeTabNameSelector, uiSelector], [activeTabNameSelector, uiSelector],
@ -58,4 +59,4 @@ const FloatingGalleryButton = () => {
) : null; ) : null;
}; };
export default FloatingGalleryButton; export default memo(FloatingGalleryButton);

View File

@ -11,6 +11,7 @@ import {
} from 'features/ui/store/uiSelectors'; } from 'features/ui/store/uiSelectors';
import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice'; import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { FaSlidersH } from 'react-icons/fa'; import { FaSlidersH } from 'react-icons/fa';
@ -94,4 +95,4 @@ const FloatingParametersPanelButtons = () => {
) : null; ) : null;
}; };
export default FloatingParametersPanelButtons; export default memo(FloatingParametersPanelButtons);

View File

@ -14,7 +14,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { setIsLightboxOpen } from 'features/lightbox/store/lightboxSlice'; import { setIsLightboxOpen } from 'features/lightbox/store/lightboxSlice';
import { InvokeTabName } from 'features/ui/store/tabMap'; import { InvokeTabName } from 'features/ui/store/tabMap';
import { setActiveTab, togglePanels } from 'features/ui/store/uiSlice'; import { setActiveTab, togglePanels } from 'features/ui/store/uiSlice';
import { ReactNode, useMemo } from 'react'; import { memo, ReactNode, useMemo } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { MdDeviceHub, MdGridOn } from 'react-icons/md'; import { MdDeviceHub, MdGridOn } from 'react-icons/md';
import { activeTabIndexSelector } from '../store/uiSelectors'; import { activeTabIndexSelector } from '../store/uiSelectors';
@ -24,10 +24,10 @@ import { ResourceKey } from 'i18next';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import NodeEditor from 'features/nodes/components/NodeEditor'; import NodeEditor from 'features/nodes/components/NodeEditor';
import GenerateWorkspace from './tabs/Generate/GenerateWorkspace'; import GenerateWorkspace from './tabs/Generate/GenerateWorkspace';
import { FaImage } from 'react-icons/fa';
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { BsLightningChargeFill, BsLightningFill } from 'react-icons/bs'; import { BsLightningChargeFill } from 'react-icons/bs';
import { configSelector } from 'features/system/store/configSelectors'; import { configSelector } from 'features/system/store/configSelectors';
import { isEqual } from 'lodash';
export interface InvokeTabInfo { export interface InvokeTabInfo {
id: InvokeTabName; id: InvokeTabName;
@ -35,10 +35,6 @@ export interface InvokeTabInfo {
workarea: ReactNode; workarea: ReactNode;
} }
const tabIconStyles: ChakraProps['sx'] = {
boxSize: 6,
};
const tabs: InvokeTabInfo[] = [ const tabs: InvokeTabInfo[] = [
{ {
id: 'generate', id: 'generate',
@ -57,13 +53,19 @@ const tabs: InvokeTabInfo[] = [
}, },
]; ];
const enabledTabsSelector = createSelector(configSelector, (config) => { const enabledTabsSelector = createSelector(
const { disabledTabs } = config; configSelector,
(config) => {
const { disabledTabs } = config;
return tabs.filter((tab) => !disabledTabs.includes(tab.id)); return tabs.filter((tab) => !disabledTabs.includes(tab.id));
}); },
{
memoizeOptions: { resultEqualityCheck: isEqual },
}
);
export default function InvokeTabs() { const InvokeTabs = () => {
const activeTab = useAppSelector(activeTabIndexSelector); const activeTab = useAppSelector(activeTabIndexSelector);
const enabledTabs = useAppSelector(enabledTabsSelector); const enabledTabs = useAppSelector(enabledTabsSelector);
const isLightBoxOpen = useAppSelector( const isLightBoxOpen = useAppSelector(
@ -160,4 +162,6 @@ export default function InvokeTabs() {
<TabPanels>{tabPanels}</TabPanels> <TabPanels>{tabPanels}</TabPanels>
</Tabs> </Tabs>
); );
} };
export default memo(InvokeTabs);