Skip to content

Commit

Permalink
feat(ui): add cancel all except current queue item functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
rikublock committed Nov 28, 2024
1 parent 8a0ffb7 commit 1f0a154
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 1 deletion.
3 changes: 3 additions & 0 deletions invokeai/frontend/web/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@
"pauseSucceeded": "Processor Paused",
"pauseFailed": "Problem Pausing Processor",
"cancel": "Cancel",
"cancelAllExceptCurrentQueueItemAlertDialog": "TODO Canceling the current queue item will immediately cancels any processing and the results will be lost. But will finish current in-progress items.",
"cancelAllExceptCurrentQueueItemAlertDialog2": "Are you sure you want to cancel all pending queue items?",
"cancelAllExceptCurrentTooltip": "Cancel All Except Current Item",
"cancelTooltip": "Cancel Current Item",
"cancelSucceeded": "Item Canceled",
"cancelFailed": "Problem Canceling Item",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { ConfirmationAlertDialog, Text } from '@invoke-ai/ui-library';
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
import { buildUseBoolean } from 'common/hooks/useBoolean';
import { useCancelAllExceptCurrentQueueItem } from 'features/queue/hooks/useCancelAllExceptCurrentQueueItem';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';

const [useCancelAllExceptCurrentQueueItemConfirmationAlertDialog] = buildUseBoolean(false);

export const useCancelAllExceptCurrentQueueItemDialog = () => {
const dialog = useCancelAllExceptCurrentQueueItemConfirmationAlertDialog();
const { cancelAllExceptCurrentQueueItem, isLoading, isDisabled, queueStatus } = useCancelAllExceptCurrentQueueItem();

return {
cancelAllExceptCurrentQueueItem,
isOpen: dialog.isTrue,
openDialog: dialog.setTrue,
closeDialog: dialog.setFalse,
isLoading,
queueStatus,
isDisabled,
};
};

export const CancelAllExceptCurrentQueueItemConfirmationAlertDialog = memo(() => {
useAssertSingleton('CancelAllExceptCurrentQueueItemConfirmationAlertDialog');
const { t } = useTranslation();
const cancelAllExceptCurrentQueueItem = useCancelAllExceptCurrentQueueItemDialog();

return (
<ConfirmationAlertDialog
isOpen={cancelAllExceptCurrentQueueItem.isOpen}
onClose={cancelAllExceptCurrentQueueItem.closeDialog}
title={t('queue.cancelAllExceptCurrentTooltip')}
acceptCallback={cancelAllExceptCurrentQueueItem.cancelAllExceptCurrentQueueItem}
acceptButtonText={t('queue.cancel')}
useInert={false}
>
<Text>{t('queue.cancelAllExceptCurrentQueueItemAlertDialog')}</Text>
<br />
<Text>{t('queue.cancelAllExceptCurrentQueueItemAlertDialog2')}</Text>
</ConfirmationAlertDialog>
);
});

CancelAllExceptCurrentQueueItemConfirmationAlertDialog.displayName =
'CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IconButton, Menu, MenuButton, MenuGroup, MenuItem, MenuList } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import { SessionMenuItems } from 'common/components/SessionMenuItems';
import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
import { useClearQueueDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { QueueCountBadge } from 'features/queue/components/QueueCountBadge';
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
Expand All @@ -10,14 +11,23 @@ import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { setActiveTab } from 'features/ui/store/uiSlice';
import { memo, useCallback, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { PiListBold, PiPauseFill, PiPlayFill, PiQueueBold, PiTrashSimpleBold, PiXBold } from 'react-icons/pi';
import {
PiListBold,
PiPauseFill,
PiPlayFill,
PiQueueBold,
PiTrashSimpleBold,
PiXBold,
PiXCircle,
} from 'react-icons/pi';

export const QueueActionsMenuButton = memo(() => {
const ref = useRef<HTMLDivElement>(null);
const dispatch = useAppDispatch();
const { t } = useTranslation();
const isPauseEnabled = useFeatureStatus('pauseQueue');
const isResumeEnabled = useFeatureStatus('resumeQueue');
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
const cancelCurrent = useCancelCurrentQueueItem();
const clearQueue = useClearQueueDialog();
const {
Expand Down Expand Up @@ -52,6 +62,15 @@ export const QueueActionsMenuButton = memo(() => {
>
{t('queue.cancelTooltip')}
</MenuItem>
<MenuItem
isDestructive
icon={<PiXCircle />}
onClick={cancelAllExceptCurrent.openDialog}
isLoading={cancelAllExceptCurrent.isLoading}
isDisabled={cancelAllExceptCurrent.isDisabled}
>
{t('queue.cancelAllExceptCurrentTooltip')}
</MenuItem>
<MenuItem
isDestructive
icon={<PiTrashSimpleBold />}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useStore } from '@nanostores/react';
import { toast } from 'features/toast/toast';
import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useCancelAllExceptCurrentMutation, useGetQueueStatusQuery } from 'services/api/endpoints/queue';
import { $isConnected } from 'services/events/stores';

export const useCancelAllExceptCurrentQueueItem = () => {
const { t } = useTranslation();
const { data: queueStatus } = useGetQueueStatusQuery();
const isConnected = useStore($isConnected);
const [trigger, { isLoading }] = useCancelAllExceptCurrentMutation();

const cancelAllExceptCurrentQueueItem = useCallback(async () => {
if (!queueStatus?.queue.total) {
return;
}

// TODO fix trigger
try {
await trigger().unwrap();
toast({
id: 'QUEUE_CANCEL_SUCCEEDED',
title: t('queue.cancelSucceeded'),
status: 'success',
});
} catch {
toast({
id: 'QUEUE_CANCEL_FAILED',
title: t('queue.cancelFailed'),
status: 'error',
});
}
}, [queueStatus?.queue.total, trigger, t]);

const isDisabled = useMemo(() => !isConnected || !queueStatus?.queue.total, [isConnected, queueStatus?.queue.total]);

return {
cancelAllExceptCurrentQueueItem,
isLoading,
queueStatus,
isDisabled,
};
};
28 changes: 28 additions & 0 deletions invokeai/frontend/web/src/services/api/endpoints/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,33 @@ export const queueApi = api.injectEndpoints({
return ['SessionQueueStatus', 'BatchStatus', { type: 'QueueCountsByDestination', id: destination }];
},
}),
cancelAllExceptCurrent: build.mutation<
paths['/api/v1/queue/{queue_id}/cancel_all_except_current']['put']['responses']['200']['content']['application/json'],
paths['/api/v1/queue/{queue_id}/cancel_all_except_current']['put']['parameters']['query']
>({
query: (params) => ({
url: buildQueueUrl('cancel_all_except_current'),
method: 'PUT',
params,
}),
// TODO
onQueryStarted: async (arg, api) => {
const { dispatch, queryFulfilled } = api;
try {
await queryFulfilled;
resetListQueryData(dispatch);
} catch {
// no-op
}
},
// TODO
invalidatesTags: (result, error) => {
if (!result) {
return [];
}
return ['SessionQueueStatus', 'BatchStatus'];
},
}),
listQueueItems: build.query<
EntityState<components['schemas']['SessionQueueItemDTO'], string> & {
has_more: boolean;
Expand Down Expand Up @@ -390,6 +417,7 @@ export const queueApi = api.injectEndpoints({
});

export const {
useCancelAllExceptCurrentMutation,
useCancelByBatchIdsMutation,
useEnqueueBatchMutation,
usePauseProcessorMutation,
Expand Down

0 comments on commit 1f0a154

Please sign in to comment.