From 2740c7cdd582b5d67a0fc998df88f29700e2a08b Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Mon, 2 Feb 2026 03:31:01 -0800 Subject: [PATCH] Add expandable output stacks to assets list view (#8283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add expandable output stacks to the assets list view. Monolith ver. of https://github.com/Comfy-Org/ComfyUI_frontend/pull/8298 and its children List view currently collapses multi-output jobs into a single row, which makes sibling outputs easy to miss and causes selection/zoom behavior to drift once items are expanded elsewhere. This change adds a stack toggle to list rows, expands child outputs derived from job data, and keeps list-view selection and gallery navigation aligned with the expanded list. Output mapping and “load full outputs” checks are centralized so folder view and stacks share the same helper, and job-detail parsing now yields previewable outputs for the list view. Asset actions now prefer metadata prompt IDs to support the composite IDs used by stacked outputs. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8283-Add-expandable-output-stacks-to-assets-list-view-2f16d73d365081a99fc6f1519ac2e57c) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com> --- src/components/queue/QueueProgressOverlay.vue | 1 + .../sidebar/tabs/AssetsSidebarGridView.vue | 4 +- .../tabs/AssetsSidebarListView.stories.ts | 23 +- .../sidebar/tabs/AssetsSidebarListView.vue | 51 +++-- .../sidebar/tabs/AssetsSidebarTab.vue | 111 ++++------ .../assets/components/AssetsListItem.vue | 39 ++++ .../composables/useAssetSelection.test.ts | 74 +++++++ .../assets/composables/useAssetSelection.ts | 64 +++++- .../useAssetSelectionStore.test.ts | 23 +- .../composables/useAssetSelectionStore.ts | 11 +- .../composables/useMediaAssetActions.ts | 7 +- .../composables/useOutputStacks.test.ts | 205 ++++++++++++++++++ .../assets/composables/useOutputStacks.ts | 138 ++++++++++++ .../assets/utils/outputAssetUtil.test.ts | 153 +++++++++++++ src/platform/assets/utils/outputAssetUtil.ts | 109 ++++++++++ src/services/jobOutputCache.test.ts | 83 +++++++ src/services/jobOutputCache.ts | 71 ++++++ 17 files changed, 1054 insertions(+), 113 deletions(-) create mode 100644 src/platform/assets/composables/useOutputStacks.test.ts create mode 100644 src/platform/assets/composables/useOutputStacks.ts create mode 100644 src/platform/assets/utils/outputAssetUtil.test.ts create mode 100644 src/platform/assets/utils/outputAssetUtil.ts diff --git a/src/components/queue/QueueProgressOverlay.vue b/src/components/queue/QueueProgressOverlay.vue index 6267095939..1024dc0241 100644 --- a/src/components/queue/QueueProgressOverlay.vue +++ b/src/components/queue/QueueProgressOverlay.vue @@ -264,6 +264,7 @@ const focusAssetInSidebar = async (item: JobListItem) => { throw new Error('Asset not found in media assets panel') } assetSelectionStore.setSelection([assetId]) + assetSelectionStore.setLastSelectedAssetId(assetId) } const inspectJobAsset = wrapWithErrorHandlingAsync( diff --git a/src/components/sidebar/tabs/AssetsSidebarGridView.vue b/src/components/sidebar/tabs/AssetsSidebarGridView.vue index 6e015fe665..030f547c8c 100644 --- a/src/components/sidebar/tabs/AssetsSidebarGridView.vue +++ b/src/components/sidebar/tabs/AssetsSidebarGridView.vue @@ -2,7 +2,7 @@
@@ -70,12 +70,14 @@ import { useSettingStore } from '@/platform/settings/settingStore' const { assets, isSelected, + isInFolderView = false, assetType = 'output', showOutputCount, getOutputCount } = defineProps<{ assets: AssetItem[] isSelected: (assetId: string) => boolean + isInFolderView?: boolean assetType?: 'input' | 'output' showOutputCount: (asset: AssetItem) => boolean getOutputCount: (asset: AssetItem) => number diff --git a/src/components/sidebar/tabs/AssetsSidebarListView.stories.ts b/src/components/sidebar/tabs/AssetsSidebarListView.stories.ts index 2c50cab17c..f3c64e962a 100644 --- a/src/components/sidebar/tabs/AssetsSidebarListView.stories.ts +++ b/src/components/sidebar/tabs/AssetsSidebarListView.stories.ts @@ -1,7 +1,9 @@ import type { Meta, StoryObj } from '@storybook/vue3-vite' +import { toRef } from 'vue' import type { JobAction } from '@/composables/queue/useJobActions' import type { JobListItem } from '@/composables/queue/useJobList' +import { useOutputStacks } from '@/platform/assets/composables/useOutputStacks' import type { AssetItem } from '@/platform/assets/schemas/assetSchema' import { setMockJobActions } from '@/storybook/mocks/useJobActions' import { setMockJobItems } from '@/storybook/mocks/useJobList' @@ -138,16 +140,33 @@ function renderAssetsSidebarListView(args: StoryArgs) { setup() { setMockJobItems(args.jobs) setMockJobActions(args.actionsByJobId ?? {}) + const { assetItems, selectableAssets, isStackExpanded, toggleStack } = + useOutputStacks({ + assets: toRef(args, 'assets') + }) const selectedIds = new Set(args.selectedAssetIds ?? []) function isSelected(assetId: string) { return selectedIds.has(assetId) } - return { args, isSelected } + return { + args, + assetItems, + selectableAssets, + isSelected, + isStackExpanded, + toggleStack + } }, template: `
- +
` } diff --git a/src/components/sidebar/tabs/AssetsSidebarListView.vue b/src/components/sidebar/tabs/AssetsSidebarListView.vue index 76196e08d3..209a744f2c 100644 --- a/src/components/sidebar/tabs/AssetsSidebarListView.vue +++ b/src/components/sidebar/tabs/AssetsSidebarListView.vue @@ -40,7 +40,7 @@