Rework queue button (#968)

* Move queue button to right side

* Rework split button

* Group

* Remove unused code

* x2 buttons

* Use primevue divider

* adjust style

* Add tooltip

* Update test

* Add clearing pending tasks button to queue bar

* Fix state

* Dropdown list fix
This commit is contained in:
Chenlei Hu
2024-09-25 11:55:50 +09:00
parent 59976ea357
commit 5ee0fd3519
10 changed files with 188 additions and 200 deletions

View File

@@ -1,73 +1,47 @@
<template>
<Panel v-if="visible" class="app-menu">
<div class="app-menu-content">
<Popover ref="queuePopover" data-testid="queue-options">
<div class="queue-options">
<p class="batch-count">
<FloatLabel v-tooltip="$t('menu.batchCountTooltip')">
<InputNumber id="batchCount" v-model="batchCount" :min="1" />
<label for="batchCount">{{ $t('menu.batchCount') }}</label>
</FloatLabel>
<Slider
v-model="batchCount"
:min="1"
:max="100"
v-tooltip="$t('menu.batchCountTooltip')"
<div class="app-menu-content flex align-center">
<div class="queue-button-group flex">
<SplitButton
class="comfyui-queue-button"
:label="activeQueueModeMenuItem.label"
:icon="activeQueueModeMenuItem.icon"
severity="primary"
@click="queuePrompt"
:model="queueModeMenuItems"
data-testid="queue-button"
v-tooltip.bottom="$t('menu.queueWorkflow')"
>
<template #item="{ item }">
<Button
:label="item.label"
:icon="item.icon"
:severity="item.key === queueMode ? 'primary' : 'secondary'"
text
v-tooltip="item.tooltip"
/>
</p>
<Divider layout="vertical" />
<p class="auto-queue">
<span class="label">{{ $t('menu.autoQueue') }}</span>
<template v-for="mode in queueModes" :key="mode">
<div
v-tooltip="$t(`menu.${mode}Tooltip`)"
class="auto-queue-mode"
>
<RadioButton
v-model="queueMode"
:inputId="`autoqueue-${mode}`"
name="dynamic"
:value="mode"
:data-testid="`autoqueue-${mode}`"
/>
<label :for="`autoqueue-${mode}`">{{
$t(`menu.${mode}`)
}}</label>
</div>
</template>
</p>
</div>
</Popover>
<SplitButton
v-tooltip.bottom="$t('menu.queueWorkflow')"
:label="$t('menu.generate')"
:icon="`pi pi-${icon}`"
severity="secondary"
@click="queuePrompt"
:model="[]"
:pt="{
pcDropdown: ({ instance }) => {
instance.onDropdownButtonClick = function (e: Event) {
e.preventDefault()
queuePopover.toggle(e)
}
}
}"
data-testid="queue-button"
>
</SplitButton>
<div class="separator"></div>
<Button
v-tooltip.bottom="$t('menu.interrupt')"
icon="pi pi-times"
severity="secondary"
:disabled="!executingPrompt"
@click="() => commandStore.getCommand('Comfy.Interrupt')()"
></Button>
</template>
</SplitButton>
<BatchCountEdit />
<ButtonGroup class="execution-actions ml-2">
<Button
v-tooltip.bottom="$t('menu.interrupt')"
icon="pi pi-times"
:severity="executingPrompt ? 'danger' : 'secondary'"
:disabled="!executingPrompt"
@click="() => commandStore.getCommand('Comfy.Interrupt')()"
>
</Button>
<Button
v-tooltip.bottom="$t('sideToolbar.queueTab.clearPendingTasks')"
icon="pi pi-stop"
:severity="hasPendingTasks ? 'danger' : 'secondary'"
:disabled="!hasPendingTasks"
@click="() => commandStore.getCommand('Comfy.ClearPendingTasks')()"
/>
</ButtonGroup>
</div>
<Divider layout="vertical" class="mx-2" />
<ButtonGroup>
<Button
v-tooltip.bottom="$t('menu.refresh')"
@@ -89,18 +63,15 @@
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
import { computed } from 'vue'
import Panel from 'primevue/panel'
import Divider from 'primevue/divider'
import SplitButton from 'primevue/splitbutton'
import Button from 'primevue/button'
import FloatLabel from 'primevue/floatlabel'
import InputNumber from 'primevue/inputnumber'
import Popover from 'primevue/popover'
import Divider from 'primevue/divider'
import Slider from 'primevue/slider'
import RadioButton from 'primevue/radiobutton'
import ButtonGroup from 'primevue/buttongroup'
import BatchCountEdit from './BatchCountEdit.vue'
import {
AutoQueueMode,
useQueuePendingTaskCountStore,
useQueueSettingsStore
} from '@/stores/queueStore'
@@ -108,6 +79,8 @@ import { app } from '@/scripts/app'
import { storeToRefs } from 'pinia'
import { useSettingStore } from '@/stores/settingStore'
import { useCommandStore } from '@/stores/commandStore'
import { MenuItem } from 'primevue/menuitem'
import { useI18n } from 'vue-i18n'
const settingsStore = useSettingStore()
const commandStore = useCommandStore()
@@ -118,21 +91,46 @@ const visible = computed(
() => settingsStore.get('Comfy.UseNewMenu') === 'Floating'
)
const queuePopover = ref(null)
const queueModes = ['disabled', 'instant', 'change']
const icon = computed(() => {
switch (queueMode.value) {
case 'instant':
return 'forward'
case 'change':
return 'step-forward-alt'
default:
return 'play'
const { t } = useI18n()
const queueModeMenuItemLookup: Record<AutoQueueMode, MenuItem> = {
disabled: {
key: 'disabled',
label: 'Queue',
icon: 'pi pi-play',
tooltip: t('menu.disabledTooltip'),
command: () => {
queueMode.value = 'disabled'
}
},
instant: {
key: 'instant',
label: 'Queue (Instant)',
icon: 'pi pi-forward',
tooltip: t('menu.instantTooltip'),
command: () => {
queueMode.value = 'instant'
}
},
change: {
key: 'change',
label: 'Queue (Change)',
icon: 'pi pi-step-forward-alt',
tooltip: t('menu.changeTooltip'),
command: () => {
queueMode.value = 'change'
}
}
})
}
const activeQueueModeMenuItem = computed(
() => queueModeMenuItemLookup[queueMode.value]
)
const queueModeMenuItems = computed(() =>
Object.values(queueModeMenuItemLookup)
)
const executingPrompt = computed(() => !!queueCountStore.count.value)
const hasPendingTasks = computed(() => queueCountStore.count.value > 1)
const queuePrompt = (e: MouseEvent) => {
app.queuePrompt(e.shiftKey ? -1 : 0, batchCount.value)
@@ -149,12 +147,6 @@ const queuePrompt = (e: MouseEvent) => {
z-index: 1000;
}
.app-menu-content {
display: flex;
gap: 10px;
align-items: center;
}
:deep(.p-panel-content) {
padding: 10px;
}
@@ -163,50 +155,8 @@ const queuePrompt = (e: MouseEvent) => {
display: none;
}
.separator {
background-color: var(--p-content-border-color);
border-radius: 10px;
opacity: 0.75;
width: 5px;
height: 20px;
}
.queue-options {
display: flex;
}
.batch-count {
padding-top: 0.75rem;
display: flex;
flex-direction: column;
gap: 1em;
}
.p-slider {
--p-slider-border-radius: 5px;
margin: 5px;
padding: 2px;
}
.p-floatlabel label {
left: 2px;
}
.label {
font-size: 12px;
color: var(--p-floatlabel-focus-color);
}
.auto-queue {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 6px;
}
.auto-queue-mode {
display: flex;
align-items: center;
gap: 5px;
.comfyui-queue-button :deep(.p-splitbutton-dropdown) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
</style>

View File

@@ -0,0 +1,69 @@
<template>
<div
class="batch-count"
:class="props.class"
v-tooltip.bottom="$t('menu.batchCount')"
>
<InputNumber
class="w-14"
v-model="batchCount"
:min="minQueueCount"
:max="maxQueueCount"
fluid
showButtons
:pt="{
incrementButton: {
class: 'w-6',
onmousedown: () => {
handleClick(true)
}
},
decrementButton: {
class: 'w-6',
onmousedown: () => {
handleClick(false)
}
}
}"
/>
</div>
</template>
<script lang="ts" setup>
import { useQueueSettingsStore } from '@/stores/queueStore'
import { storeToRefs } from 'pinia'
import InputNumber from 'primevue/inputnumber'
interface Props {
class?: string
}
const props = withDefaults(defineProps<Props>(), {
class: ''
})
const queueSettingsStore = useQueueSettingsStore()
const { batchCount } = storeToRefs(queueSettingsStore)
const minQueueCount = 1
const maxQueueCount = 100
const handleClick = (increment: boolean) => {
let newCount: number
if (increment) {
const originalCount = batchCount.value - 1
newCount = originalCount * 2
} else {
const originalCount = batchCount.value + 1
newCount = Math.floor(originalCount / 2)
}
batchCount.value = newCount
}
</script>
<style scoped>
:deep(.p-inputtext) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
</style>

View File

@@ -34,11 +34,10 @@
<Button
v-if="queueStore.hasPendingTasks"
icon="pi pi-stop"
text
severity="danger"
@click="clearPendingTasks"
class="clear-pending-button"
v-tooltip="$t('sideToolbar.queueTab.clearPendingTasks')"
text
@click="() => commandStore.getCommand('Comfy.ClearPendingTasks')()"
v-tooltip.bottom="$t('sideToolbar.queueTab.clearPendingTasks')"
/>
<Button
icon="pi pi-trash"
@@ -109,6 +108,7 @@ import { TaskItemImpl, useQueueStore } from '@/stores/queueStore'
import { api } from '@/scripts/api'
import { ComfyNode } from '@/types/comfyWorkflow'
import { useSettingStore } from '@/stores/settingStore'
import { useCommandStore } from '@/stores/commandStore'
import { app } from '@/scripts/app'
const IMAGE_FIT = 'Comfy.Queue.ImageFit'
@@ -116,6 +116,7 @@ const confirm = useConfirm()
const toast = useToast()
const queueStore = useQueueStore()
const settingStore = useSettingStore()
const commandStore = useCommandStore()
const { t } = useI18n()
// Expanded view: show all outputs in a flat list.
@@ -230,16 +231,6 @@ const confirmRemoveAll = (event: Event) => {
})
}
const clearPendingTasks = async () => {
await queueStore.clear(['queue'])
toast.add({
severity: 'info',
summary: 'Confirmed',
detail: 'Pending tasks deleted',
life: 3000
})
}
const onStatus = async () => {
await queueStore.update()
updateVisibleTasks()