## Summary
Replace all runtime `isElectron()` function calls with the build-time
`isDesktop` constant from `@/platform/distribution/types`, enabling
dead-code elimination in non-desktop builds.
## Changes
- **What**: Migrate 30 files from runtime `isElectron()` detection
(checking `window.electronAPI`) to the compile-time `isDesktop` constant
(driven by `__DISTRIBUTION__` Vite define). Remove `isElectron` from
`envUtil.ts`. Update `isNativeWindow()` to use `isDesktop`. Guard
`electronAPI()` calls behind `isDesktop` checks in stores. Update 7 test
files to use `vi.hoisted` + getter mock pattern for per-test `isDesktop`
toggling. Add `DISTRIBUTION=desktop` to `dev:electron` script.
## Review Focus
- The `electronDownloadStore.ts` now guards the top-level
`electronAPI()` call behind `isDesktop` to prevent crashes on
non-desktop builds.
- Test mocking pattern uses `vi.hoisted` with a getter to allow per-test
toggling of the `isDesktop` value.
- Pre-existing issues not addressed: `as ElectronAPI` cast in
`envUtil.ts`, `:class="[]"` in `BaseViewTemplate.vue`,
`@ts-expect-error` in `ModelLibrarySidebarTab.vue`.
- This subsumes PR #8627 and renders PR #6122 and PR #7374 obsolete.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8710-refactor-replace-runtime-isElectron-with-build-time-isDesktop-constant-3006d73d365081c08037f0e61c2f6c77)
by [Unito](https://www.unito.io)
Wire checkout attribution into GTM events and checkout POST payloads.
This updates the cloud telemetry flow so the backend team can correlate checkout events without relying on frontend cookie parsing. We now surface GA4 identity via a GTM-provided global and include attribution on both `begin_checkout` telemetry and the checkout POST body. The backend should continue to derive the Firebase UID from the auth header; the checkout POST body does not include a user ID.
GTM events pushed (unchanged list, updated payloads):
- `page_view` (page title/location/referrer as before)
- `sign_up` / `login`
- `begin_checkout` now includes:
- `user_id`, `tier`, `cycle`, `checkout_type`, `previous_tier` (if change flow)
- `ga_client_id`, `ga_session_id`, `ga_session_number`
- `gclid`, `gbraid`, `wbraid`
Backend-facing change:
- `POST /customers/cloud-subscription-checkout/:tier` now includes a JSON body with attribution fields only:
- `ga_client_id`, `ga_session_id`, `ga_session_number`
- `gclid`, `gbraid`, `wbraid`
- Backend should continue to derive the Firebase UID from the auth header.
Required GTM setup:
- Provide `window.__ga_identity__` via a GTM Custom HTML tag (after GA4/Google tag) with `{ client_id, session_id, session_number }`. The frontend reads this to populate the GA fields.
<img width="1416" height="1230" alt="image" src="https://github.com/user-attachments/assets/b77cf0ed-be69-4497-a540-86e5beb7bfac" />
## Screenshots (if applicable)
<img width="991" height="385" alt="image" src="https://github.com/user-attachments/assets/8309cd9e-5ab5-4fba-addb-2d101aaae7e9"/>
Manual Testing:
<img width="3839" height="2020" alt="image" src="https://github.com/user-attachments/assets/36901dfd-08db-4c07-97b8-a71e6783c72f"/>
<img width="2141" height="851" alt="image" src="https://github.com/user-attachments/assets/2e9f7aa4-4716-40f7-b147-1c74b0ce8067"/>
<img width="2298" height="982" alt="image" src="https://github.com/user-attachments/assets/72cbaa53-9b92-458a-8539-c987cf753b02"/>
<img width="2125" height="999" alt="image" src="https://github.com/user-attachments/assets/4b22387e-8027-4f50-be49-a410282a1adc"/>
To manually test, you will need to override api/features in devtools to also return this:
```
"gtm_container_id": "GTM-NP9JM6K7"
```
┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8354-fix-route-gtm-through-telemetry-entrypoint-2f66d73d36508138afacdeffe835f28a) by [Unito](https://www.unito.io)
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **New Features**
* Analytics expanded: page view tracking, richer auth telemetry (includes user IDs), and checkout begin events with attribution.
* Google Tag Manager support and persistent checkout attribution (GA/client/session IDs, gclid/gbraid/wbraid).
* **Chores**
* Telemetry reworked to support multiple providers via a registry with cloud-only initialization.
* Workflow module refactored for clearer exports.
* **Tests**
* Added/updated tests for attribution, telemetry, and subscription flows.
* **CI**
* New check prevents telemetry from leaking into distribution artifacts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary
Add team workspace member management and invite system.
## Changes
- Add members panel with role management (owner/admin/member) and member
removal
- Add invite system with email invites, pending invite display, and
revoke functionality
- Add invite URL loading for accepting invites
- Add subscription panel updates for member management
- Add i18n translations for member and invite features
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8245-Workspaces-4-members-invites-2f06d73d36508176b2caf852a1505c4a)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Discussion here:
https://comfy-organization.slack.com/archives/C0A0XANFJRE/p1764899027465379
Implement: Subscription tier query parameter for direct checkout flow
Example button link: `/cloud/subscribe?tier=standard`
`tier` could be `standard`, `creator` or `pro`
`cycle` could be `monthly` or `yearly`. it is optional, and `monthly` by
default.
<!-- One sentence describing what changed and why. -->
## Changes
- **What**: <!-- Core functionality added/modified -->
- Add a landing page called `CloudSubscriptionRedirectView.vue` to
handling the subscription tier button link parameter
- Extract subscription handling logic from `PriceTable.vue`
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- Code change touched `PriceTable.vue`
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->
## Review Focus
- link will redirect to login url, when cloud app not login
- after login, the cloud app will redirect to CloudSubscriptionRedirect
page
- wait for several seconds, the cloud app will be redirected to checkout
page
<!-- Critical design decisions or edge cases that need attention -->
<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->
## Screenshots (if applicable)

<!-- Add screenshots or video recording to help explain your changes -->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7553-feat-handling-subscription-tier-button-link-parameter-2cb6d73d365081ee9580e89090248300)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
## Summary
Extracts desktop UI into apps/desktop-ui package with minimal changes.
## Changes
- **What**:
- Separates desktop-specific code into standalone package with
independent Vite config, router, and i18n
- Drastically simplifies the main app router by removing all desktop
routes
- Adds a some code duplication, most due to the existing design
- Some duplication can be refactored to be *simpler* on either side - no
need to split things by `isElectron()`
- Rudimentary storybook support has been added
- **Breaking**: Stacked PR for publishing must be merged before this PR
makes it to stable core (but publishing _could_ be done manually)
- #5915
- **Dependencies**: Takes full advantage of pnpm catalog. No additional
dependencies added.
## Review Focus
- Should be no changes to normal frontend operation
- Scripts added to root package.json are acceptable
- The duplication in this PR is copied as is, wherever possible. Any
corrections or fix-ups beyond the scope of simply migrating the
functionality as-is, can be addressed in later PRs. That said, if any
changes are made, it instantly becomes more difficult to separate the
duplicated code out into a shared utility.
- Tracking issue to address concerns: #5925
### i18n
Fixing i18n is out of scope for this PR. It is a larger task that we
should consider carefully and implement properly. Attempting to isolate
the desktop i18n and duplicate the _current_ localisation scripts would
be wasted energy.
* Move to new route
* Convert to tailwind
* Basic style
* Add userStore
* nit
* nit
* nit
* Remove app.#setUser
* Route to user-select view
* Mock login
* Use primevue UI components
* handle create new user
* Remove legacy user selection
* Add logout button on side toolbar
* Add username to logout button tooltip
* Add playwright tests
* hide logout button in single user server
* nit
* fix router and move graph related parts to GraphView.vue
* (fix) add back child element in UnloadWindowConfirmDialog
* (cleanup) remove empty callback
* (fix) routing issue when base url is not webroot
* add back DEV_SERVER_COMFYUI_URL
* test to validate subrouting
* Update test expectations [skip ci]
* core tests need to prep the page
* Update test expectations [skip ci]
---------
Co-authored-by: github-actions <github-actions@github.com>
* (fix) index.html formating for prettier
* (add) proper icon management
- on-demand icons auto importing
- handle all available icon sets (https://icones.js.org)
* (fix) proper css management
* (add) front stack improvement:
- implement vue router
- prepare for App.vue simplification
- proper management of views and layouts
- fix Tailwind CSS and prepare for overall css cleaning
* (fix) move back user.css to public dir
* (fix) remove user.css import from main.ts