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 = () => (
);