diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index b2d873d6d5..57b69199df 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -86,6 +86,7 @@ "back": "Back", "batch": "Batch Manager", "cancel": "Cancel", + "copy": "Copy", "copyError": "$t(gallery.copy) Error", "close": "Close", "on": "On", diff --git a/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx b/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx index 932af0298e..d333b64ebf 100644 --- a/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/AboutModal/AboutModal.tsx @@ -4,6 +4,7 @@ import { Grid, GridItem, Heading, + IconButton, Image, Modal, ModalBody, @@ -12,7 +13,9 @@ import { ModalFooter, ModalHeader, ModalOverlay, + Spacer, Text, + Tooltip, useDisclosure, } from '@invoke-ai/ui-library'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; @@ -20,8 +23,9 @@ import { discordLink, githubLink, websiteLink } from 'features/system/store/cons import { map } from 'lodash-es'; import InvokeLogoYellow from 'public/assets/images/invoke-tag-lrg.svg'; import type { ReactElement } from 'react'; -import { cloneElement, memo } from 'react'; +import { cloneElement, memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; +import { PiCopyBold } from 'react-icons/pi'; import { useGetAppDepsQuery, useGetAppVersionQuery } from 'services/api/endpoints/appInfo'; type AboutModalProps = { @@ -32,13 +36,18 @@ type AboutModalProps = { const AboutModal = ({ children }: AboutModalProps) => { const { isOpen, onOpen, onClose } = useDisclosure(); const { t } = useTranslation(); - const { deps } = useGetAppDepsQuery(undefined, { + const { depsArray, depsObject } = useGetAppDepsQuery(undefined, { selectFromResult: ({ data }) => ({ - deps: data ? map(data, (version, name) => ({ name, version })) : [], + depsObject: data, + depsArray: data ? map(data, (version, name) => ({ name, version })) : [], }), }); const { data: appVersion } = useGetAppVersionQuery(); + const handleCopy = useCallback(() => { + navigator.clipboard.writeText(JSON.stringify(depsObject, null, 2)); + }, [depsObject]); + return ( <> {cloneElement(children, { @@ -46,17 +55,27 @@ const AboutModal = ({ children }: AboutModalProps) => { })} - + {t('accessibility.about')} - - {t('common.localSystem')} - - {deps.map(({ name, version }, i) => ( + + {t('common.localSystem')} + + + } + variant="ghost" + /> + + + {depsArray.map(({ name, version }, i) => ( {name} {version ? version : t('common.notInstalled')}