| import type { TooltipProps } from '@invoke-ai/ui-library'; | |
| import { Divider, Flex, ListItem, Text, Tooltip, UnorderedList } from '@invoke-ai/ui-library'; | |
| import { createSelector } from '@reduxjs/toolkit'; | |
| import { useAppSelector } from 'app/store/storeHooks'; | |
| import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue'; | |
| import { selectSendToCanvas } from 'features/controlLayers/store/canvasSettingsSlice'; | |
| import { selectIterations, selectParamsSlice } from 'features/controlLayers/store/paramsSlice'; | |
| import { | |
| selectDynamicPromptsIsLoading, | |
| selectDynamicPromptsSlice, | |
| } from 'features/dynamicPrompts/store/dynamicPromptsSlice'; | |
| import { getShouldProcessPrompt } from 'features/dynamicPrompts/util/getShouldProcessPrompt'; | |
| import { selectAutoAddBoardId } from 'features/gallery/store/gallerySelectors'; | |
| import type { PropsWithChildren } from 'react'; | |
| import { memo, useMemo } from 'react'; | |
| import { useTranslation } from 'react-i18next'; | |
| import { useEnqueueBatchMutation } from 'services/api/endpoints/queue'; | |
| import { useBoardName } from 'services/api/hooks/useBoardName'; | |
| const selectPromptsCount = createSelector(selectParamsSlice, selectDynamicPromptsSlice, (params, dynamicPrompts) => | |
| getShouldProcessPrompt(params.positivePrompt) ? dynamicPrompts.prompts.length : 1 | |
| ); | |
| type Props = TooltipProps & { | |
| prepend?: boolean; | |
| }; | |
| export const QueueButtonTooltip = ({ prepend, children, ...rest }: PropsWithChildren<Props>) => { | |
| return ( | |
| <Tooltip label={<TooltipContent prepend={prepend} />} maxW={512} {...rest}> | |
| {children} | |
| </Tooltip> | |
| ); | |
| }; | |
| const TooltipContent = memo(({ prepend = false }: { prepend?: boolean }) => { | |
| const { t } = useTranslation(); | |
| const { isReady, reasons } = useIsReadyToEnqueue(); | |
| const sendToCanvas = useAppSelector(selectSendToCanvas); | |
| const isLoadingDynamicPrompts = useAppSelector(selectDynamicPromptsIsLoading); | |
| const promptsCount = useAppSelector(selectPromptsCount); | |
| const iterationsCount = useAppSelector(selectIterations); | |
| const autoAddBoardId = useAppSelector(selectAutoAddBoardId); | |
| const autoAddBoardName = useBoardName(autoAddBoardId); | |
| const [_, { isLoading }] = useEnqueueBatchMutation({ | |
| fixedCacheKey: 'enqueueBatch', | |
| }); | |
| const queueCountPredictionLabel = useMemo(() => { | |
| const generationCount = Math.min(promptsCount * iterationsCount, 10000); | |
| const prompts = t('queue.prompts', { count: promptsCount }); | |
| const iterations = t('queue.iterations', { count: iterationsCount }); | |
| const generations = t('queue.generations', { count: generationCount }); | |
| return `${promptsCount} ${prompts} \u00d7 ${iterationsCount} ${iterations} -> ${generationCount} ${generations}`.toLowerCase(); | |
| }, [iterationsCount, promptsCount, t]); | |
| const label = useMemo(() => { | |
| if (isLoading) { | |
| return t('queue.enqueueing'); | |
| } | |
| if (isLoadingDynamicPrompts) { | |
| return t('dynamicPrompts.loading'); | |
| } | |
| if (isReady) { | |
| if (prepend) { | |
| return t('queue.queueFront'); | |
| } | |
| return t('queue.queueBack'); | |
| } | |
| return t('queue.notReady'); | |
| }, [isLoading, isLoadingDynamicPrompts, isReady, prepend, t]); | |
| const addingTo = useMemo(() => { | |
| if (sendToCanvas) { | |
| return t('controlLayers.stagingOnCanvas'); | |
| } | |
| return t('parameters.invoke.addingImagesTo'); | |
| }, [sendToCanvas, t]); | |
| const destination = useMemo(() => { | |
| if (sendToCanvas) { | |
| return t('queue.canvas'); | |
| } | |
| if (autoAddBoardName) { | |
| return autoAddBoardName; | |
| } | |
| return t('boards.uncategorized'); | |
| }, [autoAddBoardName, sendToCanvas, t]); | |
| return ( | |
| <Flex flexDir="column" gap={1}> | |
| <Text fontWeight="semibold">{label}</Text> | |
| <Text>{queueCountPredictionLabel}</Text> | |
| {reasons.length > 0 && ( | |
| <> | |
| <Divider opacity={0.2} borderColor="base.900" /> | |
| <UnorderedList> | |
| {reasons.map((reason, i) => ( | |
| <ListItem key={`${reason.content}.${i}`}> | |
| <span> | |
| {reason.prefix && ( | |
| <Text as="span" fontWeight="semibold"> | |
| {reason.prefix}:{' '} | |
| </Text> | |
| )} | |
| <Text as="span">{reason.content}</Text> | |
| </span> | |
| </ListItem> | |
| ))} | |
| </UnorderedList> | |
| </> | |
| )} | |
| <Divider opacity={0.2} borderColor="base.900" /> | |
| <Text fontStyle="oblique 10deg"> | |
| {addingTo}{' '} | |
| <Text as="span" fontWeight="semibold"> | |
| {destination} | |
| </Text> | |
| </Text> | |
| </Flex> | |
| ); | |
| }); | |
| TooltipContent.displayName = 'QueueButtonTooltipContent'; | |