Skip to content

Commit b09008c

Browse files
feat(ui): add cancel and clear all as toggleable app feature
1 parent 7adac45 commit b09008c

File tree

7 files changed

+230
-81
lines changed

7 files changed

+230
-81
lines changed

invokeai/frontend/web/src/app/types/invokeai.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export type AppFeature =
2727
| 'bulkDownload'
2828
| 'starterModels'
2929
| 'hfToken'
30-
| 'retryQueueItem';
30+
| 'retryQueueItem'
31+
| 'cancelAndClearAll';
3132
/**
3233
* A disable-able Stable Diffusion feature
3334
*/
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { ButtonProps } from '@invoke-ai/ui-library';
2+
import { Button } from '@invoke-ai/ui-library';
3+
import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
4+
import { memo } from 'react';
5+
import { useTranslation } from 'react-i18next';
6+
import { PiXCircle } from 'react-icons/pi';
7+
8+
type Props = ButtonProps;
9+
10+
export const CancelAllExceptCurrentButton = memo((props: Props) => {
11+
const { t } = useTranslation();
12+
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
13+
14+
return (
15+
<>
16+
<Button
17+
onClick={cancelAllExceptCurrent.openDialog}
18+
isLoading={cancelAllExceptCurrent.isLoading}
19+
isDisabled={cancelAllExceptCurrent.isDisabled}
20+
tooltip={t('queue.cancelAllExceptCurrentTooltip')}
21+
leftIcon={<PiXCircle />}
22+
colorScheme="error"
23+
data-testid={t('queue.clear')}
24+
{...props}
25+
>
26+
{t('queue.clear')}
27+
</Button>
28+
</>
29+
);
30+
});
31+
32+
CancelAllExceptCurrentButton.displayName = 'CancelAllExceptCurrentButton';
Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,89 @@
11
import { IconButton, useShiftModifier } from '@invoke-ai/ui-library';
2+
import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
23
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
4+
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
35
import { memo } from 'react';
46
import { useTranslation } from 'react-i18next';
5-
import { PiTrashSimpleBold, PiXBold } from 'react-icons/pi';
7+
import { PiTrashSimpleBold, PiXBold, PiXCircle } from 'react-icons/pi';
68

79
import { useClearQueueDialog } from './ClearQueueConfirmationAlertDialog';
810

9-
export const ClearQueueIconButton = memo((_) => {
11+
export const ClearQueueIconButton = memo(() => {
12+
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
13+
const shift = useShiftModifier();
14+
15+
if (!shift) {
16+
// Shift is not pressed - show cancel current
17+
return <CancelCurrentIconButton />;
18+
}
19+
20+
if (isCancelAndClearAllEnabled) {
21+
// Shift is pressed and cancel and clear all is enabled - show cancel and clear all
22+
return <CancelAndClearAllIconButton />;
23+
}
24+
25+
// Shift is pressed and cancel and clear all is disabled - show cancel all except current
26+
return <CancelAllExceptCurrentIconButton />;
27+
});
28+
29+
ClearQueueIconButton.displayName = 'ClearQueueIconButton';
30+
31+
const CancelCurrentIconButton = memo(() => {
1032
const { t } = useTranslation();
11-
const clearQueue = useClearQueueDialog();
1233
const cancelCurrentQueueItem = useCancelCurrentQueueItem();
1334

14-
// Show the single item clear button when shift is pressed
15-
// Otherwise show the clear queue button
16-
const shift = useShiftModifier();
35+
return (
36+
<IconButton
37+
size="lg"
38+
isDisabled={cancelCurrentQueueItem.isDisabled}
39+
isLoading={cancelCurrentQueueItem.isLoading}
40+
aria-label={t('queue.cancel')}
41+
tooltip={t('queue.cancelTooltip')}
42+
icon={<PiXBold />}
43+
colorScheme="error"
44+
onClick={cancelCurrentQueueItem.cancelQueueItem}
45+
/>
46+
);
47+
});
48+
49+
CancelCurrentIconButton.displayName = 'CancelCurrentIconButton';
50+
51+
const CancelAndClearAllIconButton = memo(() => {
52+
const { t } = useTranslation();
53+
const clearQueue = useClearQueueDialog();
1754

1855
return (
1956
<IconButton
2057
size="lg"
21-
isDisabled={shift ? clearQueue.isDisabled : cancelCurrentQueueItem.isDisabled}
22-
isLoading={shift ? clearQueue.isLoading : cancelCurrentQueueItem.isLoading}
23-
aria-label={shift ? t('queue.clear') : t('queue.cancel')}
24-
tooltip={shift ? t('queue.clearTooltip') : t('queue.cancelTooltip')}
25-
icon={shift ? <PiTrashSimpleBold /> : <PiXBold />}
58+
isDisabled={clearQueue.isDisabled}
59+
isLoading={clearQueue.isLoading}
60+
aria-label={t('queue.clear')}
61+
tooltip={t('queue.clearTooltip')}
62+
icon={<PiTrashSimpleBold />}
2663
colorScheme="error"
27-
onClick={shift ? clearQueue.openDialog : cancelCurrentQueueItem.cancelQueueItem}
28-
data-testid={shift ? t('queue.clear') : t('queue.cancel')}
64+
onClick={clearQueue.openDialog}
2965
/>
3066
);
3167
});
3268

33-
ClearQueueIconButton.displayName = 'ClearQueueIconButton';
69+
CancelAndClearAllIconButton.displayName = 'CancelAndClearAllIconButton';
70+
71+
const CancelAllExceptCurrentIconButton = memo(() => {
72+
const { t } = useTranslation();
73+
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
74+
75+
return (
76+
<IconButton
77+
size="lg"
78+
isDisabled={cancelAllExceptCurrent.isDisabled}
79+
isLoading={cancelAllExceptCurrent.isLoading}
80+
aria-label={t('queue.clear')}
81+
tooltip={t('queue.cancelAllExceptCurrentTooltip')}
82+
icon={<PiXCircle />}
83+
colorScheme="error"
84+
onClick={cancelAllExceptCurrent.openDialog}
85+
/>
86+
);
87+
});
88+
89+
CancelAllExceptCurrentIconButton.displayName = 'CancelAllExceptCurrentIconButton';

invokeai/frontend/web/src/features/queue/components/QueueActionsMenuButton.tsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const QueueActionsMenuButton = memo(() => {
2727
const { t } = useTranslation();
2828
const isPauseEnabled = useFeatureStatus('pauseQueue');
2929
const isResumeEnabled = useFeatureStatus('resumeQueue');
30+
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
3031
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
3132
const cancelCurrent = useCancelCurrentQueueItem();
3233
const clearQueue = useClearQueueDialog();
@@ -71,15 +72,17 @@ export const QueueActionsMenuButton = memo(() => {
7172
>
7273
{t('queue.cancelAllExceptCurrentTooltip')}
7374
</MenuItem>
74-
<MenuItem
75-
isDestructive
76-
icon={<PiTrashSimpleBold />}
77-
onClick={clearQueue.openDialog}
78-
isLoading={clearQueue.isLoading}
79-
isDisabled={clearQueue.isDisabled}
80-
>
81-
{t('queue.clearTooltip')}
82-
</MenuItem>
75+
{isCancelAndClearAllEnabled && (
76+
<MenuItem
77+
isDestructive
78+
icon={<PiTrashSimpleBold />}
79+
onClick={clearQueue.openDialog}
80+
isLoading={clearQueue.isLoading}
81+
isDisabled={clearQueue.isDisabled}
82+
>
83+
{t('queue.clearTooltip')}
84+
</MenuItem>
85+
)}
8386
{isResumeEnabled && (
8487
<MenuItem
8588
icon={<PiPlayFill />}

invokeai/frontend/web/src/features/queue/components/QueueTabQueueControls.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable i18next/no-literal-string */
22
import { ButtonGroup, Flex } from '@invoke-ai/ui-library';
3+
import { CancelAllExceptCurrentButton } from 'features/queue/components/CancelAllExceptCurrentButton';
34
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
45
import { memo } from 'react';
56

@@ -12,6 +13,8 @@ import ResumeProcessorButton from './ResumeProcessorButton';
1213
const QueueTabQueueControls = () => {
1314
const isPauseEnabled = useFeatureStatus('pauseQueue');
1415
const isResumeEnabled = useFeatureStatus('resumeQueue');
16+
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
17+
1518
return (
1619
<Flex flexDir="column" layerStyle="first" borderRadius="base" p={2} gap={2}>
1720
<Flex gap={2}>
@@ -25,7 +28,8 @@ const QueueTabQueueControls = () => {
2528
)}
2629
<ButtonGroup w={28} orientation="vertical" size="sm">
2730
<PruneQueueButton />
28-
<ClearQueueButton />
31+
{isCancelAndClearAllEnabled && <ClearQueueButton />}
32+
{!isCancelAndClearAllEnabled && <CancelAllExceptCurrentButton />}
2933
</ButtonGroup>
3034
</Flex>
3135
<ClearModelCacheButton />

invokeai/frontend/web/src/features/ui/components/AppContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ export const AppContent = memo(() => {
141141
)}
142142
<Panel id="main-panel" order={1} minSize={20} style={panelStyles}>
143143
<MainPanelContent />
144-
{withLeftPanel && <FloatingParametersPanelButtons panelApi={leftPanel} />}
144+
{withLeftPanel && <FloatingParametersPanelButtons togglePanel={leftPanel.toggle} />}
145145
{withRightPanel && <FloatingGalleryButton panelApi={rightPanel} />}
146146
</Panel>
147147
{withRightPanel && (

0 commit comments

Comments
 (0)