mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat: Initial port of Model Manager to new tab
This commit is contained in:
parent
9e35643911
commit
2ad5a4ea46
@ -1,93 +0,0 @@
|
|||||||
import {
|
|
||||||
Flex,
|
|
||||||
Modal,
|
|
||||||
ModalBody,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalContent,
|
|
||||||
ModalFooter,
|
|
||||||
ModalHeader,
|
|
||||||
ModalOverlay,
|
|
||||||
useDisclosure,
|
|
||||||
} from '@chakra-ui/react';
|
|
||||||
import { cloneElement } from 'react';
|
|
||||||
|
|
||||||
import { RootState } from 'app/store/store';
|
|
||||||
import { useAppSelector } from 'app/store/storeHooks';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import type { ReactElement } from 'react';
|
|
||||||
|
|
||||||
import { useListModelsQuery } from 'services/api/endpoints/models';
|
|
||||||
import CheckpointModelEdit from './CheckpointModelEdit';
|
|
||||||
import DiffusersModelEdit from './DiffusersModelEdit';
|
|
||||||
import ModelList from './ModelList';
|
|
||||||
|
|
||||||
type ModelManagerModalProps = {
|
|
||||||
children: ReactElement;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function ModelManagerModal({
|
|
||||||
children,
|
|
||||||
}: ModelManagerModalProps) {
|
|
||||||
const {
|
|
||||||
isOpen: isModelManagerModalOpen,
|
|
||||||
onOpen: onModelManagerModalOpen,
|
|
||||||
onClose: onModelManagerModalClose,
|
|
||||||
} = useDisclosure();
|
|
||||||
|
|
||||||
const { data: pipelineModels } = useListModelsQuery({
|
|
||||||
model_type: 'pipeline',
|
|
||||||
});
|
|
||||||
|
|
||||||
const openModel = useAppSelector(
|
|
||||||
(state: RootState) => state.system.openModel
|
|
||||||
);
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const renderModelEditTabs = () => {
|
|
||||||
if (!openModel || !pipelineModels) return;
|
|
||||||
|
|
||||||
if (pipelineModels['entities'][openModel]['model_format'] === 'diffusers') {
|
|
||||||
return (
|
|
||||||
<DiffusersModelEdit
|
|
||||||
modelToEdit={openModel}
|
|
||||||
retrievedModel={pipelineModels['entities'][openModel]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<CheckpointModelEdit
|
|
||||||
modelToEdit={openModel}
|
|
||||||
retrievedModel={pipelineModels['entities'][openModel]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{cloneElement(children, {
|
|
||||||
onClick: onModelManagerModalOpen,
|
|
||||||
})}
|
|
||||||
<Modal
|
|
||||||
isOpen={isModelManagerModalOpen}
|
|
||||||
onClose={onModelManagerModalClose}
|
|
||||||
size="full"
|
|
||||||
>
|
|
||||||
<ModalOverlay />
|
|
||||||
<ModalContent>
|
|
||||||
<ModalCloseButton />
|
|
||||||
<ModalHeader>{t('modelManager.modelManager')}</ModalHeader>
|
|
||||||
<ModalBody>
|
|
||||||
<Flex width="100%" columnGap={8}>
|
|
||||||
<ModelList />
|
|
||||||
{renderModelEditTabs()}
|
|
||||||
</Flex>
|
|
||||||
</ModalBody>
|
|
||||||
<ModalFooter />
|
|
||||||
</ModalContent>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -5,21 +5,18 @@ import StatusIndicator from './StatusIndicator';
|
|||||||
import { Link } from '@chakra-ui/react';
|
import { Link } from '@chakra-ui/react';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaBug, FaCube, FaDiscord, FaGithub, FaKeyboard } from 'react-icons/fa';
|
import { FaBug, FaDiscord, FaGithub, FaKeyboard } from 'react-icons/fa';
|
||||||
import { MdSettings } from 'react-icons/md';
|
import { MdSettings } from 'react-icons/md';
|
||||||
|
import { useFeatureStatus } from '../hooks/useFeatureStatus';
|
||||||
|
import ColorModeButton from './ColorModeButton';
|
||||||
import HotkeysModal from './HotkeysModal/HotkeysModal';
|
import HotkeysModal from './HotkeysModal/HotkeysModal';
|
||||||
import InvokeAILogoComponent from './InvokeAILogoComponent';
|
import InvokeAILogoComponent from './InvokeAILogoComponent';
|
||||||
import LanguagePicker from './LanguagePicker';
|
import LanguagePicker from './LanguagePicker';
|
||||||
import ModelManagerModal from './ModelManager/ModelManagerModal';
|
|
||||||
import SettingsModal from './SettingsModal/SettingsModal';
|
import SettingsModal from './SettingsModal/SettingsModal';
|
||||||
import { useFeatureStatus } from '../hooks/useFeatureStatus';
|
|
||||||
import ColorModeButton from './ColorModeButton';
|
|
||||||
|
|
||||||
const SiteHeader = () => {
|
const SiteHeader = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const isModelManagerEnabled =
|
|
||||||
useFeatureStatus('modelManager').isFeatureEnabled;
|
|
||||||
const isLocalizationEnabled =
|
const isLocalizationEnabled =
|
||||||
useFeatureStatus('localization').isFeatureEnabled;
|
useFeatureStatus('localization').isFeatureEnabled;
|
||||||
const isBugLinkEnabled = useFeatureStatus('bugLink').isFeatureEnabled;
|
const isBugLinkEnabled = useFeatureStatus('bugLink').isFeatureEnabled;
|
||||||
@ -37,20 +34,6 @@ const SiteHeader = () => {
|
|||||||
<Spacer />
|
<Spacer />
|
||||||
<StatusIndicator />
|
<StatusIndicator />
|
||||||
|
|
||||||
{isModelManagerEnabled && (
|
|
||||||
<ModelManagerModal>
|
|
||||||
<IAIIconButton
|
|
||||||
aria-label={t('modelManager.modelManager')}
|
|
||||||
tooltip={t('modelManager.modelManager')}
|
|
||||||
size="sm"
|
|
||||||
variant="link"
|
|
||||||
data-variant="link"
|
|
||||||
fontSize={20}
|
|
||||||
icon={<FaCube />}
|
|
||||||
/>
|
|
||||||
</ModelManagerModal>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<HotkeysModal>
|
<HotkeysModal>
|
||||||
<IAIIconButton
|
<IAIIconButton
|
||||||
aria-label={t('common.hotkeysLabel')}
|
aria-label={t('common.hotkeysLabel')}
|
||||||
|
@ -1,7 +1,81 @@
|
|||||||
import { memo } from 'react';
|
import { Tab, TabList, TabPanel, TabPanels, Tabs } from '@chakra-ui/react';
|
||||||
|
import i18n from 'i18n';
|
||||||
|
import { ReactNode, memo } from 'react';
|
||||||
|
import AddModelsPanel from './subpanels/AddModelsPanel';
|
||||||
|
import MergeModelsPanel from './subpanels/MergeModelsPanel';
|
||||||
|
import ModelManagerPanel from './subpanels/ModelManagerPanel';
|
||||||
|
|
||||||
|
type ModelManagerTabName = 'modelmanager' | 'add_models' | 'merge_models';
|
||||||
|
|
||||||
|
type ModelManagerTabInfo = {
|
||||||
|
id: ModelManagerTabName;
|
||||||
|
label: string;
|
||||||
|
content: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const modelManagerTabs: ModelManagerTabInfo[] = [
|
||||||
|
{
|
||||||
|
id: 'modelmanager',
|
||||||
|
label: i18n.t('modelManager.modelManager'),
|
||||||
|
content: <ModelManagerPanel />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'add_models',
|
||||||
|
label: i18n.t('modelManager.addModel'),
|
||||||
|
content: <AddModelsPanel />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'merge_models',
|
||||||
|
label: i18n.t('modelManager.mergeModels'),
|
||||||
|
content: <MergeModelsPanel />,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const ModelManagerTab = () => {
|
const ModelManagerTab = () => {
|
||||||
return 'Model Manager';
|
const renderTabsList = () => {
|
||||||
|
const modelManagerTabListsToRender: ReactNode[] = [];
|
||||||
|
modelManagerTabs.forEach((modelManagerTab) => {
|
||||||
|
modelManagerTabListsToRender.push(
|
||||||
|
<Tab key={modelManagerTab.id}>{modelManagerTab.label}</Tab>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TabList
|
||||||
|
sx={{
|
||||||
|
w: '100%',
|
||||||
|
color: 'base.200',
|
||||||
|
flexDirection: 'row',
|
||||||
|
borderBottomWidth: 2,
|
||||||
|
borderColor: 'accent.700',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{modelManagerTabListsToRender}
|
||||||
|
</TabList>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTabPanels = () => {
|
||||||
|
const modelManagerTabPanelsToRender: ReactNode[] = [];
|
||||||
|
modelManagerTabs.forEach((modelManagerTab) => {
|
||||||
|
modelManagerTabPanelsToRender.push(
|
||||||
|
<TabPanel key={modelManagerTab.id}>{modelManagerTab.content}</TabPanel>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return <TabPanels sx={{ p: 2 }}>{modelManagerTabPanelsToRender}</TabPanels>;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
isLazy
|
||||||
|
variant="invokeAI"
|
||||||
|
sx={{ w: 'full', h: 'full', p: 2, gap: 4, flexDirection: 'column' }}
|
||||||
|
>
|
||||||
|
{renderTabsList()}
|
||||||
|
{renderTabPanels()}
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(ModelManagerTab);
|
export default memo(ModelManagerTab);
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import AddModel from 'features/ui/components/tabs/ModelManager/subpanels/AddModelsPanel/AddModel';
|
||||||
|
|
||||||
|
export default function AddModelsPanel() {
|
||||||
|
return (
|
||||||
|
<Flex>
|
||||||
|
<AddModel />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -10,13 +10,11 @@ import {
|
|||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
|
||||||
import IAIInput from 'common/components/IAIInput';
|
import IAIInput from 'common/components/IAIInput';
|
||||||
import IAINumberInput from 'common/components/IAINumberInput';
|
import IAINumberInput from 'common/components/IAINumberInput';
|
||||||
|
import IAISimpleCheckbox from 'common/components/IAISimpleCheckbox';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import SearchModels from './SearchModels';
|
|
||||||
|
|
||||||
// import { addNewModel } from 'app/socketio/actions';
|
// import { addNewModel } from 'app/socketio/actions';
|
||||||
|
|
||||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
@ -24,12 +22,13 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { Field, Formik } from 'formik';
|
import { Field, Formik } from 'formik';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { InvokeModelConfigProps } from 'app/types/invokeai';
|
|
||||||
import type { RootState } from 'app/store/store';
|
import type { RootState } from 'app/store/store';
|
||||||
import { setAddNewModelUIOption } from 'features/ui/store/uiSlice';
|
import type { InvokeModelConfigProps } from 'app/types/invokeai';
|
||||||
import type { FieldInputProps, FormikProps } from 'formik';
|
|
||||||
import IAIForm from 'common/components/IAIForm';
|
import IAIForm from 'common/components/IAIForm';
|
||||||
import { IAIFormItemWrapper } from 'common/components/IAIForms/IAIFormItemWrapper';
|
import { IAIFormItemWrapper } from 'common/components/IAIForms/IAIFormItemWrapper';
|
||||||
|
import { setAddNewModelUIOption } from 'features/ui/store/uiSlice';
|
||||||
|
import type { FieldInputProps, FormikProps } from 'formik';
|
||||||
|
import SearchModels from './SearchModels';
|
||||||
|
|
||||||
const MIN_MODEL_SIZE = 64;
|
const MIN_MODEL_SIZE = 64;
|
||||||
const MAX_MODEL_SIZE = 2048;
|
const MAX_MODEL_SIZE = 2048;
|
@ -0,0 +1,10 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import MergeModels from 'features/ui/components/tabs/ModelManager/subpanels/MergeModelsPanel/MergeModels';
|
||||||
|
|
||||||
|
export default function MergeModelsPanel() {
|
||||||
|
return (
|
||||||
|
<Flex>
|
||||||
|
<MergeModels />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
|
|
||||||
|
import { useListModelsQuery } from 'services/api/endpoints/models';
|
||||||
|
import CheckpointModelEdit from './ModelManagerPanel/CheckpointModelEdit';
|
||||||
|
import DiffusersModelEdit from './ModelManagerPanel/DiffusersModelEdit';
|
||||||
|
import ModelList from './ModelManagerPanel/ModelList';
|
||||||
|
|
||||||
|
export default function ModelManagerPanel() {
|
||||||
|
const { data: pipelineModels } = useListModelsQuery({
|
||||||
|
model_type: 'pipeline',
|
||||||
|
});
|
||||||
|
|
||||||
|
const openModel = useAppSelector(
|
||||||
|
(state: RootState) => state.system.openModel
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderModelEditTabs = () => {
|
||||||
|
if (!openModel || !pipelineModels) return;
|
||||||
|
|
||||||
|
if (pipelineModels['entities'][openModel]['model_format'] === 'diffusers') {
|
||||||
|
return (
|
||||||
|
<DiffusersModelEdit
|
||||||
|
modelToEdit={openModel}
|
||||||
|
retrievedModel={pipelineModels['entities'][openModel]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<CheckpointModelEdit
|
||||||
|
modelToEdit={openModel}
|
||||||
|
retrievedModel={pipelineModels['entities'][openModel]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Flex width="100%" columnGap={8}>
|
||||||
|
<ModelList />
|
||||||
|
{renderModelEditTabs()}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -1,9 +1,7 @@
|
|||||||
import { Box, Flex, Heading, Spacer, Spinner, Text } from '@chakra-ui/react';
|
import { Box, Flex, Spinner, Text } from '@chakra-ui/react';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIInput from 'common/components/IAIInput';
|
import IAIInput from 'common/components/IAIInput';
|
||||||
|
|
||||||
import AddModel from './AddModel';
|
|
||||||
import MergeModels from './MergeModels';
|
|
||||||
import ModelListItem from './ModelListItem';
|
import ModelListItem from './ModelListItem';
|
||||||
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -185,13 +183,6 @@ const ModelList = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDirection="column" rowGap={4} width="50%" minWidth="50%">
|
<Flex flexDirection="column" rowGap={4} width="50%" minWidth="50%">
|
||||||
<Flex justifyContent="space-between" alignItems="center" gap={2}>
|
|
||||||
<Heading size="md">{t('modelManager.availableModels')}</Heading>
|
|
||||||
<Spacer />
|
|
||||||
<AddModel />
|
|
||||||
<MergeModels />
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<IAIInput
|
<IAIInput
|
||||||
onChange={handleSearchFilter}
|
onChange={handleSearchFilter}
|
||||||
label={t('modelManager.search')}
|
label={t('modelManager.search')}
|
Loading…
x
Reference in New Issue
Block a user