Commit Graph

7907 Commits

Author SHA1 Message Date
Kelly Yang
63fff48ce6 fix(keybindings): serialize KeybindingImpl to plain object before persisting
_.isEqual compares constructors, so KeybindingImpl instances are never
equal to the plain objects returned by the backend. Serialize bindings
to plain objects before passing to setMany so the deep-equality check
in settingStore can correctly skip redundant writes.
2026-05-05 14:24:27 -07:00
Kelly Yang
55a558f323 fix(settings): use deep equality to skip redundant setting writes
`applySettingLocally` compared `newValue` and `oldValue` with `===`,
but `get()` always returns a `_.cloneDeep` result, so object and array
settings always produced different references even when the values were
identical. Replace with `_.isEqual` so redundant `onChange` calls and
API writes are correctly suppressed for non-primitive settings.
2026-05-05 13:57:05 -07:00
Yourz
fb32b9a5c5 fix(website): prevent HeroSection fade from bleeding into CloudBannerSection on /download (#11974)
*PR Created by the Glary-Bot Agent*

---

## Summary

The left side of `CloudBannerSection` on `/download` showed an
unintended fade-out: the bottom-left of the banner appeared darker than
the rest of the bar.

## Root cause

`product/local/HeroSection.vue` renders an SVG illustration whose
container has `lg:z-1` and whose SVG element has `overflow-visible`. The
SVG contains a left-edge fade `<rect x="300" y="150" width="250"
height="900" fill="url(#localHeroFadeLeft)" />` that paints outside the
SVG's `viewBox` (`400 200 550 800`) — including upward into the area
occupied by the preceding `CloudBannerSection`.

Because `CloudBannerSection` had `position: static` and `z-auto`, the
positively-stacked illustration painted over the banner's bottom-left,
producing the visible darkening.

## Fix

Establish a stacking context on `CloudBannerSection` (`relative z-20`)
so it always renders above the hero illustration's overflow on every
page that includes the banner (download, api, cloud/enterprise, and
zh-CN equivalents).

This is a minimal, isolated change to the shared component — no logic or
markup structure changes.

## Verification

- Reproduced visually at `lg` breakpoint and confirmed the fade is gone
after the fix.
- Verified `/download`, `/api`, `/cloud/enterprise`, and
`/zh-CN/download` render correctly.
- `pnpm typecheck` and `pnpm typecheck:website` pass (run automatically
by pre-commit hook).
- `oxfmt`, `oxlint`, `eslint`, `stylelint` all pass.

### Before
![Before — left side of CloudBannerSection darkens with a
fade](.glary/screenshots/before-download-top.png)

### After
![After — banner background is uniform across full
width](.glary/screenshots/after-download-fix.png)

## Follow-up

Consider adding a Playwright visual regression test for the banner/hero
seam on `/download` to catch future stacking regressions (called out by
review).

## Screenshots

![Before — CloudBannerSection on /download shows a darker fade on the
bottom-left of the
banner](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/5e82c32678dd22a4a48d5fa9d8b531f033d1f4ad6e0e286657e985266efd672c/pr-images/1777994095943-59c4d522-597b-49ff-a494-6a4bb52d76a0.png)

![After — CloudBannerSection on /download has uniform background across
its full width with no left-side
fade](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/5e82c32678dd22a4a48d5fa9d8b531f033d1f4ad6e0e286657e985266efd672c/pr-images/1777994096270-03017b24-b01f-49b9-8fa4-0a297c57253e.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11974-fix-website-prevent-HeroSection-fade-from-bleeding-into-CloudBannerSection-on-downloa-3576d73d3650813d8924fb54d5f78cee)
by [Unito](https://www.unito.io)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-05 18:06:10 +00:00
Yourz
6474faaa17 fix(website): prevent illustration cutoff in enterprise hero section (#11973)
*PR Created by the Glary-Bot Agent*

---

## Summary

The illustration in the `HeroSection` of `/cloud/enterprise` was getting
cut off at the top — the topmost ripple ring was clipped by the
section's `overflow-y-clip`/`overflow-hidden`.

**Root cause:** the SVG wrapper has `scale-150`, which makes the
rendered illustration 50% larger than its layout box and overflows
symmetrically (~25% above, ~25% below). The section only had
`lg:pb-[min(8vw,10rem)]` — bottom padding — and on lg the wrapper had
`lg:translate-y-[40px]` to nudge it down, but that wasn't enough room
for the top to escape clipping. On mobile there was no padding at all,
so the same issue occurred.

**Fix:** add symmetric vertical padding (`pt-16` on mobile,
`lg:pt-[min(8vw,10rem)]` mirroring the existing bottom value on lg) so
the scaled illustration has room above and below. Removed the
now-unnecessary `lg:translate-y-[40px]` since symmetric padding keeps
the illustration vertically centered within the flex row.

Verified at 375px (mobile), 1024px (lg), and 1440px (xl) viewports — all
four ripple rings render fully without clipping at the top.

## Verification

- `pnpm typecheck:website` 
- `pnpm exec oxfmt --check` on edited file 
- `pnpm exec oxlint` on edited file 
- `pnpm --filter @comfyorg/website build` 
- Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck,
typecheck:website) 
- Visual verification with Playwright at mobile / lg / xl

## Before vs After

**Desktop (1440px) — before:** the topmost ripple ring is clipped at the
top of the section.
**Desktop (1440px) — after:** all four ripple rings are fully visible.

**Mobile (375px) — before:** the top of the outermost ring is cut off by
the section's top edge.
**Mobile (375px) — after:** the full illustration (rings + blocks) is
visible.

## Screenshots

![Before: 1440px viewport — top ripple rings clipped at the section's
top
edge](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/69533c93dc49c06a54e467a56e2fd862864e928779a183f7e07881a177bbbf72/pr-images/1777993734642-2fe8d55a-bfba-4715-909e-96310dfebbfb.png)

![After: 1440px viewport — all four ripple rings fully
visible](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/69533c93dc49c06a54e467a56e2fd862864e928779a183f7e07881a177bbbf72/pr-images/1777993735034-59b1694b-d478-4219-8b3a-76a6e784229e.png)

![Before: 375px mobile viewport — outermost ring cut off at the
top](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/69533c93dc49c06a54e467a56e2fd862864e928779a183f7e07881a177bbbf72/pr-images/1777993735430-5c33c79f-66a4-433f-9558-aaeaaea8fcab.png)

![After: 375px mobile viewport — full illustration
visible](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/69533c93dc49c06a54e467a56e2fd862864e928779a183f7e07881a177bbbf72/pr-images/1777993735799-bd72ec20-bc5d-43d3-846d-cc793cabf29e.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11973-fix-website-prevent-illustration-cutoff-in-enterprise-hero-section-3576d73d3650813f9f04c3f93b9b42d6)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-05 18:04:34 +00:00
pythongosssss
da6a3e0722 test: add tests for dragging workflow tabs (#11971)
## Summary

Adds tests for drag to reorder workflow tabs

## Changes

- **What**: 
- test drag start/end, ensure active tab is maintained

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11971-test-add-tests-for-dragging-workflow-tabs-3576d73d365081d090fccfc8804fa6aa)
by [Unito](https://www.unito.io)
2026-05-05 18:02:55 +00:00
Yourz
eecbaa8f39 fix(website): change 'Blogs' to 'Blog' in Resources nav dropdown (#11970)
*PR Created by the Glary-Bot Agent*

---

## Summary

Corrects the "Blogs" label to "Blog" (singular) in the website header's
Resources dropdown menu, as requested in #website-and-docs Slack
channel.

## Changes

- `apps/website/src/i18n/translations.ts`: `nav.blogs` English value
`Blogs` → `Blog` (zh-CN translation `博客` left unchanged since it was
already correct)

This also makes the header consistent with the footer, which already
labeled the same link as "Blog".

## Verification

- `pnpm typecheck` (astro check): 0 errors, 0 warnings, 0 hints (87
files)
- `pnpm test:unit`: 30 tests passed across 4 files
- `pnpm exec eslint apps/website/src/i18n/translations.ts`: clean
- Manual verification via Playwright on `pnpm dev` — Resources dropdown
now displays "Blog"
- Code review (oracle): 0 issues found

## Screenshot

Resources dropdown after the change:

## Screenshots

![Resources dropdown in site header showing 'Blog'
(singular)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/65e8a452a2ef553db097f1a5b55a024084f75cfc77f4f18359fcf73f31e264f8/pr-images/1777991675069-e9e180b3-54e5-48d3-8365-3abafa09df27.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11970-fix-website-change-Blogs-to-Blog-in-Resources-nav-dropdown-3576d73d365081638245d235bec04230)
by [Unito](https://www.unito.io)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-05 17:55:48 +00:00
Marwan Ahmed
0e110bec0d fix(i18n): rename OpenAI GPT Image 1 to GPT Image 2 across locales (#11968)
## Summary

Aligns the `OpenAIGPTImage1` node display name in all 11 non-English
`nodeDefs.json` locale files with the English source-of-truth, which was
already updated to `OpenAI GPT Image 2`.

## Changes

- **What**: Updates `display_name`, the description string, and the
prompt tooltip in `ja`, `ru`, `zh`, `zh-TW`, `ar`, `pt-BR`, `ko`, `fr`,
`es`, `fa`, and `tr` locales from `GPT Image 1` to `GPT Image 2` (and
`GPT Görüntü 1` → `GPT Görüntü 2` in Turkish, `GPT صورة 1` → `GPT صورة
2` in Arabic). Other tooltips already referenced `GPT Image 2` and are
unchanged.
- **Breaking**: None — the registry node id `OpenAIGPTImage1` is
preserved (it is an internal identifier, not user-facing).

## Review Focus

- Translations were updated mechanically — please confirm the
version-number change is acceptable as-is for non-Latin scripts (Arabic,
Persian, Korean, Japanese, Chinese) where the version number was kept as
`2` per the existing pattern.
- The English locale already used `OpenAI GPT Image 2`, so this PR
brings the other locales into sync; no English copy was changed.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11968-fix-i18n-rename-OpenAI-GPT-Image-1-to-GPT-Image-2-across-locales-3576d73d365081bfa204cbf528d84bf3)
by [Unito](https://www.unito.io)

Co-authored-by: Marwan Ahmed <marwan@Marwans-MacBook-Pro.local>
2026-05-05 17:54:25 +00:00
Alexander Brown
32984459bf ci: exclude release branches from website previews (#11952)
## Summary

Exclude core and cloud minor release branches from Vercel website
preview deployments.

## Changes

- **What**: Added `pull_request.branches-ignore` entries for `core/*`
and `cloud/*` to the Vercel Website Preview workflow.

## Review Focus

Confirm the branch exclusion patterns match the minor release branch
naming convention.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11952-ci-exclude-release-branches-from-website-previews-3576d73d36508194b835eda9bc12f174)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-05-05 17:20:33 +00:00
jaeone94
0307281ff2 fix: highlight missing input slots on Vue nodes (#11950)
## Summary

Restores required-input validation highlighting on Vue node input slots.

## Changes

- **What**: Passes validation error state from `NodeSlots` to
`InputSlot` using node locator IDs, including subgraph and nested
subgraph execution IDs.
- **What**: Adds unit coverage for root, one-level subgraph, and nested
subgraph slot error mapping.
- **What**: Adds a Vue Nodes screenshot regression test that asserts the
missing required input slot itself receives the error highlight.
- **Dependencies**: None.

## Review Focus

- Required input errors on Vue-rendered node's slots.
- The new Playwright screenshot expectation will need the `New Browser
Test Expectation` label for Linux baseline generation.

## Screenshots (if applicable)
Before

<img width="499" height="324" alt="스크린샷 2026-05-05 오후 3 00 44"
src="https://github.com/user-attachments/assets/285fdf91-6d7e-480b-99b9-715705f78914"
/>

After 

<img width="482" height="356" alt="스크린샷 2026-05-05 오후 3 01 11"
src="https://github.com/user-attachments/assets/51b8db49-eb9c-4155-8aa5-109c0bd7699b"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11950-fix-highlight-missing-input-slots-on-Vue-nodes-3576d73d365081bd85bfd1ea149d45c5)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-05-05 14:10:35 +00:00
jaeone94
21406dceb1 fix: skip nested subgraph containers in replay scan (#11908)
## Summary

Fixes the Cloud-only nested subgraph missing-model false positive
covered by the stacked regression test in #11907.

When returning from an outer subgraph to the root graph, the Vue graph
node manager replays `onNodeAdded` for existing graph nodes. The
realtime error-clearing hook handled a subgraph container by recursively
scanning all interior nodes. For nested subgraphs, that also scanned the
nested subgraph container itself.

Nested subgraph container widgets are promoted synthetic views of
interior widgets. Scanning them as real model-loader nodes is wrong: the
container node type is the subgraph UUID, not `UNETLoader`, so Cloud
asset resolution can classify an installed promoted model as missing.

## Changes

- Skip nested subgraph container nodes during parent subgraph replay
scans.
- Keep scanning real active interior leaf nodes.
- Add unit coverage proving the replay scan visits the `UNETLoader` leaf
but not the nested subgraph container.
- Remove the `test.fail()` annotation from the Cloud E2E regression test
added in #11907.

## Stacked PR

This PR is stacked on #11907. After #11907 lands, this branch should be
rebased or retargeted onto `main`.

## Verification

- `pnpm exec vitest run
src/composables/graph/useErrorClearingHooks.test.ts -t "skips nested
subgraph containers during parent subgraph replay scan"`
- `pnpm exec oxfmt --check
src/composables/graph/useErrorClearingHooks.ts
src/composables/graph/useErrorClearingHooks.test.ts
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts`
- `pnpm exec eslint src/composables/graph/useErrorClearingHooks.ts
src/composables/graph/useErrorClearingHooks.test.ts
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts`
- `pnpm exec oxlint src/composables/graph/useErrorClearingHooks.ts
src/composables/graph/useErrorClearingHooks.test.ts
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts
--type-aware`
- `pnpm typecheck`
- `pnpm typecheck:browser`
- `pnpm build:cloud`
- `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 pnpm
exec playwright test
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts
--project=cloud`
- commit hook: `pnpm typecheck`, `pnpm typecheck:browser`
- push hook: `pnpm knip`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11908-fix-skip-nested-subgraph-containers-in-replay-scan-3566d73d3650819c8687d6ab74add1b9)
by [Unito](https://www.unito.io)
2026-05-05 21:05:54 +09:00
jaeone94
14320a131f test: add Playwright regression test for nested subgraph Cloud missing model (#11907)
## Summary

Adds a Cloud Playwright regression test for the nested subgraph case
where an installed Lotus diffusion model is incorrectly surfaced as
missing after returning to the root graph.

The fixture keeps the reproduction small: root graph -> subgraph node ->
nested subgraph node -> `UNETLoader` using
`lotus-depth-d-v1-1.safetensors`. The test stubs `/api/assets` through
the shared asset API fixture so that model is explicitly present as a
`diffusion_models` asset.

This test is intentionally written as an XFAIL regression guard. Its
setup and precondition checks are outside the XFAIL section: initial
workflow load must not show the error overlay, the Errors tab must
initially stay hidden, subgraph entry must succeed, root return must
succeed, and the replay scan must run. Only the final `Errors` tab
visibility assertion is expected to fail on current Cloud behavior.

## What a green run means

A green CI run for this PR means the Cloud-only bug was reproduced at
the intended point. The test reaches the root-return replay scan,
verifies that the replay scan ran, and then current Cloud behavior makes
the Errors tab visible even though the Lotus model exists in
`/api/assets`.

If any earlier setup or navigation step fails, or if the root-return
replay scan does not run, the test fails normally because those checks
happen before `test.fail()` is applied.

Locally, removing `test.fail()` produces the expected red result after
the replay-scan precondition passes, with `panel-tab-errors` visible.

The intended post-fix contract is that the replay scan still runs, but
the Errors tab remains hidden.

## Why this is XFAIL

This PR intentionally ships only the regression test, not the production
fix. The final behavioral assertion is annotated with `test.fail()`
because the current Cloud replay path still treats the nested subgraph
promoted model widget as missing.

When the follow-up fix lands, Playwright will report this test as an
unexpected pass until the `test.fail()` annotation is removed. That is
the handoff point for converting this regression guard into a normal
passing E2E test.

## Follow-up

The stacked fix PR is #11908. It updates the replay scan so nested
subgraph container nodes are skipped, then removes the `test.fail()`
annotation from this test.

## Verification

- `pnpm exec oxfmt --check browser_tests/fixtures/assetApiFixture.ts
browser_tests/tests/cloud-asset-default.spec.ts
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts`
- `pnpm exec oxlint browser_tests/fixtures/assetApiFixture.ts
browser_tests/tests/cloud-asset-default.spec.ts
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts
--type-aware`
- `pnpm exec eslint browser_tests/fixtures/assetApiFixture.ts
browser_tests/tests/cloud-asset-default.spec.ts
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts`
- `pnpm typecheck:browser`
- `pnpm typecheck`
- `pnpm lint`
- `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 pnpm
exec playwright test
browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts
browser_tests/tests/cloud-asset-default.spec.ts --project=cloud`
- Temporarily removed `test.fail()` locally and verified the test fails
only after the replay-scan precondition passes, with `panel-tab-errors`
visible

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11907-test-add-Playwright-regression-test-for-nested-subgraph-Cloud-missing-model-3566d73d3650810b86d4de916c2852f9)
by [Unito](https://www.unito.io)
2026-05-05 11:17:30 +00:00
Christian Byrne
a763c7132c feat(website): add "comfyui app" SEO keywords to product pages (#11834)
*PR Created by the Glary-Bot Agent*

---

## Summary

Adds "comfyui app" / "comfyui web app" / "comfy ui application" keywords
to the titles and meta descriptions of the home, download, and Comfy
Cloud pages (and zh-CN equivalents) to recover organic traffic for those
queries.

## Context

Organic traffic for the query **"comfyui app"** dropped after
`https://docs.comfy.org/interface/app-mode` started outranking the
product/landing pages. The docs page about app-mode converts worse than
the product pages, so we want Google to prefer comfy.org product pages
for that query. The cleanest, lowest-risk lever is on-page SEO metadata.

## Changes

- **What**:
- `apps/website/src/pages/index.astro` → title `ComfyUI App —
Professional Control of Visual AI` + product-focused description.
- `apps/website/src/pages/download.astro` → title `Download the ComfyUI
App — Run Visual AI Locally` + desktop-app description.
- `apps/website/src/pages/cloud/index.astro` → title `Comfy Cloud — The
ComfyUI Web App` + web-app description.
- `apps/website/src/pages/zh-CN/{index,download,cloud/index}.astro` →
localised Chinese titles and descriptions so the zh-CN product pages no
longer fall back to the English `BaseLayout` default.
- `apps/website/src/layouts/BaseLayout.astro` → unchanged net-net
(touched then reverted to neutral copy after review feedback so
non-product / non-localised pages keep their existing, generic
fallback).
- **Breaking**: none. Visual content, routing, and components are
untouched — only `<title>` and `<meta>` tags change.

## Review Focus

- The keyword copy reads naturally (no stuffing) and stays under typical
SERP truncation limits (≤ ~165 chars).
- zh-CN pages get Chinese descriptions — they intentionally don't repeat
the English keywords, since "comfyui app" is an English-language query.
- Pre-existing behaviour preserved: zh-CN pages **without** an explicit
description still inherit the English `BaseLayout` default. Fixing that
fallback for the whole zh-CN tree is out of scope for this PR — happy to
follow up if desired.

## Verification

- `pnpm typecheck` — 0 errors
- `pnpm build` — 39 pages built clean
- `pnpm test:unit` — 23/23 pass
- `pnpm format:check apps/website/src` — clean
- Manually verified rendered `<title>` and `<meta name="description">`
via Playwright on `/`, `/download`, `/cloud`, and the zh-CN equivalents.

## Screenshots

Home page rendered with the new title (visible in browser tab / SERP
preview); visual content unchanged.

## Screenshots

![Home page rendered after SEO meta changes — visual content
unchanged](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/727d10d9c63b96b716a8b45e3e96a50b2d78a4282567880f9e3c2becd80ac988/pr-images/1777704618466-41280e96-bd96-4668-8dbb-afa8e3601838.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11834-feat-website-add-comfyui-app-SEO-keywords-to-product-pages-3546d73d3650819da11bd665c2fcfb88)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-05 11:05:52 +00:00
Benjamin Lu
3f223dbbb4 test: add jobs api browser mock fixture (#11280)
## Summary

Add a typed Playwright jobs API mock and migrate the floating queue
overlay browser spec onto it.

## Changes

- replace the backend/seed terminology with `JobsApiMock`,
`jobsApiMockFixture`, `mockJobs()`, and `MockJobRecord`
- keep the mock at the network boundary with `page.route()` for
`/api/jobs`, `/api/jobs/{id}`, and `/api/history`
- remove backend-like query behavior that these browser tests do not
use, including sort handling, workflow filtering, and strict limit
validation

## Why

This keeps jobs coverage fast and profile-independent while avoiding
backend architecture changes for test setup. The fixture now serves only
the response shapes the UI consumes instead of pretending to be a
general in-memory backend.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11280-test-add-in-memory-jobs-backend-fixture-3436d73d365081bb87e8c9771654496c)
by [Unito](https://www.unito.io)
2026-05-05 03:54:41 -07:00
Christian Byrne
60f789d580 test: add OutputHistory.vue component tests (#11140)
## Summary

Add 29 Vitest component tests for `OutputHistory.vue`, which previously
had 0% coverage (132 missed lines).

## Changes

- **What**: New test file
`src/renderer/extensions/linearMode/OutputHistory.test.ts` covering
rendering, selection behavior, emit updateSelection, workflow tab
switch, media change watcher, and keyboard navigation.

## Review Focus

- Mock setup for stores (`linearOutputStore`, `workflowStore`,
`appModeStore`, `queueStore`) and composables (`useOutputHistory`)
- Keyboard navigation tests dispatching events on `document.body`
- Selection emission tests verifying `updateSelection` event payloads

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11140-test-add-OutputHistory-vue-component-tests-33e6d73d3650811692cdc36fdd41e9ba)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
2026-05-05 03:41:07 -07:00
Yourz
24fc11aa3e fix(website): remove placeholder author info for groove-jones customer story (#11937)
*PR Created by the Glary-Bot Agent*

---

Removes the placeholder "GROOVE JONES CONTRIBUTORS" author card from the
Groove Jones customer story (`/customers/groove-jones`). The card was
rendering with `TBD` / `待补充` values for the contributor name and role.

## Change

Deletes 3 i18n keys from `apps/website/src/i18n/translations.ts`:

- `customers.detail.groove-jones.topic-10.block.2.label`
- `customers.detail.groove-jones.topic-10.block.2.name`
- `customers.detail.groove-jones.topic-10.block.2.role`

Block types in `ContentSection.vue` are inferred from the presence of
suffix keys (`.role` → `author` block) via `deriveSections` in
`apps/website/src/config/contentSections.ts`. Removing the keys causes
the author card to drop out of the rendered output entirely. The other
two blocks in topic-10 (intro paragraph + Dale Carman blockquote) remain
unchanged.

## Verification

- `pnpm typecheck` — passes
- `pnpm lint` — 0 errors (1 pre-existing warning, unrelated)
- `pnpm format` — applied
- `pnpm knip` — clean (1 pre-existing warning, unrelated)
- Manual: ran `pnpm dev` for the website app, navigated to
`/customers/groove-jones`, confirmed the conclusion section ends
naturally — no `TBD` text, no orphan `CONTRIBUTORS` label, no broken
card.

Code review (Oracle): 0 critical / 0 warning / 0 suggestion.

## Screenshots

![Conclusion section of the Groove Jones customer story — ends with the
Dale Carman blockquote, no contributor card, no TBD
placeholders](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/97021278678b2d01e3b2a67eed39f0499d7de31ad48cc414e95caca876eb37d9/pr-images/1777939400797-d8b627c0-a52c-42ab-990f-f7d36ab8ef66.jpg)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11937-fix-website-remove-placeholder-author-info-for-groove-jones-customer-story-3576d73d36508193b1a0c0c3cd887686)
by [Unito](https://www.unito.io)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-05 09:48:12 +00:00
Yourz
055486cac0 feat(website): add 4 team photos and remove infinite scroll loop (#11945)
## Summary

Add 4 new team photos and remove the infinite scroll behavior from the
careers page team photos carousel.

## Changes

- **What**:
  - Add 4 new photos (team4–team7) to `TeamPhotosSection.vue`
- Remove the infinite scroll loop (`loopedPhotos`, `onScroll` handler,
`onMounted` scroll initializer)

<img width="1000" height="308" alt="Kapture 2026-05-05 at 11 02 16"
src="https://github.com/user-attachments/assets/f5f6737f-c6bf-4abf-8780-d72c895f4015"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11945-feat-website-add-4-team-photos-and-remove-infinite-scroll-loop-3576d73d365081cabebecbc06666b9d9)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-05-05 09:47:37 +00:00
Benjamin Lu
f6ddd26cef fix: use resized QPO thumbnails (#11946)
## Summary

Use resized preview URLs for floating QPO row thumbnails so the expanded
overlay does not load full-size image assets while the canvas is being
navigated.

Linear: FE-538

## Changes

- **What**: Pass `ResultItemImpl.previewUrl` into `AssetsListItem` for
completed image/video job rows.
- **Dependencies**: None.

## Review Focus

Confirm this only changes the row thumbnail source; full asset viewing
still flows through the existing job/task preview output.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11946-fix-use-resized-QPO-thumbnails-3576d73d365081b68682d1b7b109af30)
by [Unito](https://www.unito.io)
2026-05-05 08:58:25 +00:00
pythongosssss
6822a6883d test: add tests for layout settings (#11692)
## Summary

Adds tests for UI layout settings

## Changes

- **What**: 
- add initialFeatureFlags to allow setting feature flags before initial
setup to prevent needing to reload page
- tests sidebar + topbar settings

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11692-test-add-tests-for-layout-settings-34f6d73d36508117b1daedbb68176e04)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-05-05 08:47:07 +00:00
Benjamin Lu
3637b61fcd Use Reka popover for queue job details (#11540)
## Summary
Use ShadCN-style Reka popover primitives for the live queue job list
after the unused legacy queue row implementation is removed in #11621.
This is the first step in migrating popovers toward the ShadCN UI
pattern: local design-system wrappers over Reka UI, rather than ad hoc
direct Reka or PrimeVue popovers at each call site.

## Changes
- **What**: Added the minimal ShadCN-style popover primitives needed by
this fix: `Popover`, `PopoverAnchor`, and `PopoverContent`.
- **What**: Migrated `JobAssetsList` job details from manual fixed
positioning to these popover primitives with viewport collision
handling.
- **What**: Removed the obsolete manual hover-position helper after
`JobAssetsList` stopped using it.
- **Dependencies**: No new dependencies; the primitives wrap the
existing `reka-ui` package.
- Added browser coverage for bottom-row job details clipping in the
queue overlay.

## Review Focus
- This PR is stacked on #11621.
- The live queue surfaces are `JobAssetsList` consumers: expanded queue
progress overlay and job history sidebar.
- The new `src/components/ui/popover` files intentionally seed the
ShadCN-style migration path, but only include the pieces used here to
keep the first PR small.
- Follow-up PRs can add `PopoverTrigger` and migrate existing
PrimeVue/direct-Reka popovers once there is an actual caller.
2026-05-05 01:49:12 -07:00
Christian Byrne
d1df5fadf8 fix(website): update payment-failed heading to "Unable to complete payment" (#11943)
*PR Created by the Glary-Bot Agent*

---

## Summary

Reword the `payment.failed.title` copy on `comfy.org/payment/failed`
from "Payment was not completed" to "Unable to complete payment" — a
more active, distinguishing phrasing per design feedback.

## Changes

- `apps/website/src/i18n/translations.ts` — update English (`Unable to
complete payment`) and Chinese (`无法完成支付`) translations
- `apps/website/e2e/payment.spec.ts` — update both English and zh-CN
heading assertions to match

## Verification

- `pnpm --filter website typecheck` — passes
- `pnpm --filter website test:unit` — 30 tests passing
- Pre-commit hooks (oxfmt, oxlint, eslint, typecheck, typecheck:website)
— all pass
- Manual visual verification with Playwright on `/payment/failed` and
`/zh-CN/payment/failed` — both render the new heading correctly
(screenshots attached)

## Screenshots

![English /payment/failed page showing 'Unable to complete payment'
heading](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/704ef878d4d0c345146cd20fece87d6edf7e1cd0bbe5094daad0f00b414035fe/pr-images/1777946058984-deb77e19-c7ce-4c25-a004-c8425856145e.png)

![Chinese /zh-CN/payment/failed page showing the new
heading](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/704ef878d4d0c345146cd20fece87d6edf7e1cd0bbe5094daad0f00b414035fe/pr-images/1777946059339-c50ac07c-d4ed-46af-992b-0c56ac469c23.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11943-fix-website-update-payment-failed-heading-to-Unable-to-complete-payment-3576d73d3650817e85e2e7a3891cc307)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-05 08:30:12 +00:00
Christian Byrne
7d67fe364b [chore] Update Comfy Registry API types from comfy-api@274f83b (#11948)
## Automated API Type Update

This PR updates the Comfy Registry API types from the latest comfy-api
OpenAPI specification.

- API commit: 274f83b
- Generated on: 2026-05-05T04:14:20Z

These types are automatically generated using openapi-typescript.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11948-chore-Update-Comfy-Registry-API-types-from-comfy-api-274f83b-3576d73d3650813b9a39f8d0f7183445)
by [Unito](https://www.unito.io)

Co-authored-by: coderfromthenorth93 <213232275+coderfromthenorth93@users.noreply.github.com>
2026-05-05 08:03:32 +00:00
Comfy Org PR Bot
7c2321cc23 1.44.17 (#11938)
Patch version increment to 1.44.17

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11938-1-44-17-3576d73d365081e89010e68cbf1c2625)
by [Unito](https://www.unito.io)

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
v1.44.17
2026-05-05 07:56:34 +00:00
Kelly Yang
a877ccde94 Test/edit attention unit tests (#11301)
## Summary

A follow-up PR of
https://github.com/Comfy-Org/ComfyUI_frontend/issues/11107.


## Changes

Add unit test to `editAttention.ts` 
- [x] `Extract pure functions to module level`: **Moved**
`incrementWeight`, `findNearestEnclosure`, and `addWeightToParentheses`
out of the `init()` closure and **promoted** them to module-level
functions with `export` to allow for independent testing.
- [x] `Add unit tests for incrementWeight`: **Added** 6 tests covering
edge cases such as normal increment/decrement, NaN input, negative
weights, and floating-point precision.
- [x] `Add unit tests for findNearestEnclosure`: **Added** 7 tests
covering edge cases including simple brackets, no brackets, cursor
outside, nested brackets (inner/outer), empty strings, and missing
closing brackets.
- [x] `Add unit tests for addWeightToParentheses`: **Added** 6 tests
covering scenarios like adding a default 1.0 weight, retaining existing
weights, no changes when brackets are absent, scientific notation
weights, negative weights, and multi-word tokens.
- [x] `Mock app module`: **Used** `vi.mock('@/scripts/app')` to
intercept side effects from `app.registerExtension`, **preventing** the
triggering of ComfyUI extension registration logic during module import.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adjusts token selection/weight-detection logic used during
Ctrl/Cmd+Arrow editing, which could subtly change how prompts are
rewritten in edge cases (nested parens, scientific notation, time-like
text). Adds tests that should reduce regression risk but behavior
changes still warrant verification in the UI.
> 
> **Overview**
> Adds a new `vitest` unit test suite for `editAttention` by mocking
`app.registerExtension` side effects and validating `incrementWeight`,
`findNearestEnclosure`, and `addWeightToParentheses` across common and
edge cases.
> 
> Refactors those helpers to exported module-level functions and
tightens parsing/selection behavior: `findNearestEnclosure` now handles
the cursor being on an opening `(`, `addWeightToParentheses` improves
trailing weight detection (supports scientific notation/negatives and
avoids misclassifying time-like `12:30`), and the weight-rewrite regex
now matches exponent forms.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
df20340b49. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->



┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11301-Test-edit-attention-unit-tests-3446d73d365081f29e8dfceefc06f5d3)
by [Unito](https://www.unito.io)
2026-05-05 06:48:26 +00:00
Dante
e3883f4a2c test: add unit tests for layoutStore setter and query paths (#11747)
## Summary

Adds 11 tests for \`src/renderer/core/layout/store/layoutStore.ts\`
covering paths previously uncovered by the existing 17-test suite.
Targets the customRef setter machinery, reactive queries, and
link-layout updates that are reachable through the public API.

## Test Coverage

\`getNodeLayoutRef\` setter:
- Setter on a fresh ref triggers \`createNode\`.
- Position-only change triggers \`moveNode\`.
- Size-only change triggers \`resizeNode\`.
- zIndex-only change triggers \`setNodeZIndex\`.
- Setting to \`null\` triggers \`deleteNode\`.

Queries:
- \`getNodesInBounds\` returns reactive node IDs intersecting the
bounds.
- \`queryNodeAtPoint\` returns the top-zIndex node containing the point.
- \`queryNodeAtPoint\` returns \`null\` when no node contains the point.

Link layouts:
- \`updateLinkLayout\` short-circuits when bounds and centerPos
unchanged but still updates the path.
- \`updateLinkLayout\` replaces stored layout when bounds change.
- \`deleteLinkLayout\` removes the link and its segment layouts.

## Testing

\`\`\`bash
pnpm vitest run src/renderer/core/layout/store/layoutStore.test.ts
\`\`\`

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11747-test-add-unit-tests-for-layoutStore-setter-and-query-paths-3516d73d365081d9bc1de336ff7258ea)
by [Unito](https://www.unito.io)
2026-05-05 05:03:20 +00:00
Kelly Yang
5e16802832 refactor: remove @ts-expect-error suppressions in CustomizationDialog (#11339)
… (issue #11092 phase 4b)

## Summary

Part of #11092 — Phase 4b: remove 2 `@ts-expect-error` suppressions from
`CustomizationDialog.vue`.

## Changes

`selectedIcon` ref initialisation and `resetCustomization` assignment
both suppressed a type error on `Array.find()` returning `T |
undefined`.

**Why**

`Array.find()` has no way to statically guarantee a match, so its return
type is always `T | undefined`. Both usages were searching `iconOptions`
— a literal array of 8 entries declared in the same scope — and
TypeScript could not prove that the searched value would always be
found, even though at runtime it always is (the default icon value is
defined from `iconOptions[0]`).

**How**

Added `iconOptions[0]` as a final fallback via `??` in both places.
Because `iconOptions` is a non-empty literal array, `iconOptions[0]` is
provably non-null to TypeScript, which makes the overall expression type
`T` and satisfies the assignment. The explicit generic on `ref<{ name:
string; value: string }>` was also dropped — TypeScript infers the type
correctly from the non-nullable initialiser. In `resetCustomization`,
`||` was replaced with `??` since the values being null-coalesced are
objects (never falsy), making `??` the semantically precise operator for
this case.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: UI-only refactor that adds explicit fallbacks for
`Array.find()` results and introduces a small unit test suite; behavior
should remain the same except for safer handling of unexpected icon
values.
> 
> **Overview**
> Removes two `@ts-expect-error` suppressions in
`CustomizationDialog.vue` by making `selectedIcon` initialization and
`resetCustomization` use a guaranteed fallback (`iconOptions[0]`) via
`??`, ensuring the selected icon is never `undefined`.
> 
> Adds `CustomizationDialog.test.ts` to verify `confirm` emits the
expected icon/color for default, provided initial values, and an invalid
`initialIcon` fallback.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f77addf713. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11339-refactor-remove-ts-expect-error-suppressions-in-CustomizationDialog-3456d73d36508165865ac569e047db2e)
by [Unito](https://www.unito.io)
2026-05-04 21:41:09 -04:00
Kelly Yang
0e9a5ecbe9 refactor: extract GPU lifecycle into useGPUResources (phase D) (#11784)
## Summary
Phase D of the **useBrushDrawing-refactor plan.md**. Extract `WebGPU`
state management from `useBrushDrawing` into a dedicated
`useGPUResources` composable, reducing `useBrushDrawing` from ~1,160
lines to ~230. This is Phase D of the ongoing `useBrushDrawing`
decomposition (Phases A–C landed in previous PRs).
   
## Changes
- **What**: Split `useBrushDrawing` along a clean boundary — GPU
device/texture lifecycle moves to `useGPUResources`, stroke
orchestration stays in `useBrushDrawing`. Shared reactive state
(`dirtyRect`, `isSavingHistory`, `previewCanvas`) is now owned by
`useGPUResources` and exposed as refs. A pure
   `clampDirtyRect` helper is extracted to `gpuUtils.ts`.
- **Dependencies**: No new dependencies
## Tests
Local test - pass            


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Refactors WebGPU initialization, texture management, and readback
paths used during drawing; regressions could affect stroke rendering,
canvas visibility, and undo/redo GPU sync.
> 
> **Overview**
> Extracts WebGPU device/texture/renderer lifecycle, watchers (clear,
undo/redo sync, texture recreation), and readback logic out of
`useBrushDrawing` into a new `useGPUResources` composable, with shared
refs (`dirtyRect`, `isSavingHistory`, `previewCanvas`, `hasRenderer`)
now owned by that module.
> 
> Updates `useBrushDrawing` to delegate GPU-specific operations
(prepare/render/draw point/composite/readback/cleanup) to
`useGPUResources` while keeping CPU drawing + stroke orchestration, and
adds new pure helpers in `gpuUtils` (`clampDirtyRect`,
`buildStrokePoints`) to centralize dirty-rect clamping and stroke point
resampling.
> 
> Adds Vitest coverage for the new helpers, `useGPUResources`
no-op/error behavior when GPU isn’t available, and `useBrushDrawing`
interactions with the extracted GPU API (composition mode selection,
shift-line, history save, and canvas/preview opacity restoration).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
a9fcd80ab5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->



┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11784-refactor-extract-GPU-lifecycle-into-useGPUResources-phase-D-3526d73d365081108a97c164a0bfa13e)
by [Unito](https://www.unito.io)
2026-05-04 20:49:10 -04:00
Dante
9013102db9 fix: use capitalize for keybinding badges (#11810)
## Summary

Render keybinding badges in sentence case (`Ctrl + Shift + A`) instead
of UPPERCASE (`CTRL + SHIFT + A`) by swapping the `uppercase` Tailwind
class for `capitalize` in `KeyComboDisplay.vue`.

`KeyComboImpl.getKeySequences()` already returns labels in their
canonical form (`Ctrl`, `Alt`, `Shift`, plus the raw key). The badge
styling was forcing them all to UPPER, which is what FE-524 calls out.
`text-transform: capitalize` cleanly handles every case: lower modifier,
upper modifier, and single character keys.

- Fixes FE-524

## Before / After

| Before (`uppercase`) | After (`capitalize`) |
| --- | --- |
| <img
src="https://raw.githubusercontent.com/Comfy-Org/ComfyUI_frontend/c6bb96fce/docs/screenshots/fe-524/before.png"
width="480"> | <img
src="https://raw.githubusercontent.com/Comfy-Org/ComfyUI_frontend/c6bb96fce/docs/screenshots/fe-524/after.png"
width="480"> |

## Test plan

- [ ] Open Settings → Keybinding panel and confirm modifier badges
render as `Ctrl`, `Alt`, `Shift` instead of `CTRL`, `ALT`, `SHIFT`
- [ ] Confirm single-letter keys (e.g. `A`, `S`) still render uppercase
- [ ] Edit a keybinding and verify the live preview badges in the dialog
also render in sentence case
2026-05-04 20:38:31 -04:00
Christian Byrne
6ea5a5e32d fix(load3d): preserve unknown Model Config fields with spread (#11838)
## Summary

Use spread pattern when writing `nodeValue.properties['Model Config']`
so future ModelConfig fields are preserved across viewer dialog
cancel/apply.

## Changes

- **What**: Spread existing `Model Config` before applying known keys in
both `restoreInitialState()` and `applyChanges()` in
[useLoad3dViewer.ts](src/composables/useLoad3dViewer.ts). Removes the
hard-coded `showSkeleton: false` override from `applyChanges()` so it
falls through from the existing config.

## Review Focus

The change is intentionally minimal and matches the suggestion in the
upstream issue. Two regression tests added (one each for restore/apply)
verify that an unknown future field on Model Config survives both code
paths.

Fixes #11346

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11838-fix-load3d-preserve-unknown-Model-Config-fields-with-spread-3546d73d3650819686efc4e1a9799ad9)
by [Unito](https://www.unito.io)
2026-05-04 20:32:57 -04:00
Alexander Brown
90b3d8a5c6 test: add mask editor brush adjustment and layer management browser tests (#11368)
*PR Created by the Glary-Bot Agent*

---

## Summary

Adds `browser_tests/tests/maskEditorBrushLayers.spec.ts` covering
untested brush settings interaction and tool/layer management in the
mask editor.

### Coverage gaps filled
- `useBrushDrawing.ts` — brush thickness/opacity/hardness slider
interaction
- `useToolManager.ts` — tool switching with independent mask data, data
preservation across tool switches

### Test cases (5 tests, 2 groups)
| Group | Tests | Behavior |
|---|---|---|
| Brush settings | 3 | Thickness slider changes size, opacity slider
changes opacity, hardness slider changes hardness |
| Layer management | 2 | Different tools produce independent mask data,
switching tools preserves previous mask data |

### References
- Reuses patterns from existing `maskEditor.spec.ts` (`loadImageOnNode`,
`openMaskEditorDialog`, `drawStrokeOnPointerZone`,
`getMaskCanvasPixelData`)
- Follows `browser_tests/AGENTS.md` directory structure
- Follows `browser_tests/FLAKE_PREVENTION_RULES.md` assertion patterns

### Verification
- TypeScript: clean
- ESLint: clean
- oxlint: clean
- oxfmt: formatted

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11368-test-add-mask-editor-brush-adjustment-and-layer-management-browser-tests-3466d73d36508170ae24ebea2b73d60d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-05-04 20:31:15 -04:00
Christian Byrne
551cf21fb1 fix(load3d): reapply up-direction after fitToViewer() transform reset (#11826)
## Summary

`fitToViewer()` in `SceneModelManager` resets the model rotation to
`(0,0,0)` as part of its normalize-and-scale flow, but does not reapply
`currentUpDirection` afterward. This causes a state/view mismatch when
the user has previously selected a non-default up-axis (e.g. `+x`,
`-z`): the model snaps back to its raw orientation while the Up
Direction control still shows the previously selected value.

## Changes

- In `fitToViewer()`, clear `originalRotation` (to avoid compounding
with the stale pre-fit base) then reapply `currentUpDirection` if it is
not `'original'`
- Add 5 unit tests covering: no-op when no model, reapplication of
direction, no rotation compounding on repeated calls, zero rotation for
`'original'` direction, and stale `originalRotation` guard

## Testing

### Automated

- `src/extensions/core/load3d/SceneModelManager.test.ts` — 5 new tests
in `describe('fitToViewer')`
- All 48 unit tests pass

### E2E Verification Steps

1. Open the Load3D viewer with any 3D model
2. Change **Up Direction** to any non-default value (e.g. `+x` or `-z`)
— observe model rotates correctly
3. Click **Fit to Viewer** — model should remain in the chosen
up-direction orientation, not snap back to raw orientation
4. Click **Fit to Viewer** again — rotation should remain stable (no
compounding)
5. Change Up Direction back to `original` then click **Fit to Viewer** —
model should return to neutral orientation `(0,0,0)`

## Review Focus

The key invariant: `fitToViewer()` resets `rotation.set(0,0,0)`
explicitly, so we must clear `originalRotation = null` before calling
`setUpDirection`. Otherwise `setUpDirection` restores the stale pre-fit
rotation as a base and then adds the direction offset on top,
compounding incorrectly.

Fixes #11347

<!-- Pipeline-Ticket: pick-issue-3414 -->

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11826-fix-load3d-reapply-up-direction-after-fitToViewer-transform-reset-3546d73d36508166b9bcecc9949c4952)
by [Unito](https://www.unito.io)
2026-05-04 20:29:24 -04:00
Christian Byrne
2c8ecd82ec fix(load3d): snapshot original materials before reapplying materialMode (#11825)
## Summary

Fixes a bug where models reloaded in wireframe/normal/depth modes would
not restore to their original materials correctly, because the material
snapshot was being taken *after* the mode was applied.

## Changes

- Move `setupModelMaterials(model)` to immediately after
`scene.add(model)` and before `setMaterialMode()` / `setUpDirection()`
in `SceneModelManager.setupModel()`
- Save `materialMode` into `pendingMaterialMode` before calling
`setupModelMaterials()`, since the latter internally calls
`setMaterialMode('original')` which resets `this.materialMode` —
preserving the value ensures the subsequent reapplication guard works
correctly
- Update stale test assertion that reflected the old (incorrect) call
order
- Add regression test: verifies that `originalMaterials` captures the
pre-mutation material and that restoring to `'original'` after a
non-original load gives back the true original mesh material

## Testing

### Automated

- `src/extensions/core/load3d/SceneModelManager.test.ts` — 44 tests, all
pass
- Full load3d test suite — 401 tests, all pass

### E2E Verification Steps

1. Open ComfyUI with a Load3D node
2. Load any GLB/OBJ model
3. Switch Material Mode to **Wireframe** (or Normal/Depth)
4. Load a different model (or reload the same one)
5. Switch Material Mode back to **Original**
6. Verify the model renders with its original diffuse/PBR materials (not
wireframe)

## Review Focus

The key invariant: `setupModelMaterials()` must snapshot mesh materials
in their *unmodified* state. It must run before any `setMaterialMode()`
call that mutates them. The `pendingMaterialMode` variable is needed
because `setupModelMaterials()` internally calls
`setMaterialMode('original')`, which updates `this.materialMode`, making
the subsequent guard `if (this.materialMode !== 'original')` silently
skip reapplication without it.

Fixes #11344

<!-- Pipeline-Ticket: pick-issue-3417 -->

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11825-fix-load3d-snapshot-original-materials-before-reapplying-materialMode-3546d73d3650818b9c35fa60c15f17a3)
by [Unito](https://www.unito.io)
2026-05-04 20:28:09 -04:00
Kelly Yang
7b59c561ff fix(load3d): update renderer pixel ratio on canvas zoom to fix LOD resolution (#11734)
## Summary

Preview 3D and Animation nodes were stuck at the LOD from initial page
load because CSS `scale3d` transforms don't affect
`clientWidth`/`clientHeight` — `handleResize()` always received
layout-space dimensions regardless of zoom level. This fix passes
`ds.scale` as the renderer pixel ratio so the 3D scene renders at the
correct visual resolution when the graph is zoomed in or out.

## Changes

- **What**: In `Load3d.handleResize()`, call
`renderer.setPixelRatio(ds.scale)` before `setSize` so pixel density
scales with canvas zoom. A `getZoomScale` callback is threaded through
`Load3DOptions` → `Load3d` constructor → `handleResize`. In `useLoad3d`,
a watcher on `canvasStore.appScalePercentage` triggers `handleResize`
whenever the zoom level changes.
- **What**: Fix `SceneManager.captureScene()` to save and restore the
renderer's logical size and pixel ratio around capture, so exact-pixel
output is unaffected by the current zoom state.

## Review Focus

- `handleResize` now calls `setPixelRatio` before `setSize`. Three.js
renders at `logicalWidth × pixelRatio` physical pixels while CSS
displays it at `logicalWidth` CSS pixels — this is the standard pattern
for HiDPI but here used to match the visual zoom level.
- `captureScene` must reset `pixelRatio` to 1 so `setSize(w, h)`
produces exactly `w×h` pixel output. It saves and restores both logical
size and pixel ratio via `renderer.getSize()` /
`renderer.getPixelRatio()`.
- The zoom watcher is guarded with `getActivePinia()` to avoid errors in
unit tests and non-Pinia contexts.

## Test
before


https://github.com/user-attachments/assets/9778ad54-7cb2-4fdc-b200-65a683ee8e4d

after


https://github.com/user-attachments/assets/acfaaf7a-43c7-495f-b352-5dd2cdaa94db

## Analysis Report

https://linear.app/comfyorg/issue/FE-401/bug-preview-3d-and-animation-nodes-lod-stuck-at-initial-page-load

## More
- Add `debounce` and pixel ratio limit


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it changes core `Load3d.handleResize()` rendering
behavior (pixel ratio/LOD) and adds a debounced zoom-driven resize
watcher, which could affect performance or visual output across all
Load3D nodes. Capture logic is also refactored to manipulate renderer
size/pixel ratio and camera params, so regressions would show up in
thumbnails/exports.
> 
> **Overview**
> Fixes Load3D LOD/render sharpness when the graph canvas is zoomed by
threading a new `getZoomScale` option from `useLoad3d` into `Load3d` and
using it to call `renderer.setPixelRatio()` (clamped) during
`handleResize()`.
> 
> Adds a debounced watcher on `canvasStore.appScalePercentage` to
trigger `handleResize()` on zoom changes, and updates
`SceneManager.captureScene()` to temporarily force pixel ratio 1 and
restore renderer size/pixel ratio and camera settings after capture.
Coverage is expanded with new Playwright smoke coverage plus unit tests
for zoom propagation, debouncing, pixel ratio behavior, and capture
state restoration.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
261940d111. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->





┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11734-fix-load3d-update-renderer-pixel-ratio-on-canvas-zoom-to-fix-LOD-resolution-3516d73d365081e6b3d4cdd05f516489)
by [Unito](https://www.unito.io)
2026-05-04 20:25:55 -04:00
LifetimeVip
8b1d564729 chore(i18n): correct zh and zh-TW translations (#11930)
## Summary

Fixes several issues in both Simplified Chinese (zh) and Traditional
Chinese (zh-TW) locale files that were identified through systematic
comparison against the English source.

### Changes

**nodeDefs.json (zh + zh-TW):**
- **CLIPLoader.description**: Added missing model recipes (lumina2, wan,
hidream, omnigen2) to match English source
- **ByteDanceSeedreamNode.display_name**: Updated version from "Seedream
4" to "Seedream 4.5 and 5.0" to match English
- **BriaImageEditNode.display_name**: Added missing "FIBO" model name

**nodeDefs.json (zh only):**
- **APG.inputs.eta.name**: Fixed incorrect translation "预计到达时间" (ETA) ->
kept as "eta" (technical parameter name)

**commands.json (zh + zh-TW):**
- **Comfy_ToggleLinear**: Updated label to match English "Toggle App
Mode"
- **Experimental_ToggleVueNodes**: Rebranded "Vue 节点"/"Vue 節點" to "Nodes
2.0" to match English

**settings.json (zh + zh-TW):**
- **Comfy_VueNodes_Enabled / Comfy_VueNodes_AutoScaleLayout**: Rebranded
"Vue 节点"/"Vue 節點" to "Nodes 2.0"

**main.json (zh + zh-TW):**
- **errorDialog.accessRestrictedMessage / accessRestrictedTitle**: Added
missing Chinese translations

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11930-fix-i18n-correct-zh-and-zh-TW-translations-3566d73d365081ff9b0beb1c1fc7ef1a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: LifetimeVip <lifetimevip@users.noreply.github.com>
2026-05-05 00:05:51 +00:00
Christian Byrne
ea2e8e59f2 test: add MembersPanelContent unit tests (#11402)
## Summary

Add 27 unit tests for MembersPanelContent component covering workspace
views, member management, and billing states.

## Changes

- **What**: New test file for MembersPanelContent with 27 tests across 8
describe blocks (personal workspace, owner view, member view, sorting,
search filtering, pending invites, single seat plan, member count
display)

## Review Focus

- Uses `@testing-library/vue` + `@testing-library/user-event` per
project conventions
- Component stubs (Button, SearchInput, Menu, UserAvatar) for isolation
- Reactive mock refs in `vi.hoisted()` shared across `vi.mock()` calls

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11402-test-add-MembersPanelContent-unit-tests-3476d73d36508107abcbce95b72b3fb7)
by [Unito](https://www.unito.io)
2026-05-04 20:02:15 -04:00
Christian Byrne
1f60f7cfcc test: add unit tests for useImageCrop composable (#11138)
## Summary

Add 40 unit tests for `useImageCrop` composable (previously 0% coverage,
277 missed lines).

## Changes

- **What**: New test file `src/composables/useImageCrop.test.ts`
covering:
  - Crop computed properties (read/write/defaults)
  - `cropBoxStyle` computation
  - `selectedRatio` / `isLockEnabled` aspect ratio locking
  - `applyLockedRatio` with boundary clamping
  - `resizeHandles` filtering (8 handles unlocked, 4 corners locked)
  - `handleImageLoad` / `handleImageError`
  - Drag start/move/end with boundary clamping
  - Resize from all 4 edges + MIN_CROP_SIZE enforcement
  - Constrained resize with locked aspect ratio (corner handles)
  - `getInputImageUrl` with subgraph node resolution
  - `updateDisplayedDimensions` for landscape/portrait/zero dimensions
  - `initialize` with `resolveNode` lookup

## Review Focus

Test-only change. Mocks `resolveNode`, `useNodeOutputStore`, and
`useResizeObserver`. No production code changes.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11138-test-add-unit-tests-for-useImageCrop-composable-33e6d73d365081e6aa06e98b66feb585)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-05-04 19:55:06 -04:00
Christian Byrne
5e3266e0c2 test: add e2e tests for node replacement flows (#11242)
## Summary

Add Playwright e2e tests for the node replacement feature (swap nodes UI
in the errors tab).

## Changes

- **What**: 6 e2e test cases across two describe blocks covering single
and multi-type node replacement flows. Tests verify swap nodes group
visibility, in-place replacement, widget value preservation, Replace All
across multiple types, output connection preservation, and success toast
display. Includes typed mock data for `/api/node_replacements` and two
workflow fixture files with fake missing node types mapped to real core
nodes.

## Review Focus

- Mock setup pattern in `setupNodeReplacement` — enables feature flag
via `page.evaluate` and routes the API endpoint
- Workflow fixture design — uses fake node types (E2E_OldSampler,
E2E_OldUpscaler) that map to real registered types (KSampler,
ImageScaleBy)
- Assertion coverage for link preservation after replacement

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11242-test-add-e2e-tests-for-node-replacement-flows-3426d73d3650811e87d7f0d96fd66433)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
2026-05-04 15:52:33 -07:00
Terry Jia
b5b502755f fix(load3d): parse [output]/[input]/[temp] annotation when loading (#11805)
## Summary
The Vue node model picker mixes output assets into the dropdown with a
trailing ' [output]' suffix on the value. Forwarding that string to
loadModel as a literal filename under the configured input folder caused
a 404 and the model never rendered. Strip the trailing folder annotation
per call and use the matching folder so picking an output asset loads
correctly while plain values keep the configured folder.

Output assets stored under a subfolder (e.g. 3d/) were exposed in the
Vue node dropdown as just '<filename> [output]', so selection produced
an /api/view URL with empty subfolder and a 404. Read the subfolder from
the asset's OutputAssetMetadata and prefix it onto the annotated path so
the downstream load handler can split it back out and target the correct
folder.

## Screenshots (if applicable)

https://github.com/user-attachments/assets/463d1071-efdc-46a4-b101-8e1c012d19c7

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11805-fix-load3d-parse-output-input-temp-annotation-when-loading-3536d73d365081a8ac9cf75d14ae29e6)
by [Unito](https://www.unito.io)
2026-05-04 18:44:52 -04:00
pythongosssss
5fbcea6b27 test: add test for workflow delete confirmation (#11780)
## Summary

Adds tests for the `Comfy.Workflow.ConfirmDelete` setting

## Changes

- **What**: 
- ensures dialog does/doesnt appear based on the setting

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11780-test-add-test-for-workflow-delete-confirmation-3526d73d36508134a3cdf0e908b95919)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-05-04 21:51:50 +00:00
Comfy Org PR Bot
ac36dc47a4 docs: Weekly Documentation Update (#11465)
## Summary

Fixed two minor documentation inaccuracies found during comprehensive
documentation audit:
- Corrected outdated "Lodash" reference to "Utility Functions" in unit
testing guide
- Updated package manager command from `npx` to `pnpm dlx` in Playwright
skill documentation

## Changes Made

### Documentation Fixes

#### docs/testing/unit-testing.md:150
- **Before**: `## Mocking Lodash Functions`
- **After**: `## Mocking Utility Functions`
- **Reason**: The section describes mocking `es-toolkit/compat`
functions, not Lodash. The project uses es-toolkit as stated in
AGENTS.md line 158 and docs/guidance/typescript.md line 60.

#### .claude/skills/writing-playwright-tests/SKILL.md:117
- **Before**: `npx playwright show-trace trace.zip`
- **After**: `pnpm dlx playwright show-trace trace.zip`
- **Reason**: Project standardizes on pnpm, explicitly avoiding npx per
AGENTS.md line 42: "use `pnpx` or `pnpm dlx` — never `npx`"

## Audit Summary

Comprehensive audit verified accuracy of:
-  Core documentation (CLAUDE.md, AGENTS.md, README.md)
-  All docs/**/*.md files (40+ files including ADRs, testing guides,
architecture docs)
-  All README files throughout repository (21 files)
-  All .claude/commands/*.md files (8 files)
-  Code examples and API references
-  File structure references (verified src/router.ts, src/i18n.ts,
src/main.ts, config files exist)
-  Package dependencies (es-toolkit ^1.39.9 confirmed)
-  Script commands (pnpm test:unit, pnpm test:browser:local, etc.)
-  External resource links
-  ADR index and dates

All other documentation remains accurate and up-to-date as of
2026-05-04.

## Review Notes

This PR contains only two trivial corrections to terminology/commands.
No functional changes, no code changes, no breaking changes. The
documentation audit found the codebase documentation to be in excellent
condition overall.

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
2026-05-04 21:37:52 +00:00
Christian Byrne
aef71852f0 feat: add demo pages with Arcade embeds at /demos/{slug} (#11436)
*PR Created by the Glary-Bot Agent*

---

## Summary

Adds a demo pages system to the website that embeds Arcade interactive
walkthroughs at `comfy.org/demos/{slug}`. These pages will be linked
from welcome/lifecycle emails via Customer.io.

- Adds `/demos/image-to-video` and `/demos/workflow-templates` as the
first two demos
- Follows the existing `customers/[slug].astro` pattern exactly
(config-driven `getStaticPaths()`)
- Full SEO: OG/Twitter cards, HowTo + LearningResource + BreadcrumbList
JSON-LD schemas
- GEO: AI crawler directives in robots.txt, crawlable transcript
alongside iframe
- A11y: iframe title, sr-only transcript, aria-expanded toggle, noscript
fallback
- Email optimization: 1200x630 OG images, SSG pre-rendered, preconnect
to Arcade CDN
- Full zh-CN localization
- Library index stub at /demos for future expansion
- Automatic sitemap inclusion

## Architecture

Adding a new demo = adding one object to `src/config/demos.ts`.

## Note

OG images are tiny placeholders — replace with real 1200x630 screenshots
before go-live.

## Screenshots

![Demo detail page showing Arcade embed with full design
system](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/d4e44d93c258f779ed62667c7924810f9ae7f20f0c9105acd9c3f86f63816bd1/pr-images/1776645565133-5566bf1b-e965-437d-b21f-89e7a751f883.png)

![Demo library index - Coming Soon
stub](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/d4e44d93c258f779ed62667c7924810f9ae7f20f0c9105acd9c3f86f63816bd1/pr-images/1776645565461-0e334640-13e6-4554-ad6e-b3843e107572.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11436-feat-add-demo-pages-with-Arcade-embeds-at-demos-slug-3486d73d365081abbd72e02bf497a43a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:53:36 -07:00
Dante
94b570a177 test: rename misnamed Mixpanel test and cover the actual provider class (#11749)
## Summary

The existing \`MixpanelTelemetryProvider.test.ts\` was misnamed: it only
tested \`getExecutionContext\` from \`../../utils/getExecutionContext\`,
never the provider class itself — provider coverage sat at **0%**
despite a 239-line test file living next to it.

This PR:

1. **Renames** the existing test file to
\`src/platform/telemetry/utils/getExecutionContext.test.ts\` (co-located
with the source it actually tests). Updates its relative import to
\`./getExecutionContext\`.
2. **Adds** a fresh
\`src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.test.ts\`
covering the provider class.

Lifts provider coverage from **0% → 81.1%** lines (functions 73.5%,
branches 88.5%).

## Test Coverage (new tests)

Constructor / initialization:
- Without \`mixpanel_token\`, warns and disables itself; subsequent
\`trackXxx\` calls are no-ops.
- With \`mixpanel_token\`, dynamically imports mixpanel-browser, calls
\`init\`, and after \`loaded()\` fires identifies users via
\`onUserResolved\`.

Queueing semantics:
- Events fired before \`loaded()\` are queued and flushed in order once
Mixpanel reports ready.

Filtering:
- Events listed in the default \`disabledEvents\` set (e.g.
\`workflow_opened\`) are suppressed.

Direct dispatchers (parameterized \`it.each\`):
- 16 \`trackXxx\` methods covered: signup/auth/login, subscription
lifecycle, credit topup events, template lifecycle, workflow
imported/saved, default-view, enter-linear, share-flow, execution
success/error.
- \`trackApiCreditTopupButtonPurchaseClicked\` payload includes
\`credit_amount\`.
- \`trackEmailVerification\` dispatches the matching
\`USER_EMAIL_VERIFY_*\` event for each stage.
- \`trackSubscription\` maps \`'modal_opened'\` and
\`'subscribe_clicked'\` to their distinct events.
- \`trackRunButton\` populates \`RunButtonProperties\` from the
execution context.
- \`trackWorkflowExecution\` consumes the latest \`trigger_source\` from
\`trackRunButton\`, then resets it to \`'unknown'\`.

Survey:
- On \`'submitted'\`, normalized properties are written to
\`Mixpanel.people\`.
- On \`'opened'\`, \`Mixpanel.people\` is not touched.

Topup delegation:
- \`startTopupTracking\`, \`clearTopupTracking\`,
\`checkForCompletedTopup\` all forward to the \`topupTracker\` utility.

## Testing

\`\`\`bash
pnpm vitest run
src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.test.ts
pnpm vitest run src/platform/telemetry/utils/getExecutionContext.test.ts
\`\`\`

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11749-test-rename-misnamed-Mixpanel-test-and-cover-the-actual-provider-class-3516d73d365081609c54f34bd2d8b00d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-05-04 14:52:03 -07:00
Comfy Org PR Bot
846412af17 [chore] Update Ingest API types from cloud@758732f (#11479)
## Automated Ingest API Type Update

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

- Cloud commit: 758732f
- 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.

---------

Co-authored-by: skishore23 <178779+skishore23@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-05-04 21:37:31 +00:00
Benjamin Lu
aa2169e108 test: reset queue history cap in browser tests (#11773)
## Summary
- Reset `Comfy.Queue.MaxHistoryItems` in the shared browser-test
`comfyPage` setup so worker-persisted queue settings cannot leak between
tests.
- Keep the queue settings spec focused on asserting the setting behavior
without local cleanup scaffolding.

## Validation
- `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://127.0.0.1:65419
PLAYWRIGHT_SETUP_API_URL=http://127.0.0.1:65400
TEST_COMFYUI_DIR=/Users/ben/.codex/comfyui-preview-env/runtime/worktrees/fe-500-maxhistoryitems
pnpm exec playwright test
browser_tests/tests/queue/queueSettings.spec.ts --project=chromium
--workers=1`
- `pnpm exec eslint browser_tests/tests/queue/queueSettings.spec.ts
browser_tests/fixtures/ComfyPage.ts`
- `pnpm exec oxlint browser_tests/tests/queue/queueSettings.spec.ts
browser_tests/fixtures/ComfyPage.ts`
- `pnpm typecheck:browser`
- `git diff --check`
- commit hook: staged oxfmt, oxlint, eslint, `pnpm typecheck`, `pnpm
typecheck:browser`

Linear: FE-500
v1.44.16
2026-05-04 21:31:36 +00:00
Comfy Org PR Bot
cc24d1411a 1.44.16 (#11813)
Patch version increment to 1.44.16

**Base branch:** `main`

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-04 21:30:31 +00:00
AustinMroz
c2abbeda80 Fix core node detection for missing nodes (#11809)
Nodes in the 'essentials' category do not have type 'core'. The check
has been updated to instead use the dedicated `isCoreNode` prop.

No tests currently. The existing tests for this code section all mock
out the relevant code path and properly writing a test for this would
take far more time than I can allocate right now.

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11809-Fix-core-node-detection-for-missing-nodes-3536d73d3650815aabb2deb54c4ecec4)
by [Unito](https://www.unito.io)
2026-05-04 14:21:35 -07:00
Benjamin Lu
56ac3762a0 fix: catch angle-bracket Error assertions (#11909)
## Summary

Extends the new unsafe Error assertion lint rule from #11845 to also
reject angle-bracket assertions.

## Changes

- **What**: Adds a `TSTypeAssertion` selector alongside the existing
`TSAsExpression` selector and broadens the lint message to cover Error
type assertions generally.

## Review Focus

This is stacked on #11845 and only addresses the lint-rule bypass for
`<Error>value` syntax.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11909-fix-catch-angle-bracket-Error-assertions-3566d73d365081f58ecfecfa2e948c33)
by [Unito](https://www.unito.io)

---------

Co-authored-by: bymyself <cbyrne@comfy.org>
2026-05-04 14:16:47 -07:00
guill
f70285dcb2 fix(website): point Install via GitHub buttons to install docs anchor (#11852)
*PR Created by the Glary-Bot Agent*

---

## Summary

Updates the "Install via GitHub" CTA buttons on the `/download` page to
deep-link to the install instructions section of the ComfyUI README
(`#installing`) instead of the repo root, so users land directly on
setup steps.

## Changes

- `apps/website/src/config/routes.ts`: add `externalLinks.githubInstall
= 'https://github.com/Comfy-Org/ComfyUI#installing'` (separate from
`externalLinks.github`, which is still used by the navbar/footer/star
badge for the generic repo link).
- `apps/website/src/components/product/local/HeroSection.vue`: switch
the secondary CTA next to "Download Local" from `externalLinks.github`
to `externalLinks.githubInstall`.
- `apps/website/src/components/product/local/EcoSystemSection.vue`: same
swap on the ecosystem-section CTA.

The platform-aware `Download Local` button (Windows/macOS installers via
`useDownloadUrl`) and the generic GitHub social/repo links elsewhere on
the site are unchanged.

## Verification

- `pnpm --filter @comfyorg/website typecheck` — 0 errors
- `pnpm --filter @comfyorg/website test:unit` — 23/23 passing
- `pnpm exec eslint` on changed files — clean
- `pnpm exec oxfmt --check` — clean
- Manual via `pnpm dev` + Playwright DOM assertion on `/download`:
- Hero "INSTALL FROM GITHUB" →
`https://github.com/Comfy-Org/ComfyUI#installing` ✓
- EcoSystem "INSTALL FROM GITHUB" →
`https://github.com/Comfy-Org/ComfyUI#installing` ✓
- Other "GitHub" links (nav, footer, star badge) → unchanged at
`https://github.com/Comfy-Org/ComfyUI` ✓

Per request from #website-and-docs: the local download surfaces should
at least link to the ComfyUI install instructions on GitHub. Companion
change to comfy-org/website#227.

## Screenshots

![Download page hero with INSTALL FROM GITHUB button now linking to
install docs
anchor](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/3c608b478e1150f3fc43b6092811c93ff3cd90a253263ab05ac43fe8ce7a0843/pr-images/1777761785467-060efddb-f5a0-44a8-8bbe-287c991171ee.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11852-fix-website-point-Install-via-GitHub-buttons-to-install-docs-anchor-3546d73d365081fe8370cd675ae8f896)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:16:36 -07:00
Christian Byrne
6762c08134 feat(website): add payment success and failed pages (#11855)
*PR Created by the Glary-Bot Agent*

---

## Summary

Recreate the two payment status pages that were never migrated from
Framer (they weren't in the sitemap, so were missed). The Stripe
checkout flow in `comfy-api` redirects to
`https://www.comfy.org/payment/{success,failed}` after a checkout
session, so users currently hit a 404 on completion or cancel.

## Changes

- **What**: New static Astro pages at `/payment/success`,
`/payment/failed` and their `/zh-CN/` variants, sharing a
`PaymentStatusSection.vue` component built from the existing
`BrandButton` / `SectionLabel` primitives. Translation keys live in
`src/i18n/translations.ts` for both locales. Pages are `noindex` and
explicitly excluded from the generated sitemap. Adds a Playwright e2e
spec covering both pages in both locales.
- **Dependencies**: none

## Review Focus

- **URL slug**: matches production Stripe config
(`STRIPE_CANCEL_URL=…/payment/failed` in
`comfy-api/run-service-{prod,staging}.yaml`), not `/payment/failure`.
- **Primary CTA target**: links to `externalLinks.apiKeys`
(`platform.comfy.org/profile/api-keys`) — the platform root is just a
redirect, so this avoids a hop.
- **Locale-aware secondary CTA**: derived from `getRoutes(locale)` so
future i18n/route changes flow through the existing helper.
- **Stale fallback** (out of scope):
`comfy-api/gateways/stripe/stripe.go:159` has an unrelated stale
fallback pointing at `/payments/` (plural) that's overridden by the env
config in production. Worth fixing in a follow-up.

## Screenshots

EN success / failed and zh-CN success / failed at desktop widths. Mobile
viewport stacks the CTA buttons vertically (verified locally).

## Screenshots

![Payment success page (EN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774408278-fd3b63f2-357d-401a-8861-5e45050bc930.png)

![Payment failed page (EN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774408672-a8ada80c-030c-4f7e-805d-c9e3edd2ec1e.png)

![Payment success page (zh-CN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774408994-2ac1dc5a-8556-4ca1-929b-71d8812337e1.png)

![Payment failed page (zh-CN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774409357-a79be0ae-36b3-4c1a-84ce-cb65415fee0a.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11855-feat-website-add-payment-success-and-failed-pages-3556d73d3650819f8f45d8ecf27cb264)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:15:57 -07:00
Alexander Brown
211c49f538 docs(skill): improve backport-management with tiered triage, path pre-filter, and public-API conflict review (#11868)
*PR Created by the Glary-Bot Agent*

---

Synthesizes lessons from the recent `v1.43.16` backport session (PRs
#11856–#11862) into the `.claude/skills/backport-management/` skill.

**Documentation only — no code, no workflow, no automation changes.**

## What's new

### `SKILL.md`
- **Quick Start** expanded from 7 to 12 steps, surfacing the pre-filter
and target-file-existence check that should run BEFORE per-PR triage
- **New gotcha**: *Cherry-Picked Tests Can Reference Files Added By
Earlier Unbackported PRs* — drop the test, document why
- **New gotcha**: *Backport-Only Compatibility Shims* — when a
refactor-style fix's mechanism relies on changes that aren't on the
older branch, a literal cherry-pick can recreate the bug for extensions
still using the old contract. Real example: #11541 + `LGraphNode.vue`
`handleDrop`
- **New section**: *Path Pre-Filter* under Auto-Skip Categories —
auto-skip PRs touching only `apps/website/`, `browser_tests/`,
`.github/`, `packages/design-system/`, generated types, `.claude/`,
`docs/`, or `*.stories.ts`. Removes 30–50% of candidates without reading
their bodies

### `reference/analysis.md`
- **New subsection**: *Verify Target File Existence* — `git cat-file -e`
before cherry-pick to skip PRs targeting features the branch doesn't
ship, faster than letting cherry-pick fail with modify/delete
- **New section**: *Tiered Triage* — **Tier 1** (core editor
must-haves), **Tier 2** (cloud-distribution only), **Tier 3** (skip)
before per-PR Y/N. Surfaces release-engineering decisions a flat
MUST/SHOULD list obscures

### `reference/discovery.md`
- Reconciliation workflow combining Slack bot list + git gap,
subtracting already-backported PRs (extracted via `Backport of #` grep
on the branch)
- Clarifies that no single source is authoritative

### `reference/execution.md`
- **New Step 0**: *Test-Then-Resolve Pre-Pass* — moved the dry-run loop
to the top of the workflow so you classify clean vs conflict before
triggering automation
- **New inline guard**: *Public-API conflict review* in the manual
cherry-pick loop — consult oracle BEFORE pushing if resolution touches
LiteGraph callbacks, `node.*` methods, or extension-API surfaces
- **Per-PR validation block** (typecheck + targeted unit tests + ESLint
+ oxfmt) before push, in addition to wave verification
- **Three new lessons learned** (19–21) covering the above
- **New PR Body Template** for manual cherry-picks — non-negotiable
conflict-resolution section so reviewers don't have to re-derive
resolution logic from the diff six months later

## Why

1. **Path pre-filtering** caught 35 of 61 candidates as `skip` before
any per-PR analysis was needed during the `v1.43.16` session
(`apps/website/`, CI, tests, design-system). The previous flat
MUST/SHOULD/SKIP rubric meant reading every PR.

2. **Oracle review on PR #11856** (#11541 backport) caught a regression
in `LGraphNode.vue:823` where the upstream PR's removal of the legacy
`handled === true` sync-return path would silently break custom nodes
still using the old `onDragDrop` contract — recreating the very
duplicate-node bug the PR was fixing. The skill had no guidance for this
class of issue.

3. **Two separate backports** (#11180, #11541) hit the same
modify/delete conflict pattern: a test file added on `main` by an
earlier unbackported PR. The skill's *Conflict Triage* table covered
modify/delete generally but didn't surface this specific anti-pattern of
smuggling in test scaffolding without its prerequisites.

4. **Discovery sources** — the skill assumed Slack bot + git gap as
inputs but didn't show how to reconcile them with already-backported
PRs, leading to potential double-cherry-picking.

## Verification

- No code, no workflow, no automation changes — skill documentation only
- `git diff --check` clean
- All four edited files render as valid markdown
- Cross-references between SKILL.md and `reference/*.md` files validated
by line-count check

## Out of scope (intentionally not changed)

- The `pr-backport.yaml` GitHub Action — the skill describes this but
doesn't own it
- The Slack bot — described as *Source 1*, not modified
- The PR title convention `[backport TARGET] ...` — kept as-is
(CodeRabbit's auto-skip filter relies on it)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11868-docs-skill-improve-backport-management-with-tiered-triage-path-pre-filter-and-public-3556d73d3650814faec3df795567bee3)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-05-04 14:13:13 -07:00
Christian Byrne
b83602fd23 feat: hide Google SSO button in embedded webviews (#10699)
Hide the Google SSO login/signup button when the app runs inside an
embedded webview (Android WebView, iOS WKWebView, social app in-app
browsers), where Google blocks OAuth with a `403 disallowed_useragent`
error.


Fixes #7017

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10699-feat-hide-Google-SSO-button-in-embedded-webviews-3326d73d365081048e35d9d678fe1a2f)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
2026-05-04 14:08:06 -07:00