mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-01-15 09:18:00 -05:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28d3356710 | ||
|
|
81e70fb9d2 | ||
|
|
971c425734 | ||
|
|
b09008c530 |
@@ -570,7 +570,10 @@ ValueToInsertTuple: TypeAlias = tuple[
|
||||
str | None, # destination (optional)
|
||||
int | None, # retried_from_item_id (optional, this is always None for new items)
|
||||
]
|
||||
"""A type alias for the tuple of values to insert into the session queue table."""
|
||||
"""A type alias for the tuple of values to insert into the session queue table.
|
||||
|
||||
**If you change this, be sure to update the `enqueue_batch` and `retry_items_by_id` methods in the session queue service!**
|
||||
"""
|
||||
|
||||
|
||||
def prepare_values_to_insert(
|
||||
|
||||
@@ -27,6 +27,7 @@ from invokeai.app.services.session_queue.session_queue_common import (
|
||||
SessionQueueItemDTO,
|
||||
SessionQueueItemNotFoundError,
|
||||
SessionQueueStatus,
|
||||
ValueToInsertTuple,
|
||||
calc_session_count,
|
||||
prepare_values_to_insert,
|
||||
)
|
||||
@@ -689,7 +690,7 @@ class SqliteSessionQueue(SessionQueueBase):
|
||||
"""Retries the given queue items"""
|
||||
try:
|
||||
cursor = self._conn.cursor()
|
||||
values_to_insert: list[tuple] = []
|
||||
values_to_insert: list[ValueToInsertTuple] = []
|
||||
retried_item_ids: list[int] = []
|
||||
|
||||
for item_id in item_ids:
|
||||
@@ -715,16 +716,16 @@ class SqliteSessionQueue(SessionQueueBase):
|
||||
else queue_item.item_id
|
||||
)
|
||||
|
||||
value_to_insert = (
|
||||
value_to_insert: ValueToInsertTuple = (
|
||||
queue_item.queue_id,
|
||||
queue_item.batch_id,
|
||||
queue_item.destination,
|
||||
field_values_json,
|
||||
queue_item.origin,
|
||||
queue_item.priority,
|
||||
workflow_json,
|
||||
cloned_session_json,
|
||||
cloned_session.id,
|
||||
queue_item.batch_id,
|
||||
field_values_json,
|
||||
queue_item.priority,
|
||||
workflow_json,
|
||||
queue_item.origin,
|
||||
queue_item.destination,
|
||||
retried_from_item_id,
|
||||
)
|
||||
values_to_insert.append(value_to_insert)
|
||||
|
||||
@@ -27,7 +27,8 @@ export type AppFeature =
|
||||
| 'bulkDownload'
|
||||
| 'starterModels'
|
||||
| 'hfToken'
|
||||
| 'retryQueueItem';
|
||||
| 'retryQueueItem'
|
||||
| 'cancelAndClearAll';
|
||||
/**
|
||||
* A disable-able Stable Diffusion feature
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { ButtonProps } from '@invoke-ai/ui-library';
|
||||
import { Button } from '@invoke-ai/ui-library';
|
||||
import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiXCircle } from 'react-icons/pi';
|
||||
|
||||
type Props = ButtonProps;
|
||||
|
||||
export const CancelAllExceptCurrentButton = memo((props: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
onClick={cancelAllExceptCurrent.openDialog}
|
||||
isLoading={cancelAllExceptCurrent.isLoading}
|
||||
isDisabled={cancelAllExceptCurrent.isDisabled}
|
||||
tooltip={t('queue.cancelAllExceptCurrentTooltip')}
|
||||
leftIcon={<PiXCircle />}
|
||||
colorScheme="error"
|
||||
data-testid={t('queue.clear')}
|
||||
{...props}
|
||||
>
|
||||
{t('queue.clear')}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
CancelAllExceptCurrentButton.displayName = 'CancelAllExceptCurrentButton';
|
||||
@@ -1,33 +1,89 @@
|
||||
import { IconButton, useShiftModifier } from '@invoke-ai/ui-library';
|
||||
import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
|
||||
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiTrashSimpleBold, PiXBold } from 'react-icons/pi';
|
||||
import { PiTrashSimpleBold, PiXBold, PiXCircle } from 'react-icons/pi';
|
||||
|
||||
import { useClearQueueDialog } from './ClearQueueConfirmationAlertDialog';
|
||||
|
||||
export const ClearQueueIconButton = memo((_) => {
|
||||
const { t } = useTranslation();
|
||||
const clearQueue = useClearQueueDialog();
|
||||
const cancelCurrentQueueItem = useCancelCurrentQueueItem();
|
||||
|
||||
// Show the single item clear button when shift is pressed
|
||||
// Otherwise show the clear queue button
|
||||
export const ClearQueueIconButton = memo(() => {
|
||||
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
|
||||
const shift = useShiftModifier();
|
||||
|
||||
if (!shift) {
|
||||
// Shift is not pressed - show cancel current
|
||||
return <CancelCurrentIconButton />;
|
||||
}
|
||||
|
||||
if (isCancelAndClearAllEnabled) {
|
||||
// Shift is pressed and cancel and clear all is enabled - show cancel and clear all
|
||||
return <CancelAndClearAllIconButton />;
|
||||
}
|
||||
|
||||
// Shift is pressed and cancel and clear all is disabled - show cancel all except current
|
||||
return <CancelAllExceptCurrentIconButton />;
|
||||
});
|
||||
|
||||
ClearQueueIconButton.displayName = 'ClearQueueIconButton';
|
||||
|
||||
const CancelCurrentIconButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const cancelCurrentQueueItem = useCancelCurrentQueueItem();
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
size="lg"
|
||||
isDisabled={shift ? clearQueue.isDisabled : cancelCurrentQueueItem.isDisabled}
|
||||
isLoading={shift ? clearQueue.isLoading : cancelCurrentQueueItem.isLoading}
|
||||
aria-label={shift ? t('queue.clear') : t('queue.cancel')}
|
||||
tooltip={shift ? t('queue.clearTooltip') : t('queue.cancelTooltip')}
|
||||
icon={shift ? <PiTrashSimpleBold /> : <PiXBold />}
|
||||
isDisabled={cancelCurrentQueueItem.isDisabled}
|
||||
isLoading={cancelCurrentQueueItem.isLoading}
|
||||
aria-label={t('queue.cancel')}
|
||||
tooltip={t('queue.cancelTooltip')}
|
||||
icon={<PiXBold />}
|
||||
colorScheme="error"
|
||||
onClick={shift ? clearQueue.openDialog : cancelCurrentQueueItem.cancelQueueItem}
|
||||
data-testid={shift ? t('queue.clear') : t('queue.cancel')}
|
||||
onClick={cancelCurrentQueueItem.cancelQueueItem}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
ClearQueueIconButton.displayName = 'ClearQueueIconButton';
|
||||
CancelCurrentIconButton.displayName = 'CancelCurrentIconButton';
|
||||
|
||||
const CancelAndClearAllIconButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const clearQueue = useClearQueueDialog();
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
size="lg"
|
||||
isDisabled={clearQueue.isDisabled}
|
||||
isLoading={clearQueue.isLoading}
|
||||
aria-label={t('queue.clear')}
|
||||
tooltip={t('queue.clearTooltip')}
|
||||
icon={<PiTrashSimpleBold />}
|
||||
colorScheme="error"
|
||||
onClick={clearQueue.openDialog}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
CancelAndClearAllIconButton.displayName = 'CancelAndClearAllIconButton';
|
||||
|
||||
const CancelAllExceptCurrentIconButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
size="lg"
|
||||
isDisabled={cancelAllExceptCurrent.isDisabled}
|
||||
isLoading={cancelAllExceptCurrent.isLoading}
|
||||
aria-label={t('queue.clear')}
|
||||
tooltip={t('queue.cancelAllExceptCurrentTooltip')}
|
||||
icon={<PiXCircle />}
|
||||
colorScheme="error"
|
||||
onClick={cancelAllExceptCurrent.openDialog}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
CancelAllExceptCurrentIconButton.displayName = 'CancelAllExceptCurrentIconButton';
|
||||
|
||||
@@ -27,6 +27,7 @@ export const QueueActionsMenuButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const isPauseEnabled = useFeatureStatus('pauseQueue');
|
||||
const isResumeEnabled = useFeatureStatus('resumeQueue');
|
||||
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
|
||||
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
|
||||
const cancelCurrent = useCancelCurrentQueueItem();
|
||||
const clearQueue = useClearQueueDialog();
|
||||
@@ -71,15 +72,17 @@ export const QueueActionsMenuButton = memo(() => {
|
||||
>
|
||||
{t('queue.cancelAllExceptCurrentTooltip')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
isDestructive
|
||||
icon={<PiTrashSimpleBold />}
|
||||
onClick={clearQueue.openDialog}
|
||||
isLoading={clearQueue.isLoading}
|
||||
isDisabled={clearQueue.isDisabled}
|
||||
>
|
||||
{t('queue.clearTooltip')}
|
||||
</MenuItem>
|
||||
{isCancelAndClearAllEnabled && (
|
||||
<MenuItem
|
||||
isDestructive
|
||||
icon={<PiTrashSimpleBold />}
|
||||
onClick={clearQueue.openDialog}
|
||||
isLoading={clearQueue.isLoading}
|
||||
isDisabled={clearQueue.isDisabled}
|
||||
>
|
||||
{t('queue.clearTooltip')}
|
||||
</MenuItem>
|
||||
)}
|
||||
{isResumeEnabled && (
|
||||
<MenuItem
|
||||
icon={<PiPlayFill />}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable i18next/no-literal-string */
|
||||
import { ButtonGroup, Flex } from '@invoke-ai/ui-library';
|
||||
import { CancelAllExceptCurrentButton } from 'features/queue/components/CancelAllExceptCurrentButton';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { memo } from 'react';
|
||||
|
||||
@@ -12,6 +13,8 @@ import ResumeProcessorButton from './ResumeProcessorButton';
|
||||
const QueueTabQueueControls = () => {
|
||||
const isPauseEnabled = useFeatureStatus('pauseQueue');
|
||||
const isResumeEnabled = useFeatureStatus('resumeQueue');
|
||||
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" layerStyle="first" borderRadius="base" p={2} gap={2}>
|
||||
<Flex gap={2}>
|
||||
@@ -25,7 +28,8 @@ const QueueTabQueueControls = () => {
|
||||
)}
|
||||
<ButtonGroup w={28} orientation="vertical" size="sm">
|
||||
<PruneQueueButton />
|
||||
<ClearQueueButton />
|
||||
{isCancelAndClearAllEnabled && <ClearQueueButton />}
|
||||
{!isCancelAndClearAllEnabled && <CancelAllExceptCurrentButton />}
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
<ClearModelCacheButton />
|
||||
|
||||
@@ -141,7 +141,7 @@ export const AppContent = memo(() => {
|
||||
)}
|
||||
<Panel id="main-panel" order={1} minSize={20} style={panelStyles}>
|
||||
<MainPanelContent />
|
||||
{withLeftPanel && <FloatingParametersPanelButtons panelApi={leftPanel} />}
|
||||
{withLeftPanel && <FloatingParametersPanelButtons togglePanel={leftPanel.toggle} />}
|
||||
{withRightPanel && <FloatingGalleryButton panelApi={rightPanel} />}
|
||||
</Panel>
|
||||
{withRightPanel && (
|
||||
|
||||
@@ -3,11 +3,12 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { ToolChooser } from 'features/controlLayers/components/Tool/ToolChooser';
|
||||
import { CanvasManagerProviderGate } from 'features/controlLayers/contexts/CanvasManagerProviderGate';
|
||||
import { useImageViewer } from 'features/gallery/components/ImageViewer/useImageViewer';
|
||||
import { useCancelAllExceptCurrentQueueItemDialog } from 'features/queue/components/CancelAllExceptCurrentQueueItemConfirmationAlertDialog';
|
||||
import { useClearQueueDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
|
||||
import { InvokeButtonTooltip } from 'features/queue/components/InvokeButtonTooltip/InvokeButtonTooltip';
|
||||
import { useCancelCurrentQueueItem } from 'features/queue/hooks/useCancelCurrentQueueItem';
|
||||
import { useInvoke } from 'features/queue/hooks/useInvoke';
|
||||
import type { UsePanelReturn } from 'features/ui/hooks/usePanel';
|
||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { selectActiveTab } from 'features/ui/store/uiSelectors';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -18,22 +19,53 @@ import {
|
||||
PiSparkleFill,
|
||||
PiTrashSimpleBold,
|
||||
PiXBold,
|
||||
PiXCircle,
|
||||
} from 'react-icons/pi';
|
||||
import { useGetQueueStatusQuery } from 'services/api/endpoints/queue';
|
||||
|
||||
type Props = {
|
||||
panelApi: UsePanelReturn;
|
||||
togglePanel: () => void;
|
||||
};
|
||||
|
||||
const FloatingSidePanelButtons = (props: Props) => {
|
||||
const FloatingSidePanelButtons = ({ togglePanel }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const tab = useAppSelector(selectActiveTab);
|
||||
const imageViewer = useImageViewer();
|
||||
const isCancelAndClearAllEnabled = useFeatureStatus('cancelAndClearAll');
|
||||
|
||||
return (
|
||||
<Flex pos="absolute" transform="translate(0, -50%)" top="50%" insetInlineStart={2} direction="column" gap={2}>
|
||||
{tab === 'canvas' && !imageViewer.isOpen && (
|
||||
<CanvasManagerProviderGate>
|
||||
<ToolChooser />
|
||||
</CanvasManagerProviderGate>
|
||||
)}
|
||||
<ButtonGroup orientation="vertical" h={48}>
|
||||
<Tooltip label={t('accessibility.toggleLeftPanel')} placement="end">
|
||||
<IconButton
|
||||
aria-label={t('accessibility.toggleLeftPanel')}
|
||||
onClick={togglePanel}
|
||||
icon={<PiSlidersHorizontalBold />}
|
||||
flexGrow={1}
|
||||
/>
|
||||
</Tooltip>
|
||||
<InvokeIconButton />
|
||||
<CancelCurrentIconButton />
|
||||
{/* Show the cancel all except current button instead of cancel and clear all when it is disabled */}
|
||||
{isCancelAndClearAllEnabled && <CancelAndClearAllIconButton />}
|
||||
{!isCancelAndClearAllEnabled && <CancelAllExceptCurrentIconButton />}
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(FloatingSidePanelButtons);
|
||||
|
||||
const InvokeIconButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const queue = useInvoke();
|
||||
const shift = useShiftModifier();
|
||||
const tab = useAppSelector(selectActiveTab);
|
||||
const imageViewer = useImageViewer();
|
||||
const clearQueue = useClearQueueDialog();
|
||||
const { data: queueStatus } = useGetQueueStatusQuery();
|
||||
const cancelCurrent = useCancelCurrentQueueItem();
|
||||
|
||||
const queueButtonIcon = useMemo(() => {
|
||||
const isProcessing = (queueStatus?.queue.in_progress ?? 0) > 0;
|
||||
@@ -47,59 +79,80 @@ const FloatingSidePanelButtons = (props: Props) => {
|
||||
}, [queue.isDisabled, queueStatus?.queue.in_progress, shift]);
|
||||
|
||||
return (
|
||||
<Flex pos="absolute" transform="translate(0, -50%)" top="50%" insetInlineStart={2} direction="column" gap={2}>
|
||||
{tab === 'canvas' && !imageViewer.isOpen && (
|
||||
<CanvasManagerProviderGate>
|
||||
<ToolChooser />
|
||||
</CanvasManagerProviderGate>
|
||||
)}
|
||||
<ButtonGroup orientation="vertical" h={48}>
|
||||
<Tooltip label={t('accessibility.toggleLeftPanel')} placement="end">
|
||||
<IconButton
|
||||
aria-label={t('accessibility.toggleLeftPanel')}
|
||||
onClick={props.panelApi.toggle}
|
||||
icon={<PiSlidersHorizontalBold />}
|
||||
flexGrow={1}
|
||||
/>
|
||||
</Tooltip>
|
||||
<InvokeButtonTooltip prepend={shift} placement="end">
|
||||
<IconButton
|
||||
aria-label={t('queue.queueBack')}
|
||||
onClick={shift ? queue.queueFront : queue.queueBack}
|
||||
isLoading={queue.isLoading}
|
||||
isDisabled={queue.isDisabled}
|
||||
icon={queueButtonIcon}
|
||||
colorScheme="invokeYellow"
|
||||
flexGrow={1}
|
||||
/>
|
||||
</InvokeButtonTooltip>
|
||||
<Tooltip label={t('queue.cancelTooltip')} placement="end">
|
||||
<IconButton
|
||||
isDisabled={cancelCurrent.isDisabled}
|
||||
isLoading={cancelCurrent.isLoading}
|
||||
aria-label={t('queue.cancelTooltip')}
|
||||
icon={<PiXBold />}
|
||||
onClick={cancelCurrent.cancelQueueItem}
|
||||
colorScheme="error"
|
||||
flexGrow={1}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip label={t('queue.clearTooltip')} placement="end">
|
||||
<IconButton
|
||||
isDisabled={clearQueue.isDisabled}
|
||||
isLoading={clearQueue.isLoading}
|
||||
aria-label={t('queue.clearTooltip')}
|
||||
icon={<PiTrashSimpleBold />}
|
||||
colorScheme="error"
|
||||
onClick={clearQueue.openDialog}
|
||||
data-testid={t('queue.clear')}
|
||||
flexGrow={1}
|
||||
/>
|
||||
</Tooltip>
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
<InvokeButtonTooltip prepend={shift} placement="end">
|
||||
<IconButton
|
||||
aria-label={t('queue.queueBack')}
|
||||
onClick={shift ? queue.queueFront : queue.queueBack}
|
||||
isLoading={queue.isLoading}
|
||||
isDisabled={queue.isDisabled}
|
||||
icon={queueButtonIcon}
|
||||
colorScheme="invokeYellow"
|
||||
flexGrow={1}
|
||||
/>
|
||||
</InvokeButtonTooltip>
|
||||
);
|
||||
};
|
||||
});
|
||||
InvokeIconButton.displayName = 'InvokeIconButton';
|
||||
|
||||
export default memo(FloatingSidePanelButtons);
|
||||
const CancelCurrentIconButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const cancelCurrentQueueItem = useCancelCurrentQueueItem();
|
||||
|
||||
return (
|
||||
<Tooltip label={t('queue.cancelTooltip')} placement="end">
|
||||
<IconButton
|
||||
isDisabled={cancelCurrentQueueItem.isDisabled}
|
||||
isLoading={cancelCurrentQueueItem.isLoading}
|
||||
aria-label={t('queue.cancelTooltip')}
|
||||
icon={<PiXBold />}
|
||||
onClick={cancelCurrentQueueItem.cancelQueueItem}
|
||||
colorScheme="error"
|
||||
flexGrow={1}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
||||
CancelCurrentIconButton.displayName = 'CancelCurrentIconButton';
|
||||
|
||||
const CancelAndClearAllIconButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const clearQueue = useClearQueueDialog();
|
||||
|
||||
return (
|
||||
<Tooltip label={t('queue.clearTooltip')} placement="end">
|
||||
<IconButton
|
||||
isDisabled={clearQueue.isDisabled}
|
||||
isLoading={clearQueue.isLoading}
|
||||
aria-label={t('queue.clearTooltip')}
|
||||
icon={<PiTrashSimpleBold />}
|
||||
colorScheme="error"
|
||||
onClick={clearQueue.openDialog}
|
||||
flexGrow={1}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
||||
CancelAndClearAllIconButton.displayName = 'CancelAndClearAllIconButton';
|
||||
|
||||
const CancelAllExceptCurrentIconButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const cancelAllExceptCurrent = useCancelAllExceptCurrentQueueItemDialog();
|
||||
|
||||
return (
|
||||
<Tooltip label={t('queue.cancelAllExceptCurrentTooltip')} placement="end">
|
||||
<IconButton
|
||||
isDisabled={cancelAllExceptCurrent.isDisabled}
|
||||
isLoading={cancelAllExceptCurrent.isLoading}
|
||||
aria-label={t('queue.clear')}
|
||||
icon={<PiXCircle />}
|
||||
colorScheme="error"
|
||||
onClick={cancelAllExceptCurrent.openDialog}
|
||||
flexGrow={1}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
||||
CancelAllExceptCurrentIconButton.displayName = 'CancelAllExceptCurrentIconButton';
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "5.8.0"
|
||||
__version__ = "5.8.1"
|
||||
|
||||
Reference in New Issue
Block a user