docs(assets): unify display_name helper docstrings + fixture tests (FE-747)#12399
docs(assets): unify display_name helper docstrings + fixture tests (FE-747)#12399dante01yoon wants to merge 8 commits into
Conversation
…, FE-748) FE-748: drop the isCloud branch in getMediaDisplayName. Resolve through the shared getAssetDisplayFilename helper so the missingMedia surface uses the same fallback chain (user_metadata.filename -> metadata.filename -> display_name -> asset.name) as the asset card and browser surfaces. FE-747: align assetMetadataUtils helper docstrings with the unified display_name shape emitted by both Core and Cloud per the BE-808 Asset Identity RFC. Add fixture tests covering the Cloud (hash + display_name) and OSS (filename + nullable display_name) response shapes.
📝 WalkthroughWalkthroughClarifies asset display helper docs, adds tests ensuring Cloud and OSS assets produce consistent UI labels (including OSS display_name overrides), and refactors missing-media name resolution to use filename-indexed asset lookups with accompanying tests for precedence and library option mapping. ChangesUnified Asset Identity Implementation
Sequence DiagramsequenceDiagram
participant Caller
participant getMediaDisplayName
participant useAssetsStore
participant inputAssetsByFilename
participant getAssetDisplayFilename
Caller->>getMediaDisplayName: call(name)
getMediaDisplayName->>useAssetsStore: get store instance
useAssetsStore-->>getMediaDisplayName: store reference
getMediaDisplayName->>inputAssetsByFilename: lookup(name)
alt Asset found
inputAssetsByFilename-->>getMediaDisplayName: asset
getMediaDisplayName->>getAssetDisplayFilename: getAssetDisplayFilename(asset)
getAssetDisplayFilename-->>getMediaDisplayName: display label
getMediaDisplayName-->>Caller: return label
else Asset not found
inputAssetsByFilename-->>getMediaDisplayName: undefined
getMediaDisplayName-->>Caller: return raw name
end
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested Labels
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 7✅ Passed checks (7 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/platform/missingMedia/composables/useMissingMediaInteractions.test.ts (1)
6-12: ⚡ Quick winAvoid module-level mutable mock state; switch to a hoisted mock container.
Using a shared mutable
Mapat module scope makes isolation fragile as this suite grows. Prefer avi.hoistedstate object for the mocked store source of truth.Proposed refactor
-const mockInputAssetsByFilename = new Map<string, AssetItem>() +const mockedAssetsState = vi.hoisted(() => ({ + inputAssetsByFilename: new Map<string, AssetItem>() +})) vi.mock('`@/stores/assetsStore`', () => ({ useAssetsStore: () => ({ - inputAssetsByFilename: mockInputAssetsByFilename + inputAssetsByFilename: mockedAssetsState.inputAssetsByFilename }) })) describe('getMediaDisplayName', () => { beforeEach(() => { - mockInputAssetsByFilename.clear() + mockedAssetsState.inputAssetsByFilename.clear() }) @@ - mockInputAssetsByFilename.set(hash, { + mockedAssetsState.inputAssetsByFilename.set(hash, { @@ - mockInputAssetsByFilename.set(hash, { + mockedAssetsState.inputAssetsByFilename.set(hash, { @@ - mockInputAssetsByFilename.set(hash, { + mockedAssetsState.inputAssetsByFilename.set(hash, { @@ - mockInputAssetsByFilename.set(hash, { + mockedAssetsState.inputAssetsByFilename.set(hash, {As per coding guidelines: "Keep module mocks contained; do not use global mutable state within test files; use vi.hoisted() if necessary."
Also applies to: 22-24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platform/missingMedia/composables/useMissingMediaInteractions.test.ts` around lines 6 - 12, Replace the module-scoped mutable Map mockInputAssetsByFilename with a hoisted mock container: create a vi.hoisted(() => ({ inputAssetsByFilename: new Map<string, AssetItem>() })) object and have the mocked useAssetsStore return that container's inputAssetsByFilename instead of the top-level Map; update any tests that mutate mockInputAssetsByFilename to mutate the hoisted container (referencing mockInputAssetsByFilename and useAssetsStore in the diff) so each test file run gets isolated, resettable state.src/platform/assets/utils/assetMetadataUtils.test.ts (1)
388-389: ⚡ Quick winRemove redundant inline comments in the new test block.
These comments restate what test names and fixture identifiers already convey; please drop them to match repo guidance on minimizing code comments.
As per coding guidelines: "Avoid new usage of code comments; do not add or retain redundant comments."
Also applies to: 398-399
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/platform/assets/utils/assetMetadataUtils.test.ts` around lines 388 - 389, Remove the redundant inline comments that restate already-clear test names and fixture identifiers — specifically delete the comment text about "Cloud asset: `asset.name` is a content hash; `display_name` carries the user-facing label." (and the similar redundant comments at the other test lines) from the new test block in assetMetadataUtils.test; leave the tests and fixtures unchanged, only remove those comment lines so the tests conform to the "no redundant comments" guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/platform/assets/utils/assetMetadataUtils.test.ts`:
- Around line 388-389: Remove the redundant inline comments that restate
already-clear test names and fixture identifiers — specifically delete the
comment text about "Cloud asset: `asset.name` is a content hash; `display_name`
carries the user-facing label." (and the similar redundant comments at the other
test lines) from the new test block in assetMetadataUtils.test; leave the tests
and fixtures unchanged, only remove those comment lines so the tests conform to
the "no redundant comments" guideline.
In `@src/platform/missingMedia/composables/useMissingMediaInteractions.test.ts`:
- Around line 6-12: Replace the module-scoped mutable Map
mockInputAssetsByFilename with a hoisted mock container: create a vi.hoisted(()
=> ({ inputAssetsByFilename: new Map<string, AssetItem>() })) object and have
the mocked useAssetsStore return that container's inputAssetsByFilename instead
of the top-level Map; update any tests that mutate mockInputAssetsByFilename to
mutate the hoisted container (referencing mockInputAssetsByFilename and
useAssetsStore in the diff) so each test file run gets isolated, resettable
state.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4212abbd-b8eb-4827-b0ca-a9f88a461604
📒 Files selected for processing (4)
src/platform/assets/utils/assetMetadataUtils.test.tssrc/platform/assets/utils/assetMetadataUtils.tssrc/platform/missingMedia/composables/useMissingMediaInteractions.test.tssrc/platform/missingMedia/composables/useMissingMediaInteractions.ts
…DisplayName Adds 4 cases against the in-file consumer of getMediaDisplayName that was previously untested: empty-on-missing-widget, Cloud-hash combo values mapped through the shared helper chain (display_name and metadata.filename), OSS filename pass-through, and the candidate-name filter. Caught by the FE-747/748 PR review pass.
Codecov Report✅ All modified and coverable lines are covered by tests. @@ Coverage Diff @@
## main #12399 +/- ##
===========================================
- Coverage 76.27% 62.14% -14.13%
===========================================
Files 1570 1458 -112
Lines 103893 75080 -28813
Branches 30937 21151 -9786
===========================================
- Hits 79248 46662 -32586
- Misses 23771 28074 +4303
+ Partials 874 344 -530
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 1177 files with indirect coverage changes 🚀 New features to boost your workflow:
|
# Conflicts: # src/platform/assets/utils/assetMetadataUtils.test.ts # src/platform/assets/utils/assetMetadataUtils.ts
DrJKL
left a comment
There was a problem hiding this comment.
Sunsets really are beautiful, aren't they?
LGTM — single-source-of-truth move onto getAssetDisplayFilename is the right call, the BE-808 cloud/OSS parity tests read cleanly, and the integration test for getLibraryOptions gives real behavioural coverage. A handful of nits below, none blocking.
| if (!isCloud) return name | ||
| return useAssetsStore().getInputName(name) | ||
| const asset = useAssetsStore().inputAssetsByFilename.get(name) | ||
| return asset ? getAssetDisplayFilename(asset) : name |
There was a problem hiding this comment.
Subtle behavioural drift worth flagging in the PR description: the old getInputName(name) path returned asset.name (always the raw asset name). The new getAssetDisplayFilename chain prefers user_metadata.filename → metadata.filename → display_name → asset.name. For Cloud workflows that means the missing-media row and pending-selection label in MissingMediaRow.vue will now surface whatever the queue mapper put into display_name instead of the hash-y asset.name. Almost certainly desired per BE-808, just worth confirming both MissingMediaRow call sites are happy with the richer fallback.
There was a problem hiding this comment.
Confirmed and intended per BE-808. Both MissingMediaRow.vue call sites are happy with the richer fallback — see PR description §1/§2 (live setupState dump) for the per-layer verification. The drift is documented in the Review Focus + Verification sections. No production-visible change today since current Cloud assets have display_name=null (§6); the new layers activate once BE-1043 starts populating it.
| * Human-readable filename for UI labels. | ||
| * Fallback: user_metadata.filename → metadata.filename → display_name → asset.name. | ||
| * For serialized identifiers use {@link getAssetFilename}. | ||
| */ |
There was a problem hiding this comment.
Nit: the trimmed docstring loses the useful "queue output mappers in Cloud populate display_name" context. Since useMissingMediaInteractions.getMediaDisplayName now relies on that contract, consider keeping one short sentence about who populates display_name.
There was a problem hiding this comment.
Intentionally left as-is. The empirical Cloud probe (PR description §6) showed display_name is null across all sampled Cloud assets and asset.name is already a friendly filename — so the "queue output mappers populate display_name" framing is not current production behaviour and was deliberately dropped to avoid a misleading docstring. Per the BE-808 RFC display_name is the unified field both backends emit once BE-1043/1044 land; the docstring reflects that contract rather than naming a specific (currently inaccurate) populator.
|
|
||
| it('honours OSS-emitted display_name when present', () => { | ||
| const ossWithDisplayName: AssetItem = { | ||
| ...ossShape, |
There was a problem hiding this comment.
Nit: name: 'sunset.png' is already inherited from ...ossShape — the explicit re-assignment is a no-op and slightly muddies what the test is varying (the display_name field). Safe to drop.
There was a problem hiding this comment.
Done — dropped the redundant re-assignment; the fixture now only varies display_name.
| useMissingMediaInteractions | ||
| } from '@/platform/missingMedia/composables/useMissingMediaInteractions' | ||
|
|
||
| const mockInputAssetsByFilename = new Map<string, AssetItem>() |
There was a problem hiding this comment.
Nit: module-level mutable mockInputAssetsByFilename is the "global mutable state in test file" pattern the unit-testing guide steers away from. clear() in beforeEach makes it safe in practice, but vi.hoisted(() => ({ inputAssetsByFilename: new Map() })) would match the project convention and make the hoisting explicit.
There was a problem hiding this comment.
Done — switched to a single vi.hoisted(() => ({ inputAssetsByFilename, getNodeByExecutionId, resolveComboValues })) container in f0299e5, matching the project convention.
| mockGetNodeByExecutionId(...args) | ||
| })) | ||
|
|
||
| const mockResolveComboValues = vi.fn() |
There was a problem hiding this comment.
Nit: same hoisting story for mockGetNodeByExecutionId / mockResolveComboValues. Works because the inner refs are only dereferenced when the mocked fns are called, but vi.hoisted() removes the latent TDZ trap and signals intent to the next editor.
There was a problem hiding this comment.
Done — getNodeByExecutionId / resolveComboValues now live in the same hoisted container and are assigned directly into the mock factories, removing the module-level vi.fn() consts.
| pendingSelection: {}, | ||
| uploadState: {}, | ||
| missingMediaCandidates: null, | ||
| removeMissingMediaByName: vi.fn() |
There was a problem hiding this comment.
Nit: removeMissingMediaByName: vi.fn() (and updateInputs, addAlert further down) are wired up but never asserted. Either drop them from the mocks, or add a confirmSelection / handleUpload test that actually exercises them.
There was a problem hiding this comment.
Dropped updateInputs / removeMissingMediaByName from the mocks — the tested paths (getMediaDisplayName, getLibraryOptions) never call them. Kept the toastStore module mock as a needed boundary. A dedicated confirmSelection / handleUpload spec is a worthwhile follow-up but out of scope here.
- Hoist mutable mock state via vi.hoisted to match test conventions - Drop unused store mock fns (updateInputs, removeMissingMediaByName) - Remove redundant name re-assignment in OSS display_name fixture
…lsts-helpers-to-unified-asset
…lsts-helpers-to-unified-asset
…igrate-assetmetadatautilsts-helpers-to-unified-asset # Conflicts: # src/platform/assets/utils/assetMetadataUtils.ts # src/platform/missingMedia/composables/useMissingMediaInteractions.ts
c52dcfc
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1677 passed, 0 failed · 3 flaky📊 Browser Reports
📦 Bundle: 7.45 MB gzip 🟢 -72 BDetailsSummary
Category Glance App Entry Points — 45.8 kB (baseline 45.8 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.26 MB (baseline 1.26 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 95.3 kB (baseline 95.3 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 9 added / 9 removed / 3 unchanged Panels & Settings — 523 kB (baseline 523 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed / 14 unchanged User & Accounts — 19.9 kB (baseline 19.9 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 6 added / 6 removed / 3 unchanged Editors & Dialogs — 112 kB (baseline 112 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 4 added / 4 removed / 1 unchanged UI Components — 57.2 kB (baseline 57.2 kB) • ⚪ 0 BReusable component library chunks
Status: 5 added / 5 removed / 8 unchanged Data & Services — 266 kB (baseline 266 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 12 added / 12 removed / 3 unchanged Utilities & Hooks — 3.3 MB (baseline 3.3 MB) • 🟢 -173 BHelpers, composables, and utility bundles
Status: 15 added / 15 removed / 15 unchanged Vendor & Third-Party — 15.3 MB (baseline 15.3 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 16 unchanged Other — 10.4 MB (baseline 10.4 MB) • ⚪ 0 BBundles that do not match a named category
Status: 64 added / 64 removed / 85 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-06-18T03:21:42.600Z",
"gitSha": "b800aaf0e507596f23671df90aa0e94d1f231885",
"branch": "jaewon/fe-747-l3-fe-migrate-assetmetadatautilsts-helpers-to-unified-asset",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2022.5109999999518,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.274000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 355.56499999999994,
"heapDeltaBytes": -2078196,
"heapUsedBytes": 56297576,
"domNodes": 20,
"jsHeapTotalBytes": 26214400,
"scriptDurationMs": 20.179000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-idle",
"durationMs": 2038.0119999999806,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.32,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 339.255,
"heapDeltaBytes": -1944996,
"heapUsedBytes": 56460120,
"domNodes": 20,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 19.302,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2043.8669999999775,
"styleRecalcs": 77,
"styleRecalcDurationMs": 48.513,
"layouts": 12,
"layoutDurationMs": 3.4740000000000006,
"taskDurationMs": 860.937,
"heapDeltaBytes": -7256376,
"heapUsedBytes": 51490352,
"domNodes": 62,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 130.221,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1793.2250000000067,
"styleRecalcs": 75,
"styleRecalcDurationMs": 35.275,
"layouts": 12,
"layoutDurationMs": 3.5749999999999997,
"taskDurationMs": 731.5830000000001,
"heapDeltaBytes": -7182216,
"heapUsedBytes": 51191608,
"domNodes": 58,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 123.26700000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1721.0890000000063,
"styleRecalcs": 33,
"styleRecalcDurationMs": 17.419000000000004,
"layouts": 6,
"layoutDurationMs": 0.611,
"taskDurationMs": 296.937,
"heapDeltaBytes": -1589512,
"heapUsedBytes": 51568436,
"domNodes": 80,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 24.494000000000003,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1724.0499999999201,
"styleRecalcs": 30,
"styleRecalcDurationMs": 15.194999999999999,
"layouts": 6,
"layoutDurationMs": 0.48700000000000004,
"taskDurationMs": 289.18,
"heapDeltaBytes": 1878904,
"heapUsedBytes": 60223132,
"domNodes": 77,
"jsHeapTotalBytes": 25952256,
"scriptDurationMs": 22.169,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 597.6709999999912,
"styleRecalcs": 11,
"styleRecalcDurationMs": 10.265999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 324.81399999999996,
"heapDeltaBytes": 4988520,
"heapUsedBytes": 54476476,
"domNodes": 18,
"jsHeapTotalBytes": 10485760,
"scriptDurationMs": 55.92400000000001,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 543.0969999999888,
"styleRecalcs": 12,
"styleRecalcDurationMs": 7.533999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 325.548,
"heapDeltaBytes": 7233948,
"heapUsedBytes": 65603084,
"domNodes": 20,
"jsHeapTotalBytes": 18612224,
"scriptDurationMs": 60.276,
"eventListeners": 0,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2009.2390000000364,
"styleRecalcs": 12,
"styleRecalcDurationMs": 11.086,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 471.73699999999997,
"heapDeltaBytes": 11055324,
"heapUsedBytes": 72340652,
"domNodes": 24,
"jsHeapTotalBytes": 5505024,
"scriptDurationMs": 86.482,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 1988.354999999956,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.741999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 469.716,
"heapDeltaBytes": -9247772,
"heapUsedBytes": 62200672,
"domNodes": 20,
"jsHeapTotalBytes": 9842688,
"scriptDurationMs": 82.14399999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2124.789000000021,
"styleRecalcs": 69,
"styleRecalcDurationMs": 18.572000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1019.5419999999999,
"heapDeltaBytes": 9776288,
"heapUsedBytes": 83105700,
"domNodes": 16,
"jsHeapTotalBytes": 12902400,
"scriptDurationMs": 375.046,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-pan",
"durationMs": 2087.953000000084,
"styleRecalcs": 69,
"styleRecalcDurationMs": 18.488999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1018.4929999999998,
"heapDeltaBytes": 9684064,
"heapUsedBytes": 82496544,
"domNodes": 18,
"jsHeapTotalBytes": 9494528,
"scriptDurationMs": 372.87800000000004,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3084.6310000000017,
"styleRecalcs": 62,
"styleRecalcDurationMs": 15.059999999999997,
"layouts": 60,
"layoutDurationMs": 7.083,
"taskDurationMs": 1221.68,
"heapDeltaBytes": 11035056,
"heapUsedBytes": 66563264,
"domNodes": 6,
"jsHeapTotalBytes": 2097152,
"scriptDurationMs": 469.504,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3090.086999999926,
"styleRecalcs": 63,
"styleRecalcDurationMs": 16.23,
"layouts": 60,
"layoutDurationMs": 6.999,
"taskDurationMs": 1242.596,
"heapDeltaBytes": 11705108,
"heapUsedBytes": 65887832,
"domNodes": 8,
"jsHeapTotalBytes": 2621440,
"scriptDurationMs": 487.03,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 1995.792999999992,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.768000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 459.12,
"heapDeltaBytes": -9206948,
"heapUsedBytes": 64391856,
"domNodes": 16,
"jsHeapTotalBytes": 7745536,
"scriptDurationMs": 80.41599999999998,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2022.3000000000866,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.821,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 479.346,
"heapDeltaBytes": -8331188,
"heapUsedBytes": 63428412,
"domNodes": 20,
"jsHeapTotalBytes": 9842688,
"scriptDurationMs": 86.06800000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 564.1939999999863,
"styleRecalcs": 47,
"styleRecalcDurationMs": 10.430999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 342.288,
"heapDeltaBytes": 7705628,
"heapUsedBytes": 66443100,
"domNodes": 20,
"jsHeapTotalBytes": 19398656,
"scriptDurationMs": 119.77799999999999,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 559.3499999999949,
"styleRecalcs": 48,
"styleRecalcDurationMs": 10.791999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 347.54799999999994,
"heapDeltaBytes": 7726920,
"heapUsedBytes": 66416608,
"domNodes": 22,
"jsHeapTotalBytes": 19660800,
"scriptDurationMs": 117.365,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66666666666665,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-idle",
"durationMs": 2004.6690000000353,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.859,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 346.79099999999994,
"heapDeltaBytes": -2528348,
"heapUsedBytes": 56197680,
"domNodes": 20,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 16.36,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 1993.5850000000528,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.088000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 323.68,
"heapDeltaBytes": -2286948,
"heapUsedBytes": 56577976,
"domNodes": 16,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 12.213999999999999,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1677.1380000000136,
"styleRecalcs": 75,
"styleRecalcDurationMs": 35.077000000000005,
"layouts": 16,
"layoutDurationMs": 4.195,
"taskDurationMs": 656.1279999999999,
"heapDeltaBytes": -10706764,
"heapUsedBytes": 47984996,
"domNodes": 61,
"jsHeapTotalBytes": 27000832,
"scriptDurationMs": 93.399,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1726.376000000073,
"styleRecalcs": 75,
"styleRecalcDurationMs": 35.887,
"layouts": 16,
"layoutDurationMs": 4.445,
"taskDurationMs": 669.828,
"heapDeltaBytes": -10715284,
"heapUsedBytes": 47951332,
"domNodes": 61,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 93.867,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-transition-enter",
"durationMs": 949.3400000000065,
"styleRecalcs": 17,
"styleRecalcDurationMs": 27.778999999999996,
"layouts": 4,
"layoutDurationMs": 13.387,
"taskDurationMs": 708.5400000000002,
"heapDeltaBytes": 2634032,
"heapUsedBytes": 78866864,
"domNodes": 13833,
"jsHeapTotalBytes": 16515072,
"scriptDurationMs": 25.37600000000001,
"eventListeners": 2529,
"totalBlockingTimeMs": 160,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8146.094000000005,
"styleRecalcs": 251,
"styleRecalcDurationMs": 53.053,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3500.2960000000003,
"heapDeltaBytes": -2417880,
"heapUsedBytes": 67568332,
"domNodes": 20,
"jsHeapTotalBytes": 17096704,
"scriptDurationMs": 1204.1100000000001,
"eventListeners": 20,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333338,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 8099.467000000004,
"styleRecalcs": 250,
"styleRecalcDurationMs": 54.611,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 3551.5190000000002,
"heapDeltaBytes": -2640228,
"heapUsedBytes": 67699700,
"domNodes": 22,
"jsHeapTotalBytes": 19193856,
"scriptDurationMs": 1212.273,
"eventListeners": 20,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "vue-large-graph-idle",
"durationMs": 12609.549000000015,
"styleRecalcs": 1,
"styleRecalcDurationMs": 2.0440000000000182,
"layouts": 1,
"layoutDurationMs": 3.0469999999999944,
"taskDurationMs": 12536.477,
"heapDeltaBytes": -19713360,
"heapUsedBytes": 167853204,
"domNodes": -3306,
"jsHeapTotalBytes": 20680704,
"scriptDurationMs": 631.2570000000001,
"eventListeners": -16472,
"totalBlockingTimeMs": 906,
"frameDurationMs": 17.223333333333237,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 12344.80999999994,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 12329.759000000004,
"heapDeltaBytes": -30278708,
"heapUsedBytes": 169415144,
"domNodes": -3308,
"jsHeapTotalBytes": 21729280,
"scriptDurationMs": 564.3739999999999,
"eventListeners": -16473,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.223333333333358,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 14054.960999999992,
"styleRecalcs": 65,
"styleRecalcDurationMs": 16.549999999999983,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 14023.831,
"heapDeltaBytes": -23214280,
"heapUsedBytes": 168442240,
"domNodes": -3306,
"jsHeapTotalBytes": 19894272,
"scriptDurationMs": 900.6070000000001,
"eventListeners": -16472,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.223333333333237,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 14705.363999999918,
"styleRecalcs": 66,
"styleRecalcDurationMs": 17.028000000000016,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 14682.882000000001,
"heapDeltaBytes": -30519140,
"heapUsedBytes": 180931752,
"domNodes": -3308,
"jsHeapTotalBytes": 21643264,
"scriptDurationMs": 853.1370000000001,
"eventListeners": -16472,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.219999999999953,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 499.292999999966,
"styleRecalcs": 19,
"styleRecalcDurationMs": 31.782999999999998,
"layouts": 5,
"layoutDurationMs": 1.3880000000000001,
"taskDurationMs": 227.15600000000003,
"heapDeltaBytes": -22050124,
"heapUsedBytes": 48380448,
"domNodes": -196,
"jsHeapTotalBytes": 5169152,
"scriptDurationMs": 21.973,
"eventListeners": -134,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666682,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "workflow-execution",
"durationMs": 450.1229999999623,
"styleRecalcs": 17,
"styleRecalcDurationMs": 22.013,
"layouts": 4,
"layoutDurationMs": 0.9920000000000002,
"taskDurationMs": 101.22899999999998,
"heapDeltaBytes": 4922928,
"heapUsedBytes": 69873972,
"domNodes": 155,
"jsHeapTotalBytes": 4718592,
"scriptDurationMs": 15.052999999999999,
"eventListeners": 69,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.663333333333338,
"p95FrameDurationMs": 16.700000000000273
}
]
} |
Summary
Originally bundled FE-747 + FE-748. After merging latest
main, FE-748 is obsolete (see below) and nothing of it remains, so this PR is now FE-747 only: theassetMetadataUtilsdisplay helpers are documented against the unified BE-808 asset shape, backed by Cloud/OSS fixture tests. No production behavior change — only docstrings and tests; the helper bodies are byte-identical tomain.Why FE-748 is obsolete
FE-748 migrated
getMediaDisplayNameinsrc/platform/missingMedia/composables/useMissingMediaInteractions.tsonto the unifieddisplay_name. Upstream PR #12705 ("Simplify missing media error presentation") then removed the entire missing-media library/upload flow, deleting that composable along withMissingMediaRow.vueandMissingMediaLibrarySelect.vue.getMediaDisplayName/getLibraryOptionsnow have zero consumers anywhere insrc/— the missing-media error tab no longer resolves asset display names at all; it renders a flat{nodeName} - {inputName}list. FE-748 has no surface left to land on. The merge conflict was resolved by accepting the upstream deletion and removing the orphaned spec; FE-748 is closed as superseded.Changes (FE-747)
src/platform/assets/utils/assetMetadataUtils.tsgetAssetDisplayFilename/getAssetCardTitledocstrings:display_nameis the unified user-facing label per the BE-808 Asset Identity RFC, not a "Cloud-only / queue-output mapper" field. No code change — the helpers already consumedisplay_namethrough the existing fallback chain. The merge also preservedgetAssetStoredFilename(added onmain).src/platform/assets/utils/assetMetadataUtils.test.tsasset.name= hash,display_name= filename) and OSS (asset.name= filename, nullabledisplay_name) — asserting both helpers render the same label, plusdisplay_nameprecedence cases.Verification — 2026-06-17 (CDP, OSS + Cloud)
Dynamic-imported the merged module and ran the helpers against real data in both environments:
--enable-assets) behind the dev server: real input assets (04_toolbox.png,image64x64.webp, …) resolve to their friendly filename; the Imported-tab cards render filenames, never hashes.cloud.comfy.orgsession, real/api/assets: correct labels forinput/output/models. Key case — anoutputasset whosehashis a content hash (183f9635….mp4) resolves to itsdisplay_name(video/ComfyUI-vid_3_00001_.mp4), no hash leak. Models resolve viauser_metadata.filename; the card title uses the curatedmetadata.name(pre-existing behavior).user_metadata.filename → metadata.filename → display_name → asset.nameconfirmed.display_name(BE-1043 has landed), so the fallback chain is live, not dormant. No regression in either environment.pnpm typecheck,eslint, the 59assetMetadataUtils.test.tscases, and full CI (incl. cloud Playwright) pass.Refs
display_name, now live)