From 2ca98c8ae46fdc47e3a9b571bf655fca59fdc239 Mon Sep 17 00:00:00 2001 From: Simon Pinfold Date: Wed, 8 Apr 2026 17:37:49 +1200 Subject: [PATCH] fix: prefer job-level exports over asset filters Amp-Thread-ID: https://ampcode.com/threads/T-019d6a6f-e97a-7659-b41f-41763db3920a Co-authored-by: Amp --- .../composables/useMediaAssetActions.test.ts | 16 ++++++++++++++ .../composables/useMediaAssetActions.ts | 22 ++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/platform/assets/composables/useMediaAssetActions.test.ts b/src/platform/assets/composables/useMediaAssetActions.test.ts index dd1c0fc2b3..6fe64961d0 100644 --- a/src/platform/assets/composables/useMediaAssetActions.test.ts +++ b/src/platform/assets/composables/useMediaAssetActions.test.ts @@ -379,6 +379,22 @@ describe('useMediaAssetActions', () => { job2: ['img2.png'] }) }) + + it('should omit name filters when job-level and asset-level selections share a jobId', async () => { + const jobLevelAsset = createOutputAsset('a1', 'img1.png', 'job1', 3) + const assetLevelSelection = createOutputAsset('a2', 'img2.png', 'job1') + + const actions = useMediaAssetActions() + actions.downloadMultipleAssets([jobLevelAsset, assetLevelSelection]) + + await vi.waitFor(() => { + expect(mockCreateAssetExport).toHaveBeenCalledTimes(1) + }) + + const payload = mockCreateAssetExport.mock.calls[0][0] + expect(payload.job_ids).toEqual(['job1']) + expect(payload.job_asset_name_filters).toBeUndefined() + }) }) describe('downloadMultipleAssets - export toast file count', () => { diff --git a/src/platform/assets/composables/useMediaAssetActions.ts b/src/platform/assets/composables/useMediaAssetActions.ts index 2bcf4f2fac..458b5a1aae 100644 --- a/src/platform/assets/composables/useMediaAssetActions.ts +++ b/src/platform/assets/composables/useMediaAssetActions.ts @@ -154,13 +154,22 @@ export function useMediaAssetActions() { if (getAssetType(asset) === 'output') { const metadata = getOutputAssetMetadata(asset.user_metadata) const jobId = metadata?.jobId || asset.id + const outputCount = metadata?.outputCount + if (!jobIds.includes(jobId)) { jobIds.push(jobId) } + // Only add name filters when outputCount is unknown. // When outputCount is set, the asset is a job-level selection // from the gallery and the user wants all outputs for that job. - if (metadata?.jobId && asset.name && metadata.outputCount == null) { + if (typeof outputCount === 'number') { + delete jobAssetNameFilters[jobId] + } else if ( + metadata?.jobId && + asset.name && + !countedJobLevelIds.has(jobId) + ) { if (!jobAssetNameFilters[metadata.jobId]) { jobAssetNameFilters[metadata.jobId] = [] } @@ -173,12 +182,13 @@ export function useMediaAssetActions() { // represents a single job-wide export of outputCount files. Once a // job has been counted at the job level, skip any further assets // from the same jobId so mixed selections don't double-count. - const outputCount = metadata?.outputCount - if (countedJobLevelIds.has(jobId)) { + if (typeof outputCount === 'number') { + if (!countedJobLevelIds.has(jobId)) { + countedJobLevelIds.add(jobId) + fileCount += outputCount + } + } else if (countedJobLevelIds.has(jobId)) { // already counted at the job level, ignore this asset - } else if (typeof outputCount === 'number') { - fileCount += outputCount - countedJobLevelIds.add(jobId) } else { fileCount += 1 }