import { Flex, MenuItem, Spinner } from '@chakra-ui/react'; import { useStore } from '@nanostores/react'; import { useAppToaster } from 'app/components/Toaster'; import { $customStarUI } from 'app/store/nanostores/customStarUI'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { setInitialCanvasImage } from 'features/canvas/store/canvasSlice'; import { imagesToChangeSelected, isModalOpenChanged, } from 'features/changeBoardModal/store/slice'; import { imagesToDeleteSelected } from 'features/deleteImageModal/store/slice'; import { workflowLoadRequested } from 'features/nodes/store/actions'; import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters'; import { initialImageSelected } from 'features/parameters/store/actions'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboard'; import { setActiveTab } from 'features/ui/store/uiSlice'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { FaAsterisk, FaCopy, FaDownload, FaExternalLinkAlt, FaFolder, FaQuoteRight, FaSeedling, FaShare, FaTrash, } from 'react-icons/fa'; import { MdDeviceHub, MdStar, MdStarBorder } from 'react-icons/md'; import { useGetImageMetadataFromFileQuery, useStarImagesMutation, useUnstarImagesMutation, } from 'services/api/endpoints/images'; import { ImageDTO } from 'services/api/types'; import { configSelector } from '../../../system/store/configSelectors'; import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions'; import { flushSync } from 'react-dom'; type SingleSelectionMenuItemsProps = { imageDTO: ImageDTO; }; const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => { const { imageDTO } = props; const dispatch = useAppDispatch(); const { t } = useTranslation(); const toaster = useAppToaster(); const isCanvasEnabled = useFeatureStatus('unifiedCanvas').isFeatureEnabled; const { shouldFetchMetadataFromApi } = useAppSelector(configSelector); const customStarUi = useStore($customStarUI); const { metadata, workflow, isLoading } = useGetImageMetadataFromFileQuery( { image: imageDTO, shouldFetchMetadataFromApi }, { selectFromResult: (res) => ({ isLoading: res.isFetching, metadata: res?.currentData?.metadata, workflow: res?.currentData?.workflow, }), } ); const [starImages] = useStarImagesMutation(); const [unstarImages] = useUnstarImagesMutation(); const { isClipboardAPIAvailable, copyImageToClipboard } = useCopyImageToClipboard(); const handleDelete = useCallback(() => { if (!imageDTO) { return; } dispatch(imagesToDeleteSelected([imageDTO])); }, [dispatch, imageDTO]); const { recallBothPrompts, recallSeed, recallAllParameters } = useRecallParameters(); // Recall parameters handlers const handleRecallPrompt = useCallback(() => { recallBothPrompts( metadata?.positive_prompt, metadata?.negative_prompt, metadata?.positive_style_prompt, metadata?.negative_style_prompt ); }, [ metadata?.negative_prompt, metadata?.positive_prompt, metadata?.positive_style_prompt, metadata?.negative_style_prompt, recallBothPrompts, ]); const handleRecallSeed = useCallback(() => { recallSeed(metadata?.seed); }, [metadata?.seed, recallSeed]); const handleLoadWorkflow = useCallback(() => { if (!workflow) { return; } dispatch(workflowLoadRequested(workflow)); }, [dispatch, workflow]); const handleSendToImageToImage = useCallback(() => { dispatch(sentImageToImg2Img()); dispatch(initialImageSelected(imageDTO)); }, [dispatch, imageDTO]); const handleSendToCanvas = useCallback(() => { dispatch(sentImageToCanvas()); flushSync(() => { dispatch(setActiveTab('unifiedCanvas')); }); dispatch(setInitialCanvasImage(imageDTO)); toaster({ title: t('toast.sentToUnifiedCanvas'), status: 'success', duration: 2500, isClosable: true, }); }, [dispatch, imageDTO, t, toaster]); const handleUseAllParameters = useCallback(() => { recallAllParameters(metadata); }, [metadata, recallAllParameters]); const handleChangeBoard = useCallback(() => { dispatch(imagesToChangeSelected([imageDTO])); dispatch(isModalOpenChanged(true)); }, [dispatch, imageDTO]); const handleCopyImage = useCallback(() => { copyImageToClipboard(imageDTO.image_url); }, [copyImageToClipboard, imageDTO.image_url]); const handleStarImage = useCallback(() => { if (imageDTO) { starImages({ imageDTOs: [imageDTO] }); } }, [starImages, imageDTO]); const handleUnstarImage = useCallback(() => { if (imageDTO) { unstarImages({ imageDTOs: [imageDTO] }); } }, [unstarImages, imageDTO]); return ( <> } > {t('common.openInNewTab')} {isClipboardAPIAvailable && ( } onClickCapture={handleCopyImage}> {t('parameters.copyImage')} )} } w="100%" > {t('parameters.downloadImage')} : } onClickCapture={handleLoadWorkflow} isDisabled={isLoading || !workflow} > {t('nodes.loadWorkflow')} : } onClickCapture={handleRecallPrompt} isDisabled={ isLoading || (metadata?.positive_prompt === undefined && metadata?.negative_prompt === undefined) } > {t('parameters.usePrompt')} : } onClickCapture={handleRecallSeed} isDisabled={isLoading || metadata?.seed === undefined} > {t('parameters.useSeed')} : } onClickCapture={handleUseAllParameters} isDisabled={isLoading || !metadata} > {t('parameters.useAll')} } onClickCapture={handleSendToImageToImage} id="send-to-img2img" > {t('parameters.sendToImg2Img')} {isCanvasEnabled && ( } onClickCapture={handleSendToCanvas} id="send-to-canvas" > {t('parameters.sendToUnifiedCanvas')} )} } onClickCapture={handleChangeBoard}> Change Board {imageDTO.starred ? ( } onClickCapture={handleUnstarImage} > {customStarUi ? customStarUi.off.text : `Unstar Image`} ) : ( } onClickCapture={handleStarImage} > {customStarUi ? customStarUi.on.text : `Star Image`} )} } onClickCapture={handleDelete} > {t('gallery.deleteImage')} ); }; export default memo(SingleSelectionMenuItems); const SpinnerIcon = () => ( );