mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 02:32:18 +00:00
fix: move queue assets action into filter controls (#8926)
## Summary Move the queue overlay "Show assets" action into the filter controls as an icon button, so the action is available inline with other list controls while keeping existing behavior. ## Changes - **What**: - Remove the full-width "Show assets" button from `QueueOverlayExpanded`. - Add a secondary icon button in `JobFiltersBar` with tooltip + aria-label and emit `showAssets` on click. - Wire `showAssets` from `JobFiltersBar` through `QueueOverlayExpanded` to the existing handler. - Add `JobFiltersBar` unit coverage to verify `showAssets` is emitted when the icon button is clicked. ## Review Focus - Verify the icon button placement in the filter row is sensible and discoverable. - Verify clicking the new button opens the assets panel as before. - Verify tooltip and accessibility label copy are correct. ## Screenshots (if applicable) Design: https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3924-38560&m=dev <img width="349" height="52" alt="Screenshot 2026-02-16 at 4 53 34 PM" src="https://github.com/user-attachments/assets/347772d6-5536-457a-a65f-de251e35a0e4" />
This commit is contained in:
@@ -9,23 +9,12 @@
|
|||||||
@clear-queued="$emit('clearQueued')"
|
@clear-queued="$emit('clearQueued')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="px-3">
|
|
||||||
<Button
|
|
||||||
class="w-full gap-1 justify-center"
|
|
||||||
variant="secondary"
|
|
||||||
size="sm"
|
|
||||||
@click="$emit('showAssets')"
|
|
||||||
>
|
|
||||||
<i class="icon-[comfy--image-ai-edit] size-4" />
|
|
||||||
<span>{{ t('sideToolbar.queueProgressOverlay.showAssets') }}</span>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<JobFiltersBar
|
<JobFiltersBar
|
||||||
:selected-job-tab="selectedJobTab"
|
:selected-job-tab="selectedJobTab"
|
||||||
:selected-workflow-filter="selectedWorkflowFilter"
|
:selected-workflow-filter="selectedWorkflowFilter"
|
||||||
:selected-sort-mode="selectedSortMode"
|
:selected-sort-mode="selectedSortMode"
|
||||||
:has-failed-jobs="hasFailedJobs"
|
:has-failed-jobs="hasFailedJobs"
|
||||||
|
@show-assets="$emit('showAssets')"
|
||||||
@update:selected-job-tab="$emit('update:selectedJobTab', $event)"
|
@update:selected-job-tab="$emit('update:selectedJobTab', $event)"
|
||||||
@update:selected-workflow-filter="
|
@update:selected-workflow-filter="
|
||||||
$emit('update:selectedWorkflowFilter', $event)
|
$emit('update:selectedWorkflowFilter', $event)
|
||||||
@@ -53,9 +42,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
|
||||||
|
|
||||||
import Button from '@/components/ui/button/Button.vue'
|
|
||||||
import type {
|
import type {
|
||||||
JobGroup,
|
JobGroup,
|
||||||
JobListItem,
|
JobListItem,
|
||||||
@@ -94,8 +81,6 @@ const emit = defineEmits<{
|
|||||||
(e: 'viewItem', item: JobListItem): void
|
(e: 'viewItem', item: JobListItem): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const currentMenuItem = ref<JobListItem | null>(null)
|
const currentMenuItem = ref<JobListItem | null>(null)
|
||||||
const jobContextMenuRef = ref<InstanceType<typeof JobContextMenu> | null>(null)
|
const jobContextMenuRef = ref<InstanceType<typeof JobContextMenu> | null>(null)
|
||||||
|
|
||||||
|
|||||||
79
src/components/queue/job/JobFiltersBar.test.ts
Normal file
79
src/components/queue/job/JobFiltersBar.test.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
vi.mock('primevue/popover', () => {
|
||||||
|
const PopoverStub = defineComponent({
|
||||||
|
name: 'Popover',
|
||||||
|
setup(_, { slots, expose }) {
|
||||||
|
expose({
|
||||||
|
hide: () => undefined,
|
||||||
|
toggle: (_event: Event) => undefined
|
||||||
|
})
|
||||||
|
return () => slots.default?.()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return { default: PopoverStub }
|
||||||
|
})
|
||||||
|
|
||||||
|
vi.mock('@/platform/distribution/types', () => ({
|
||||||
|
isCloud: false
|
||||||
|
}))
|
||||||
|
|
||||||
|
import JobFiltersBar from '@/components/queue/job/JobFiltersBar.vue'
|
||||||
|
|
||||||
|
const i18n = createI18n({
|
||||||
|
legacy: false,
|
||||||
|
locale: 'en',
|
||||||
|
messages: {
|
||||||
|
en: {
|
||||||
|
g: {
|
||||||
|
all: 'All',
|
||||||
|
completed: 'Completed'
|
||||||
|
},
|
||||||
|
queue: {
|
||||||
|
jobList: {
|
||||||
|
sortMostRecent: 'Most recent',
|
||||||
|
sortTotalGenerationTime: 'Total generation time'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sideToolbar: {
|
||||||
|
queueProgressOverlay: {
|
||||||
|
filterJobs: 'Filter jobs',
|
||||||
|
filterBy: 'Filter by',
|
||||||
|
sortJobs: 'Sort jobs',
|
||||||
|
sortBy: 'Sort by',
|
||||||
|
showAssets: 'Show assets',
|
||||||
|
showAssetsPanel: 'Show assets panel',
|
||||||
|
filterAllWorkflows: 'All workflows',
|
||||||
|
filterCurrentWorkflow: 'Current workflow'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('JobFiltersBar', () => {
|
||||||
|
it('emits showAssets when the assets icon button is clicked', async () => {
|
||||||
|
const wrapper = mount(JobFiltersBar, {
|
||||||
|
props: {
|
||||||
|
selectedJobTab: 'All',
|
||||||
|
selectedWorkflowFilter: 'all',
|
||||||
|
selectedSortMode: 'mostRecent',
|
||||||
|
hasFailedJobs: false
|
||||||
|
},
|
||||||
|
global: {
|
||||||
|
plugins: [i18n],
|
||||||
|
directives: { tooltip: () => undefined }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const showAssetsButton = wrapper.get(
|
||||||
|
'button[aria-label="Show assets panel"]'
|
||||||
|
)
|
||||||
|
await showAssetsButton.trigger('click')
|
||||||
|
|
||||||
|
expect(wrapper.emitted('showAssets')).toHaveLength(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -127,6 +127,15 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
<Button
|
||||||
|
v-tooltip.top="showAssetsTooltipConfig"
|
||||||
|
variant="secondary"
|
||||||
|
size="icon"
|
||||||
|
:aria-label="t('sideToolbar.queueProgressOverlay.showAssetsPanel')"
|
||||||
|
@click="$emit('showAssets')"
|
||||||
|
>
|
||||||
|
<i class="icon-[comfy--image-ai-edit] size-4" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -150,6 +159,7 @@ const props = defineProps<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
(e: 'showAssets'): void
|
||||||
(e: 'update:selectedJobTab', value: JobTab): void
|
(e: 'update:selectedJobTab', value: JobTab): void
|
||||||
(e: 'update:selectedWorkflowFilter', value: 'all' | 'current'): void
|
(e: 'update:selectedWorkflowFilter', value: 'all' | 'current'): void
|
||||||
(e: 'update:selectedSortMode', value: JobSortMode): void
|
(e: 'update:selectedSortMode', value: JobSortMode): void
|
||||||
@@ -165,6 +175,9 @@ const filterTooltipConfig = computed(() =>
|
|||||||
const sortTooltipConfig = computed(() =>
|
const sortTooltipConfig = computed(() =>
|
||||||
buildTooltipConfig(t('sideToolbar.queueProgressOverlay.sortBy'))
|
buildTooltipConfig(t('sideToolbar.queueProgressOverlay.sortBy'))
|
||||||
)
|
)
|
||||||
|
const showAssetsTooltipConfig = computed(() =>
|
||||||
|
buildTooltipConfig(t('sideToolbar.queueProgressOverlay.showAssets'))
|
||||||
|
)
|
||||||
|
|
||||||
// This can be removed when cloud implements /jobs and we switch to it.
|
// This can be removed when cloud implements /jobs and we switch to it.
|
||||||
const showWorkflowFilter = !isCloud
|
const showWorkflowFilter = !isCloud
|
||||||
|
|||||||
Reference in New Issue
Block a user