Skip to content

feat: add feature usage tracker for nightly surveys#8175

Merged
christian-byrne merged 5 commits intomainfrom
feat/feature-usage-tracker
Jan 20, 2026
Merged

feat: add feature usage tracker for nightly surveys#8175
christian-byrne merged 5 commits intomainfrom
feat/feature-usage-tracker

Conversation

@christian-byrne
Copy link
Contributor

@christian-byrne christian-byrne commented Jan 20, 2026

Introduces useFeatureUsageTracker composable that tracks how many times a user has used a specific feature, along with first and last usage timestamps. Data persists to localStorage using @vueuse/core's useStorage. This composable provides the foundation for triggering surveys after a configurable number of feature uses. Includes comprehensive unit tests.

┆Issue is synchronized with this Notion page by Unito

@christian-byrne christian-byrne requested a review from a team as a code owner January 20, 2026 05:07
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jan 20, 2026
@christian-byrne christian-byrne changed the title feat: add feature-based usage tracker for nightly surveys feat: add feature usage tracker for nightly surveys Jan 20, 2026
@github-actions
Copy link

github-actions bot commented Jan 20, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/20/2026, 09:30:24 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

Warning

Rate limit exceeded

@christian-byrne has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 18 minutes and 21 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between c90217d and 0ad85d1.

📒 Files selected for processing (2)
  • src/platform/surveys/useFeatureUsageTracker.test.ts
  • src/platform/surveys/useFeatureUsageTracker.ts
📝 Walkthrough

Walkthrough

Adds a new Vue composition function useFeatureUsageTracker(featureId) that records per-feature usage (useCount, firstUsed, lastUsed) with persistence to localStorage, and a Vitest test suite validating initialization, increments, timestamps, reset, isolation, and persistence.

Changes

Cohort / File(s) Summary
Feature Usage Tracking
src/platform/surveys/useFeatureUsageTracker.ts
New composition function exposing usage, useCount, trackUsage(), and reset(); stores per-feature FeatureUsage records in localStorage via useStorage under key comfy.featureUsage.
Feature Usage Tracking Tests
src/platform/surveys/useFeatureUsageTracker.test.ts
New Vitest suite covering initialization, increment behavior, firstUsed/lastUsed timestamp handling (with fake timers), reset(), multi-feature isolation, persistence to localStorage, and loading from pre-existing stored data.

Sequence Diagram

sequenceDiagram
    participant VueComponent as Vue Component
    participant Tracker as useFeatureUsageTracker
    participant UseStorage as useStorage (`@vueuse/core`)
    participant LocalStorage as localStorage

    VueComponent->>Tracker: call trackUsage()
    activate Tracker
    Tracker->>Tracker: increment useCount
    Tracker->>Tracker: set firstUsed if unset
    Tracker->>Tracker: update lastUsed
    Tracker->>UseStorage: update reactive store
    activate UseStorage
    UseStorage->>LocalStorage: persist "comfy.featureUsage" data
    deactivate UseStorage
    deactivate Tracker

    VueComponent->>Tracker: read usage / useCount (computed)
    
    VueComponent->>Tracker: call reset()
    activate Tracker
    Tracker->>UseStorage: remove feature record
    activate UseStorage
    UseStorage->>LocalStorage: persist removal
    deactivate UseStorage
    deactivate Tracker
Loading

Suggested reviewers

  • KarryCharon
  • shinshin86
  • Yorha4D

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.

❤️ Share

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

@github-actions
Copy link

github-actions bot commented Jan 20, 2026

🎭 Playwright Tests: ⚠️ Passed with flaky tests

Results: 505 passed, 0 failed, 1 flaky, 8 skipped (Total: 514)

❌ Failed Tests

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

@github-actions
Copy link

github-actions bot commented Jan 20, 2026

Bundle Size Report

Summary

  • Raw size: 21.3 MB baseline 21.3 MB — ⚪ 0 B
  • Gzip: 4.43 MB baseline 4.43 MB — ⚪ 0 B
  • Brotli: 3.28 MB baseline 3.28 MB — ⚪ 0 B
  • Bundles: 155 current • 155 baseline

Category Glance
Vendor & Third-Party ⚪ 0 B (10.4 MB) · Other ⚪ 0 B (6.25 MB) · Data & Services ⚪ 0 B (3.04 MB) · Graph Workspace ⚪ 0 B (1.02 MB) · Panels & Settings ⚪ 0 B (430 kB) · Views & Navigation ⚪ 0 B (80.7 kB) · + 5 more

Per-category breakdown
App Entry Points — 22.4 kB (baseline 22.4 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-BoyCZVZF.js 22.4 kB 22.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Graph Workspace — 1.02 MB (baseline 1.02 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-Dh17zZcL.js 1.02 MB 1.02 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Views & Navigation — 80.7 kB (baseline 80.7 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudAuthTimeoutView-D52_XcLg.js 5.24 kB 5.24 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudForgotPasswordView-D7J7o1ef.js 6.26 kB 6.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudLayoutView-C9zCy0_u.js 8.54 kB 8.54 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudLoginView-GjYviDAM.js 11.8 kB 11.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSignupView-DtXwBMlp.js 8.18 kB 8.18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSorryContactSupportView-QtHXqQri.js 1.97 kB 1.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSubscriptionRedirectView-TL2VyN5r.js 5.27 kB 5.27 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSurveyView-Cg84jZHZ.js 17.1 kB 17.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-Bf1taiS0.js 500 B 500 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserCheckView-BnpPGP1W.js 10.5 kB 10.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserSelectView-DwFkHpVV.js 5.28 kB 5.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Panels & Settings — 430 kB (baseline 430 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/AboutPanel-5SHSVfHO.js 10.8 kB 10.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudRemoteConfig-DAt8IsL9.js 1.82 kB 1.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ExtensionPanel-4qm76-sp.js 10.2 kB 10.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/KeybindingPanel-DXTY423t.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LegacyCreditsPanel-BxP86WG0.js 23.8 kB 23.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/remoteConfig-B0rgMcLx.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/remoteConfig-CW7J8vSK.js 188 B 188 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ServerConfigPanel-CyzOkoB5.js 7.23 kB 7.23 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-6DVADt2n.js 34.3 kB 34.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-B0j03ezr.js 38.3 kB 38.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BHe-AJJN.js 29.6 kB 29.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BT2lfy0S.js 29.5 kB 29.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Cp0lF2Mp.js 31.2 kB 31.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CwdesOpm.js 32.1 kB 32.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D3SeHgho.js 28.6 kB 28.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D42m_JEJ.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-FF_vLB0C.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-reUMVWRn.js 30.4 kB 30.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-s7kHNBdQ.js 28.9 kB 28.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscriptionPanel-DqSom3WU.js 20.6 kB 20.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserPanel-B07dT5bP.js 6.58 kB 6.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
User & Accounts — 3.94 kB (baseline 3.94 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-BpeYb7sM.js 178 B 178 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/auth-CaEK9jbn.js 3.54 kB 3.54 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/firebaseAuthStore-Cw-kw2kh.js 217 B 217 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
Editors & Dialogs — 2.8 kB (baseline 2.8 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-C6Iu_R2I.js 2.62 kB 2.62 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useSubscriptionDialog-YIMSLXtK.js 179 B 179 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
UI Components — 32.8 kB (baseline 32.8 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Button-BFptkwN0.js 3.75 kB 3.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudBadge-CMqQgcTG.js 1.85 kB 1.85 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudFeedbackTopbarButton-D_g2N7Xt.js 866 B 866 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyQueueButton-D4akzQOi.js 9.52 kB 9.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyQueueButton-DvvcwDJc.js 181 B 181 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscribeButton-B6x1hZd-.js 12.5 kB 12.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-CkcXZWJQ.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-_hGIrcI2.js 2.41 kB 2.41 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Data & Services — 3.04 MB (baseline 3.04 MB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/api-BOpd8NRT.js 1.15 MB 1.15 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/audioService-j02oXWQa.js 2.03 kB 2.03 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/dialogService-BrgQhtgj.js 1.87 MB 1.87 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/keybindingService-PEpPvZNA.js 6.78 kB 6.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/releaseStore-CLfKFDQF.js 8.91 kB 8.91 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/releaseStore-CuoFruJo.js 140 B 140 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/serverConfigStore-CDOQj4Ec.js 2.64 kB 2.64 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/userStore-Bl5lcT3X.js 2.16 kB 2.16 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Utilities & Hooks — 18.7 kB (baseline 18.7 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/_plugin-vue_export-helper-xVPqUhAl.js 467 B 467 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/audioUtils-CRfIlB8N.js 1.24 kB 1.24 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-De0C_hc6.js 7.2 kB 7.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-0PqWmn-8.js 1.78 kB 1.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-BUCOyXf2.js 421 B 421 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/subscriptionCheckoutUtil-CjXT_oeo.js 1.98 kB 1.98 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/tailwindUtil-Chuu3TbR.js 487 B 487 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useCurrentUser-CmAG-IXG.js 145 B 145 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useErrorHandling-CsVuBcit.js 5 kB 5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Vendor & Third-Party — 10.4 MB (baseline 10.4 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-Dr8GmMlH.js 408 kB 408 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-DqqTGPL6.js 3.92 MB 3.92 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-EBXVECvF.js 3.04 MB 3.04 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-ViWrLgbb.js 172 kB 172 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-Dqb1VEds.js 1.83 MB 1.83 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-BxNhpyUI.js 650 kB 650 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-VHAq3Lid.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-CArXWFIl.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 6.25 MB (baseline 6.25 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/AudioPreviewPlayer-BvRFwfA7.js 191 B 191 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/AudioPreviewPlayer-DR5-BqYr.js 12.7 kB 12.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/auto-Bv9cmrEd.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/BaseViewTemplate-IW9hrOJ8.js 2.42 kB 2.42 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudBadges-CndICkgU.js 1.08 kB 1.08 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudRunButtonWrapper-CrPzMAHJ.js 1.79 kB 1.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudSessionCookie-BaWAAgDp.js 2.9 kB 2.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudSubscription-DKyIl0ev.js 976 B 976 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-6dIwsSNi.js 17.2 kB 17.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BahwM9ZP.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BoJZgy7S.js 17 kB 17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BQtdp20P.js 20.6 kB 20.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CEMgeOuO.js 18.5 kB 18.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CnxND6sZ.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-coXkrooi.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CZcHDaAg.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DDPGTXy9.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DsGC6118.js 17.8 kB 17.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-yZ2AjT4s.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/core-CAnBCzt9.js 177 kB 177 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/GlobalToast-DYyR4hLg.js 3.05 kB 3.05 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/graphHasMissingNodes-CKuiGjIw.js 1.06 kB 1.06 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LazyImage-B2qJgYQV.js 14.1 kB 14.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3D-Dd8XaBwA.js 131 B 131 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3D-dE88d5DN.js 55.7 kB 55.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BH76kbq7.js 104 kB 104 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-C-gNarDo.js 105 kB 105 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CA0dzqpC.js 124 kB 124 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CbaIObx3.js 121 kB 121 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CKH_pYcz.js 161 kB 161 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CotnVZA-.js 134 kB 134 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-D-IO_jVl.js 119 kB 119 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DLii8dI6.js 117 kB 117 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-i8aQGyai.js 145 kB 145 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Uwzs8jut.js 141 kB 141 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-vWcCEZeZ.js 117 kB 117 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-Bj6UL3Mt.js 2.38 kB 2.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-D8pQnmES.js 2 kB 2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-D0aiBzXG.js 2.34 kB 2.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-BCNtw1s2.js 2.84 kB 2.84 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-FcNs04XW.js 143 B 143 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-6qSb98D5.js 329 kB 329 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-B4G_Dl5E.js 361 kB 361 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BhmSU7DZ.js 371 kB 371 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bxky0ZDY.js 332 kB 332 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CCSKuw9P.js 400 kB 400 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Cd4f2ERd.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CLdE8MPH.js 355 kB 355 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CqDWLi76.js 399 kB 399 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CqyprhWq.js 433 kB 433 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D4Fo85EU.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DF-ErmAt.js 351 kB 351 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/PanelTemplate-D-tocmTy.js 16.2 kB 16.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/preservedQueryNamespaces-BsMrb3S_.js 3.23 kB 3.23 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-DZ1Jt5wB.js 838 B 838 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-CqTjxoQm.js 1.53 kB 1.53 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-BIIoltvA.js 4.21 kB 4.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscribeToRun-DM9v58Gw.js 2.96 kB 2.96 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscriptionRequiredDialogContent-CTlqTFYv.js 28.7 kB 28.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ValueControlPopover-CURg8-Ik.js 4.86 kB 4.86 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-Dneex3J5.js 518 B 518 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetAudioUI-Py6UfnF-.js 3.22 kB 3.22 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-CUDq_bgN.js 4.71 kB 4.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-T8Ljl7oe.js 186 B 186 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-1bZGfe6O.js 2.79 kB 2.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-CE6qc5iJ.js 3.71 kB 3.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-Bjqrk0m2.js 4.57 kB 4.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-CrN6SGuP.js 3.79 kB 3.79 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCrop-Dr1hsz8w.js 17.1 kB 17.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputNumber-CYqkrDkI.js 18.2 kB 18.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputNumber-D_9iQDpA.js 186 B 186 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-CtnWVTX2.js 2.58 kB 2.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-zNq5xTi-.js 2.61 kB 2.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLegacy-DEArfNbl.js 164 B 164 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-D4Dx6Rvq.js 3.22 kB 3.22 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-DfR_ZXyS.js 1.31 kB 1.31 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetRecordAudio-CjtMQX8a.js 18.2 kB 18.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetSelect-DHpJs8qU.js 161 B 161 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetSelect-Hb6obsgb.js 50.5 kB 50.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetTextarea-CDG12iu3.js 3.52 kB 3.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-VNa5cXfN.js 3.08 kB 3.08 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetWithControl-DlG3CXy0.js 8.02 kB 8.02 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/platform/surveys/useFeatureUsageTracker.test.ts`:
- Around line 51-61: The test uses a real setTimeout which is flaky; convert it
to Vitest fake timers by calling vi.useFakeTimers() at the start of the test,
replace the await new Promise((r) => setTimeout(r, 10)) with
vi.advanceTimersByTime(10) (or vi.advanceTimersToNextTimer()/vi.runAllTimers()
as appropriate), then call vi.useRealTimers()/vi.restoreAllMocks() at the end to
clean up; update the test around useFeatureUsageTracker/trackUsage/usage to use
these vi timer APIs so lastUsed progression is deterministic in CI.

AustinMroz
AustinMroz previously approved these changes Jan 20, 2026
Copy link
Collaborator

@AustinMroz AustinMroz left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/platform/surveys/useFeatureUsageTracker.test.ts`:
- Around line 96-107: The persistence test should use fake timers to
deterministically flush the async storage write: before invoking
useFeatureUsageTracker('persisted-feature') call vi.useFakeTimers(), call
trackUsage(), then advance timers with vi.runAllTimers() (or
vi.runOnlyPendingTimers()) to force the useStorage flush, read localStorage
(STORAGE_KEY) and assert, and finally restore timers with vi.useRealTimers();
reference the useFeatureUsageTracker hook, the trackUsage call, and STORAGE_KEY
when making the change.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/platform/surveys/useFeatureUsageTracker.test.ts`:
- Around line 35-49: Use fake timers to make the timestamp assertions
deterministic: call vi.useFakeTimers() and vi.setSystemTime(fixedTs) at the
start of the test, then import useFeatureUsageTracker(), call trackUsage(),
assert usage.value.firstUsed === fixedTs, advance/set system time again before
the second trackUsage() call to assert firstUsed remains unchanged, and finally
call vi.useRealTimers() to restore real timers; reference the
useFeatureUsageTracker import and the usage/trackUsage variables in your
changes.

@christian-byrne christian-byrne merged commit 5df793b into main Jan 20, 2026
27 checks passed
@christian-byrne christian-byrne deleted the feat/feature-usage-tracker branch January 20, 2026 21:35
godwiniheuwa pushed a commit to godwiniheuwa/ComfyUI_frontend that referenced this pull request Jan 22, 2026
Introduces `useFeatureUsageTracker` composable that tracks how many
times a user has used a specific feature, along with first and last
usage timestamps. Data persists to localStorage using `@vueuse/core`'s
`useStorage`. This composable provides the foundation for triggering
surveys after a configurable number of feature uses. Includes
comprehensive unit tests.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8175-feat-add-feature-usage-tracker-for-nightly-surveys-2ee6d73d36508118859ece6fcf17561d)
by [Unito](https://www.unito.io)
christian-byrne added a commit that referenced this pull request Jan 28, 2026
…vey(s) (#8189)

## Summary

Adds `useSurveyEligibility` composable that determines whether a user
should see a survey based on multiple criteria: nightly localhost build
only (`isNightly && !isCloud && !isDesktop`), configurable usage
threshold (default 3), 14-day global cooldown between any surveys,
once-per-feature-ever display, optional percentage-based sampling, and
user opt-out support. All state persists to localStorage. Includes
extensive unit tests covering all eligibility conditions.

See:

- #8149
- #8175

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8189-feat-add-composable-to-determine-if-user-is-eligible-for-nightly-survey-s-2ee6d73d365081f088f2fd76032cc60a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants