mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): support disabledFeatures, add nicer loading
- `disabledParametersPanels` -> `disabledFeatures` - handle disabling `faceRestore`, `upscaling`, `lightbox`, `modelManager` and OSS header links/buttons - wait until models are loaded to hide loading screen - also wait until schema is parsed if `nodes` is an enabled tab
This commit is contained in:
parent
82c4dd8b86
commit
c1c881ded5
@ -1,39 +0,0 @@
|
|||||||
import { Flex, Spinner, Text } from '@chakra-ui/react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
interface LoaderProps {
|
|
||||||
showText?: boolean;
|
|
||||||
text?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This component loads before the theme so we cannot use theme tokens here
|
|
||||||
|
|
||||||
const Loading = (props: LoaderProps) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const { showText = false, text = t('common.loadingInvokeAI') } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
width="100vw"
|
|
||||||
height="100vh"
|
|
||||||
alignItems="center"
|
|
||||||
justifyContent="center"
|
|
||||||
bg="#121212"
|
|
||||||
flexDirection="column"
|
|
||||||
rowGap={4}
|
|
||||||
>
|
|
||||||
<Spinner color="grey" w="5rem" h="5rem" />
|
|
||||||
{showText && (
|
|
||||||
<Text
|
|
||||||
color="grey"
|
|
||||||
fontWeight="semibold"
|
|
||||||
fontFamily="'Inter', sans-serif"
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Loading;
|
|
@ -15,17 +15,24 @@ import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel';
|
|||||||
import Lightbox from 'features/lightbox/components/Lightbox';
|
import Lightbox from 'features/lightbox/components/Lightbox';
|
||||||
import { useAppDispatch, useAppSelector } from './storeHooks';
|
import { useAppDispatch, useAppSelector } from './storeHooks';
|
||||||
import { PropsWithChildren, useEffect } from 'react';
|
import { PropsWithChildren, useEffect } from 'react';
|
||||||
import { setDisabledPanels, setDisabledTabs } from 'features/ui/store/uiSlice';
|
|
||||||
import { InvokeTabName } from 'features/ui/store/tabMap';
|
import { InvokeTabName } from 'features/ui/store/tabMap';
|
||||||
import { shouldTransformUrlsChanged } from 'features/system/store/systemSlice';
|
import { shouldTransformUrlsChanged } from 'features/system/store/systemSlice';
|
||||||
import { setShouldFetchImages } from 'features/gallery/store/resultsSlice';
|
import { setShouldFetchImages } from 'features/gallery/store/resultsSlice';
|
||||||
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
|
import Loading from 'common/components/Loading/Loading';
|
||||||
|
import {
|
||||||
|
ApplicationFeature,
|
||||||
|
disabledFeaturesChanged,
|
||||||
|
disabledTabsChanged,
|
||||||
|
} from 'features/system/store/systemSlice';
|
||||||
|
import { useIsApplicationReady } from 'features/system/hooks/useIsApplicationReady';
|
||||||
|
|
||||||
keepGUIAlive();
|
keepGUIAlive();
|
||||||
|
|
||||||
interface Props extends PropsWithChildren {
|
interface Props extends PropsWithChildren {
|
||||||
options: {
|
options: {
|
||||||
disabledPanels: string[];
|
|
||||||
disabledTabs: InvokeTabName[];
|
disabledTabs: InvokeTabName[];
|
||||||
|
disabledFeatures: ApplicationFeature[];
|
||||||
shouldTransformUrls?: boolean;
|
shouldTransformUrls?: boolean;
|
||||||
shouldFetchImages: boolean;
|
shouldFetchImages: boolean;
|
||||||
};
|
};
|
||||||
@ -35,15 +42,21 @@ const App = (props: Props) => {
|
|||||||
useToastWatcher();
|
useToastWatcher();
|
||||||
|
|
||||||
const currentTheme = useAppSelector((state) => state.ui.currentTheme);
|
const currentTheme = useAppSelector((state) => state.ui.currentTheme);
|
||||||
|
const disabledFeatures = useAppSelector(
|
||||||
|
(state) => state.system.disabledFeatures
|
||||||
|
);
|
||||||
|
|
||||||
|
const isApplicationReady = useIsApplicationReady();
|
||||||
|
|
||||||
const { setColorMode } = useColorMode();
|
const { setColorMode } = useColorMode();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(setDisabledPanels(props.options.disabledPanels));
|
dispatch(disabledFeaturesChanged(props.options.disabledFeatures));
|
||||||
}, [dispatch, props.options.disabledPanels]);
|
}, [dispatch, props.options.disabledFeatures]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(setDisabledTabs(props.options.disabledTabs));
|
dispatch(disabledTabsChanged(props.options.disabledTabs));
|
||||||
}, [dispatch, props.options.disabledTabs]);
|
}, [dispatch, props.options.disabledTabs]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -61,8 +74,8 @@ const App = (props: Props) => {
|
|||||||
}, [setColorMode, currentTheme]);
|
}, [setColorMode, currentTheme]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid w="100vw" h="100vh">
|
<Grid w="100vw" h="100vh" position="relative">
|
||||||
<Lightbox />
|
{!disabledFeatures.includes('lightbox') && <Lightbox />}
|
||||||
<ImageUploader>
|
<ImageUploader>
|
||||||
<ProgressBar />
|
<ProgressBar />
|
||||||
<Grid
|
<Grid
|
||||||
@ -83,16 +96,34 @@ const App = (props: Props) => {
|
|||||||
<ImageGalleryPanel />
|
<ImageGalleryPanel />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Box>
|
|
||||||
<Console />
|
|
||||||
</Box>
|
|
||||||
</ImageUploader>
|
</ImageUploader>
|
||||||
|
|
||||||
|
<AnimatePresence>
|
||||||
|
{!isApplicationReady && (
|
||||||
|
<motion.div
|
||||||
|
key="loading"
|
||||||
|
initial={{ opacity: 1 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
style={{ zIndex: 3 }}
|
||||||
|
>
|
||||||
|
<Box position="absolute" top={0} left={0} w="100vw" h="100vh">
|
||||||
|
<Loading />
|
||||||
|
</Box>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
<Portal>
|
<Portal>
|
||||||
<FloatingParametersPanelButtons />
|
<FloatingParametersPanelButtons />
|
||||||
</Portal>
|
</Portal>
|
||||||
<Portal>
|
<Portal>
|
||||||
<FloatingGalleryButton />
|
<FloatingGalleryButton />
|
||||||
</Portal>
|
</Portal>
|
||||||
|
<Portal>
|
||||||
|
<Console />
|
||||||
|
</Portal>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
import { Flex, Image } from '@chakra-ui/react';
|
||||||
|
import InvokeAILogoImage from 'assets/images/logo.png';
|
||||||
|
|
||||||
|
// This component loads before the theme so we cannot use theme tokens here
|
||||||
|
|
||||||
|
const Loading = () => {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
position="relative"
|
||||||
|
width="100vw"
|
||||||
|
height="100vh"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
bg="#151519"
|
||||||
|
>
|
||||||
|
<Image src={InvokeAILogoImage} w="8rem" h="8rem" />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Loading;
|
@ -15,11 +15,12 @@ import '@fontsource/inter/700.css';
|
|||||||
import '@fontsource/inter/800.css';
|
import '@fontsource/inter/800.css';
|
||||||
import '@fontsource/inter/900.css';
|
import '@fontsource/inter/900.css';
|
||||||
|
|
||||||
import Loading from './Loading';
|
import Loading from './common/components/Loading/Loading';
|
||||||
|
|
||||||
// Localization
|
// Localization
|
||||||
import './i18n';
|
import './i18n';
|
||||||
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
|
import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares';
|
||||||
|
import { ApplicationFeature } from 'features/system/store/systemSlice';
|
||||||
|
|
||||||
const App = lazy(() => import('./app/App'));
|
const App = lazy(() => import('./app/App'));
|
||||||
const ThemeLocaleProvider = lazy(() => import('./app/ThemeLocaleProvider'));
|
const ThemeLocaleProvider = lazy(() => import('./app/ThemeLocaleProvider'));
|
||||||
@ -28,6 +29,7 @@ interface Props extends PropsWithChildren {
|
|||||||
apiUrl?: string;
|
apiUrl?: string;
|
||||||
disabledPanels?: string[];
|
disabledPanels?: string[];
|
||||||
disabledTabs?: InvokeTabName[];
|
disabledTabs?: InvokeTabName[];
|
||||||
|
disabledFeatures?: ApplicationFeature[];
|
||||||
token?: string;
|
token?: string;
|
||||||
shouldTransformUrls?: boolean;
|
shouldTransformUrls?: boolean;
|
||||||
shouldFetchImages?: boolean;
|
shouldFetchImages?: boolean;
|
||||||
@ -35,8 +37,15 @@ interface Props extends PropsWithChildren {
|
|||||||
|
|
||||||
export default function Component({
|
export default function Component({
|
||||||
apiUrl,
|
apiUrl,
|
||||||
disabledPanels = [],
|
|
||||||
disabledTabs = [],
|
disabledTabs = [],
|
||||||
|
disabledFeatures = [
|
||||||
|
'lightbox',
|
||||||
|
'bugLink',
|
||||||
|
'discordLink',
|
||||||
|
'githubLink',
|
||||||
|
'localization',
|
||||||
|
'modelManager',
|
||||||
|
],
|
||||||
token,
|
token,
|
||||||
children,
|
children,
|
||||||
shouldTransformUrls,
|
shouldTransformUrls,
|
||||||
@ -69,12 +78,12 @@ export default function Component({
|
|||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<PersistGate loading={<Loading />} persistor={persistor}>
|
<PersistGate loading={<Loading />} persistor={persistor}>
|
||||||
<React.Suspense fallback={<Loading showText />}>
|
<React.Suspense fallback={<Loading />}>
|
||||||
<ThemeLocaleProvider>
|
<ThemeLocaleProvider>
|
||||||
<App
|
<App
|
||||||
options={{
|
options={{
|
||||||
disabledPanels,
|
|
||||||
disabledTabs,
|
disabledTabs,
|
||||||
|
disabledFeatures,
|
||||||
shouldTransformUrls,
|
shouldTransformUrls,
|
||||||
shouldFetchImages,
|
shouldFetchImages,
|
||||||
}}
|
}}
|
||||||
|
@ -70,8 +70,8 @@ const currentImageButtonsSelector = createSelector(
|
|||||||
selectedImageSelector,
|
selectedImageSelector,
|
||||||
],
|
],
|
||||||
(
|
(
|
||||||
system: SystemState,
|
system,
|
||||||
gallery: GalleryState,
|
gallery,
|
||||||
postprocessing,
|
postprocessing,
|
||||||
ui,
|
ui,
|
||||||
lightbox,
|
lightbox,
|
||||||
@ -81,6 +81,8 @@ const currentImageButtonsSelector = createSelector(
|
|||||||
const { isProcessing, isConnected, isGFPGANAvailable, isESRGANAvailable } =
|
const { isProcessing, isConnected, isGFPGANAvailable, isESRGANAvailable } =
|
||||||
system;
|
system;
|
||||||
|
|
||||||
|
const { disabledFeatures } = system;
|
||||||
|
|
||||||
const { upscalingLevel, facetoolStrength } = postprocessing;
|
const { upscalingLevel, facetoolStrength } = postprocessing;
|
||||||
|
|
||||||
const { isLightboxOpen } = lightbox;
|
const { isLightboxOpen } = lightbox;
|
||||||
@ -90,6 +92,7 @@ const currentImageButtonsSelector = createSelector(
|
|||||||
const { intermediateImage, currentImage } = gallery;
|
const { intermediateImage, currentImage } = gallery;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
disabledFeatures,
|
||||||
isProcessing,
|
isProcessing,
|
||||||
isConnected,
|
isConnected,
|
||||||
isGFPGANAvailable,
|
isGFPGANAvailable,
|
||||||
@ -134,7 +137,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
activeTabName,
|
activeTabName,
|
||||||
shouldHidePreview,
|
shouldHidePreview,
|
||||||
selectedImage,
|
selectedImage,
|
||||||
|
disabledFeatures,
|
||||||
} = useAppSelector(currentImageButtonsSelector);
|
} = useAppSelector(currentImageButtonsSelector);
|
||||||
|
|
||||||
const { getUrl, shouldTransformUrls } = useGetUrl();
|
const { getUrl, shouldTransformUrls } = useGetUrl();
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
@ -328,24 +333,19 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
useHotkeys(
|
useHotkeys(
|
||||||
'Shift+U',
|
'Shift+U',
|
||||||
() => {
|
() => {
|
||||||
if (
|
|
||||||
isESRGANAvailable &&
|
|
||||||
!shouldDisableToolbarButtons &&
|
|
||||||
isConnected &&
|
|
||||||
!isProcessing &&
|
|
||||||
upscalingLevel
|
|
||||||
) {
|
|
||||||
handleClickUpscale();
|
handleClickUpscale();
|
||||||
} else {
|
},
|
||||||
toast({
|
{
|
||||||
title: t('toast.upscalingFailed'),
|
enabled: () =>
|
||||||
status: 'error',
|
disabledFeatures.includes('upscaling') ||
|
||||||
duration: 2500,
|
!isESRGANAvailable ||
|
||||||
isClosable: true,
|
shouldDisableToolbarButtons ||
|
||||||
});
|
!isConnected ||
|
||||||
}
|
isProcessing ||
|
||||||
|
!upscalingLevel,
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
disabledFeatures,
|
||||||
selectedImage,
|
selectedImage,
|
||||||
isESRGANAvailable,
|
isESRGANAvailable,
|
||||||
shouldDisableToolbarButtons,
|
shouldDisableToolbarButtons,
|
||||||
@ -362,24 +362,20 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
useHotkeys(
|
useHotkeys(
|
||||||
'Shift+R',
|
'Shift+R',
|
||||||
() => {
|
() => {
|
||||||
if (
|
|
||||||
isGFPGANAvailable &&
|
|
||||||
!shouldDisableToolbarButtons &&
|
|
||||||
isConnected &&
|
|
||||||
!isProcessing &&
|
|
||||||
facetoolStrength
|
|
||||||
) {
|
|
||||||
handleClickFixFaces();
|
handleClickFixFaces();
|
||||||
} else {
|
|
||||||
toast({
|
|
||||||
title: t('toast.faceRestoreFailed'),
|
|
||||||
status: 'error',
|
|
||||||
duration: 2500,
|
|
||||||
isClosable: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
enabled: () =>
|
||||||
|
disabledFeatures.includes('faceRestore') ||
|
||||||
|
!isGFPGANAvailable ||
|
||||||
|
shouldDisableToolbarButtons ||
|
||||||
|
!isConnected ||
|
||||||
|
isProcessing ||
|
||||||
|
!facetoolStrength,
|
||||||
|
},
|
||||||
|
|
||||||
[
|
[
|
||||||
|
disabledFeatures,
|
||||||
selectedImage,
|
selectedImage,
|
||||||
isGFPGANAvailable,
|
isGFPGANAvailable,
|
||||||
shouldDisableToolbarButtons,
|
shouldDisableToolbarButtons,
|
||||||
@ -509,6 +505,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
isChecked={shouldHidePreview}
|
isChecked={shouldHidePreview}
|
||||||
onClick={handlePreviewVisibility}
|
onClick={handlePreviewVisibility}
|
||||||
/>
|
/>
|
||||||
|
{!disabledFeatures.includes('lightbox') && (
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
icon={<FaExpand />}
|
icon={<FaExpand />}
|
||||||
tooltip={
|
tooltip={
|
||||||
@ -524,6 +521,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
isChecked={isLightboxOpen}
|
isChecked={isLightboxOpen}
|
||||||
onClick={handleLightBox}
|
onClick={handleLightBox}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<ButtonGroup isAttached={true}>
|
<ButtonGroup isAttached={true}>
|
||||||
@ -556,7 +554,12 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
/>
|
/>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
|
{!(
|
||||||
|
disabledFeatures.includes('faceRestore') &&
|
||||||
|
disabledFeatures.includes('upscaling')
|
||||||
|
) && (
|
||||||
<ButtonGroup isAttached={true}>
|
<ButtonGroup isAttached={true}>
|
||||||
|
{!disabledFeatures.includes('faceRestore') && (
|
||||||
<IAIPopover
|
<IAIPopover
|
||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
@ -585,7 +588,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
</IAIButton>
|
</IAIButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
</IAIPopover>
|
</IAIPopover>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!disabledFeatures.includes('upscaling') && (
|
||||||
<IAIPopover
|
<IAIPopover
|
||||||
triggerComponent={
|
triggerComponent={
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
@ -614,7 +619,9 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
|||||||
</IAIButton>
|
</IAIButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
</IAIPopover>
|
</IAIPopover>
|
||||||
|
)}
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
)}
|
||||||
|
|
||||||
<ButtonGroup isAttached={true}>
|
<ButtonGroup isAttached={true}>
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
|
@ -57,6 +57,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
galleryImageMinimumWidth,
|
galleryImageMinimumWidth,
|
||||||
mayDeleteImage,
|
mayDeleteImage,
|
||||||
shouldUseSingleGalleryColumn,
|
shouldUseSingleGalleryColumn,
|
||||||
|
disabledFeatures,
|
||||||
} = useAppSelector(hoverableImageSelector);
|
} = useAppSelector(hoverableImageSelector);
|
||||||
const { image, isSelected } = props;
|
const { image, isSelected } = props;
|
||||||
const { url, thumbnail, name, metadata } = image;
|
const { url, thumbnail, name, metadata } = image;
|
||||||
@ -133,7 +134,6 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
metadata.sd_metadata?.image?.init_image_path
|
metadata.sd_metadata?.image?.init_image_path
|
||||||
);
|
);
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
dispatch(setActiveTab('img2img'));
|
|
||||||
dispatch(setAllImageToImageParameters(metadata?.sd_metadata));
|
dispatch(setAllImageToImageParameters(metadata?.sd_metadata));
|
||||||
toast({
|
toast({
|
||||||
title: t('toast.initialImageSet'),
|
title: t('toast.initialImageSet'),
|
||||||
@ -174,9 +174,11 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
|||||||
menuProps={{ size: 'sm', isLazy: true }}
|
menuProps={{ size: 'sm', isLazy: true }}
|
||||||
renderMenu={() => (
|
renderMenu={() => (
|
||||||
<MenuList>
|
<MenuList>
|
||||||
|
{!disabledFeatures.includes('lightbox') && (
|
||||||
<MenuItem onClickCapture={handleLightBox}>
|
<MenuItem onClickCapture={handleLightBox}>
|
||||||
{t('parameters.openInViewer')}
|
{t('parameters.openInViewer')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
)}
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClickCapture={handleUsePrompt}
|
onClickCapture={handleUsePrompt}
|
||||||
isDisabled={image?.metadata?.sd_metadata?.prompt === undefined}
|
isDisabled={image?.metadata?.sd_metadata?.prompt === undefined}
|
||||||
|
@ -77,6 +77,7 @@ export const hoverableImageSelector = createSelector(
|
|||||||
shouldUseSingleGalleryColumn: gallery.shouldUseSingleGalleryColumn,
|
shouldUseSingleGalleryColumn: gallery.shouldUseSingleGalleryColumn,
|
||||||
activeTabName,
|
activeTabName,
|
||||||
isLightboxOpen: lightbox.isLightboxOpen,
|
isLightboxOpen: lightbox.isLightboxOpen,
|
||||||
|
disabledFeatures: system.disabledFeatures,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -85,8 +85,7 @@ const nodesSlice = createSlice({
|
|||||||
},
|
},
|
||||||
extraReducers(builder) {
|
extraReducers(builder) {
|
||||||
builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => {
|
builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => {
|
||||||
state.schema = action.payload;
|
state.invocationTemplates = action.payload;
|
||||||
state.invocationTemplates = parseSchema(action.payload);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.addMatcher(isFulfilledAnyGraphBuilt, (state, action) => {
|
builder.addMatcher(isFulfilledAnyGraphBuilt, (state, action) => {
|
||||||
|
@ -114,7 +114,5 @@ export const parseSchema = (openAPI: OpenAPIV3.Document) => {
|
|||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
console.debug('Generated invocations: ', invocations);
|
|
||||||
|
|
||||||
return invocations;
|
return invocations;
|
||||||
};
|
};
|
||||||
|
@ -2,21 +2,25 @@ import { Accordion } from '@chakra-ui/react';
|
|||||||
import { createSelector } from '@reduxjs/toolkit';
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { Feature } from 'app/features';
|
import { Feature } from 'app/features';
|
||||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||||
|
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||||
import { tabMap } from 'features/ui/store/tabMap';
|
import { tabMap } from 'features/ui/store/tabMap';
|
||||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||||
import { openAccordionItemsChanged } from 'features/ui/store/uiSlice';
|
import { openAccordionItemsChanged } from 'features/ui/store/uiSlice';
|
||||||
import { filter } from 'lodash';
|
import { filter, map } from 'lodash';
|
||||||
import { ReactNode, useCallback } from 'react';
|
import { ReactNode, useCallback } from 'react';
|
||||||
import InvokeAccordionItem from './AccordionItems/InvokeAccordionItem';
|
import InvokeAccordionItem from './AccordionItems/InvokeAccordionItem';
|
||||||
|
|
||||||
const parametersAccordionSelector = createSelector([uiSelector], (uiSlice) => {
|
const parametersAccordionSelector = createSelector(
|
||||||
|
[uiSelector, systemSelector],
|
||||||
|
(uiSlice, system) => {
|
||||||
const {
|
const {
|
||||||
activeTab,
|
activeTab,
|
||||||
openLinearAccordionItems,
|
openLinearAccordionItems,
|
||||||
openUnifiedCanvasAccordionItems,
|
openUnifiedCanvasAccordionItems,
|
||||||
disabledParameterPanels,
|
|
||||||
} = uiSlice;
|
} = uiSlice;
|
||||||
|
|
||||||
|
const { disabledFeatures } = system;
|
||||||
|
|
||||||
let openAccordions: number[] = [];
|
let openAccordions: number[] = [];
|
||||||
|
|
||||||
if (tabMap[activeTab] === 'linear') {
|
if (tabMap[activeTab] === 'linear') {
|
||||||
@ -29,9 +33,10 @@ const parametersAccordionSelector = createSelector([uiSelector], (uiSlice) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
openAccordions,
|
openAccordions,
|
||||||
disabledParameterPanels,
|
disabledFeatures,
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export type ParametersAccordionItem = {
|
export type ParametersAccordionItem = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -53,7 +58,7 @@ type ParametersAccordionProps = {
|
|||||||
* Main container for generation and processing parameters.
|
* Main container for generation and processing parameters.
|
||||||
*/
|
*/
|
||||||
const ParametersAccordion = ({ accordionItems }: ParametersAccordionProps) => {
|
const ParametersAccordion = ({ accordionItems }: ParametersAccordionProps) => {
|
||||||
const { openAccordions, disabledParameterPanels } = useAppSelector(
|
const { openAccordions, disabledFeatures } = useAppSelector(
|
||||||
parametersAccordionSelector
|
parametersAccordionSelector
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -68,20 +73,16 @@ const ParametersAccordion = ({ accordionItems }: ParametersAccordionProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Render function for accordion items
|
// Render function for accordion items
|
||||||
const renderAccordionItems = useCallback(() => {
|
const renderAccordionItems = useCallback(
|
||||||
// Filter out disabled accordions
|
() =>
|
||||||
const filteredAccordionItems = filter(
|
map(accordionItems, (accordionItem) => (
|
||||||
accordionItems,
|
|
||||||
(item) => disabledParameterPanels.indexOf(item.name) === -1
|
|
||||||
);
|
|
||||||
|
|
||||||
return filteredAccordionItems.map((accordionItem) => (
|
|
||||||
<InvokeAccordionItem
|
<InvokeAccordionItem
|
||||||
key={accordionItem.name}
|
key={accordionItem.name}
|
||||||
accordionItem={accordionItem}
|
accordionItem={accordionItem}
|
||||||
/>
|
/>
|
||||||
));
|
)),
|
||||||
}, [disabledParameterPanels, accordionItems]);
|
[accordionItems]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Accordion
|
<Accordion
|
||||||
|
@ -110,7 +110,7 @@ const Console = () => {
|
|||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
insetInlineStart: 0,
|
insetInlineStart: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
zIndex: 9999,
|
zIndex: 1,
|
||||||
}}
|
}}
|
||||||
maxHeight="90vh"
|
maxHeight="90vh"
|
||||||
>
|
>
|
||||||
@ -128,6 +128,7 @@ const Console = () => {
|
|||||||
borderTopWidth: 5,
|
borderTopWidth: 5,
|
||||||
bg: 'base.850',
|
bg: 'base.850',
|
||||||
borderColor: 'base.700',
|
borderColor: 'base.700',
|
||||||
|
zIndex: 2,
|
||||||
}}
|
}}
|
||||||
ref={viewerRef}
|
ref={viewerRef}
|
||||||
onScroll={handleOnScroll}
|
onScroll={handleOnScroll}
|
||||||
@ -166,7 +167,7 @@ const Console = () => {
|
|||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
insetInlineStart: 2,
|
insetInlineStart: 2,
|
||||||
bottom: 12,
|
bottom: 12,
|
||||||
zIndex: '10000',
|
zIndex: 1,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -184,7 +185,7 @@ const Console = () => {
|
|||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
insetInlineStart: 2,
|
insetInlineStart: 2,
|
||||||
bottom: 2,
|
bottom: 2,
|
||||||
zIndex: '10000',
|
zIndex: 1,
|
||||||
}}
|
}}
|
||||||
colorScheme={hasError || !wasErrorSeen ? 'error' : 'base'}
|
colorScheme={hasError || !wasErrorSeen ? 'error' : 'base'}
|
||||||
/>
|
/>
|
||||||
|
@ -8,8 +8,13 @@ import ModelManagerModal from './ModelManager/ModelManagerModal';
|
|||||||
import SettingsModal from './SettingsModal/SettingsModal';
|
import SettingsModal from './SettingsModal/SettingsModal';
|
||||||
import ThemeChanger from './ThemeChanger';
|
import ThemeChanger from './ThemeChanger';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import { useAppSelector } from 'app/storeHooks';
|
||||||
|
import { RootState } from 'app/store';
|
||||||
|
|
||||||
const SiteHeaderMenu = () => {
|
const SiteHeaderMenu = () => {
|
||||||
|
const disabledFeatures = useAppSelector(
|
||||||
|
(state: RootState) => state.system.disabledFeatures
|
||||||
|
);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -18,6 +23,7 @@ const SiteHeaderMenu = () => {
|
|||||||
flexDirection={{ base: 'column', xl: 'row' }}
|
flexDirection={{ base: 'column', xl: 'row' }}
|
||||||
gap={{ base: 4, xl: 1 }}
|
gap={{ base: 4, xl: 1 }}
|
||||||
>
|
>
|
||||||
|
{!disabledFeatures.includes('modelManager') && (
|
||||||
<ModelManagerModal>
|
<ModelManagerModal>
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label={t('modelManager.modelManager')}
|
aria-label={t('modelManager.modelManager')}
|
||||||
@ -29,6 +35,7 @@ const SiteHeaderMenu = () => {
|
|||||||
icon={<FaCube />}
|
icon={<FaCube />}
|
||||||
/>
|
/>
|
||||||
</ModelManagerModal>
|
</ModelManagerModal>
|
||||||
|
)}
|
||||||
|
|
||||||
<HotkeysModal>
|
<HotkeysModal>
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
@ -44,8 +51,9 @@ const SiteHeaderMenu = () => {
|
|||||||
|
|
||||||
<ThemeChanger />
|
<ThemeChanger />
|
||||||
|
|
||||||
<LanguagePicker />
|
{!disabledFeatures.includes('localization') && <LanguagePicker />}
|
||||||
|
|
||||||
|
{!disabledFeatures.includes('bugLink') && (
|
||||||
<Link
|
<Link
|
||||||
isExternal
|
isExternal
|
||||||
href="http://github.com/invoke-ai/InvokeAI/issues"
|
href="http://github.com/invoke-ai/InvokeAI/issues"
|
||||||
@ -61,7 +69,9 @@ const SiteHeaderMenu = () => {
|
|||||||
icon={<FaBug />}
|
icon={<FaBug />}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!disabledFeatures.includes('githubLink') && (
|
||||||
<Link
|
<Link
|
||||||
isExternal
|
isExternal
|
||||||
href="http://github.com/invoke-ai/InvokeAI"
|
href="http://github.com/invoke-ai/InvokeAI"
|
||||||
@ -77,7 +87,9 @@ const SiteHeaderMenu = () => {
|
|||||||
icon={<FaGithub />}
|
icon={<FaGithub />}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!disabledFeatures.includes('discordLink') && (
|
||||||
<Link
|
<Link
|
||||||
isExternal
|
isExternal
|
||||||
href="https://discord.gg/ZmtBAhwWhy"
|
href="https://discord.gg/ZmtBAhwWhy"
|
||||||
@ -93,6 +105,7 @@ const SiteHeaderMenu = () => {
|
|||||||
icon={<FaDiscord />}
|
icon={<FaDiscord />}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
)}
|
||||||
|
|
||||||
<SettingsModal>
|
<SettingsModal>
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { RootState } from 'app/store';
|
||||||
|
import { useAppSelector } from 'app/storeHooks';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
const isApplicationReadySelector = createSelector(
|
||||||
|
[(state: RootState) => state.system],
|
||||||
|
(system) => {
|
||||||
|
const {
|
||||||
|
disabledFeatures,
|
||||||
|
disabledTabs,
|
||||||
|
wereModelsReceived,
|
||||||
|
wasSchemaParsed,
|
||||||
|
} = system;
|
||||||
|
|
||||||
|
return {
|
||||||
|
disabledTabs,
|
||||||
|
disabledFeatures,
|
||||||
|
wereModelsReceived,
|
||||||
|
wasSchemaParsed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const useIsApplicationReady = () => {
|
||||||
|
const {
|
||||||
|
disabledTabs,
|
||||||
|
disabledFeatures,
|
||||||
|
wereModelsReceived,
|
||||||
|
wasSchemaParsed,
|
||||||
|
} = useAppSelector(isApplicationReadySelector);
|
||||||
|
|
||||||
|
const isApplicationReady = useMemo(() => {
|
||||||
|
if (!wereModelsReceived) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!disabledTabs.includes('nodes') && !wasSchemaParsed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}, [disabledTabs, wereModelsReceived, wasSchemaParsed]);
|
||||||
|
|
||||||
|
return isApplicationReady;
|
||||||
|
};
|
@ -19,6 +19,8 @@ const itemsToBlacklist: (keyof SystemState)[] = [
|
|||||||
'isCancelScheduled',
|
'isCancelScheduled',
|
||||||
'sessionId',
|
'sessionId',
|
||||||
'progressImage',
|
'progressImage',
|
||||||
|
'wereModelsReceived',
|
||||||
|
'wasSchemaParsed',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const systemBlacklist = itemsToBlacklist.map(
|
export const systemBlacklist = itemsToBlacklist.map(
|
||||||
|
@ -19,6 +19,9 @@ import { ProgressImage } from 'services/events/types';
|
|||||||
import { initialImageSelected } from 'features/parameters/store/generationSlice';
|
import { initialImageSelected } from 'features/parameters/store/generationSlice';
|
||||||
import { makeToast } from '../hooks/useToastWatcher';
|
import { makeToast } from '../hooks/useToastWatcher';
|
||||||
import { sessionCanceled, sessionInvoked } from 'services/thunks/session';
|
import { sessionCanceled, sessionInvoked } from 'services/thunks/session';
|
||||||
|
import { InvokeTabName } from 'features/ui/store/tabMap';
|
||||||
|
import { receivedModels } from 'services/thunks/model';
|
||||||
|
import { receivedOpenAPISchema } from 'services/thunks/schema';
|
||||||
|
|
||||||
export type LogLevel = 'info' | 'warning' | 'error';
|
export type LogLevel = 'info' | 'warning' | 'error';
|
||||||
|
|
||||||
@ -32,10 +35,18 @@ export interface Log {
|
|||||||
[index: number]: LogEntry;
|
[index: number]: LogEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReadinessPayload = {
|
/**
|
||||||
isReady: boolean;
|
* A disable-able application feature
|
||||||
reasonsWhyNotReady: string[];
|
*/
|
||||||
};
|
export type ApplicationFeature =
|
||||||
|
| 'faceRestore'
|
||||||
|
| 'upscaling'
|
||||||
|
| 'lightbox'
|
||||||
|
| 'modelManager'
|
||||||
|
| 'githubLink'
|
||||||
|
| 'discordLink'
|
||||||
|
| 'bugLink'
|
||||||
|
| 'localization';
|
||||||
|
|
||||||
export type InProgressImageType = 'none' | 'full-res' | 'latents';
|
export type InProgressImageType = 'none' | 'full-res' | 'latents';
|
||||||
|
|
||||||
@ -96,6 +107,22 @@ export interface SystemState
|
|||||||
* Whether or not URLs should be transformed to use a different host
|
* Whether or not URLs should be transformed to use a different host
|
||||||
*/
|
*/
|
||||||
shouldTransformUrls: boolean;
|
shouldTransformUrls: boolean;
|
||||||
|
/**
|
||||||
|
* Array of disabled tabs
|
||||||
|
*/
|
||||||
|
disabledTabs: InvokeTabName[];
|
||||||
|
/**
|
||||||
|
* Array of disabled features
|
||||||
|
*/
|
||||||
|
disabledFeatures: ApplicationFeature[];
|
||||||
|
/**
|
||||||
|
* Whether or not the available models were received
|
||||||
|
*/
|
||||||
|
wereModelsReceived: boolean;
|
||||||
|
/**
|
||||||
|
* Whether or not the OpenAPI schema was received and parsed
|
||||||
|
*/
|
||||||
|
wasSchemaParsed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialSystemState: SystemState = {
|
const initialSystemState: SystemState = {
|
||||||
@ -144,6 +171,10 @@ const initialSystemState: SystemState = {
|
|||||||
isCancelScheduled: false,
|
isCancelScheduled: false,
|
||||||
subscribedNodeIds: [],
|
subscribedNodeIds: [],
|
||||||
shouldTransformUrls: false,
|
shouldTransformUrls: false,
|
||||||
|
disabledTabs: [],
|
||||||
|
disabledFeatures: [],
|
||||||
|
wereModelsReceived: false,
|
||||||
|
wasSchemaParsed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const systemSlice = createSlice({
|
export const systemSlice = createSlice({
|
||||||
@ -347,6 +378,21 @@ export const systemSlice = createSlice({
|
|||||||
shouldTransformUrlsChanged: (state, action: PayloadAction<boolean>) => {
|
shouldTransformUrlsChanged: (state, action: PayloadAction<boolean>) => {
|
||||||
state.shouldTransformUrls = action.payload;
|
state.shouldTransformUrls = action.payload;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* `disabledTabs` was changed
|
||||||
|
*/
|
||||||
|
disabledTabsChanged: (state, action: PayloadAction<InvokeTabName[]>) => {
|
||||||
|
state.disabledTabs = action.payload;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* `disabledFeatures` was changed
|
||||||
|
*/
|
||||||
|
disabledFeaturesChanged: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<ApplicationFeature[]>
|
||||||
|
) => {
|
||||||
|
state.disabledFeatures = action.payload;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers(builder) {
|
extraReducers(builder) {
|
||||||
/**
|
/**
|
||||||
@ -417,7 +463,8 @@ export const systemSlice = createSlice({
|
|||||||
step,
|
step,
|
||||||
total_steps,
|
total_steps,
|
||||||
progress_image,
|
progress_image,
|
||||||
invocation,
|
node,
|
||||||
|
source_node_id,
|
||||||
graph_execution_state_id,
|
graph_execution_state_id,
|
||||||
} = action.payload.data;
|
} = action.payload.data;
|
||||||
|
|
||||||
@ -514,6 +561,20 @@ export const systemSlice = createSlice({
|
|||||||
builder.addCase(initialImageSelected, (state) => {
|
builder.addCase(initialImageSelected, (state) => {
|
||||||
state.toastQueue.push(makeToast(i18n.t('toast.sentToImageToImage')));
|
state.toastQueue.push(makeToast(i18n.t('toast.sentToImageToImage')));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Received available models from the backend
|
||||||
|
*/
|
||||||
|
builder.addCase(receivedModels.fulfilled, (state, action) => {
|
||||||
|
state.wereModelsReceived = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenAPI schema was received and parsed
|
||||||
|
*/
|
||||||
|
builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => {
|
||||||
|
state.wasSchemaParsed = true;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -554,6 +615,8 @@ export const {
|
|||||||
cancelTypeChanged,
|
cancelTypeChanged,
|
||||||
subscribedNodeIdsSet,
|
subscribedNodeIdsSet,
|
||||||
shouldTransformUrlsChanged,
|
shouldTransformUrlsChanged,
|
||||||
|
disabledTabsChanged,
|
||||||
|
disabledFeaturesChanged,
|
||||||
} = systemSlice.actions;
|
} = systemSlice.actions;
|
||||||
|
|
||||||
export default systemSlice.reducer;
|
export default systemSlice.reducer;
|
||||||
|
@ -64,8 +64,13 @@ export default function InvokeTabs() {
|
|||||||
(state: RootState) => state.lightbox.isLightboxOpen
|
(state: RootState) => state.lightbox.isLightboxOpen
|
||||||
);
|
);
|
||||||
|
|
||||||
const { shouldPinGallery, disabledTabs, shouldPinParametersPanel } =
|
const { shouldPinGallery, shouldPinParametersPanel } = useAppSelector(
|
||||||
useAppSelector((state: RootState) => state.ui);
|
(state: RootState) => state.ui
|
||||||
|
);
|
||||||
|
|
||||||
|
const disabledTabs = useAppSelector(
|
||||||
|
(state: RootState) => state.system.disabledTabs
|
||||||
|
);
|
||||||
|
|
||||||
const activeTabs = buildTabs(disabledTabs);
|
const activeTabs = buildTabs(disabledTabs);
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import { initialImageSelected } from 'features/parameters/store/generationSlice';
|
|
||||||
import { setActiveTabReducer } from './extraReducers';
|
import { setActiveTabReducer } from './extraReducers';
|
||||||
import { InvokeTabName, tabMap } from './tabMap';
|
import { InvokeTabName, tabMap } from './tabMap';
|
||||||
import { AddNewModelType, UIState } from './uiTypes';
|
import { AddNewModelType, UIState } from './uiTypes';
|
||||||
|
|
||||||
const initialtabsState: UIState = {
|
const initialUIState: UIState = {
|
||||||
activeTab: 0,
|
activeTab: 0,
|
||||||
currentTheme: 'dark',
|
currentTheme: 'dark',
|
||||||
parametersPanelScrollPosition: 0,
|
parametersPanelScrollPosition: 0,
|
||||||
@ -19,13 +18,11 @@ const initialtabsState: UIState = {
|
|||||||
shouldPinGallery: true,
|
shouldPinGallery: true,
|
||||||
shouldShowGallery: true,
|
shouldShowGallery: true,
|
||||||
shouldHidePreview: false,
|
shouldHidePreview: false,
|
||||||
disabledParameterPanels: [],
|
|
||||||
disabledTabs: [],
|
|
||||||
openLinearAccordionItems: [],
|
openLinearAccordionItems: [],
|
||||||
openUnifiedCanvasAccordionItems: [],
|
openUnifiedCanvasAccordionItems: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: UIState = initialtabsState;
|
const initialState: UIState = initialUIState;
|
||||||
|
|
||||||
export const uiSlice = createSlice({
|
export const uiSlice = createSlice({
|
||||||
name: 'ui',
|
name: 'ui',
|
||||||
@ -98,12 +95,6 @@ export const uiSlice = createSlice({
|
|||||||
state.shouldShowParametersPanel = true;
|
state.shouldShowParametersPanel = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setDisabledPanels: (state, action: PayloadAction<string[]>) => {
|
|
||||||
state.disabledParameterPanels = action.payload;
|
|
||||||
},
|
|
||||||
setDisabledTabs: (state, action: PayloadAction<InvokeTabName[]>) => {
|
|
||||||
state.disabledTabs = action.payload;
|
|
||||||
},
|
|
||||||
openAccordionItemsChanged: (state, action: PayloadAction<number[]>) => {
|
openAccordionItemsChanged: (state, action: PayloadAction<number[]>) => {
|
||||||
if (tabMap[state.activeTab] === 'linear') {
|
if (tabMap[state.activeTab] === 'linear') {
|
||||||
state.openLinearAccordionItems = action.payload;
|
state.openLinearAccordionItems = action.payload;
|
||||||
@ -135,8 +126,6 @@ export const {
|
|||||||
togglePinParametersPanel,
|
togglePinParametersPanel,
|
||||||
toggleParametersPanel,
|
toggleParametersPanel,
|
||||||
toggleGalleryPanel,
|
toggleGalleryPanel,
|
||||||
setDisabledPanels,
|
|
||||||
setDisabledTabs,
|
|
||||||
openAccordionItemsChanged,
|
openAccordionItemsChanged,
|
||||||
} = uiSlice.actions;
|
} = uiSlice.actions;
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { InvokeTabName } from './tabMap';
|
|
||||||
|
|
||||||
export type AddNewModelType = 'ckpt' | 'diffusers' | null;
|
export type AddNewModelType = 'ckpt' | 'diffusers' | null;
|
||||||
|
|
||||||
export interface UIState {
|
export interface UIState {
|
||||||
@ -16,8 +14,6 @@ export interface UIState {
|
|||||||
shouldHidePreview: boolean;
|
shouldHidePreview: boolean;
|
||||||
shouldPinGallery: boolean;
|
shouldPinGallery: boolean;
|
||||||
shouldShowGallery: boolean;
|
shouldShowGallery: boolean;
|
||||||
disabledParameterPanels: string[];
|
|
||||||
disabledTabs: InvokeTabName[];
|
|
||||||
openLinearAccordionItems: number[];
|
openLinearAccordionItems: number[];
|
||||||
openUnifiedCanvasAccordionItems: number[];
|
openUnifiedCanvasAccordionItems: number[];
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,9 @@ export const socketMiddleware = () => {
|
|||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
dispatch(socketConnected({ timestamp: getTimestamp() }));
|
dispatch(socketConnected({ timestamp: getTimestamp() }));
|
||||||
|
|
||||||
const { results, uploads, models, nodes } = getState();
|
const { results, uploads, models, nodes, system } = getState();
|
||||||
|
|
||||||
|
const { disabledTabs } = system;
|
||||||
|
|
||||||
// These thunks need to be dispatch in middleware; cannot handle in a reducer
|
// These thunks need to be dispatch in middleware; cannot handle in a reducer
|
||||||
if (!results.ids.length) {
|
if (!results.ids.length) {
|
||||||
@ -107,7 +109,7 @@ export const socketMiddleware = () => {
|
|||||||
dispatch(receivedModels());
|
dispatch(receivedModels());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nodes.schema) {
|
if (!nodes.schema && !disabledTabs.includes('nodes')) {
|
||||||
dispatch(receivedOpenAPISchema());
|
dispatch(receivedOpenAPISchema());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||||
|
import { parseSchema } from 'features/nodes/util/parseSchema';
|
||||||
import { OpenAPIV3 } from 'openapi-types';
|
import { OpenAPIV3 } from 'openapi-types';
|
||||||
|
|
||||||
export const receivedOpenAPISchema = createAsyncThunk(
|
export const receivedOpenAPISchema = createAsyncThunk(
|
||||||
@ -9,6 +10,10 @@ export const receivedOpenAPISchema = createAsyncThunk(
|
|||||||
|
|
||||||
console.debug('OpenAPI schema: ', jsonData);
|
console.debug('OpenAPI schema: ', jsonData);
|
||||||
|
|
||||||
return jsonData;
|
const parsedSchema = parseSchema(jsonData);
|
||||||
|
|
||||||
|
console.debug('Parsed schema: ', parsedSchema);
|
||||||
|
|
||||||
|
return parsedSchema;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user