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 { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
const DEFAULT_CONFIG = {};
interface Props extends PropsWithChildren {
config?: PartialAppConfig;
}
const App = ({ config = {}, children }: Props) => {
const App = ({ config = DEFAULT_CONFIG, children }: Props) => {
useToastWatcher();
useGlobalHotkeys();

View File

@ -1,5 +1,6 @@
import { Flex, Image, Spinner } from '@chakra-ui/react';
import InvokeAILogoImage from 'assets/images/logo.png';
import { memo } from 'react';
// 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 { useAppSelector } from 'app/store/storeHooks';
import { useCallback } from 'react';
import { OpenAPI } from 'services/api';
export const getUrlAlt = (url: string, shouldTransformUrls: boolean) => {
@ -15,14 +16,19 @@ export const useGetUrl = () => {
(state: RootState) => state.config.shouldTransformUrls
);
return {
shouldTransformUrls,
getUrl: (url?: string) => {
const getUrl = useCallback(
(url?: string) => {
if (OpenAPI.BASE && shouldTransformUrls) {
return [OpenAPI.BASE, url].join('/');
}
return url;
},
[shouldTransformUrls]
);
return {
shouldTransformUrls,
getUrl,
};
};

View File

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

View File

@ -11,6 +11,7 @@ import CurrentImageFallback from './CurrentImageFallback';
import ImageMetadataViewer from './ImageMetaDataViewer/ImageMetadataViewer';
import NextPrevImageButtons from './NextPrevImageButtons';
import CurrentImageHidden from './CurrentImageHidden';
import { memo } from 'react';
export const imagesSelector = createSelector(
[uiSelector, selectedImageSelector, systemSelector],
@ -50,7 +51,7 @@ export const imagesSelector = createSelector(
}
);
export default function CurrentImagePreview() {
const CurrentImagePreview = () => {
const { shouldShowImageDetails, imageToDisplay, shouldHidePreview } =
useAppSelector(imagesSelector);
const { getUrl } = useGetUrl();
@ -115,4 +116,6 @@ export default function CurrentImagePreview() {
)}
</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 useResolution from 'common/hooks/useResolution';
import { Flex } from '@chakra-ui/react';
import { memo } from 'react';
const GALLERY_TAB_WIDTHS: Record<
InvokeTabName,
@ -72,7 +73,7 @@ const galleryPanelSelector = createSelector(
}
);
export default function ImageGalleryPanel() {
export const ImageGalleryPanel = () => {
const dispatch = useAppDispatch();
const {
shouldPinGallery,
@ -232,4 +233,6 @@ export default function ImageGalleryPanel() {
};
return renderImageGallery();
}
};
export default memo(ImageGalleryPanel);

View File

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

View File

@ -4,23 +4,27 @@ import * as InvokeAI from 'app/types/invokeai';
import promptToString from 'common/util/promptToString';
import { useAppDispatch } from 'app/store/storeHooks';
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.
// This hook provides a function to do that.
const useSetBothPrompts = () => {
const dispatch = useAppDispatch();
return (inputPrompt: InvokeAI.Prompt) => {
const promptString =
typeof inputPrompt === 'string'
? inputPrompt
: promptToString(inputPrompt);
return useCallback(
(inputPrompt: InvokeAI.Prompt) => {
const promptString =
typeof inputPrompt === 'string'
? inputPrompt
: promptToString(inputPrompt);
const [prompt, negativePrompt] = getPromptAndNegative(promptString);
const [prompt, negativePrompt] = getPromptAndNegative(promptString);
dispatch(setPrompt(prompt));
dispatch(setNegativePrompt(negativePrompt));
};
dispatch(setPrompt(prompt));
dispatch(setNegativePrompt(negativePrompt));
},
[dispatch]
);
};
export default useSetBothPrompts;

View File

@ -9,7 +9,7 @@ import {
} from 'features/system/store/systemSlice';
import { isEqual } from 'lodash-es';
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 { useTranslation } from 'react-i18next';
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 { SystemState } from 'features/system/store/systemSlice';
import { isEqual } from 'lodash-es';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PROGRESS_BAR_THICKNESS } from 'theme/util/constants';
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 { useState } from 'react';
import { memo, useState } from 'react';
import ModelSelect from './ModelSelect';
import StatusIndicator from './StatusIndicator';
@ -65,5 +65,4 @@ const SiteHeader = () => {
);
};
SiteHeader.displayName = 'SiteHeader';
export default SiteHeader;
export default memo(SiteHeader);

View File

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

View File

@ -89,18 +89,6 @@ export interface SystemState
* Array of node IDs that we want to handle when events received
*/
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
*/
@ -358,27 +346,6 @@ export const systemSlice = createSlice({
subscribedNodeIdsSet: (state, action: PayloadAction<string[]>) => {
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) {
/**
@ -386,6 +353,7 @@ export const systemSlice = createSlice({
*/
builder.addCase(socketSubscribed, (state, action) => {
state.sessionId = action.payload.sessionId;
console.log(`Subscribed to session ${action.payload.sessionId}`);
});
/**
@ -594,9 +562,6 @@ export const {
scheduledCancelAborted,
cancelTypeChanged,
subscribedNodeIdsSet,
// shouldTransformUrlsChanged,
// disabledTabsChanged,
// disabledFeaturesChanged,
} = systemSlice.actions;
export default systemSlice.reducer;

View File

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

View File

@ -11,6 +11,7 @@ import {
} from 'features/ui/store/uiSelectors';
import { setShouldShowParametersPanel } from 'features/ui/store/uiSlice';
import { isEqual } from 'lodash-es';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { FaSlidersH } from 'react-icons/fa';
@ -94,4 +95,4 @@ const FloatingParametersPanelButtons = () => {
) : 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 { InvokeTabName } from 'features/ui/store/tabMap';
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 { MdDeviceHub, MdGridOn } from 'react-icons/md';
import { activeTabIndexSelector } from '../store/uiSelectors';
@ -24,10 +24,10 @@ import { ResourceKey } from 'i18next';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import NodeEditor from 'features/nodes/components/NodeEditor';
import GenerateWorkspace from './tabs/Generate/GenerateWorkspace';
import { FaImage } from 'react-icons/fa';
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 { isEqual } from 'lodash';
export interface InvokeTabInfo {
id: InvokeTabName;
@ -35,10 +35,6 @@ export interface InvokeTabInfo {
workarea: ReactNode;
}
const tabIconStyles: ChakraProps['sx'] = {
boxSize: 6,
};
const tabs: InvokeTabInfo[] = [
{
id: 'generate',
@ -57,13 +53,19 @@ const tabs: InvokeTabInfo[] = [
},
];
const enabledTabsSelector = createSelector(configSelector, (config) => {
const { disabledTabs } = config;
const enabledTabsSelector = createSelector(
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 enabledTabs = useAppSelector(enabledTabsSelector);
const isLightBoxOpen = useAppSelector(
@ -160,4 +162,6 @@ export default function InvokeTabs() {
<TabPanels>{tabPanels}</TabPanels>
</Tabs>
);
}
};
export default memo(InvokeTabs);