mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-04 21:22:07 +00:00
## Summary
- Running jobs now show cancel button at all times (always visible, not
just on hover)
- Cancel/delete buttons use destructive red styling by default with
hover state
- Changed pending job icon from clock to loader-circle with spin
animation
- Fixed icon buttons to be square (size-6) instead of rectangular
- Added TODO comment for future declarative button config system
- Pending hint ("Job added to queue") now shows only once per entry and
no longer resets when other jobs update
- Spinner animation now applies only to the pending loader icon;
completed/check icons no longer spin
- Queue overlay hover/active state also triggers when hovering the top
menu bar so controls stay visible
## Design Spec
https://www.notion.so/comfy-org/Design-Queue-Dialog-Job-Ordering-and-Cancel-Button-Visibility-2b46d73d365081748a43d5cc9fbe2639
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6893-feat-Improve-queue-job-item-UX-based-on-design-feedback-2b56d73d365081a2bc7ef6f6fea1c739)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
126 lines
4.2 KiB
Vue
126 lines
4.2 KiB
Vue
<template>
|
|
<div class="flex flex-col gap-3 p-2">
|
|
<div class="flex flex-col gap-1">
|
|
<div
|
|
class="relative h-2 w-full overflow-hidden rounded-full border border-interface-stroke bg-interface-panel-surface"
|
|
>
|
|
<div
|
|
class="absolute inset-0 h-full rounded-full transition-[width]"
|
|
:style="totalProgressStyle"
|
|
/>
|
|
<div
|
|
class="absolute inset-0 h-full rounded-full transition-[width]"
|
|
:style="currentNodeProgressStyle"
|
|
/>
|
|
</div>
|
|
<div class="flex items-start justify-end gap-4 text-[12px] leading-none">
|
|
<div class="flex items-center gap-1 text-text-primary opacity-90">
|
|
<i18n-t keypath="sideToolbar.queueProgressOverlay.total">
|
|
<template #percent>
|
|
<span class="font-bold">{{ totalPercentFormatted }}</span>
|
|
</template>
|
|
</i18n-t>
|
|
</div>
|
|
<div class="flex items-center gap-1 text-text-secondary">
|
|
<span>{{ t('sideToolbar.queueProgressOverlay.currentNode') }}</span>
|
|
<span class="inline-block max-w-[10rem] truncate">{{
|
|
currentNodeName
|
|
}}</span>
|
|
<span class="flex items-center gap-1">
|
|
<span>{{ currentNodePercentFormatted }}</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div :class="bottomRowClass">
|
|
<div class="flex items-center gap-4 text-[12px] text-text-primary">
|
|
<div class="flex items-center gap-2">
|
|
<span class="opacity-90">
|
|
<span class="font-bold">{{ runningCount }}</span>
|
|
<span class="ml-1">{{
|
|
t('sideToolbar.queueProgressOverlay.running')
|
|
}}</span>
|
|
</span>
|
|
<IconButton
|
|
v-if="runningCount > 0"
|
|
v-tooltip.top="cancelJobTooltip"
|
|
type="secondary"
|
|
size="sm"
|
|
class="size-6 bg-destructive-background hover:bg-destructive-background-hover"
|
|
:aria-label="t('sideToolbar.queueProgressOverlay.interruptAll')"
|
|
@click="$emit('interruptAll')"
|
|
>
|
|
<i
|
|
class="icon-[lucide--x] block size-4 leading-none text-text-primary"
|
|
/>
|
|
</IconButton>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2">
|
|
<span class="opacity-90">
|
|
<span class="font-bold">{{ queuedCount }}</span>
|
|
<span class="ml-1">{{
|
|
t('sideToolbar.queueProgressOverlay.queuedSuffix')
|
|
}}</span>
|
|
</span>
|
|
<IconButton
|
|
v-if="queuedCount > 0"
|
|
v-tooltip.top="clearQueueTooltip"
|
|
type="secondary"
|
|
size="sm"
|
|
class="size-6 bg-secondary-background hover:bg-destructive-background"
|
|
:aria-label="t('sideToolbar.queueProgressOverlay.clearQueued')"
|
|
@click="$emit('clearQueued')"
|
|
>
|
|
<i
|
|
class="icon-[lucide--list-x] block size-4 leading-none text-text-primary"
|
|
/>
|
|
</IconButton>
|
|
</div>
|
|
</div>
|
|
|
|
<TextButton
|
|
class="h-6 min-w-[120px] flex-1 px-2 py-0 text-[12px]"
|
|
type="secondary"
|
|
:label="t('sideToolbar.queueProgressOverlay.viewAllJobs')"
|
|
@click="$emit('viewAllJobs')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import IconButton from '@/components/button/IconButton.vue'
|
|
import TextButton from '@/components/button/TextButton.vue'
|
|
import { buildTooltipConfig } from '@/composables/useTooltipConfig'
|
|
|
|
defineProps<{
|
|
totalProgressStyle: Record<string, string>
|
|
currentNodeProgressStyle: Record<string, string>
|
|
totalPercentFormatted: string
|
|
currentNodePercentFormatted: string
|
|
currentNodeName: string
|
|
runningCount: number
|
|
queuedCount: number
|
|
bottomRowClass: string
|
|
}>()
|
|
|
|
defineEmits<{
|
|
(e: 'interruptAll'): void
|
|
(e: 'clearQueued'): void
|
|
(e: 'viewAllJobs'): void
|
|
}>()
|
|
|
|
const { t } = useI18n()
|
|
const cancelJobTooltip = computed(() =>
|
|
buildTooltipConfig(t('sideToolbar.queueProgressOverlay.cancelJobTooltip'))
|
|
)
|
|
const clearQueueTooltip = computed(() =>
|
|
buildTooltipConfig(t('sideToolbar.queueProgressOverlay.clearQueueTooltip'))
|
|
)
|
|
</script>
|