Commit Graph

7778 Commits

Author SHA1 Message Date
Christian Byrne
dc09eb60e4 fix: add deprecation warning for widget.inputEl on STRING multiline widgets (#9808)
## Summary

Add a deprecation warning when custom nodes access `widget.inputEl` on
STRING multiline widgets, directing them to use `widget.element`
instead.

## Changes

- **What**: Add a reusable `defineDeprecatedProperty` helper in
`feedback.ts` that creates an ODP getter/setter proxy from a deprecated
property to its replacement, logging via the existing `warnDeprecated`
utility (deduplicates: warns once per unique message per session). Use
it to deprecate `widget.inputEl` → `widget.element`.

## Review Focus

- `defineDeprecatedProperty` is generic and can be reused for future
property deprecations across the codebase.
- `warnDeprecated` already handles deduplication via a `Set`, so heavy
access patterns (e.g. custom nodes reading `widget.inputEl` in tight
loops) won't spam.
- `enumerable: false` keeps the deprecated alias out of `Object.keys()`
/ `for...in` / `JSON.stringify`.

Fixes Comfy-Org/ComfyUI#12893

<!-- Pipeline-Ticket: 6b291ba2-694c-42d6-ac0c-fcbdcba9373a -->

---------

Co-authored-by: Dante <bunggl@naver.com>
2026-03-28 13:24:49 -07:00
Christian Byrne
30b17407db fix: use v-show for frequently toggled canvas overlay components (#9401)
## What
Replace `v-if` with `v-show` on SelectionRectangle and NodeTooltip
components.

## Why
Firefox profiler shows 687 Vue `insert` markers from mount/unmount
cycling during canvas interaction. These components toggle frequently
during drag and mouse move events.

## How
- **SelectionRectangle**: `v-if` → `v-show` (single element, safe to
keep in DOM)
- **NodeTooltip**: `v-if` → `v-show` + no-op guard on `hideTooltip()` to
skip redundant reactivity triggers

## Perf Impact
Expected reduction: ~687 Vue insert/remove operations per profiling
session

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9401-fix-use-v-show-for-frequently-toggled-canvas-overlay-components-31a6d73d365081aba2d7fce079bde7e9)
by [Unito](https://www.unito.io)
2026-03-28 13:23:20 -07:00
Alexander Brown
5b4ebf4d99 test: audit skipped tests — prune stale, re-enable stable, remove dead code (#10312)
## Summary

Audit all skipped/fixme tests: delete stale tests whose underlying
features were removed, re-enable tests that pass with minimal fixes, and
remove orphaned production code that only the deleted tests exercised.
Net result: **−2,350 lines** across 50 files.

## Changes

- **Pruned stale skipped tests** (entire files deleted):
- `LGraph.configure.test.ts`, `LGraph.constructor.test.ts` — tested
removed LGraph constructor paths
- `LGraphCanvas.ghostAutoPan.test.ts`,
`LGraphCanvas.linkDragAutoPan.test.ts`, `useAutoPan.test.ts`,
`useSlotLinkInteraction.autoPan.test.ts` — tested removed auto-pan
feature
- `useNodePointerInteractions.test.ts` — single skipped test for removed
callback
  - `ImageLightbox.test.ts` — component replaced by `MediaLightbox`
- `appModeWidgetRename.spec.ts` (E2E) — feature removed; helper
`AppModeHelper.ts` also deleted
- `domWidget.spec.ts`, `widget.spec.ts` (E2E) — tested removed widget
behavior

- **Removed orphaned production code** surfaced by test pruning:
- `useAutoPan.ts` — composable + 93 lines of auto-pan logic in
`LGraphCanvas.ts`
  - `ImageLightbox.vue` — replaced by `MediaLightbox`
- Auto-pan integration in `useSlotLinkInteraction.ts` and
`useNodeDrag.ts`
- Dead settings (`LinkSnapping.AutoPanSpeed`,
`LinkSnapping.AutoPanMargin`) in `coreSettings.ts` and
`useLitegraphSettings.ts`
- Unused subgraph methods (`SubgraphNode.getExposedInput`,
`SubgraphInput.getParentInput`)
- Dead i18n key, dead API schema field, dead fixture exports
(`dirtyTest`, `basicSerialisableGraph`)
  - Dead test utility `litegraphTestUtils.ts`

- **Re-enabled skipped tests with minimal fixes**:
  - `useBrowserTabTitle.test.ts` — removed skip, test passes as-is
- `eventUtils.test.ts` — replaced MSW dependency with direct `fetch`
mock
- `SubscriptionPanel.test.ts` — stabilized button selectors,
timezone-safe date assertion
- `LinkConnector.test.ts` — removed stale describe blocks, kept passing
suite
- `widgetUtil.test.ts` — removed skipped tests for deleted functionality
- `comfyManagerStore.test.ts` — removed skipped `isPackInstalling` /
`action buttons` / `loading states` blocks

- **Re-enabled then re-skipped 3 flaky E2E tests** (fail in CI for
pre-existing reasons):
- `browserTabTitle.spec.ts` — canvas click timeout (element not visible)
  - `groupNode.spec.ts` — screenshot diff (stale golden image)
  - `nodeSearchBox.spec.ts` — `p-dialog-mask` intercepts pointer events

- **Simplified production code** alongside test cleanup:
- `useNodeDrag.ts` — removed auto-pan integration, simplified from
170→100 lines
- `DropZone.vue` — refactored URL-drop handling, removed unused code
path
- `ToInputFromIoNodeLink.ts`, `SubgraphInputEventMap.ts` — removed dead
subgraph wiring

- **Dependencies**: none
- **Breaking**: none (all removed code was internal/unused)

## Review Focus

- Confirm deleted production code (`useAutoPan`, `ImageLightbox`,
subgraph methods) has no remaining callers
- Validate that simplified `useNodeDrag.ts` preserves drag behavior
without auto-pan
- Check that re-skipped E2E tests have clear skip reasons for future
triage

## Screenshots (if applicable)

N/A

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-03-28 13:08:52 -07:00
pythongosssss
6836419e96 fix: App mode - Save as not using correct extension or persisting mode on change (#10679)
## Summary

With a previously saved workflow, selecting "Save as" in app mode would
not correctly change the file extension to the chosen mode, and would
require an additional save after to persist the actual mode change.

Recreation:
- Build app
- Save as worklow X, app mode
- Select Save as from builder footer [Save | v] chevron button
- Select node graph
- Save
- Check workflow on disk - it's still called X.app.json and doesn't have
linearMode: false <-- bug

## Changes

- **What**: 
- pass isApp to save workflow
- ensure active graph & initialMode are correctly set when calling
saveAs BEFORE the actual saveWorkflow call
- add linearMode to workflowShema to prevent casts
- tests

## Review Focus
e2e tests coming in a follow up PR along with some refactoring of the
browser tests (left this PR focused to the actual fix)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10679-fix-App-mode-Save-as-not-using-correct-extension-or-persisting-mode-on-change-3316d73d365081ef985cf57c91c34299)
by [Unito](https://www.unito.io)
2026-03-28 12:08:35 -07:00
Christian Byrne
4c59a5e424 [chore] Update Ingest API types from cloud@0125ed6 (#10677)
## Automated Ingest API Type Update

This PR updates the Ingest API TypeScript types and Zod schemas from the
latest cloud OpenAPI specification.

- Cloud commit: 0125ed6
- Generated using @hey-api/openapi-ts with Zod plugin

These types cover cloud-only endpoints (workspaces, billing, secrets,
assets, tasks, etc.).
Overlapping endpoints shared with the local ComfyUI Python backend are
excluded.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10677-chore-Update-Ingest-API-types-from-cloud-0125ed6-3316d73d36508122a6f2ec7df88d416b)
by [Unito](https://www.unito.io)

---------

Co-authored-by: dante01yoon <6510430+dante01yoon@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-03-28 22:51:04 +09:00
Dante
82242f1b00 refactor: add Badge component and fix twMerge font-size detection (#10580)
## Summary
- Rename `text-xxxs`/`text-xxs` to `text-3xs`/`text-2xs` in design
system CSS — fixes `tailwind-merge` incorrectly classifying custom
font-size utilities as color classes, which clobbered text color
- Add `Badge` component with updated severity colors matching Figma
design (white text on colored backgrounds)
- Add Badge stories under `Components/Badges/Badge`
- Add unit tests including twMerge regression coverage

Split from #10438 per review feedback — this PR contains the
foundational Badge component; migration of consumers follows in a
separate PR.

## Test plan
- [x] Unit tests pass (`Badge.test.ts` — 12 tests)
- [x] Typecheck passes
- [x] Lint passes
- [ ] Verify Badge stories render correctly in Storybook
- [ ] Verify existing components using `text-2xs`/`text-3xs` render
unchanged

Fixes #10438 (partial)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10580-refactor-add-Badge-component-and-fix-twMerge-font-size-detection-32f6d73d3650810dae7cd0d4af67fd1c)
by [Unito](https://www.unito.io)
2026-03-27 19:23:59 -07:00
Comfy Org PR Bot
f9c334092c 1.43.8 (#10635)
Patch version increment to 1.43.8

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10635-1-43-8-3316d73d3650815db627c30a83d2b9fc)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
v1.43.8
2026-03-27 19:19:07 -07:00
Christian Byrne
04aee0308b feat: add SHA-256 hashed email to GTM dataLayer for sign_up/login events (#10591)
## Summary

Adds SHA-256 hashed user email to GTM dataLayer `sign_up` and `login`
events to improve Meta/LinkedIn Conversions API (CAPI) match rate via
Stape server-side tracking.

## Privacy

- Email is SHA-256 hashed client-side before being pushed to dataLayer —
the raw email never enters the analytics pipeline.
- Email is normalized (trimmed + lowercased) before hashing per
Google/Meta requirements.
- If email is absent (e.g., GitHub OAuth without public email), no
`user_data` entry is pushed.

## Testing

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10591-feat-add-SHA-256-hashed-email-to-GTM-dataLayer-for-sign_up-login-events-3306d73d36508148a321d62810698013)
by [Unito](https://www.unito.io)
2026-03-27 19:18:05 -07:00
Dante
caa6f89436 test(assets): add property-based tests for asset utility functions (#10619)
## Summary

Add property-based tests (using `fast-check`) for asset-related pure
utility functions, complementing existing example-based unit tests with
algebraic invariant checks across thousands of randomized inputs.

Fixes #10617

## Changes

- **What**: 4 new `*.property.test.ts` files covering
`assetFilterUtils`, `assetSortUtils`, `useAssetSelection`, and
`useOutputStacks` — 32 property-based tests total

## Why property-based testing (fast-check)?

### Gap in existing tests

The existing example-based unit tests (53 tests across 3 files) verify
behavior for **hand-picked inputs** — specific category names, known
sort orderings, fixed asset lists. This leaves two blind spots:

1. **Edge-case discovery**: Example tests only cover cases the author
anticipates. Property tests generate hundreds of randomized inputs per
run, probing boundaries the author didn't consider (e.g., empty strings,
single-char names, deeply nested tag paths, assets with `undefined`
metadata fields).

2. **Algebraic invariants**: Certain guarantees should hold for **all**
inputs, not just the handful tested. For example:
- "Filtering always produces a subset" — impossible to violate with 5
examples, easy to violate in production with unexpected metadata shapes
- "Sorting is idempotent" — an unstable sort bug would only surface with
specific duplicate patterns
- "Reconciled selection IDs are always within visible assets" — a
set-intersection bug might only appear with specific overlap patterns
between selection and visible sets

3. **No test coverage for `useOutputStacks`**: The composable had zero
tests before this PR.

### What these tests verify (invariant catalog)

| Module | # Properties | Key invariants |
|--------|-------------|----------------|
| `assetFilterUtils` | 10 | Filter result ⊆ input; `"all"` is identity;
ownership partitions into disjoint my/public; empty constraint is
identity |
| `assetSortUtils` | 8 | Never mutates input; output is permutation of
input; idempotent (sort∘sort = sort); adjacent pairs satisfy comparator;
`"default"` preserves order |
| `useAssetSelection` | 7 | After reconcile: selected ⊆ visible;
reconcile never adds new IDs; superset preserves all; empty visible
clears; `getOutputCount` ≥ 1; `getTotalOutputCount` ≥ len(assets) |
| `useOutputStacks` | 7 | Collapsed count = input count; items reference
input assets; unique keys; selectableAssets length = assetItems length;
no collapsed child flags; reactive ref updates |

### Quantitative impact

Each property runs 100 iterations by default → **3,200 randomized inputs
per test run** vs 53 hand-picked examples in existing tests.

**Coverage delta** (v8, measured against target modules):

| Module | Metric | Before (53 tests) | After (+32 property) | Delta |
|--------|--------|-------------------|---------------------|-------|
| `useAssetSelection.ts` | Branch | 76.92% | 94.87% | **+17.95pp** |
| `useAssetSelection.ts` | Stmts | 82.50% | 90.00% | **+7.50pp** |
| `useAssetSelection.ts` | Lines | 81.69% | 88.73% | **+7.04pp** |
| `useOutputStacks.ts` | Stmts | 0% | 37.50% | **+37.50pp** (new) |
| `useOutputStacks.ts` | Funcs | 0% | 75.00% | **+75.00pp** (new) |
| `assetFilterUtils.ts` | All | 97.5%+ | 97.5%+ | maintained |
| `assetSortUtils.ts` | All | 100% | 100% | maintained |

### Prior art

Follows the established pattern from
`src/platform/workflow/persistence/base/draftCacheV2.property.test.ts`.

## Review Focus

- Are the chosen invariants correct and meaningful (not just
change-detector tests)?
- Are the `fc.Arbitrary` generators representative of real-world asset
data shapes?

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10619-test-assets-add-property-based-tests-for-asset-utility-functions-3306d73d3650816985ebcd611bbe0837)
by [Unito](https://www.unito.io)
2026-03-28 10:26:55 +09:00
Dante
c4d0b3c97a feat: fetch publish tag suggestions from hub labels API (#10497)
<img width="1305" height="730" alt="스크린샷 2026-03-28 오전 10 17
30"
src="https://github.com/user-attachments/assets/316fcb72-e749-40da-b29f-05af91f30610"
/>

## Summary
- Replace hardcoded `COMFY_HUB_TAG_OPTIONS` with dynamic fetch from `GET
/hub/labels?type=tag`
- Falls back to the existing static tag list when the API call fails
- Adds `zHubLabelListResponse` Zod schema and `fetchTagLabels` service
method

## Test plan
- [ ] Open publish wizard → verify tag suggestions load from API
- [ ] Disconnect network / use env without hub API → verify hardcoded
fallback tags appear
- [ ] Select and deselect tags → verify behavior unchanged
- [ ] Unit tests pass (`pnpm vitest run` on affected files)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10497-feat-fetch-publish-tag-suggestions-from-hub-labels-API-32e6d73d3650815fb113cf591030d4e8)
by [Unito](https://www.unito.io)
2026-03-28 10:19:21 +09:00
Terry Jia
3eb7c29ea4 test: add image compare widget basic e2e tests (#10597)
## Summary
test: add image compare widget basic e2e tests

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10597-test-add-image-compare-widget-basic-e2e-tests-3306d73d365081699125e86b6caa7188)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-03-27 18:15:11 -07:00
Christian Byrne
cc2cb7e89f [chore] Update Ingest API types from cloud@d4d0319 (#10625)
## Automated Ingest API Type Update

This PR updates the Ingest API TypeScript types and Zod schemas from the
latest cloud OpenAPI specification.

- Cloud commit: d4d0319
- Generated using @hey-api/openapi-ts with Zod plugin

These types cover cloud-only endpoints (workspaces, billing, secrets,
assets, tasks, etc.).
Overlapping endpoints shared with the local ComfyUI Python backend are
excluded.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10625-chore-Update-Ingest-API-types-from-cloud-d4d0319-3306d73d365081509b1cc5cc9727e4f4)
by [Unito](https://www.unito.io)

---------

Co-authored-by: MillerMedia <7741082+MillerMedia@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-27 18:13:29 -07:00
Arthur R Longbottom
d2f4d41960 test: make SubscriptionPanel refill date test timezone-agnostic (#10618)
## Summary

Fix timezone-dependent test failure in SubscriptionPanel and add a local
CI script.

## Changes

- **What**: The `renders refill date with literal slashes` test
hardcoded `12/31/24` but the component renders using local timezone
`Date` methods. In UTC-negative timezones, `2024-12-31T00:00:00Z`
renders as Dec 30. Now computes the expected string the same way the
component does.
- **What**: Added `pnpm test:ci:local` script
(`scripts/test-ci-local.sh`) that builds the frontend, starts a ComfyUI
backend with `--multi-user --front-end-root dist`, runs vitest +
Playwright, then cleans up. One command for full local CI.

## Review Focus

This is a test-only change — no production code modified. The
SubscriptionPanel component itself is unchanged; only the test assertion
is made timezone-agnostic.

## E2E Regression Test

Not applicable — this PR fixes a unit test assertion, not a production
bug. No user-facing behavior changed.
2026-03-27 17:31:25 -07:00
Terry Jia
070a5f59fe add basic mask editor tests (#10574)
## Summary
add basic mask editor tests

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10574-add-basic-mask-editor-tests-32f6d73d36508170b8b2c684be56cd26)
by [Unito](https://www.unito.io)
2026-03-27 16:04:36 -04:00
pythongosssss
7864e780e7 feat: App mode - Rework save flow (#10439)
## Summary

Users were finding the final step of the builder flow
confusing/misleading, with the "choose default mode" not actually saving
the workflow and people losing changes. This updates it to remove
"save"/"set default" as a step in the builder, and changes it to a
distinct action.

## Changes

- **What**: 
- add mode selection tab on footer toolbar
- extract reusable radio group component
- remove setting default mode dialog
- add save/save as/saved dialogs

## Screenshots (if applicable)


https://github.com/user-attachments/assets/c7439c2e-a917-4f2b-b176-f8bb8c10026d

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10439-feat-App-mode-Rework-save-flow-32d6d73d3650814781b6c7bbea685a97)
by [Unito](https://www.unito.io)
2026-03-27 12:53:09 -07:00
Alexander Brown
db1257fdb3 test: migrate 8 hard-case component tests from VTU to VTL (Phase 3) (#10493)
## Summary

Phase 3 of the VTL migration: migrate 8 hard-case component tests from
@vue/test-utils to @testing-library/vue (68 tests).

Stacked on #10490.

## Changes

- **What**: Migrate SignInForm, CurrentUserButton, NodeSearchBoxPopover,
BaseThumbnail, JobAssetsList, SelectionToolbox, QueueOverlayExpanded,
PackVersionSelectorPopover from VTU to VTL
- **`wrapper.vm` elimination**: 13 instances across 4 files (5 in
SignInForm, 3 in CurrentUserButton, 3 in PackVersionSelectorPopover, 2
in BaseThumbnail) replaced with user interactions or removed
- **`vm.$emit()` on stubs**: Interactive stubs with `setup(_, { emit })`
expose buttons or closure-based emit functions (QueueOverlayExpanded,
NodeSearchBoxPopover, JobAssetsList)
- **Removed**: 6 change-detector/redundant tests, 3 `@ts-expect-error`
annotations, `PackVersionSelectorVM` interface, `getVM` helper
- **BaseThumbnail**: Removed `useEventListener` mock — real event
handler attaches, `fireEvent.error(img)` triggers error state

## Review Focus

- Interactive stub patterns: `JobAssetsListStub` and `NodeSearchBoxStub`
use closure-based emit functions to trigger parent event handlers
without `vm.$emit`
- SignInForm form submission test fills PrimeVue Form fields via
`userEvent.type` and submits via button click (replaces `vm.onSubmit()`
direct call)
- CurrentUserButton Popover stub tracks open/close state reactively
- JobAssetsList: file-level `eslint-disable` for
`no-container`/`no-node-access`/`prefer-user-event` since stubs lack
ARIA roles and hover tests need `fireEvent`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10493-test-migrate-8-hard-case-component-tests-from-VTU-to-VTL-Phase-3-32e6d73d365081f88097df634606d7e3)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-03-27 12:37:09 -07:00
Arthur R Longbottom
7e7e2d5647 fix: persist subgraph viewport across navigation and tab switches (#10247)
## Summary

Fix subgraph viewport (zoom + position) drifting when navigating in/out
of subgraphs and switching workflow tabs.

## Problem

Three root causes:
1. **First visit**: `restoreViewport()` silently returned on cache miss,
leaving canvas at stale position
2. **Cross-workflow leakage**: Cache keyed by bare `graphId` — two
workflows with the same subgraph or unsaved workflows shared cache
entries
3. **Stale save on tab switch**: `loadGraphData` and
`changeTracker.restore()` overwrite `canvas.ds` before the async watcher
could save the old viewport

## Solution

1. **Workflow-scoped cache keys**: `${path}#${instanceId}:${graphId}` —
WeakMap assigns unique IDs per workflow object, handling unsaved
workflows with identical paths
2. **`flush: 'sync'` on activeSubgraph watcher**: Fires immediately
during `setGraph()`, BEFORE `loadGraphData`/`changeTracker` can corrupt
`canvas.ds`
3. **Cache miss → rAF fitToBounds**: On first visit, computes bounds
from `graph._nodes` and calls `ds.fitToBounds()` after the browser has
rendered
4. **Workflow switch watcher** (`flush: 'sync'`): Pre-saves viewport
under old workflow identity, suppresses `onNavigated` saves during load
cycle

Key architectural insight: `setGraph()` never touches `canvas.ds`, but
`loadGraphData` and `changeTracker.restore()` both write to it. By using
`flush: 'sync'`, the save happens during `setGraph` (before the
overwrites).

## Review Focus

- `subgraphNavigationStore.ts` — the three fixes and their interaction
- `flush: 'sync'` watchers — critical for correct save timing
- `suppressNavigatedSave` flag — prevents stale saves during async
workflow load

## Breaking Changes

None. Viewport cache is session-only (in-memory LRU). Existing workflows
unaffected.

## Demo Video of Fix


https://github.com/user-attachments/assets/71dd4107-a030-4e68-aa11-47fe00101b25

## Test plan

- [x] Unit: save/restore with workflow-scoped keys
- [x] Unit: cache miss doesn't mutate canvas synchronously
- [x] Unit: navigation integration (enter/exit preserves viewport)
- [x] E2E: first subgraph visit has visible nodes
- [x] Manual: enter subgraph → zoom/pan → exit → re-enter → viewport
restored
- [x] Manual: tab with subgraph → different tab → back → viewport
restored
- [x] Manual: two unsaved workflows → switch between → viewports
isolated

- Fixes #10246
- Related: #8173
<!-- QA_REPORT_SECTION -->
---
## 🔍 Automated QA Report

| | |
|---|---|
| **Status** |  Complete |
| **Report** |
[sno-qa-10247.comfy-qa.pages.dev](https://sno-qa-10247.comfy-qa.pages.dev/)
|
| **CI Run** | [View
workflow](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/23373279990)
|

Before/after video recordings with **Behavior Changes** and **Timeline
Comparison** tables.
2026-03-27 19:32:57 +00:00
pythongosssss
dabfc6521e test: Add test to prevent regression of workflow corruption during graph loading (#10623)
## Summary

Adds regression test for
https://github.com/Comfy-Org/ComfyUI_frontend/pull/9531

## Changes

- **What**:  
- registers extension that triggers checkState during
afterConfigureGraph (at this point the workflow data and active graph
are not in sync), previously causing it to overwrite the workflow data
- switches between tabs
- ensures they are not corrupted

Line 35 can be uncommented to cause the test to fail by clearing the
isLoadingGraph flag

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10623-test-Add-test-to-prevent-regression-of-workflow-corruption-during-graph-loading-3306d73d3650815fbf02ef23dfdcddce)
by [Unito](https://www.unito.io)
2026-03-27 11:54:07 -07:00
Jin Yi
2f9431c6dd fix: stop Escape key propagation in Select components (#10397) 2026-03-27 18:50:04 +09:00
Christian Byrne
62979e3818 refactor: rename firebaseAuthStore to authStore with shared test fixtures (#10483)
## Summary

Rename `useFirebaseAuthStore` → `useAuthStore` and
`FirebaseAuthStoreError` → `AuthStoreError`. Introduce shared mock
factory (`authStoreMock.ts`) to replace 16 independent bespoke mocks.

## Changes

- **What**: Mechanical rename of store, composable, class, and store ID
(`firebaseAuth` → `auth`). Created
`src/stores/__tests__/authStoreMock.ts` — a shared mock factory with
reactive controls, used by all consuming test files. Migrated all 16
test files from ad-hoc mocks to the shared factory.
- **Files**: 62 files changed (rename propagation + new test infra)

## Review Focus

- Mock factory API design in `authStoreMock.ts` — covers all store
properties with reactive `controls` for per-test customization
- Self-test in `authStoreMock.test.ts` validates computed reactivity

Fixes #8219

## Stack

This is PR 1/5 in a stacked refactoring series:
1. **→ This PR**: Rename + shared test fixtures
2. #10484: Extract auth-routing from workspaceApi
3. #10485: Auth token priority tests
4. #10486: Decompose MembersPanelContent
5. #10487: Consolidate SubscriptionTier type

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-27 00:31:11 -07:00
Kelly Yang
6e249f2e05 fix: prevent canvas zoom when scrolling image history dropdown (#10550)
## Summary
 
Fix #10549 where using the mouse wheel over the image history dropdown
(e.g., in "Load Image" nodes) would trigger canvas zooming instead of
scrolling the list.

## Changes
Added `data-capture-wheel="true" ` to the root container. This attribute
is used by the `TransformPane` to identify elements that should consume
wheel events.

## Screenshots
 
after


https://github.com/user-attachments/assets/8935a1ca-9053-4ef1-9ab8-237f43eabb35

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10550-fix-prevent-canvas-zoom-when-scrolling-image-history-dropdown-32f6d73d365081c4ad09f763481ef8c2)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Terry Jia <terryjia88@gmail.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-27 06:43:24 +00:00
Jin Yi
a1c46d7086 fix: replace hardcoded font-size 10px/11px with text-2xs Tailwind token (#10604)
## Summary

Replace all hardcoded `text-[10px]`, `text-[11px]`, and `font-size:
10px` with a new `text-2xs` Tailwind theme token (0.625rem / 10px).

## Changes

- **What**: Add `--text-2xs` custom theme token to design system CSS and
replace 14 hardcoded font-size occurrences across 12 files with
`text-2xs`.

## Review Focus

Consistent use of design tokens instead of arbitrary values for small
font sizes.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10604-fix-replace-hardcoded-font-size-10px-11px-with-text-2xs-Tailwind-token-3306d73d365081dfa1ebdc278e0a20b7)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-03-26 23:35:05 -07:00
Benjamin Lu
dd89b74ca5 fix: wait for settings before cloud desktop promo (#10526)
this fixes two issues, setting store race did not await load, and it
only cleared shown on clear not on show

## Summary

Wait for settings to load before deciding whether to show the one-time
macOS desktop cloud promo so the persisted dismissal state is respected
on launch.

## Changes

- **What**: Await `settingStore.load()` before checking
`Comfy.Desktop.CloudNotificationShown`, keep the promo gated to macOS
desktop, and persist the shown flag before awaiting dialog close.
- **Dependencies**: None

## Review Focus

- Launch-time settings race for `Comfy.Desktop.CloudNotificationShown`
- One-time modal behavior if the app closes before the dialog is
dismissed
- Regression coverage in `src/App.test.ts`

## Screenshots (if applicable)

- N/A

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10526-fix-wait-for-settings-before-cloud-desktop-promo-32e6d73d365081939fc3ca5b4346b873)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-26 22:31:31 -07:00
Christian Byrne
e809d74192 perf: disable Sentry event target wrapping to reduce DOM event overhead (#10472)
## Summary

Disable Sentry `browserApiErrorsIntegration` event target wrapping for
cloud builds to eliminate 231.7ms of `sentryWrapped` overhead during
canvas interaction.

## Changes

- **What**: Configure `browserApiErrorsIntegration({ eventTarget: false
})` in the cloud Sentry init path. This prevents Sentry from wrapping
every `addEventListener` callback in try/catch, which was the #1 hot
function during multi-cluster panning (100 profiling samples). Error
capturing still works via `window.onerror` and `unhandledrejection`.

## Review Focus

- Confirm that disabling event target wrapping is acceptable for cloud
error monitoring — Sentry still captures unhandled errors, just not
errors thrown inside individual event handler callbacks.
- Non-cloud builds already had `integrations: []` /
`defaultIntegrations: false`, so no change there.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10472-perf-disable-Sentry-event-target-wrapping-to-reduce-DOM-event-overhead-32d6d73d365081cdb455e47aee34dcc6)
by [Unito](https://www.unito.io)
2026-03-26 22:06:47 -07:00
Kelly Yang
47c9a027a7 fix: use try/finally for loading state in TeamWorkspacesDialogContent… (#10601)
… onCreate

## Summary
Wrap the function body in try/finally in the
`src/platform/workspace/components/dialogs/TeamWorkspacesDialogContent.vue`
to avoid staying in a permanent loading state if an unexpected error
happens.

Fix #10458 

```
async function onCreate() {
  if (!isValidName.value || loading.value) return
  loading.value = true

  try {
    const name = workspaceName.value.trim()
    try {
      await workspaceStore.createWorkspace(name)
    } catch (error) {
      toast.add({
        severity: 'error',
        summary: t('workspacePanel.toast.failedToCreateWorkspace'),
        detail: error instanceof Error ? error.message : t('g.unknownError')
      })
      return
    }
    try {
      await onConfirm?.(name)
    } catch (error) {
      toast.add({
        severity: 'error',
        summary: t('teamWorkspacesDialog.confirmCallbackFailed'),
        detail: error instanceof Error ? error.message : t('g.unknownError')
      })
    }
    dialogStore.closeDialog({ key: DIALOG_KEY })
  } finally {
    loading.value = false
  }
}
```

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10601-fix-use-try-finally-for-loading-state-in-TeamWorkspacesDialogContent-3306d73d365081dcb97bf205d7be9ca7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 21:38:11 -07:00
Christian Byrne
6fbc5723bd fix: hide inaccurate resolution subtitle on cloud asset cards (#10602)
## Summary

Hide image resolution subtitle on cloud asset cards because thumbnails
are downscaled to max 512px, causing `naturalWidth`/`naturalHeight` to
report incorrect dimensions.

## Changes

- **What**: Gate the dimension display in `MediaAssetCard.vue` behind
`!isCloud` so resolution is only shown on local (where full-res images
are loaded). Added TODO referencing #10590 for re-enabling once
`/assets` API returns original dimensions in metadata.

## Review Focus

One-line conditional change — the `isCloud` import from
`@/platform/distribution/types` follows the established pattern used
across the repo.

Fixes #10590

## Screenshots (if applicable)

N/A — this removes a subtitle that was displaying wrong values (e.g.,
showing 512x512 for a 1024x1024 image on cloud).

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10602-fix-hide-inaccurate-resolution-subtitle-on-cloud-asset-cards-3306d73d36508186bd3ad704bd83bf14)
by [Unito](https://www.unito.io)
2026-03-27 13:32:11 +09:00
Benjamin Lu
db6e5062f2 test: add assets sidebar empty-state coverage (#10595)
## Summary

Add the first user-centric Playwright coverage for the assets sidebar
empty state and introduce a small assets-specific test helper/page
object surface.

## Changes

- **What**: add `AssetsSidebarTab`, add `AssetsHelper`, and cover
generated/imported empty states in a dedicated browser spec

## Review Focus

This is intentionally a small first slice for assets-sidebar coverage.
The new helper still mocks the HTTP boundary in Playwright for now
because current OSS job history and input files are global backend
state, which makes true backend-seeded parallel coverage a separate
backend change.

Long-term recommendation: add backend-owned, user-scoped test seeding
for jobs/history and input assets so browser tests can hit the real
routes on a shared backend. Follow-up: COM-307.

Fixes COM-306

## Screenshots (if applicable)

Not applicable.

## Validation

- `pnpm typecheck:browser`
- `pnpm exec playwright test browser_tests/tests/sidebar/assets.spec.ts
--project=chromium` against an isolated preview env

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10595-test-add-assets-sidebar-empty-state-coverage-3306d73d365081d1b34fdd146ae6c5c6)
by [Unito](https://www.unito.io)
2026-03-26 21:19:38 -07:00
Terry Jia
6da5d26980 test: add painter widget e2e tests (#10599)
## Summary
add painter widget e2e tests

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10599-test-add-painter-widget-e2e-tests-3306d73d365081899b3ec3e1d7c6f57c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-03-27 00:19:17 -04:00
Johnpaul Chiwetelu
9b6b762a97 test: add browser tests for zoom controls (#10589)
## Summary
- Add E2E Playwright tests for zoom controls: default zoom level, zoom
to fit, zoom out with clamping at 10% minimum, manual percentage input,
and toggle visibility
- Add `data-testid` attributes to `ZoomControlsModal.vue` for stable
test selectors
- Add new TestId entries to `selectors.ts`

## Test plan
- [x] All 6 new tests pass locally
- [x] Existing minimap and graphCanvasMenu tests still pass
- [ ] CI passes

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10589-test-add-browser-tests-for-zoom-controls-3306d73d36508177ae19e16b3f62b8e7)
by [Unito](https://www.unito.io)
2026-03-27 05:18:46 +01:00
Kelly Yang
00c8c11288 fix: derive payment redirect URLs from getComfyPlatformBaseUrl() (#10600)
Replaces hardcoded `https://www.comfy.org/payment/...` URLs with
`getComfyPlatformBaseUrl()` so staging deploys no longer redirect users
to production after payment.

fix #10456

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10600-fix-derive-payment-redirect-URLs-from-getComfyPlatformBaseUrl-3306d73d365081679ef4da840337bb81)
by [Unito](https://www.unito.io)
2026-03-26 20:51:07 -07:00
Comfy Org PR Bot
668f7e48e7 1.43.7 (#10583)
Patch version increment to 1.43.7

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10583-1-43-7-3306d73d3650810f921bf97fc447e402)
by [Unito](https://www.unito.io)

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
v1.43.7
2026-03-26 19:56:32 -07:00
Alexander Brown
3de387429a test: migrate 11 interactive component tests from VTU to VTL (Phase 2) (#10490)
## Summary

Phase 2 of the VTL migration: migrate 11 interactive component tests
from @vue/test-utils to @testing-library/vue (69 tests).

Stacked on #10471.

## Changes

- **What**: Migrate BatchCountEdit, BypassButton, BuilderFooterToolbar,
ComfyActionbar, SidebarIcon, EditableText, UrlInput, SearchInput,
TagsInput, TreeExplorerTreeNode, ColorCustomizationSelector from VTU to
VTL
- **Pattern transforms**: `trigger('click')` → `userEvent.click()`,
`setValue()` → `userEvent.type()`, `findComponent().props()` →
`getByRole/getByText/getByTestId`, `emitted()` → callback props
- **Removed**: 4 `@ts-expect-error` annotations, 1 change-detector test
(SearchInput `vm.focus`)
- **PrimeVue**: `data-pc-name` selectors + `aria-pressed` for
SelectButton, container queries for ColorPicker/InputIcon

## Review Focus

- PrimeVue escape hatches in ColorCustomizationSelector
(SelectButton/ColorPicker lack standard ARIA roles)
- Teleport test in ComfyActionbar uses `container.querySelector`
intentionally (scoped to teleport target)
- SearchInput debounce tests use `fireEvent.update` instead of
`userEvent.type` due to fake timer interaction
- EditableText escape-then-blur test simplified:
`userEvent.keyboard('{Escape}')` already triggers blur internally

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10490-test-migrate-11-interactive-component-tests-from-VTU-to-VTL-Phase-2-32e6d73d3650817ca40fd61395499e3f)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-26 19:46:31 -07:00
Alexander Brown
08b1199265 test: migrate 13 component tests from VTU to VTL (Phase 1) (#10471)
## Summary

Migrate 13 component test files from @vue/test-utils to
@testing-library/vue as Phase 1 of incremental VTL adoption.

## Changes

- **What**: Rewrite 13 test files (88 tests) to use `render`/`screen`
queries, `userEvent` interactions, and `jest-dom` assertions. Add
`data-testid` attributes to 6 components for lint-clean icon/element
queries. Delete unused `src/utils/test-utils.ts`.
- **Dependencies**: `@testing-library/vue`,
`@testing-library/user-event`, `@testing-library/jest-dom` (installed in
Phase 0)

## Review Focus

- `data-testid` additions to component templates are minimal and
non-behavioral
- PrimeVue passthrough (`pt`) usage in UserAvatar.vue for icon testid
- 2 targeted `eslint-disable` in FormRadioGroup.test.ts where PrimeVue
places `aria-describedby` on wrapper div, not input

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10471-test-migrate-13-component-tests-from-VTU-to-VTL-Phase-1-32d6d73d36508159a33ffa285afb4c38)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-03-26 18:15:11 -07:00
Dante
98a9facc7d tool: add CSS containment audit skill and Playwright diagnostic (#10026)
## Summary

- Add a Playwright-based diagnostic tool (`@audit` tagged) that
automatically detects DOM elements where CSS `contain: layout style`
would improve rendering performance
- Extend `ComfyPage` fixture and `playwright.config.ts` to support
`@audit` tag (excluded from CI, perf infra enabled)
- Add `/contain-audit` skill definition documenting the workflow

## How it works

1. Loads the 245-node workflow in a real browser
2. Walks the DOM tree and scores every element by subtree size and
sizing constraints
3. For each high-scoring candidate, applies `contain: layout style` via
JS
4. Measures rendering performance (style recalcs, layouts, task
duration) before and after
5. Takes before/after screenshots to detect visual breakage
6. Outputs a ranked report to console

## Test plan

- [ ] `pnpm typecheck` passes
- [ ] `pnpm typecheck:browser` passes
- [ ] `pnpm lint` passes
- [ ] Existing Playwright tests unaffected (`@audit` excluded from CI
via `grepInvert`)
- [ ] Run `pnpm exec playwright test
browser_tests/tests/containAudit.spec.ts --project=chromium` locally
with dev server

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10026-tool-add-CSS-containment-audit-skill-and-Playwright-diagnostic-3256d73d365081b29470df164f798f7d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:08:41 +09:00
jaeone94
8b1cf594d1 fix: improve error overlay design and indicator placement (#10564)
## Summary

- Move error red border from TopMenuSection/ComfyActionbar to
ErrorOverlay
- Add error indicator (outline + StatusBadge dot) on right side panel
toggle button when errors are present, the panel/overlay are closed, and
the errors tab setting is enabled
- Replace technical group titles (e.g. "Missing Node Packs") with
user-friendly i18n messages in ErrorOverlay
- Dynamically change action button label based on single error type
(e.g. "Show missing nodes" instead of "See Errors")
- Remove unused `hasAnyError` prop from ComfyActionbar
- Fix `type="secondary"` → `variant="secondary"` on panel toggle button
- Pre-wire `missing_media` error type support for #10309
- Migrate ErrorOverlay E2E selectors from `getByText`/`getByRole` to
`data-testid`
- Update E2E screenshot snapshots affected by TopMenuSection error state
design changes

## Test plan

- [x] Trigger execution error → verify red border on ErrorOverlay, no
red border on TopMenuSection/ComfyActionbar
- [x] With errors and right side panel closed → verify red outline + dot
on panel toggle button
- [x] Open right side panel or error overlay → verify indicator
disappears
- [x] Disable `Comfy.RightSidePanel.ShowErrorsTab` → verify no indicator
even with errors
- [x] Load workflow with only missing nodes → verify "Show missing
nodes" button label and friendly message
- [x] Load workflow with only missing models → verify "Show missing
models" button label and count message
- [x] Load workflow with mixed errors → verify "See Errors" fallback
label
- [x] E2E: `pnpm test:browser:local -- --grep "Error overlay"`

## Screenshots
<img width="498" height="381" alt="스크린샷 2026-03-26 230252"
src="https://github.com/user-attachments/assets/034f0f3f-e6a1-4617-b8f6-cd4c145e3a47"
/>
<img width="550" height="303" alt="스크린샷 2026-03-26 230525"
src="https://github.com/user-attachments/assets/2958914b-0ff0-461b-a6ea-7f2811bf33c2"
/>
<img width="551" height="87" alt="스크린샷 2026-03-26 230318"
src="https://github.com/user-attachments/assets/396e9cb1-667e-44c4-83fe-ab113b313d16"
/>

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Dante <bunggl@naver.com>
2026-03-27 09:11:26 +09:00
Dante
ff263fced0 fix: make splitter state key position-aware to prevent shared panel widths (#9525)
## Summary

Fix right-side sidebar panels and left-side panels sharing the same
PrimeVue Splitter state key, causing them to incorrectly apply each
other's saved widths.

## Changes

- **What**: Make `sidebarStateKey` position-aware by including
`sidebarLocation` and offside panel visibility in the localStorage key

## Problem

When sidebar location is set to **right**, all panels (both the
right-side sidebar like Job History and left-side panels like Workflow
overview) share a single PrimeVue Splitter `state-key`
(`unified-sidebar`). PrimeVue persists panel widths to localStorage
using this key, so any resize on one side gets applied to the other.

### AS-IS (before fix)

The `sidebarStateKey` is computed without any awareness of panel
position:

```typescript
// Always returns 'unified-sidebar' (when unified width enabled)
// or the active tab id — regardless of sidebar location or offside panel state
const sidebarStateKey = computed(() => {
  return unifiedWidth.value
    ? 'unified-sidebar'
    : (activeSidebarTabId.value ?? 'default-sidebar')
})
```

This produces a **single localStorage key** for all layout
configurations. The result:

1. Set sidebar to **right**, open **Job History** → resize it smaller →
saved to `unified-sidebar`
2. Open **Workflow overview** (appears on the left as an offside panel)
→ loads the same `unified-sidebar` key → gets the Job History width
applied to a completely different panel position
3. Both panels open simultaneously share the same persisted width, even
though they are on opposite sides of the screen

This is exactly the behavior shown in the [issue
screenshots](https://github.com/Comfy-Org/ComfyUI_frontend/issues/9440):
pulling the Workflow overview smaller also changes Job History to that
same size, and vice versa.

### TO-BE (after fix)

The `sidebarStateKey` now includes `sidebarLocation` (`left`/`right`)
and whether the offside panel is visible:

```typescript
const sidebarTabKey = computed(() => {
  return unifiedWidth.value
    ? 'unified-sidebar'
    : (activeSidebarTabId.value ?? 'default-sidebar')
})

const sidebarStateKey = computed(() => {
  const base = sidebarTabKey.value
  const suffix = showOffsideSplitter.value ? '-with-offside' : ''
  return `${base}-${sidebarLocation.value}${suffix}`
})
```

This produces **distinct localStorage keys** per layout configuration:
| Layout | Key |
|--------|-----|
| Sidebar left, no offside | `unified-sidebar-left` |
| Sidebar left, right panel open | `unified-sidebar-left-with-offside` |
| Sidebar right, no offside | `unified-sidebar-right` |
| Sidebar right, left panel open | `unified-sidebar-right-with-offside`
|

Each configuration now persists and restores its own panel sizes
independently, so resizing Job History on the right no longer affects
Workflow overview on the left.

## Review Focus

- The offside suffix (`-with-offside`) is necessary because the Splitter
transitions from a 2-panel layout (sidebar + center) to a 3-panel layout
(sidebar + center + offside) — these are fundamentally different panel
configurations and should not share persisted sizes.

Fixes #9440

## Screenshots (if applicable)

See issue for reproduction screenshots:
https://github.com/Comfy-Org/ComfyUI_frontend/issues/9440

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 08:31:56 +09:00
Alexander Brown
3e197b5c57 docs: ADR 0008 — Entity Component System (#10420)
## Summary

Architecture documentation proposing an Entity Component System for the
litegraph layer.

```mermaid
graph LR
    subgraph Today["Today: Spaghetti"]
        God["🍝 God Objects"]
        Circ["🔄 Circular Deps"]
        Mut["💥 Render Mutations"]
    end

    subgraph Tomorrow["Tomorrow: ECS"]
        ID["🏷️ Branded IDs"]
        Comp["📦 Components"]
        Sys["⚙️ Systems"]
        World["🌍 World"]
    end

    God -->|"decompose"| Comp
    Circ -->|"flatten"| ID
    Mut -->|"separate"| Sys
    Comp --> World
    ID --> World
    Sys -->|"query"| World
```

## Changes

- **What**: ADR 0008 + 4 architecture docs (no code changes)
- `docs/adr/0008-entity-component-system.md` — entity taxonomy, branded
IDs, component decomposition, migration strategy
- `docs/architecture/entity-interactions.md` — as-is Mermaid diagrams of
all entity relationships
- `docs/architecture/entity-problems.md` — structural problems with
file:line evidence
- `docs/architecture/ecs-target-architecture.md` — target architecture
diagrams
- `docs/architecture/proto-ecs-stores.md` — analysis of existing Pinia
stores as proto-ECS patterns

## Review Focus

- Does the entity taxonomy (Node, Link, Subgraph, Widget, Slot, Reroute,
Group) cover all cases?
- Are the component decompositions reasonable starting points?
- Is the migration strategy (bridge layer, incremental extraction)
feasible?
- Are there entity interactions or problems we missed?

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10420-docs-ADR-0008-Entity-Component-System-32d6d73d365081feb048d16a5231d350)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-03-26 16:14:44 -07:00
Deep Mehta
9573074ea6 feat: add model-to-node mappings for 10 node packs (#10560)
## Summary
Add `MODEL_NODE_MAPPINGS` entries for 10 model directories missing UI
backlinks.

### New mappings
- `BiRefNet` → `LayerMask: LoadBiRefNetModelV2` (`version`)
- `EVF-SAM` → `LayerMask: EVFSAMUltra` (`model`)
- `florence2` → `DownloadAndLoadFlorence2Model` (`model`)
- `interpolation` → `DownloadAndLoadGIMMVFIModel` (`model`)
- `rmbg` → `RMBG` (`model`)
- `smol` → `LayerUtility: LoadSmolLM2Model` (`model`)
- `transparent-background` → `LayerMask: TransparentBackgroundUltra`
(`model`)
- `yolo` → `LayerMask: ObjectDetectorYOLO8` (`yolo_model`)
- `mediapipe` → `LivePortraitLoadMediaPipeCropper` (auto-load)
- `superprompt-v1` → `Superprompt` (auto-load)

These mappings ensure the "Use" button in the model browser correctly
creates the appropriate loader node.

## Test plan
- [ ] Verify "Use" button works for models in each new directory

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

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10560-feat-add-model-to-node-mappings-for-10-node-packs-32f6d73d365081d18b6acda078e7fe0b)
by [Unito](https://www.unito.io)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:01:08 -07:00
Alexander Brown
68d47af075 fix: normalize legacy prefixed proxyWidget entries on configure (#10573)
## Summary

Normalize legacy prefixed proxyWidget entries during subgraph configure
so nested subgraph widgets resolve correctly.

## Changes

- **What**: Extract `normalizeLegacyProxyWidgetEntry` to strip legacy
`nodeId: innerNodeId: widgetName` prefixes from serialized proxyWidgets
and resolve the correct `disambiguatingSourceNodeId`. Write-back
comparison now checks serialized content (not just array length) so
stale formats are cleaned up even when the entry count is unchanged.

## Review Focus

- The iterative prefix-stripping loop in `resolveLegacyPrefixedEntry` —
it peels one `N: ` prefix per iteration and tries all disambiguator
candidates at each level.
- The write-back condition change from length comparison to
`JSON.stringify` equality.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10573-fix-normalize-legacy-prefixed-proxyWidget-entries-on-configure-32f6d73d365081e886e1c9b3939e3b9f)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-03-26 15:53:10 -07:00
Alexander Brown
897cf9cb8f Mark failing test as in need of fixing (#10572)
CC @christian-byrne

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10572-Mark-failing-test-as-in-need-of-fixing-32f6d73d3650815cba72d19ebc54b0b3)
by [Unito](https://www.unito.io)
2026-03-26 12:23:44 -07:00
jaeone94
e9b01cf479 fix: create initial workflow tab when persistence is disabled (#10565)
## Summary

- When `Comfy.Workflow.Persist` is OFF and storage is empty,
`initializeWorkflow()` returned without creating any workflow tab —
leaving users with no tab and no way to save
- Now falls through to `loadDefaultWorkflow()` so a default temporary
workflow is always created

## Root Cause

In `useWorkflowPersistenceV2.ts`, `initializeWorkflow()` had an early
return when persistence was disabled:

```ts
if (!workflowPersistenceEnabled.value) return
```

This skipped `loadDefaultWorkflow()`, which is responsible for creating
the initial temporary workflow tab via `comfyApp.loadGraphData()` →
`afterLoadNewGraph()` → `workflowStore.createNewTemporary()`.

## Fix

One-line change: `return` → `return loadDefaultWorkflow()`.

## Test plan

- [x] E2E test: verifies `openWorkflows.length >= 1` after reload with
persistence OFF

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10565-fix-create-initial-workflow-tab-when-persistence-is-disabled-32f6d73d365081d5a681c3e019d373c3)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-26 11:16:50 -07:00
Terry Jia
bcb39b1bf6 feat: support histogram display in curve widget (#10365)
## Summary
- WidgetCurve reads histogram data from nodeOutputStore (sent by backend
CurveEditor node via ui output) and passes it to CurveEditor
- histogramToPath now supports arbitrary-length bin arrays instead
ofhardcoded 256

need BE changes

## Screenshots (if applicable)
<img width="2431" height="1022" alt="image"
src="https://github.com/user-attachments/assets/8421d4a7-1bff-4269-8b55-649838f9d619"
/>

<img width="2462" height="979" alt="image"
src="https://github.com/user-attachments/assets/191c9163-82ab-4eb2-bb74-0037b3ccd383"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10365-feat-support-histogram-display-in-curve-widget-32a6d73d3650816b9852d73309a0b35f)
by [Unito](https://www.unito.io)
2026-03-26 05:29:08 -04:00
Alexander Brown
d940ea76ee fix: repoint ancestor promoted widget bindings when packing nested subgraphs (#10532)
## Summary

Packing nodes inside a subgraph into a nested subgraph no longer blanks
the parent subgraph node's promoted widget values.

## Changes

- **What**: After `convertToSubgraph` moves interior nodes into a nested
subgraph, `_repointAncestorPromotions` rewrites the promotion store
entries on all host SubgraphNodes so they chain through the new nested
node. `rebuildInputWidgetBindings()` then clears the stale
`input._widget` PromotedWidgetView cache and re-resolves bindings from
current connections.
- The root cause was two separate sets of PromotedWidgetView references:
`node.widgets` (rebuilt from the store — correct) vs `input._widget`
(cached at promotion time — stale). `SubgraphNode.serialize()` reads
`input._widget.value`, which resolved against removed node IDs →
`missing-node` → blank values on the next `checkState` cycle.

## Review Focus

- `_repointAncestorPromotions` iterates all graphs to find host nodes of
the current subgraph type — verify this covers all cases (multiple
instances of the same subgraph type).
- `rebuildInputWidgetBindings()` clears `_promotedViewManager` and
re-resolves — confirm no side effects on event listeners or pending
promotions.
- The nested node gets duplicate promotion entries (from both
`_repointAncestorPromotions` and `promoteRecommendedWidgets` via the
`subgraph-converted` event). `store.promote()` deduplicates via
`isPromoted`, but worth verifying.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10532-fix-repoint-ancestor-promoted-widget-bindings-when-packing-nested-subgraphs-32e6d73d365081109d5aea0660434082)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com>
Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: pythongosssss <125205205+pythongosssss@users.noreply.github.com>
Co-authored-by: Yourz <crazilou@vip.qq.com>
2026-03-25 22:43:52 -07:00
Alexander Brown
d397318ad8 Update README for browser testing commands (#10541)
## Summary

Update recommended commands in browser_tests README

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10541-Update-README-for-browser-testing-commands-32f6d73d36508175a675e865a990caed)
by [Unito](https://www.unito.io)

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-03-25 21:50:02 -07:00
Christian Byrne
d860d54366 test: add large graph zoom perf test for ResizeObserver baseline (#10478)
## Summary

Adds a `@perf` test that establishes a baseline for ResizeObserver
layout cost during zoom on a large graph (245 nodes).

## Changes

- **What**: New `large graph zoom interaction` perf test that zooms
in/out 30 steps on `large-graph-workflow`, measuring `layouts`,
`layoutDurationMs`, `frameDurationMs`, and `TBT`. Each zoom step
triggers ResizeObserver for all node elements due to CSS scale changes.

## Review Focus

This is **PR 1 of 2** for throttling the ResizeObserver during zoom/pan.
Once this merges and establishes a baseline on main, the fix PR (#10473)
will show a CI-proven delta demonstrating the improvement.

The test follows the same patterns as `large graph pan interaction` and
`canvas zoom sweep`.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10478-test-add-large-graph-zoom-perf-test-for-ResizeObserver-baseline-32d6d73d365081169537e557c14d8c51)
by [Unito](https://www.unito.io)
2026-03-25 21:05:36 -07:00
Comfy Org PR Bot
86d202bcc1 1.43.6 (#10540)
Patch version increment to 1.43.6

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10540-1-43-6-32f6d73d3650810fb3f5c6d4c59130f2)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
v1.43.6
2026-03-25 20:31:24 -07:00
Johnpaul Chiwetelu
60b6f78397 chore: bump CI container to 0.0.16 (#10527) 2026-03-26 02:34:27 +01:00
Yourz
6c7c3ea006 fix: tree explorer row height and width overflow (#10501)
## Summary

Fix tree explorer row sizing: consistent row height and prevent
horizontal overflow.

## Changes

- **What**:
1. Reduce node bookmark button from `size-6` (24px) to `size-5` (20px)
so node and folder rows both have 36px height, matching
`TreeVirtualizer` estimate-size and fixing tree list overlap.
2. Change row width from `w-full` to `w-[calc(100%-var(--spacing)*4)]`
to prevent horizontal overflow while keeping `mx-2` margin.

## Review Focus

Pure UI change — no test coverage needed. Verify tree rows render at
consistent height and no horizontal overflow occurs.

## Screenshots (if applicable)

| Before    | After |
| -------- | ------- |
|<img width="1218" height="1662" alt="image"
src="https://github.com/user-attachments/assets/89c799ab-cef3-40ee-88ca-900f5d3c7890"
/>|<img width="407" height="758" alt="image"
src="https://github.com/user-attachments/assets/f9aa4569-aaf8-467f-9dde-a187151af9aa"
/>|

N/A

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10501-fix-tree-explorer-row-height-and-width-overflow-32e6d73d3650819aa645c2262693ec62)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-03-26 09:20:42 +09:00
pythongosssss
771f68f92a fix: App mode - workaround for alt+m producing alt+μ on mac (#10528)
## Summary

Adds a second keybinding for app mode as on Mac Alt+M produces Alt+μ

## Changes

- **What**: add extra binding entry

## Screenshots (if applicable)

Still shows alt + m in the keybinding panel
<img width="840" height="206" alt="image"
src="https://github.com/user-attachments/assets/f1906bc2-e7c2-4eac-b3ca-5a8a207cc93c"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10528-fix-App-mode-workaround-for-alt-m-producing-alt-on-mac-32e6d73d36508176b7d6d918c5bb88f3)
by [Unito](https://www.unito.io)
2026-03-25 16:15:41 -07:00
Comfy Org PR Bot
c5e9e52e5f 1.43.5 (#10489)
Patch version increment to 1.43.5

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10489-1-43-5-32e6d73d365081c8aed2d65a4823a0c0)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
v1.43.5
2026-03-25 14:55:05 -07:00