[QPOv2] Add media assets viewmode toggle (#7729)

Adds a button to toggle the view mode of the media assets panel

<img width="530" height="326" alt="image"
src="https://github.com/user-attachments/assets/0946e87d-03b0-4606-9142-ac18aae89ecc"
/>

Part of the QPO v2 iteration, figma design can be found
[here](https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3330-37286&m=dev).
This will be implemented in a series of stacked PRs that can be reviewed
and merged individually.

main <-- #7729, #7731, #7737, #7743, #7745

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7729-QPOv2-Add-media-assets-viewmode-toggle-2d16d73d365081e5b641efce5a5c1662)
by [Unito](https://www.unito.io)
This commit is contained in:
Benjamin Lu
2026-01-06 12:24:41 -08:00
committed by GitHub
parent 14d0ec73f6
commit 372890811d
8 changed files with 101 additions and 3 deletions

View File

@@ -47,6 +47,7 @@
<MediaAssetFilterBar
v-model:search-query="searchQuery"
v-model:sort-by="sortBy"
v-model:view-mode="viewMode"
v-model:media-type-filters="mediaTypeFilters"
class="pb-1 px-2 2xl:px-4"
:show-generation-time-sort="activeTab === 'output'"
@@ -198,6 +199,7 @@ const activeTab = ref<'input' | 'output'>('output')
const folderPromptId = ref<string | null>(null)
const folderExecutionTime = ref<number | undefined>(undefined)
const isInFolderView = computed(() => folderPromptId.value !== null)
const viewMode = ref<'list' | 'grid'>('grid')
// Track which asset's context menu is open (for single-instance context menu management)
const openContextMenuId = ref<string | null>(null)

View File

@@ -67,7 +67,6 @@ import { useWorkflowTemplateSelectorDialog } from './useWorkflowTemplateSelector
const { isActiveSubscription, showSubscriptionDialog } = useSubscription()
const moveSelectedNodesVersionAdded = '1.22.2'
export function useCoreCommands(): ComfyCommand[] {
const workflowService = useWorkflowService()
const workflowStore = useWorkflowStore()
@@ -79,6 +78,7 @@ export function useCoreCommands(): ComfyCommand[] {
const executionStore = useExecutionStore()
const telemetry = useTelemetry()
const { staticUrls, buildDocsUrl } = useExternalLink()
const settingStore = useSettingStore()
const bottomPanelStore = useBottomPanelStore()
@@ -86,6 +86,14 @@ export function useCoreCommands(): ComfyCommand[] {
useSelectedLiteGraphItems()
const getTracker = () => workflowStore.activeWorkflow?.changeTracker
function isQueuePanelV2Enabled() {
return settingStore.get('Comfy.Queue.QPOV2')
}
async function toggleQueuePanelV2() {
await settingStore.set('Comfy.Queue.QPOV2', !isQueuePanelV2Enabled())
}
const moveSelectedNodes = (
positionUpdater: (pos: Point, gridSize: number) => Point
) => {
@@ -1191,6 +1199,12 @@ export function useCoreCommands(): ComfyCommand[] {
await useWorkflowService().reloadCurrentWorkflow() // ensure changes take effect immediately
}
},
{
id: 'Comfy.ToggleQPOV2',
icon: 'pi pi-list',
label: 'Toggle Queue Panel V2',
function: toggleQueuePanelV2
},
{
id: 'Comfy.ToggleLinear',
icon: 'pi pi-database',

View File

@@ -263,6 +263,9 @@
"Comfy_ToggleLinear": {
"label": "toggle linear mode"
},
"Comfy_ToggleQPOV2": {
"label": "Toggle Queue Panel V2"
},
"Comfy_ToggleTheme": {
"label": "Toggle Theme (Dark/Light)"
},
@@ -327,4 +330,4 @@
"label": "Toggle Workflows Sidebar",
"tooltip": "Workflows"
}
}
}

View File

@@ -721,6 +721,8 @@
"colonPercent": ": {percent}",
"currentNode": "Current node:",
"viewAllJobs": "View all jobs",
"viewList": "List view",
"viewGrid": "Grid view",
"running": "running",
"preview": "Preview",
"interruptAll": "Interrupt all running jobs",
@@ -2468,4 +2470,4 @@
"recentReleases": "Recent releases",
"helpCenterMenu": "Help Center Menu"
}
}
}

View File

@@ -31,18 +31,26 @@
/>
</template>
</AssetSortButton>
<MediaAssetViewModeToggle
v-if="isQueuePanelV2Enabled"
v-model:view-mode="viewMode"
/>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import SearchBox from '@/components/common/SearchBox.vue'
import { isCloud } from '@/platform/distribution/types'
import { useSettingStore } from '@/platform/settings/settingStore'
import MediaAssetFilterButton from './MediaAssetFilterButton.vue'
import MediaAssetFilterMenu from './MediaAssetFilterMenu.vue'
import AssetSortButton from './MediaAssetSortButton.vue'
import MediaAssetSortMenu from './MediaAssetSortMenu.vue'
import type { SortBy } from './MediaAssetSortMenu.vue'
import MediaAssetViewModeToggle from './MediaAssetViewModeToggle.vue'
const { showGenerationTimeSort = false } = defineProps<{
searchQuery: string
@@ -56,6 +64,12 @@ const emit = defineEmits<{
}>()
const sortBy = defineModel<SortBy>('sortBy', { required: true })
const viewMode = defineModel<'list' | 'grid'>('viewMode', { required: true })
const settingStore = useSettingStore()
const isQueuePanelV2Enabled = computed(() =>
settingStore.get('Comfy.Queue.QPOV2')
)
const handleSearchChange = (value: string | undefined) => {
emit('update:searchQuery', value ?? '')

View File

@@ -0,0 +1,54 @@
<template>
<div
class="inline-flex items-center gap-1 rounded-lg bg-secondary-background p-1"
role="group"
>
<Button
type="button"
variant="muted-textonly"
size="icon"
:aria-label="t('sideToolbar.queueProgressOverlay.viewList')"
:aria-pressed="viewMode === 'list'"
:class="
cn(
'rounded-lg',
viewMode === 'list'
? 'bg-secondary-background-selected text-text-primary hover:bg-secondary-background-selected'
: 'text-text-secondary hover:bg-secondary-background-hover'
)
"
@click="viewMode = 'list'"
>
<i class="icon-[lucide--table-of-contents] size-4" />
</Button>
<Button
type="button"
variant="muted-textonly"
size="icon"
:aria-label="t('sideToolbar.queueProgressOverlay.viewGrid')"
:aria-pressed="viewMode === 'grid'"
:class="
cn(
'rounded-lg',
viewMode === 'grid'
? 'bg-secondary-background-selected text-text-primary hover:bg-secondary-background-selected'
: 'text-text-secondary hover:bg-secondary-background-hover'
)
"
@click="viewMode = 'grid'"
>
<i class="icon-[lucide--layout-grid] size-4" />
</Button>
</div>
</template>
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import Button from '@/components/ui/button/Button.vue'
import { cn } from '@/utils/tailwindUtil'
const viewMode = defineModel<'list' | 'grid'>('viewMode', { required: true })
const { t } = useI18n()
</script>

View File

@@ -1139,5 +1139,13 @@ export const CORE_SETTINGS: SettingParams[] = [
type: 'hidden',
defaultValue: false,
versionAdded: '1.34.1'
},
{
id: 'Comfy.Queue.QPOV2',
name: 'Queue Panel V2',
type: 'hidden',
tooltip: 'Enable the new Assets Panel design with list/grid view toggle',
defaultValue: false,
experimental: true
}
]

View File

@@ -503,6 +503,7 @@ const zSettings = z.object({
'Comfy.VueNodes.Enabled': z.boolean(),
'Comfy.VueNodes.AutoScaleLayout': z.boolean(),
'Comfy.Assets.UseAssetAPI': z.boolean(),
'Comfy.Queue.QPOV2': z.boolean(),
'Comfy-Desktop.AutoUpdate': z.boolean(),
'Comfy-Desktop.SendStatistics': z.boolean(),
'Comfy-Desktop.WindowStyle': z.string(),