Skip to content

Commit 3210f96

Browse files
Model Manager 3.0 UI (#3735)
DONE: - Restore Update Model functionality - Restore Delete Model functionality - Restore Model Convert functionality - Restore Model Merge functionality - Refine UX (fine tweaks when everything is done - TODO) TODO - Add Model (will be finished in a future PR once the backend work is done)
2 parents e8d531b + 3c7cf72 commit 3210f96

File tree

50 files changed

+1269
-980
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1269
-980
lines changed

invokeai/backend/model_management/model_manager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ def del_model(
589589
rmtree(str(model_path))
590590
else:
591591
model_path.unlink()
592+
self.commit()
592593

593594
# LS: tested
594595
def add_model(

invokeai/frontend/web/public/locales/en.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@
343343
"safetensorModels": "SafeTensors",
344344
"modelAdded": "Model Added",
345345
"modelUpdated": "Model Updated",
346+
"modelUpdateFailed": "Model Update Failed",
346347
"modelEntryDeleted": "Model Entry Deleted",
347348
"cannotUseSpaces": "Cannot Use Spaces",
348349
"addNew": "Add New",
@@ -397,8 +398,8 @@
397398
"delete": "Delete",
398399
"deleteModel": "Delete Model",
399400
"deleteConfig": "Delete Config",
400-
"deleteMsg1": "Are you sure you want to delete this model entry from InvokeAI?",
401-
"deleteMsg2": "This will not delete the model checkpoint file from your disk. You can readd them if you wish to.",
401+
"deleteMsg1": "Are you sure you want to delete this model from InvokeAI?",
402+
"deleteMsg2": "This WILL delete the model from disk if it is in the InvokeAI root folder. If you are using a custom location, then the model WILL NOT be deleted from disk.",
402403
"formMessageDiffusersModelLocation": "Diffusers Model Location",
403404
"formMessageDiffusersModelLocationDesc": "Please enter at least one.",
404405
"formMessageDiffusersVAELocation": "VAE Location",
@@ -409,7 +410,7 @@
409410
"convertToDiffusersHelpText2": "This process will replace your Model Manager entry with the Diffusers version of the same model.",
410411
"convertToDiffusersHelpText3": "Your checkpoint file on the disk will NOT be deleted or modified in anyway. You can add your checkpoint to the Model Manager again if you want to.",
411412
"convertToDiffusersHelpText4": "This is a one time process only. It might take around 30s-60s depending on the specifications of your computer.",
412-
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 4GB-7GB in size.",
413+
"convertToDiffusersHelpText5": "Please make sure you have enough disk space. Models generally vary between 2GB-7GB in size.",
413414
"convertToDiffusersHelpText6": "Do you wish to convert this model?",
414415
"convertToDiffusersSaveLocation": "Save Location",
415416
"v1": "v1",
@@ -420,12 +421,14 @@
420421
"pathToCustomConfig": "Path To Custom Config",
421422
"statusConverting": "Converting",
422423
"modelConverted": "Model Converted",
424+
"modelConversionFailed": "Model Conversion Failed",
423425
"sameFolder": "Same folder",
424426
"invokeRoot": "InvokeAI folder",
425427
"custom": "Custom",
426428
"customSaveLocation": "Custom Save Location",
427429
"merge": "Merge",
428430
"modelsMerged": "Models Merged",
431+
"modelsMergeFailed": "Model Merge Failed",
429432
"mergeModels": "Merge Models",
430433
"modelOne": "Model 1",
431434
"modelTwo": "Model 2",
@@ -446,7 +449,8 @@
446449
"weightedSum": "Weighted Sum",
447450
"none": "none",
448451
"addDifference": "Add Difference",
449-
"pickModelType": "Pick Model Type"
452+
"pickModelType": "Pick Model Type",
453+
"selectModel": "Select Model"
450454
},
451455
"parameters": {
452456
"general": "General",
@@ -599,7 +603,6 @@
599603
"nodesLoaded": "Nodes Loaded",
600604
"nodesLoadedFailed": "Failed To Load Nodes",
601605
"nodesCleared": "Nodes Cleared"
602-
603606
},
604607
"tooltip": {
605608
"feature": {

invokeai/frontend/web/src/app/components/ThemeLocaleProvider.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import { theme as invokeAITheme } from 'theme/theme';
99

1010
import '@fontsource-variable/inter';
1111
import { MantineProvider } from '@mantine/core';
12-
import { mantineTheme } from 'mantine-theme/theme';
1312
import 'overlayscrollbars/overlayscrollbars.css';
1413
import 'theme/css/overlayscrollbars.css';
14+
import { useMantineTheme } from 'mantine-theme/theme';
1515

1616
type ThemeLocaleProviderProps = {
1717
children: ReactNode;
@@ -35,8 +35,10 @@ function ThemeLocaleProvider({ children }: ThemeLocaleProviderProps) {
3535
document.body.dir = direction;
3636
}, [direction]);
3737

38+
const mantineTheme = useMantineTheme();
39+
3840
return (
39-
<MantineProvider withGlobalStyles theme={mantineTheme}>
41+
<MantineProvider theme={mantineTheme}>
4042
<ChakraProvider theme={theme} colorModeManager={manager}>
4143
{children}
4244
</ChakraProvider>

invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/socketio/socketConnected.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { log } from 'app/logging/useLogger';
2-
import { appSocketConnected, socketConnected } from 'services/events/actions';
2+
import { modelsApi } from 'services/api/endpoints/models';
33
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
4+
import { appSocketConnected, socketConnected } from 'services/events/actions';
45
import { startAppListening } from '../..';
56

67
const moduleLog = log.child({ namespace: 'socketio' });
@@ -23,6 +24,13 @@ export const addSocketConnectedEventListener = () => {
2324

2425
// pass along the socket event as an application action
2526
dispatch(appSocketConnected(action.payload));
27+
28+
// update all server state
29+
dispatch(modelsApi.endpoints.getMainModels.initiate());
30+
dispatch(modelsApi.endpoints.getControlNetModels.initiate());
31+
dispatch(modelsApi.endpoints.getLoRAModels.initiate());
32+
dispatch(modelsApi.endpoints.getTextualInversionModels.initiate());
33+
dispatch(modelsApi.endpoints.getVaeModels.initiate());
2634
},
2735
});
2836
};

invokeai/frontend/web/src/app/store/store.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,11 @@ export const store = configureStore({
100100
// manually type state, cannot type the arg
101101
// const typedState = state as ReturnType<typeof rootReducer>;
102102

103-
if (action.type.startsWith('api/')) {
104-
// don't log api actions, with manual cache updates they are extremely noisy
105-
return false;
106-
}
103+
// TODO: doing this breaks the rtk query devtools, commenting out for now
104+
// if (action.type.startsWith('api/')) {
105+
// // don't log api actions, with manual cache updates they are extremely noisy
106+
// return false;
107+
// }
107108

108109
if (actionsDenylist.includes(action.type)) {
109110
// don't log other noisy actions

invokeai/frontend/web/src/common/components/IAIForms/IAIFormItemWrapper.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import { Flex } from '@chakra-ui/react';
1+
import { Flex, useColorMode } from '@chakra-ui/react';
22
import { ReactElement } from 'react';
3+
import { mode } from 'theme/util/mode';
34

45
export function IAIFormItemWrapper({
56
children,
67
}: {
78
children: ReactElement | ReactElement[];
89
}) {
10+
const { colorMode } = useColorMode();
911
return (
1012
<Flex
1113
sx={{
@@ -14,7 +16,7 @@ export function IAIFormItemWrapper({
1416
rowGap: 4,
1517
borderRadius: 'base',
1618
width: 'full',
17-
bg: 'base.900',
19+
bg: mode('base.100', 'base.900')(colorMode),
1820
}}
1921
>
2022
{children}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { useColorMode } from '@chakra-ui/react';
2+
import { TextInput, TextInputProps } from '@mantine/core';
3+
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
4+
import { mode } from 'theme/util/mode';
5+
6+
type IAIMantineTextInputProps = TextInputProps;
7+
8+
export default function IAIMantineTextInput(props: IAIMantineTextInputProps) {
9+
const { ...rest } = props;
10+
const {
11+
base50,
12+
base100,
13+
base200,
14+
base300,
15+
base800,
16+
base700,
17+
base900,
18+
accent500,
19+
accent300,
20+
} = useChakraThemeTokens();
21+
const { colorMode } = useColorMode();
22+
23+
return (
24+
<TextInput
25+
styles={() => ({
26+
input: {
27+
color: mode(base900, base100)(colorMode),
28+
backgroundColor: mode(base50, base900)(colorMode),
29+
borderColor: mode(base200, base800)(colorMode),
30+
borderWidth: 2,
31+
outline: 'none',
32+
':focus': {
33+
borderColor: mode(accent300, accent500)(colorMode),
34+
},
35+
},
36+
label: {
37+
color: mode(base700, base300)(colorMode),
38+
fontWeight: 'normal',
39+
},
40+
})}
41+
{...rest}
42+
/>
43+
);
44+
}

invokeai/frontend/web/src/common/components/IAIMantineMultiSelect.tsx

Lines changed: 5 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { Tooltip, useColorMode, useToken } from '@chakra-ui/react';
1+
import { Tooltip } from '@chakra-ui/react';
22
import { MultiSelect, MultiSelectProps } from '@mantine/core';
33
import { useAppDispatch } from 'app/store/storeHooks';
4-
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
54
import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice';
5+
import { useMantineMultiSelectStyles } from 'mantine-theme/hooks/useMantineMultiSelectStyles';
66
import { KeyboardEvent, RefObject, memo, useCallback } from 'react';
7-
import { mode } from 'theme/util/mode';
87

98
type IAIMultiSelectProps = MultiSelectProps & {
109
tooltip?: string;
@@ -14,25 +13,6 @@ type IAIMultiSelectProps = MultiSelectProps & {
1413
const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
1514
const { searchable = true, tooltip, inputRef, ...rest } = props;
1615
const dispatch = useAppDispatch();
17-
const {
18-
base50,
19-
base100,
20-
base200,
21-
base300,
22-
base400,
23-
base500,
24-
base600,
25-
base700,
26-
base800,
27-
base900,
28-
accent200,
29-
accent300,
30-
accent400,
31-
accent500,
32-
accent600,
33-
} = useChakraThemeTokens();
34-
const [boxShadow] = useToken('shadows', ['dark-lg']);
35-
const { colorMode } = useColorMode();
3616

3717
const handleKeyDown = useCallback(
3818
(e: KeyboardEvent<HTMLInputElement>) => {
@@ -52,6 +32,8 @@ const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
5232
[dispatch]
5333
);
5434

35+
const styles = useMantineMultiSelectStyles();
36+
5537
return (
5638
<Tooltip label={tooltip} placement="top" hasArrow isOpen={true}>
5739
<MultiSelect
@@ -60,92 +42,7 @@ const IAIMantineMultiSelect = (props: IAIMultiSelectProps) => {
6042
onKeyUp={handleKeyUp}
6143
searchable={searchable}
6244
maxDropdownHeight={300}
63-
styles={() => ({
64-
label: {
65-
color: mode(base700, base300)(colorMode),
66-
fontWeight: 'normal',
67-
},
68-
searchInput: {
69-
':placeholder': {
70-
color: mode(base300, base700)(colorMode),
71-
},
72-
},
73-
input: {
74-
backgroundColor: mode(base50, base900)(colorMode),
75-
borderWidth: '2px',
76-
borderColor: mode(base200, base800)(colorMode),
77-
color: mode(base900, base100)(colorMode),
78-
paddingRight: 24,
79-
fontWeight: 600,
80-
'&:hover': { borderColor: mode(base300, base600)(colorMode) },
81-
'&:focus': {
82-
borderColor: mode(accent300, accent600)(colorMode),
83-
},
84-
'&:is(:focus, :hover)': {
85-
borderColor: mode(base400, base500)(colorMode),
86-
},
87-
'&:focus-within': {
88-
borderColor: mode(accent200, accent600)(colorMode),
89-
},
90-
'&[data-disabled]': {
91-
backgroundColor: mode(base300, base700)(colorMode),
92-
color: mode(base600, base400)(colorMode),
93-
cursor: 'not-allowed',
94-
},
95-
},
96-
value: {
97-
backgroundColor: mode(base200, base800)(colorMode),
98-
color: mode(base900, base100)(colorMode),
99-
button: {
100-
color: mode(base900, base100)(colorMode),
101-
},
102-
'&:hover': {
103-
backgroundColor: mode(base300, base700)(colorMode),
104-
cursor: 'pointer',
105-
},
106-
},
107-
dropdown: {
108-
backgroundColor: mode(base200, base800)(colorMode),
109-
borderColor: mode(base200, base800)(colorMode),
110-
boxShadow,
111-
},
112-
item: {
113-
backgroundColor: mode(base200, base800)(colorMode),
114-
color: mode(base800, base200)(colorMode),
115-
padding: 6,
116-
'&[data-hovered]': {
117-
color: mode(base900, base100)(colorMode),
118-
backgroundColor: mode(base300, base700)(colorMode),
119-
},
120-
'&[data-active]': {
121-
backgroundColor: mode(base300, base700)(colorMode),
122-
'&:hover': {
123-
color: mode(base900, base100)(colorMode),
124-
backgroundColor: mode(base300, base700)(colorMode),
125-
},
126-
},
127-
'&[data-selected]': {
128-
backgroundColor: mode(accent400, accent600)(colorMode),
129-
color: mode(base50, base100)(colorMode),
130-
fontWeight: 600,
131-
'&:hover': {
132-
backgroundColor: mode(accent500, accent500)(colorMode),
133-
color: mode('white', base50)(colorMode),
134-
},
135-
},
136-
'&[data-disabled]': {
137-
color: mode(base500, base600)(colorMode),
138-
cursor: 'not-allowed',
139-
},
140-
},
141-
rightSection: {
142-
width: 24,
143-
padding: 20,
144-
button: {
145-
color: mode(base900, base100)(colorMode),
146-
},
147-
},
148-
})}
45+
styles={styles}
14946
{...rest}
15047
/>
15148
</Tooltip>

0 commit comments

Comments
 (0)