fix: move clear queued controls into queue header (#8920)

## Summary
- Move queued-count summary and clear-queued action into the Queue Overlay header so controls remain visible while expanded content scrolls.

## What changed
- `QueueOverlayExpanded.vue`
  - Passes `queuedCount` and `clearQueued` through to the header.
  - Removes duplicated summary/action content from the lower section.
- `QueueOverlayHeader.vue`
  - Accepts new header data/actions for queued count and clear behavior.
  - Renders queued summary and clear button beside the title.
  - Adjusts layout to support persistent header actions.
- Updated header unit tests to cover queued summary rendering and clear action behavior.

## Testing
- Header unit tests were updated for the new behavior.
- No additional test execution was requested.

## Notes
- UI composition change only; queue execution semantics are unchanged.

Design: https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3924-38560&m=dev

<img width="356" height="59" alt="Screenshot 2026-02-16 at 3 30 44 PM" src="https://github.com/user-attachments/assets/987e42bd-9e24-4e65-9158-3f96b5338199" />
This commit is contained in:
Benjamin Lu
2026-02-16 18:03:52 -08:00
committed by GitHub
parent 2ca0c30cf7
commit 3dba245dd3
3 changed files with 49 additions and 24 deletions

View File

@@ -4,12 +4,14 @@
:header-title="headerTitle"
:show-concurrent-indicator="showConcurrentIndicator"
:concurrent-workflow-count="concurrentWorkflowCount"
:queued-count="queuedCount"
@clear-history="$emit('clearHistory')"
@clear-queued="$emit('clearQueued')"
/>
<div class="flex items-center justify-between px-3">
<div class="px-3">
<Button
class="grow gap-1 justify-center"
class="w-full gap-1 justify-center"
variant="secondary"
size="sm"
@click="$emit('showAssets')"
@@ -17,26 +19,6 @@
<i class="icon-[comfy--image-ai-edit] size-4" />
<span>{{ t('sideToolbar.queueProgressOverlay.showAssets') }}</span>
</Button>
<div class="ml-4 inline-flex items-center">
<div
class="inline-flex h-6 items-center text-[12px] leading-none text-text-primary opacity-90"
>
<span class="font-bold">{{ queuedCount }}</span>
<span class="ml-1">{{
t('sideToolbar.queueProgressOverlay.queuedSuffix')
}}</span>
</div>
<Button
v-if="queuedCount > 0"
class="ml-2"
variant="destructive"
size="icon"
:aria-label="t('sideToolbar.queueProgressOverlay.clearQueued')"
@click="$emit('clearQueued')"
>
<i class="icon-[lucide--list-x] size-4" />
</Button>
</div>
</div>
<JobFiltersBar

View File

@@ -40,6 +40,8 @@ const i18n = createI18n({
sideToolbar: {
queueProgressOverlay: {
running: 'running',
queuedSuffix: 'queued',
clearQueued: 'Clear queued',
moreOptions: 'More options',
clearHistory: 'Clear history'
}
@@ -54,6 +56,7 @@ const mountHeader = (props = {}) =>
headerTitle: 'Job queue',
showConcurrentIndicator: true,
concurrentWorkflowCount: 2,
queuedCount: 3,
...props
},
global: {
@@ -80,6 +83,25 @@ describe('QueueOverlayHeader', () => {
expect(wrapper.find('.inline-flex.items-center.gap-1').exists()).toBe(false)
})
it('shows queued summary and emits clear queued', async () => {
const wrapper = mountHeader({ queuedCount: 4 })
expect(wrapper.text()).toContain('4')
expect(wrapper.text()).toContain('queued')
const clearQueuedButton = wrapper.get('button[aria-label="Clear queued"]')
await clearQueuedButton.trigger('click')
expect(wrapper.emitted('clearQueued')).toHaveLength(1)
})
it('hides clear queued button when queued count is zero', () => {
const wrapper = mountHeader({ queuedCount: 0 })
expect(wrapper.find('button[aria-label="Clear queued"]').exists()).toBe(
false
)
})
it('toggles popover and emits clear history', async () => {
const spy = vi.spyOn(tooltipConfig, 'buildTooltipConfig')

View File

@@ -1,8 +1,8 @@
<template>
<div
class="flex h-12 items-center justify-between gap-2 border-b border-interface-stroke px-2"
class="flex h-12 items-center gap-2 border-b border-interface-stroke px-2"
>
<div class="px-2 text-[14px] font-normal text-text-primary">
<div class="min-w-0 flex-1 px-2 text-[14px] font-normal text-text-primary">
<span>{{ headerTitle }}</span>
<span
v-if="showConcurrentIndicator"
@@ -17,6 +17,25 @@
</span>
</span>
</div>
<div
class="inline-flex h-6 items-center gap-2 text-[12px] leading-none text-text-primary"
>
<span class="opacity-90">
<span class="font-bold">{{ queuedCount }}</span>
<span class="ml-1">{{
t('sideToolbar.queueProgressOverlay.queuedSuffix')
}}</span>
</span>
<Button
v-if="queuedCount > 0"
variant="destructive"
size="icon"
:aria-label="t('sideToolbar.queueProgressOverlay.clearQueued')"
@click="$emit('clearQueued')"
>
<i class="icon-[lucide--list-x] size-4" />
</Button>
</div>
<div v-if="!isCloud" class="flex items-center gap-1">
<Button
v-tooltip.top="moreTooltipConfig"
@@ -78,10 +97,12 @@ defineProps<{
headerTitle: string
showConcurrentIndicator: boolean
concurrentWorkflowCount: number
queuedCount: number
}>()
const emit = defineEmits<{
(e: 'clearHistory'): void
(e: 'clearQueued'): void
}>()
const { t } = useI18n()