diff --git a/invokeai/frontend/web/src/app/components/App.tsx b/invokeai/frontend/web/src/app/components/App.tsx
index 2208aa5d58..e333d13332 100644
--- a/invokeai/frontend/web/src/app/components/App.tsx
+++ b/invokeai/frontend/web/src/app/components/App.tsx
@@ -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
+
);
diff --git a/invokeai/frontend/web/src/common/hooks/useBoolean.ts b/invokeai/frontend/web/src/common/hooks/useBoolean.ts
index 123e48cd75..46e96d424c 100644
--- a/invokeai/frontend/web/src/common/hooks/useBoolean.ts
+++ b/invokeai/frontend/web/src/common/hooks/useBoolean.ts
@@ -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) => {
+ 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;
+ };
+};
diff --git a/invokeai/frontend/web/src/features/queue/components/ClearQueueButton.tsx b/invokeai/frontend/web/src/features/queue/components/ClearQueueButton.tsx
index c899dd0482..5b2806c93a 100644
--- a/invokeai/frontend/web/src/features/queue/components/ClearQueueButton.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/ClearQueueButton.tsx
@@ -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={}
colorScheme="error"
- onClick={disclosure.onOpen}
+ onClick={dialogState.setTrue}
data-testid={t('queue.clear')}
{...props}
>
{t('queue.clear')}
-
>
);
};
diff --git a/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx b/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx
index 291419d024..b90d66073e 100644
--- a/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/ClearQueueConfirmationAlertDialog.tsx
@@ -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 (
{
{t('queue.clearQueueAlertDialog2')}
);
-};
+});
-export default memo(ClearQueueButton);
+ClearQueueConfirmationsAlertDialog.displayName = 'ClearQueueConfirmationsAlertDialog';
diff --git a/invokeai/frontend/web/src/features/queue/components/ClearQueueIconButton.tsx b/invokeai/frontend/web/src/features/queue/components/ClearQueueIconButton.tsx
index 41843ad66c..39a84c0216 100644
--- a/invokeai/frontend/web/src/features/queue/components/ClearQueueIconButton.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/ClearQueueIconButton.tsx
@@ -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;
-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={}
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 ? (
-
- ) : (
-
- )}
-
- >
- );
-};
+ if (shift) {
+ return ;
+ }
+
+ return ;
+});
+
+ClearQueueIconButton.displayName = 'ClearQueueIconButton';
diff --git a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx
index 101c82376c..99456b042f 100644
--- a/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx
+++ b/invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx
@@ -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 (
-
-