fix(assets): resolve annotated widget values to their own directory - #15065
fix(assets): resolve annotated widget values to their own directory#15065christian-byrne wants to merge 4 commits into
Conversation
…ut dir A Load Image node populated from the assets sidebar's Generated tab holds an [output]-annotated widget value. setNodeOutputs parses it with parseFilePath, which does not strip the annotation, and types every image with the caller's folder (default 'input'), so the preview requests /api/view?type=input&filename=generated.png+%5Boutput%5D&subfolder=runs%2F2026 which 404s and renders 'Image failed to load' on the node.
createAnnotatedPath writes '<path> [output]' / '[temp]' for assets that do not live under the input root, but nothing could read that back: setNodeOutputs handed the raw value to parseFilePath, which only splits on the last '/', and typed every image with the caller's folder (default 'input'). Add parseAnnotatedPath as the inverse of createAnnotatedPath and use it when building outputs, so the annotation decides the directory and never leaks into the filename. Unannotated values keep resolving to the caller's folder, so the upload path is unchanged. Also fixes the same latent bug in useMaskEditorSaver, which passes an annotated path with folder: 'input'.
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 7 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
Comment |
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1801 passed, 0 failed · 3 flaky📊 Browser Reports
📦 Bundle: 8.7 MB gzip 🔴 +642 BDetailsSummary
Category Glance App Entry Points — 3.67 kB (baseline 3.67 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.36 MB (baseline 1.36 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 2 added / 2 removed / 1 unchanged Views & Navigation — 124 kB (baseline 124 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 13 added / 13 removed / 4 unchanged Panels & Settings — 565 kB (baseline 565 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed / 16 unchanged User & Accounts — 27 kB (baseline 27 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 6 added / 6 removed / 4 unchanged Editors & Dialogs — 125 kB (baseline 125 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 7 added / 7 removed / 1 unchanged UI Components — 67.1 kB (baseline 67.1 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed / 8 unchanged Data & Services — 3.5 MB (baseline 3.5 MB) • 🔴 +1.47 kBStores, services, APIs, and repositories
Status: 14 added / 14 removed / 3 unchanged Utilities & Hooks — 550 kB (baseline 550 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 18 added / 18 removed / 20 unchanged Vendor & Third-Party — 16.3 MB (baseline 16.3 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 17 unchanged Other — 14 MB (baseline 14 MB) • ⚪ 0 BBundles that do not match a named category
Status: 68 added / 68 removed / 217 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-08-11T23:36:38.676Z",
"gitSha": "ec053a11512126560dabd94def40f1eaacce4b82",
"branch": "cb/trackB-assets-loadimage",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2108.86899999997,
"styleRecalcs": 8,
"styleRecalcDurationMs": 9.513,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 755.7230000000001,
"heapDeltaBytes": 5878480,
"heapUsedBytes": 70181256,
"domNodes": 16,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 31.041,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-idle",
"durationMs": 2037.98699999993,
"styleRecalcs": 8,
"styleRecalcDurationMs": 9.509,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 661.006,
"heapDeltaBytes": 5803528,
"heapUsedBytes": 70176056,
"domNodes": 16,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 29.002000000000002,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2098.410000000001,
"styleRecalcs": 78,
"styleRecalcDurationMs": 55.269000000000005,
"layouts": 12,
"layoutDurationMs": 4.1610000000000005,
"taskDurationMs": 1139.973,
"heapDeltaBytes": -10406888,
"heapUsedBytes": 53913392,
"domNodes": -281,
"jsHeapTotalBytes": 24616960,
"scriptDurationMs": 143.88899999999998,
"eventListeners": -155,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1990.8060000000205,
"styleRecalcs": 78,
"styleRecalcDurationMs": 48.287,
"layouts": 12,
"layoutDurationMs": 5.372,
"taskDurationMs": 1096.248,
"heapDeltaBytes": -10283316,
"heapUsedBytes": 54076216,
"domNodes": -282,
"jsHeapTotalBytes": 23830528,
"scriptDurationMs": 145.007,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66999999999998,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1748.078000000021,
"styleRecalcs": 30,
"styleRecalcDurationMs": 21.353,
"layouts": 6,
"layoutDurationMs": 0.7209999999999999,
"taskDurationMs": 505.61400000000003,
"heapDeltaBytes": 8846344,
"heapUsedBytes": 73206872,
"domNodes": 76,
"jsHeapTotalBytes": 24641536,
"scriptDurationMs": 31.503000000000004,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1742.6860000000488,
"styleRecalcs": 32,
"styleRecalcDurationMs": 22.467,
"layouts": 6,
"layoutDurationMs": 0.7259999999999999,
"taskDurationMs": 506.738,
"heapDeltaBytes": 8768160,
"heapUsedBytes": 73156152,
"domNodes": 77,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 31.587999999999997,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 747.3170000000096,
"styleRecalcs": 8,
"styleRecalcDurationMs": 7.056,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 490.07900000000006,
"heapDeltaBytes": -11308104,
"heapUsedBytes": 53226332,
"domNodes": 12,
"jsHeapTotalBytes": 25690112,
"scriptDurationMs": 75.132,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 693.9539999999624,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.45,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 444.83900000000006,
"heapDeltaBytes": -11045944,
"heapUsedBytes": 53285924,
"domNodes": 16,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 65.461,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "large-graph-idle",
"durationMs": 2126.751000000013,
"styleRecalcs": 9,
"styleRecalcDurationMs": 11.674,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 969.052,
"heapDeltaBytes": 6827636,
"heapUsedBytes": 66685344,
"domNodes": -282,
"jsHeapTotalBytes": 3248128,
"scriptDurationMs": 151.23600000000002,
"eventListeners": -181,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2109.6300000000383,
"styleRecalcs": 8,
"styleRecalcDurationMs": 9.158,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 940.8829999999999,
"heapDeltaBytes": 7814932,
"heapUsedBytes": 67304684,
"domNodes": -281,
"jsHeapTotalBytes": 3510272,
"scriptDurationMs": 144.082,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-pan",
"durationMs": 2455.246000000045,
"styleRecalcs": 69,
"styleRecalcDurationMs": 18.372999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1524.5910000000001,
"heapDeltaBytes": -5163012,
"heapUsedBytes": 55430764,
"domNodes": -281,
"jsHeapTotalBytes": 4296704,
"scriptDurationMs": 491.828,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "large-graph-pan",
"durationMs": 2369.372999999996,
"styleRecalcs": 68,
"styleRecalcDurationMs": 16.305000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1526.806,
"heapDeltaBytes": -5926504,
"heapUsedBytes": 55013340,
"domNodes": -287,
"jsHeapTotalBytes": 4820992,
"scriptDurationMs": 474.323,
"eventListeners": -179,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-zoom",
"durationMs": 3729.5009999999706,
"styleRecalcs": 64,
"styleRecalcDurationMs": 16.663,
"layouts": 60,
"layoutDurationMs": 9.32,
"taskDurationMs": 1840.7279999999998,
"heapDeltaBytes": -4773720,
"heapUsedBytes": 57544480,
"domNodes": -289,
"jsHeapTotalBytes": 5869568,
"scriptDurationMs": 641.054,
"eventListeners": -181,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-zoom",
"durationMs": 3597.488999999996,
"styleRecalcs": 64,
"styleRecalcDurationMs": 17.162,
"layouts": 60,
"layoutDurationMs": 9.746,
"taskDurationMs": 1772.7240000000002,
"heapDeltaBytes": 1183376,
"heapUsedBytes": 63314484,
"domNodes": 10,
"jsHeapTotalBytes": 8126464,
"scriptDurationMs": 638.696,
"eventListeners": 10,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "minimap-idle",
"durationMs": 2081.08900000002,
"styleRecalcs": 7,
"styleRecalcDurationMs": 7.987000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 950.5130000000001,
"heapDeltaBytes": 7798800,
"heapUsedBytes": 68590596,
"domNodes": -285,
"jsHeapTotalBytes": 2723840,
"scriptDurationMs": 139.08399999999997,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "minimap-idle",
"durationMs": 2086.618999999928,
"styleRecalcs": 8,
"styleRecalcDurationMs": 8.288,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 942.0930000000001,
"heapDeltaBytes": 7627816,
"heapUsedBytes": 68204600,
"domNodes": -285,
"jsHeapTotalBytes": 3772416,
"scriptDurationMs": 142.34999999999997,
"eventListeners": -149,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 697.3949999999718,
"styleRecalcs": 45,
"styleRecalcDurationMs": 10.949,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 475.45399999999995,
"heapDeltaBytes": -10202808,
"heapUsedBytes": 54261096,
"domNodes": 16,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 134.91,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 720.0689999999668,
"styleRecalcs": 46,
"styleRecalcDurationMs": 12.136999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 487.658,
"heapDeltaBytes": -10418260,
"heapUsedBytes": 54100628,
"domNodes": 18,
"jsHeapTotalBytes": 25165824,
"scriptDurationMs": 140.658,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-idle",
"durationMs": 2018.8139999999635,
"styleRecalcs": 9,
"styleRecalcDurationMs": 10.342999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 641.0989999999999,
"heapDeltaBytes": 5859956,
"heapUsedBytes": 70265196,
"domNodes": 18,
"jsHeapTotalBytes": 24903680,
"scriptDurationMs": 24.845,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2058.7240000000975,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.817,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 703.082,
"heapDeltaBytes": -18257920,
"heapUsedBytes": 46120892,
"domNodes": 1,
"jsHeapTotalBytes": 23044096,
"scriptDurationMs": 26.180000000000003,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1803.6920000000123,
"styleRecalcs": 77,
"styleRecalcDurationMs": 44.80199999999999,
"layouts": 16,
"layoutDurationMs": 5.37,
"taskDurationMs": 931.6719999999999,
"heapDeltaBytes": -3373576,
"heapUsedBytes": 61119468,
"domNodes": 62,
"jsHeapTotalBytes": 25427968,
"scriptDurationMs": 109.84200000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1899.6630000000323,
"styleRecalcs": 80,
"styleRecalcDurationMs": 48.816,
"layouts": 16,
"layoutDurationMs": 5.556,
"taskDurationMs": 1003.1719999999999,
"heapDeltaBytes": -18334108,
"heapUsedBytes": 46075132,
"domNodes": 1,
"jsHeapTotalBytes": 22781952,
"scriptDurationMs": 111.42799999999998,
"eventListeners": -153,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1448.3220000000756,
"styleRecalcs": 20,
"styleRecalcDurationMs": 32.859,
"layouts": 16,
"layoutDurationMs": 15.027000000000003,
"taskDurationMs": 1145.4240000000002,
"heapDeltaBytes": 3858704,
"heapUsedBytes": 76658292,
"domNodes": 13673,
"jsHeapTotalBytes": 15728640,
"scriptDurationMs": 47.23399999999999,
"eventListeners": 2373,
"totalBlockingTimeMs": 148,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "viewport-pan-sweep",
"durationMs": 9165.238999999985,
"styleRecalcs": 250,
"styleRecalcDurationMs": 47.622,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 5430.944,
"heapDeltaBytes": 17701316,
"heapUsedBytes": 77193160,
"domNodes": -284,
"jsHeapTotalBytes": 5275648,
"scriptDurationMs": 1604.671,
"eventListeners": -161,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "viewport-pan-sweep",
"durationMs": 9002.357999999958,
"styleRecalcs": 249,
"styleRecalcDurationMs": 46.967999999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 5389.241999999999,
"heapDeltaBytes": 19892204,
"heapUsedBytes": 79455548,
"domNodes": -283,
"jsHeapTotalBytes": 5537792,
"scriptDurationMs": 1589.557,
"eventListeners": -133,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.80000000000109
},
{
"name": "vue-large-graph-idle",
"durationMs": 19664.21200000002,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 19618.006,
"heapDeltaBytes": -41149560,
"heapUsedBytes": 160623708,
"domNodes": -8316,
"jsHeapTotalBytes": -8331264,
"scriptDurationMs": 627.0910000000001,
"eventListeners": -16385,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.33666666666662,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-idle",
"durationMs": 19711.231,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 19692.788,
"heapDeltaBytes": -58445596,
"heapUsedBytes": 167853636,
"domNodes": -8312,
"jsHeapTotalBytes": -5971968,
"scriptDurationMs": 597.166,
"eventListeners": -16389,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.333333333333332,
"p95FrameDurationMs": 33.400000000001455
},
{
"name": "vue-large-graph-pan",
"durationMs": 24975.833999999963,
"styleRecalcs": 181,
"styleRecalcDurationMs": 32.869999999999955,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 24939.915000000005,
"heapDeltaBytes": -49854992,
"heapUsedBytes": 156023092,
"domNodes": -8312,
"jsHeapTotalBytes": -10162176,
"scriptDurationMs": 1055.209,
"eventListeners": -16379,
"totalBlockingTimeMs": 1287,
"frameDurationMs": 18.886666666666617,
"p95FrameDurationMs": 33.200000000004366
},
{
"name": "vue-large-graph-pan",
"durationMs": 24492.886999999995,
"styleRecalcs": 178,
"styleRecalcDurationMs": 30.547999999999963,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 24465.533,
"heapDeltaBytes": -56199964,
"heapUsedBytes": 166753392,
"domNodes": -8312,
"jsHeapTotalBytes": -9641984,
"scriptDurationMs": 989.841,
"eventListeners": -16377,
"totalBlockingTimeMs": 1408,
"frameDurationMs": 18.33666666666662,
"p95FrameDurationMs": 16.700000000004366
},
{
"name": "workflow-execution",
"durationMs": 466.61200000005465,
"styleRecalcs": 11,
"styleRecalcDurationMs": 21.374999999999996,
"layouts": 3,
"layoutDurationMs": 0.6880000000000001,
"taskDurationMs": 127.56300000000002,
"heapDeltaBytes": 5063096,
"heapUsedBytes": 68482168,
"domNodes": 122,
"jsHeapTotalBytes": 5767168,
"scriptDurationMs": 12.328,
"eventListeners": 99,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333335,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 470.03799999993134,
"styleRecalcs": 11,
"styleRecalcDurationMs": 22.032999999999998,
"layouts": 3,
"layoutDurationMs": 0.6739999999999999,
"taskDurationMs": 119.587,
"heapDeltaBytes": 5047436,
"heapUsedBytes": 68480268,
"domNodes": 119,
"jsHeapTotalBytes": 4980736,
"scriptDurationMs": 13.786,
"eventListeners": 97,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
}
]
} |
…esult
The preservation guard identified widget previews by directory ('every image is
type input'), which only worked because annotated values were misparsed into the
input directory. Now that an [output] widget value resolves to the output
directory, that proxy no longer holds and running the graph would clear the
preview.
Track the widget-sourced locators explicitly instead, so the guard covers a
widget pointing at an output or temp asset as well as an input one.
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## main #15065 +/- ##
=======================================
Coverage 81.32% 81.33%
=======================================
Files 1873 1873
Lines 106556 106572 +16
Branches 33382 33309 -73
=======================================
+ Hits 86661 86680 +19
+ Misses 19549 19536 -13
- Partials 346 356 +10
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 8 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Load Image nodes populated from the assets sidebar's Generated tab show "Image failed to load" permanently, on the same nodes, surviving reload and re-upload.
Root cause
createAnnotatedPathwrites<path> [output]/<path> [temp]for assets that don't live under the implicitinputroot. Nothing could read that format back.nodeOutputStore.createOutputshanded the raw widget value toparseFilePath, which only splits on the last/and leaves the annotation glued to the filename, then typed every image with the caller'sfolder— which defaults to'input'and is never passed by the Load Image combo callback. So a value ofruns/2026/generated.png [output]produced:which 404s. The value is stored in the workflow, so the failure is deterministic per node and re-uploading the asset never helps.
This is why file-picker uploads work and sidebar-inserted assets don't: uploads write a bare
input-rooted name, which parses correctly by accident.Change
parseAnnotatedPath, the exact inverse ofcreateAnnotatedPath, colocated with it.createOutputsuses it so the annotation decides the directory instead of leaking into the filename. Unannotated values still resolve to the caller's folder, so the upload path is byte-for-byte unchanged.useMaskEditorSaver(:308) passes an annotated path withfolder: 'input'and had the same latent bug; it is fixed by the same change.Regression coverage
Red commit first (
8e5780729c) — the repro asserts the broken URL, and CI on that commit shows it failing.setNodeOutputsroutes[output]/[temp]values to the right directory, preserves subfolders, builds an annotation-free/api/viewURL, and leaves unannotated values alone.parseAnnotatedPathround-trips againstcreateAnnotatedPath, honours the fallback root, and does not treat a mid-path bracket as an annotation.browser_tests/tests/loadImageAnnotatedPath.spec.tsloads a workflow whose Load Image widget holds an[output]value and asserts the intercepted/api/viewrequest carriestype=outputand an unannotated filename.Knock-on fix included
The empty-execution preservation guard in
setOutputsByLocatorIdidentified widget previews by directory — "every image istype: input". That proxy only held because annotated values were being misparsed into the input directory. Once an[output]widget value resolves correctly, running the graph would have cleared the preview.So the guard now tracks widget-sourced locators explicitly, which covers a widget pointing at an
outputortempasset as well as aninputone. Two tests cover it, and I verified they fail when the new clause is removed.Scope
Client-side parsing of a string the client itself produced — no API, schema, or backend contract involved. Independent of the assets rework.
Notes for review
Load3DConfiguration.parseAnnotatedFilenameandassetMappers.stripDirectoryAnnotation. Deliberately not consolidated in this PR to keep the diff minimal; worth a follow-up.