mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-03 05:38:26 +00:00
de05790f5b9e58dfd950fba6c19bc7207d0fe16f
8434 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
de05790f5b |
test: drop mock-refactor files, split into follow-up PR
Reverts the 8 test files whose new coverage required rewriting existing mock scaffolding, keeping this PR purely additive (no deleted lines except formatting). Rework lands separately in #13411 so it can be reviewed on its own. |
||
|
|
31ebd0a07f |
Merge remote-tracking branch 'origin/main' into codex/coverage-composables-logic
# Conflicts: # src/composables/useFeatureFlags.test.ts |
||
|
|
4cc0402325 |
revert(website): remove Creative Campus customer stories (#13370) (#13407)
## Summary Reverts #13370 (the five Creative Campus customer stories) from `main`. These are education-tied stories, and the "Education Program is live" CTA links to the education page, which is not live yet, so they should not be public before the education launch. This is a clean `git revert` of the squash commit `49a90d4e2` (no history rewrite, no force-push). No work is lost: the story branch (`feat/website-customer-stories-education`) is intact, and the stories will relaunch together with pricing and the education page via #13406. ## Changes - **What**: Reverts the 5 new story MDX files, the new article block components, and the related changes to `CustomerArticle.astro`, `global.css`, `Figure`/`Quote`/`Contributors`, the content test, and the e2e spec. The existing five stories and the customers pages are unaffected. - **Breaking**: none. ## Review Focus - Pure inverse of #13370; the diff is `-858/+11` mirroring the original merge. - Files touched by #13370 are disjoint from the education-page work in #13406, so this does not conflict with that branch. ## Verification - Build: 497 pages (down 5 en story pages). Unit: 156/156. Typecheck: 0 errors. format:check and knip clean. ## Next steps - Stories move into the education bundle (#13406) via a separate PR. - When the education page and its auth (FE-1174) are ready, pricing + customer stories + education launch together. |
||
|
|
470c302879 | test: cover critical composable logic | ||
|
|
a2adfe5124 |
fix(ci): drop unsupported 'range' genhtml ignore-errors category (#13396)
## Summary - `CI: E2E Coverage`'s `Generate HTML coverage report` step fails on every run with `genhtml: ERROR: unknown argument for --ignore-errors: 'range'` - The runner's `apt-get install lcov` resolves to lcov 2.0-4ubuntu2 (Ubuntu 24.04/noble), but the `range` ignore-errors category was only added in lcov 2.1 - lcov 2.0 already reports the out-of-range-line condition under the `source` category, which is already in the ignore list, so `range` was both unsupported and redundant on this runner ## Test plan - [x] Confirmed lcov 2.0-4ubuntu2 is what `apt-get install lcov` resolves to on `ubuntu-latest` - [x] Confirmed via lcov's `lcovutil.pm` source that `range` (`$ERROR_RANGE`) is only registered as of v2.1, and in v2.0 the equivalent out-of-range case falls under `$ERROR_SOURCE` - [ ] CI: E2E Coverage run on this branch's merge should pass the "Generate HTML coverage report" step |
||
|
|
49a90d4e2e |
feat(website): add five Creative Campus customer stories (#13370)
## Summary Add the five new Comfy Education Initiative (Creative Campus) customer stories to `/customers`, each with its own detail page, reusing the existing Astro content-collection pattern. Brings the listing to ten stories. Linear: FE-1161. ## Changes - **What**: Five new English MDX stories (Xindi Zhang, Ina Conradi, Golan Levin, Kathy Smith, and the UAL CCI partnership) added to the customers collection, ordered after the existing five. Adds a small set of reusable article blocks these stories need: `Embed` (Vimeo), `Video` (wraps the existing `VideoPlayer`), `Download` (workflow JSON), `AuthorBio`, `EducationCta`, `AtAGlance`, a styled inline `Link`, and `Heading4`. `Quote`'s `name` is now optional for unattributed pull-quotes; `Figure` gained an optional rich-caption slot (for captions that contain links); `AuthorBio` supports a single-author bio via slot. - **Breaking**: none. All additions are backward compatible; the existing five stories and their pages are untouched. - **Dependencies**: none. ## Review Focus - The logic to review is small and isolated: the new block components in `components/customers/content/` and their registration in `CustomerArticle.astro`. The rest of the diff is MDX content. - **Story copy is transcribed verbatim from the source docs**; punctuation (em/en dashes, curly quotes) is preserved as written and is intentional, not a formatting slip. - **Downloads (cross-origin):** the workflow JSON files are on media.comfy.org, so the HTML `download` attribute is ignored by browsers. The real download is forced server-side with `Content-Disposition: attachment` on the storage objects. Xindi's two workflow files are served from a cache-fresh `.../workflows/` path (with an explicit `filename=`) so the CDN serves the attachment header immediately. - **Embed hardening:** the Vimeo `Embed` iframe carries `referrerpolicy="strict-origin-when-cross-origin"` and a scoped `sandbox` (`allow-scripts allow-same-origin allow-presentation allow-popups`); the player was verified to still load and play. - All media (card covers, inline images, one video with a poster frame, workflow JSON/PNG downloads) is hosted on media.comfy.org. No local assets are committed. Golan's workflow files are re-hosted there; his lesson-plan and demo-project links intentionally stay on GitHub/p5.js as view-only. - English-first: Chinese versions will be added later through a separate translation service. The listing and detail pages already handle a locale that only has English entries, so no page-code changes were needed. - Tags: "Creative Campus Showcase" for the four teaching stories, and "Creative Campus Partnership" for the UAL announcement. ## Verification - Unit `176/176`, typecheck (astro check) `0 errors`, build `502 pages`, `format:check`, `knip`, and `eslint` all pass. - e2e customer specs `6/6` pass (includes a new test asserting the Creative Campus education blocks render). - Visual pass on all ten stories at desktop (1440) and mobile (390): no horizontal overflow, the Vimeo player plays, and all downloads resolve to media.comfy.org. ## Screenshots (if applicable) Easiest way to review is the Vercel preview: https://comfy-website-preview-pr-13370.vercel.app/customers then open the five new stories. Verified on desktop (1440) and mobile (390). |
||
|
|
d6c582c399 |
feat(billing): gate consolidated billing behind consolidated_billing_enabled flag (#13359)
## Summary Shields personal-workspace billing code paths behind the new `consolidated_billing_enabled` feature flag so they fall back to the **legacy** billing flow while the flag is `false`. Team workspaces are unaffected and continue to use the workspace-scoped billing flow. ## Changes - Add `consolidatedBillingEnabled` to `useFeatureFlags` (reads the `consolidated_billing_enabled` server flag / remote config, defaults to `false`) and to the `RemoteConfig` type. - New `useBillingRouting` composable — a single source of truth for whether the active workspace uses the workspace vs. legacy billing flow: - team workspaces disabled → legacy - personal workspace + consolidated billing off/missing → legacy - personal workspace + consolidated billing on → workspace - team workspace → workspace - workspace not loaded yet → legacy - Route `useBillingContext` and the affected UI sites (`SubscriptionPanel`, `useSubscriptionDialog`, `UsageLogsTable`, `TopUpCreditsDialogContentLegacy`) through `useBillingRouting` instead of keying on `teamWorkspacesEnabled` directly. - Update the storybook `useFeatureFlags` mock to stay in sync. ## Testing - `pnpm test:unit` for `useBillingRouting`, `useBillingContext`, `useSubscriptionDialog`, and `UsageLogsTable` (new + updated coverage for the routing matrix). Remaining quality gates (`typecheck`, `lint`) are being verified in CI. ## Related Requires the backend PR that adds the `consolidated_billing_enabled` flag to `/api/features`. --------- Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
a6db1ab3d6 |
fix(website): restore node-link.svg intrinsic sizing (#13384)
## Summary Restore the original `node-link.svg` asset, which PR #13095 accidentally overwrote with a stretch-to-fill Figma export, breaking the node connector across the marketing site. ## Changes - **What**: Revert `apps/website/public/icons/node-link.svg` to its intrinsic **20×32** form (`fill="#F2FF59"`). PR #13283 had replaced it with a raw Figma export (`preserveAspectRatio="none"`, `width="100%" height="100%"`, `fill="var(--fill-0, …)"`). Every consumer loads it as a bare `<img src>` and relies on the intrinsic size plus `scale-*`/`rotate` classes — with no intrinsic dimensions the connector expanded to fill its container and distorted. ## Review Focus - The overwrite originated in the first commit of #13283's stack and rode through the squash merge; nothing in that PR actually referenced this file (the MCP page uses the separate `NodeUnionIcon.vue`), so restoring the shared asset fixes all consumers (`BuildWhatSection`, `ProductShowcaseSection`, `OurValuesSection`, `GalleryDetailModal`) without touching the MCP page. - `apps/website/dist/icons/node-link.svg` is stale build output and regenerates on the next `pnpm build`. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions <github-actions@github.com> |
||
|
|
2ec2a0e091 |
feat: attribute payment intent through paywall, checkout, and top-up telemetry (#13363)
## Summary Answers "why did this user want to pay?" by capturing the triggering product moment at every paywall/upsell entry point and carrying it through checkout and success telemetry. ## Changes - **What**: - Widen `SubscriptionDialogReason` from 4 coarse values to 13 grounded intent sources (`subscribe_to_run`, `upgrade_to_add_credits`, `invite_member_upsell`, `settings_billing_panel`, etc.) - Fire `app:subscription_required_modal_opened` from `useSubscriptionDialog` (the choke point all dialog variants pass through) — the workspace/unified path previously emitted nothing; remove the now-duplicate emitters in `useSubscription` and `usePricingTableUrlLoader` - Add `payment_intent_source` to `BeginCheckoutMetadata`/`SubscriptionSuccessMetadata`, threaded via the existing `reason` prop: dialog → `PricingTable` → `performSubscriptionCheckout` → pending-attempt record, so legacy `app:monthly_subscription_succeeded` carries intent alongside `checkout_attempt_id` - Fire `begin_checkout` on the workspace checkout path (`useSubscriptionCheckout`, personal + team confirm) and the team deep-link util — both previously emitted nothing; `tier` widened to `TierKey | 'team'` - Implement `trackBeginCheckout` in `PostHogTelemetryProvider` (was GTM/host-only, so `begin_checkout` never reached PostHog) - Thread `showSubscriptionDialog(options)` through the billing-context adapters and pass a reason at ~14 call sites; add `source` to `app:add_api_credit_button_clicked` ## Review Focus - `modal_opened` now fires once per dialog actually shown, so a free-tier user clicking Upgrade emits two events (free-tier dialog, then pricing table) where the legacy path emitted one - Intent is threaded explicitly via props/params rather than shared state; `useSubscriptionCheckout` gained an optional second parameter |
||
|
|
9cf5c9a93f |
refactor(website): tidy customer story review nits (#13324)
## Summary Small follow-up to #13289 applying two non-blocking review nits from Alex's review. ## Changes - **What**: drop the redundant `before:content-['']` on the customer-story list bullet (Tailwind emits the empty `content` automatically once another `before:` utility is present), and rename `HEADER_OFFSET` to `HEADER_OFFSET_PX` in `ArticleNav` so the scroll constants use consistent unit suffixes. ## Review Focus Both changes are cosmetic with no behavior change. Confirmed in the browser that the list bullet still renders identically (6px yellow dot) without the explicit `content` utility. ## Notes from the #13289 review (left as-is here, open to discussion) Three other comments from the review are intentionally not changed in this PR; reasoning below so the decisions are on record: - **`Category` type in `ArticleNav`**: kept the `ComponentProps<typeof CategoryNav>` derivation. AGENTS.md says to derive component types via `vue-component-type-helpers` rather than redefining them, so the current form follows the styleguide. Happy to switch to a plain named type if preferred. - **Section ids in frontmatter vs the body `<Section>`**: kept the `customers.content.test.ts` parity test. The short TOC labels live only in frontmatter and Astro can't introspect the rendered MDX body to build the nav, so the frontmatter `sections` list and the body anchor ids can't be trivially deduplicated. A real fix would need a remark plugin (larger, separate change). The test guards against silent drift in the meantime. - **`nextStory` throw**: left as a fail-loud, build-time invariant. The slug always comes from the same `getStaticPaths` collection, so the throw is effectively unreachable; it surfaces a future-refactor bug loudly instead of linking to the wrong story. |
||
|
|
9e5fb67b76 |
Show app mode run validation warning (#12557)
## Summary Adds an app mode validation warning so users can see when a workflow has errors before running and jump directly back to graph mode to review them. ## Changes - **What**: Adds a reusable app mode warning banner above the Run button when the execution error store reports workflow errors, including validation and missing asset states. - **What**: Reuses the existing graph-error navigation flow so the warning action switches out of app mode and opens the Errors panel in graph mode. - **What**: Updates the app mode Run button icon and accessible label in the warning state while keeping the Run action non-blocking. - **What**: Adds unit coverage for the warning render/accessibility state and an E2E flow that triggers a validation failure, dismisses the overlay, and opens graph errors from the app mode warning. - **Breaking**: None. - **Dependencies**: None. ## Review Focus The warning intentionally mirrors graph mode behavior: it surfaces the error state but does not prevent the user from clicking Run. This avoids turning display-level validation signals into hard execution blockers. The warning is driven by the existing `hasAnyError` aggregate, so missing nodes, missing models, and missing media are included alongside prompt/node/execution errors. ## Tests - `pnpm format` - `pnpm lint` - `pnpm typecheck` - `pnpm test:unit` - `pnpm knip` - `pnpm test:browser:local browser_tests/tests/appModeValidationWarning.spec.ts` ## Screenshots <img width="461" height="994" alt="스크린샷 2026-06-25 오후 7 00 55" src="https://github.com/user-attachments/assets/f8fc20bf-d572-46b5-9fa4-312e7c4c8076" /> |
||
|
|
690e0e3590 |
test: add critical unit coverage gate (#13313)
## Summary
Add a `COVERAGE_CRITICAL` unit-coverage gate over folder-based critical
runtime areas and wire it into the unit CI job. First PR of a stacked
series that ratchets the gate upward as tests land.
## Changes
- **What**: `vite.config.mts` gains `CRITICAL_COVERAGE_INCLUDE` folder
globs for core runtime areas: `src/base`, `src/composables`, `src/core`,
`src/schemas`, `src/scripts`, `src/services`, `src/stores`, `src/utils`,
selected `src/platform` logic slices, selected
`src/lib/litegraph/src/{node,subgraph,utils}` primitives, and selected
`src/workbench` manager logic; `package.json` gains
`test:coverage:critical` (`COVERAGE_CRITICAL=true vitest run
--coverage`); `ci-tests-unit.yaml` runs the gate. The thresholds are
env-gated, so the normal `test:coverage` run is unaffected.
- **Breaking**: none.
## Review Focus
Establishes the measurement substrate, no tests added yet. Thresholds
are locked to the current baseline over the folder-based critical scope
so CI is green:
| metric | baseline | threshold |
|---|---|---|
| statements | 69.53% (24287/34930) | 69 |
| branches | 60.7% (11497/18940) | 60 |
| functions | 67.34% (4980/7395) | 67 |
| lines | 70.83% (22619/31930) | 70 |
The scope is intentionally not whole `src/platform`, `src/lib`, or
`src/workbench`: UI-heavy and specialized lanes like platform
components, telemetry/surveys, litegraph
canvas/widgets/infrastructure/types, and manager components/types stay
outside this gate for now.
Subsequent stacked PRs add tests and bump these thresholds; a later
refactor series ratchets branches to 90.
Created by Codex
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Changes are limited to test/coverage configuration and CI; no
application runtime behavior is modified.
>
> **Overview**
> Introduces a **critical-path unit coverage gate** that only runs when
`COVERAGE_CRITICAL=true`, leaving the existing `pnpm test:coverage`
behavior unchanged.
>
> **Vitest** (`vite.config.mts`): when the flag is set, coverage is
limited to folder globs for core runtime areas (base, composables, core,
services, stores, utils, selected platform/workspace/auth slices,
litegraph node/subgraph/utils, workbench manager logic, etc.) and
**Vitest thresholds** are enforced (statements 69%, branches 60%,
functions 67%, lines 70%). In that mode, litegraph is no longer
blanket-excluded from coverage the way the full `src` run still excludes
`src/lib/litegraph/**`.
>
> **Tooling & CI**: adds `test:coverage:critical` in `package.json` and
a new unit CI step after Codecov upload that runs the gate so
regressions in those areas fail the job.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
|
||
|
|
01738b7b19 |
feat(website): move customer stories to Astro content collections (#13289)
## Summary
Move the five customer stories on `/customers` out of the old
`customerStories.ts` array and the shared i18n file into an Astro
content collection (MDX, English and Chinese). The pages look and read
exactly the same; this just changes where the content lives so it is
easier to edit, and it sets the pattern we will reuse to migrate the
rest of the marketing content.
Linear: FE-1158
## Changes
- **What**:
- Added a `customers` content collection (`src/content.config.ts` +
`src/content/customers.schema.ts`), with one MDX file per story per
locale under `src/content/customers/{en,zh-CN}/`.
- Rebuilt the article rendering as small static components (`Section`,
`Figure`, `Quote`, `Contributors`, `Steps`, plus styled
paragraph/heading/list). The article body is now static HTML; only the
scroll-spy sidebar (`ArticleNav.vue`) ships JavaScript.
- Repointed the `/customers` listing and detail pages (both locales) to
read from the collection.
- Removed the old `customerStories.ts` array and the customer-story keys
from `translations.ts` (about 1,300 lines).
- Dropped the two "Read more" links that just redirected back to the
same page; kept the two that point to the real Substack articles.
- Switched the "Read more" button to the design-system `Button`, which
also fixes its vertical alignment.
- Added a short pattern doc at `apps/website/src/content/README.md` for
reuse.
- **Dependencies**: `@astrojs/mdx` (renders the MDX content).
## Review Focus
This is meant to be a no-visual-change migration. I checked content and
layout against the live site for all five stories in both languages, on
desktop and mobile. The only intended differences are the two removed
self-referential "Read more" links and the read-more button now using
the shared `Button`.
A few small setup changes explain part of the diff:
- `src/env.d.ts` now references `.astro/types.d.ts` so the collection
types resolve (this is the repo's first content collection).
- `astro.config.ts` sets `markdown.smartypants: false` so quotes stay
straight (MDX would otherwise curl them). This option is deprecated in
Astro 7 and moves onto the markdown processor; that belongs with the
eventual Astro 7 upgrade, not here.
- ESLint ignores the `astro:` virtual modules for `apps/website` files
(they are real at build time, but the resolver cannot see them).
- Content MDX is excluded from `oxfmt` in `.oxfmtrc.json`: the formatter
rewraps component slots and changes the rendered output (it broke the
blockquotes), so content files are kept out of it like generated files
and fixtures.
- `components/common/ContentSection.vue` and `config/contentSections.ts`
are untouched; they still power the legal and privacy pages.
The diff is large, but most of it is MDX content, the lockfile, and the
removed i18n keys. The logic to review is small: the collection config
and schema, the components, and the page wiring.
## Screenshots
No visual change is intended, so before and after of the article pages
are identical (verified across both locales and on desktop and mobile).
The one deliberate tweak is the "Read more" button, which now uses the
design-system `Button` for better vertical alignment. Before/after
captures are available if needed.
|
||
|
|
be9de941c9 |
refactor: brand link slot and reroute ids (#13296)
## Summary Brand link, reroute, and slot identifiers through LiteGraph, subgraph, and layout flows so raw numeric workflow data is converted at boundaries while runtime APIs keep branded IDs. ## Changes - **What**: Add canonical `LinkId`, `RerouteId`, and `SlotId` types plus minting helpers, then re-export litegraph/layout ID types from those modules. - **What**: Keep `LinkId`, `RerouteId`, and `SlotId` references branded across graph links, reroutes, node slots, subgraph slots, link deduplication, link drop handling, layout storage, and tests. - **What**: Convert raw numeric IDs only at periphery points: serialized workflow DTOs, legacy graph link proxy access, copied/pasted graph data, Yjs/string layout keys, and test fixtures. - **What**: Move slot layout identity onto branded `SlotId` values using stable `node:direction:index` ordering, while keeping DOM dataset values stringified at the boundary. - **What**: Avoid slot-key scans during link drops by carrying the link segment identity directly through the drop path. ## Review Focus - Branded IDs should not be widened back to `LinkId | number` / `RerouteId | number` in runtime APIs. - Serialized workflow shapes intentionally remain numeric for compatibility. - `_subgraphSlot.linkIds` remains `LinkId[]`; call sites should not treat it as raw `number[]`. - `MapProxyHandler` is the compatibility boundary for deprecated indexed `graph.links[id]` access. ## Validation - `pnpm typecheck` - `pnpm test:unit src/lib/litegraph/src/LLink.test.ts src/lib/litegraph/src/LGraph.test.ts src/lib/litegraph/src/LGraphNode.test.ts src/lib/litegraph/src/canvas/LinkConnector.core.test.ts src/lib/litegraph/src/canvas/LinkConnector.integration.test.ts src/lib/litegraph/src/canvas/LinkConnectorSubgraphInputValidation.test.ts src/lib/litegraph/src/LGraphCanvas.drawConnections.test.ts src/lib/litegraph/src/node/slotUtils.test.ts src/lib/litegraph/src/subgraph/ExecutableNodeDTO.test.ts src/core/graph/subgraph/promotionUtils.test.ts src/core/graph/subgraph/migration/proxyWidgetMigration.test.ts src/renderer/core/layout/store/layoutStore.test.ts src/renderer/core/layout/utils/layoutUtils.test.ts src/renderer/extensions/minimap/minimapCanvasRenderer.test.ts src/scripts/promotedWidgetControl.test.ts` - Commit hook: `oxfmt`, `oxlint`, `eslint`, `pnpm typecheck` - Push hook: `knip --cache` --------- Co-authored-by: AustinMroz <austin@comfy.org> |
||
|
|
f4e0430072 |
fix: disable global keybindings while a modal dialog is open (#12184)
## Summary
Block background keybindings from firing while a modal dialog (e.g.
Templates) is open, so typing `w` no longer toggles the workflow sidebar
behind the modal.
## Changes
- **What**: In `keybindingService.keybindHandler`, gate command
execution on `dialogStore.dialogStack`. When a dialog is open, only
keybindings whose event target is inside the dialog (`[role="dialog"]`)
fire; all other matches are dropped.
## Review Focus
- The dialog scope check uses `target.closest('[role="dialog"]')` so
dialog-internal shortcuts still work — confirm PrimeVue/Reka dialogs
render with `role="dialog"` on the wrapper (they do; this is the
WAI-ARIA standard the libraries follow).
- Updated `keybindingService.escape.test.ts` "modifiers regardless of
dialog state" case to the new contract (modifiers also blocked),
matching the team consensus in FE-642 that all keybindings should be
disabled when a modal is open.
- New `keybindingService.dialog.test.ts` covers: no-dialog → fires;
dialog open + target outside → blocked; dialog open + target inside →
fires.
Fixes FE-642
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-12184-fix-disable-global-keybindings-while-a-modal-dialog-is-open-35e6d73d3650812fbc5dd5490ccde24f)
by [Unito](https://www.unito.io)
Co-authored-by: Dante <bunggl@naver.com>
|
||
|
|
c78592c1ec |
feat: add upload button to dropdown menu filter bar (#12507)
## Summary Add an Upload button to the dropdown popover's filter bar so users can pick a file without closing the dropdown to reach the small upload icon next to the input. The upload button in the dropdown menu includes text and uses the same icon as the external quick upload button. This design ensures that after using it, users will understand that the icon on the external button means upload. Even if users didn't understand it before, they will correctly interpret it next time. related linear FE-581 ## Changes - **What**: - Expose `showPicker()` from `FormDropdownInput`; it calls `HTMLInputElement.showPicker()` on the single existing hidden `<input type="file">` (falls back to `input.click()` on browsers without showPicker). - Add an Upload button in `FormDropdownMenuFilter` that emits `show-picker`, bubbled up through `FormDropdownMenu` to `FormDropdown`, which then calls `triggerRef.showPicker()`. The whole chain runs in the click event's synchronous stack to satisfy the browser's transient activation requirement, so no extra `<input type="file">` is added to the DOM. - Style the button with the project's standard inverted-button tokens (`bg-base-foreground` / `text-base-background`) so it tracks theme changes. ## Review Focus - The `triggerRef!.showPicker()` non-null assertion in `FormDropdown.vue` is intentional: by the time `show-picker` is emitted the trigger is guaranteed to be mounted; a null here would indicate a real bug we want to surface, not swallow. - Verify the new button reuses the same upload path as the inline icon button (single `<input type="file">`, single `handleFileChange`). ## Screenshots <img width="1304" height="1442" alt="CleanShot 2026-06-02 at 14 39 33@2x" src="https://github.com/user-attachments/assets/b2d1cdd8-e28a-467d-8142-afd707264d0e" /> <details><summary>Old Versions</summary> <p> https://github.com/user-attachments/assets/2d64873b-6bec-4eca-aa89-a72dd11aa809 </p> </details> |
||
|
|
00b0c6b434 |
fix: close widget dropdown on outside pointerdown and canvas viewport moves (#12812)
## Summary Model/widget dropdowns stayed open until mouseup, detached from their node when the canvas moved while open, and needed two clicks to dismiss after the inner scrollbar took focus. ## Changes - **What**: - Dismiss the dropdown on `pointerdown` outside the menu/trigger (capture phase) instead of PrimeVue's `click` (mouseup) dismissal. The dropdown now closes the instant a press lands, before a drag or box-select can start, and a focused inner scrollbar no longer swallows the first outside click. - Close the dropdown whenever the canvas viewport moves, by watching the reactive `useTransformState().camera`. This reacts to the canvas abstraction layer rather than guessing input intent, so it covers pan/zoom from any device — mouse drag, trackpad pan, wheel scroll/zoom — where no `pointerdown` ever fires. The popover is teleported to the document body and cannot follow the viewport, so closing is the correct behavior. ## Review Focus - Box-select and node-drag both begin with a `pointerdown` outside the popover, so they are covered by the immediate dismissal path; the camera watch handles pointer-less viewport motion. - `closeOnEscape` and in-menu interactions are unaffected; presses inside the menu or on the trigger are excluded via `composedPath()`. Fixes FE-808 --------- Co-authored-by: Dante <bunggl@naver.com> |
||
|
|
da34fa3944 |
docs(website): update ToS payment terms for Free Tier overages (#13315)
*PR Created by the Glary-Bot Agent* --- Updates two sections on https://comfy.org/terms-of-service per legal copy provided in [the website-and-docs Slack thread](https://comfy-org.slack.com/archives/C098QHJ8YDR/p1782775899132369). ## Changes Edits `apps/website/src/i18n/translations.ts` (the source of truth for the ToS page rendered by `apps/website/src/pages/terms-of-service.astro`): - **`tos.payment.block.1` — Plans; Fees; Free Tier.** Adds language clarifying that a Free Tier user who provides a payment method expressly authorizes Comfy to charge it for overages (intentional use, third-party use, or technical factors), and that approach-to-cap notifications are best-effort, not a precondition to charging. - **`tos.payment.block.3` — Self-Serve Credit Card Billing.** Clarifies that the billing authorization applies to paid Plan and Free Tier overages alike, and that retry rights for failed charges extend to Free Tier overage charges. `en` and `zh-CN` values are kept in sync per the existing convention for these keys (the `/zh-CN/terms-of-service` page is a redirect to the English page). ## Open question for legal / requester `tos.effectiveDate` is currently `May 13, 2026` and was **not** bumped in this PR — the original request did not mention it. If legal wants this revision to carry a new effective date, that should be a follow-up commit on this branch before merge. ## Verification - `pnpm typecheck` (apps/website): 0 errors, 0 warnings. - `pnpm build` (apps/website): 497 pages built; the rendered `/terms-of-service` HTML contains both new sentences. - `pnpm exec eslint` / `oxfmt --check` on the changed file: clean. - Husky pre-commit (`lint-staged` + `check-unused-i18n-keys`): clean. - Manual: served the built `dist/` via local HTTP and verified the rendered Payment section in a real browser (screenshot below). ## Screenshots  Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
c8ed15da31 |
feat: follow --comfy-api-base for staging and preview backends (#13054)
## Summary Let the running ComfyUI server decide which backend the web UI talks to (and which Firebase project it signs you into), so launching with `--comfy-api-base` just works with the regular bundled frontend. ## Changes - **What**: At startup the frontend reads `/api/features` on every build (not just cloud) and treats the server's `comfy_api_base_url` / `comfy_platform_base_url` as authoritative, falling back to the build-time defaults. When that api base is a staging-tier host (staging, or a `*.testenvs.comfy.org` preview env) and the server hasn't supplied its own Firebase config, the frontend picks the dev Firebase project, derived from the api base. Production is left exactly as it is today. - `main.ts`: load remote config first thing, before Firebase initializes, so every module sees the right values from the first render - `config/comfyApi.ts`: the api/platform getters now read the server's values on all distributions - `config/firebase.ts`: `getFirebaseConfig()` resolves in order: a server-provided config first (cloud), then the dev project for a staging-tier api base, then the build-time default - `platform/remoteConfig/refreshRemoteConfig.ts`: the startup fetch now has a 5s timeout, so a slow or wedged `/features` can never keep the app from mounting; on failure we fall back to the build-time defaults - **Breaking**: None. With no `/features` overrides (production and ordinary self-hosting), behavior is unchanged ## Review Focus - The precedence in `getFirebaseConfig()` (`config/firebase.ts`): server config first, then the staging-tier dev project, then the build-time default. The staging-tier check matches `stagingapi.comfy.org` and any `*.testenvs.comfy.org` host, and falls back to build-time for anything it can't parse. - Running `refreshRemoteConfig()` unconditionally and first in `main.ts`, with the new fetch timeout as the safety net. ## Testing I tested every case by hand, locally, on top of the automated checks. Tested both with `pnpm run build` and `USE_PROD_CONFIG=true pnpm build` and running Comfy from that folder. Pointed a local ComfyUI at each backend with `--comfy-api-base` and signed in with Google each time: - **Production** (default / `https://api.comfy.org`): stays on production and signs into the production Firebase project, identical to today. - **Staging** (`https://stagingapi.comfy.org`): follows it and signs into the dev project. - **Ephemeral preview env** (`https://pr-<n>.testenvs.comfy.org`): the friendly host is accepted as-is, the frontend follows it, lands in the dev project, and Google sign-in completes. The only exception where fronted does not respect the `--comfy-api-base` is when Comfy runs against `prod` and frontend runs with the `pnpm run dev` - due to overridden config(this is expected behavior). Supersedes: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12560 Companion Core PR: https://github.com/Comfy-Org/ComfyUI/pull/14569 ## Screenshots (if applicable) <!-- Add screenshots or video recording to help explain your changes --> |
||
|
|
b132abc64a |
fix: center video asset in the Load Video node preview (#13172)
## Summary Center the Load Video node preview and keep the node from auto-resizing on clip load, so the video letterboxes in place like the Load Image node (FE-1092). ## Changes - **What**: Makes the video stay centered horizontally and vertically - Playwright browser test expectations updated at run https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/28267324092 ## Review Focus - Ensure that patterns and idioms were followed ## Screenshots (if applicable) Horizontally centered <img width="902" height="392" alt="image" src="https://github.com/user-attachments/assets/a9fbec56-1613-44b4-a423-9f709a246c63" /> Vertically centered <img width="220" height="1124" alt="image" src="https://github.com/user-attachments/assets/5497f39b-2ea2-4247-a087-a7d89768b4ce" /> Full aspect ratio <img width="433" height="672" alt="image" src="https://github.com/user-attachments/assets/d579fb14-34c6-4963-abc9-034611232d3d" /> Minimum size <img width="217" height="376" alt="image" src="https://github.com/user-attachments/assets/80df0411-3ff1-4050-ac8e-761b7b8a7c40" /> Preview centering is asserted in `browser_tests/tests/vueNodes/videoPreview.spec.ts`. --------- Co-authored-by: github-actions <github-actions@github.com> |
||
|
|
55c52a730a |
Enable cloud PostHog pageviews (#13286)
## Summary This PR enables native PostHog `$pageview` capture for `cloud.comfy.org` by setting cloud PostHog `capture_pageview` to `history_change`. This keeps `autocapture` disabled, preserves the existing custom `app:page_view` event, and lets the PostHog SDK capture the initial pageview plus SPA history navigation pageviews. The goal is to make cross-domain funnel tracking cleaner between `comfy.org` and `cloud.comfy.org`, since `comfy.org` already emits native `$pageview` events. ## Why We want to measure the visitor funnel more accurately across: - `comfy.org` visits - `cloud.comfy.org` visits - signup clicks / signup opened - signup completion - first cloud workflow run - first subscription - first credit purchase Using native `$pageview` on both website and cloud should make PostHog and downstream warehouse/Hex analysis cleaner for trackable users, while leaving custom app pageview telemetry intact for existing consumers. ## Validation - `pnpm test:unit src/platform/telemetry/providers/cloud/PostHogTelemetryProvider.test.ts` - `pnpm typecheck` - `pnpm lint:unstaged` - pre-commit hook: `oxfmt`, `oxlint`, `eslint`, `pnpm typecheck` - pre-push hook: `knip --cache` Note: local validation printed an engine warning because the Codex runtime has Node `v24.14.0` while this repo declares `>=25 <26`; the commands above still passed. |
||
|
|
fbe462143a |
fix: re-export GroupNodeHandler for custom node compat (#13299)
Fixes #13175 #12931 slimmed groupNode.ts down to migration-only and dropped the export on GroupNodeHandler. ComfyUI-Manager still imports it (import { GroupNodeConfig, GroupNodeHandler } from "../../extensions/core/groupNode.js" in components-manager.js), so the legacy shim no longer providing that export throws "does not provide an export named 'GroupNodeHandler'" at module load. That kills the whole Manager extension before setup() runs — which is why the Manager button vanished from the toolbar since 1.47.3 (backend loads fine, frontend JS dies). Just re-adds the export (class is still there, only the keyword was lost) plus the existing @knipIgnoreUnusedButUsedByCustomNodes tag since nothing in src imports it. Tested by loading with ComfyUI-Manager installed: the groupNode.js import error is gone and the Manager button shows again. typecheck/knip/lint pass. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
61cb1bcde0 |
fix(website): point launches Comfy MCP CTA to /mcp (#13287)
*PR Created by the Glary-Bot Agent* --- ## Summary Update the `EXPLORE` CTA on the Comfy MCP card on [/launches](https://comfy.org/launches) to link to [/mcp](https://comfy.org/mcp) instead of the docs (`docs.comfy.org/agent-tools/cloud`). ## Change Single line in `apps/website/src/data/drops.ts`: ```diff cta: { label: EXPLORE, - href: { en: externalLinks.docsMcp, 'zh-CN': externalLinks.docsMcp } + href: { en: '/mcp', 'zh-CN': '/zh-CN/mcp' } } ``` Matches the locale-aware pattern used by sibling cards (`/download` / `/zh-CN/download`, `/api` / `/zh-CN/api`). Both `src/pages/mcp.astro` and `src/pages/zh-CN/mcp.astro` already exist, so neither link is dead. The `externalLinks.docsMcp` constant is retained because the MCP page itself still uses it. ## Verification - `pnpm typecheck` / `pnpm typecheck:website` clean. - `oxfmt`, `oxlint`, `eslint` clean (all ran via lint-staged on commit). - Manually loaded `/launches` and `/zh-CN/launches` in the dev server and confirmed the Comfy MCP card now points to `/mcp` and `/zh-CN/mcp` respectively. - Loaded `/mcp` and confirmed the destination page renders ("Comfy MCP — Drive ComfyUI from any AI agent"). - Code review by Oracle: no issues. Screenshot shows the updated MCP card on /launches. ## Screenshots  Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
9dcab4ee96 |
Essentials Cleanup (#13183)
Address several followup comments from #12744 |
||
|
|
dc29f30b02 |
Track theme setting changes via telemetry (#13142)
Fix Color Palette changes not getting tracked, requested by design team. Capture theme changes as `app:setting_changed` telemetry. The only existing hook lived in `SettingItem.vue`, which renders *visible* settings; `Comfy.ColorPalette` is hidden and changed through bespoke theme UI, so it was never tracked. Open to opinions here, we can also remove the hook in SettingItem.vue, and just make everything that was visible opt in. Linear: https://linear.app/comfyorg/issue/GTM-158/track-theme-usage-with-posthog-events |
||
|
|
fb3350ee0e |
feat(website): redesign Comfy MCP setup steps and add button variant (#13285)
## Summary Reworks the Comfy MCP page's **"Set up Comfy MCP in three steps"** section to match the new design, and adds a per-action button `variant` option to `FeatureGrid01`. The three steps are now: | Step | Title | Action | | --- | --- | --- | | 1 | Copy the MCP URL | Copy field showing `https://cloud.comfy.org/mcp` | | 2 | Add the connector | Filled button **"COMFY CLOUD MCP DOCS" ↗** → MCP docs | | 3 | Connect and sign in | Filled button **"COMFY CLOUD SKILLS" ↗** → comfy-skills repo | ## Changes - **`FeatureGrid01.vue`** — add `variant?: 'default' | 'outline'` to the link card action; button now uses `card.action.variant ?? 'outline'` instead of a hardcoded outline, so callers can opt into the filled style. - **`config/routes.ts`** — add `mcpSkills` external link (`https://github.com/Comfy-Org/comfy-skills`). - **`i18n/translations.ts`** — refresh the `mcp.setup.*` copy (en + zh-CN): new subtitle, reworded steps, new `step2.cta` / `step3.cta`, drop the now-unused `step1.cta`. - **`SetupSection.vue`** — re-map cards: step 1 → copy field, steps 2 & 3 → filled link buttons. ## Test plan - [x] `pnpm typecheck` — 0 errors - [x] Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck) pass - [ ] Visual check on `/mcp` and `/zh-CN/mcp` (copy field on step 1; two filled yellow CTAs with up-right arrows on steps 2 & 3) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
be8e0010ee |
feat(website): rebuild Comfy MCP page on the design system (+ zh-CN) (#13283)
Rebuilds the **Comfy MCP** marketing page on the website design-system stack and adds the missing zh-CN page. ## What's here - Replaces the bespoke `components/product/mcp/` section silo with thin `templates/mcp/*` wrappers over reusable `blocks/` + `common/` components. - Adds `src/pages/zh-CN/mcp.astro` and threads `locale` through every section (was English-only). - New/extended design-system blocks: - `FeatureGrid01` — setup steps, with a reusable `ui/CopyableField` (uses `@vueuse/core` `useClipboard`). - `FeatureGrid02` — how-it-works steps with `NodeUnionIcon` connectors + a CTA pair via `ui/button`. - `FeatureRows01` — alternating media rows; `ReasonsSplit01` — "why" list. - `HeroSplit01` gained `subtitle`, a `media` slot, and a `class` passthrough; `SectionHeader` gained `align`. - Standardized block section spacing on `px-6 py-16 lg:py-24`. - Refreshed all 8 MCP FAQ answers (en + zh-CN) and hydrated the FAQ section so the accordion is interactive. ## Notes - Stacked on the original MCP landing-page commits (previously PR #13095); those ride along here. - `typecheck` and `build` are green; `/mcp` and `/zh-CN/mcp` both render in both locales. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Balpreet Brar <balpreet.brar@growthnatives.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
d0e97d6933 |
fix(website): move launches nav item and add cleanplate workflow link (#13282)
## Summary - Move the `/launches` nav item from **Company → More** to **Products → Features** in the main navbar - Add the workflow link to the **Cleanplate Walkthrough** learning tutorial (`https://comfy.org/workflows/8f2cf0df5da6-8f2cf0df5da6/`) ## Changes - `apps/website/src/data/mainNavigation.ts` - `apps/website/src/data/learningTutorials.ts` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
3377b8e07e |
feat(publish): prefill prior metadata and update published workflows in place (#13139)
> **Goal: make updating a published Hub workflow painless in admin panel.** Today a admin who needs to change a > published workflow has to reject + reshare + republish, which breaks the share link, resets stats, > and blanks the thumbnail — and the rejected backlog can't be cleared. This is one of 3 PRs that fix it: > > | PR | Repo | Fixes | > |----|------|-------| > | [#4505](https://github.com/Comfy-Org/cloud/pull/4505) | `cloud` | Re-publish stops losing data; the editor can read its own published metadata; reviewer search + admin delete | > | #13139 | `ComfyUI_frontend` | The publish dialog prefills prior metadata + thumbnail and updates in place | > | [#10 ](https://github.com/Comfy-Org/comfy-admin-panels/pull/10)| `comfy-admin-panels` | Admins can delete rejected/stale workflows | > > **Merge order:** `cloud` first (the others depend on its endpoints), then `ComfyUI_frontend` and > `comfy-admin-panels` in either order. ## Summary Editor side of the same effort. Re-opening the publish dialog for an already-published workflow now prefills its description, tags, and thumbnail, restores the thumbnail across step/type changes, keeps the local workflow name in sync, and labels the action "Update" instead of "Publish". Depends on the `cloud` PR — that's what finally returns the `share_id` the dialog reads from. ## Changes - **What**: - **Prefill the thumbnail** — `extractPrefill` dropped `thumbnail_url` / `thumbnail_comparison_url`, so only the thumbnail *type* was remembered, never the image. Thread the URLs into `PublishPrefill` and restore them; on submit, send the existing URL when no new file is attached (reuses the `sampleImageUrls` precedent — an existing URL, not a `File`), so re-publishing doesn't blank it. - **Uploads survive navigation** — the thumbnail step kept its `File` in local component state, so leaving the step and coming back blanked a fresh upload. The step is now controlled — files live in the form data, the single source of truth that survives the remount. - **Type-gate the prefilled image** — a restored image must only show on the tab it belongs to; `existingThumbnailType` keeps an image off the video tab (which was hiding the upload prompt) while still restoring it when you toggle back. - **Refetch on rename** — the dialog is a reused singleton, so `onMounted` fires once; a watch on the active workflow path refetches prefill when a rename changes it (the description was going stale). - **Name sync** — editing the name field published a new Hub display name but never renamed the local workflow, so the editor tab (and a reload) kept the old name. Publish now renames the local file when the chosen name differs. - **"Update" CTA** — the intro panel and footer read "Update" (not "Publish") when the workflow is already published, and note that the share link + stats are preserved. ## Review Focus - `existingThumbnailType` is the load-bearing bit for both the preview and submit gating — confirm an image prefill never submits as a video after a type toggle, and that toggling back restores it. - Name sync renames *after* a successful publish and is non-fatal on failure (toast + keep the publish). The Hub record is keyed by workflow ID, so the rename doesn't orphan it — worth a sanity check. ## Screenshots https://github.com/user-attachments/assets/99dd9eff-987f-4ddb-9cf1-e9b40f61e7dc |
||
|
|
4a2393be48 |
chore: drop unnecessary exports on file-local types to satisfy knip (#13204)
Current `main` **fails a fresh `knip` run** with 13 unused exported types (exit 1). They're invisible on main because lint/knip only runs on `pull_request`/`merge_group`, never on push to main — so merge skew (one PR adds an export used by file X; a later PR removes X's usage) accumulates latent failures that ambush backport branches (e.g. #13163, #13162). Each of the 13 is `export`ed but referenced only within its own file (verified 0 importers; ≥2 in-file uses, so not dead code). Fix: drop the redundant `export`. Types cleaned: `VideoSource`, `ObjectInfoResponse`, `PromotedMissingModelWorkflow`, `PixelReadout`, `ResizeDirection`, `ResizeHandle`, `RunButtonTelemetryOptions`, `ResolvedModelNode`, `AccountPreconditionContext`, `SubscriptionDialogOptions`, `MonthlyCreditsUsage`, `MissingMediaReference`, `ResolvedHostWidget`. Reviewer note: `ResolvedHostWidget` and `ResolvedModelNode` sit under `renderer/extensions`/`platform/assets`; no in-repo importers, but if either is intended as published/extension-facing API, prefer a knip `entry`/`ignore` over un-exporting — flag in review and I'll adjust. After fresh `knip`: **0 unused exported types**. Supersedes #13179 (fixed only `AccountPreconditionContext`). Pairs with the push-gate workflow #13203 — merge this first so that gate is green on main. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a451a90868 |
FE-1150 feat(rightSidePanel): hide 3D viewport widgets from panel (#13206)
## Summary Add a hideInPanel widget option so a widget still renders on the node body but is omitted from the right side panel. Apply it to the Three.js viewport widgets (Load3D, Preview3D, Load3DAdvanced, SaveGLB), whose non-syncable scene state would diverge if a second instance rendered in the panel. App mode and the subgraph editor are unaffected (they filter on canvasOnly independently). Discussed with @alexisrolland and @PabloWiedemann ## Screenshots before <img width="2206" height="1181" alt="image" src="https://github.com/user-attachments/assets/e536871f-65e6-4d6e-aa61-dc981362214f" /> after <img width="2743" height="1295" alt="image" src="https://github.com/user-attachments/assets/6cc6d252-57ac-464a-a2b7-1ada5ab9e705" /> |
||
|
|
be102899d7 |
1.47.6 (#13194)
Patch version increment to 1.47.6 **Base branch:** `main` --------- Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com>v1.47.6 |
||
|
|
abd1a6f10a |
fix: use error colour for runtime execution error node outline (#13184)
## Summary A node that fails at runtime is now outlined in the same red as a node that fails validation, instead of magenta. ## Changes - **What**: The `executionError` stroke in `litegraphService.ts` was hardcoded to magenta (`#f0f`); validation errors use `LiteGraph.NODE_ERROR_COLOUR` (red). Reuse that constant so both error states render consistently. One-line change; `LiteGraph` is already imported. ## Review Focus No test added: asserting a hardcoded stroke colour would be a change-detector test. The two error paths (validation via `has_errors` / `NODE_ERROR_COLOUR`, runtime via `lastExecutionError`) now share the same colour source. |
||
|
|
c16f10b49e |
Long workflow name cleanup (#13180)
When loading a workflow by dragging and dropping an output from the assets sidebar, the very long and unhelpful url would be used as the workflow name. This is fixed by instead using the asset display name | Before | After | | ------ | ----- | | <img width="360" alt="before" src="https://github.com/user-attachments/assets/5c68ae48-1fa6-40e1-b2fb-6188ccd60391"/> | <img width="360" alt="after" src="https://github.com/user-attachments/assets/29770c35-da48-4be9-943e-8ee69eb25e6a" />| Additionally, a max width is added to the breadcrumb items to avoid extremely long names. | Before | After | | ------ | ----- | | <img width="360" alt="before" src="https://github.com/user-attachments/assets/508155ec-81d7-4ca5-8910-f42a70c9cb4b"/> | <img width="360" alt="after" src="https://github.com/user-attachments/assets/d335ceb7-bfeb-481f-a132-c700e017ee0c" />| |
||
|
|
64253de713 |
fix: e2e coverage html report asset failures (#13127)
## Summary
Harden E2E coverage HTML generation against non-renderable LCOV source
entries so public assets and stale sourcemap paths no longer abort the
report.
## Changes
- **What**: Removes `assets/images/*` entries from merged E2E LCOV
before upload/report generation.
- **What**: Lets `genhtml` ignore range warnings and synthesize missing
source files when LCOV references stale paths.
- **Dependencies**: None.
## Review Focus
Root cause: Playwright/Monocart can emit LCOV `SF:` records that
`genhtml` cannot read from the checkout. The failed run stopped first on
public assets like `assets/images/hf-logo.svg`; replaying the same
artifact also exposed stale source paths after those assets were
removed.
The filter is intentionally `assets/images/*`, not `assets/*`, because
real `lcov` matching would also remove legitimate source coverage under
`src/platform/assets/...`.
## Validation
- `yamllint --config-file .yamllint
.github/workflows/ci-tests-e2e-coverage.yaml`
- Replayed failed run `28138018468` merged LCOV:
- `assets/images/*` strip leaves `0` `SF:assets/...` entries
- preserves `68` `SF:src/platform/assets/...` entries
- `genhtml` exits `0` with `--ignore-errors source,unmapped,range
--synthesize-missing`
- Commit hook: `oxfmt`, `oxlint`, `eslint`, `pnpm typecheck`
- Push hook: `knip --cache`
## Screenshots (if applicable)
N/A, CI workflow-only.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Changes are limited to the E2E coverage GitHub Actions workflow; no
application runtime or security paths are touched.
>
> **Overview**
> Fixes E2E coverage HTML generation failing when merged LCOV references
paths **genhtml** cannot read (public static assets and stale sourcemap
paths from Playwright/Monocart).
>
> The **Strip non-source entries** step now also drops `assets/images/*`
via `lcov --remove`, scoped narrowly so real source under
`src/platform/assets/...` stays in the report. **Generate HTML coverage
report** passes `--ignore-errors source,unmapped,range` and
`--synthesize-missing` so remaining unmapped or missing sources do not
abort the job.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
|
||
|
|
b4ae6344d7 |
Brand local node IDs (#13085)
## Summary Adds a branded local `NodeId` helper and starts separating local node identity from serialized workflow IDs. ## Changes - **What**: Adds central `NodeId` parsing/branding helpers, migrates nearby widget identity types, keeps queue results at the serialized boundary, and removes misleading workflow `NodeId` usage from execution error maps. ## Review Focus Check that the first migration slice keeps serialized/API IDs as raw `number | string` while local UI/store IDs use the branded string type. ## Caveat `SUBGRAPH_INPUT_ID` and `SUBGRAPH_OUTPUT_ID` are now branded local `NodeId` string values internally instead of numeric sentinels. Reviewers should double-check extension compatibility for callers that import `Constants` and compare those values numerically. ## Screenshots (if applicable) N/A --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: AustinMroz <austin@comfy.org> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
feaa4ce82f |
refactor: localize system stats headers and fix PyTorch casing (#12253)
## Summary Localizes the 12 system stats column headers via vue-i18n and fixes the `Pytorch` → `PyTorch` casing typo. ## Changes - **src/locales/en/main.json**: Add 11 i18n keys under `g.systemStats*` namespace - **src/components/common/SystemStatsPanel.vue**: - Import `useI18n` and use `t()` for column headers - Change `header` field to `headerKey` in ColumnDef type - Fix PyTorch casing (was `Pytorch Version`) ## Context Follow-up to PR #11816 per review comment. ## Test plan - [x] Column headers render correctly - [x] Copy System Info includes localized headers - [ ] Verify other locales can override (out of scope - EN only for now) Closes #11870 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12253-refactor-localize-system-stats-headers-and-fix-PyTorch-casing-3606d73d36508134af99f7ca4f9c6593) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com> |
||
|
|
f5d059b720 |
feat(i18n): add Hebrew (he) language support (#12721)
## Summary
Adds full Hebrew (`he` / עברית) localization for the ComfyUI frontend
UI, registered the same additive way as the existing RTL locales (`ar`,
`fa`).
## Changes
- **What**:
- New `src/locales/he/main.json`, `commands.json`, and `settings.json` —
complete, human-reviewed Hebrew translations.
- Exact key parity with `en` (3524 / 125 / 235 keys), verified
programmatically.
- All `{interpolation}` placeholders and `|`-separated plural forms are
preserved (same segment counts as `en`).
- Established technical terms are kept in English (API, GPU, VAE, CLIP,
LoRA, ControlNet, Civitai, Hugging Face, flux, Nodes 2.0, …).
- `dataTypes` and `nodeCategories` are kept as verbatim English
identifiers; option **keys** in
`settings.json`/`menuLabels`/`contextMenu` are left untouched (only
their display values are translated).
- `src/locales/he/nodeDefs.json` is an empty object on purpose, so node
definitions fall back to English and get auto-populated by the release
i18n workflow (per the locale CONTRIBUTING guide).
- Registered `he: { text: 'עברית', loaders: loadersFor('he') }` in
`src/locales/localeConfig.ts` (which automatically adds it to the
Settings → Language dropdown and `SUPPORTED_LOCALE_OPTIONS`).
- Added `he` to `outputLocales` in `.i18nrc.cjs`, plus a Hebrew glossary
block for the CI translator.
## Review Focus
- This follows the approach of #7876 (Persian/Farsi). Like the existing
`ar`/`fa` locales, it translates UI text only and does **not** introduce
RTL layout (`dir="rtl"`) — the app does not currently apply RTL layout
for any locale. I'm happy to follow up with proper RTL layout support in
a separate PR if that's wanted.
- Recurring-term glossary used for consistency: node = צומת, workflow =
תהליך עבודה, queue = תור, widget = פקד, subgraph = תת-גרף, canvas =
קנבס, bypass = עקיפה, prompt = פרומפט.
- Native-speaker review is very welcome. cc translation maintainers
@Yorha4D @KarryCharon @DorotaLuna @shinshin86
## Screenshots
Text-only locale addition — no UI/layout changes. After this change,
**Settings → Language** lists **"עברית"**, and selecting it renders the
UI in Hebrew (untranslated node definitions fall back to English).
---------
Co-authored-by: Yosef Chai <192742853+yosef-chai@users.noreply.github.com>
Co-authored-by: christian-byrne <abolkonsky.rem@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
||
|
|
e2c670bbc3 |
fix: prevent payment routes from being indexed (#12706)
## Summary Allow crawler access to `/payment/` routes in robots.txt so search engines can read the `noindex` tag, and forcefully inject the `x-robots-tag: noindex` header via `vercel.json`. ## Changes - **What**: Removed `Disallow: /payment/` from `robots.txt` and added rules to `vercel.json` applying `x-robots-tag: noindex` to `/payment/(.*)` and `/zh-CN/payment/(.*)` routes. ## Review Focus - The configurations in `vercel.json` apply to both English and localized payment routes (`/zh-CN/payment/(.*)`). --------- Co-authored-by: nav-tej <36310614+nav-tej@users.noreply.github.com> Co-authored-by: Christian Byrne <cbyrne@comfy.org> |
||
|
|
dfcb336499 |
fix: give backport push a token that can update workflow files (#13038)
## Summary The `PR Backport` workflow silently fails for any PR that also modifies a file under `.github/workflows/**`. ## Root cause The `backport` job checks out with the default `GITHUB_TOKEN` and reuses those persisted credentials for `git push`. GitHub refuses to let that token create or update workflow files: ``` ! [remote rejected] backport-12804-to-core-1.45 -> backport-12804-to-core-1.45 (refusing to allow a GitHub App to create or update workflow `.github/workflows/ci-tests-e2e.yaml` without `workflows` permission) error: failed to push some refs ``` The cherry-pick itself succeeds — only the push is rejected. And because the `run:` step inherits `set -e`, the loop aborts before writing the `failed=` output, so the "Comment on failures" step (`if: failure() && steps.backport.outputs.failed`) posts nothing. The result is a red job with no explanation on the PR. ## History PR #12804 touched `.github/workflows/ci-tests-e2e.yaml` and `.github/actions/setup-frontend/action.yaml`. Its backport run ([27788259837](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/27788259837/job/82230406910)) failed exactly this way: cherry-pick clean on every target, push rejected on the workflow file. All four backports (#12966, #12967, #12968, #12969) had to be created manually. ## Changes Check out with `PR_GH_TOKEN` (already used by the Create-PR step) so the push carries `workflow` scope. > [!IMPORTANT] > `PR_GH_TOKEN` must have **workflow** write permission for this to take effect. If it does not, the secret needs that scope added. ## Follow-up (not in this PR) The push failure aborts the whole job under `set -e` with no PR comment. Even with the token fixed, a push rejected for another reason (branch protection, etc.) would still fail silently. Wrapping the push so a single-target failure is recorded as a `push-failed` reason and reported via the existing failure-comment step would make the workflow degrade gracefully. --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
caabebe145 |
Redesign missing model detection contract for promoted subgraph widgets (#13059)
## Summary Redesign missing-model detection for ADR 0009 promoted subgraph widgets so candidates are created from the widget value the user can actually edit, while still using the concrete interior widget as the schema/options source. ## Why This PR Exists This PR comes from the follow-up missing-model detection work for the ADR 0009 / 1.46 subgraph widget changes introduced by [#12197](https://github.com/Comfy-Org/ComfyUI_frontend/pull/12197). [#12197](https://github.com/Comfy-Org/ComfyUI_frontend/pull/12197) intentionally changed promoted subgraph widgets to be represented through subgraph input links. After that change, the promoted widget on the host `SubgraphNode` is the editable value owner, and linked interior widgets are no longer guaranteed to mirror that value. The old missing-model contract still treated the concrete interior node widget as the effective source of truth in subgraph cases: - recursive scans entered the subgraph and scanned the interior widget value; - candidates were keyed by the interior node/widget identity; - the parent subgraph host mostly received propagated highlight/navigation behavior; - subgraph container widgets were not treated as first-class candidate sources. That contract breaks after ADR 0009. A user can resolve a missing model by changing the promoted host widget to an installed model, while the linked interior widget can still hold the old stale value. If detection keeps scanning the linked interior value, entering the subgraph or reloading the workflow can re-create a false missing-model error that no longer corresponds to the value the user can edit. ADR 0009 also means the same subgraph definition can be reused by multiple `SubgraphNode` hosts. Once missing-model detection moves from the interior definition widget to the promoted host widget, the selected value is no longer a property of the shared definition alone. It is a property of a specific host instance. That makes the old interior-node identity insufficient for mode changes, removal handling, and re-scan behavior: a single interior leaf definition can be reachable through multiple host execution paths, and only the affected host path should add, remove, or restore a candidate. This PR also builds on [#12990](https://github.com/Comfy-Org/ComfyUI_frontend/pull/12990), which narrowed workflow-level `models[]` and embedded model data to metadata enrichment only. Together, the intended boundary is: - live widgets create missing-model candidates; - workflow/root-level `models[]` and node metadata only enrich candidates that already came from a live widget; - promoted widget values are read from the editable host widget, not inferred from stale interior `widgets_values`. ## Changes - **What**: - Introduces promoted-widget scan targets that split: - host promoted widget value and candidate identity; - concrete leaf widget/node definition data. - Scans the outermost unlinked promoted widget on a `SubgraphNode` host as the selected value owner. - Skips linked interior widgets as candidate sources, preventing stale linked widget values from producing duplicate or false missing-model candidates. - Resolves the concrete leaf widget for combo options, asset-widget support, node type, directory lookup, and embedded metadata enrichment. - Keys promoted missing-model candidates by the host execution id and host promoted widget name. - Adds `sourceExecutionId` to promoted candidates so liveness still follows the concrete source execution path, including nested inactive subgraph containers. - Uses source-scope activity for pipeline filtering and async verification, while keeping highlight/store/clearing identity host-keyed. - Removes host-keyed promoted candidates when their source execution scope is removed or bypassed. - Re-scans ancestor subgraph hosts when an interior source path is un-bypassed, so host-keyed promoted errors can reappear correctly. - Handles shared subgraph definitions by deriving promoted source paths from the concrete host instance path, rather than treating the shared definition node id as globally unique. - Shares promoted source resolution between Vue node processing and the right-side panel to avoid drift. - Aligns missing-model clearing across Vue node widgets, legacy canvas widgets, and right-side panel Parameters/Nodes section widgets. - Adds unit coverage for scan identity, source-scope liveness, dynamic mode changes, source-scope removal, shared-definition host isolation, and right-side panel clearing. - Adds nested promoted-widget E2E coverage for OSS and Cloud flows across Vue, Parameters tab, and legacy widget surfaces. - **Breaking**: None expected. - **Dependencies**: None. ## New Detection Contract A missing-model candidate is created from an unlinked final editable value owner. That value owner can be: - a normal node model widget; or - the outermost promoted model widget displayed on a `SubgraphNode` host. For promoted widgets: - the host promoted widget supplies the selected value; - the host execution id and host widget name are the candidate identity; - the concrete leaf widget supplies definition data such as combo options and asset-browser support; - the concrete source execution path is retained as `sourceExecutionId` for liveness only; - linked interior widgets are skipped as candidate sources because their values are not authoritative when driven by a promoted input. For a nested chain: `Outer promoted widget A -> inner promoted widget B -> concrete widget C` only `A` creates the candidate. `B` and `C` are linked along the promoted-input path and are skipped as selected-value sources, while `C` still provides the concrete widget definition used to evaluate `A`. ## Shared Definition And Source-Scope Liveness ADR 0009 promoted widgets make subgraphs behave more like reusable definitions with host-owned inputs. Two host `SubgraphNode`s can point at the same interior subgraph definition while carrying different promoted widget values. In that shape, the missing-model candidate must be keyed to the editable host surface, but the activity check cannot use the host id alone. For example, if two outer hosts share the same nested subgraph definition, one host can select a valid model while the other still selects a missing model. The result should be one missing-model reference, not a single definition-level error and not two errors after one host is fixed. Likewise, bypassing or un-bypassing an interior nested container should affect only the host execution paths that actually pass through that container. This PR therefore separates two concepts: - **candidate identity**: host execution id + host promoted widget name, used for storage, highlight, navigation, and clearing; - **candidate liveness**: concrete source execution path, used for scan-time activity checks, pipeline filtering, async verification, source-scope removal, and re-exposure after mode changes. That separation is the reason this PR updates more than the scan itself. Moving the detection target to the subgraph host also requires the mode-change and removal paths to understand that a host-keyed candidate can be invalidated by a descendant source path, and can need to be restored by re-scanning an ancestor host when an interior source path becomes active again. ## Review Focus Please review the identity split carefully: - candidate/store/highlight/clearing identity should remain host-keyed for promoted widgets; - liveness should use `sourceExecutionId` when present, falling back to `nodeId` for normal candidates; - scan-time activity checks should account for the source node itself and all ancestor subgraph containers; - source-scope removal should remove host-keyed candidates whose concrete source path was removed or bypassed; - un-bypassing an interior source path should re-scan affected ancestor subgraph hosts so host-keyed candidates can reappear; - shared subgraph definitions should not merge errors across different host instances; - linked interior widgets should not produce their own missing-model candidates; - asset-browser eligibility should be resolved from the concrete leaf node type and widget name, not the synthetic subgraph host type; - right-side panel edits should clear host missing-model errors and source validation errors consistently. The E2E matrix intentionally keeps nested promoted workflows only. Nested promoted widgets cover the same editable host path as single promoted widgets while also exercising the `A -> B -> C` chain that can break source-scope liveness and re-scan behavior. The nested fixture also includes multiple host instances that share the same subgraph definition, so it verifies that fixing one host does not accidentally clear or suppress another host's missing-model candidate. Direct/single promoted behavior is still covered at the unit level. ## Non-Goals - This PR does not reintroduce workflow-level `models[]` candidate creation. - This PR does not infer selected model values from `widgets_values`. - This PR does not synchronize linked interior widget values back from promoted host widgets. - This PR does not redesign missing-media scanning; missing media still skips subgraph containers and remains keyed by concrete interior paths. The shared async post-verification active-scope filter is intentionally stricter, so a pending missing-media candidate is no longer surfaced if its own node is bypassed or removed while verification is in flight. ## Validation - `pnpm exec vitest run src/components/rightSidePanel/parameters/SectionWidgets.test.ts src/platform/missingModel/missingModelScan.test.ts src/composables/graph/useErrorClearingHooks.test.ts src/platform/missingModel/missingModelPipeline.test.ts src/platform/missingModel/missingModelStore.test.ts src/utils/graphTraversalUtil.test.ts src/composables/graph/useGraphNodeManager.test.ts src/renderer/extensions/vueNodes/composables/useProcessedWidgets.test.ts --reporter=dot` - 8 files passed, 294 tests passed. - `pnpm exec vitest run src/platform/missingModel/missingModelScan.test.ts src/core/graph/subgraph/resolveConcretePromotedWidget.test.ts src/components/rightSidePanel/parameters/SectionWidgets.test.ts` - 3 files passed, 71 tests passed. - `pnpm typecheck` - `pnpm typecheck:browser` - `pnpm format:check` - targeted ESLint for changed production/unit/E2E files - `git diff --check` - `pnpm build` - `pnpm build:cloud` - OSS affected E2E on the 8188 build: - `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 pnpm exec playwright test browser_tests/tests/propertiesPanel/errorsTabModeAware.spec.ts --project=chromium --grep "Changing an OSS .*promoted|Refreshing a resolved promoted|Reloading a resolved nested"` - 5 passed. - Cloud affected E2E on the 8188 cloud build: - `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 pnpm exec playwright test browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts --project=cloud --grep "Changing a Cloud .*promoted"` - 2 passed; the Cloud legacy promoted asset-modal case still fails until [#13075](https://github.com/Comfy-Org/ComfyUI_frontend/pull/13075) is merged. - Full OSS `errorsTabModeAware.spec.ts` on the 8188 build: - 23 passed; 3 existing paste/clipboard cases failed before the promoted subgraph section with node count remaining at 1 after `clipboard.paste()`. - Commit hooks ran `oxfmt`, `oxlint`, `eslint`, `pnpm typecheck`, and browser typecheck where applicable. - Pre-push hook ran `pnpm knip --cache`. ## Screenshots Before https://github.com/user-attachments/assets/6380c1da-1d92-4b70-888e-3ade572c4b5b After https://github.com/user-attachments/assets/4cfc24d6-3dc3-4e36-9b31-72fea6b3d9d5 |
||
|
|
7d3d8ce63f |
feat(website): add /drops landing page (livestream hero + drops grid) (#13053)
## Summary Adds the `/drops` landing page in English and Simplified Chinese, ahead of the 2026-06-24 livestream. The page is composed of a livestream-gated hero, a 10-card drops grid, a subscribe banner, and a closing CTA. Production media for the hero and several cards is wired in; the rest fall back to placeholders. ## Changes - **New `/drops` page** (`pages/drops.astro`, `pages/zh-CN/drops.astro`) plus en/zh-CN translations. - **`HeroLivestream01` block** — renders the rotating-logo video before the stream window, swaps to a YouTube nocookie iframe between `startDateTime` and `endDateTime`. SSR stays deterministic on the logo and only flips to the embed after client hydration. Takes `youtubeVideoId` directly (no URL parsing). - **Drops grid** — `data/drops.ts` defines the 10 cards with `imageFor` / `videoFor` media helpers, badges, and per-locale title/description/href. `DropCard.vue` renders an image or autoplaying muted video inside the new `Card` primitive set (`Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`). - **Supporting blocks** — `SubscribeBanner` uses the Button `link` variant with an animated hover underline; closing `CtaCenter01` is extended with a terms link. `resolveRel` is shared from `utils/cta.ts` instead of duplicated per block. - **Visual extension to `HeroLivestream01.visual`** — discriminated `image | video` union so the hero can render a looping video. - **E2E** — `e2e/drops.spec.ts` covers both locales (hero + grid render, locale-correct links). ## Review Focus - `youtubeVideoId` is currently a `nlLZfNIqF8M` placeholder; `startDateTime`/`endDateTime` are placeholders too — see TODO in `HeroSection.vue`. These need to be swapped to the production stream + window before launch. - Several drop cards still point at placeholder destinations (e.g. Comfy MCP at `/mcp`) — TODO noted in `drops.ts`. - Drop card media is a mix of images and short MP4s served from `media.comfy.org`. The videos autoplay muted/looped with `preload="metadata"`. ## Test plan - [ ] `pnpm --filter website dev` → visit `/drops` and `/zh-CN/drops`; confirm hero video plays, grid renders all 10 cards, video cards loop, subscribe banner link styled correctly - [ ] Temporarily set `startDateTime` to the past and `endDateTime` to the future; confirm hero swaps to the YouTube iframe after hydration - [ ] `pnpm --filter website test:e2e drops.spec.ts` - [ ] `pnpm typecheck:website` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
506e33e7dd |
ci: Update CLA allowlist for GitHub Actions (#13169)
## Summary - Update CLA check `allowlist` to add `GitHub Action` , `action@github.com`, `Glary-Bot` - Reorder list alphabetically |
||
|
|
7376402fc6 |
Essentials tab redesign (#12744)
Subsumes #12304 Redesigns the Essentials tab to be frontend designed with more accessible icons and tighter organization. <img width="381" height="1345" alt="image" src="https://github.com/user-attachments/assets/193f7f5f-20c8-4bf0-8304-ec2c990186d0" /> --------- Co-authored-by: comfydesigner <comfydesigner@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
be38f14619 |
docs: retarget ECS architecture docs to dedicated stores over a single World (#13039)
## Summary Realign the ECS architecture docs and ADR 0008 with the shipped direction (PR #12617): entity data lives in dedicated Pinia stores keyed by string IDs, rather than one unified \"World\" registry addressed by branded entity IDs. ## Changes - **What**: Docs-only. Retarget the `docs/architecture/` set + ADR 0008 + agent guidance from the single-World/branded-`*EntityId` model to the dedicated-store model that PR #12617 actually shipped (`widgetValueStore` keyed by `WidgetId`, `layoutStore`, `nodeOutputStore`, `domWidgetStore`, `subgraphNavigationStore`, `previewExposureStore`). - `AGENTS.md` + `.agents/checks/adr-compliance.md`: point entity-data guidance at dedicated stores; fix the inverted `world.getComponent` compliance check (it flagged correct store-based code). - `ADR 0008`: dated amendment note (stays Proposed); rewrite the World section → dedicated stores, Branded ID design (`WidgetId` composite string), migration strategy, render-loop, consequences, notes. - `proto-ecs-stores.md`: flip the \"Unified World / branded IDs\" framing from gap-to-close → target; replace the deleted `PromotedWidgetViewManager` with the `input.widgetId` store-backed model; fix key formats and store count. - `ecs-target-architecture.md` / `ecs-lifecycle-scenarios.md` / `ecs-migration-plan.md`: reframe all `world.*` APIs and `*EntityId` brands to per-store APIs + string keys; mark already-shipped migration phases done. - `subgraph-boundaries-and-promotion.md` / `entity-interactions.md` / `entity-problems.md`: scope-tagged store entries; swap removed `PromotionStore` for `previewExposureStore`. - `appendix-critical-analysis.md`: post-pivot status banner + resolution notes on the critiques the pivot vindicated; still-open gaps (extension callbacks, atomicity, Y.js↔ECS) left live. - `appendix-ecs-pattern-survey.md`: supersede banner; keep the external library survey (§1). - Delete obsolete `ecs-world-command-api.md` (its command-pattern argument folded into ADR 0008). - **Breaking**: None (documentation only). ## Review Focus - ADR 0008 stays **Proposed** with an amendment note rather than a new superseding ADR — confirm that's the preferred mechanism vs. a fresh ADR. - Numeric per-kind brands (`NodeEntityId`, `LinkEntityId`, …) are retained in ADR 0008 but explicitly marked aspirational/unshipped; only `WidgetId` (composite string) reflects shipped code. - `appendix-ecs-pattern-survey.md` §2–§4 are kept under a supersede banner as historical record (they describe the deleted `src/world/` substrate) rather than rewritten — confirm that's preferred over deletion. - Net −384 lines; no code or test changes. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
13b42d9b59 |
Ensure dynamic combo children cleanup state (#13073)
#12617 introduced a regression in Dynamic Combos. If two options have child widgets of the same name (such as `bit_depth` on `Save Image (Advanced)`), then widget state would be incorrectly shared between the two widgets. This is resolved by having removed widgets also delete their state. There was previous interest in having widgets of this type keep state when valid. This interest remains, but will require a more controlled intentional implementation in the future. Since the bit depth options on `Save Image (Advanced)` could potentially be expanded in the future, this PR specifically adds a new devtools node for testing with. --------- Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
e604c85b88 |
1.47.5 (#13166)
Patch version increment to 1.47.5 **Base branch:** `main` --------- Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com>v1.47.5 |
||
|
|
7ae3ad936c |
When dragging vue nodes, also drag reroutes (#12885)
`selectedItems` was being filtered to nodes and groups. Since no special behaviour is being performed on groups, the 'move groups' code is relaxed to instead 'move all non-node selected items'. |
||
|
|
7b83228cdd |
1.47.4 (#13083)
Patch version increment to 1.47.4 **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: Christian Byrne <cbyrne@comfy.org>v1.47.4 |
||
|
|
d26f578c81 |
refactor(litegraph): delete dead onGetNodeMenuOptions, deprecate onBeforeChange (#12230)
Stacks on #12228. Part of the LGraph dead-hook cleanup per AUDIT-LG.9. ## What - `LGraph.onGetNodeMenuOptions` — **deleted** (field + dispatcher in `LGraphCanvas.getNodeMenuOptions`). Zero ecosystem consumers. - `LGraph.onBeforeChange` — **deprecated, not deleted**. The field and the dispatch in `LGraph.beforeChange()` are kept, but assigning a handler now emits a one-time `warnDeprecated` nudging migration to `LGraphCanvas.onBeforeChange`. ## Why onBeforeChange is preserved The W2F-1 re-audit found `bmad4ever/ComfyUI-Bmad-DirtyUndoRedo` assigns `app.graph.onBeforeChange = fn` (the listener-assignment pattern). Deleting the field outright would silently turn those handlers into no-ops. Keeping it as a deprecated shim preserves backward compatibility during a grace period while signaling the intended replacement. `onAfterChange` is untouched (so `BennyKok/comfyui-deploy`'s `onAfterChange` wrapper keeps working). `LGraphCanvas.onBeforeChange` remains a separate field, and the canvas dispatch chain `this.canvasAction((c) => c.onBeforeChange?.(this))` is unchanged. ## Tests `LGraph.test.ts` covers the shim: the assigned listener is still invoked, the deprecation warning fires when used, and no warning fires when no listener is assigned. ## Sequencing - Stacks on #12228 - Sequences behind Alex's Phase B (#11939, #11811) --------- Co-authored-by: Connor Byrne <c.byrne@comfy.org> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |