mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 22:09:37 +00:00
## Summary Address follow-up review feedback from #8740 by consolidating completed-banner thumbnail fields and tightening queue count sanitization. ## Changes - **What**: - Consolidated completed notification thumbnail data to `thumbnailUrls` only by removing legacy `thumbnailUrl` support from the queue banner notification type and renderer. - Updated queue notification banner stories to use `thumbnailUrls` consistently. - Simplified `sanitizeCount` to treat any non-positive or non-number value as the fallback count (`1`). ## Review Focus Confirm the completed notification payload shape is now consistently `thumbnailUrls` and no consumer relies on `thumbnailUrl`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8880-fix-queue-address-follow-up-review-comments-from-8740-3076d73d365081719a70d860691c5f05) by [Unito](https://www.unito.io)
150 lines
4.0 KiB
Vue
150 lines
4.0 KiB
Vue
<template>
|
|
<div class="inline-flex overflow-hidden rounded-lg bg-secondary-background">
|
|
<div class="flex items-center gap-2 p-1 pr-3">
|
|
<div
|
|
:class="
|
|
cn(
|
|
'relative shrink-0 items-center rounded-[4px]',
|
|
showsCompletionPreview && showThumbnails
|
|
? 'flex h-8 overflow-visible p-0'
|
|
: showsCompletionPreview
|
|
? 'flex size-8 justify-center overflow-hidden p-0'
|
|
: 'flex size-8 justify-center p-1'
|
|
)
|
|
"
|
|
>
|
|
<template v-if="showThumbnails">
|
|
<div class="flex h-8 shrink-0 items-center">
|
|
<div
|
|
v-for="(thumbnailUrl, index) in thumbnailUrls"
|
|
:key="`completion-preview-${index}`"
|
|
:class="
|
|
cn(
|
|
'relative size-8 shrink-0 overflow-hidden rounded-[4px]',
|
|
index > 0 && '-ml-3 ring-2 ring-secondary-background'
|
|
)
|
|
"
|
|
>
|
|
<img
|
|
:src="thumbnailUrl"
|
|
:alt="t('sideToolbar.queueProgressOverlay.preview')"
|
|
class="size-full object-cover"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<div
|
|
v-else-if="showCompletionGradientFallback"
|
|
class="size-full bg-linear-to-br from-coral-500 via-coral-500 to-azure-600"
|
|
/>
|
|
<i
|
|
v-else
|
|
:class="cn(iconClass, 'size-4', iconColorClass)"
|
|
aria-hidden="true"
|
|
/>
|
|
</div>
|
|
<div class="flex h-full items-center">
|
|
<span
|
|
class="overflow-hidden text-ellipsis text-center font-inter text-[12px] leading-normal font-normal text-base-foreground"
|
|
>
|
|
{{ bannerText }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import type { QueueNotificationBanner } from '@/composables/queue/useQueueNotificationBanners'
|
|
import { cn } from '@/utils/tailwindUtil'
|
|
|
|
const { notification } = defineProps<{
|
|
notification: QueueNotificationBanner
|
|
}>()
|
|
|
|
const { t, n } = useI18n()
|
|
|
|
const thumbnailUrls = computed(() => {
|
|
if (notification.type !== 'completed') {
|
|
return []
|
|
}
|
|
return notification.thumbnailUrls?.slice(0, 2) ?? []
|
|
})
|
|
|
|
const showThumbnails = computed(() => {
|
|
if (notification.type !== 'completed') {
|
|
return false
|
|
}
|
|
return thumbnailUrls.value.length > 0
|
|
})
|
|
|
|
const showCompletionGradientFallback = computed(
|
|
() => notification.type === 'completed' && !showThumbnails.value
|
|
)
|
|
|
|
const showsCompletionPreview = computed(
|
|
() => showThumbnails.value || showCompletionGradientFallback.value
|
|
)
|
|
|
|
const bannerText = computed(() => {
|
|
const count = notification.count
|
|
if (notification.type === 'queuedPending') {
|
|
return t('queue.jobQueueing')
|
|
}
|
|
if (notification.type === 'queued') {
|
|
if (count === 1) {
|
|
return t('queue.jobAddedToQueue')
|
|
}
|
|
return t(
|
|
'sideToolbar.queueProgressOverlay.jobsAddedToQueue',
|
|
{ count: n(count) },
|
|
count
|
|
)
|
|
}
|
|
if (notification.type === 'failed') {
|
|
if (count === 1) {
|
|
return t('sideToolbar.queueProgressOverlay.jobFailed')
|
|
}
|
|
return t(
|
|
'sideToolbar.queueProgressOverlay.jobsFailed',
|
|
{ count: n(count) },
|
|
count
|
|
)
|
|
}
|
|
if (count === 1) {
|
|
return t('sideToolbar.queueProgressOverlay.jobCompleted')
|
|
}
|
|
return t(
|
|
'sideToolbar.queueProgressOverlay.jobsCompleted',
|
|
{ count: n(count) },
|
|
count
|
|
)
|
|
})
|
|
|
|
const iconClass = computed(() => {
|
|
if (notification.type === 'queuedPending') {
|
|
return 'icon-[lucide--loader-circle]'
|
|
}
|
|
if (notification.type === 'queued') {
|
|
return 'icon-[lucide--check]'
|
|
}
|
|
if (notification.type === 'failed') {
|
|
return 'icon-[lucide--circle-alert]'
|
|
}
|
|
return 'icon-[lucide--image]'
|
|
})
|
|
|
|
const iconColorClass = computed(() => {
|
|
if (notification.type === 'queuedPending') {
|
|
return 'animate-spin text-slate-100'
|
|
}
|
|
if (notification.type === 'failed') {
|
|
return 'text-danger-200'
|
|
}
|
|
return 'text-slate-100'
|
|
})
|
|
</script>
|