3.0 Pre-Release Polish -- Bug Fixes / Style Fixes / Misc (#3812)

## What type of PR is this? (check all applicable)

- [ ] Refactor
- [x] Feature
- [x] Bug Fix
- [ ] Optimization
- [ ] Documentation Update


## Have you discussed this change with the InvokeAI team?
- [x] Yes
- [ ] No, because:

      
## Description

Making some final style fixes before we push the next 3.0 version
tomorrow.

- Fixed light mode colors in Settings Modal.
- Double checked other light mode colors. Nothing seems off.
- Added Base Model badge to the model list item. Makes it visually
better and also serves as a quick glance feature for the user.
- Some minor styling updates to the Node Editor.
- Fixed hotkeys 'G' and 'O', 'Shift+G' and 'Shift+O' used to toggle the
panels not resizing canvas. #3780
- Fixed hotkey 'N' not working for Snap To Grid on Canvas.
- Fixed brush opacity hotkeys not working.
- Cleaned up hotkeys modal of hotkeys that are no longer used.
- Updated compel requirement to `2.0.0`


## Related Tickets & Documents

<!--
For pull requests that relate or close an issue, please include them
below. 

For example having the text: "closes #1234" would connect the current
pull
request to issue 1234.  And when we merge the pull request, Github will
automatically close the issue.
-->

- Related Issue #
- Closes #3780

## QA Instructions, Screenshots, Recordings

<!-- 
Please provide steps on how to test changes, any hardware or 
software specifications as well as any other pertinent information. 
-->

## Added/updated tests?

- [ ] Yes
- [x] No : _please replace this line with details on why tests
      have not been included_

## [optional] Are there any post deployment tasks we need to perform?
This commit is contained in:
blessedcoolant 2023-07-19 00:04:57 +12:00 committed by GitHub
commit 68f2fb2601
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 135 additions and 77 deletions

View File

@ -1,7 +1,9 @@
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { RootState } from 'app/store/store'; import { RootState } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale';
import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { import {
setActiveTab, setActiveTab,
toggleGalleryPanel, toggleGalleryPanel,
@ -14,10 +16,11 @@ import React, { memo } from 'react';
import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook'; import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook';
const globalHotkeysSelector = createSelector( const globalHotkeysSelector = createSelector(
(state: RootState) => state.hotkeys, [(state: RootState) => state.hotkeys, (state: RootState) => state.ui],
(hotkeys) => { (hotkeys, ui) => {
const { shift } = hotkeys; const { shift } = hotkeys;
return { shift }; const { shouldPinParametersPanel, shouldPinGallery } = ui;
return { shift, shouldPinGallery, shouldPinParametersPanel };
}, },
{ {
memoizeOptions: { memoizeOptions: {
@ -34,7 +37,10 @@ const globalHotkeysSelector = createSelector(
*/ */
const GlobalHotkeys: React.FC = () => { const GlobalHotkeys: React.FC = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { shift } = useAppSelector(globalHotkeysSelector); const { shift, shouldPinParametersPanel, shouldPinGallery } = useAppSelector(
globalHotkeysSelector
);
const activeTabName = useAppSelector(activeTabNameSelector);
useHotkeys( useHotkeys(
'*', '*',
@ -51,18 +57,30 @@ const GlobalHotkeys: React.FC = () => {
useHotkeys('o', () => { useHotkeys('o', () => {
dispatch(toggleParametersPanel()); dispatch(toggleParametersPanel());
if (activeTabName === 'unifiedCanvas' && shouldPinParametersPanel) {
dispatch(requestCanvasRescale());
}
}); });
useHotkeys(['shift+o'], () => { useHotkeys(['shift+o'], () => {
dispatch(togglePinParametersPanel()); dispatch(togglePinParametersPanel());
if (activeTabName === 'unifiedCanvas') {
dispatch(requestCanvasRescale());
}
}); });
useHotkeys('g', () => { useHotkeys('g', () => {
dispatch(toggleGalleryPanel()); dispatch(toggleGalleryPanel());
if (activeTabName === 'unifiedCanvas' && shouldPinGallery) {
dispatch(requestCanvasRescale());
}
}); });
useHotkeys(['shift+g'], () => { useHotkeys(['shift+g'], () => {
dispatch(togglePinGalleryPanel()); dispatch(togglePinGalleryPanel());
if (activeTabName === 'unifiedCanvas') {
dispatch(requestCanvasRescale());
}
}); });
useHotkeys('1', () => { useHotkeys('1', () => {

View File

@ -11,6 +11,7 @@ import {
setIsMouseOverBoundingBox, setIsMouseOverBoundingBox,
setIsMovingBoundingBox, setIsMovingBoundingBox,
setIsTransformingBoundingBox, setIsTransformingBoundingBox,
setShouldSnapToGrid,
} from 'features/canvas/store/canvasSlice'; } from 'features/canvas/store/canvasSlice';
import { uiSelector } from 'features/ui/store/uiSelectors'; import { uiSelector } from 'features/ui/store/uiSelectors';
import Konva from 'konva'; import Konva from 'konva';
@ -20,6 +21,7 @@ import { Vector2d } from 'konva/lib/types';
import { isEqual } from 'lodash-es'; import { isEqual } from 'lodash-es';
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { Group, Rect, Transformer } from 'react-konva'; import { Group, Rect, Transformer } from 'react-konva';
const boundingBoxPreviewSelector = createSelector( const boundingBoxPreviewSelector = createSelector(
@ -91,6 +93,10 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
const scaledStep = 64 * stageScale; const scaledStep = 64 * stageScale;
useHotkeys('N', () => {
dispatch(setShouldSnapToGrid(!shouldSnapToGrid));
});
const handleOnDragMove = useCallback( const handleOnDragMove = useCallback(
(e: KonvaEventObject<DragEvent>) => { (e: KonvaEventObject<DragEvent>) => {
if (!shouldSnapToGrid) { if (!shouldSnapToGrid) {

View File

@ -139,7 +139,7 @@ const IAICanvasToolChooserOptions = () => {
); );
useHotkeys( useHotkeys(
['shift+BracketLeft'], ['Shift+BracketLeft'],
() => { () => {
dispatch( dispatch(
setBrushColor({ setBrushColor({
@ -156,7 +156,7 @@ const IAICanvasToolChooserOptions = () => {
); );
useHotkeys( useHotkeys(
['shift+BracketRight'], ['Shift+BracketRight'],
() => { () => {
dispatch( dispatch(
setBrushColor({ setBrushColor({

View File

@ -110,8 +110,11 @@ const SelectItem = forwardRef<HTMLDivElement, ItemProps>(
return ( return (
<div ref={ref} {...others}> <div ref={ref} {...others}>
<div> <div>
<Text>{label}</Text> <Text fontWeight={600}>{label}</Text>
<Text size="xs" color="base.600"> <Text
size="xs"
sx={{ color: 'base.600', _dark: { color: 'base.500' } }}
>
{description} {description}
</Text> </Text>
</div> </div>

View File

@ -20,8 +20,8 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => {
justifyContent: 'space-between', justifyContent: 'space-between',
px: 2, px: 2,
py: 1, py: 1,
bg: 'base.300', bg: 'base.100',
_dark: { bg: 'base.700' }, _dark: { bg: 'base.900' },
}} }}
> >
<Tooltip label={nodeId}> <Tooltip label={nodeId}>
@ -30,7 +30,7 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => {
sx={{ sx={{
fontWeight: 600, fontWeight: 600,
color: 'base.900', color: 'base.900',
_dark: { color: 'base.100' }, _dark: { color: 'base.200' },
}} }}
> >
{title} {title}

View File

@ -59,7 +59,7 @@ export const InvocationComponent = memo((props: NodeProps<InvocationValue>) => {
flexDirection: 'column', flexDirection: 'column',
borderBottomRadius: 'md', borderBottomRadius: 'md',
py: 2, py: 2,
bg: 'base.200', bg: 'base.150',
_dark: { bg: 'base.800' }, _dark: { bg: 'base.800' },
}} }}
> >

View File

@ -1,9 +1,9 @@
import 'reactflow/dist/style.css';
import { Box } from '@chakra-ui/react'; import { Box } from '@chakra-ui/react';
import { ReactFlowProvider } from 'reactflow'; import { ReactFlowProvider } from 'reactflow';
import 'reactflow/dist/style.css';
import { Flow } from './Flow';
import { memo } from 'react'; import { memo } from 'react';
import { Flow } from './Flow';
const NodeEditor = () => { const NodeEditor = () => {
return ( return (

View File

@ -1,9 +1,9 @@
import { Box, useToken } from '@chakra-ui/react'; import { Box, useToken } from '@chakra-ui/react';
import { NODE_MIN_WIDTH } from 'app/constants'; import { NODE_MIN_WIDTH } from 'app/constants';
import { useAppSelector } from 'app/store/storeHooks';
import { PropsWithChildren } from 'react'; import { PropsWithChildren } from 'react';
import { DRAG_HANDLE_CLASSNAME } from '../hooks/useBuildInvocation'; import { DRAG_HANDLE_CLASSNAME } from '../hooks/useBuildInvocation';
import { useAppSelector } from 'app/store/storeHooks';
type NodeWrapperProps = PropsWithChildren & { type NodeWrapperProps = PropsWithChildren & {
selected: boolean; selected: boolean;

View File

@ -15,7 +15,7 @@ import {
ModalOverlay, ModalOverlay,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { cloneElement, ReactElement } from 'react'; import { ReactElement, cloneElement } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import HotkeysModalItem from './HotkeysModalItem'; import HotkeysModalItem from './HotkeysModalItem';
@ -65,11 +65,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: t('hotkeys.pinOptions.desc'), desc: t('hotkeys.pinOptions.desc'),
hotkey: 'Shift+O', hotkey: 'Shift+O',
}, },
{
title: t('hotkeys.toggleViewer.title'),
desc: t('hotkeys.toggleViewer.desc'),
hotkey: 'Z',
},
{ {
title: t('hotkeys.toggleGallery.title'), title: t('hotkeys.toggleGallery.title'),
desc: t('hotkeys.toggleGallery.desc'), desc: t('hotkeys.toggleGallery.desc'),
@ -85,12 +80,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: t('hotkeys.changeTabs.desc'), desc: t('hotkeys.changeTabs.desc'),
hotkey: '1-5', hotkey: '1-5',
}, },
{
title: t('hotkeys.consoleToggle.title'),
desc: t('hotkeys.consoleToggle.desc'),
hotkey: '`',
},
]; ];
const generalHotkeys = [ const generalHotkeys = [
@ -109,11 +98,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
desc: t('hotkeys.setParameters.desc'), desc: t('hotkeys.setParameters.desc'),
hotkey: 'A', hotkey: 'A',
}, },
{
title: t('hotkeys.restoreFaces.title'),
desc: t('hotkeys.restoreFaces.desc'),
hotkey: 'Shift+R',
},
{ {
title: t('hotkeys.upscale.title'), title: t('hotkeys.upscale.title'),
desc: t('hotkeys.upscale.desc'), desc: t('hotkeys.upscale.desc'),

View File

@ -183,7 +183,7 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => {
> >
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<ModalHeader>{t('common.settingsLabel')}</ModalHeader> <ModalHeader bg="none">{t('common.settingsLabel')}</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody> <ModalBody>
<Flex sx={{ gap: 4, flexDirection: 'column' }}> <Flex sx={{ gap: 4, flexDirection: 'column' }}>
@ -331,12 +331,15 @@ export default SettingsModal;
const StyledFlex = (props: PropsWithChildren) => { const StyledFlex = (props: PropsWithChildren) => {
return ( return (
<Flex <Flex
layerStyle="second"
sx={{ sx={{
flexDirection: 'column', flexDirection: 'column',
gap: 2, gap: 2,
p: 4, p: 4,
borderRadius: 'base', borderRadius: 'base',
bg: 'base.100',
_dark: {
bg: 'base.900',
},
}} }}
> >
{props.children} {props.children}

View File

@ -3,7 +3,7 @@ import { EntityState } from '@reduxjs/toolkit';
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 { forEach } from 'lodash-es'; import { forEach } from 'lodash-es';
import type { ChangeEvent } from 'react'; import type { ChangeEvent, PropsWithChildren } from 'react';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { import {
@ -44,13 +44,7 @@ const ModelList = (props: ModelListProps) => {
return ( return (
<Flex flexDirection="column" rowGap={4} width="50%" minWidth="50%"> <Flex flexDirection="column" rowGap={4} width="50%" minWidth="50%">
<Flex <Flex flexDirection="column" gap={4} paddingInlineEnd={4}>
flexDirection="column"
gap={4}
maxHeight={window.innerHeight - 240}
overflow="scroll"
paddingInlineEnd={4}
>
<ButtonGroup isAttached> <ButtonGroup isAttached>
<IAIButton <IAIButton
onClick={() => setModelFormatFilter('all')} onClick={() => setModelFormatFilter('all')}
@ -83,6 +77,7 @@ const ModelList = (props: ModelListProps) => {
{['all', 'diffusers'].includes(modelFormatFilter) && {['all', 'diffusers'].includes(modelFormatFilter) &&
filteredDiffusersModels.length > 0 && ( filteredDiffusersModels.length > 0 && (
<StyledModelContainer>
<Flex sx={{ gap: 2, flexDir: 'column' }}> <Flex sx={{ gap: 2, flexDir: 'column' }}>
<Text variant="subtext" fontSize="sm"> <Text variant="subtext" fontSize="sm">
Diffusers Diffusers
@ -96,9 +91,11 @@ const ModelList = (props: ModelListProps) => {
/> />
))} ))}
</Flex> </Flex>
</StyledModelContainer>
)} )}
{['all', 'checkpoint'].includes(modelFormatFilter) && {['all', 'checkpoint'].includes(modelFormatFilter) &&
filteredCheckpointModels.length > 0 && ( filteredCheckpointModels.length > 0 && (
<StyledModelContainer>
<Flex sx={{ gap: 2, flexDir: 'column' }}> <Flex sx={{ gap: 2, flexDir: 'column' }}>
<Text variant="subtext" fontSize="sm"> <Text variant="subtext" fontSize="sm">
Checkpoint Checkpoint
@ -112,6 +109,7 @@ const ModelList = (props: ModelListProps) => {
/> />
))} ))}
</Flex> </Flex>
</StyledModelContainer>
)} )}
</Flex> </Flex>
</Flex> </Flex>
@ -143,3 +141,24 @@ const modelsFilter = (
}); });
return filteredModels; return filteredModels;
}; };
const StyledModelContainer = (props: PropsWithChildren) => {
return (
<Flex
flexDirection="column"
maxHeight={window.innerHeight - 280}
overflow="scroll"
gap={4}
borderRadius={4}
p={4}
sx={{
bg: 'base.200',
_dark: {
bg: 'base.800',
},
}}
>
{props.children}
</Flex>
);
};

View File

@ -1,5 +1,5 @@
import { DeleteIcon } from '@chakra-ui/icons'; import { DeleteIcon } from '@chakra-ui/icons';
import { Flex, Text, Tooltip } from '@chakra-ui/react'; import { Badge, Flex, Text, Tooltip } from '@chakra-ui/react';
import { makeToast } from 'app/components/Toaster'; import { makeToast } from 'app/components/Toaster';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import IAIAlertDialog from 'common/components/IAIAlertDialog'; import IAIAlertDialog from 'common/components/IAIAlertDialog';
@ -20,6 +20,13 @@ type ModelListItemProps = {
setSelectedModelId: (v: string | undefined) => void; setSelectedModelId: (v: string | undefined) => void;
}; };
const modelBaseTypeMap = {
'sd-1': 'SD1',
'sd-2': 'SD2',
sdxl: 'SDXL',
'sdxl-refiner': 'SDXLR',
};
export default function ModelListItem(props: ModelListItemProps) { export default function ModelListItem(props: ModelListItemProps) {
const isBusy = useAppSelector(selectIsBusy); const isBusy = useAppSelector(selectIsBusy);
const { t } = useTranslation(); const { t } = useTranslation();
@ -76,7 +83,7 @@ export default function ModelListItem(props: ModelListItemProps) {
bg: isSelected ? 'accent.400' : 'base.100', bg: isSelected ? 'accent.400' : 'base.100',
color: isSelected ? 'base.50' : 'base.800', color: isSelected ? 'base.50' : 'base.800',
_hover: { _hover: {
bg: isSelected ? 'accent.500' : 'base.200', bg: isSelected ? 'accent.500' : 'base.300',
color: isSelected ? 'base.50' : 'base.800', color: isSelected ? 'base.50' : 'base.800',
}, },
_dark: { _dark: {
@ -84,16 +91,34 @@ export default function ModelListItem(props: ModelListItemProps) {
bg: isSelected ? 'accent.600' : 'base.850', bg: isSelected ? 'accent.600' : 'base.850',
_hover: { _hover: {
color: isSelected ? 'base.50' : 'base.100', color: isSelected ? 'base.50' : 'base.100',
bg: isSelected ? 'accent.550' : 'base.800', bg: isSelected ? 'accent.550' : 'base.700',
}, },
}, },
}} }}
onClick={handleSelectModel} onClick={handleSelectModel}
> >
<Flex gap={4} alignItems="center">
<Badge
minWidth={14}
p={1}
fontSize="sm"
sx={{
bg: 'base.350',
color: 'base.900',
_dark: { bg: 'base.500' },
}}
>
{
modelBaseTypeMap[
model.base_model as keyof typeof modelBaseTypeMap
]
}
</Badge>
<Tooltip label={model.description} hasArrow placement="bottom"> <Tooltip label={model.description} hasArrow placement="bottom">
<Text sx={{ fontWeight: 500 }}>{model.model_name}</Text> <Text sx={{ fontWeight: 500 }}>{model.model_name}</Text>
</Tooltip> </Tooltip>
</Flex> </Flex>
</Flex>
<IAIAlertDialog <IAIAlertDialog
title={t('modelManager.deleteModel')} title={t('modelManager.deleteModel')}
acceptCallback={handleModelDelete} acceptCallback={handleModelDelete}

View File

@ -13,13 +13,13 @@ import { popoverTheme } from './components/popover';
import { progressTheme } from './components/progress'; import { progressTheme } from './components/progress';
import { no_scrollbar } from './components/scrollbar'; import { no_scrollbar } from './components/scrollbar';
import { selectTheme } from './components/select'; import { selectTheme } from './components/select';
import { skeletonTheme } from './components/skeleton';
import { sliderTheme } from './components/slider'; import { sliderTheme } from './components/slider';
import { switchTheme } from './components/switch'; import { switchTheme } from './components/switch';
import { tabsTheme } from './components/tabs'; import { tabsTheme } from './components/tabs';
import { textTheme } from './components/text'; import { textTheme } from './components/text';
import { textareaTheme } from './components/textarea'; import { textareaTheme } from './components/textarea';
import { tooltipTheme } from './components/tooltip'; import { tooltipTheme } from './components/tooltip';
import { skeletonTheme } from './components/skeleton';
export const theme: ThemeOverride = { export const theme: ThemeOverride = {
config: { config: {
@ -74,7 +74,7 @@ export const theme: ThemeOverride = {
'0px 0px 0px 1px var(--invokeai-colors-base-150), 0px 0px 0px 4px var(--invokeai-colors-accent-400)', '0px 0px 0px 1px var(--invokeai-colors-base-150), 0px 0px 0px 4px var(--invokeai-colors-accent-400)',
dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 4px var(--invokeai-colors-accent-400)', dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 4px var(--invokeai-colors-accent-400)',
}, },
nodeSelectedOutline: `0 0 0 2px var(--invokeai-colors-base-500)`, nodeSelectedOutline: `0 0 0 2px var(--invokeai-colors-accent-450)`,
}, },
colors: InvokeAIColors, colors: InvokeAIColors,
components: { components: {

View File

@ -38,7 +38,7 @@ dependencies = [
"albumentations", "albumentations",
"click", "click",
"clip_anytorch", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip", "clip_anytorch", # replacing "clip @ https://github.com/openai/CLIP/archive/eaa22acb90a5876642d0507623e859909230a52d.zip",
"compel==2.0.0rc2", "compel==2.0.0",
"controlnet-aux>=0.0.6", "controlnet-aux>=0.0.6",
"timm==0.6.13", # needed to override timm latest in controlnet_aux, see https://github.com/isl-org/ZoeDepth/issues/26 "timm==0.6.13", # needed to override timm latest in controlnet_aux, see https://github.com/isl-org/ZoeDepth/issues/26
"datasets", "datasets",