feat(ui): use singleton for clear q confirm dialog

This commit is contained in:
psychedelicious 2024-08-23 19:44:58 +10:00
parent d0464330f7
commit 3af577b210
9 changed files with 77 additions and 53 deletions

View File

@ -14,6 +14,7 @@ import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardMo
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
import { ClearQueueConfirmationsAlertDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { StylePresetModal } from 'features/stylePresets/components/StylePresetForm/StylePresetModal';
import { configChanged } from 'features/system/store/configSlice';
import { languageSelector } from 'features/system/store/systemSelectors';
@ -118,6 +119,7 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage, selectedWorkflowId, desti
<ChangeBoardModal />
<DynamicPromptsModal />
<StylePresetModal />
<ClearQueueConfirmationsAlertDialog />
<PreselectedImage selectedImage={selectedImage} />
</ErrorBoundary>
);

View File

@ -1,3 +1,4 @@
import type { WritableAtom } from 'nanostores';
import { useCallback, useMemo, useState } from 'react';
export const useBoolean = (initialValue: boolean) => {
@ -19,3 +20,33 @@ export const useBoolean = (initialValue: boolean) => {
return api;
};
export const buildUseBoolean = ($boolean: WritableAtom<boolean>) => {
return () => {
const setTrue = useCallback(() => {
$boolean.set(true);
}, []);
const setFalse = useCallback(() => {
$boolean.set(false);
}, []);
const set = useCallback((value: boolean) => {
$boolean.set(value);
}, []);
const toggle = useCallback(() => {
$boolean.set(!$boolean.get());
}, []);
const api = useMemo(
() => ({
setTrue,
setFalse,
set,
toggle,
$boolean,
}),
[set, setFalse, setTrue, toggle]
);
return api;
};
};

View File

@ -1,6 +1,6 @@
import type { ButtonProps } from '@invoke-ai/ui-library';
import { Button, useDisclosure } from '@invoke-ai/ui-library';
import ClearQueueConfirmationAlertDialog from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { Button } from '@invoke-ai/ui-library';
import { useClearQueueConfirmationAlertDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { useClearQueue } from 'features/queue/hooks/useClearQueue';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
@ -10,7 +10,7 @@ type Props = ButtonProps;
const ClearQueueButton = (props: Props) => {
const { t } = useTranslation();
const disclosure = useDisclosure();
const dialogState = useClearQueueConfirmationAlertDialog();
const { isLoading, isDisabled } = useClearQueue();
return (
@ -21,13 +21,12 @@ const ClearQueueButton = (props: Props) => {
tooltip={t('queue.clearTooltip')}
leftIcon={<PiTrashSimpleFill />}
colorScheme="error"
onClick={disclosure.onOpen}
onClick={dialogState.setTrue}
data-testid={t('queue.clear')}
{...props}
>
{t('queue.clear')}
</Button>
<ClearQueueConfirmationAlertDialog disclosure={disclosure} />
</>
);
};

View File

@ -1,21 +1,24 @@
import type { UseDisclosureReturn } from '@invoke-ai/ui-library';
import { ConfirmationAlertDialog, Text } from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { buildUseBoolean } from 'common/hooks/useBoolean';
import { useClearQueue } from 'features/queue/hooks/useClearQueue';
import { atom } from 'nanostores';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
type Props = {
disclosure: UseDisclosureReturn;
};
const $boolean = atom(false);
export const useClearQueueConfirmationAlertDialog = buildUseBoolean($boolean);
const ClearQueueButton = ({ disclosure }: Props) => {
export const ClearQueueConfirmationsAlertDialog = memo(() => {
const { t } = useTranslation();
const dialogState = useClearQueueConfirmationAlertDialog();
const isOpen = useStore(dialogState.$boolean);
const { clearQueue } = useClearQueue();
return (
<ConfirmationAlertDialog
isOpen={disclosure.isOpen}
onClose={disclosure.onClose}
isOpen={isOpen}
onClose={dialogState.setFalse}
title={t('queue.clearTooltip')}
acceptCallback={clearQueue}
acceptButtonText={t('queue.clear')}
@ -25,6 +28,6 @@ const ClearQueueButton = ({ disclosure }: Props) => {
<Text>{t('queue.clearQueueAlertDialog2')}</Text>
</ConfirmationAlertDialog>
);
};
});
export default memo(ClearQueueButton);
ClearQueueConfirmationsAlertDialog.displayName = 'ClearQueueConfirmationsAlertDialog';

View File

@ -1,19 +1,17 @@
import type { IconButtonProps } from '@invoke-ai/ui-library';
import { IconButton, useDisclosure, useShiftModifier } from '@invoke-ai/ui-library';
import ClearQueueConfirmationAlertDialog from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { IconButton, useShiftModifier } from '@invoke-ai/ui-library';
import { useClearQueueConfirmationAlertDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
import { useClearQueue } from 'features/queue/hooks/useClearQueue';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiTrashSimpleBold, PiXBold } from 'react-icons/pi';
type ClearQueueButtonProps = Omit<IconButtonProps, 'aria-label'>;
type ClearQueueIconButtonProps = ClearQueueButtonProps & {
onOpen: () => void;
};
export const ClearAllQueueIconButton = ({ onOpen, ...props }: ClearQueueIconButtonProps) => {
export const ClearAllQueueIconButton = memo((props: ClearQueueButtonProps) => {
const { t } = useTranslation();
const dialogState = useClearQueueConfirmationAlertDialog();
const { isLoading, isDisabled } = useClearQueue();
return (
@ -24,14 +22,16 @@ export const ClearAllQueueIconButton = ({ onOpen, ...props }: ClearQueueIconButt
tooltip={t('queue.clearTooltip')}
icon={<PiTrashSimpleBold size="16px" />}
colorScheme="error"
onClick={onOpen}
onClick={dialogState.setTrue}
data-testid={t('queue.clear')}
{...props}
/>
);
};
});
const ClearSingleQueueItemIconButton = (props: ClearQueueButtonProps) => {
ClearAllQueueIconButton.displayName = 'ClearAllQueueIconButton';
const ClearSingleQueueItemIconButton = memo((props: ClearQueueButtonProps) => {
const { t } = useTranslation();
const { cancelQueueItem, isLoading, isDisabled } = useCancelCurrentQueueItem();
@ -48,22 +48,20 @@ const ClearSingleQueueItemIconButton = (props: ClearQueueButtonProps) => {
{...props}
/>
);
};
});
export const ClearQueueIconButton = (props: ClearQueueButtonProps) => {
ClearSingleQueueItemIconButton.displayName = 'ClearSingleQueueItemIconButton';
export const ClearQueueIconButton = memo((props: ClearQueueButtonProps) => {
// Show the single item clear button when shift is pressed
// Otherwise show the clear queue button
const shift = useShiftModifier();
const disclosure = useDisclosure();
return (
<>
{shift ? (
<ClearAllQueueIconButton {...props} onOpen={disclosure.onOpen} />
) : (
<ClearSingleQueueItemIconButton {...props} />
)}
<ClearQueueConfirmationAlertDialog disclosure={disclosure} />
</>
);
};
if (shift) {
return <ClearAllQueueIconButton {...props} />;
}
return <ClearSingleQueueItemIconButton {...props} />;
});
ClearQueueIconButton.displayName = 'ClearQueueIconButton';

View File

@ -10,7 +10,7 @@ import {
useDisclosure,
} from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import ClearQueueConfirmationAlertDialog from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { useClearQueueConfirmationAlertDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { useClearQueue } from 'features/queue/hooks/useClearQueue';
import { usePauseProcessor } from 'features/queue/hooks/usePauseProcessor';
import { useResumeProcessor } from 'features/queue/hooks/useResumeProcessor';
@ -26,7 +26,7 @@ export const QueueActionsMenuButton = memo(() => {
const { isOpen, onOpen, onClose } = useDisclosure();
const dispatch = useAppDispatch();
const { t } = useTranslation();
const clearQueueDisclosure = useDisclosure();
const dialogState = useClearQueueConfirmationAlertDialog();
const isPauseEnabled = useFeatureStatus('pauseQueue');
const isResumeEnabled = useFeatureStatus('resumeQueue');
const { queueSize } = useGetQueueStatusQuery(undefined, {
@ -51,15 +51,13 @@ export const QueueActionsMenuButton = memo(() => {
return (
<Box pos="relative">
<ClearQueueConfirmationAlertDialog disclosure={clearQueueDisclosure} />
<Menu isOpen={isOpen} onOpen={onOpen} onClose={onClose} placement="bottom-end">
<MenuButton as={IconButton} aria-label="Queue Actions Menu" icon={<RiListCheck />} />
<MenuList>
<MenuItem
isDestructive
icon={<PiTrashSimpleBold size="16px" />}
onClick={clearQueueDisclosure.onOpen}
onClick={dialogState.setTrue}
isLoading={isLoadingClearQueue}
isDisabled={isDisabledClearQueue}
>

View File

@ -17,9 +17,6 @@ const QueueControls = () => {
<InvokeQueueBackButton />
<Spacer />
<QueueActionsMenuButton />
{/* <CancelCurrentQueueItemButton asIconButton />
{isResumeEnabled && <ResumeProcessorButton asIconButton />}
{isPauseEnabled && <PauseProcessorButton asIconButton />} */}
<ClearQueueIconButton />
</ButtonGroup>
<ProgressBar />

View File

@ -1,7 +1,6 @@
import type { SystemStyleObject } from '@invoke-ai/ui-library';
import { ButtonGroup, Flex, Icon, IconButton, Portal, spinAnimation, useDisclosure } from '@invoke-ai/ui-library';
import { ButtonGroup, Flex, Icon, IconButton, Portal, spinAnimation } from '@invoke-ai/ui-library';
import CancelCurrentQueueItemIconButton from 'features/queue/components/CancelCurrentQueueItemIconButton';
import ClearQueueConfirmationAlertDialog from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { ClearAllQueueIconButton } from 'features/queue/components/ClearQueueIconButton';
import { QueueButtonTooltip } from 'features/queue/components/QueueButtonTooltip';
import { useQueueBack } from 'features/queue/hooks/useQueueBack';
@ -36,8 +35,6 @@ const FloatingSidePanelButtons = (props: Props) => {
[isDisabled, queueStatus?.processor.is_processing]
);
const disclosure = useDisclosure();
if (!props.panelApi.isCollapsed) {
return null;
}
@ -76,8 +73,7 @@ const FloatingSidePanelButtons = (props: Props) => {
</QueueButtonTooltip>
<CancelCurrentQueueItemIconButton sx={floatingButtonStyles} />
</ButtonGroup>
<ClearAllQueueIconButton sx={floatingButtonStyles} onOpen={disclosure.onOpen} />
<ClearQueueConfirmationAlertDialog disclosure={disclosure} />
<ClearAllQueueIconButton sx={floatingButtonStyles} />
</Flex>
</Portal>
);

View File

@ -25,7 +25,7 @@ const WorkflowLibraryMenu = () => {
const shift = useShiftModifier();
useGlobalMenuClose(onClose);
return (
<Menu isOpen={isOpen} onOpen={onOpen} onClose={onClose}>
<Menu isOpen={isOpen} onOpen={onOpen} onClose={onClose} isLazy>
<MenuButton
as={IconButton}
aria-label={t('workflows.workflowEditorMenu')}