Commit Graph

371 Commits

Author SHA1 Message Date
Christian Byrne
278d491030 refactor: move ellipsis and punctuation into i18n translation strings (#8573)
## Summary

Move ellipsis and punctuation characters into i18n translation strings
for proper internationalization support.

## Changes

- Add 12 new translation keys with punctuation included:
- Placeholder keys with trailing ellipsis (e.g.,
`searchNodesPlaceholder: "Search Nodes..."`)
  - `downloadWithSize` with interpolation: `"Download ({size})"`
  - `completedWithCheckmark`: `"Completed ✓"`
- Prompt keys with colons (e.g., `enterNewNamePrompt: "Enter new
name:"`)
- Update 20 files to use new translation keys instead of string
concatenation

## Review Focus

This eliminates string concatenation patterns like `$t('key') + '...'`
that break proper internationalization, since different languages may
use different punctuation or may not need ellipsis/colons in the same
contexts.

Fixes #7333


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Standardized localization across the app: unified search placeholders
and input hints; updated dialog prompt texts for renaming,
saving/exporting, and related prompts.
* **New Features**
  * Download buttons now show file size via localized text.
  * Completed status displays a localized label with a checkmark.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8573-refactor-move-ellipsis-and-punctuation-into-i18n-translation-strings-2fc6d73d365081828ad3f257bcac7799)
by [Unito](https://www.unito.io)
2026-02-03 15:50:18 -08:00
Alexander Brown
f2d5bfab73 test(browser): refactor browser tests for reliability and maintainability (#8510)
## Summary

Major refactoring of browser tests to improve reliability,
maintainability, and type safety.

## Changes

### Test Infrastructure Decomposition
- Decomposed `ComfyPage.ts` (~1000 lines) into focused helpers:
- `CanvasHelper`, `DebugHelper`, `SubgraphHelper`,
`NodeOperationsHelper`
- `SettingsHelper`, `WorkflowHelper`, `ClipboardHelper`,
`KeyboardHelper`
- Created `ContextMenu` page object, `BaseDialog` base class, and
`BottomPanel` page object
- Extracted `DefaultGraphPositions` constants

### Locator Stability
- Added `data-testid` attributes to Vue components (sidebar, dialogs,
node library)
- Created centralized `selectors.ts` with test ID constants
- Replaced fragile CSS selectors (`.nth()`, `:nth-child()`) with
`getByTestId`/`getByRole`

### Performance & Reliability
- Removed `setTimeout` anti-patterns (replaced with `waitForFunction`)
- Replaced `waitForTimeout` with retrying assertions
- Replaced hardcoded coordinates with computed `NodeReference` positions
- Enforced LF line endings for all text files

### Type Safety
- Enabled `no-explicit-any` lint rule for browser_tests via oxlint
- Purged `as any` casts from browser_tests
- Added Window type augmentation for standardized window access
- Added proper type annotations throughout

### Bug Fixes
- Restored `ExtensionManager` API contract
- Removed test-only settings from production schema
- Fixed flaky selectors and missing test setup

## Testing
- All browser tests pass
- Typecheck passes


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Overhauled browser E2E test infrastructure with many new
helpers/fixtures, updated test APIs, and CI test container image bumped
for consistency.

* **Chores**
* Standardized line endings and applied stricter lint rules for browser
tests; workspace dependency version updated.

* **Documentation**
* Updated Playwright and TypeScript testing guidance and test-run
commands.

* **UI**
* Added stable data-testids to multiple components to improve
testability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-03 12:29:40 -08:00
Christian Byrne
4f2872460c fix: remove delete account button and direct users to support (#8515)
## Summary
Reverts PR #5216 delete account functionality. The delete button only
removed Firebase accounts without canceling Stripe subscriptions,
causing orphaned accounts and support issues.

## Changes
- Removed delete account button from UserPanel.vue
- Added text directing users to contact support@comfy.org for account
deletion (clickable mailto: link)
- Cleaned up related code: removed `handleDeleteAccount` from
useCurrentUser.ts, `deleteAccount` from useFirebaseAuthActions.ts,
`_deleteAccount` from firebaseAuthStore.ts
- Updated en/main.json locale with `contactSupport` key using {email}
placeholder

## Testing
- Typecheck and lint pass
- Manual verification: user settings panel shows contact support text
instead of delete button

## Related Issues
Fixes COM-14243

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8515-fix-remove-delete-account-button-and-direct-users-to-support-2fa6d73d3650819dbc83efb41c07a809)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-01-31 19:14:44 -08:00
Christian Byrne
47113b117e refactor: migrate keybindings to DDD structure (#8369)
## Summary

Migrate keybindings domain to `src/platform/keybindings/` following DDD
principles.

## Changes

- **What**: Consolidate keybinding-related code (types, store, service,
defaults, reserved keys) into a single domain module with flat structure
- Extracted `KeyComboImpl` and `KeybindingImpl` classes into separate
files
- Updated all consumers to import from new location
- Colocated tests with source files
- Updated stores/README.md and services/README.md to remove migrated
entries

## Review Focus

- Verify all import paths were updated correctly
- Check that the flat structure is appropriate (vs nested core/data/ui
layers)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8369-refactor-migrate-keybindings-to-DDD-structure-2f66d73d36508120b169dc737075fb45)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-29 18:40:58 -08:00
AustinMroz
dce6fd1040 Fix invalid keybind flash (#8435)
Previously the save keybind action would
- apply the new keybind
- wait for a network request to persist the change
- close the dialogue regardless of the results of the above changes

During this network request, the dialog would show a warning that the
keybind is invalid because the dialogue "contains a modified keybind
which conflicts with an existing keybind"
<img width="506" height="261" alt="image"
src="https://github.com/user-attachments/assets/e46150ce-9349-4f8e-b3b5-fb0b20dd3db9"
/>


This PR changes the order these actions are applied in.
- The dialogue is immediately closed
- The keybinding is updated if valid
- The keybinding is persisted.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8435-Fix-invalid-keybind-flash-2f76d73d3650815c9657f35e77d331fe)
by [Unito](https://www.unito.io)
2026-01-29 16:26:07 -08:00
Alexander Brown
440e25e232 fix(test): Mobile Settings (#8332)
## Summary

Bigger mask.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8332-fix-test-Mobile-Settings-2f56d73d3650813b8e39ea5d77e39c18)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-27 00:21:15 -08:00
Simula_r
4771565486 Workspaces 4 members invites (#8245)
## 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>
2026-01-24 15:52:40 -08:00
Johnpaul Chiwetelu
941cd2b4a5 refactor: improve TypeScript patterns in test files (Group 1/8) (#8253)
## Summary
Improves type safety in test files by replacing unsafe type patterns
with proper TypeScript idioms.

## Changes
- Define typed `TestWindow` interface extending `Window` for Playwright
tests with custom properties
- Use `Partial<HTMLElement>` with single type assertion for DOM element
mocks
- Remove redundant type imports
- Fix `console.log` → `console.warn` in test fixture

## Files Changed
16 test files across browser_tests, packages, and src/components

## Test Plan
-  `pnpm typecheck` passes
-  No new `any` types introduced
-  All pre-commit hooks pass

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8253-refactor-improve-TypeScript-patterns-in-test-files-Group-1-8-2f16d73d365081548f9ece7bcf0525ee)
by [Unito](https://www.unito.io)

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-23 02:35:09 +01:00
Simula_r
a08ccb55c1 Workspaces 3 create a workspace (#8221)
## Summary

Add workspace creation and management (create, edit, delete, leave,
switch workspaces).

  Follow-up PR will add invite and membership flow.

  ## Changes

  - Workspace CRUD dialogs
  - Workspace switcher popover in topbar
  - Workspace settings panel
  - Subscription panel for workspace context
  

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8221-Workspaces-3-create-a-workspace-2ef6d73d36508155975ffa6e315971ec)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 14:54:41 -07:00
Jin Yi
0288b02113 [refactor] Manager dialog simplification (#8041)
## Summary
Simplifies the Manager dialog by consolidating components and using
BaseModalLayout with v-model support for right panel state.

## Changes
- **Consolidation**: Merged ManagerDialogContent, ManagerHeader,
ManagerNavSidebar, RegistrySearchBar, and SearchFilterDropdown into
single ManagerDialog component
- **Right panel**: Added v-model:rightPanelOpen to BaseModalLayout for
external panel state control; clicking a node card now auto-opens the
info panel
- **Cleanup**: Removed unused useResponsiveCollapse composable, TabItem
and SearchOption types
- **UI tweaks**: Moved action buttons (Install All/Update All) from
header-right-area to contentFilter area


[manager-capture.webm](https://github.com/user-attachments/assets/2dd6092a-965d-4885-8ba6-6a2cc51f024a)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8041-refactor-Manager-dialog-simplification-2e86d73d3650815ba699e49a2748b682)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-01-15 23:32:02 -08:00
Alexander Brown
971316205f Fix(test): Mask username field in settings since it's not deterministic. (#8033)
## Summary

Should stop this from flipping back and forth depending on which user
the harness ends up with.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8033-Fix-test-Mask-username-field-in-settings-since-it-s-not-deterministic-2e76d73d3650811e85f4fc4ca2253e7e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-13 15:44:45 -08:00
Simula_r
3377844408 feat: local/legacy settings dialog fix (#7990)
## Summary

Fix the issue where local/desktop users would top up and then see the
settings homepage dialog instead of the credits tab.

## Changes

- **What**: useSubscription.ts, TopUpCreditsDialogContent.vue,
SubscriptionRequiredDialogContent.vue
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

## Screenshots (if applicable)

Showing this screen after topping up on local/desktop:
<img width="789" height="752" alt="image"
src="https://github.com/user-attachments/assets/ea92b30b-5c3b-412a-acbe-1b0893621e53"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7990-feat-local-legacy-settings-dialog-fix-2e76d73d365081c7b1e1f96a24745e7b)
by [Unito](https://www.unito.io)
2026-01-12 20:50:05 -08:00
Simula_r
f240ecaaff fix: UX nits and styles (#7933)
## Summary

- Fix UX nits

## Screenshots


https://github.com/user-attachments/assets/f224a710-5cfd-4aad-a617-20ec56a37370

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7933-fix-UX-nits-and-styles-2e36d73d365081379a48e1030b7d4340)
by [Unito](https://www.unito.io)
2026-01-09 15:40:25 -08:00
Simula_r
1bf5b5397d Feat(cloud)/new top up dialog (#7899)
## Summary

- Implement the new add credits (top up) dialog. 
- Refactor the subscription dialog to make different credit types easier
to understand

## Changes

- **What**: TopUpCreditsDialogContent.vue, SubscriptionPanel.vue,
/en/main.json
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

## Review Focus

<!-- Critical design decisions or edge cases that need attention -->

<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->


https://github.com/user-attachments/assets/a6454651-e195-4430-bfcc-0f2a8c1dc80b

Relevant notion links:

https://www.notion.so/comfy-org/Implement-New-Top-Up-Dialog-with-Custom-Amount-Input-2df6d73d36508142b901fc0edb0d1fc1?source=copy_link

https://www.notion.so/comfy-org/Implement-Update-confusing-credits-remaining-this-month-message-2df6d73d36508168b7e5ed46754cec60?source=copy_link
2026-01-08 19:22:50 -08:00
Jin Yi
eea24166e0 Refactor/code-reivew (#7893)
## Summary

<!-- One sentence describing what changed and why. -->
https://github.com/Comfy-Org/ComfyUI_frontend/pull/7871
https://github.com/Comfy-Org/ComfyUI_frontend/pull/7858
I refactored the code based on the reviews I received on those two PRs.

## Changes

- **What**: 

1. Updated IconGroup to address the backgroundClass handling.
2. Replaced text-gold-600 with a semantic color token.
3. Replaced PrimeVue Icon with a lucide icon.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7893-Refactor-code-reivew-2e26d73d365081e68a44e89ed1163062)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-01-08 15:52:49 -07:00
Jin Yi
6a733918a7 Improve Import Failed Error Messages (#7871) 2026-01-07 18:54:01 -07:00
Simula_r
ab6678534f Feat(cloud)/pricing plan template details (#7867)
## Summary

- Use video helper popover in top up modal
- Update copy for video helper
- Misc style changes

## Changes

- **What**: /en/main.json, TopUpCreditsDialogContent.vue,
PricingTable.vue
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

## Screenshots (if applicable)

<img width="2226" height="1322" alt="image"
src="https://github.com/user-attachments/assets/e8419c73-f26c-4d1c-84a6-10cdd10937c4"
/>
<img width="2880" height="1624" alt="image"
src="https://github.com/user-attachments/assets/b27c3665-5eae-4983-a40b-f88705bf53be"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7867-Feat-cloud-pricing-plan-template-details-2e16d73d365081599610e47151b3783b)
by [Unito](https://www.unito.io)
2026-01-06 19:45:06 -07:00
Alexander Brown
10feb1fd5b chore: migrate tests from tests-ui/ to colocate with source files (#7811)
## Summary

Migrates all unit tests from `tests-ui/` to colocate with their source
files in `src/`, improving discoverability and maintainability.

## Changes

- **What**: Relocated all unit tests to be adjacent to the code they
test, following the `<source>.test.ts` naming convention
- **Config**: Updated `vitest.config.ts` to remove `tests-ui` include
pattern and `@tests-ui` alias
- **Docs**: Moved testing documentation to `docs/testing/` with updated
paths and patterns

## Review Focus

- Migration patterns documented in
`temp/plans/migrate-tests-ui-to-src.md`
- Tests use `@/` path aliases instead of relative imports
- Shared fixtures placed in `__fixtures__/` directories

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7811-chore-migrate-tests-from-tests-ui-to-colocate-with-source-files-2da6d73d36508147a4cce85365dee614)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
2026-01-05 16:32:24 -08:00
Alexander Brown
7b68b19f11 Component: The Rest of the PrimeVue buttons (#7649)
## Summary

Automated initial change, cleaned up manually.

Please check the screenshot changes.

Includes a11y updates to icon buttons.

Doesn't hit the buttons in Desktop.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7649-WIP-Component-The-Rest-of-the-PrimeVue-buttons-2ce6d73d365081d68e06f200f1321267)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-12-29 15:03:34 -08:00
Simula_r
ccb73186fb refactor: start on removing FF for subscription tiers (#7596)
## Summary

Refactor: remove FF for subscription tier, remove legacy code for non
subscription tier logic.
 
## Review Focus

Preexisting cloud functionality impact.

<!-- 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-7596-refactor-start-on-removing-FF-for-subscription-tiers-2cc6d73d3650816bac3aef893e4f37cd)
by [Unito](https://www.unito.io)
2025-12-19 18:52:37 -07:00
Alexander Brown
2c26fbb550 Component: Button Migration 3: IconTextButton (#7603)
## Summary

Replace all the `IconTextButton`s with `Button`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7603-WIP-Component-Button-Migraion-3-IconTextButton-2cd6d73d365081b7b742fa2172dc2ba8)
by [Unito](https://www.unito.io)
2025-12-18 16:09:56 -08:00
Christian Byrne
fa1719fece fix: pricing table links to wrong page in docs (p2) (#7434)
## Summary

Continuation of updating pricing table link (p1 was
https://github.com/Comfy-Org/ComfyUI_frontend/pull/7402). Create a
constant since it's now used in multiple locations.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7434-fix-pricing-table-links-to-wrong-page-in-docs-p2-2c86d73d36508199b320d49faa6a0c73)
by [Unito](https://www.unito.io)
2025-12-17 19:56:35 -07:00
Alexander Brown
8d7dd9ed67 Component: Button migration 1: TextButton (#7537)
## Summary

Setup the variants and migrate existing uses of
TextButton/TextIconButton/IconButton to a single Button component.

Still a work in progress.

## Changes

- **What**: Add a new Button
- **What**: Migrate old buttons
- **What**: Delete old buttons
- **Dependencies**: CVA, upgrade Storybook

## Review Focus

<!-- 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-7537-WIP-Component-Button-migration-2cb6d73d36508156a81bfc7bbddb36e9)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2025-12-16 20:38:24 -08:00
Christian Byrne
eb04dc20f3 fix: staging badge shown in cloud settings panel (#7444)
## Summary

Fixes issue where settings panel on cloud was showing a "Staging" badge
because the badge's logic was being dictated by the buildtime config.
Adds the same pattern used everywhere else where, if cloud distribution,
use runtime config; otherwise, fallback to buildtime config. Allows
cloud to switch between staging and prod at runtime while local switches
at buildtime.

After fix:

<img width="2062" height="811" alt="image"
src="https://github.com/user-attachments/assets/e53547c5-3dcc-42ea-9e75-602fe7f855a2"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7444-fix-staging-badge-shown-in-cloud-settings-panel-2c86d73d36508154a788e8e2a6dd025a)
by [Unito](https://www.unito.io)
2025-12-13 18:41:17 -07:00
AustinMroz
f2a0e5102e Cleanup app.graph usage (#7399)
Prior to the release of subgraphs, there was a single graph accessed
through `app.graph`. Now that there's multiple graphs, there's a lot of
code that needs to be reviewed and potentially updated depending on if
it cares about nearby nodes, all nodes, or something else requiring
specific attention.

This was done by simply changing the type of `app.graph` to unknown so
the typechecker will complain about every place it's currently used.
References were then updated to `app.rootGraph` if the previous usage
was correct, or actually rewritten.

By not getting rid of `app.graph`, this change already ensures that
there's no loss of functionality for custom nodes, but the prior typing
of `app.graph` can always be restored if future dissuasion of
`app.graph` usage creates issues.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7399-Cleanup-app-graph-usage-2c76d73d365081178743dfdcf07f44d0)
by [Unito](https://www.unito.io)
2025-12-11 23:37:34 -07:00
Yourz
c99865ce7f fix: disable the sign up and sign in button when form is invalid (#7376)
## Summary

<!-- One sentence describing what changed and why. -->

Add a disabled state to the sign-up button in the cloud onboarding
views. The button should be disabled when the form is invalid to prevent
users from submitting incomplete or incorrectly formatted information.

## Changes

- **What**: <!-- Core functionality added/modified -->
- Add disabled state to SignUp button and SignIn button when SignUp or
SignIn form is invalid.
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

## Review Focus

<!-- Critical design decisions or edge cases that need attention -->

Changes for this notion:
https://www.notion.so/comfy-org/Implement-Disable-sign-up-button-when-form-is-invalid-in-cloud-onboarding-2c56d73d365081edbf8bf06b1f5e52e5

<!-- If this PR fixes an issue, uncomment and update the line below -->
<!-- Fixes #ISSUE_NUMBER -->

## Screenshots (if applicable)
Sign In button

Before(button not disabled when email is invalid)
![Kapture 2025-12-11 at 22 30
59](https://github.com/user-attachments/assets/4278473b-350e-4fea-a299-199697c354b7)

After
![Kapture 2025-12-11 at 22 28
45](https://github.com/user-attachments/assets/b677a444-39ce-487c-a2ad-31369585e333)

<!-- Add screenshots or video recording to help explain your changes -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7376-fix-disable-the-sign-up-and-sign-in-button-when-form-is-invalid-2c66d73d36508139af44cd7cb1e1aeb9)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2025-12-11 07:47:41 -07:00
Christian Byrne
29af56c154 fix: remove useless/misleading toast in topup dialog (#7375)
## Summary

Removes a toast that says "Purchase successful" when clicking the "Add
credits" button -- that button just opens Stripe checkout in another
tab, so the toast is misleading and could be wrong.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7375-fix-remove-useless-misleading-toast-in-topup-dialog-2c66d73d36508124bb65feaf7cf26712)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2025-12-11 07:34:58 -07:00
Yourz
a65e63a322 fix: throttle sign-up and sign-in button (#7358)
## Summary

<!-- One sentence describing what changed and why. -->
Throttle signup button to prevent duplicate Firebase accounts

## Changes

- **What**: <!-- Core functionality added/modified -->
  - Add throttle to SignUp Button in SignUpForm component
  - Add throttle to SignIn Button in SignInForm component
  - Add loading state to SignUp Button in SignUpForm component

## Review Focus
related to this Notion page:
https://www.notion.so/comfy-org/Implement-Throttle-signup-button-to-prevent-duplicate-Firebase-accounts-2c46d73d36508193a8d1fb5146674956

<!-- 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-7358-fix-throttle-sign-up-and-sign-in-button-2c66d73d365081278f4dde0f34d60153)
by [Unito](https://www.unito.io)
2025-12-11 05:48:22 -07:00
Christian Byrne
ea59fb5fc3 fix: hardcoded color tokens (not theme-aware) (#7366)
## Summary

Fixes instances of hardcoded color tokens (not semantic) which are not
theme-aware and therefore are incorrect on e.g. light mode.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7366-fix-hardcoded-color-tokens-not-theme-aware-2c66d73d365081e294aaff366fc78a8f)
by [Unito](https://www.unito.io)
2025-12-11 04:05:42 -07:00
Alexander Brown
72b5444d5a Devex: Linter updates (#7309)
## Summary

Updates for the linter/formatter deps, turning on some more rules.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7309-WIP-Linter-updates-2c56d73d36508101b3ece6bcaf7e5212)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2025-12-10 11:08:47 -08:00
Christian Byrne
356ebe538f style: redesign TopUpCredits dialog (#7305)
Redesigned the TopUpCredits dialog to match Figma design specifications
with proper layout, typography, colors and selection states. Updated
dialog to use workflow-aware messaging, removed header, applied design
system tokens, and integrated subscription renewal dates. Modified
credit packages to use clean USD amounts with realistic video estimates
and fixed button disabled states to show blue with 30% opacity per Figma
design.

| Before | After |
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
| <img width="675" height="863" alt="Screenshot from 2025-12-09
18-08-21"
src="https://github.com/user-attachments/assets/331c7a48-74ae-4a58-b70f-aa476c3fc87c"
/> | <img width="675" height="863" alt="Screenshot from 2025-12-09
18-06-23"
src="https://github.com/user-attachments/assets/dcb7b358-6045-4c89-82ed-3283a20eea89"
/>
 |
2025-12-09 21:30:56 -07:00
Christian Byrne
2c06c58621 feat: update subscription panel with tier-based design and improved UX (#7307)
Transforms the subscription credits panel from legacy design to
tier-based layout with Creator tier details, updated typography using
design system tokens, improved responsive credit breakdown layout, and
better subscription management flow. Updates credit formatting to remove
unnecessary decimals and Credits suffix, replaces external Stripe
billing portal with inline dialog, and reorganizes plan benefits section
with proper v-for structure matching Figma specifications.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7307-feat-update-subscription-panel-with-tier-based-design-and-improved-UX-2c56d73d365081ef8b63e262a6822c72)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2025-12-09 21:30:06 -07:00
Christian Byrne
aef40834f3 add shared comfy credit conversion helpers (#7061)
Introduces cents<->usd<->credit converters plus basic formatters and
adds test. Lays groundwork to start converting UI components into
displaying comfy credits.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7061-add-shared-comfy-credit-conversion-helpers-2bb6d73d3650810bb34fdf9bb3fc115b)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-09 05:11:27 -07:00
Alexander Brown
04158deb02 Feat: Rename and Delete for imported Models ☁️ (#6969)
## Summary

Add Rename and Delete options for Personal Models.

Also updates and standardizes some styles for Cards and adds a simple
Confirmation dialog.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6969-WIP-Feat-Rename-and-Delete-for-custom-Models-2b86d73d36508140a687e929b0544ae6)
by [Unito](https://www.unito.io)

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-12-01 17:16:05 -08:00
Jin Yi
6bb35d46c1 fix: Conditionally hide bottom border in missing nodes modal on non-cloud environments (#6779)
## Summary
- Conditionally hide the bottom border of the missing nodes modal
content when not running in cloud environment
- The footer is not visible in non-cloud environments, so the bottom
border was appearing disconnected

## Changes
- Added conditional `border-b-1` class based on `isCloud` flag in
`MissingNodesContent.vue`
- Keeps top border visible in all environments
- Bottom border only shows in cloud environment where footer is present

## Test plan
- [ ] Open missing nodes dialog in cloud environment - bottom border
should be visible
- [ ] Open missing nodes dialog in non-cloud environment - bottom border
should be hidden
- [ ] Verify top border remains visible in both environments

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6779-fix-Conditionally-hide-bottom-border-in-missing-nodes-modal-on-non-cloud-environments-2b16d73d365081cea1c8c98b11878045)
by [Unito](https://www.unito.io)
2025-11-20 16:52:08 -07:00
AustinMroz
a20fb7d260 Allow unsetting widget labels (#6773)
https://github.com/user-attachments/assets/af344318-dac2-4611-b080-910cdfa1e87d

Quick followup to #6752
- Adds support for placeholder values in dialogService.prompt
- When label is unset, initial prompt is empty
- Display original widget name as placeholder
- When prompt returns an empty string (as opposed to null for a canceled
operation), remove widget label

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6773-Allow-unsetting-widget-labels-2b16d73d365081ae9f5dd085d0081733)
by [Unito](https://www.unito.io)
2025-11-19 21:14:32 -08:00
Alexander Brown
471ccca1dd Style: Design System use across more components (#6705)
## Summary

Only remaining use is in `buttonTypes.ts` which @viva-jinyi is going to
be working on to consolidate our different buttons soon.

## Changes

- **What**: Replace light/dark colors with theme aware design system
tokens.

## Review Focus

Double check the chosen colors for the components

## Screenshots

| Before | After |
| ------ | ----- |
| <img width="607" height="432" alt="image"
src="https://github.com/user-attachments/assets/6c0ee6d6-819f-40b1-b775-f8b25dd18104"
/> | <img width="646" height="488" alt="image"
src="https://github.com/user-attachments/assets/9c8532de-8ac6-4b48-9021-3fd0b3e0bc63"
/> |

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6705-Style-WIP-Design-System-use-across-more-components-2ab6d73d365081619115fc5f87a46341)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-11-17 12:27:10 -08:00
Jin Yi
8dd5a9900b [refactor] Unify Cloud/OSS Missing Nodes modal (#6673)
## Summary
- Merged separate Cloud and OSS workflow warning modals into single
unified modal
- Removed legacy LoadWorkflowWarning.vue
- Renamed CloudMissingNodes* components to MissingNodes* for clarity
- Environment branching now handled internally via isCloud flag
- Restructured i18n: removed loadWorkflowWarning, added
missingNodes.cloud/oss sections
- Improved OSS button styling to match Cloud consistency

## Key Changes
- **OSS**: "Open Manager" + "Install All" buttons
- **Cloud**: "Learn More" + "Got It" buttons (unchanged)
- Single unified modal displays different UI/text based on environment

## 📝 Note on File Renames

This PR renames the following files:

- `CloudMissingNodesHeader.vue` → `MissingNodesHeader.vue` (R053, 53%
similarity)
- `CloudMissingNodesContent.vue` → `MissingNodesContent.vue` (R067, 67%
similarity)
- `LoadWorkflowWarning.vue` → `MissingNodesFooter.vue` (R051, 51%
similarity)
- `CloudMissingNodesFooter.vue` → Deleted (replaced by new
MissingNodesFooter)

**Why GitHub PR UI doesn't show renames properly:**

GitHub detects renames only when file similarity is above 70%. In this
PR, the Cloud/OSS unification significantly modified file contents,
resulting in 51-67% similarity.

However, **Git history correctly records these as renames**. You can
verify with:

```bash
git show <commit-hash> --name-status
```

While GitHub UI shows "additions/deletions", these are actually rename +
modification operations.

## Test Plan
- [x] Test OSS mode: missing nodes modal shows "Open Manager" and
"Install All" buttons
- [x] Test Cloud mode: missing nodes modal shows "Learn More" and "Got
It" buttons
- [x] Verify Install All button functionality in OSS
- [x] Verify modal closes automatically after all nodes are installed
(OSS)


[missingnodes.webm](https://github.com/user-attachments/assets/36d3b4b0-ff8b-4b45-824c-3bc15d93f1a2)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6673-refactor-Unify-Cloud-OSS-Missing-Nodes-modal-2aa6d73d365081a88827d0fa85db4c63)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-15 12:09:44 -08:00
ComfyUI Wiki
b347dd1734 Centralized management of external links (#4471)
Update the desktop guide links to make them platform and locale-aware

Edited by Terry:
Refactor external link management by introducing a centralized
useExternalLink composable with automatic locale and platform detection
for documentation URLs.

- Created useExternalLink composable - A new centralized utility for
managing all external links
- Dynamic docs URL builder (buildDocsUrl) - Automatically constructs
docs.comfy.org URLs with:
  - Locale detection (Chinese vs English)
  - Platform detection (macOS vs Windows for desktop)
  - Flexible path construction with options

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-4471-Add-platform-and-locale-aware-desktop-guide-URL-2346d73d3650815ea4a4dd64be575bbe)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Terry Jia <terryjia88@gmail.com>
2025-11-13 21:35:28 -08:00
Jin Yi
bd6825a274 [style] Fix missing node modal styling (#6672)
## Summary
- Fix background and border colors in the missing nodes modal to use
semantic theme values
- Replace `ContentDivider` component with Tailwind border utilities for
cleaner code
- Update widget background from `bg-component-node-widget-background` to
`bg-secondary-background`
- Update text color from `text-text-secondary` to
`text-muted-foreground`
- Add root-level dialog styling to ensure proper background and border
colors

## Test plan
- [x] Open a workflow with missing nodes
- [x] Verify the missing nodes modal displays with correct background
colors
- [x] Verify border colors match the design system
- [x] Verify text is readable with proper contrast

Before
<img width="658" height="669" alt="before"
src="https://github.com/user-attachments/assets/1ad390ce-bffe-434f-90df-1b624bbb9d3b"
/>

After
<img width="749" height="647" alt="after"
src="https://github.com/user-attachments/assets/c8dccb44-99b8-4387-9e91-490769205979"
/>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6672-style-Fix-missing-node-modal-styling-2aa6d73d365081aea0f5eee35bc27ea7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2025-11-14 02:11:58 +00:00
Jin Yi
f97cf77e75 Add cloud-specific missing nodes warning dialog (#6659)
## Summary
Implements a cloud-specific dialog to warn users when loading workflows
with unsupported custom nodes in Comfy Cloud. The new dialog follows the
visual style of the node conflict dialog and provides appropriate
messaging and actions.

## Changes
- Add `CloudMissingNodesHeader`, `CloudMissingNodesContent`, and
`CloudMissingNodesFooter` components
- Add `showCloudLoadWorkflowWarning` to dialogService
- Update app.ts to show cloud dialog when in cloud environment  
- Add `cloud.missingNodes` translations

## Screenshots
The dialog displays:
- Warning icon and title
- Description of the issue
- List of missing nodes
- "Learn more" link and "Ok, got it" button

## Test plan
1. Load a workflow with custom nodes in cloud environment
2. Verify cloud-specific dialog appears with appropriate styling
3. Verify "Learn more" button opens cloud documentation
4. Verify "Ok, got it" button closes dialog

## Notes
- Two unused i18n keys (`cloud.missingNodes.cannotRun` and
`cloud.missingNodes.missingNodes`) are included for future PR that will
add breadcrumb warning icons and run button disable functionality

<img width="1367" height="988" alt="스크린샷 2025-11-12 오후 4 33 38"
src="https://github.com/user-attachments/assets/75a6fced-959f-4e93-9b82-4e61b53a9ee4"
/>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6659-Add-cloud-specific-missing-nodes-warning-dialog-2a96d73d36508161ae55fe157f55cd17)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 02:03:09 -08:00
Christian Byrne
437c3b2da0 set config via feature flags (#6590)
In cloud environment, allow all the config values to be set by the
feature flag endpoint and be updated dynamically (on 30s poll). Retain
origianl behavior for OSS. On cloud, config changes shouldn't be changed
via redeploy and the promoted image should match the staging image.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6590-set-config-via-feature-flags-2a26d73d3650819f8084eb2695c51f22)
by [Unito](https://www.unito.io)

---------

Co-authored-by: DrJKL <DrJKL0424@gmail.com>
2025-11-05 13:45:21 -07:00
Benjamin Lu
7bf8e5af38 feat(telemetry): add tracking for sidebar, run menu, dialogs, subgraphs, settings and credits (#6511)
Summary
- Add comprehensive telemetry for key UI interactions using existing
telemetry hooks (cloud-enabled, no-op in OSS):

Sidebar and top-level
- Node library button: `node_library`
- Model library button: `model_library`
- Workflows button: `workflows`
- Assets/Media button: `assets`
- Templates button: `templates`
- Keyboard Shortcuts: `keyboard_shortcuts`
- Console: `console`
- Help Center: `help_center`
- Settings (from Comfy logo menu): `settings_menu`

Floating canvas menu
- Minimap toggle: `minimap_toggle`
- Hide links toggle: `hide_links`

Run button and queue
- Run button handle (drag): `run_button_handle`
- Run mode selection: `run_instant`, `run_on_change`
- Queue multiple: `queue_multiple` fires on each run when batch count >
1 (moved from batch-count-change to run-time, per guidance)

Error dialogs
- Close (X/mask/ESC): `error_dialog_close` via dialog onClose
- Show report: `error_show_report`
- Help fix this: `error_help_fix_this`
- Find issues: `error_find_issues`

Nodes / Subgraphs
- Selection toolbox “Node info”: `node_info`
- Enter subgraph (node header enter): `open_subgraph`
- Subgraph breadcrumb navigation: `subgraph_breadcrumb_item` and
`subgraph_breadcrumb_root`

Settings / Credits / Search
- Settings menu button (under Comfy logo): `settings_menu`
- Purchase credits (Settings > Credits panel): tracked via existing
`trackAddApiCreditButtonClicked`
- Purchase credits (Avatar popover Top Up): tracked via existing
`trackAddApiCreditButtonClicked`
- Debounced search telemetry already present for node search and
template filters; left as-is

Notes and answers
- Error dialog onClose: only fires when the dialog actually closes (X,
mask, ESC, or programmatic close). “Show report” and “Help fix this” do
not close the dialog; they each emit their own events.
- Telemetry is behind the cloud provider; calls are optional
(`useTelemetry()?.…`). OSS builds send nothing.

Open questions / follow-ups
- Primary Run button click: today cloud-only `trackRunButton` exists; we
can also emit a UI-level `run` click (`UI_BUTTON_CLICKED` style)
alongside it if desired. Confirm preference and I can add it.
- Subgraph usage richness: if we want structured analytics (e.g.,
action, depth, subgraph id, node count), I can add a dedicated provider
method and include richer metadata at enter/breadcrumb.
- Optional parity: track the Comfy menu’s “Browse Templates” item in
addition to the sidebar Templates button.

Quality
- Ran `pnpm lint:fix` and `pnpm typecheck`; both pass locally.

Implementation details
- All handlers refactored to named functions where needed; used `void`
for intentionally unawaited async calls per lint rules.
- Event names kept consistent in `button_id` strings; happy to align to
a different naming scheme if you prefer.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6511-feat-telemetry-add-tracking-for-sidebar-run-menu-dialogs-subgraphs-settings-and-cre-29e6d73d365081a1b8b4fdfbbf40e18b)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-01 23:09:41 -07:00
Benjamin Lu
72389637ed feat(telemetry): track API credit top-up success via audit events (#6500)
Summary
- Add TelemetryEvents.API_CREDIT_TOPUP_SUCCEEDED and provider method
trackApiCreditTopupSucceeded
- Introduce topupTrackerStore to persist pending top-ups per user
(localStorage) and reconcile against recent audit logs
- Hook purchase flow to start tracking before opening Stripe checkout
- Reconcile after fetching audit events (UsageLogsTable) and after
fetchBalance, then emit telemetry, refresh balance, and clear pending
- Minor refactor in customerEventsService to return awaited result

Implementation details
- Matching strategy:
  - Event type: credit_added
  - Time window: createdAt between top-up start time and +24h
  - Amount: if known, e.params.amount must equal expected cents
- Cross-tab/user changes: synchronize via storage event and userId
watcher

Limitations / Follow-up
- Reconciliation fetches only page 1 (limit 10) of events; in
high-volume cases, a recent credit_added could fall outside the first
page
- The window and pagination issue will be "resolved by a followup PR to
core and cloud"

Files touched
- src/stores/topupTrackerStore.ts (new)
- src/components/dialog/content/setting/UsageLogsTable.vue
- src/composables/auth/useFirebaseAuthActions.ts
- src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.ts
- src/platform/telemetry/types.ts
- src/services/customerEventsService.ts

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6500-feat-telemetry-track-API-credit-top-up-success-via-audit-events-29e6d73d365081169941efae70cf71fe)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <chrbyrne96@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-01 13:17:41 -07:00
Arjan Singh
de535269ee feat(telemetry): help center and workflow creation (#6505)
## Summary

For Cloud distribution:
1. Track help center usage
2. Track workflow creation

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6505-feat-telemetry-help-center-and-workflow-creation-29e6d73d36508185af8ccbf19d5af9e7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <chrbyrne96@gmail.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-01 12:21:50 -07:00
Christian Byrne
c8e24190cd Cloud/gate topup on subscription (#6399)
## Summary

Gate the Top up buttons in the user dropdown and credits page of the
settings.


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6399-Cloud-gate-topup-on-subscription-29c6d73d36508127866cdcbcfda66c46)
by [Unito](https://www.unito.io)

---------

Co-authored-by: DrJKL <DrJKL0424@gmail.com>
2025-11-01 01:37:00 -07:00
Terry Jia
99958d3aa9 add api node link (#6494)
## Summary

add api node page link on credit and subscription pannel

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6494-add-api-node-link-29e6d73d365081aaa2f4d1647683ecda)
by [Unito](https://www.unito.io)
2025-11-01 01:12:31 -07:00
Christian Byrne
1322a56653 Cloud/tracking v2 (#6400)
## Summary

<!-- One sentence describing what changed and why. -->

## Changes

- **What**: <!-- Core functionality added/modified -->
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

## Review Focus

<!-- 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-6400-Cloud-tracking-v2-29c6d73d365081a1ae32e9337f510a9e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Arjan Singh <arjan@comfy.org>
2025-10-30 20:46:42 -07:00
Alexander Brown
b03cf7e11d Style: Token renaming and style organization (#6337)
## Summary

Align color names and organize style.css some more

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6337-Style-Token-renaming-and-style-organization-29a6d73d365081b69f25ce1298c67fdc)
by [Unito](https://www.unito.io)
2025-10-28 12:13:28 -07:00
Christian Byrne
b1439be7f0 remove checkbox from sign up form (#6269)
## Summary

Removes the checkbox from the sign up form to simplify the user
experience. The "By clicking 'Next' or 'Sign Up'..." notice at the
bottom already covers terms and privacy.

## Changes

- Removed checkbox field from sign up schema
- Updated `SignUpForm.vue` component
- Removed unused `Checkbox` import

## Before/After

**Before:**
Sign up form included a checkbox that users had to check before
submitting

**After:**
Sign up form is cleaner without the checkbox. The existing notice text
covers the same information:
> "By clicking 'Next' or 'Sign Up', you agree to our Terms of Use and
Privacy Policy."

This notice appears on both sign in and sign up modals.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6269-remove-checkbox-from-sign-up-form-2976d73d3650819ab480e4db6685baee)
by [Unito](https://www.unito.io)
2025-10-24 19:21:16 -07:00