mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-11 16:30:57 +00:00
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:
52
src/platform/assets/composables/media/assetMappers.test.ts
Normal file
52
src/platform/assets/composables/media/assetMappers.test.ts
Normal 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'])
|
||||
})
|
||||
})
|
||||
@@ -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],
|
||||
|
||||
Reference in New Issue
Block a user