diff --git a/invokeai/frontend/web/src/common/components/IAICustomSelect.tsx b/invokeai/frontend/web/src/common/components/IAICustomSelect.tsx index 6d6cdbadf5..5047a24c63 100644 --- a/invokeai/frontend/web/src/common/components/IAICustomSelect.tsx +++ b/invokeai/frontend/web/src/common/components/IAICustomSelect.tsx @@ -104,7 +104,8 @@ const IAICustomSelect = (props: IAICustomSelectProps) => { ref={refs.setFloating} sx={{ ...floatingStyles, - width: 'max-content', + width: 'full', + // width: 'max-content', top: 0, left: 0, flexDirection: 'column', @@ -118,6 +119,7 @@ const IAICustomSelect = (props: IAICustomSelectProps) => { px: 0, h: 'fit-content', maxH: 64, + minW: 48, }} > diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx index e2cf3d17bd..f46c1fea4b 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNet.tsx @@ -3,8 +3,10 @@ import { ControlNetProcessorNode } from '../store/types'; import { ImageDTO } from 'services/api'; import CannyProcessor from './processors/CannyProcessor'; import { + CONTROLNET_PROCESSORS, ControlNet, ControlNetModel, + ControlNetProcessor, controlNetBeginStepPctChanged, controlNetEndStepPctChanged, controlNetImageChanged, @@ -23,7 +25,18 @@ import ParamControlNetModel from './parameters/ParamControlNetModel'; import ParamControlNetWeight from './parameters/ParamControlNetWeight'; import ParamControlNetBeginStepPct from './parameters/ParamControlNetBeginStepPct'; import ParamControlNetEndStepPct from './parameters/ParamControlNetEndStepPct'; -import { Flex, HStack, VStack } from '@chakra-ui/react'; +import { + Box, + Flex, + HStack, + Tab, + TabList, + TabPanel, + TabPanels, + Tabs, + VStack, + useDisclosure, +} from '@chakra-ui/react'; import IAISelectableImage from './parameters/IAISelectableImage'; import IAIButton from 'common/components/IAIButton'; import IAIIconButton from 'common/components/IAIIconButton'; @@ -31,6 +44,7 @@ import IAISwitch from 'common/components/IAISwitch'; import ParamControlNetIsPreprocessed from './parameters/ParamControlNetIsPreprocessed'; import IAICollapse from 'common/components/IAICollapse'; import ControlNetProcessorCollapse from './ControlNetProcessorCollapse'; +import IAICustomSelect from 'common/components/IAICustomSelect'; type ControlNetProps = { controlNet: ControlNet; @@ -50,9 +64,14 @@ const ControlNet = (props: ControlNetProps) => { } = props.controlNet; const dispatch = useAppDispatch(); - const [processorType, setProcessorType] = useState< - ControlNetProcessorNode['type'] - >('canny_image_processor'); + const [processorType, setProcessorType] = + useState('canny'); + + const handleProcessorTypeChanged = (type: string | null | undefined) => { + setProcessorType(type as ControlNetProcessor); + }; + + const { isOpen, onToggle } = useDisclosure(); const handleControlImageChanged = useCallback( (controlImage: ImageDTO) => { @@ -82,34 +101,82 @@ const ControlNet = (props: ControlNetProps) => { ); return ( - - Remove ControlNet + - - - - - + + + + Model Config + + + Preprocess + + + + + + + + + + + + + + + Remove ControlNet ); }; export default memo(ControlNet); + +export type ControlNetProcessorProps = { + controlNetId: string; + controlImage: ImageDTO | null; + processedControlImage: ImageDTO | null; + type: ControlNetProcessor; +}; + +const ProcessorComponent = (props: ControlNetProcessorProps) => { + const { type } = props; + if (type === 'canny') { + return ; + } + return null; +}; diff --git a/invokeai/frontend/web/src/features/controlNet/components/ControlNetProcessorCollapse.tsx b/invokeai/frontend/web/src/features/controlNet/components/ControlNetProcessorCollapse.tsx index 2023402af3..0ce675f4ed 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/ControlNetProcessorCollapse.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/ControlNetProcessorCollapse.tsx @@ -1,67 +1,76 @@ -import { useDisclosure } from '@chakra-ui/react'; -import IAICollapse from 'common/components/IAICollapse'; -import { memo, useState } from 'react'; -import CannyProcessor from './processors/CannyProcessor'; -import { ImageDTO } from 'services/api'; -import IAICustomSelect from 'common/components/IAICustomSelect'; -import { - CONTROLNET_PROCESSORS, - ControlNetProcessor, -} from '../store/controlNetSlice'; +// import { Collapse, Flex, useDisclosure } from '@chakra-ui/react'; +// import { memo, useState } from 'react'; +// import CannyProcessor from './processors/CannyProcessor'; +// import { ImageDTO } from 'services/api'; +// import IAICustomSelect from 'common/components/IAICustomSelect'; +// import { +// CONTROLNET_PROCESSORS, +// ControlNetProcessor, +// } from '../store/controlNetSlice'; +// import IAISwitch from 'common/components/IAISwitch'; -export type ControlNetProcessorProps = { - controlNetId: string; - image: ImageDTO; - type: ControlNetProcessor; -}; +// export type ControlNetProcessorProps = { +// controlNetId: string; +// controlImage: ImageDTO | null; +// processedControlImage: ImageDTO | null; +// type: ControlNetProcessor; +// }; -const ProcessorComponent = (props: ControlNetProcessorProps) => { - const { type } = props; - if (type === 'canny') { - return ; - } - return null; -}; +// const ProcessorComponent = (props: ControlNetProcessorProps) => { +// const { type } = props; +// if (type === 'canny') { +// return ; +// } +// return null; +// }; -type ControlNetProcessorCollapseProps = { - controlNetId: string; - image: ImageDTO | null; -}; +// type ControlNetProcessorCollapseProps = { +// isOpen: boolean; +// controlNetId: string; +// controlImage: ImageDTO | null; +// processedControlImage: ImageDTO | null; +// }; +// const ControlNetProcessorCollapse = ( +// props: ControlNetProcessorCollapseProps +// ) => { +// const { isOpen, controlImage, controlNetId, processedControlImage } = props; -const ControlNetProcessorCollapse = ( - props: ControlNetProcessorCollapseProps -) => { - const { image, controlNetId } = props; - const { isOpen, onToggle } = useDisclosure(); +// const [processorType, setProcessorType] = +// useState('canny'); - const [processorType, setProcessorType] = - useState('canny'); +// const handleProcessorTypeChanged = (type: string | null | undefined) => { +// setProcessorType(type as ControlNetProcessor); +// }; - const handleProcessorTypeChanged = (type: string | null | undefined) => { - setProcessorType(type as ControlNetProcessor); - }; +// return ( +// +// +// {controlImage && ( +// +// )} +// +// ); +// }; - return ( - - - {image && ( - - )} - - ); -}; +// export default memo(ControlNetProcessorCollapse); -export default memo(ControlNetProcessorCollapse); +export default {}; diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/IAISelectableImage.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/IAISelectableImage.tsx index 635c192db1..1f8fc89c33 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/parameters/IAISelectableImage.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/IAISelectableImage.tsx @@ -64,6 +64,7 @@ const IAISelectableImage = (props: IAISelectableImageProps) => { fallbackStrategy="beforeLoadOrError" fallback={} onError={onError} + draggable={false} sx={{ borderRadius: 'base', }} @@ -80,6 +81,7 @@ const IAISelectableImage = (props: IAISelectableImageProps) => { > } onClick={onReset} diff --git a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetIsEnabled.tsx b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetIsEnabled.tsx index f29b9396b4..f42265cb22 100644 --- a/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetIsEnabled.tsx +++ b/invokeai/frontend/web/src/features/controlNet/components/parameters/ParamControlNetIsEnabled.tsx @@ -1,5 +1,5 @@ import { useAppDispatch } from 'app/store/storeHooks'; -import IAIFullCheckbox from 'common/components/IAIFullCheckbox'; +import IAISwitch from 'common/components/IAISwitch'; import { controlNetToggled } from 'features/controlNet/store/controlNetSlice'; import { memo, useCallback } from 'react'; @@ -17,7 +17,7 @@ const ParamControlNetIsEnabled = (props: ParamControlNetIsEnabledProps) => { }, [dispatch, controlNetId]); return ( - { return ( { - const { controlNetId, image, type } = props; + const { controlNetId, controlImage, processedControlImage, type } = props; const dispatch = useAppDispatch(); const [lowThreshold, setLowThreshold] = useState(100); const [highThreshold, setHighThreshold] = useState(200); const handleProcess = useCallback(() => { - if (!image) { + if (!controlImage) { return; } @@ -28,15 +27,15 @@ const CannyProcessor = (props: ControlNetProcessorProps) => { id: CANNY_PROCESSOR, type: 'canny_image_processor', image: { - image_name: image.image_name, - image_origin: image.image_origin, + image_name: controlImage.image_name, + image_origin: controlImage.image_origin, }, low_threshold: lowThreshold, high_threshold: highThreshold, }, }) ); - }, [controlNetId, dispatch, highThreshold, image, lowThreshold]); + }, [controlNetId, dispatch, highThreshold, controlImage, lowThreshold]); const handleReset = useCallback(() => { dispatch( @@ -65,10 +64,12 @@ const CannyProcessor = (props: ControlNetProcessorProps) => { max={255} withInput /> - - - - + ); }; diff --git a/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetProcessButton.tsx b/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetProcessButton.tsx deleted file mode 100644 index 2fb6d60e55..0000000000 --- a/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetProcessButton.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import IAIButton from 'common/components/IAIButton'; -import { memo } from 'react'; - -type ControlNetProcessButtonProps = { - onClick: () => void; -}; - -const ControlNetProcessButton = (props: ControlNetProcessButtonProps) => { - const { onClick } = props; - return Process Control Image; -}; - -export default memo(ControlNetProcessButton); diff --git a/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetProcessorButtons.tsx b/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetProcessorButtons.tsx new file mode 100644 index 0000000000..afa94d6ada --- /dev/null +++ b/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetProcessorButtons.tsx @@ -0,0 +1,44 @@ +import { Flex } from '@chakra-ui/react'; +import { memo } from 'react'; +import { FaUndo } from 'react-icons/fa'; +import IAIButton from 'common/components/IAIButton'; + +type ControlNetProcessorButtonsProps = { + handleProcess: () => void; + isProcessDisabled: boolean; + handleReset: () => void; + isResetDisabled: boolean; +}; + +const ControlNetProcessorButtons = (props: ControlNetProcessorButtonsProps) => { + const { handleProcess, isProcessDisabled, handleReset, isResetDisabled } = + props; + return ( + + + Preprocess + + } + onClick={handleReset} + isDisabled={isResetDisabled} + > + Reset Processing + + + ); +}; + +export default memo(ControlNetProcessorButtons); diff --git a/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetResetProcessedImageButton.tsx b/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetResetProcessedImageButton.tsx deleted file mode 100644 index 11a4f66ac1..0000000000 --- a/invokeai/frontend/web/src/features/controlNet/components/processors/common/ControlNetResetProcessedImageButton.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import IAIButton from 'common/components/IAIButton'; -import { memo } from 'react'; -import { FaUnderline, FaUndo } from 'react-icons/fa'; - -type ControlNetResetProcessedImageButtonProps = { - onClick: () => void; -}; - -const ControlNetResetProcessedImageButton = ( - props: ControlNetResetProcessedImageButtonProps -) => { - const { onClick } = props; - return ( - } onClick={onClick}> - Reset Processing - - ); -}; - -export default memo(ControlNetResetProcessedImageButton); diff --git a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts index ab62646c0f..8e5ecf64fa 100644 --- a/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts +++ b/invokeai/frontend/web/src/features/gallery/store/gallerySlice.ts @@ -50,7 +50,10 @@ export const gallerySlice = createSlice({ }, extraReducers: (builder) => { builder.addCase(imageUpserted, (state, action) => { - if (state.shouldAutoSwitchToNewImages) { + if ( + state.shouldAutoSwitchToNewImages && + action.payload.image_category === 'general' + ) { state.selectedImage = action.payload; } }); diff --git a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildTextToImageGraph.ts b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildTextToImageGraph.ts index 753ccccff8..65c205f9a4 100644 --- a/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildTextToImageGraph.ts +++ b/invokeai/frontend/web/src/features/nodes/util/graphBuilders/buildTextToImageGraph.ts @@ -19,6 +19,7 @@ const NOISE = 'noise'; const RANDOM_INT = 'rand_int'; const RANGE_OF_SIZE = 'range_of_size'; const ITERATE = 'iterate'; +const CONTROL_NET = 'control_net'; /** * Builds the Text to Image tab graph. diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx index 52ea702c4c..a3f91fd432 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/ControlNet/ParamControlNetCollapse.tsx @@ -1,4 +1,12 @@ -import { Flex, useDisclosure } from '@chakra-ui/react'; +import { + Flex, + Spacer, + Tab, + TabList, + TabPanel, + TabPanels, + Tabs, +} from '@chakra-ui/react'; import { useTranslation } from 'react-i18next'; import IAICollapse from 'common/components/IAICollapse'; import { memo, useCallback } from 'react'; @@ -13,22 +21,23 @@ import { isControlNetEnabledToggled, } from 'features/controlNet/store/controlNetSlice'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; -import { map } from 'lodash-es'; +import { map, startCase } from 'lodash-es'; import { v4 as uuidv4 } from 'uuid'; +import { CloseIcon } from '@chakra-ui/icons'; const selector = createSelector( controlNetSelector, (controlNet) => { const { controlNets, isEnabled } = controlNet; - return { controlNets, isEnabled }; + return { controlNetsArray: map(controlNets), isEnabled }; }, defaultSelectorOptions ); const ParamControlNetCollapse = () => { const { t } = useTranslation(); - const { controlNets, isEnabled } = useAppSelector(selector); + const { controlNetsArray, isEnabled } = useAppSelector(selector); const dispatch = useAppDispatch(); const handleClickControlNetToggle = useCallback(() => { @@ -46,17 +55,35 @@ const ParamControlNetCollapse = () => { onToggle={handleClickControlNetToggle} withSwitch > - - } - /> - - {map(controlNets, (c) => ( - - ))} + + + {controlNetsArray.map((c, i) => ( + + {i + 1} + + ))} + } + /> + + + {controlNetsArray.map((c) => ( + + + + ))} + + ); }; diff --git a/invokeai/frontend/web/src/theme/components/tabs.ts b/invokeai/frontend/web/src/theme/components/tabs.ts index 5eb1a36013..daf6e18cab 100644 --- a/invokeai/frontend/web/src/theme/components/tabs.ts +++ b/invokeai/frontend/web/src/theme/components/tabs.ts @@ -26,6 +26,7 @@ const invokeAITablist = defineStyle((_props) => ({ padding: 2, borderRadius: 'base', _selected: { + borderBottomColor: 'base.800', bg: 'accent.700', color: 'accent.100', _hover: {