Backport of #7899 to `cloud/1.36`
## Summary
- Implement the new add credits (top up) dialog
- Refactor the subscription dialog to make different credit types easier
to understand
## Conflicts Resolved
- `src/components/dialog/content/TopUpCreditsDialogContent.vue` - Took
PR version (new UI)
- `src/locales/en/main.json` - Added missing `usdAmount` translation key
Automatically created by manual backport process.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7932-backport-cloud-1-36-Feat-cloud-new-top-up-dialog-2e36d73d3650812dba2cd7edcb43259b)
by [Unito](https://www.unito.io)
Backport of #7793 to `cloud/1.36`
Automatically created by backport workflow.
Co-authored-by: Luke Mino-Altherr <luke@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Fixes the cancel button on queue job items to properly handle pending
(queued) jobs.
## Problem
The cancel button was calling `api.interrupt()` for all jobs, but
interrupt only affects running/initializing jobs. For pending jobs, it
silently fails with log message: `"Prompt ... is not currently running,
skipping interrupt"`.
The "Cancel job" option in the context menu worked correctly because it
checks the job state first.
Reported in #7758.
## Changes
Update `onCancelItem` in `QueueProgressOverlay.vue` to mirror the
behavior of `cancelJob()` in `useJobMenu.ts`:
- Check `item.state` before deciding which API to call
- Call `api.interrupt(promptId)` for `running` or `initialization`
states
- Call `api.deleteItem('queue', promptId)` for `pending` state
- Refresh queue state after cancel action with `queueStore.update()`
## Testing
- All 3816 unit tests pass
- Type check passes
- Lint passes (prettier, oxlint, eslint)
## Steps to Reproduce (before fix)
1. Queue more than 1 job
2. Open job history
3. Click "Cancel" button on any "in queue" job
4. Observe nothing happens (job remains in queue)
After this fix, clicking Cancel on a pending job will remove it from the
queue.
Fixes#7758
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7788-fix-queue-Cancel-button-now-works-for-pending-jobs-2d86d73d365081b3957fdf1d5d677809)
by [Unito](https://www.unito.io)
---------
Co-authored-by: RUiNtheExtinct <deepkarma001@gmail.com>
## Problem
When sidebar is positioned on the right, the properties panel also
appears on the right, causing both panels to compete for space and
creating a poor layout.
## Solution
Properties panel now dynamically positions itself opposite to the
sidebar:
- Sidebar left → Properties panel right (default)
- Sidebar right → Properties panel left
## Changes
- Modified `LiteGraphCanvasSplitterOverlay.vue` to conditionally render
properties panel based on sidebar location
- Updated splitter refresh key to recalculate layout when sidebar
position changes
- Added dynamic close button icon in `RightSidePanel.vue` that points in
the correct direction
## Testing
- Created E2E tests to verify positioning behavior
- Manually verified visual behavior in browser
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7647-feat-position-properties-panel-opposite-to-sidebar-2ce6d73d365081049683e74c8d03dbdd)
by [Unito](https://www.unito.io)
## Summary
Ensure the templates locale Playwright test validates localized UI text
instead of waiting on a flaky network request.
## Changes
- **What**: Update `Templates >> Uses proper locale files for templates`
to assert on French strings rendered in the dialog and confirm English
fallback is absent
## Review Focus
- Confirm the chosen French strings always appear when the localized
bundle loads so the test meaningfully covers the regression
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7705-test-deflake-templates-locale-coverage-2d16d73d365081ffbf9adc1623a36733)
by [Unito](https://www.unito.io)
# Fix Import Failed Warning Icon
## Problem Description
Warning icons were not displayed when import failed errors occurred in
installed packages.
## Root Cause
Conflict detection logic mismatch between `PackCardFooter` and
`PackEnableToggle`:
- **PackCardFooter**: Uses `checkNodeCompatibility()`
- System compatibility check **before** installation (OS, accelerator,
version, etc.)
- Does not include import failed information
- **PackEnableToggle**: Uses `getConflictsForPackageByID()`
- Actual conflict data **after** installation (including import failed)
- But was dependent on parent component's `hasConflict` prop
## Changes Made
### 1. PackEnableToggle.vue
```diff
- <div v-if="hasConflict">
+ <div v-if="packageConflict?.has_conflict">
```
- Removed `hasConflict` prop dependency
- Changed to use only internal store data (`packageConflict`)
### 2. PackCardFooter.vue
```diff
- <PackEnableToggle :has-conflict="hasConflicts" :node-pack="nodePack" />
+ <PackEnableToggle :node-pack="nodePack" />
```
- Removed unnecessary `has-conflict` prop passing
## Result
- ✅ Warning icon properly displays for installed packages with import
failed errors
- ✅ Conflict modal works correctly when clicked
- ✅ Each component uses appropriate conflict detection logic
[after.webm](https://github.com/user-attachments/assets/80576018-0a5b-4e32-9df6-686be3774313)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7753-fix-import-fail-info-warning-icon-2d36d73d365081518fbeedf539a19040)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
#7435 introduced a tricky regression which will cause extremely small
levels of zoom with nodes spread far apart when in vue mode. I am able
to consistently reproduce this behaviour by
- Being in vue mode
- Swapping to a different tab so that ComfyUI is in the background
- Making a pointless line change to frontend code so that vite forces a
reload
- Waiting ~1 minute to ensure the reload completes
- Swapping back to the ComfyUI tab
From testing, if a reload occurs while the tab is backgrounded, the
canvas has an uninitialized size of 300x150. This PR proposes falling
back to a more sane default width and height of 1920x1080 if it is
detected that the canvas element is unitialized.
| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/8e19fc98-7187-4008-98cc-fb5ea3bcdce2"/>
| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/add88614-3451-44df-ae9a-b0b867486459"
/>|
This appears to have consistently good results, but second opinions or
further testing would be appreciated. A more reasonable option (like
skipping this automatic fitView if the canvas has uninitialized size) is
likely to be safer, even if it results in a return of edge cases
resulting in a graph having no nodes in view after load.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7751-Workaround-for-reload-causing-node-spread-2d36d73d365081b9ae74d5f0e6f436f5)
by [Unito](https://www.unito.io)
## Summary
Adds HuggingFace as a model import source alongside CivitAI, with
improved UX for model type selection and UTF-8 filename support.
## Changes
- **Import Sources**: Implemented extensible import source handler
pattern supporting both CivitAI and HuggingFace
- **UTF-8 Support**: Decode URL-encoded filenames to properly display
international characters (e.g., Chinese)
- **UX**: Sort model types alphabetically for easier selection
- **Feature Flag**: Added `huggingfaceModelImportEnabled` flag for
gradual rollout
- **i18n**: Use proper template parameters for localized error messages
## Technical Details
- Created `ImportSourceHandler` interface for extensibility
- Refactored existing CivitAI logic into handler pattern
- Added URL validation per source
- Filename decoding handles malformed URLs gracefully
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7540-feat-Add-HuggingFace-model-import-support-2cb6d73d3650818f966cca89244e8c36)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Pass target tier to billing portal API for deep linking to Stripe's
subscription update confirmation screen when user has an active
subscription.
## Changes
- **What**: When a user with an active subscription clicks a tier in
PricingTable, pass the target tier (including billing cycle) to
`accessBillingPortal` which sends it as `target_tier` in the request
body. This enables the backend to create a Stripe billing portal deep
link directly to the subscription update confirmation screen.
- **Dependencies**: Requires comfy-api PR for `POST /customers/billing`
`target_tier` support
## Review Focus
- PricingTable now differentiates between new subscriptions (checkout
flow) and existing subscriptions (billing portal with deep link)
- Type derivation uses `Parameters<typeof
authStore.accessBillingPortal>[0]` to avoid duplicating the tier union
(matches codebase pattern)
- Registry types manually updated to include `target_tier` field (will
be regenerated when API is deployed)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7692-feat-pass-target-tier-to-billing-portal-for-subscription-updates-2d06d73d365081b38fe4c81e95dce58c)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Updates SubscriptionPanel to display yearly-appropriate labels for
annual subscribers:
- "Credits remaining this year" instead of "this month"
- "Yearly credits" instead of "Monthly credits" in the "Your plan
includes" section
## Changes
- Added `creditsRemainingThisYear` i18n key
- Added `creditsRemainingLabel` computed that switches based on
`isYearlySubscription`
- Updated `tierBenefits` to use `yearlyCreditsLabel` for annual
subscribers
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7706-fix-show-yearly-labels-in-subscription-panel-for-annual-subscribers-2d16d73d365081488552c2c0b03d862e)
by [Unito](https://www.unito.io)
## Summary
Removes the legacy mask editor. May also want to remove the "Beta" tags
on all the current mask editor components/mentions in the app now as
well.
## Context
Telemetry data shows zero users using the legacy mask editor. It has
been considerable time since we switched to the new one, and there
really is no reason to use the legacy version given how lacking it is.
In https://github.com/Comfy-Org/ComfyUI_frontend/pull/7332 (v1.35.2 -
Dec 11, 2025), we added a final warning that the legacy mask editor is
being removed.
On 1.36, this PR can be merged, as more than enough warning will have
been given.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7370-cleanup-remove-the-legacy-mask-editor-and-all-related-code-2c66d73d365081d58fbed0f3c84bcb0d)
by [Unito](https://www.unito.io)