diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx index 392580e3a1..501ebe76fd 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageHeader.tsx @@ -4,13 +4,17 @@ import { createSelector } from '@reduxjs/toolkit'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useRefImageEntity } from 'features/controlLayers/components/RefImage/useRefImageEntity'; import { useRefImageIdContext } from 'features/controlLayers/contexts/RefImageIdContext'; +import { selectMainModelConfig } from 'features/controlLayers/store/paramsSlice'; import { refImageDeleted, refImageIsEnabledToggled, selectRefImageEntityIds, } from 'features/controlLayers/store/refImagesSlice'; +import { getGlobalReferenceImageWarnings } from 'features/controlLayers/store/validators'; import { memo, useCallback, useMemo } from 'react'; -import { PiCircleBold, PiCircleFill, PiTrashBold } from 'react-icons/pi'; +import { PiCircleBold, PiCircleFill, PiTrashBold, PiWarningBold } from 'react-icons/pi'; + +import { RefImageWarningTooltipContent } from './RefImageWarningTooltipContent'; const textSx: SystemStyleObject = { color: 'base.300', @@ -28,6 +32,12 @@ export const RefImageHeader = memo(() => { ); const refImageNumber = useAppSelector(selectRefImageNumber); const entity = useRefImageEntity(id); + const mainModelConfig = useAppSelector(selectMainModelConfig); + + const warnings = useMemo(() => { + return getGlobalReferenceImageWarnings(entity, mainModelConfig); + }, [entity, mainModelConfig]); + const deleteRefImage = useCallback(() => { dispatch(refImageDeleted({ id })); }, [dispatch, id]); @@ -42,6 +52,18 @@ export const RefImageHeader = memo(() => { Reference Image #{refImageNumber} + {warnings.length > 0 && ( + } + icon={} + colorScheme="warning" + /> + )} {!entity.isEnabled && ( Disabled diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx index 016384d058..01fcde269b 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImagePreview.tsx @@ -1,5 +1,5 @@ import type { SystemStyleObject } from '@invoke-ai/ui-library'; -import { Flex, Icon, IconButton, Image, Skeleton, Text } from '@invoke-ai/ui-library'; +import { Flex, Icon, IconButton, Image, Skeleton, Text, Tooltip } from '@invoke-ai/ui-library'; import { skipToken } from '@reduxjs/toolkit/query'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { round } from 'es-toolkit/compat'; @@ -17,6 +17,8 @@ import { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { PiExclamationMarkBold, PiEyeSlashBold, PiImageBold } from 'react-icons/pi'; import { useGetImageDTOQuery } from 'services/api/endpoints/images'; +import { RefImageWarningTooltipContent } from './RefImageWarningTooltipContent'; + const baseSx: SystemStyleObject = { '&[data-is-open="true"]': { borderColor: 'invokeBlue.300', @@ -51,9 +53,6 @@ const getImageSxWithWeight = (weight: number): SystemStyleObject => { return { ...baseSx, - '&[data-is-disabled="true"]': { - opacity: 0.4, - }, _after: { content: '""', position: 'absolute', @@ -95,8 +94,8 @@ export const RefImagePreview = memo(() => { }; }, [entity.config]); - const isInvalid = useMemo(() => { - return getGlobalReferenceImageWarnings(entity, mainModelConfig).length > 0; + const warnings = useMemo(() => { + return getGlobalReferenceImageWarnings(entity, mainModelConfig); }, [entity, mainModelConfig]); const onClick = useCallback(() => { @@ -126,74 +125,76 @@ export const RefImagePreview = memo(() => { ); } return ( - - 0 ? : undefined}> + } maxW="full" maxH="full" - borderRadius="base" - /> - {isIPAdapterConfig(entity.config) && ( - - - {`${round(entity.config.weight * 100, 2)}%`} - - - )} - {!entity.isEnabled && ( - 0} + data-is-disabled={!entity.isEnabled} + role="button" + onClick={onClick} + cursor="pointer" + > + } + maxW="full" + maxH="full" + borderRadius="base" /> - )} - {entity.isEnabled && isInvalid && ( - - )} - + {isIPAdapterConfig(entity.config) && ( + + + {`${round(entity.config.weight * 100, 2)}%`} + + + )} + {!entity.isEnabled && ( + + )} + {entity.isEnabled && warnings.length > 0 && ( + + )} + + ); }); RefImagePreview.displayName = 'RefImagePreview'; diff --git a/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageWarningTooltipContent.tsx b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageWarningTooltipContent.tsx new file mode 100644 index 0000000000..6c9fdffe49 --- /dev/null +++ b/invokeai/frontend/web/src/features/controlLayers/components/RefImage/RefImageWarningTooltipContent.tsx @@ -0,0 +1,18 @@ +import { Flex, ListItem, Text, UnorderedList } from '@invoke-ai/ui-library'; +import { upperFirst } from 'es-toolkit/compat'; +import { useTranslation } from 'react-i18next'; + +export const RefImageWarningTooltipContent = ({ warnings }: { warnings: string[] }) => { + const { t } = useTranslation(); + + return ( + + Invalid Reference Image: + + {warnings.map((tKey) => ( + {upperFirst(t(tKey))} + ))} + + + ); +};