fix(assets): strip directory annotation from input filenames (#12086)

## Summary

Imported assets render as a generic check-check icon instead of a
thumbnail because the OSS `/internal/files/{type}` endpoint returns
annotated filenames (`photo.png [input]`) that the assets-sidebar mapper
passes through verbatim, which breaks extension-based media-type
detection.

## Changes

- **What**: Strip ComfyUI's trailing directory-type annotation (`
[input]`, ` [output]`, `[temp]`) in `mapInputFileToAssetItem` so `name`,
`id`, and the generated `/view?filename=…` URL all use the canonical
on-disk filename. Adds a focused unit test.
- **Breaking**: None.
- **Dependencies**: None.

## Review Focus

### Root cause

ComfyUI core PR
[comfyanonymous/ComfyUI#13078](https://github.com/comfyanonymous/ComfyUI/pull/13078)
(April 2026) changed `/internal/files/{type}` to append the directory
type to each entry:

```python
# api_server/routes/internal/internal_routes.py
return web.json_response(
    [f"{entry.name} [{directory_type}]" for entry in sorted_files], status=200
)
```

The annotation is the wire format `LoadImage`-style widgets expect, so
the backend change is correct. The assets-sidebar mapper treated the
response strings as raw filenames. After
[#8914](https://github.com/Comfy-Org/ComfyUI_frontend/pull/8914) changed
`getMediaTypeFromFilename` to default unknown extensions to `'other'`,
every input asset now routes to `MediaOtherTop` and renders as
`icon-[lucide--check-check]`:

```
getMediaTypeFromFilename("photo.png [input]").split('.').pop() === "png [input]" → 'other'
```

The strip happens at data ingestion so every consumer of
`AssetItem.name` (sidebar grid, list, filter, gallery, drag-drop,
delete) gets the canonical filename automatically. OSS-only — Cloud
paths get clean names from the cloud API and are unaffected.

Reproduces locally on stock OSS ComfyUI on `main` of both repos; no
public issue tracker entry.

## Screenshots (if applicable)
Before:
<img width="1091" height="718" alt="image"
src="https://github.com/user-attachments/assets/ff1f070d-da39-4e5a-bc6d-99b7214f7da8"
/>

After:
<img width="1089" height="716" alt="image"
src="https://github.com/user-attachments/assets/7123d9bf-f7dd-4430-b6f7-f6702b70baaa"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-12086-fix-assets-strip-directory-annotation-from-input-filenames-35a6d73d365081e9b9eed7d8630d6f0b)
by [Unito](https://www.unito.io)
This commit is contained in:
Henry Lee
2026-05-09 07:31:57 +10:00
committed by GitHub
parent a4faaa0159
commit ca54877f9d
2 changed files with 68 additions and 4 deletions

View File

@@ -0,0 +1,52 @@
import { describe, expect, it, vi } from 'vitest'
import { mapInputFileToAssetItem } from './assetMappers'
vi.mock('@/scripts/api', () => ({
api: {
apiURL: (path: string) => `/api${path}`
}
}))
vi.mock('@/platform/distribution/cloudPreviewUtil', () => ({
appendCloudResParam: vi.fn()
}))
describe('mapInputFileToAssetItem', () => {
it('preserves a clean filename', () => {
const asset = mapInputFileToAssetItem('photo.png', 0, 'input')
expect(asset.name).toBe('photo.png')
expect(asset.id).toBe('input-0-photo.png')
expect(asset.preview_url).toBe('/api/view?filename=photo.png&type=input')
})
it.each([
['photo.png [input]', 'photo.png'],
['photo.png [output]', 'photo.png'],
['photo.png [temp]', 'photo.png'],
['clip.mp4[input]', 'clip.mp4'],
['MyFile.WEBP [Input]', 'MyFile.WEBP']
])('strips ComfyUI directory annotation: %s -> %s', (input, expectedName) => {
const asset = mapInputFileToAssetItem(input, 1, 'input')
expect(asset.name).toBe(expectedName)
expect(asset.id).toBe(`input-1-${expectedName}`)
expect(asset.preview_url).toBe(
`/api/view?filename=${encodeURIComponent(expectedName)}&type=input`
)
})
it('leaves non-annotation brackets in the filename intact', () => {
const asset = mapInputFileToAssetItem('my [draft] image.png', 0, 'input')
expect(asset.name).toBe('my [draft] image.png')
})
it('uses the directory passed in for the type query param', () => {
const asset = mapInputFileToAssetItem('clip.mp4 [output]', 0, 'output')
expect(asset.preview_url).toBe('/api/view?filename=clip.mp4&type=output')
expect(asset.tags).toEqual(['output'])
})
})

View File

@@ -51,6 +51,17 @@ export function mapTaskOutputToAssetItem(
}
}
/**
* Strips ComfyUI's trailing directory-type annotation (e.g. ` [input]`,
* ` [output]`, `[temp]`) from a filename returned by the OSS internal
* `/internal/files/{type}` endpoint. The annotation is part of the wire
* format LoadImage-style widgets expect, but for the assets sidebar we
* want the canonical on-disk filename so type detection / titles work.
*/
function stripDirectoryAnnotation(filename: string): string {
return filename.replace(/\s*\[(?:input|output|temp)\]\s*$/i, '')
}
/**
* Maps input directory file to AssetItem format
* @param filename The filename
@@ -63,13 +74,14 @@ export function mapInputFileToAssetItem(
index: number,
directory: 'input' | 'output' = 'input'
): AssetItem {
const params = new URLSearchParams({ filename, type: directory })
const cleanName = stripDirectoryAnnotation(filename)
const params = new URLSearchParams({ filename: cleanName, type: directory })
const preview_url = api.apiURL(`/view?${params}`)
appendCloudResParam(params, filename)
appendCloudResParam(params, cleanName)
return {
id: `${directory}-${index}-${filename}`,
name: filename,
id: `${directory}-${index}-${cleanName}`,
name: cleanName,
size: 0,
created_at: new Date().toISOString(),
tags: [directory],