feat(video): filmstrip trim timeline and playback composables - #14139
Conversation
🎨 Storybook: ✅ Built — View Storybook🎭 Playwright: ✅ 1736 passed, 0 failed · 2 flaky📊 Browser Reports
📦 Bundle: 8.12 MB gzip 🟢 -4.81 kBDetailsSummary
Category Glance App Entry Points — 3.64 kB (baseline 3.64 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 1.28 MB (baseline 1.28 MB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed / 1 unchanged Views & Navigation — 112 kB (baseline 112 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 12 added / 12 removed / 4 unchanged Panels & Settings — 551 kB (baseline 551 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 11 added / 11 removed / 15 unchanged User & Accounts — 29.1 kB (baseline 29.1 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 7 added / 7 removed / 3 unchanged Editors & Dialogs — 121 kB (baseline 121 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 5 added / 5 removed / 1 unchanged UI Components — 64.6 kB (baseline 64.6 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed / 8 unchanged Data & Services — 3.37 MB (baseline 3.39 MB) • 🟢 -13.4 kBStores, services, APIs, and repositories
Status: 14 added / 14 removed / 3 unchanged Utilities & Hooks — 357 kB (baseline 363 kB) • 🟢 -5.58 kBHelpers, composables, and utility bundles
Status: 19 added / 19 removed / 16 unchanged Vendor & Third-Party — 15.7 MB (baseline 15.7 MB) • ⚪ 0 BExternal libraries and shared vendor chunks Status: 16 unchanged Other — 12.5 MB (baseline 12.5 MB) • 🔴 +641 BBundles that do not match a named category
Status: 78 added / 78 removed / 199 unchanged ⚡ Performance Report
Show regressions
All metrics
Historical variance (last 15 runs)
Trend (last 15 commits on main)
Raw data{
"timestamp": "2026-07-28T03:37:50.929Z",
"gitSha": "ab35bf088046260855a76371e8c28f2fedc56b2d",
"branch": "feat/video-trim-timeline",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2056.482000000017,
"styleRecalcs": 9,
"styleRecalcDurationMs": 10.043999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 591.364,
"heapDeltaBytes": 3765148,
"heapUsedBytes": 71521512,
"domNodes": 18,
"jsHeapTotalBytes": 20582400,
"scriptDurationMs": 24.511,
"eventListeners": 6,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-idle",
"durationMs": 2036.5419999999403,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.808,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 613.593,
"heapDeltaBytes": 3436916,
"heapUsedBytes": 71233172,
"domNodes": 18,
"jsHeapTotalBytes": 21106688,
"scriptDurationMs": 27.274,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1934.2720000000213,
"styleRecalcs": 79,
"styleRecalcDurationMs": 43.56,
"layouts": 12,
"layoutDurationMs": 3.8200000000000003,
"taskDurationMs": 954.0780000000001,
"heapDeltaBytes": -15081148,
"heapUsedBytes": 52762312,
"domNodes": -273,
"jsHeapTotalBytes": 22020096,
"scriptDurationMs": 138.569,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1953.948999999966,
"styleRecalcs": 77,
"styleRecalcDurationMs": 46.182,
"layouts": 12,
"layoutDurationMs": 4.191000000000001,
"taskDurationMs": 1011.263,
"heapDeltaBytes": -1329524,
"heapUsedBytes": 66467736,
"domNodes": 59,
"jsHeapTotalBytes": 21368832,
"scriptDurationMs": 140.081,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1722.0379999999977,
"styleRecalcs": 32,
"styleRecalcDurationMs": 17.683999999999997,
"layouts": 6,
"layoutDurationMs": 0.6840000000000002,
"taskDurationMs": 386.973,
"heapDeltaBytes": 7030984,
"heapUsedBytes": 74834536,
"domNodes": 78,
"jsHeapTotalBytes": 20320256,
"scriptDurationMs": 20.377999999999997,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "canvas-zoom-sweep",
"durationMs": 1734.2139999999517,
"styleRecalcs": 31,
"styleRecalcDurationMs": 19.937000000000005,
"layouts": 6,
"layoutDurationMs": 0.7789999999999997,
"taskDurationMs": 458.998,
"heapDeltaBytes": 7154436,
"heapUsedBytes": 74861240,
"domNodes": 76,
"jsHeapTotalBytes": 20320256,
"scriptDurationMs": 28.508,
"eventListeners": 19,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "dom-widget-clipping",
"durationMs": 621.044999999981,
"styleRecalcs": 11,
"styleRecalcDurationMs": 7.657000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 404.6430000000001,
"heapDeltaBytes": -12541304,
"heapUsedBytes": 55537892,
"domNodes": 18,
"jsHeapTotalBytes": 21368832,
"scriptDurationMs": 64.893,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "dom-widget-clipping",
"durationMs": 735.0940000000037,
"styleRecalcs": 10,
"styleRecalcDurationMs": 8.806999999999999,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 429.65700000000004,
"heapDeltaBytes": -11996592,
"heapUsedBytes": 55823696,
"domNodes": 16,
"jsHeapTotalBytes": 21106688,
"scriptDurationMs": 65.113,
"eventListeners": 2,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-idle",
"durationMs": 2056.262000000004,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.830000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 822.25,
"heapDeltaBytes": 6584708,
"heapUsedBytes": 65324380,
"domNodes": -277,
"jsHeapTotalBytes": 4788224,
"scriptDurationMs": 130.739,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "large-graph-idle",
"durationMs": 2049.233999999956,
"styleRecalcs": 9,
"styleRecalcDurationMs": 8.931000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 879.9,
"heapDeltaBytes": 6549248,
"heapUsedBytes": 65238624,
"domNodes": -274,
"jsHeapTotalBytes": 4526080,
"scriptDurationMs": 139.18,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2274.0650000000073,
"styleRecalcs": 68,
"styleRecalcDurationMs": 13.862,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1363.953,
"heapDeltaBytes": 2742956,
"heapUsedBytes": 62462356,
"domNodes": -278,
"jsHeapTotalBytes": 4730880,
"scriptDurationMs": 458.201,
"eventListeners": -142,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "large-graph-pan",
"durationMs": 2311.6710000000467,
"styleRecalcs": 68,
"styleRecalcDurationMs": 14.519000000000004,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 1438.901,
"heapDeltaBytes": 4866840,
"heapUsedBytes": 64812416,
"domNodes": -278,
"jsHeapTotalBytes": 4730880,
"scriptDurationMs": 480.698,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-zoom",
"durationMs": 3276.945000000012,
"styleRecalcs": 65,
"styleRecalcDurationMs": 16.335999999999995,
"layouts": 60,
"layoutDurationMs": 7.55,
"taskDurationMs": 1636.463,
"heapDeltaBytes": 1675240,
"heapUsedBytes": 63032240,
"domNodes": -281,
"jsHeapTotalBytes": 7671808,
"scriptDurationMs": 572.2309999999999,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "large-graph-zoom",
"durationMs": 3511.833000000024,
"styleRecalcs": 65,
"styleRecalcDurationMs": 16.598,
"layouts": 60,
"layoutDurationMs": 8.286,
"taskDurationMs": 1735.989,
"heapDeltaBytes": 13994648,
"heapUsedBytes": 75423840,
"domNodes": -282,
"jsHeapTotalBytes": 7671808,
"scriptDurationMs": 621.6270000000001,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.670000000000012,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2018.4319999999616,
"styleRecalcs": 7,
"styleRecalcDurationMs": 7.460000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 715.2420000000001,
"heapDeltaBytes": 5908840,
"heapUsedBytes": 66505236,
"domNodes": -280,
"jsHeapTotalBytes": 4526080,
"scriptDurationMs": 116.212,
"eventListeners": -146,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "minimap-idle",
"durationMs": 2040.7229999999572,
"styleRecalcs": 7,
"styleRecalcDurationMs": 7.673000000000003,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 825.312,
"heapDeltaBytes": 6544772,
"heapUsedBytes": 67406552,
"domNodes": -277,
"jsHeapTotalBytes": 5050368,
"scriptDurationMs": 136.477,
"eventListeners": -144,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 594.7579999999562,
"styleRecalcs": 47,
"styleRecalcDurationMs": 12.293,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 418.349,
"heapDeltaBytes": -12028064,
"heapUsedBytes": 55961780,
"domNodes": 20,
"jsHeapTotalBytes": 21893120,
"scriptDurationMs": 125.68399999999998,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 672.505000000001,
"styleRecalcs": 47,
"styleRecalcDurationMs": 12.626000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 443.72,
"heapDeltaBytes": -11775256,
"heapUsedBytes": 56116408,
"domNodes": 20,
"jsHeapTotalBytes": 21630976,
"scriptDurationMs": 134.06699999999998,
"eventListeners": 8,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-idle",
"durationMs": 2028.981999999985,
"styleRecalcs": 9,
"styleRecalcDurationMs": 9.728000000000002,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 594.6949999999999,
"heapDeltaBytes": -22302468,
"heapUsedBytes": 45676304,
"domNodes": 18,
"jsHeapTotalBytes": 20447232,
"scriptDurationMs": 22.848,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
},
{
"name": "subgraph-idle",
"durationMs": 2010.5470000000878,
"styleRecalcs": 10,
"styleRecalcDurationMs": 9.815000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 654.1629999999999,
"heapDeltaBytes": 3460308,
"heapUsedBytes": 71366460,
"domNodes": 20,
"jsHeapTotalBytes": 21368832,
"scriptDurationMs": 25.245,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1739.9730000000204,
"styleRecalcs": 75,
"styleRecalcDurationMs": 39.804,
"layouts": 16,
"layoutDurationMs": 4.369,
"taskDurationMs": 849.3739999999999,
"heapDeltaBytes": -20265388,
"heapUsedBytes": 47643676,
"domNodes": -273,
"jsHeapTotalBytes": 20971520,
"scriptDurationMs": 96.098,
"eventListeners": -148,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.800000000000182
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1722.4220000000514,
"styleRecalcs": 75,
"styleRecalcDurationMs": 40.688,
"layouts": 16,
"layoutDurationMs": 4.7170000000000005,
"taskDurationMs": 886.781,
"heapDeltaBytes": -5435384,
"heapUsedBytes": 62286528,
"domNodes": 61,
"jsHeapTotalBytes": 21893120,
"scriptDurationMs": 105.01100000000001,
"eventListeners": 4,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "subgraph-transition-enter",
"durationMs": 1418.309000000022,
"styleRecalcs": 18,
"styleRecalcDurationMs": 32.18900000000001,
"layouts": 14,
"layoutDurationMs": 13.118999999999998,
"taskDurationMs": 1041.4449999999997,
"heapDeltaBytes": 29112664,
"heapUsedBytes": 97342672,
"domNodes": 13673,
"jsHeapTotalBytes": 15990784,
"scriptDurationMs": 42.09299999999999,
"eventListeners": 2371,
"totalBlockingTimeMs": 142,
"frameDurationMs": 16.666666666666636,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 8654.597999999965,
"styleRecalcs": 249,
"styleRecalcDurationMs": 37.793,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 4902.383000000001,
"heapDeltaBytes": 12372604,
"heapUsedBytes": 71348680,
"domNodes": -276,
"jsHeapTotalBytes": 7061504,
"scriptDurationMs": 1510.973,
"eventListeners": -126,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "viewport-pan-sweep",
"durationMs": 9198.834999999917,
"styleRecalcs": 249,
"styleRecalcDurationMs": 39.93100000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 5106.671,
"heapDeltaBytes": 15435552,
"heapUsedBytes": 74637372,
"domNodes": -274,
"jsHeapTotalBytes": 6799360,
"scriptDurationMs": 1609.044,
"eventListeners": -126,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "vue-large-graph-idle",
"durationMs": 17113.179999999942,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17075.862,
"heapDeltaBytes": -42233224,
"heapUsedBytes": 166931892,
"domNodes": -8312,
"jsHeapTotalBytes": -15142912,
"scriptDurationMs": 598.9219999999999,
"eventListeners": -16387,
"totalBlockingTimeMs": 0,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.80000000000291
},
{
"name": "vue-large-graph-idle",
"durationMs": 17705.239000000005,
"styleRecalcs": 0,
"styleRecalcDurationMs": 0,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 17684.091,
"heapDeltaBytes": -28509388,
"heapUsedBytes": 179699976,
"domNodes": -8312,
"jsHeapTotalBytes": -13832192,
"scriptDurationMs": 610.452,
"eventListeners": -16389,
"totalBlockingTimeMs": 0,
"frameDurationMs": 18.33666666666662,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 20674.622999999996,
"styleRecalcs": 142,
"styleRecalcDurationMs": 17.724000000000018,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 20606.156,
"heapDeltaBytes": -30251788,
"heapUsedBytes": 178112960,
"domNodes": -8312,
"jsHeapTotalBytes": -12083200,
"scriptDurationMs": 946.897,
"eventListeners": -16385,
"totalBlockingTimeMs": 250,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "vue-large-graph-pan",
"durationMs": 21400.11800000002,
"styleRecalcs": 144,
"styleRecalcDurationMs": 19.67399999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 21358.184,
"heapDeltaBytes": -33268208,
"heapUsedBytes": 166163292,
"domNodes": -8312,
"jsHeapTotalBytes": -13570048,
"scriptDurationMs": 926.3249999999999,
"eventListeners": -16379,
"totalBlockingTimeMs": 302,
"frameDurationMs": 17.776666666666642,
"p95FrameDurationMs": 16.799999999999272
},
{
"name": "workflow-execution",
"durationMs": 460.6309999999212,
"styleRecalcs": 13,
"styleRecalcDurationMs": 18.933,
"layouts": 3,
"layoutDurationMs": 0.675,
"taskDurationMs": 122.47699999999999,
"heapDeltaBytes": -15832268,
"heapUsedBytes": 51095768,
"domNodes": 130,
"jsHeapTotalBytes": 7475200,
"scriptDurationMs": 10.975999999999997,
"eventListeners": 67,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.66333333333332,
"p95FrameDurationMs": 16.700000000000728
},
{
"name": "workflow-execution",
"durationMs": 469.6639999999661,
"styleRecalcs": 13,
"styleRecalcDurationMs": 19.793,
"layouts": 3,
"layoutDurationMs": 0.71,
"taskDurationMs": 118.595,
"heapDeltaBytes": -16044156,
"heapUsedBytes": 50996672,
"domNodes": 119,
"jsHeapTotalBytes": 7475200,
"scriptDurationMs": 11.106,
"eventListeners": 65,
"totalBlockingTimeMs": 0,
"frameDurationMs": 16.666666666666668,
"p95FrameDurationMs": 16.699999999999818
}
]
} |
🌐 Website E2ETip All tests passed.
🔗 Website PreviewWebsite Preview: https://comfy-website-preview-pr-14139.vercel.app This commit: https://website-frontend-5iyqxe1fz-comfyui.vercel.app Last updated: 2026-07-28T03:26:27Z for |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a video filmstrip trimming component with pointer and keyboard scrubbing, trim-aware playback, localized duration and file-size formatting, English video-edit strings, and design-system color tokens. Vitest coverage validates UI states, scrubbing, playback, and formatting behavior. ChangesVideo trim editing
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant VideoFilmstripTrim
participant useTimelineScrub
participant useTrimPlayback
participant HTMLVideoElement
User->>VideoFilmstripTrim: scrub or toggle playback
VideoFilmstripTrim->>useTimelineScrub: startScrubDrag
useTimelineScrub->>VideoFilmstripTrim: update playheadFrame and emit scrub
VideoFilmstripTrim->>useTrimPlayback: handleScrub or change isPlaying
useTrimPlayback->>HTMLVideoElement: seek, play, or pause
HTMLVideoElement->>useTrimPlayback: timeupdate
useTrimPlayback->>VideoFilmstripTrim: update playheadFrame
Possibly related PRs
Suggested reviewers: Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Biome (2.5.3)packages/design-system/src/css/style.cssFile contains syntax errors that prevent linting: Line 9: Tailwind-specific syntax is disabled.; Line 11: Tailwind-specific syntax is disabled.; Line 13: Tailwind-specific syntax is disabled.; Line 16: Tailwind-specific syntax is disabled.; Line 19: Tailwind-specific syntax is disabled.; Line 21: Tailwind-specific syntax is disabled.; Line 23: Tailwind-specific syntax is disabled.; Line 415: Tailwind-specific syntax is disabled.; Line 568: Tailwind-specific syntax is disabled.; Line 574: Tailwind-specific syntax is disabled.; Line 580: Tailwind-specific syntax is disabled.; Line 595: Tailwind-specific syntax is disabled.; Line 1859: Tailwind-specific syntax is disabled. 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.
Actionable comments posted: 5
🤖 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.
Inline comments:
In `@packages/design-system/src/css/style.css`:
- Around line 252-254: Update the --video-trim-selection-background declaration
to use `#ffd500` directly instead of the undefined --color-datatype-CLIP fallback,
and preserve --video-trim-playhead-background as the existing video-trim token.
In `@src/components/videoEdit/VideoFilmstripTrim.test.ts`:
- Around line 45-49: Add independent hardcoded boundary assertions to the
VideoFilmstripTrim tests instead of relying solely on expectedFrameAt, covering
exact left and right edges and confirming frame 0 and frameMax. Keep the helper
for general mapping checks, but ensure these assertions validate the public
behavior without duplicating pointerToFrame’s formula.
In `@src/composables/video/useTrimPlayback.test.ts`:
- Around line 81-170: The useTrimPlayback test suite lacks coverage for playback
rejection and trim-bound changes during active playback. Add a test covering
handlePlaybackChange’s video.play() rejection path and assert isPlaying becomes
false, plus a test that changes startFrame or endFrame while isPlaying is true
and verifies the playhead/currentTime are reseeked or clamped to the updated
trim window; preserve existing disabled and boundary behavior.
In `@src/composables/video/useTrimPlayback.ts`:
- Around line 92-104: Update resolvePlayheadTrimCollision so seekPreviewToFrame
is called whenever the playhead is clamped to a changed trim boundary,
regardless of isPlaying.value. Preserve the existing no-op behavior when the
playhead remains within bounds, and ensure handleTimeUpdate retains its
upper-bound playback behavior.
In `@src/composables/video/useVideoEditFormats.test.ts`:
- Around line 35-43: Add boundary assertions to the existing “picks the unit by
magnitude” test for formatFileSize: verify 1024 returns the kilobyte format with
value 1, and 1024 * 1024 returns the megabyte format with value 1. Keep the
current lower-magnitude and fractional-megabyte assertions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b229535e-8059-4372-8376-0995715eff17
📒 Files selected for processing (9)
packages/design-system/src/css/style.csssrc/components/videoEdit/VideoFilmstripTrim.test.tssrc/components/videoEdit/VideoFilmstripTrim.vuesrc/composables/video/useTimelineScrub.tssrc/composables/video/useTrimPlayback.test.tssrc/composables/video/useTrimPlayback.tssrc/composables/video/useVideoEditFormats.test.tssrc/composables/video/useVideoEditFormats.tssrc/locales/en/main.json
e37c738 to
804f1c4
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 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.
Inline comments:
In `@src/components/videoEdit/VideoFilmstripTrim.test.ts`:
- Around line 6-12: Update the vi.hoisted factory defining activeHandle to be
async and obtain ref via dynamic import('vue') instead of require('vue');
preserve the existing Ref typing and activeHandle initialization.
In `@src/components/videoEdit/VideoFilmstripTrim.vue`:
- Around line 76-107: Update the filmstrip loading accessibility in the wrapper
containing `data-testid="filmstrip-track"`: keep decorative thumbnails hidden
from assistive technology, but move the skeleton’s loading status (`aria-busy`
and localized label) outside the `aria-hidden="true"` subtree so it is exposed
while loading.
In `@src/composables/video/useTimelineScrub.ts`:
- Around line 60-70: Update startScrubDrag to guard
el.setPointerCapture(event.pointerId) against exceptions, ensuring
isScrubDragging is reset and cleanupScrubDrag is handled if capture fails so the
drag state cannot remain stuck. Preserve the existing successful pointer-capture
flow and listener setup.
- Around line 48-58: Update updateScrubFromPointer to clamp the pointer-derived
frame before comparing it with playheadFrame, so out-of-bounds pointer movements
are deduplicated while preserving scrubToFrame’s clamping behavior. Ensure
startScrubDrag still forces the initial scrubToFrame emission when its initial
pointer position matches the current frame.
In `@src/composables/video/useTrimPlayback.ts`:
- Line 1: Remove the UTF-8 BOM from the beginning of both
src/composables/video/useTrimPlayback.ts at lines 1-1 and
src/composables/video/useTrimPlayback.test.ts at lines 1-1, re-saving each file
as plain UTF-8 while leaving their imports and contents unchanged.
- Around line 40-70: Update waitForVideoSeek to guarantee settlement by adding a
module-level SEEK_TIMEOUT_MS fallback timer, with finish declared before the
timer and clearing the timeout when seeked or error fires. In
seekPreviewToFrame, preserve seekId checks for normal completion but ensure a
superseded seek’s timeout or event cannot leave isSeeking stuck true; only relax
the staleness guard as needed to clear the state for abandoned seeks.
In `@src/composables/video/useVideoEditFormats.ts`:
- Around line 6-25: The formatDuration and formatFileSize helpers must reject
NaN, negative, and infinite metadata while preserving zero as the valid duration
fallback case; update src/composables/video/useVideoEditFormats.ts lines 6-25 to
validate these inputs before formatting and return the established fallback
translations. Add matching NaN, negative, and Infinity cases in
src/composables/video/useVideoEditFormats.test.ts lines 28-45, verifying each
uses the fallback contract.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: bc329b67-fed7-4ba3-bb79-a2c60535d5d4
📒 Files selected for processing (9)
packages/design-system/src/css/style.csssrc/components/videoEdit/VideoFilmstripTrim.test.tssrc/components/videoEdit/VideoFilmstripTrim.vuesrc/composables/video/useTimelineScrub.tssrc/composables/video/useTrimPlayback.test.tssrc/composables/video/useTrimPlayback.tssrc/composables/video/useVideoEditFormats.test.tssrc/composables/video/useVideoEditFormats.tssrc/locales/en/main.json
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## main #14139 +/- ##
==========================================
- Coverage 79.24% 79.11% -0.14%
==========================================
Files 1730 1746 +16
Lines 96155 97439 +1284
Branches 30905 32025 +1120
==========================================
+ Hits 76197 77087 +890
- Misses 19578 19961 +383
- Partials 380 391 +11
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 45 files with indirect coverage changes 🚀 New features to boost your workflow:
|
804f1c4 to
048dbf5
Compare
dante01yoon
left a comment
There was a problem hiding this comment.
Two user-facing issues need addressing before merge: the sampled filmstrip does not represent the full duration at normal aspect ratios, and preview seeking is unavailable from the keyboard.
| :src="thumbnail" | ||
| alt="" | ||
| draggable="false" | ||
| class="h-full w-auto shrink-0 select-none" |
There was a problem hiding this comment.
issue: These thumbnails keep their intrinsic width and cannot shrink, while the filmstrip container clips overflow. With the 20 samples produced by useVideoFilmstrip, a 16:9 frame is about 85px wide at this 48px height, so a typical node-width timeline shows only the first few samples and clips the rest of the video. Could we size the samples into equal-width slots across the available track (cropping with object-cover as needed) so the full duration is represented?
| : 'cursor-grab' | ||
| ) | ||
| " | ||
| @pointerdown.stop="startScrubDrag" |
There was a problem hiding this comment.
issue: Preview seeking is only wired to pointer events on this non-focusable div (and the playhead is also a div). The intended VideoEditPanel caller renders the <video> without native controls, so keyboard users can play/pause but cannot seek the preview. Could the track expose slider semantics (tabindex, aria-valuemin/max/now) and Arrow/Home/End handling that updates the playhead and emits scrub?
048dbf5 to
fe6a613
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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.
Inline comments:
In `@src/components/videoEdit/VideoFilmstripTrim.test.ts`:
- Around line 449-461: Extend the disabled-state test in
VideoFilmstripTrim.test.ts to simulate pointerDown on the filmstrip track while
disabled is true, then assert playheadFrame remains unchanged. Target the
track’s existing test identifier and validate the startScrubDrag isDisabled
guard in VideoFilmstripTrim.vue, while preserving the existing hidden-handle
assertions.
In `@src/composables/video/useVideoEditFormats.test.ts`:
- Around line 20-25: Add an assertion in the “rounds to a tenth of a second”
test for an upward-rounding input such as 2.46, expecting the formatted duration
to use 2.5. Keep the existing assertions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4c1bccfc-6e1d-4e67-afa5-e77777a9180d
📒 Files selected for processing (9)
packages/design-system/src/css/style.csssrc/components/videoEdit/VideoFilmstripTrim.test.tssrc/components/videoEdit/VideoFilmstripTrim.vuesrc/composables/video/useTimelineScrub.tssrc/composables/video/useTrimPlayback.test.tssrc/composables/video/useTrimPlayback.tssrc/composables/video/useVideoEditFormats.test.tssrc/composables/video/useVideoEditFormats.tssrc/locales/en/main.json
fe6a613 to
91acfb5
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/components/videoEdit/VideoFilmstripTrim.test.ts (1)
449-461: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winStill missing interaction coverage for the
disabledscrub/keydown guard.This test only asserts handles are hidden when
disabled: true; it doesn't exercisestartScrubDrag'sisDisabled()guard (disabled || totalFrames <= 1inuseTimelineScrub.ts) orhandleTrackKeydown's early return. ApointerDown/keyDownon the track whiledisabled: trueassertingplayheadFramedoesn't change would directly validate the lockout path.As per path instructions,
.agents/checks/test-quality.mdcalls out checking for "edge-case coverage (empty/null/error/disabled states, boundary conditions)."🤖 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/components/videoEdit/VideoFilmstripTrim.test.ts` around lines 449 - 461, The disabled-state test only verifies hidden handles and not interaction lockout. Extend the test around renderFilmstrip with disabled: true to trigger pointerDown and keyDown on the track, then assert playheadFrame remains unchanged, covering both startScrubDrag’s isDisabled guard and handleTrackKeydown’s early return.Source: Path instructions
🤖 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.
Inline comments:
In `@src/composables/video/useTimelineScrub.ts`:
- Around line 59-92: Update startScrubDrag so the active pointerId is captured
and onMove, endDrag, and their listener handling only respond to events matching
that pointer. Preserve the existing cleanup behavior for the initiating pointer
while ignoring concurrent pointers’ move, up, and lostpointercapture events.
In `@src/composables/video/useVideoEditFormats.ts`:
- Around line 6-7: Update formatDuration in
src/composables/video/useVideoEditFormats.ts at lines 6-7 to accept number |
null while preserving the existing zero-label behavior. Add an assertion in
src/composables/video/useVideoEditFormats.test.ts at lines 14-18 verifying
formatDuration(null) returns the zero-duration label.
---
Duplicate comments:
In `@src/components/videoEdit/VideoFilmstripTrim.test.ts`:
- Around line 449-461: The disabled-state test only verifies hidden handles and
not interaction lockout. Extend the test around renderFilmstrip with disabled:
true to trigger pointerDown and keyDown on the track, then assert playheadFrame
remains unchanged, covering both startScrubDrag’s isDisabled guard and
handleTrackKeydown’s early return.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 3f3593d6-343d-42e9-8665-4bd90bffcd57
📒 Files selected for processing (9)
packages/design-system/src/css/style.csssrc/components/videoEdit/VideoFilmstripTrim.test.tssrc/components/videoEdit/VideoFilmstripTrim.vuesrc/composables/video/useTimelineScrub.tssrc/composables/video/useTrimPlayback.test.tssrc/composables/video/useTrimPlayback.tssrc/composables/video/useVideoEditFormats.test.tssrc/composables/video/useVideoEditFormats.tssrc/locales/en/main.json
91acfb5 to
c737f70
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In `@src/components/videoEdit/VideoFilmstripTrim.vue`:
- Around line 41-48: Move the slider semantics from the outer filmstrip
container to the playhead wrapper or another non-container descendant: relocate
role, tabindex, aria-valuemin, aria-valuemax, aria-valuenow, and
handleTrackKeydown there, while leaving the outer div as a plain positioned
container. Add aria-disabled="true" whenever disabled is true, preserving the
existing enabled behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: aa90bf0e-b633-42c7-b625-2abf7d8c1ac1
📒 Files selected for processing (11)
packages/design-system/src/css/style.csssrc/components/videoEdit/VideoFilmstripTrim.test.tssrc/components/videoEdit/VideoFilmstripTrim.vuesrc/composables/useRangeEditor.test.tssrc/composables/useRangeEditor.tssrc/composables/video/useTimelineScrub.tssrc/composables/video/useTrimPlayback.test.tssrc/composables/video/useTrimPlayback.tssrc/composables/video/useVideoEditFormats.test.tssrc/composables/video/useVideoEditFormats.tssrc/locales/en/main.json
This is seperate part for the big PR of video edit, crop, trim PR #14118
Summary
Timeline building blocks for the upcoming VIDEO_EDIT rich widget: