Skip to content

feat(assets): wire infinite scroll to the flat-output provider in the widget select dropdown#12780

Merged
mattmillerai merged 11 commits into
mainfrom
matt/fe-988-fe-wire-infinite-scroll-to-the-flat-output-provider-in-the
Jun 22, 2026
Merged

feat(assets): wire infinite scroll to the flat-output provider in the widget select dropdown#12780
mattmillerai merged 11 commits into
mainfrom
matt/fe-988-fe-wire-infinite-scroll-to-the-flat-output-provider-in-the

Conversation

@mattmillerai

Copy link
Copy Markdown
Contributor

Summary

Wires the previously-dormant loadMore path of the flat-output assets provider into the widget select dropdown, so cloud users with more than one page of outputs can actually reach them. Stacked on #12774 (FE-985); retargets to main when that merges.

Changes

  • What: VirtualGrid's existing approach-end event now forwards through FormDropdownMenuFormDropdownWidgetSelectDropdown, which calls outputMediaAssets.loadMore() guarded by hasMore/isLoadingMore and debounced 300ms — the same idiom as AssetsSidebarTab. A spinner row (loadingMore prop) renders below the grid while a page is in flight. On cloud this drives the FE-985 cursor walk; on OSS it drives the FE-962 jobs-history cursor walk via useAssetsApi.

Review Focus

  • Verified end-to-end against the dev server with a mocked 100-asset backend: scroll → after=cur-40after=cur-80 → stops at has_more:false (100/100, no duplicate fetches).

  • Known platform limitation, not introduced here: VueUse ≥14's throttleFilter with leading=false drops events spaced wider than the throttle window, so useScroll's throttle: 64 in VirtualGrid never reports discrete mouse-wheel scrolls — only high-frequency (trackpad-style) scrolling triggers approach-end. This equally affects the assets sidebar and manager dialog today; bug filed separately with root cause. Fixing it makes this wiring work for wheel users with no further changes.

  • Underfill edge: approach-end cannot fire when loaded items don't overflow the viewport (shared VirtualGrid trait with the sidebar); with the 200-item page size this only matters for heavily-filtered media types.

  • Fixes FE-988

🤖 Generated with Claude Code

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jun 11, 2026
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds an infinite-scroll capability to the asset select dropdown. A new approach-end event is threaded from VirtualGrid through FormDropdownMenu and FormDropdown to WidgetSelectDropdown, which triggers a debounced loadMore. Concurrently, assetsStore switches flat-output asset pagination from offset-based to cursor-based using getAssetsPageByTag.

Changes

Infinite Scroll Dropdown + Cursor Pagination

Layer / File(s) Summary
FormDropdownMenu: approach-end event and loading indicator
src/renderer/.../form/dropdown/FormDropdownMenu.vue, FormDropdownMenu.test.ts
Adds loadingMore prop (default false), re-emits approach-end from VirtualGrid, renders a conditional loading row below the list, and covers both behaviors with new tests using a clickable stub and rerender.
FormDropdown: loadingMore prop and approach-end forwarding
src/renderer/.../form/dropdown/FormDropdown.vue
Adds optional loadingMore?: boolean prop, declares approach-end in defineEmits, and forwards both to/from FormDropdownMenu in the template.
WidgetSelectDropdown: debounced loadMore wiring
src/renderer/.../widgets/components/WidgetSelectDropdown.vue
Imports useDebounceFn, adds a debounced handleApproachEnd guarded by hasMore/loading/isLoadingMore, and binds :loading-more and @approach-end on FormDropdown.
assetsStore: cursor-based flat-output pagination
src/stores/assetsStore.ts, src/stores/assetsStore.test.ts
Introduces flatOutputNextCursor state, rewrites fetch logic to use getAssetsPageByTag with cursor threading, dedupe filtering, and has_more + cursor-stuck termination. Tests are refactored with a makePage helper covering cursor threading, retry preservation, empty-page termination, and concurrency deduplication.

Sequence Diagram

sequenceDiagram
  participant User
  participant WidgetSelectDropdown
  participant FormDropdown
  participant FormDropdownMenu
  participant VirtualGrid
  participant assetsStore
  participant assetService

  User->>VirtualGrid: scrolls near end of list
  VirtualGrid->>FormDropdownMenu: emit approach-end
  FormDropdownMenu->>FormDropdown: emit approach-end
  FormDropdown->>WidgetSelectDropdown: emit approach-end
  WidgetSelectDropdown->>WidgetSelectDropdown: handleApproachEnd (debounced, guards hasMore/loading)
  WidgetSelectDropdown->>assetsStore: loadMoreFlatOutputs()
  assetsStore->>assetService: getAssetsPageByTag('output', true, {limit, after: cursor})
  assetService-->>assetsStore: AssetResponse {items, has_more, next_cursor}
  assetsStore->>assetsStore: dedupe + append, update flatOutputNextCursor
  assetsStore-->>FormDropdownMenu: isLoadingMore → renders loading row
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • dante01yoon

Poem

🐇 Hop, hop, the list grows long,
Cursor threads the pages strong,
approach-end bubbles up the chain,
A spinner spins, then loads again,
No more offsets — cursors reign!
✨ The rabbit scrolls with joy today. ✨


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore (reviewers only)

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
End-To-End Regression Coverage For Fixes ❌ Error PR uses bug-fix language ("fix(assets)...") and changes src/ files for frontend application, but browser_tests changes are mass-imported test files (769 new files added) unrelated to FE-988 fix, no... Add or update a Playwright regression test under browser_tests/tests/ specific to the infinite scroll widget dropdown functionality, or add a concrete explanation in the PR description of why an E2E regression test is not practical.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(assets): wire infinite scroll to the flat-output provider in the widget select dropdown' clearly and specifically summarizes the main change—connecting infinite scroll functionality to the dropdown's flat-output assets provider.
Description check ✅ Passed The description comprehensively covers the Summary, Changes (What/Dependencies), and Review Focus sections with detailed implementation notes, known limitations, and verification details, aligning well with the template structure.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Adr Compliance For Entity/Litegraph Changes ✅ Passed PR changes are in src/renderer/ and src/stores/ only—none in src/lib/litegraph/, src/ecs/, or graph entity paths. ADR compliance check not applicable.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/fe-988-fe-wire-infinite-scroll-to-the-flat-output-provider-in-the

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.76923% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...eNodes/widgets/components/WidgetSelectDropdown.vue 16.66% 5 Missing ⚠️
@@             Coverage Diff             @@
##             main   #12780       +/-   ##
===========================================
- Coverage   75.59%   62.90%   -12.70%     
===========================================
  Files        1570     1459      -111     
  Lines       95272    74414    -20858     
  Branches    27359    19340     -8019     
===========================================
- Hits        72021    46810    -25211     
- Misses      22458    27260     +4802     
+ Partials      793      344      -449     
Flag Coverage Δ
e2e ?
unit 62.90% <80.76%> (+0.75%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
.../widgets/components/form/dropdown/FormDropdown.vue 84.61% <100.00%> (-6.92%) ⬇️
...gets/components/form/dropdown/FormDropdownMenu.vue 83.87% <100.00%> (-3.23%) ⬇️
src/stores/assetsStore.ts 90.64% <100.00%> (+0.83%) ⬆️
...eNodes/widgets/components/WidgetSelectDropdown.vue 53.24% <16.66%> (-22.76%) ⬇️

... and 1145 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

pull Bot pushed a commit to Mu-L/ComfyUI_frontend that referenced this pull request Jun 11, 2026
…rg#12781)

## Summary

Every `VirtualGrid` consumer (assets sidebar, manager dialog, widget
select dropdown) is blind to discrete mouse-wheel scrolling:
`useScroll`'s `throttle: 64` never reports scroll position, so the
virtualization window stays frozen — users see blank space below the
first viewport of items and `approach-end` (infinite scroll) never
fires. Trackpad scrolling masks the bug by emitting events faster than
the throttle window.

## Changes

- **What**: drop the `throttle` option from `useScroll` in `VirtualGrid`
and remove the `scrollThrottle` prop (no consumer passes it). Scroll
events are frame-aligned and the handler is cheap, so the throttle
bought nothing even when it worked.
- **Root cause**: VueUse ≥14 `throttleFilter` with `leading=false` (what
`useScroll` uses) marks spaced-out events as executed without executing
them — each event re-arms an `isLeading` restore timer that makes the
next event skip its invoke, and the trailing branch is unreachable when
`elapsed > duration`. Regression of vueuse#2390; still present on vueuse
`main`.

## Review Focus

- Verified live against staging: with the throttle, sidebar scrolled to
`scrollTop` 1250 while `scrollY` stayed 0 and the render window stayed
at `[0..3)` of 27 (blank viewport); with this fix, `scrollY` tracks 1:1
and the window advances. Bare-vs-throttled `useScroll` compared
side-by-side on the same element to isolate the cause.
- Unblocks wheel-scroll for Comfy-Org#12780's dropdown infinite scroll with no
changes there.

- Fixes FE-990

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Calls the reusable Comfy-Org/github-workflows cursor-review.yml (single source of truth for panel, judge, prompts, scripts) instead of a standalone copy. Label-gated to the team; secret-bearing jobs skip fork PRs. Judge overridden to Opus 4.8.

@dante01yoon dante01yoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read-only review at 5de4e08 (not approving, per request). Stacked on #12774 — base is matt/fe-985…, so this needs that to merge / a retarget to main first.

The event-forwarding chain (VirtualGrid → FormDropdownMenu → FormDropdown → WidgetSelectDropdown → loadMore) is clean, the debounce + hasMore/isLoadingMore guard mirrors the sidebar idiom, and the spinner row sizes its iconify icon with size-6 (correct — not a font-size class). Tests cover both the approach-end forward and the loading-more row toggle. One non-blocking question inline.

Heads-up: #12417 (FE-732) also edits WidgetSelectDropdown.vue; no logic overlap, but expect a small rebase conflict whichever lands second.

}
}

const handleApproachEnd = useDebounceFn(async () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (non-blocking): per the PR description, VueUse ≥14's throttleFilter(leading=false) makes useScroll's throttle: 64 in VirtualGrid drop discrete mouse-wheel events, so approach-end only fires for high-frequency (trackpad-style) scrolling. That leaves this wiring effectively inert for mouse-wheel users until the separate throttle bug is fixed. Is the intent to land the (harmless-but-inactive) wiring ahead of that fix, or to stack the throttle fix first so FE-988 ships actually-working for everyone? Either is defensible — just flagging that on merge the feature is non-functional for a large share of users.

@mattmillerai mattmillerai Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed on the wiring side: @approach-end is debounced 300ms and guarded by hasMore/isLoadingMore before loadMore(), with :loading-more driving the spinner — correct in isolation and a no-op when approach-end never fires. Your premise holds too: the event originates upstream in VirtualGrid's useScroll({ throttle: 64 }), and the leading=false wheel-event drop lives there, outside this diff.

So this lands as-is: the mouse-wheel dormancy is a pre-existing VirtualGrid throttle limitation that's tracked separately — not introduced or worsened by this PR, and trackpad scrolling works today. Not gating this change.

@mattmillerai mattmillerai added needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch cloud/1.45 Backport PRs for cloud 1.45 labels Jun 17, 2026
@mattmillerai mattmillerai changed the base branch from matt/fe-985-fe-adopt-cursor-pagination-in-the-flat-output-infinite to main June 17, 2026 18:10
@mattmillerai mattmillerai requested a review from a team June 17, 2026 18:10
mattmillerai and others added 7 commits June 17, 2026 11:17
- fetchFlatOutputs threads next_cursor into after on loadMore, falling
  back to offset paging for backends that mint no cursors
- hasMore is now server-authoritative (has_more) instead of the
  page-length heuristic, with empty-page and non-advancing-cursor guards
- reset path clears the cursor and stays a from-the-top head fetch
- pin cursor preservation across a failed loadMore (retry resumes via after)
- pin cursor clearing on refresh via the failed-refresh path (kills a
  surviving mutant on the reset-path clear)
- rename error test to match actual preserve-on-error behavior
- use vi.resetAllMocks to isolate per-test once-queues
… widget select dropdown

- VirtualGrid approach-end forwards through FormDropdownMenu and
  FormDropdown to WidgetSelectDropdown, which loads the next page via
  the assets provider (cursor-paginated on cloud, jobs history on OSS)
- guarded by hasMore/isLoadingMore and debounced, mirroring the
  assets sidebar idiom
- loadingMore spinner row below the grid while a page is in flight
@mattmillerai mattmillerai force-pushed the matt/fe-988-fe-wire-infinite-scroll-to-the-flat-output-provider-in-the branch from 6a5a4ca to 00fc87f Compare June 17, 2026 18:48
@mattmillerai mattmillerai changed the base branch from main to ci/cursor-review-workflow June 17, 2026 18:54
@mattmillerai mattmillerai added the cursor-review Trigger multi-model Cursor agent review on this PR label Jun 17, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

Found 7 finding(s).

Severity Count
🟠 High 1
🟡 Medium 2
🟢 Low 4

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

Comment thread src/stores/assetsStore.ts
Comment thread src/stores/assetsStore.ts Outdated
Comment thread src/stores/assetsStore.ts
Comment thread src/stores/assetsStore.ts
Comment thread src/stores/assetsStore.ts
Base automatically changed from ci/cursor-review-workflow to main June 17, 2026 20:56
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

🎭 Playwright: ✅ 1671 passed, 0 failed · 1 flaky

📊 Browser Reports
  • chromium: View Report (✅ 1652 / ❌ 0 / ⚠️ 0 / ⏭️ 5)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 16 / ❌ 0 / ⚠️ 1 / ⏭️ 0)

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 06/19/2026, 02:37:13 AM UTC

Links

📦 Bundle: 7.44 MB gzip 🔴 +356 B

Details

Summary

  • Raw size: 31.3 MB baseline 31.3 MB — 🔴 +1.73 kB
  • Gzip: 7.44 MB baseline 7.44 MB — 🔴 +356 B
  • Brotli: 5.1 MB baseline 5.1 MB — 🔴 +234 B
  • Bundles: 274 current • 274 baseline • 124 added / 124 removed

Category Glance
Other 🔴 +1.3 kB (10.4 MB) · Utilities & Hooks 🔴 +425 B (3.32 MB) · Vendor & Third-Party ⚪ 0 B (15.3 MB) · Graph Workspace ⚪ 0 B (1.25 MB) · Panels & Settings ⚪ 0 B (523 kB) · Data & Services ⚪ 0 B (266 kB) · + 5 more

App Entry Points — 45.8 kB (baseline 45.8 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-B3u6Hyj9.js (removed) 45.8 kB 🟢 -45.8 kB 🟢 -13.5 kB 🟢 -11.7 kB
assets/index-CrtKkSBt.js (new) 45.8 kB 🔴 +45.8 kB 🔴 +13.5 kB 🔴 +11.7 kB

Status: 1 added / 1 removed

Graph Workspace — 1.25 MB (baseline 1.25 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CTQEKUWr.js (new) 1.25 MB 🔴 +1.25 MB 🔴 +266 kB 🔴 +200 kB
assets/GraphView-NML_yZzY.js (removed) 1.25 MB 🟢 -1.25 MB 🟢 -266 kB 🟢 -201 kB

Status: 1 added / 1 removed

Views & Navigation — 95.3 kB (baseline 95.3 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-B0rZ2wcm.js (new) 19.5 kB 🔴 +19.5 kB 🔴 +5.05 kB 🔴 +4.48 kB
assets/CloudSurveyView-BXoPPiyb.js (removed) 19.5 kB 🟢 -19.5 kB 🟢 -5.05 kB 🟢 -4.48 kB
assets/CloudLoginView-d4kVMcci.js (removed) 11.4 kB 🟢 -11.4 kB 🟢 -3.06 kB 🟢 -2.69 kB
assets/CloudLoginView-DTlS-3i4.js (new) 11.4 kB 🔴 +11.4 kB 🔴 +3.06 kB 🔴 +2.69 kB
assets/CloudSignupView-91K4fmqi.js (new) 9.7 kB 🔴 +9.7 kB 🔴 +2.72 kB 🔴 +2.39 kB
assets/CloudSignupView-ChU_BCRj.js (removed) 9.7 kB 🟢 -9.7 kB 🟢 -2.72 kB 🟢 -2.39 kB
assets/CloudLayoutView-BohAEGOe.js (removed) 9.36 kB 🟢 -9.36 kB 🟢 -2.34 kB 🟢 -2.02 kB
assets/CloudLayoutView-CeGw6KyA.js (new) 9.36 kB 🔴 +9.36 kB 🔴 +2.34 kB 🔴 +2.03 kB
assets/UserCheckView-DYIQT72U.js (new) 8.8 kB 🔴 +8.8 kB 🔴 +2.22 kB 🔴 +1.94 kB
assets/UserCheckView-qWrDAoun.js (removed) 8.8 kB 🟢 -8.8 kB 🟢 -2.22 kB 🟢 -1.93 kB
assets/UserSelectView-BivJb2GW.js (removed) 6 kB 🟢 -6 kB 🟢 -2.15 kB 🟢 -1.89 kB
assets/UserSelectView-C1s3f7vX.js (new) 6 kB 🔴 +6 kB 🔴 +2.15 kB 🔴 +1.89 kB
assets/CloudForgotPasswordView-RVontOcU.js (removed) 5.15 kB 🟢 -5.15 kB 🟢 -1.76 kB 🟢 -1.54 kB
assets/CloudForgotPasswordView-Vn9tMVgB.js (new) 5.15 kB 🔴 +5.15 kB 🔴 +1.76 kB 🔴 +1.54 kB
assets/CloudAuthTimeoutView-BQG1ppqo.js (removed) 4.49 kB 🟢 -4.49 kB 🟢 -1.57 kB 🟢 -1.37 kB
assets/CloudAuthTimeoutView-DYTWNkun.js (new) 4.49 kB 🔴 +4.49 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/CloudSubscriptionRedirectView-CdmknRcU.js (new) 4.3 kB 🔴 +4.3 kB 🔴 +1.57 kB 🔴 +1.39 kB
assets/CloudSubscriptionRedirectView-DpXPdWbD.js (removed) 4.3 kB 🟢 -4.3 kB 🟢 -1.57 kB 🟢 -1.39 kB

Status: 9 added / 9 removed / 3 unchanged

Panels & Settings — 523 kB (baseline 523 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-BGQMhMKF.js (removed) 49.4 kB 🟢 -49.4 kB 🟢 -9.96 kB 🟢 -8.83 kB
assets/KeybindingPanel-CqupT25d.js (new) 49.4 kB 🔴 +49.4 kB 🔴 +9.96 kB 🔴 +8.82 kB
assets/SecretsPanel-BNfiYbTy.js (new) 24.2 kB 🔴 +24.2 kB 🔴 +5.76 kB 🔴 +5.06 kB
assets/SecretsPanel-Dh__rrbn.js (removed) 24.2 kB 🟢 -24.2 kB 🟢 -5.76 kB 🟢 -5.07 kB
assets/LegacyCreditsPanel-C-OZ8jwm.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -5.52 kB 🟢 -4.84 kB
assets/LegacyCreditsPanel-DnVfu5Bb.js (new) 20.9 kB 🔴 +20.9 kB 🔴 +5.52 kB 🔴 +4.85 kB
assets/SubscriptionPanel-BtvdyHDd.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.98 kB 🟢 -4.35 kB
assets/SubscriptionPanel-sXFbdUal.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.98 kB 🔴 +4.36 kB
assets/AboutPanel-_t3p_pb2.js (new) 11.7 kB 🔴 +11.7 kB 🔴 +3.22 kB 🔴 +2.89 kB
assets/AboutPanel-D601W4SL.js (removed) 11.7 kB 🟢 -11.7 kB 🟢 -3.22 kB 🟢 -2.89 kB
assets/ExtensionPanel-C05V3l-m.js (new) 9.03 kB 🔴 +9.03 kB 🔴 +2.5 kB 🔴 +2.2 kB
assets/ExtensionPanel-CzS8n2eb.js (removed) 9.03 kB 🟢 -9.03 kB 🟢 -2.5 kB 🟢 -2.2 kB
assets/ServerConfigPanel-CWart8Cq.js (removed) 6.15 kB 🟢 -6.15 kB 🟢 -1.98 kB 🟢 -1.76 kB
assets/ServerConfigPanel-UeDjrCaL.js (new) 6.15 kB 🔴 +6.15 kB 🔴 +1.98 kB 🔴 +1.76 kB
assets/UserPanel-DDZZdNkG.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.82 kB 🟢 -1.58 kB
assets/UserPanel-twYwT_pv.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.82 kB 🔴 +1.58 kB
assets/refreshRemoteConfig-CH0G_DhT.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +699 B 🔴 +606 B
assets/refreshRemoteConfig-Ci1SZeMs.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -696 B 🟢 -598 B
assets/cloudRemoteConfig-BcxFYjl3.js (new) 990 B 🔴 +990 B 🔴 +543 B 🔴 +454 B
assets/cloudRemoteConfig-BulY2GLo.js (removed) 990 B 🟢 -990 B 🟢 -541 B 🟢 -455 B

Status: 10 added / 10 removed / 14 unchanged

User & Accounts — 19.9 kB (baseline 19.9 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-BiKzy15e.js (removed) 3.69 kB 🟢 -3.69 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/auth-CnzvpK7h.js (new) 3.69 kB 🔴 +3.69 kB 🔴 +1.3 kB 🔴 +1.12 kB
assets/usePostAuthRedirect-BNB4V13-.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/usePostAuthRedirect-wUZsZvS4.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.28 kB 🟢 -1.11 kB
assets/SignUpForm-BGUlqrEo.js (removed) 3.19 kB 🟢 -3.19 kB 🟢 -1.29 kB 🟢 -1.15 kB
assets/SignUpForm-D-m8X4ve.js (new) 3.19 kB 🔴 +3.19 kB 🔴 +1.29 kB 🔴 +1.15 kB
assets/UpdatePasswordContent-BNqpJQIb.js (removed) 1.92 kB 🟢 -1.92 kB 🟢 -880 B 🟢 -769 B
assets/UpdatePasswordContent-C_gUvGHN.js (new) 1.92 kB 🔴 +1.92 kB 🔴 +879 B 🔴 +765 B
assets/authStore-DcMcMt3U.js (removed) 130 B 🟢 -130 B 🟢 -109 B 🟢 -105 B
assets/authStore-PFz_h2Kd.js (new) 130 B 🔴 +130 B 🔴 +109 B 🔴 +108 B
assets/auth-Dj8PniTR.js (removed) 105 B 🟢 -105 B 🟢 -96 B 🟢 -81 B
assets/auth-Dv3zXHyW.js (new) 105 B 🔴 +105 B 🔴 +96 B 🔴 +88 B

Status: 6 added / 6 removed / 3 unchanged

Editors & Dialogs — 112 kB (baseline 112 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyHubPublishDialog-DtukkUnn.js (new) 86 kB 🔴 +86 kB 🔴 +18.6 kB 🔴 +15.8 kB
assets/ComfyHubPublishDialog-MyGNmJS2.js (removed) 86 kB 🟢 -86 kB 🟢 -18.6 kB 🟢 -15.9 kB
assets/useShareDialog-DFyyD5tj.js (new) 23.4 kB 🔴 +23.4 kB 🔴 +5.54 kB 🔴 +4.92 kB
assets/useShareDialog-TLZzjAv6.js (removed) 23.4 kB 🟢 -23.4 kB 🟢 -5.55 kB 🟢 -4.91 kB
assets/ComfyHubPublishDialog-DqzKvyr_.js (removed) 143 B 🟢 -143 B 🟢 -105 B 🟢 -88 B
assets/ComfyHubPublishDialog-Y5kM13GW.js (new) 143 B 🔴 +143 B 🔴 +105 B 🔴 +91 B
assets/useSubscriptionDialog-DEo32t67.js (new) 110 B 🔴 +110 B 🔴 +102 B 🔴 +90 B
assets/useSubscriptionDialog-DwJURLel.js (removed) 110 B 🟢 -110 B 🟢 -102 B 🟢 -88 B

Status: 4 added / 4 removed / 1 unchanged

UI Components — 57.2 kB (baseline 57.2 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-BmLqDP4S.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.83 kB 🔴 +3.42 kB
assets/ComfyQueueButton-BvwiArEu.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.83 kB 🟢 -3.42 kB
assets/useTerminalTabs-BOr-tg1e.js (new) 12.1 kB 🔴 +12.1 kB 🔴 +3.83 kB 🔴 +3.38 kB
assets/useTerminalTabs-BPFgS-Dn.js (removed) 12.1 kB 🟢 -12.1 kB 🟢 -3.84 kB 🟢 -3.39 kB
assets/SubscribeButton-MiNwYIXN.js (new) 2.44 kB 🔴 +2.44 kB 🔴 +1.05 kB 🔴 +928 B
assets/SubscribeButton-oiHXGL7w.js (removed) 2.44 kB 🟢 -2.44 kB 🟢 -1.05 kB 🟢 -943 B
assets/cloudFeedbackTopbarButton-5Mxll6y_.js (removed) 829 B 🟢 -829 B 🟢 -497 B 🟢 -416 B
assets/cloudFeedbackTopbarButton-BnUA2_GZ.js (new) 829 B 🔴 +829 B 🔴 +499 B 🔴 +452 B
assets/ComfyQueueButton-CG2zZ1_P.js (removed) 128 B 🟢 -128 B 🟢 -99 B 🟢 -91 B
assets/ComfyQueueButton-CjFFWh2V.js (new) 128 B 🔴 +128 B 🔴 +99 B 🔴 +90 B

Status: 5 added / 5 removed / 8 unchanged

Data & Services — 266 kB (baseline 266 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/load3dService-Blo3Cv0O.js (new) 125 kB 🔴 +125 kB 🔴 +27.6 kB 🔴 +23.4 kB
assets/load3dService-VuHM_sBb.js (removed) 125 kB 🟢 -125 kB 🟢 -27.6 kB 🟢 -23.4 kB
assets/api-BrssVGr8.js (removed) 84.3 kB 🟢 -84.3 kB 🟢 -22.7 kB 🟢 -19.6 kB
assets/api-CkdsCN1v.js (new) 84.3 kB 🔴 +84.3 kB 🔴 +22.7 kB 🔴 +19.6 kB
assets/workflowShareService-Dbv8iO7Q.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.91 kB 🟢 -4.36 kB
assets/workflowShareService-dRIGzBd6.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.91 kB 🔴 +4.35 kB
assets/keybindingService-B9IfmXi7.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.67 kB 🟢 -3.23 kB
assets/keybindingService-BH1VsuGa.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.67 kB 🔴 +3.23 kB
assets/releaseStore-KhsOuZNG.js (new) 8.29 kB 🔴 +8.29 kB 🔴 +2.34 kB 🔴 +2.05 kB
assets/releaseStore-kPkwe14L.js (removed) 8.29 kB 🟢 -8.29 kB 🟢 -2.34 kB 🟢 -2.04 kB
assets/extensionStore-6_ZCbtGA.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.57 kB
assets/extensionStore-ByDL6W1C.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.58 kB
assets/userStore-B83r2WS_.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +931 B 🔴 +828 B
assets/userStore-Bh4OA09V.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -930 B 🟢 -819 B
assets/audioService-Dewm4UYC.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -861 B 🟢 -747 B
assets/audioService-qGtmIM_i.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +863 B 🔴 +749 B
assets/dialogService-CTD-NZCe.js (new) 100 B 🔴 +100 B 🔴 +99 B 🔴 +93 B
assets/dialogService-Hg-ANIFN.js (removed) 100 B 🟢 -100 B 🟢 -99 B 🟢 -95 B
assets/settingStore-BDI-wizK.js (removed) 98 B 🟢 -98 B 🟢 -98 B 🟢 -89 B
assets/settingStore-CzKGJY_r.js (new) 98 B 🔴 +98 B 🔴 +98 B 🔴 +91 B
assets/assetsStore-C6Eo3afY.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +88 B
assets/assetsStore-XOdVtfDt.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -86 B
assets/releaseStore-DEZb1TjR.js (removed) 95 B 🟢 -95 B 🟢 -86 B 🟢 -87 B
assets/releaseStore-DtCPIJWR.js (new) 95 B 🔴 +95 B 🔴 +86 B 🔴 +81 B

Status: 12 added / 12 removed / 3 unchanged

Utilities & Hooks — 3.32 MB (baseline 3.32 MB) • 🔴 +425 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/promotionUtils-BSQH0Zmv.js (new) 2.97 MB 🔴 +2.97 MB 🔴 +686 kB 🔴 +517 kB
assets/promotionUtils-DdHQ2STH.js (removed) 2.97 MB 🟢 -2.97 MB 🟢 -686 kB 🟢 -517 kB
assets/useConflictDetection-Bu_yyhbx.js (removed) 233 kB 🟢 -233 kB 🟢 -52 kB 🟢 -42.3 kB
assets/useConflictDetection-CfzMTdD2.js (new) 233 kB 🔴 +233 kB 🔴 +52 kB 🔴 +42.3 kB
assets/useLoad3d-CotqbHrO.js (removed) 25.5 kB 🟢 -25.5 kB 🟢 -5.75 kB 🟢 -5.11 kB
assets/useLoad3d-DiGmpD73.js (new) 25.5 kB 🔴 +25.5 kB 🔴 +5.75 kB 🔴 +5.09 kB
assets/useLoad3dViewer-BrrlwN8E.js (removed) 21.1 kB 🟢 -21.1 kB 🟢 -4.97 kB 🟢 -4.34 kB
assets/useLoad3dViewer-D7V_oBG7.js (new) 21.1 kB 🔴 +21.1 kB 🔴 +4.98 kB 🔴 +4.34 kB
assets/useFeatureFlags-BHY-2NT6.js (new) 6.36 kB 🔴 +6.36 kB 🔴 +2.01 kB 🔴 +1.7 kB
assets/useFeatureFlags-D4KKpMZy.js (removed) 6.36 kB 🟢 -6.36 kB 🟢 -2.01 kB 🟢 -1.7 kB
assets/useSessionCookie-DcVR8e0K.js (new) 3.33 kB 🔴 +3.33 kB 🔴 +1.15 kB 🔴 +981 B
assets/useSessionCookie-h5Uq2mtP.js (removed) 3.33 kB 🟢 -3.33 kB 🟢 -1.15 kB 🟢 -978 B
assets/subscriptionCheckoutUtil-ComRDOr0.js (removed) 3.31 kB 🟢 -3.31 kB 🟢 -1.36 kB 🟢 -1.19 kB
assets/subscriptionCheckoutUtil-rqrdq-4-.js (new) 3.31 kB 🔴 +3.31 kB 🔴 +1.36 kB 🔴 +1.19 kB
assets/assetPreviewUtil-B1mEV_83.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1 kB 🟢 -880 B
assets/assetPreviewUtil-DalCL0oV.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.01 kB 🔴 +874 B
assets/useUpstreamValue-CRIC7UZd.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +792 B 🔴 +704 B
assets/useUpstreamValue-D1FlPnaK.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -793 B 🟢 -713 B
assets/useWorkspaceSwitch-DWaWcrzY.js (removed) 748 B 🟢 -748 B 🟢 -384 B 🟢 -337 B
assets/useWorkspaceSwitch-rvwckvlq.js (new) 748 B 🔴 +748 B 🔴 +383 B 🔴 +335 B
assets/useLoad3d-Bxpb-gtL.js (new) 311 B 🔴 +311 B 🔴 +164 B 🔴 +147 B
assets/useLoad3d-DQW869jN.js (removed) 311 B 🟢 -311 B 🟢 -163 B 🟢 -147 B
assets/useSessionCookie-CO43Dhiu.js (new) 101 B 🔴 +101 B 🔴 +86 B 🔴 +83 B
assets/useSessionCookie-DbdfMuy6.js (removed) 101 B 🟢 -101 B 🟢 -86 B 🟢 -80 B
assets/useLoad3dViewer-D56L8NCE.js (removed) 98 B 🟢 -98 B 🟢 -85 B 🟢 -86 B
assets/useLoad3dViewer-IRQ-hox7.js (new) 98 B 🔴 +98 B 🔴 +85 B 🔴 +85 B
assets/useCurrentUser-BsgTiXeb.js (new) 96 B 🔴 +96 B 🔴 +97 B 🔴 +85 B
assets/useCurrentUser-LdhZPucX.js (removed) 96 B 🟢 -96 B 🟢 -97 B 🟢 -82 B

Status: 14 added / 14 removed / 16 unchanged

Vendor & Third-Party — 15.3 MB (baseline 15.3 MB) • ⚪ 0 B

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 10.4 MB (baseline 10.4 MB) • 🔴 +1.3 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-BnXMwL6b.js (removed) 118 kB 🟢 -118 kB 🟢 -30.4 kB 🟢 -25.7 kB
assets/core-CoBk6o7y.js (new) 118 kB 🔴 +118 kB 🔴 +30.4 kB 🔴 +25.7 kB
assets/WidgetSelect-C_2pTBhG.js (new) 83.9 kB 🔴 +83.9 kB 🔴 +18.3 kB 🔴 +15.8 kB
assets/WidgetSelect-CxgcVWHp.js (removed) 82.6 kB 🟢 -82.6 kB 🟢 -18.1 kB 🟢 -15.6 kB
assets/SubscriptionRequiredDialogContentWorkspace-Ca1OvyCj.js (removed) 47.8 kB 🟢 -47.8 kB 🟢 -9.08 kB 🟢 -7.82 kB
assets/SubscriptionRequiredDialogContentWorkspace-CjPh76bx.js (new) 47.8 kB 🔴 +47.8 kB 🔴 +9.08 kB 🔴 +7.83 kB
assets/Load3DControls-BqJik2B6.js (removed) 46.8 kB 🟢 -46.8 kB 🟢 -7.57 kB 🟢 -6.62 kB
assets/Load3DControls-CPPsoxNg.js (new) 46.8 kB 🔴 +46.8 kB 🔴 +7.57 kB 🔴 +6.62 kB
assets/WorkspacePanelContent-KzYrylPJ.js (removed) 33.3 kB 🟢 -33.3 kB 🟢 -6.96 kB 🟢 -6.16 kB
assets/WorkspacePanelContent-nEnBZX5o.js (new) 33.3 kB 🔴 +33.3 kB 🔴 +6.96 kB 🔴 +6.17 kB
assets/WidgetPainter-D-FdUYww.js (new) 32.6 kB 🔴 +32.6 kB 🔴 +7.87 kB 🔴 +7 kB
assets/WidgetPainter-Dn4Lmbgu.js (removed) 32.6 kB 🟢 -32.6 kB 🟢 -7.86 kB 🟢 -6.99 kB
assets/Load3dViewerContent-B6HRUTzJ.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +6.3 kB 🔴 +5.48 kB
assets/Load3dViewerContent-BAIS49I3.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -6.3 kB 🟢 -5.48 kB
assets/SubscriptionRequiredDialogContent-BXokrL3Q.js (new) 26.6 kB 🔴 +26.6 kB 🔴 +6.57 kB 🔴 +5.8 kB
assets/SubscriptionRequiredDialogContent-DB1xY4Md.js (removed) 26.6 kB 🟢 -26.6 kB 🟢 -6.57 kB 🟢 -5.8 kB
assets/WidgetImageCrop-3xPcYmqw.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.75 kB 🔴 +5.05 kB
assets/WidgetImageCrop-DI48-Y9p.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.75 kB 🟢 -5.05 kB
assets/SubscriptionPanelContentWorkspace-C9pOxd2j.js (removed) 22.1 kB 🟢 -22.1 kB 🟢 -5.16 kB 🟢 -4.55 kB
assets/SubscriptionPanelContentWorkspace-DyC8dL2L.js (new) 22.1 kB 🔴 +22.1 kB 🔴 +5.16 kB 🔴 +4.56 kB
assets/load3d-4oqLYSSe.js (new) 21.2 kB 🔴 +21.2 kB 🔴 +5.18 kB 🔴 +4.49 kB
assets/load3d-QZJOhC70.js (removed) 21.2 kB 🟢 -21.2 kB 🟢 -5.18 kB 🟢 -4.5 kB
assets/CurrentUserPopoverWorkspace-BPGegZba.js (new) 20.5 kB 🔴 +20.5 kB 🔴 +4.68 kB 🔴 +4.18 kB
assets/CurrentUserPopoverWorkspace-DxG3JXf5.js (removed) 20.5 kB 🟢 -20.5 kB 🟢 -4.68 kB 🟢 -4.19 kB
assets/SignInContent-B5gFxNpV.js (removed) 19.9 kB 🟢 -19.9 kB 🟢 -5.01 kB 🟢 -4.37 kB
assets/SignInContent-BiMkboLH.js (new) 19.9 kB 🔴 +19.9 kB 🔴 +5.01 kB 🔴 +4.36 kB
assets/Load3D-azBHYgDk.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.52 kB 🟢 -3.94 kB
assets/Load3D-DsDl0-S5.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.52 kB 🔴 +3.94 kB
assets/WidgetInputNumber-CvLwOUeh.js (new) 19 kB 🔴 +19 kB 🔴 +4.79 kB 🔴 +4.25 kB
assets/WidgetInputNumber-hNn-hKHY.js (removed) 19 kB 🟢 -19 kB 🟢 -4.79 kB 🟢 -4.25 kB
assets/WidgetRecordAudio-CCWrlLdG.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.63 kB 🔴 +4.14 kB
assets/WidgetRecordAudio-DXFItCPO.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.63 kB 🟢 -4.14 kB
assets/WidgetRange-DP2ZPbLz.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.17 kB 🟢 -3.72 kB
assets/WidgetRange-oe2hFJ-g.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.17 kB 🔴 +3.73 kB
assets/WaveAudioPlayer-D9CiWWN5.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.48 kB 🟢 -3.07 kB
assets/WaveAudioPlayer-DBYZUrfI.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.49 kB 🔴 +3.06 kB
assets/WidgetCurve-DVWlPY-w.js (removed) 11.3 kB 🟢 -11.3 kB 🟢 -3.51 kB 🟢 -3.17 kB
assets/WidgetCurve-U0thK63I.js (new) 11.3 kB 🔴 +11.3 kB 🔴 +3.51 kB 🔴 +3.19 kB
assets/TeamWorkspacesDialogContent-DIOZq4Uo.js (removed) 10.4 kB 🟢 -10.4 kB 🟢 -3.01 kB 🟢 -2.68 kB
assets/TeamWorkspacesDialogContent-KQXJiuKM.js (new) 10.4 kB 🔴 +10.4 kB 🔴 +3.01 kB 🔴 +2.67 kB
assets/Load3DConfiguration-BN6E9xR4.js (removed) 9.02 kB 🟢 -9.02 kB 🟢 -2.66 kB 🟢 -2.34 kB
assets/Load3DConfiguration-Dx-gHoit.js (new) 9.02 kB 🔴 +9.02 kB 🔴 +2.66 kB 🔴 +2.35 kB
assets/nodeTemplates-Be42L5NW.js (removed) 8.33 kB 🟢 -8.33 kB 🟢 -2.88 kB 🟢 -2.54 kB
assets/nodeTemplates-DQDo0uBK.js (new) 8.33 kB 🔴 +8.33 kB 🔴 +2.88 kB 🔴 +2.54 kB
assets/onboardingCloudRoutes-DHfpk4ON.js (removed) 8.01 kB 🟢 -8.01 kB 🟢 -2.48 kB 🟢 -2.14 kB
assets/onboardingCloudRoutes-DmlJewZz.js (new) 8.01 kB 🔴 +8.01 kB 🔴 +2.48 kB 🔴 +2.14 kB
assets/NightlySurveyController-BgJAiA8A.js (removed) 7.95 kB 🟢 -7.95 kB 🟢 -2.7 kB 🟢 -2.4 kB
assets/NightlySurveyController-ByUb38AF.js (new) 7.95 kB 🔴 +7.95 kB 🔴 +2.7 kB 🔴 +2.39 kB
assets/InviteMemberDialogContent-CpLDnFyK.js (new) 7.03 kB 🔴 +7.03 kB 🔴 +2.14 kB 🔴 +1.85 kB
assets/InviteMemberDialogContent-DO7Z-m2G.js (removed) 7.03 kB 🟢 -7.03 kB 🟢 -2.14 kB 🟢 -1.85 kB
assets/WidgetWithControl-CcRGTxgk.js (new) 6.19 kB 🔴 +6.19 kB 🔴 +2.49 kB 🔴 +2.21 kB
assets/WidgetWithControl-O3Di-tg3.js (removed) 6.19 kB 🟢 -6.19 kB 🟢 -2.48 kB 🟢 -2.22 kB
assets/load3dPreviewExtensions-DOwxpY26.js (removed) 5.38 kB 🟢 -5.38 kB 🟢 -1.75 kB 🟢 -1.55 kB
assets/load3dPreviewExtensions-e3XYWKJ8.js (new) 5.38 kB 🔴 +5.38 kB 🔴 +1.75 kB 🔴 +1.55 kB
assets/CreateWorkspaceDialogContent-B8SMZJ9N.js (removed) 5.19 kB 🟢 -5.19 kB 🟢 -1.83 kB 🟢 -1.59 kB
assets/CreateWorkspaceDialogContent-ClvBHsoV.js (new) 5.19 kB 🔴 +5.19 kB 🔴 +1.83 kB 🔴 +1.59 kB
assets/missingModelDownload-DMxIu_WO.js (new) 5.07 kB 🔴 +5.07 kB 🔴 +1.98 kB 🔴 +1.72 kB
assets/missingModelDownload-W1X68NOJ.js (removed) 5.07 kB 🟢 -5.07 kB 🟢 -1.98 kB 🟢 -1.72 kB
assets/FreeTierDialogContent-BgI1y7n_.js (new) 5.02 kB 🔴 +5.02 kB 🔴 +1.69 kB 🔴 +1.49 kB
assets/FreeTierDialogContent-G5rCeQv4.js (removed) 5.02 kB 🟢 -5.02 kB 🟢 -1.7 kB 🟢 -1.49 kB
assets/EditWorkspaceDialogContent-CMvqlUZa.js (new) 5 kB 🔴 +5 kB 🔴 +1.8 kB 🔴 +1.56 kB
assets/EditWorkspaceDialogContent-H27EPS8-.js (removed) 5 kB 🟢 -5 kB 🟢 -1.8 kB 🟢 -1.56 kB
assets/WidgetTextarea-CILXVy49.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.9 kB 🔴 +1.67 kB
assets/WidgetTextarea-CO0QkQie.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.9 kB 🟢 -1.66 kB
assets/saveMesh-7kq5xTFo.js (removed) 4.79 kB 🟢 -4.79 kB 🟢 -1.55 kB 🟢 -1.36 kB
assets/saveMesh-GRRj06fM.js (new) 4.79 kB 🔴 +4.79 kB 🔴 +1.54 kB 🔴 +1.36 kB
assets/Preview3d-BLYXaUSq.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.43 kB 🟢 -1.23 kB
assets/Preview3d-E1RAdhGn.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.43 kB 🔴 +1.23 kB
assets/ValueControlPopover-BI2H1wSS.js (new) 4.55 kB 🔴 +4.55 kB 🔴 +1.59 kB 🔴 +1.41 kB
assets/ValueControlPopover-D-Up3-2v.js (removed) 4.55 kB 🟢 -4.55 kB 🟢 -1.59 kB 🟢 -1.41 kB
assets/CancelSubscriptionDialogContent-6C9pNSbt.js (new) 4.54 kB 🔴 +4.54 kB 🔴 +1.66 kB 🔴 +1.44 kB
assets/CancelSubscriptionDialogContent-Bg9JNxY6.js (removed) 4.54 kB 🟢 -4.54 kB 🟢 -1.66 kB 🟢 -1.44 kB
assets/tierBenefits-BU7hSKSY.js (new) 4.46 kB 🔴 +4.46 kB 🔴 +1.58 kB 🔴 +1.37 kB
assets/tierBenefits-Dax_lz5a.js (removed) 4.46 kB 🟢 -4.46 kB 🟢 -1.58 kB 🟢 -1.37 kB
assets/DeleteWorkspaceDialogContent-byuY3aqk.js (removed) 3.91 kB 🟢 -3.91 kB 🟢 -1.48 kB 🟢 -1.27 kB
assets/DeleteWorkspaceDialogContent-SQ42A6Mx.js (new) 3.91 kB 🔴 +3.91 kB 🔴 +1.48 kB 🔴 +1.26 kB
assets/LeaveWorkspaceDialogContent-B_vzBw0p.js (new) 3.73 kB 🔴 +3.73 kB 🔴 +1.42 kB 🔴 +1.22 kB
assets/LeaveWorkspaceDialogContent-BBvbki6A.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.42 kB 🟢 -1.23 kB
assets/RemoveMemberDialogContent-Dxz0LrRE.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.38 kB 🟢 -1.19 kB
assets/RemoveMemberDialogContent-kfOqvoUm.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.38 kB 🔴 +1.19 kB
assets/RevokeInviteDialogContent-aChB20FH.js (new) 3.63 kB 🔴 +3.63 kB 🔴 +1.39 kB 🔴 +1.2 kB
assets/RevokeInviteDialogContent-kVt5B60V.js (removed) 3.63 kB 🟢 -3.63 kB 🟢 -1.39 kB 🟢 -1.21 kB
assets/InviteMemberUpsellDialogContent-BuDhBZJv.js (removed) 3.48 kB 🟢 -3.48 kB 🟢 -1.24 kB 🟢 -1.07 kB
assets/InviteMemberUpsellDialogContent-CvZXppse.js (new) 3.48 kB 🔴 +3.48 kB 🔴 +1.24 kB 🔴 +1.09 kB
assets/Media3DTop-BFB5ehLv.js (new) 3.26 kB 🔴 +3.26 kB 🔴 +1.3 kB 🔴 +1.13 kB
assets/Media3DTop-D7Cwa1Wo.js (removed) 3.26 kB 🟢 -3.26 kB 🟢 -1.3 kB 🟢 -1.13 kB
assets/GlobalToast-B51CPXOz.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/GlobalToast-BGEy4Xzi.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/load3dAdvanced-Bua-nONA.js (removed) 2.85 kB 🟢 -2.85 kB 🟢 -1.12 kB 🟢 -978 B
assets/load3dAdvanced-BZoJu-_Q.js (new) 2.85 kB 🔴 +2.85 kB 🔴 +1.11 kB 🔴 +974 B
assets/SubscribeToRun-DLqT_ouU.js (new) 2.53 kB 🔴 +2.53 kB 🔴 +1.1 kB 🔴 +977 B
assets/SubscribeToRun-Dvutopsd.js (removed) 2.53 kB 🟢 -2.53 kB 🟢 -1.1 kB 🟢 -977 B
assets/graphHasMissingNodes-DPYfpYFl.js (new) 1.93 kB 🔴 +1.93 kB 🔴 +908 B 🔴 +793 B
assets/graphHasMissingNodes-gRk5uzue.js (removed) 1.93 kB 🟢 -1.93 kB 🟢 -908 B 🟢 -791 B
assets/MediaAudioTop-3pNanDwW.js (new) 1.67 kB 🔴 +1.67 kB 🔴 +838 B 🔴 +692 B
assets/MediaAudioTop-DeMs15Bh.js (removed) 1.67 kB 🟢 -1.67 kB 🟢 -838 B 🟢 -696 B
assets/CloudRunButtonWrapper-BrEFNxKW.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -547 B 🟢 -512 B
assets/CloudRunButtonWrapper-p2wQ20OL.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +549 B 🔴 +493 B
assets/cloudSessionCookie-BlcJmNYX.js (new) 991 B 🔴 +991 B 🔴 +469 B 🔴 +401 B
assets/cloudSessionCookie-JPK-45jG.js (removed) 991 B 🟢 -991 B 🟢 -470 B 🟢 -400 B
assets/cloudBadges-CMDMuuxI.js (removed) 976 B 🟢 -976 B 🟢 -560 B 🟢 -502 B
assets/cloudBadges-Dca_y_NU.js (new) 976 B 🔴 +976 B 🔴 +560 B 🔴 +507 B
assets/cloudSubscription-Bz8NahO6.js (removed) 820 B 🟢 -820 B 🟢 -454 B 🟢 -362 B
assets/cloudSubscription-zlNlYfgQ.js (new) 820 B 🔴 +820 B 🔴 +452 B 🔴 +362 B
assets/Load3DAdvanced-BQe3lO6L.js (new) 813 B 🔴 +813 B 🔴 +454 B 🔴 +408 B
assets/Load3DAdvanced-CSXRFfjh.js (removed) 813 B 🟢 -813 B 🟢 -456 B 🟢 -407 B
assets/nightlyBadges-Bsd5aYr4.js (removed) 464 B 🟢 -464 B 🟢 -305 B 🟢 -300 B
assets/nightlyBadges-D2CjBLEh.js (new) 464 B 🔴 +464 B 🔴 +305 B 🔴 +301 B
assets/missingModelDownload-DkdPiEc0.js (removed) 228 B 🟢 -228 B 🟢 -152 B 🟢 -130 B
assets/missingModelDownload-WCWjH4jk.js (new) 228 B 🔴 +228 B 🔴 +151 B 🔴 +130 B
assets/SubscriptionPanelContentWorkspace-BC7X-Rcw.js (removed) 179 B 🟢 -179 B 🟢 -117 B 🟢 -94 B
assets/SubscriptionPanelContentWorkspace-DsGvEC6M.js (new) 179 B 🔴 +179 B 🔴 +117 B 🔴 +102 B
assets/Load3dViewerContent-BXiBkTtX.js (removed) 137 B 🟢 -137 B 🟢 -103 B 🟢 -92 B
assets/Load3dViewerContent-szsfYsff.js (new) 137 B 🔴 +137 B 🔴 +103 B 🔴 +92 B
assets/Load3DAdvanced-CEsH29JO.js (removed) 122 B 🟢 -122 B 🟢 -97 B 🟢 -88 B
assets/Load3DAdvanced-NMFF7JQr.js (new) 122 B 🔴 +122 B 🔴 +97 B 🔴 +89 B
assets/WidgetLegacy-CDl95uRo.js (removed) 119 B 🟢 -119 B 🟢 -108 B 🟢 -94 B
assets/WidgetLegacy-Cq7JdgxZ.js (new) 119 B 🔴 +119 B 🔴 +108 B 🔴 +100 B
assets/workflowDraftStoreV2-BNfdgwJm.js (new) 113 B 🔴 +113 B 🔴 +105 B 🔴 +110 B
assets/workflowDraftStoreV2-DOsPH6yR.js (removed) 113 B 🟢 -113 B 🟢 -105 B 🟢 -117 B
assets/Load3D-ClJ7X0pl.js (removed) 98 B 🟢 -98 B 🟢 -89 B 🟢 -87 B
assets/Load3D-Sjrg-i8p.js (new) 98 B 🔴 +98 B 🔴 +89 B 🔴 +77 B
assets/changeTracker-B1SVu9w2.js (removed) 93 B 🟢 -93 B 🟢 -95 B 🟢 -81 B
assets/changeTracker-DOAbWQuu.js (new) 93 B 🔴 +93 B 🔴 +95 B 🔴 +84 B

Status: 62 added / 62 removed / 86 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.4 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 50.3 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 59.4 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 62.7 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 58.6 MB heap
large-graph-pan: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 79.3 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 65.7 MB heap
minimap-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 57.8 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.0 MB heap
subgraph-idle: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 54.8 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.6 MB heap
subgraph-transition-enter: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 175ms TBT · 76.4 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.3 MB heap
vue-large-graph-idle: · 58.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 160.8 MB heap
vue-large-graph-pan: · 58.1 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 50ms TBT · 168.0 MB heap
workflow-execution: · 60.0 avg FPS · 59.7 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.1 MB heap

⚠️ 7 regressions detected

Show regressions
Metric Baseline PR (median) Δ Sig
canvas-mouse-sweep: layout duration 4ms 4ms +10% ⚠️ z=2.0
canvas-zoom-sweep: task duration 345ms 394ms +14% ⚠️ z=2.9
canvas-zoom-sweep: script duration 24ms 35ms +43% ⚠️ z=2.5
large-graph-pan: style recalc duration 21ms 20ms -4% ⚠️ z=3.1
large-graph-pan: task duration 1142ms 1168ms +2% ⚠️ z=2.0
minimap-idle: task duration 533ms 677ms +27% ⚠️ z=3.2
subgraph-idle: task duration 371ms 457ms +23% ⚠️ z=2.8
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms -0% z=-0.5
canvas-idle: p95 frame time 17ms 17ms -1%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 9ms 10ms +10% z=-0.9
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 9 10 +6% z=-2.9
canvas-idle: task duration 409ms 439ms +7% z=1.4
canvas-idle: script duration 22ms 22ms +2% z=-1.3
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 53.6 MB 53.4 MB -0%
canvas-idle: DOM nodes 18 19 +6% z=-2.8
canvas-idle: event listeners 4 5 +25% z=-1.4
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms -0%
canvas-mouse-sweep: layout duration 4ms 4ms +10% ⚠️ z=2.0
canvas-mouse-sweep: style recalc duration 39ms 44ms +10% z=0.3
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 75 77 +3% z=-0.7
canvas-mouse-sweep: task duration 796ms 836ms +5% z=-0.5
canvas-mouse-sweep: script duration 131ms 132ms +1% z=-0.5
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 48.9 MB 50.3 MB +3%
canvas-mouse-sweep: DOM nodes 58 -75 -229% z=-53.1
canvas-mouse-sweep: event listeners 4 -98 -2538% z=-25.4
canvas-zoom-sweep: avg frame time 17ms 17ms +0% z=0.5
canvas-zoom-sweep: p95 frame time 17ms 17ms +0%
canvas-zoom-sweep: layout duration 1ms 1ms +3% z=1.4
canvas-zoom-sweep: style recalc duration 18ms 20ms +9% z=0.3
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 31 31 +0% z=-0.6
canvas-zoom-sweep: task duration 345ms 394ms +14% ⚠️ z=2.9
canvas-zoom-sweep: script duration 24ms 35ms +43% ⚠️ z=2.5
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 57.4 MB 59.4 MB +3%
canvas-zoom-sweep: DOM nodes 76 -92 -220% z=-215.7
canvas-zoom-sweep: event listeners 19 -83 -534% z=-20.5
dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
dom-widget-clipping: p95 frame time 17ms 17ms +1%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 9ms 8ms -10% z=-1.8
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 12 12 -4% z=-3.2
dom-widget-clipping: task duration 373ms 372ms -0% z=0.5
dom-widget-clipping: script duration 67ms 66ms -2% z=-0.6
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 62.5 MB 62.7 MB +0%
dom-widget-clipping: DOM nodes 20 19 -5% z=-2.2
dom-widget-clipping: event listeners 2 2 +0% variance too high
large-graph-idle: avg frame time 17ms 17ms +0% z=-0.6
large-graph-idle: p95 frame time 17ms 17ms -0%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 10ms 11ms +15% z=-1.0
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 10 10 +0% z=-5.1
large-graph-idle: task duration 545ms 648ms +19% z=2.0
large-graph-idle: script duration 108ms 119ms +11% z=1.6
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 58.6 MB 58.6 MB +0%
large-graph-idle: DOM nodes 20 20 +0% z=-5.2
large-graph-idle: event listeners 6 6 +0% z=-3.3
large-graph-pan: avg frame time 17ms 17ms +0% z=0.3
large-graph-pan: p95 frame time 17ms 17ms -1%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 21ms 20ms -4% ⚠️ z=3.1
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 70 69 -1% z=-0.9
large-graph-pan: task duration 1142ms 1168ms +2% ⚠️ z=2.0
large-graph-pan: script duration 427ms 414ms -3% z=0.3
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 79.2 MB 79.3 MB +0%
large-graph-pan: DOM nodes 18 17 -6% z=-1.2
large-graph-pan: event listeners 6 6 +0% z=1.3
large-graph-zoom: avg frame time 17ms 17ms -0%
large-graph-zoom: p95 frame time 17ms 17ms +0%
large-graph-zoom: layout duration 8ms 8ms +2%
large-graph-zoom: style recalc duration 19ms 21ms +9%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 64 66 +3%
large-graph-zoom: task duration 1354ms 1391ms +3%
large-graph-zoom: script duration 509ms 514ms +1%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 65.3 MB 65.7 MB +1%
large-graph-zoom: DOM nodes 10 16 +60%
large-graph-zoom: event listeners 8 7 -13%
minimap-idle: avg frame time 17ms 17ms -0% z=-0.4
minimap-idle: p95 frame time 17ms 17ms -0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 9ms 7ms -21% z=-2.7
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 9 7 -22% z=-3.8
minimap-idle: task duration 533ms 677ms +27% ⚠️ z=3.2
minimap-idle: script duration 100ms 112ms +12% z=1.4
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 60.3 MB 57.8 MB -4%
minimap-idle: DOM nodes 18 -146 -908% z=-120.4
minimap-idle: event listeners 6 -96 -1692% z=-151.6
subgraph-dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms -1%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 12ms 14ms +20% z=1.3
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 48 49 +1% z=0.9
subgraph-dom-widget-clipping: task duration 373ms 393ms +5% z=0.8
subgraph-dom-widget-clipping: script duration 127ms 133ms +5% z=0.8
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 63.8 MB 61.0 MB -4%
subgraph-dom-widget-clipping: DOM nodes 22 23 +5% z=0.7
subgraph-dom-widget-clipping: event listeners 6 8 +33% z=-1.4
subgraph-idle: avg frame time 17ms 17ms -0% z=-0.2
subgraph-idle: p95 frame time 17ms 17ms +0%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 10ms 10ms -1% z=-0.7
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 11 10 -14% z=-2.1
subgraph-idle: task duration 371ms 457ms +23% ⚠️ z=2.8
subgraph-idle: script duration 18ms 24ms +36% z=1.3
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 53.2 MB 54.8 MB +3%
subgraph-idle: DOM nodes 22 -148 -770% z=-113.2
subgraph-idle: event listeners 4 -98 -2538% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms -0% z=-0.1
subgraph-mouse-sweep: p95 frame time 17ms 17ms -0%
subgraph-mouse-sweep: layout duration 4ms 5ms +5% z=-0.5
subgraph-mouse-sweep: style recalc duration 37ms 40ms +8% z=-0.6
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 76 76 -1% z=-2.4
subgraph-mouse-sweep: task duration 711ms 743ms +5% z=-0.3
subgraph-mouse-sweep: script duration 104ms 103ms -0% z=0.4
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 45.6 MB 61.6 MB +35%
subgraph-mouse-sweep: DOM nodes 62 -80 -229% z=-65.8
subgraph-mouse-sweep: event listeners 4 -98 -2538% variance too high
subgraph-transition-enter: avg frame time 17ms 17ms -0%
subgraph-transition-enter: p95 frame time 17ms 17ms +0%
subgraph-transition-enter: layout duration 14ms 15ms +5%
subgraph-transition-enter: style recalc duration 29ms 30ms +5%
subgraph-transition-enter: layout count 4 4 +0%
subgraph-transition-enter: style recalc count 15 16 +7%
subgraph-transition-enter: task duration 785ms 873ms +11%
subgraph-transition-enter: script duration 33ms 45ms +35%
subgraph-transition-enter: TBT 164ms 175ms +7%
subgraph-transition-enter: heap used 76.2 MB 76.4 MB +0%
subgraph-transition-enter: DOM nodes 13833 13833 +0%
subgraph-transition-enter: event listeners 2529 2529 +0%
viewport-pan-sweep: avg frame time 17ms 17ms -0%
viewport-pan-sweep: p95 frame time 17ms 17ms +0%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 57ms 61ms +6%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 252 252 +0%
viewport-pan-sweep: task duration 4039ms 4073ms +1%
viewport-pan-sweep: script duration 1337ms 1341ms +0%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 64.5 MB 64.3 MB -0%
viewport-pan-sweep: DOM nodes 22 22 +0%
viewport-pan-sweep: event listeners 20 20 +0%
vue-large-graph-idle: avg frame time 17ms 17ms +0%
vue-large-graph-idle: p95 frame time 17ms 17ms +1%
vue-large-graph-idle: layout duration 0ms 0ms +0%
vue-large-graph-idle: style recalc duration 0ms 0ms +0%
vue-large-graph-idle: layout count 0 0 +0%
vue-large-graph-idle: style recalc count 0 0 +0%
vue-large-graph-idle: task duration 13271ms 13239ms -0%
vue-large-graph-idle: script duration 625ms 626ms +0%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 160.4 MB 160.8 MB +0%
vue-large-graph-idle: DOM nodes -3308 -3308 +0%
vue-large-graph-idle: event listeners -16474 -16473 -0%
vue-large-graph-pan: avg frame time 17ms 17ms +0%
vue-large-graph-pan: p95 frame time 17ms 17ms +0%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 20ms 19ms -8%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 80 69 -14%
vue-large-graph-pan: task duration 15660ms 14915ms -5%
vue-large-graph-pan: script duration 962ms 904ms -6%
vue-large-graph-pan: TBT 0ms 50ms
vue-large-graph-pan: heap used 160.4 MB 168.0 MB +5%
vue-large-graph-pan: DOM nodes -3308 -5817 +76%
vue-large-graph-pan: event listeners -16471 -16468 -0%
workflow-execution: avg frame time 17ms 17ms -0% z=-0.4
workflow-execution: p95 frame time 17ms 17ms -0%
workflow-execution: layout duration 1ms 2ms +10% z=-0.2
workflow-execution: style recalc duration 25ms 24ms -3% z=-0.1
workflow-execution: layout count 5 5 +0% z=0.1
workflow-execution: style recalc count 19 17 -11% z=-0.4
workflow-execution: task duration 122ms 130ms +7% z=0.7
workflow-execution: script duration 21ms 23ms +11% z=-1.9
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 62.0 MB 64.1 MB +3%
workflow-execution: DOM nodes 161 163 +1% z=0.2
workflow-execution: event listeners 69 69 +0% z=3.9
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-06-19T02:46:52.595Z",
  "gitSha": "00ef00af64e9516e4cd5e3091cea64f45be681b5",
  "branch": "matt/fe-988-fe-wire-infinite-scroll-to-the-flat-output-provider-in-the",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2021.1050000000341,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.574,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 442.243,
      "heapDeltaBytes": -2907852,
      "heapUsedBytes": 55834784,
      "domNodes": 20,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 20.814000000000004,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2022.878999999989,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 9.486,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 435.95900000000006,
      "heapDeltaBytes": -2539092,
      "heapUsedBytes": 56153912,
      "domNodes": 18,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 23.728,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1897.7140000000645,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 43.588,
      "layouts": 12,
      "layoutDurationMs": 3.952000000000001,
      "taskDurationMs": 850.1460000000001,
      "heapDeltaBytes": -14467016,
      "heapUsedBytes": 54027960,
      "domNodes": -211,
      "jsHeapTotalBytes": 21671936,
      "scriptDurationMs": 126.80799999999998,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1854.755999999952,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 43.507,
      "layouts": 12,
      "layoutDurationMs": 4.0600000000000005,
      "taskDurationMs": 822.596,
      "heapDeltaBytes": -7127332,
      "heapUsedBytes": 51359608,
      "domNodes": 61,
      "jsHeapTotalBytes": 25427968,
      "scriptDurationMs": 137.45200000000003,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1770.5220000000281,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 20.296000000000003,
      "layouts": 6,
      "layoutDurationMs": 0.6950000000000001,
      "taskDurationMs": 437.17900000000003,
      "heapDeltaBytes": -3685208,
      "heapUsedBytes": 64494536,
      "domNodes": -261,
      "jsHeapTotalBytes": 11972608,
      "scriptDurationMs": 38.675000000000004,
      "eventListeners": -184,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1740.9059999999954,
      "styleRecalcs": 30,
      "styleRecalcDurationMs": 18.951000000000004,
      "layouts": 6,
      "layoutDurationMs": 0.72,
      "taskDurationMs": 351.568,
      "heapDeltaBytes": 1698800,
      "heapUsedBytes": 60021708,
      "domNodes": 78,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 30.476999999999997,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 572.9420000000118,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 6.761000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 354.614,
      "heapDeltaBytes": 6902932,
      "heapUsedBytes": 65548896,
      "domNodes": 16,
      "jsHeapTotalBytes": 18612224,
      "scriptDurationMs": 59.86000000000001,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 607.0760000000064,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 10.103000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 389.465,
      "heapDeltaBytes": 7623500,
      "heapUsedBytes": 65939992,
      "domNodes": 22,
      "jsHeapTotalBytes": 18874368,
      "scriptDurationMs": 71.89099999999999,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2023.9820000000464,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 11.924000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 664.7299999999999,
      "heapDeltaBytes": -8883624,
      "heapUsedBytes": 61136428,
      "domNodes": 20,
      "jsHeapTotalBytes": 11677696,
      "scriptDurationMs": 119.61299999999999,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2041.8170000000373,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.405000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 631.087,
      "heapDeltaBytes": -8630060,
      "heapUsedBytes": 61857528,
      "domNodes": 20,
      "jsHeapTotalBytes": 11153408,
      "scriptDurationMs": 119.24400000000001,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2170.0060000000576,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 19.685000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1174.601,
      "heapDeltaBytes": 10393012,
      "heapUsedBytes": 83144012,
      "domNodes": 16,
      "jsHeapTotalBytes": 12115968,
      "scriptDurationMs": 415.263,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2109.1330000000426,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 19.83,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1162.2839999999999,
      "heapDeltaBytes": 10305916,
      "heapUsedBytes": 83247912,
      "domNodes": 18,
      "jsHeapTotalBytes": 12378112,
      "scriptDurationMs": 412.89500000000004,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3098.357999999962,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 20.207,
      "layouts": 60,
      "layoutDurationMs": 7.967999999999999,
      "taskDurationMs": 1377.8400000000001,
      "heapDeltaBytes": 13665764,
      "heapUsedBytes": 68513436,
      "domNodes": 14,
      "jsHeapTotalBytes": 5767168,
      "scriptDurationMs": 517.554,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3163.7719999999945,
      "styleRecalcs": 67,
      "styleRecalcDurationMs": 21.649,
      "layouts": 60,
      "layoutDurationMs": 8.19,
      "taskDurationMs": 1403.7640000000001,
      "heapDeltaBytes": -6883436,
      "heapUsedBytes": 69317040,
      "domNodes": 18,
      "jsHeapTotalBytes": 9318400,
      "scriptDurationMs": 510.44200000000006,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2031.0180000000173,
      "styleRecalcs": 6,
      "styleRecalcDurationMs": 5.233999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 677.337,
      "heapDeltaBytes": -28446896,
      "heapUsedBytes": 57671020,
      "domNodes": -307,
      "jsHeapTotalBytes": 102400,
      "scriptDurationMs": 111.80999999999999,
      "eventListeners": -197,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "minimap-idle",
      "durationMs": 2028.9980000000014,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 9.440000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 675.918,
      "heapDeltaBytes": -10223012,
      "heapUsedBytes": 63563500,
      "domNodes": 16,
      "jsHeapTotalBytes": 7221248,
      "scriptDurationMs": 111.699,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 617.4379999999928,
      "styleRecalcs": 49,
      "styleRecalcDurationMs": 14.666999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 418.07400000000007,
      "heapDeltaBytes": 8228444,
      "heapUsedBytes": 66940184,
      "domNodes": 24,
      "jsHeapTotalBytes": 19398656,
      "scriptDurationMs": 141.22899999999998,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 571.9420000000355,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 13.171000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 367.088,
      "heapDeltaBytes": 9974296,
      "heapUsedBytes": 61019496,
      "domNodes": 22,
      "jsHeapTotalBytes": 15990784,
      "scriptDurationMs": 125.503,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2038.5890000000018,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 11.806000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 493.05899999999997,
      "heapDeltaBytes": -9244236,
      "heapUsedBytes": 59145700,
      "domNodes": -313,
      "jsHeapTotalBytes": 20361216,
      "scriptDurationMs": 27.570000000000004,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 1999.3050000000494,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 421.11899999999997,
      "heapDeltaBytes": -3035292,
      "heapUsedBytes": 55781024,
      "domNodes": 18,
      "jsHeapTotalBytes": 25165824,
      "scriptDurationMs": 20.046,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1691.1790000000337,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 38.485,
      "layouts": 16,
      "layoutDurationMs": 4.118,
      "taskDurationMs": 724.77,
      "heapDeltaBytes": 15374448,
      "heapUsedBytes": 73965804,
      "domNodes": 65,
      "jsHeapTotalBytes": 24903680,
      "scriptDurationMs": 102.40599999999999,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1715.750000000071,
      "styleRecalcs": 75,
      "styleRecalcDurationMs": 42.17999999999999,
      "layouts": 16,
      "layoutDurationMs": 4.9510000000000005,
      "taskDurationMs": 761.247,
      "heapDeltaBytes": -13691732,
      "heapUsedBytes": 55251852,
      "domNodes": -225,
      "jsHeapTotalBytes": 16691200,
      "scriptDurationMs": 103.82600000000001,
      "eventListeners": -199,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "subgraph-transition-enter",
      "durationMs": 1399.234999999976,
      "styleRecalcs": 16,
      "styleRecalcDurationMs": 30.262000000000004,
      "layouts": 4,
      "layoutDurationMs": 15.197,
      "taskDurationMs": 872.6899999999997,
      "heapDeltaBytes": 4616604,
      "heapUsedBytes": 80079084,
      "domNodes": 13833,
      "jsHeapTotalBytes": 17039360,
      "scriptDurationMs": 44.72199999999999,
      "eventListeners": 2529,
      "totalBlockingTimeMs": 175,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8227.704000000016,
      "styleRecalcs": 252,
      "styleRecalcDurationMs": 58.324000000000005,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4026.35,
      "heapDeltaBytes": -2645336,
      "heapUsedBytes": 67436156,
      "domNodes": 22,
      "jsHeapTotalBytes": 19456000,
      "scriptDurationMs": 1331.793,
      "eventListeners": 20,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.80000000000109
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8207.677999999987,
      "styleRecalcs": 252,
      "styleRecalcDurationMs": 62.897000000000006,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4118.713,
      "heapDeltaBytes": -4049276,
      "heapUsedBytes": 67427164,
      "domNodes": 22,
      "jsHeapTotalBytes": 17620992,
      "scriptDurationMs": 1349.315,
      "eventListeners": 20,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13652.467,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13633.516,
      "heapDeltaBytes": -35542048,
      "heapUsedBytes": 167620224,
      "domNodes": -3308,
      "jsHeapTotalBytes": 18321408,
      "scriptDurationMs": 634.805,
      "eventListeners": -16472,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.220000000000073,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 12861.16400000003,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 12844.851999999999,
      "heapDeltaBytes": -22423928,
      "heapUsedBytes": 169612224,
      "domNodes": -3308,
      "jsHeapTotalBytes": 19369984,
      "scriptDurationMs": 617.6310000000001,
      "eventListeners": -16474,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333237,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15156.518000000005,
      "styleRecalcs": 72,
      "styleRecalcDurationMs": 19.397,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15136.993,
      "heapDeltaBytes": -24965784,
      "heapUsedBytes": 184376252,
      "domNodes": -8329,
      "jsHeapTotalBytes": 19775488,
      "scriptDurationMs": 891.4050000000001,
      "eventListeners": -16464,
      "totalBlockingTimeMs": 60,
      "frameDurationMs": 17.219999999999953,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 14719.71199999996,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 18.224000000000018,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 14693.831999999999,
      "heapDeltaBytes": -37019256,
      "heapUsedBytes": 167954328,
      "domNodes": -3304,
      "jsHeapTotalBytes": 18321408,
      "scriptDurationMs": 917.4680000000001,
      "eventListeners": -16472,
      "totalBlockingTimeMs": 40,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "workflow-execution",
      "durationMs": 467.47800000002826,
      "styleRecalcs": 17,
      "styleRecalcDurationMs": 24.537999999999997,
      "layouts": 5,
      "layoutDurationMs": 1.7720000000000002,
      "taskDurationMs": 134.406,
      "heapDeltaBytes": 5260944,
      "heapUsedBytes": 69615784,
      "domNodes": 168,
      "jsHeapTotalBytes": 4980736,
      "scriptDurationMs": 24.530000000000005,
      "eventListeners": 69,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66666666666665,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 456.9819999999254,
      "styleRecalcs": 17,
      "styleRecalcDurationMs": 23.558000000000003,
      "layouts": 5,
      "layoutDurationMs": 1.278,
      "taskDurationMs": 126.07800000000002,
      "heapDeltaBytes": 5237832,
      "heapUsedBytes": 64885804,
      "domNodes": 157,
      "jsHeapTotalBytes": 2883584,
      "scriptDurationMs": 22.352999999999998,
      "eventListeners": 69,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.660000000000007,
      "p95FrameDurationMs": 16.800000000000182
    }
  ]
}

… during initial load

- flatOutputHasMore now gates on fresh.length > 0 instead of batch.length > 0,
  so cursor pages whose items are all duplicates terminate pagination rather than
  looping infinitely on approach-end
- handleApproachEnd adds !loading guard to prevent concurrent loadMore during
  the opening refresh fetch
@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/uy-tieu-s-projects?upgradeToPro=build-rate-limit

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/stores/assetsStore.test.ts (1)

1734-1760: ⚡ Quick win

Strengthen failed-refresh regression coverage.

This case validates call arguments but not resulting list integrity. Please assert that retrying after a failed refresh does not introduce duplicate asset IDs.

Suggested test tightening
   it('restarts from the head when loadMore follows a failed refresh', async () => {
     vi.mocked(assetService.getAssetsPageByTag)
       .mockResolvedValueOnce(
         makePage([makeAsset('a1', 'f1.png')], {
           hasMore: true,
           nextCursor: 'cursor-1'
         })
       )
       .mockRejectedValueOnce(new Error('network down'))
-      .mockResolvedValueOnce(makePage([makeAsset('a2', 'f2.png')]))
+      // Head page again after refresh failure
+      .mockResolvedValueOnce(makePage([makeAsset('a1', 'f1.png')]))
@@
       await store.updateFlatOutputs()
       await store.updateFlatOutputs()
       await store.loadMoreFlatOutputs()
@@
       expect(assetService.getAssetsPageByTag).toHaveBeenLastCalledWith(
         'output',
         true,
         { limit: FLAT_OUTPUT_PAGE_SIZE, offset: 0 }
       )
+      const ids = store.flatOutputAssets.map((a) => a.id)
+      expect(new Set(ids).size).toBe(ids.length)

As per coding guidelines, "Write tests for all changes, especially bug fixes to catch future regressions."

🤖 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/stores/assetsStore.test.ts` around lines 1734 - 1760, The test validates
that the correct API arguments are passed when restarting from the head after a
failed refresh, but does not assert the integrity of the resulting asset list.
Add an assertion after the loadMoreFlatOutputs call to verify that the store's
flatOutputs (or equivalent collection being tested) contains the expected assets
and does not have duplicate asset IDs. This will ensure that retrying after a
failed refresh properly replaces the stale data instead of duplicating it.

Source: Coding guidelines

🤖 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/stores/assetsStore.test.ts`:
- Around line 1734-1760: The test validates that the correct API arguments are
passed when restarting from the head after a failed refresh, but does not assert
the integrity of the resulting asset list. Add an assertion after the
loadMoreFlatOutputs call to verify that the store's flatOutputs (or equivalent
collection being tested) contains the expected assets and does not have
duplicate asset IDs. This will ensure that retrying after a failed refresh
properly replaces the stale data instead of duplicating it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c65eb529-321e-4d25-ba83-fdf46c7cb99a

📥 Commits

Reviewing files that changed from the base of the PR and between eafe2af and 96c8b0e.

📒 Files selected for processing (6)
  • src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue
  • src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue
  • src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenu.test.ts
  • src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownMenu.vue
  • src/stores/assetsStore.test.ts
  • src/stores/assetsStore.ts

@dante01yoon dante01yoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial re-review of the delta since my 5de4e08 review, now at 96c8b0e (not approving, per the read-only convention).

The delta is the batch.lengthfresh.length fix for the infinite-loadMore loop — correct. One non-blocking suggestion:: the exact scenario that distinguishes the two (a loadMore page that is all-duplicate with has_more: true + an advancing cursor) has no regression test, so a revert to batch.length would stay green.

Comment thread src/stores/assetsStore.ts
nextCursor !== undefined && nextCursor === requestedAfter
flatOutputNextCursor = cursorStuck ? undefined : nextCursor
flatOutputHasMore.value =
fresh.length > 0 && page.has_more && !cursorStuck

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): this is the exact fix for the infinite-loadMore loop (gating on fresh.length instead of batch.length), but the one scenario that distinguishes the two — a loadMore page whose items are all already-seen (batch.length > 0 yet fresh.length === 0) with has_more: true and an advancing cursor — has no test. The new 'empty page' test only covers batch.length === 0 (so batch.length > 0 and fresh.length > 0 are both false), 'appends and dedupes' returns has_more: false, and 'non-advancing cursor' terminates via cursorStuck, so none would fail if this clause regressed to batch.length. Worth adding: page 1 full + has_more: true, page 2 = entirely already-seen ids with an advancing next_cursor -> assert flatOutputHasMore is false and no further fetch fires. That locks in the behavior this commit introduced.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The missing case is: page 1 full + has_more: true + advancing cursor, page 2 = same ids (all already-seen) + has_more: true + new advancing cursor → assert flatOutputHasMore is false and list length unchanged.

Added the test locally (72/72 pass, hooks green). Branch is in the merge queue so the push is blocked — either dequeue to accept the commit or I can share the snippet for you to apply:

it('marks hasMore=false when all page items are already seen with an advancing cursor', async () => {
  const firstPage = Array.from({ length: FLAT_OUTPUT_PAGE_SIZE }, (_, i) =>
    makeAsset(`a${i}`, `f${i}.png`)
  )
  vi.mocked(assetService.getAssetsPageByTag)
    .mockResolvedValueOnce(
      makePage(firstPage, { hasMore: true, nextCursor: 'cursor-1' })
    )
    .mockResolvedValueOnce(
      makePage(firstPage, { hasMore: true, nextCursor: 'cursor-2' })
    )

  const store = useAssetsStore()
  await store.updateFlatOutputs()
  await store.loadMoreFlatOutputs()

  expect(store.flatOutputHasMore).toBe(false)
  expect(store.flatOutputAssets).toHaveLength(FLAT_OUTPUT_PAGE_SIZE)
})

Confirmed this would fail if the guard regressed to batch.length > 0.

@dante01yoon dante01yoon removed their assignment Jun 19, 2026

@dante01yoon dante01yoon left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving at 96c8b0e. The delta is the batch.lengthfresh.length fix for the infinite-loadMore loop — correct. CI green. Only a non-blocking suggestion remains (add a regression test for the all-duplicate page + has_more + advancing-cursor case, which is the one scenario that distinguishes the two). LGTM.

@mattmillerai mattmillerai added this pull request to the merge queue Jun 22, 2026
Merged via the queue into main with commit 001b132 Jun 22, 2026
49 of 50 checks passed
@mattmillerai mattmillerai deleted the matt/fe-988-fe-wire-infinite-scroll-to-the-flat-output-provider-in-the branch June 22, 2026 20:38
@github-actions

Copy link
Copy Markdown

⚠️ Backport to cloud/1.45 failed

Reason: Merge conflicts detected during cherry-pick of 001b132

📄 Conflicting files
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue
🤖 Prompt for AI Agents
Backport PR #12780 (https://github.com/Comfy-Org/ComfyUI_frontend/pull/12780) to cloud/1.45.
Cherry-pick merge commit 001b132b0c318aa33887b97f893efaebb64f4614 onto new branch
backport-12780-to-cloud-1.45 from origin/cloud/1.45.
Resolve conflicts in: src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue .
For test snapshots (browser_tests/**/*-snapshots/), accept PR version if
changed in original PR, else keep target. For package.json versions, keep
target branch. For pnpm-lock.yaml, regenerate with pnpm install.
Ask user for non-obvious conflicts.
Create PR titled "[backport cloud/1.45] <original title>" with label "backport".
See .github/workflows/pr-backport.yaml for workflow details.

cc @mattmillerai

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cloud/1.45 Backport PRs for cloud 1.45 cursor-review Trigger multi-model Cursor agent review on this PR needs-backport Fix/change that needs to be cherry-picked to the current feature freeze branch size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants