mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-26 07:57:36 +00:00
af073de0e8e6e4f2bcca546384d3c19b85bf50ee
7869 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
af073de0e8 |
fix: address CodeRabbit round 3 feedback
- Validate startDownload return value to prevent phantom pending entries - Add toDownloadStatus normalizer for external status values - Replace unsafe 'as DownloadStatus' casts with validated normalization |
||
|
|
a83862bbd5 |
fix: address CodeRabbit round 2 feedback
- Reset _initPromise on failure in store for retry support - Guard electronAPI() before .DownloadManager access - Add concurrent initialize() promise guard in electron provider |
||
|
|
ece3254e9c |
fix: address CodeRabbit review feedback
- Guard concurrent initialize() with shared promise in store - Guard DownloadManager availability with actionable error - Reset initialized flag on transient failure for retry - Clean up empty listener Sets on unsubscribe |
||
|
|
fefddd85f5 |
fix: add downloadServiceStore to knip ignore for stacked PR
The store has no consumers yet — they arrive in follow-up PRs. Follows the existing CustomNodesPanel.vue precedent. |
||
|
|
57f4ee3ae0 |
fix: address review feedback for download service abstraction
- Add DownloadStartParams.tags for cloud category metadata - Guard electron initialize() for idempotency - Add cloud download service unit tests (6 tests) - Use DownloadStartParams type across all providers |
||
|
|
adb7b11a96 |
feat: add download service abstraction with functional composition
Introduce a unified DownloadService interface with per-distribution providers (Electron, Browser, Cloud) selected at build time via __DISTRIBUTION__. Tree-shaking ensures only the active provider ships. Follows the existing createAssetService/createTaskService factory pattern. This is PR 1 of the incremental migration — new files only, no existing code changes yet. Refs: DESK2-47, DESK2-48 |
||
|
|
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) |
||
|
|
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> |
||
|
|
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  ┆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> |
||
|
|
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     ┆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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
aee2e6e6dd |
test: add e2e tests for nested SubgraphNode input target resolution (#11405)
*PR Created by the Glary-Bot Agent* --- ## Summary - Adds four Playwright tests targeting `resolveSubgraphInputTarget` lines 20-31 — the `inputNode.isSubgraphNode()` branch where the target widget is a PromotedWidgetView - These lines had 0% e2e coverage because no existing test loaded a multi-level nested subgraph with VueNodes enabled - Tests use the existing `subgraph-nested-promotion.json` workflow (node 5 → Sub 0 → node 6 → Sub 1), which has outer SubgraphNode inputs connecting to an inner SubgraphNode ## Test cases | Test | Coverage target | Mechanism | |---|---|---| | Nested SubgraphNode promoted widgets render without resolution failures | Lines 20-31 (via VueNodes rendering) | Console warning collection + widget count assertion | | Subgraph input resolves through inner SubgraphNode with PromotedWidgetView | Lines 20-31 (graph structure verification) | `page.evaluate` walks link chain, asserts `isSubgraphNode() === true` and `isPromotedWidgetView === true` | | Promoted widgets from inner SubgraphNode carry correct source identity | Lines 24-31 (source identity) | Asserts widgets with `sourceNodeId === '6'` have correct `sourceWidgetName` | | Serialize and reload preserves nested promoted widget resolution | Lines 20-31 (persistence) | `serializeAndReload()` + polled widget count comparison | ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11405-test-add-e2e-tests-for-nested-SubgraphNode-input-target-resolution-3476d73d365081ab932edc8a01c55c40) 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> Co-authored-by: Connor Byrne <c.byrne@comfy.org> |
||
|
|
2a3b692c0b |
Repair: re-add bug-dump-ingest skill (#11460) — GitHub squash-commit incident recovery, step 2 of 2 (#11630)
*PR Created by the Glary-Bot Agent* --- ## Step 2 of 2 — GitHub squash-commit incident recovery for #11460 This is the companion to #11629. After #11629 (the revert) merges, this PR re-applies the original PR #11460 contents on top of the post-revert `main`, restoring the intended state of the codebase. ### ⚠️ Sequencing — must merge after #11629 Until #11629 is merged, this PR's diff against `main` is empty (because `main` currently still contains the squashed bug-dump-ingest commit that #11629 will revert). After #11629 is merged into `main`, GitHub will recompute the diff and this PR will show a clean re-add of the same 5 `.claude/skills/bug-dump-ingest/` files. ### Verification The branch was constructed by: 1. Branching from `glary/revert-pr-11460` (the revert branch in #11629). 2. `git checkout FETCH_HEAD -- .claude/skills/bug-dump-ingest/` from `refs/pull/11460/head` to restore the exact files. 3. Committing them as a single squash-style commit. I verified that all 5 file blobs are byte-for-byte identical to the original squash commit `559922eaa5c129767c22275c206c6877931ac15c` by comparing git object SHAs: | File | Object SHA | |---|---| | `.claude/skills/bug-dump-ingest/SKILL.md` | `413737835fa1c996291019483effdd39e6da33e5` | | `.claude/skills/bug-dump-ingest/reference/examples.md` | `4fc54a4f14b1359de63f558acca0de48c1b65c57` | | `.claude/skills/bug-dump-ingest/reference/linear-api.md` | `57986740df2ee02c19b81059f0f1e00e54c2a042` | | `.claude/skills/bug-dump-ingest/reference/schema.md` | `84db1a5818c04ee53a94167092ec76dd814992d4` | | `.claude/skills/bug-dump-ingest/reference/verify-commands.md` | `a2c99a43a030ccc3769692d3c09be74132645bb4` | ### Notes - One commit on `refs/pull/11460/head` (an automated lint commit `76ca1598e`) modified `src/renderer/extensions/vueNodes/widgets/components/WidgetChart.test.ts` to remove an `eslint-disable` directive. That change was **not** in the original squash commit on `main` (verified via `git show --stat`), and the directive has separately been removed from `main` by an unrelated commit (#11550), so re-applying that change would now be a no-op. This repair PR therefore intentionally restores **only the 5 bug-dump-ingest files**, matching the original squash commit exactly. - Branch name is `glary/repair-pr-11460` (the `glary/` prefix is required by the tooling; otherwise equivalent to GitHub's suggested `repair-pr-11460`). Refs: #11460, #11629 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11630-Repair-re-add-bug-dump-ingest-skill-11460-GitHub-squash-commit-incident-recovery--34d6d73d365081acbd54c19316561fa9) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
dac3396de8 |
test: add selection paste, rename, and batch rename browser tests (#11367)
*PR Created by the Glary-Bot Agent* --- ## Summary Adds `browser_tests/tests/selectionPasteRename.spec.ts` covering the untested `pasteSelection()` and `renameSelection()` paths in `useSelectionOperations.ts`. ### Coverage gaps filled - `pasteSelection()` — copy → paste creates new nodes - `renameSelection()` single node path — opens title editor - `renameSelection()` batch path — prompt dialog with sequential naming - Empty selection → toast warning ### References - Follows patterns from `selectionToolboxMoreActions.spec.ts` (More Options menu, `selectNodeWithPan`) - 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-11367-test-add-selection-paste-rename-and-batch-rename-browser-tests-3466d73d3650812194a4d8bfbed3dee7) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
d253d87c92 |
Revert "feat: add bug-dump-ingest skill (#11460)" — GitHub squash-commit incident recovery (#11629)
*PR Created by the Glary-Bot Agent* --- ## Step 1 of 2 — GitHub squash-commit incident recovery for #11460 GitHub flagged the squash commit for #11460 (`559922eaa5c129767c22275c206c6877931ac15c`) as affected by the squash-commit incident that produced non-deterministic merges. This PR is **step 1 of 2** in the recovery procedure GitHub asked us to follow. ### What this PR does Reverts `559922eaa5c129767c22275c206c6877931ac15c` (the affected squash commit for #11460, "feat: add bug-dump-ingest skill") on top of current `main`. ### Diff 5 files removed, all under `.claude/skills/bug-dump-ingest/`: - `.claude/skills/bug-dump-ingest/SKILL.md` - `.claude/skills/bug-dump-ingest/reference/examples.md` - `.claude/skills/bug-dump-ingest/reference/linear-api.md` - `.claude/skills/bug-dump-ingest/reference/schema.md` - `.claude/skills/bug-dump-ingest/reference/verify-commands.md` `git revert` applied cleanly with no conflicts. ### Recovery procedure Per GitHub's instructions: 1. **This PR (step 1)** — Revert the affected squash commit. Removes both the original changes and any unintended changes that the incident may have introduced. 2. **Next PR (step 2)** — Re-apply the original PR's changes from `refs/pull/11460/head`, rebased onto post-revert `main`. Will be opened as a separate "repair" PR. ### Review notes - This is a pure revert; please confirm the diff is exactly the inverse of #11460. - After this PR is merged, the companion repair PR will land the original changes back on `main` from a clean source ref, restoring the intended state of the codebase. - Branch name is `glary/revert-pr-11460` (the `glary/` prefix is required by the tool that opened this PR — it's otherwise equivalent to GitHub's suggested `revert-pr-11460`). - Code review: Oracle reviewed and found 0 issues (critical/warning/suggestion all 0). Ready to merge. Refs: #11460 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11629-Revert-feat-add-bug-dump-ingest-skill-11460-GitHub-squash-commit-incident-recove-34d6d73d3650810f9ed3f6068e4f1511) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
4033dde983 |
refactor(website): replace UseCaseSection scroll override with hover on desktop (#11696)
## Summary
Per product feedback, scroll-jacking the page to step through
'Industries that create with ComfyUI' categories feels bad on desktop.
This PR removes the desktop scroll override and switches to hover-driven
imagery on lg+, while preserving the existing pin/scrub interaction on
mobile/touch breakpoints.
## Changes
- **What**:
- Gate `usePinScrub` setup to `(max-width: 1023px)` so the pin/scrub
only runs on touch breakpoints; desktop never engages it.
- Wire `@mouseenter` and `@focus` on each category button to update the
active category on desktop. Click still works on both modes via the
existing `scrollToIndex` (which falls through to a direct ref set when
no ScrollTrigger instance is present).
- Pass the same `(max-width: 1023px)` to `useParallax` via its existing
`mediaQuery` option so parallax doesn't run against the no-longer-pinned
section on desktop.
- Apply the section's `lg:h-[calc(100vh+60px)]` unconditionally on lg+
since pin no longer drives it; mobile height is still managed
dynamically by `usePinScrub`'s `cacheLayout`.
- **Breaking**: None.
- **Dependencies**: None.
## Review Focus
- Mobile path inside `usePinScrub.onMounted` is byte-identical to main —
only the early-return condition gained one extra clause
(`!window.matchMedia('(max-width: 1023px)').matches`), which mobile
evaluates to `false` so it falls through to the existing setup.
- `onCategoryHover` early-returns when `isEnabled` is true, making it a
no-op on mobile (where pin is engaged), so a tap doesn't accidentally
fight the scrub.
- `@focus` is wired alongside `@mouseenter` so keyboard tab navigation
also previews the imagery.
- The previous Lenis-on-macOS workaround from this branch is reverted —
it was only needed because the scroll override existed.
## Screenshots (if applicable)
N/A — interaction change. Test on desktop (≥1024px) by hovering category
labels — imagery should swap with no scroll-jacking. Test on mobile
(<1024px) by scrolling the section; pin/scrub should engage as before.
---------
Co-authored-by: Marwan Ahmed <marwan@Marwans-MacBook-Pro.local>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
|
||
|
|
61a444ed99 |
test: combine duplicated undo/redo and settings dialog E2E tests with test.step (#11835)
## Summary Refactor E2E tests added in #11210 that repeated full prior-test bodies as setup, combining duplicate pairs into single tests with named `test.step()` blocks. ## Changes - **What**: In [`browser_tests/tests/keyboardShortcutActions.spec.ts`](../blob/batch-dispatch/cr-11556/browser_tests/tests/keyboardShortcutActions.spec.ts): - Merge `Ctrl+Z undoes` + `Ctrl+Shift+Z redoes` → single test with two `test.step()` blocks. - Merge `Ctrl+, opens settings dialog` + `Escape closes settings dialog` → single test with two `test.step()` blocks. - **What**: In [`browser_tests/tests/topbarMenuCommands.spec.ts`](../blob/batch-dispatch/cr-11556/browser_tests/tests/topbarMenuCommands.spec.ts): - Merge `Edit > Undo` + `Edit > Redo` → single test with two `test.step()` blocks. The redo step now reuses the post-undo state from its preceding step instead of re-creating and re-undoing the node, removing the duplicated setup the reviewer flagged. ## Review Focus - Naming of combined tests and `test.step()` labels. - Note: per @AustinMroz's [comment thread](https://github.com/Comfy-Org/ComfyUI_frontend/pull/11210#discussion_r3113526265), location 2 in the issue refers to the `Escape closes settings dialog` test (which duplicated the `Ctrl+,` test body), not the `Delete` test (which has unique logic). Treated accordingly. Fixes #11556 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11835-test-combine-duplicated-undo-redo-and-settings-dialog-E2E-tests-with-test-step-3546d73d365081689df3c56bfbb6f4e4) by [Unito](https://www.unito.io) |
||
|
|
385a1d421d |
[chore] Update Comfy Registry API types from comfy-api@84a4468 (#11910)
## Automated API Type Update This PR updates the Comfy Registry API types from the latest comfy-api OpenAPI specification. - API commit: 84a4468 - Generated on: 2026-05-04T15:45:35Z These types are automatically generated using openapi-typescript. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11910-chore-Update-Comfy-Registry-API-types-from-comfy-api-84a4468-3566d73d365081ef8771cb77b5de6119) by [Unito](https://www.unito.io) Co-authored-by: bigcat88 <13381981+bigcat88@users.noreply.github.com> |
||
|
|
341fef46a9 |
refactor: replace unsafe as Error assertions with type guards (#11845)
## Summary Replaces all 7 production `as Error` type assertions with proper `instanceof Error` narrowing or a new `toError()` helper, and adds an ESLint rule to prevent new ones. First slice of #11429 (the `as Error` category — 9 total occurrences, 7 production + 2 in a test file left untouched). ## Changes - **What**: - New `src/utils/errorUtil.ts` exporting `toError(value: unknown): Error` and `getErrorMessage(value: unknown): string | undefined`. `toError` returns the value unchanged if already an `Error`, otherwise wraps it (handles strings, `undefined`, JSON-serializable objects, and circular refs via `String()` fallback). - Refactored 7 production call sites: - `src/services/gateway/registrySearchGateway.ts` — `toError(error)` for `lastError` assignment in fallback loop - `src/platform/cloud/onboarding/auth.ts` (×2) — `toError(error)` for `captureApiError` Sentry calls - `src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioRecorder.ts` — `toError(err)` before forwarding to `options.onError` - `src/extensions/core/load3d/LoaderManager.ts` — replaced `error as Error & { response?: ... }` cast inside `isNotFoundError` with `'response' in error` + nested narrowing - `apps/desktop-ui/src/stores/maintenanceTaskStore.ts` — inline `error instanceof Error ? error.message : String(error)` - `apps/desktop-ui/src/components/maintenance/TaskListPanel.vue` — inline `error instanceof Error ? error.message : undefined` - New ESLint rule (`no-restricted-syntax` block named `comfy/no-unsafe-error-assertion`) banning `TSAsExpression TSTypeReference[typeName.name='Error']` in `src/**` and `apps/*/src/**`, with test files (`*.test.ts`, `*.spec.ts`) excluded. - 12 unit tests for the new helpers in `src/utils/errorUtil.test.ts`. - **Breaking**: none - **Dependencies**: none ## Review Focus - The lint rule is scoped to non-test source files. Test files retain freedom to use `as Error` for fixture construction; only 2 occurrences exist (in `teamWorkspaceStore.test.ts` and `errorDialog.spec.ts`) and they're intentional. - `toError` is duplicated as inline `instanceof` narrowing in `apps/desktop-ui/` rather than imported, since the desktop-ui workspace doesn't share `@/utils/` with the main app and adding a path mapping for one helper felt heavier than two inline guards. - Remaining `as`-on-DOM categories (HTMLElement ×133, HTMLInputElement ×55, HTMLCanvasElement ×36, KeyboardEvent ×7, Element ×3, MouseEvent ×2, Event ×2) are intentionally left for follow-up PRs to keep this one reviewable. Refs #11429 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11845-refactor-replace-unsafe-as-Error-assertions-with-type-guards-3546d73d36508137a015c4f9e8708f23) by [Unito](https://www.unito.io) |
||
|
|
24b548aebc |
fix: route footer Support link to Zendesk help center (#11904)
*PR Created by the Glary-Bot Agent* --- ## Summary The "Support" link in the marketing site footer (Contact column) was reusing the Discord external link. Update it to point at the Zendesk help center at `https://support.comfy.org/hc/en-us`, as requested in the `#website-and-docs` Slack thread. ## Changes - `apps/website/src/config/routes.ts` — add `support` entry to `externalLinks` pointing at `https://support.comfy.org/hc/en-us`. - `apps/website/src/components/common/SiteFooter.vue` — use `externalLinks.support` for the Contact > Support entry instead of `externalLinks.discord`. ## Verification - `pnpm format` and `pnpm exec eslint` clean on both files. - `pnpm typecheck` passes. - Verified locally with `pnpm dev` (Astro on `localhost:4321`); the rendered footer Support link now resolves to `https://support.comfy.org/hc/en-us` (screenshot below). ## Notes Reviewer flagged that `/hc/en-us` forces English and bypasses Zendesk locale negotiation. The exact URL was explicitly requested by the user in the Slack thread, so it is preserved here. Switching to a locale-neutral `https://support.comfy.org/` can be done as a follow-up if desired. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11904-fix-route-footer-Support-link-to-Zendesk-help-center-3566d73d36508189abcff34ae766d3c4) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
6ea278da30 |
[chore] Update Comfy Registry API types from comfy-api@9ec8c25 (#11906)
## Automated API Type Update This PR updates the Comfy Registry API types from the latest comfy-api OpenAPI specification. - API commit: 9ec8c25 - Generated on: 2026-05-04T15:11:04Z These types are automatically generated using openapi-typescript. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11906-chore-Update-Comfy-Registry-API-types-from-comfy-api-9ec8c25-3566d73d365081e394a6c13c0e30499b) by [Unito](https://www.unito.io) Co-authored-by: coderfromthenorth93 <213232275+coderfromthenorth93@users.noreply.github.com> |
||
|
|
560e53c68f |
fix: remove coming soon badge from parallel job execution (#11819)
*PR Created by the Glary-Bot Agent* --- Removes the "coming soon" badge from the Parallel Job Execution feature card on the cloud pricing page (`comfy.org/cloud/pricing`). ## Changes - `apps/website/src/components/pricing/WhatsIncludedSection.vue`: drop `isComingSoon: true` from feature11 so it renders with the standard check icon and no badge. The `isComingSoon` mechanism (clock icon + yellow badge) is preserved in the component for future use on other features. ## Note The FAQ copy elsewhere on the site (`cloud.faq.9.a`) still references "one active job at a time" and "parallel runs soon". That copy will be updated separately. ## Verification - `pnpm typecheck` (website): 0 errors - `pnpm lint`: clean (1 pre-existing warning unrelated to this change) - `pnpm format:check`: clean - `pnpm test:unit` (website): 20 passed - Visual check via Playwright on local dev server (see screenshot) ## Screenshots  ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11819-fix-remove-coming-soon-badge-from-parallel-job-execution-3546d73d365081d19060f976095d03ac) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
1999b7fba0 |
fix: remove (beta) from cloud.faq.3.a (#11905)
*PR Created by the Glary-Bot Agent* --- ## Summary Remove `(beta)` from the `cloud.faq.3.a` translation entry in both English and Simplified Chinese (`zh-CN`), since Comfy Cloud is no longer in beta. ## Changes `apps/website/src/i18n/translations.ts`: - en: `Comfy Cloud (beta) has zero setup...` → `Comfy Cloud has zero setup...` - zh-CN: `Comfy Cloud(测试版)无需任何设置...` → `Comfy Cloud 无需任何设置...` ## Verification - Pre-commit hooks (oxfmt, oxlint, eslint, typecheck, typecheck:website) all passed - Code review (oracle): 0 issues, ready to merge - Manual verification via Playwright on `/cloud` and `/zh-CN/cloud` — FAQ item 3 renders updated copy in both locales (screenshots attached) ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11905-fix-remove-beta-from-cloud-faq-3-a-3566d73d36508150997bcf2c89826091) by [Unito](https://www.unito.io) Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
285421a87c |
feat: add queue progress overlay feature survey (#11560)
*PR Created by the Glary-Bot Agent* --- ## Summary Registers a new nightly feature survey for the Queue Progress Overlay using the existing feature-survey registry (same pattern as the merged node-search survey, PRs #8175/#8355/#9934). - New registry entry `queue-progress-overlay` → Typeform `HZ5saxry`, threshold **16**, 5s display delay. - `trackFeatureUsed()` wired at the major user-initiated handlers inside the overlay so the survey triggers regardless of panel location (floating-right v1 or docked-left v2). - Run button and other ActionBar items that the overlay pops over from are deliberately **not** tracked — tracking is scoped to interactions that originate inside the job panel / queue progress overlay itself. ## Tracked interactions Both variants share most sub-components, so tracking is instrumented once at each logical surface: - **`QueueProgressOverlay.vue`** (v1 container): `viewAllJobs`, `interruptAll`, `cancelQueuedWorkflows`, `onClearHistoryFromMenu`, `toggleAssetsSidebar`, `onCancelItem`, `onDeleteItem`, `inspectJobAsset` - **`QueueOverlayExpanded.vue`**: job tab switches - **`JobHistorySidebarTab.vue`** (v2 docked): job tab switches, `clearQueuedWorkflows`, `onClearHistory`, `onCancelItem`, `onDeleteItem`, `onViewItem` - **`JobFilterActions.vue`** (shared): workflow filter + sort mode selections - **`JobHistoryActionsMenu.vue`** (shared): docked-history toggle + run-progress-bar toggle Deliberately **not tracked** to keep the signal clean: - Hover handlers (ambient preview behaviour) - Search-box keystrokes (debounced typing) - Context menu open and menu-item dispatch — menu actions either bubble through already-tracked terminal handlers (e.g. inspect-asset → `onViewItem`) or are secondary operations (copy-id, open-workflow, download). Avoids double-counting per code review feedback. ## How it works (inherits from existing infrastructure) 1. `surveyRegistry.ts` drives `NightlySurveyController` → `NightlySurveyPopover`, which handles the Typeform embed. 2. Eligibility already gated on `isNightly && !isCloud && !isDesktop`, once-per-user, 4-day global cooldown across all surveys, and opt-out. 3. Typeform response routing to #C0ALLT6Q3SQ is handled on the Typeform side. ## Verification - `pnpm typecheck` ✅ - `pnpm lint` ✅ (no new warnings) - `pnpm knip` ✅ - `pnpm test:unit` on `src/components/queue`, `src/components/sidebar/tabs/JobHistorySidebarTab`, `src/platform/surveys` → **123/123 passing** - Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck) all pass - Manual: dev server + backend boot cleanly, app loads without new runtime errors, `localStorage['Comfy.FeatureUsage']` layout verified to match what `useFeatureUsageTracker` writes ## Notes - Survey key `queue-progress-overlay` covers both v1 (floating-right) and v2 (docked-sidebar) per product guidance: _"This should trigger regardless of the location of the panel (docked from left or floating on right)."_ Both surfaces are the same product feature — the survey is intentionally scoped to the whole job-panel experience. ## Screenshots  ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11560-feat-add-queue-progress-overlay-feature-survey-34b6d73d3650819a9a50fd67fd9b5941) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
5523df1aea |
fix(website): unstretch See all case studies button (#11854)
*PR Created by the Glary-Bot Agent* --- ## Summary The "See all case studies" button on the homepage `CaseStudySpotlightSection` was rendering oddly stretched because it had `class="flex-1 text-center"` while being the sole child of a `flex-row` container — it expanded to fill the entire content column (~592px) instead of sizing to its label. This drops `flex-1`/`text-center` and adds `items-start` to the wrapper so the button sizes to its content and is left-aligned, matching the proportions of every other outline `BrandButton` on the site (Hero, UseCase, customer detail, etc.). ## Changes - `apps/website/src/components/home/CaseStudySpotlightSection.vue`: remove `flex-1 text-center` from the `BrandButton` and align the row's items to the start. `BrandButton` already centers its label internally via `inline-flex … justify-center`, so dropping `text-center` is a no-op visually. ## Before / After - Desktop before: button width = 592px (stretched across the column) - Desktop after: button width = 223px (natural) - Mobile: 1-column layout, now consistently left-aligned ## Review Focus Whether the fix should also live on the `BrandButton` component itself (e.g. a global `max-width`) instead of at the call site. I went with the instance-level fix because every other CTA in the website intentionally uses bare `BrandButton` and lets the content size it; only this one had `flex-1`. A blanket `max-width` would risk changing Hero/MobileMenu buttons that explicitly opt into `w-full lg:w-auto lg:min-w-60`. ## Screenshots    ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11854-fix-website-unstretch-See-all-case-studies-button-3556d73d365081abb3bbe9dbc51cbc07) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> |
||
|
|
65876c635d |
feat(website): add responsive media tooling for marketing assets (#11869)
*PR Created by the Glary-Bot Agent*
---
## Summary
Adds the building blocks for a responsive media system on
`apps/website`, motivated by the gallery video blurriness raised in
Slack. Three independent pieces:
1. **`<SiteVideo>` Vue component + URL helper** — emits a `<video>` with
multiple `<source>` tags, designed to pair with assets named
`${name}-${width}.${format}` on `media.comfy.org`.
2. **`scripts/process-videos.sh`** — local-developer `ffmpeg` helper
that produces VP9/WebM + H.264/MP4 variants and a poster JPG. Not wired
into CI; the team uploads to `media.comfy.org` out-of-band.
3. **Marketing image conventions** — shared `MARKETING_FORMATS` /
`MARKETING_WIDTHS` constants and a README documenting how to render
local marketing images via Astro's built-in `<Picture>` from
`astro:assets`.
This PR is **infrastructure only** — no existing pages are modified.
Adoption (e.g. converting `HeroSection`, gallery videos) is a follow-up.
The new files are added to knip's ignore list with the existing "pending
stacked PR" pattern.
## Why this shape
- **No custom `<Picture>` wrapper.** Astro 5 already ships a
`ResponsiveImage` component (name conflict), and Astro's
`LocalImageProps | RemoteImageProps` discriminated union does not
survive a thin wrapper without unsafe `as` casts. Shared constants give
the consistency benefit at lower cost.
- **No CI media-upload step.** The `Release: Website` workflow currently
only refreshes the Ashby snapshot; wiring GCS uploads into it would
require new secrets and team coordination beyond this PR's scope. The
script runs locally and outputs are uploaded to `media.comfy.org` the
same way as today.
- **Single resolution per `<video>`.** `<source media="...">` inside
`<video>` is unreliable across browsers (Safari ignores it). The script
generates multiple widths so callers can pick one per page; JS-based
selection can be layered on later if metrics demand it.
## What's verified
- `pnpm --filter @comfyorg/website test:unit` — 30 pass (7 new for
`buildVideoSources` / `videoKey`)
- `pnpm --filter @comfyorg/website typecheck` — clean
- `pnpm --filter @comfyorg/website build` — 41 pages built clean
- `pnpm knip` — exit 0
- `oxfmt --check` and `oxlint` clean on all changed files
- `bash -n` on `process-videos.sh` clean; usage and missing-deps paths
exercised manually
- Manual: home page and `/gallery` rendered via `astro dev` — both
unchanged with zero console errors (screenshots attached)
## Review feedback addressed
After Oracle review, three follow-up commits land:
- **`SiteVideo` reactivity** — `sources` is now `computed`; the
`<video>` is keyed on the joined source URLs so it remounts when the
source set changes (browsers don't reload on `<source>` mutation).
- **`SiteVideo` accessibility** — `aria-hidden="true"` only when truly
decorative (no `alt` and no `controls`).
- **Shell script robustness** — probes duration with `ffprobe` and falls
back to `t=0` for clips shorter than 1s; enables `nocaseglob` so
`CLIP.MP4` is picked up.
- **Docs** — clarifies when to use `<SiteVideo>` (lightweight
multi-source) vs `<VideoPlayer>` (captions, controls, scrubber).
## Out of scope (follow-ups)
- Converting existing pages (`HeroSection`, customer detail heros,
gallery) to use the new components. Most current images are CDN-hosted
and migrating them is a separate decision.
- Re-encoding the gallery videos at a higher source width to actually
fix the blurriness — that requires the team to run `process-videos.sh`
against the source clips and re-upload.
- Combining `<SiteVideo>`'s multi-source support with `<VideoPlayer>`'s
rich chrome.
## Screenshots


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11869-feat-website-add-responsive-media-tooling-for-marketing-assets-3556d73d3650818899c7f9ed3204c9a5)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
|
||
|
|
04918360eb |
Use hash lookup for missing asset detection (#11873)
## Summary
Use exact BLAKE3 hash lookups first for missing model/media detection,
and add a separate public-inclusive input asset cache so public input
assets are considered missing-detection candidates without changing the
user-only input assets shown in the UI.
## Changes
- **What**:
- Added `assetService.checkAssetHash()` for `HEAD
/api/assets/hash/{hash}` status-only existence checks.
- Added strict BLAKE3 hash helpers so only `blake3:<64 hex>` media
values and raw 64-hex BLAKE3 model metadata are sent to the hash
endpoint.
- Updated missing media detection to group BLAKE3 candidates by hash,
resolve them through the hash endpoint, and fall back to the legacy
asset list path for invalid/unverifiable/non-hash values.
- Updated missing model detection to use hash lookup for BLAKE3-backed
asset-supported candidates before falling back to the existing node-type
asset matching path.
- Added `assetService.getInputAssetsIncludingPublic()` backed by a
dedicated cache that fetches input assets with `include_public=true` for
missing media fallback checks.
- Kept `assetsStore.inputAssets` user-only for widget/UI display, while
invalidating the public-inclusive missing-detection cache when input
assets may change.
- Added abort handling for paginated asset fetches and shared
public-input cache callers so one aborted caller does not cancel the
shared fetch for other callers.
- Added regression coverage for hash lookup, fallback behavior, abort
paths, public input fallback detection, and cache invalidation.
- **Dependencies**: None.
- **Change size**:
- Production code: 4 files, 400 insertions, 24 deletions, net +376.
- Test code: 4 files, 806 insertions, 59 deletions, net +747.
- Total: 8 files, 1206 insertions, 83 deletions, net +1123.
## Review Focus
- The public-inclusive input asset cache is intentionally separate from
`assetsStore.inputAssets`. The existing store data is user-only and
drives the asset widgets/sidebar, so using it for missing input
detection misses public assets. Making that store public-inclusive would
change UI data semantics; this PR instead keeps the UI dataset unchanged
and adds a missing-detection-specific cache in `assetService`.
- Hash lookup is only used when the workflow exposes a valid BLAKE3
hash. Filename-like values and invalid hash values still use the legacy
fallback path.
- Missing model detection keeps the existing fallback behavior for
non-hash candidates and for hash checks that are invalid or fail
transiently.
- Async model download cache refresh behavior is left unchanged; this PR
avoids coupling model download completion to input asset cache
invalidation.
- No browser/e2e test was added because this changes the missing asset
detection data path, not UI interaction or rendering. The behavioral
coverage is in unit tests for the asset service and the missing
media/model scanners.
## Follow-up Items
- Fix `assetsStore.updateAssetTags()` partial-failure recovery. If
`removeAssetTags()` succeeds and `addAssetTags()` fails, the local model
asset cache can roll back to tags that the backend has already removed;
this should be handled in a focused model asset cache PR.
- Consider extracting shared hash-verification flow used by missing
media and missing model scans after this behavior stabilizes.
- Consider adding a concurrency cap or short-lived request cache for
large workflows with many unique hash lookups.
- Consider splitting `assetService.ts` further, e.g. hash helpers, abort
utilities, and the public-inclusive input asset cache.
- Consider tightening the asset hash service API shape so callers do not
directly depend on HTTP-oriented statuses such as `invalid`.
- Consider adding broader mutation-path coverage for public-inclusive
input cache invalidation once the cache has more consumers.
Linear: FE-534
## Screenshots (if applicable)
Before <false positive / missing image / public asset>
https://github.com/user-attachments/assets/db7ce2a9-b169-4fae-bf9f-98bb93d3ee6d
After
https://github.com/user-attachments/assets/29af9f9e-b536-4fcd-a426-3add40bcb165
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11873-Use-hash-lookup-for-missing-asset-detection-3556d73d36508165babafb16614be0d8)
by [Unito](https://www.unito.io)
|
||
|
|
af70d88860 |
fix: keep finished badge fully opaque in ProgressToastItem (#11542)
## Summary - fix **[slack](https://comfy-organization.slack.com/archives/C0A4XMHANP3/p1776801170742579)** - Move `opacity-50` off the row container onto the asset-name column only, so the contrast badge (white pill, dark label) is not dimmed to gray-on-gray when a download completes. - Matches the Figma intent that the `FINISHED` badge stands out — designer spec uses `base/foreground` for pill, `base/background` for text, which is unreadable when the parent is 50% opacity. <img width="560" height="269" alt="Screenshot 2026-04-23 at 2 46 17 PM" src="https://github.com/user-attachments/assets/fb84aa57-c348-4a86-9a65-9342c12400e1" /> <img width="764" height="332" alt="Screenshot 2026-04-23 at 2 46 41 PM" src="https://github.com/user-attachments/assets/ecbe6a5f-c2e8-4427-9c1d-f8f123009d2e" /> ## Before / After  ## Repro Cloud → trigger a model download → wait for completion → the `FINISHED` badge is the same tone as the toast surface (see Slack thread screenshots). ## Test plan - [ ] Complete a model download in cloud and confirm the `FINISHED` badge is clearly legible in both themes. - [ ] File name + subtitle still appear dimmed to signal the row is completed. - [ ] Running / failed / pending states unchanged. - Fixes [FE-237](https://linear.app/comfyorg/issue/FE-237/fix-honeytoast-badge-text-color-for-finished-job-matches-background) |
||
|
|
c955309b26 |
[chore] Update Comfy Registry API types from comfy-api@911406c (#11518)
## Automated API Type Update This PR updates the Comfy Registry API types from the latest comfy-api OpenAPI specification. - API commit: 911406c - Generated on: 2026-04-17T16:10:40Z These types are automatically generated using openapi-typescript. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11518-chore-Update-Comfy-Registry-API-types-from-comfy-api-911406c-3496d73d36508146a1e2e1ee90640fa4) by [Unito](https://www.unito.io) Co-authored-by: coderfromthenorth93 <213232275+coderfromthenorth93@users.noreply.github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
7abd9d12c8 |
chore(website): refresh Ashby roles snapshot (#11851)
Automated refresh of `apps/website/src/data/ashby-roles.snapshot.json` from the Ashby job board API. **Flow:** 1. `Release: Website` workflow ran (manual trigger). 2. This PR opens with the regenerated snapshot. 3. `CI: Vercel Website Preview` deploys a preview for review. 4. Merging to `main` triggers the production Vercel deploy. The snapshot fallback in `apps/website/src/utils/ashby.ts` remains intact: builds without `WEBSITE_ASHBY_API_KEY` continue to use the committed snapshot. Triggered by workflow run `25260868155`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11851-chore-website-refresh-Ashby-roles-snapshot-3546d73d365081579f98f13f7b58e611) by [Unito](https://www.unito.io) Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> |
||
|
|
dd9cb42fa1 |
feat: add Run your first workflow button to home hero (#11848)
## Summary Add an outline-style `BrandButton` to the right side of the home page hero section linking to the workflows page. ## Changes - **What**: - Added a `Run your first workflow` outline button below the subtitle in `apps/website/src/components/home/HeroSection.vue`, linking to `externalLinks.workflows`. Mirrors the button pattern from `product/local/HeroSection.vue`. - Added `hero.runFirstWorkflow` i18n entry (en + zh-CN) in `apps/website/src/i18n/translations.ts`. ## Review Focus - Confirmed alignment with design spec. <img width="1505" height="776" alt="image" src="https://github.com/user-attachments/assets/215e667d-1827-447b-99b8-eba8cb5ec7e3" /> <img width="335" height="700" alt="image" src="https://github.com/user-attachments/assets/aeac0876-74c3-4e12-a4b3-203f9e541bc2" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11848-feat-add-Run-your-first-workflow-button-to-home-hero-3546d73d365081358d54eddfda71111e) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
ccd19d8695 |
test: add metadata parser coverage (#11307)
## Summary Adds tests for metadata parsers ## Changes - **What**: - add test file generation script - identified & fixed bug in webp exif parsing over-reading - identified & fix bug in mp3/ogg parser where it would read from a fixed position instead of relative, causing incorrect reads throwing RangeError - added catch in latent + json parsing to resolve errors ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11307-test-add-metadata-parser-coverage-3446d73d36508108ac36dddcec0a54d4) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com> |
||
|
|
809fba7b36 |
feat: add Groove Jones customer story (#11849)
## Summary Add a new customer story for Groove Jones — Crocs x NFL FOOH holiday campaign for Dick's Sporting Goods, delivered with Comfy. ## Changes - **What**: - New entry in [`apps/website/src/config/customerStories.ts`](https://github.com/Comfy-Org/ComfyUI_frontend/blob/feat/groove-jones-customer-story/apps/website/src/config/customerStories.ts) registering slug `groove-jones` with cover image hosted on `media.comfy.org/website/customers/groove-jones/`. - Added `customers.story.groove-jones.{category,title,body}` and `customers.detail.groove-jones.topic-1` … `topic-10` translations (en + zh-CN) in [`apps/website/src/i18n/translations.ts`](https://github.com/Comfy-Org/ComfyUI_frontend/blob/feat/groove-jones-customer-story/apps/website/src/i18n/translations.ts). 10 sections matching design sidebar: INTRO, THE OUTPUT, THE PROBLEM, HOW COMFY SOLVED THE PROBLEM, BRAND-TRAINED LORAS, MULTI-MODEL ORCHESTRATION, THE PIPELINE, VERSION CONTROL, FINISHING IN NUKE, THE TAKEAWAY. - Includes 2 pull quotes (Doug Hogan, Dale Carman), 1 final blockquote + author card, and 3 inline images. - Routes `/customers/groove-jones` and `/zh-CN/customers/groove-jones` are auto-generated by `[slug].astro`. ## Review Focus - Contributors author card uses `TBD` placeholder names/roles — to be filled in. - No `readMoreHref` set yet (no public blog post URL). - All 4 images uploaded to `gs://comfy-org-videos/website/customers/groove-jones/` and served via `media.comfy.org`. <img width="1000" height="535" alt="Kapture 2026-05-02 at 23 17 04" src="https://github.com/user-attachments/assets/28654d24-0d49-4303-82ac-b6923cd6bc93" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11849-feat-add-Groove-Jones-customer-story-3546d73d36508128a64bd6809ad77447) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
df2ae6f2d0 |
fix(load3d): dispose THREE.Points GPU resources in clearModel() (#11836)
Fixes #11345 ## Summary `clearModel()` in `SceneModelManager` only traversed and disposed `THREE.Mesh` instances, leaving `THREE.Points` objects (created by `handlePLYModeSwitch()` for point-cloud mode) leaking GPU geometry and material memory on repeated point-cloud loads/clears. ## Changes - `SceneModelManager.ts`: extend the dispose traversal in `clearModel()` to also handle `THREE.Points`, mirroring the pattern already used by `removeAllMainModelsFromScene()`. - `SceneModelManager.test.ts`: add regression test verifying `geometry.dispose()` and `material.dispose()` are called for `THREE.Points` children on `clearModel()`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11836-fix-load3d-dispose-THREE-Points-GPU-resources-in-clearModel-3546d73d365081718338e824bc3e737d) by [Unito](https://www.unito.io) |
||
|
|
3c7781190a |
feat(website): add llms.txt for GEO discovery by AI search agents (#11830)
## Summary Adds `/llms.txt` at the apex following the [llms.txt standard](https://llmstxt.org) — a curated, link-based markdown file that tells LLM-based search agents (ChatGPT search, Perplexity, Claude search, Google AI Overviews, etc.) what's most important on the site. It complements `robots.txt` (crawler permissions) and `sitemap-index.xml` (URL inventory) by giving AI agents a short, prose-friendly index they can ingest into a context window. ## What's in the file 28 links across 6 sections: - **Product** (6) — homepage, Local download, Cloud, Cloud pricing, API, Enterprise - **Workflows and Gallery** (2) — gallery + community workflows site - **Customers and Case Studies** (5) — customers index + 4 named studios (Series Entertainment, Moment Factory, Ubisoft Chord, Open Story Movement) - **Developers and Documentation** (4) — docs.comfy.org, ComfyUI repo, Comfy-Org GitHub org, registry.comfy.org - **Company** (6) — about, careers, contact, blog, privacy, terms - **Optional** (5) — `zh-CN` locale variant, long-form enterprise case studies, blog posts (de-prioritized per spec — agents can skip if context-limited) The intro paragraph names the four product surfaces (Local, Cloud, API, Enterprise), the named customers, and the use-case industries (VFX & animation, advertising, gaming, eCommerce/fashion) — so an agent that ingests only the prose still gets the elevator pitch. ## Verification - All 28 URLs verified live (`HTTP 200`) before commit. - File is plain markdown — no build step. Astro/Vercel will serve it from `apps/website/public/llms.txt` exactly as it serves `robots.txt` (which lives in the same directory and ships at `https://comfy.org/robots.txt`). - Will verify on the Vercel preview deploy after this PR opens that `curl -sI https://<preview>/llms.txt` returns `200` with a sensible `content-type`. (`robots.txt` currently serves as `text/plain; charset=utf-8` — `.txt` will likely do the same; that's fine for AI agents.) ## Decisions - **No `llms-full.txt` yet.** That variant inlines full prose of key pages and requires curating substantive content. Deferred to a follow-up — the marketing-site pages are mostly Vue-rendered hero/feature blocks rather than long-form prose, so a meaningful `llms-full.txt` would need either dedicated copy or a build step that flattens i18n strings + section text. Tracking separately. - **No comment line in `robots.txt`.** I considered adding a `# AI agents: see /llms.txt` comment above the `Sitemap:` directive, but decided against it: (a) the convention is to probe the well-known path `/llms.txt` directly, not to discover it via robots.txt; (b) `robots.txt` was just polished in #11823 with a deliberate compact design and adding a non-standard comment would muddy that; (c) zero implementations I checked actually parse robots.txt for llms.txt hints. Easy to add later if needed. ## Context Third of three follow-ups from the SEO/GEO sweep on 2026-05-02: 1. ~~Comfy-Router: add `X-Content-Type-Options: nosniff` to apex security headers~~ (separate PR on `Comfy-Org/comfy-router`) 2. ~~Cloudflare: enable "Always Use HTTPS"~~ (dashboard toggle, no PR) 3. **This PR** — add `llms.txt` for GEO discovery ## Testing - [x] All linked URLs return 200 - [x] File parses as valid markdown - [ ] Preview deploy serves `/llms.txt` (will verify once preview is up) ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11830-feat-website-add-llms-txt-for-GEO-discovery-by-AI-search-agents-3546d73d365081a98c6bfc5301699f64) by [Unito](https://www.unito.io) |
||
|
|
167a1e6a0c |
fix(website): override X-Robots-Tag to index,follow on production deployment (#11831)
## P0 SEO fix — entire marketing site is currently `noindex` A deep-audit sweep on **2026-05-02** confirmed that every page on `comfy.org` (home, `/about`, `/pricing`, `/customers`, `/careers`, …) is being served with: ``` x-robots-tag: noindex ``` This hides the entire marketing site from Google and other search engines. ### Root cause `comfy.org` reaches the Astro marketing site via a Cloudflare Worker reverse proxy ([`comfy-router`](https://github.com/Comfy-Org/comfy-router)) that does: ```js fetch('https://website-frontend-comfyui.vercel.app/...') ``` Per Vercel's KB article [Avoiding duplicate-content with vercel.app URLs](https://vercel.com/kb/guide/avoiding-duplicate-content-with-vercel-app-urls): > By default, Vercel adds an `X-Robots-Tag: noindex` HTTP header to all deployments hosted on `vercel.app` URLs. […] This header tells search engines like Google not to index these deployment URLs. Because `website-frontend-comfyui.vercel.app` is **not** registered as a Production custom domain on the Vercel project, Vercel applies that header — and our Worker faithfully forwards it back to `comfy.org` clients (and Googlebot). ### Fix Vercel's documented workaround for proxied `*.vercel.app` setups is to override the header via `vercel.json` ([blog post by Dan Denney](https://www.dandenney.com/posts/front-end-dev/fixing-x-robots-nofollow-with-vercel/)): ```json "headers": [ { "source": "/(.*)", "has": [ { "type": "host", "value": "website-frontend-comfyui.vercel.app" } ], "headers": [ { "key": "X-Robots-Tag", "value": "index, follow" } ] } ] ``` ### Why the `has` host filter Critical scoping detail: without the `has` filter, the override would also apply to PR-preview deployments at `comfy-website-preview-pr-N.vercel.app`. We want previews to **stay** `noindex` to avoid duplicate-content competition with production. The filter pins the override to the production deployment hostname only. The hostname matches `WEBSITE_ORIGIN` in `comfy-router/src/index.js`: ```js const WEBSITE_ORIGIN = 'https://website-frontend-comfyui.vercel.app'; ``` ### Defense in depth A parallel PR on `comfy-router` (TBD) will also strip `X-Robots-Tag: noindex` at the Worker layer, so the public `comfy.org` response is correct even if a future Vercel project change re-introduces the upstream header. ### Verification (after merge + Vercel production deploy) ```bash # Production should no longer be noindex curl -sI https://comfy.org/ | grep -i x-robots-tag curl -sI https://comfy.org/about | grep -i x-robots-tag curl -sI https://comfy.org/pricing | grep -i x-robots-tag # Expect: empty output, OR "x-robots-tag: index, follow" # Direct Vercel production hostname curl -sI https://website-frontend-comfyui.vercel.app/ | grep -i x-robots-tag # Expect: "x-robots-tag: index, follow" # Preview deploys must stay noindex (proves the host filter works) curl -sI https://comfy-website-preview-pr-<N>.vercel.app/ | grep -i x-robots-tag # Expect: "x-robots-tag: noindex" ``` ### Pre-merge state (for the record) ``` $ curl -sI https://comfy.org/ | grep -iE 'x-robots-tag|x-served-by' x-served-by: vercel-website x-robots-tag: noindex ``` ### Scope Minimum delta — only `apps/website/vercel.json`. No other files touched. ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11831-fix-website-override-X-Robots-Tag-to-index-follow-on-production-deployment-3546d73d365081489b62e6633d25dfe5) by [Unito](https://www.unito.io) --------- Co-authored-by: Christian Byrne <christian@comfy.org> Co-authored-by: GitHub Action <action@github.com> |
||
|
|
e4e1546458 |
test: add queue notification banners lifecycle browser tests (#11366)
*PR Created by the Glary-Bot Agent* --- ## Summary - Adds `browser_tests/tests/queueNotificationBanners.spec.ts` covering `useQueueNotificationBanners` composable E2E behavior - Adds `data-testid="queue-notification-banner"` to `QueueNotificationBannerHost.vue` for stable test targeting - Registers the new test ID in `TestIds.queue.notificationBanner` ### Test coverage added (7 tests) | Group | Tests | Behavior | |---|---|---| | Queuing lifecycle | 4 | `promptQueueing` → banner appears, `promptQueued` upgrades to queued, batch plural text, requestId mismatch doesn't upgrade | | Auto-dismiss | 1 | Banner disappears after 4s timeout | | FIFO queue | 1 | Second notification shows after first auto-dismisses | | Direct queued | 1 | `promptQueued` without prior `promptQueueing` shows banner directly | ### Approach Tests dispatch `promptQueueing`/`promptQueued` custom events directly via `window.app.api.dispatchCustomEvent()` inside `page.evaluate()`, matching how `app.ts` triggers these events during real queue operations. This avoids needing a running execution pipeline while exercising the full composable → component → DOM rendering chain. ### Verification - TypeScript: zero errors - ESLint: clean - oxlint: clean - oxfmt: formatted - Playwright execution requires running ComfyUI backend (not available in sandbox) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11366-test-add-queue-notification-banners-lifecycle-browser-tests-3466d73d36508172a7ffd3fe3b4fd925) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
c1954028d1 |
feat(ci): add Release:Website workflow to refresh Ashby snapshot (#11829)
## Summary
Adds a unified manual-trigger release flow for the `apps/website`
package
(careers/marketing site at comfy.org), mirroring how main-app releases
work.
**User-facing flow:**
```
workflow_dispatch ──► fresh Ashby pull ──► auto-PR with snapshot bump
│
▼
existing CI / Vercel preview deploy
│
▼
human merges ──► auto prod deploy
```
The careers data on comfy.org comes from Ashby and is fetched at build
time by
`apps/website/src/utils/ashby.ts`. Without `WEBSITE_ASHBY_API_KEY`, the
build
falls back to a committed snapshot at
`apps/website/src/data/ashby-roles.snapshot.json`. That snapshot has
been
going stale because no CI workflow was passing the API key. This PR
fixes
both: a manual refresh workflow + day-to-day secrets wiring.
## Files
**Added**
- `.github/actions/ashby-pull/action.yaml` — composite action that runs
`pnpm --filter @comfyorg/website ashby:refresh-snapshot` with the Ashby
secrets piped in. Uses the existing `setup-frontend` composite for
pnpm/Node setup.
- `.github/workflows/release-website.yaml` — `workflow_dispatch`-only
release workflow. Checks out `main`, refreshes the snapshot via the
composite action, opens a PR labelled `Release:Website` via
`peter-evans/create-pull-request@c0f553fe…` (the same SHA pin used by
`release-version-bump.yaml`).
**Modified**
- `.github/workflows/ci-website-build.yaml` — adds
`WEBSITE_ASHBY_API_KEY`
and `WEBSITE_ASHBY_JOB_BOARD_NAME` env to the `Build website` step.
- `.github/workflows/ci-vercel-website-preview.yaml` — adds the same env
to both `vercel build` steps (preview + production).
## Snapshot fallback preserved
`apps/website/src/utils/ashby.ts` keeps using the committed snapshot
when
the API key is absent (e.g. fork PRs, secret rotation). Verified
locally:
```
$ pnpm --filter @comfyorg/website ashby:refresh-snapshot
Snapshot refresh aborted. Outcome: stale; reason: missing WEBSITE_ASHBY_API_KEY...
```
The release workflow surfaces this as a job failure, which is the
desired
behavior for a manual release trigger.
## Validation
- `yamllint --config-file .yamllint` on all changed YAML — clean
- `./scripts/cicd/check-yaml.sh` — clean
- `pinact run --check` on new files — clean (matches `.pinact.yaml`
policy)
- `pnpm install --frozen-lockfile` — works with `.nvmrc` Node 24
- Husky pre-commit hooks (eslint + typecheck + lint-staged) passed
## Caveats
- **Cannot fully end-to-end test until merged.** `workflow_dispatch`
workflows only run from branches that exist on `main`. The first
manual run can only happen after this PR lands. The pieces that
*can* be tested pre-merge — yamllint, pinact pin validation, and
the existing `CI: Website Build` / `CI: Vercel Website Preview`
workflows now picking up the secret — will run on this PR.
- **`Release:Website` label needs to be created** in the repo before
the auto-PR step will successfully apply it.
`peter-evans/create-pull-request`
will warn but not fail if the label doesn't exist. Suggested color:
`#4f6ef5` (matches `cloud/*` family in `release-branch-create.yaml`).
- The release workflow uses `secrets.PR_GH_TOKEN` (matching
`release-version-bump.yaml`) so the auto-PR can be authored by a
PAT and trigger downstream CI workflows. Without `PR_GH_TOKEN` it
will fall back behavior is up to GitHub Actions defaults — confirm
the secret exists before the first run.
## Context
Came out of work on `comfy-router#22` + `ComfyUI_frontend#11823`
(comfy.org/countdown subpage / website refresh). Discovered the
8+-day-stale snapshot while auditing the website build path.
┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11829-feat-ci-add-Release-Website-workflow-to-refresh-Ashby-snapshot-3546d73d3650811eb300d8bcb593c652)
by [Unito](https://www.unito.io)
|
||
|
|
5cad2c952b |
refactor+test: extract useSubscriptionCheckout composable, rewrite tests (#11396)
## Summary Adds 20 component tests for `SubscriptionRequiredDialogContentWorkspace.vue` covering: - **Initial rendering**: pricing table display, close/back button visibility, out_of_credits reason message - **Close button**: calls onClose callback - **Subscribe click flow**: pricing→preview transitions (new subscription & upgrade), error toasts for disallowed/missing/failed previews, monthly billing cycle - **Back button**: returns from preview to pricing step - **Add credit card**: handles subscribed status (success toast + close), needs_payment_method (opens Stripe URL), error state - **Confirm transition**: success path with close emit, error toast on failure - **Resubscribe**: success path with toast + close, error toast on failure ## Testing ```bash pnpm test:unit -- src/platform/workspace/components/SubscriptionRequiredDialogContentWorkspace.test.ts ``` All 20 tests pass. Quality gates (typecheck, lint, format, knip) pass. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11396-test-add-component-tests-for-SubscriptionRequiredDialogContentWorkspace-3476d73d36508156a218dcb67a2a334e) by [Unito](https://www.unito.io) |
||
|
|
e356addeb6 |
feat: add model links for default workflow (#11308)
We now support detecting the missing models when loading the workflow. But the default workflow didn't include an embedded model link, so users don't know where to download the model or which one to use. Users will see an error when loading the default workflow every time, so I updated it to include the model link. Before <img width="1920" height="1050" alt="image" src="https://github.com/user-attachments/assets/08774480-78ae-41b4-85bd-64b431079ec1" /> After <img width="1920" height="1050" alt="image" src="https://github.com/user-attachments/assets/dcec5a02-94ad-416f-9881-d761f4137fbd" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11308-feat-add-model-links-for-default-workflow-3446d73d365081188978e1d313c38ffe) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com> |
||
|
|
e831daae59 |
feat(website): point robots.txt at /sitemap-index.xml + AI crawler rules (#11823)
## Summary Once [comfy-router#22](https://github.com/Comfy-Org/comfy-router/pull/22) ships, `comfy.org/sitemap-index.xml` will return a unified index aggregating both the website (38 URLs) and workflow-templates sitemaps. This PR: 1. Reverts `Sitemap:` back to `/sitemap-index.xml` (was `/sitemap-0.xml` in #11802 as a workaround for the 404). 2. Adds explicit allow records for 21 search and AI/LLM crawlers (GPTBot, ChatGPT-User, OAI-SearchBot, Google-Extended, ClaudeBot, Claude-Web, anthropic-ai, PerplexityBot, Perplexity-User, Applebot-Extended, Bytespider, Amazonbot, CCBot, Meta-ExternalAgent, Meta-ExternalFetcher, Diffbot, etc.). 3. Adds `Disallow:` for `/_astro/`, `/_website/`, `/_vercel/` — Vercel build artifacts that aren't useful to crawl. ## Why granular UAs Stacked `User-agent:` records (per [RFC 9309 §2.2](https://datatracker.ietf.org/doc/html/rfc9309#section-2.2)) share one rule block. Listing each bot explicitly: - Signals intent to AI bots that look for their UA in robots.txt before crawling more aggressively. - Surfaces our crawl policy clearly to anyone inspecting the file. - Lets us add per-bot Disallows in future without restructuring. ## Merge order ⚠️ **Do NOT merge until comfy-router#22 is deployed to production.** Until then, `/sitemap-index.xml` returns 404 and this PR would re-break the issue PR #11802 patched. Verification: ```bash curl -sI https://comfy.org/sitemap-index.xml # expect: HTTP/2 200, x-served-by: worker-sitemap-index ``` Once that returns 200, this is safe to merge. ## Verification (after merge + deploy) ```bash # robots.txt is served and points at the unified index curl -s https://comfy.org/robots.txt | grep '^Sitemap:' # → Sitemap: https://comfy.org/sitemap-index.xml # Each AI crawler can fetch it for ua in 'GPTBot/1.0' 'ClaudeBot/1.0' 'PerplexityBot/1.0' 'Google-Extended' 'Applebot-Extended'; do curl -s -o /dev/null -w "$ua → %{http_code}\n" -A "$ua" https://comfy.org/robots.txt done # Sitemap is reachable from robots.txt SITEMAP=$(curl -s https://comfy.org/robots.txt | awk -F': ' '/^Sitemap:/ {print $2}') curl -s "$SITEMAP" | xmllint --noout - && echo "valid XML" ``` ## Linear / closes - Closes FE-437 (AI crawler rules) - Updates FE-432 — the robots.txt change in #11802 was a workaround that's no longer needed once #22 ships ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11823-feat-website-point-robots-txt-at-sitemap-index-xml-AI-crawler-rules-3546d73d3650811dbceedd06c00db444) by [Unito](https://www.unito.io) |
||
|
|
96575fcec9 |
feat: redesign cloud onboarding survey for ICP and persona signal (#11628)
## Summary Replaces the 4-step Cloud onboarding survey with a 7-step flow that captures both ICP attributes and user persona dimensions. The survey questions are now populated dynamically from remoteConfig. ## Changes - **What**: New survey questions — Usage, Familiarity, Role, Team size, Industry, Making, Source. Role / Team size / Industry are gated to "Work" usage; Education users see a Student / Educator short list for Role. Most option lists are randomized per visit (familiarity and team size stay ordered as ordinals). \`SurveyResponses\` extended with optional \`usage\`, \`role\`, \`teamSize\`, \`source\` fields. - **Breaking**: None — \`useCase\` and \`workflowRelationship\` remain optional in the type and existing telemetry normalization keeps working unchanged. ## Review Focus - The \`role\` step has a function-form \`options\` so the list can swap based on \`usage\`. \`steps\` is a computed that filters by \`showWhen()\` and resolves the option function — verify reactivity when \`usage\` changes. - Changing \`usage\` clears the previously-picked \`role\` via a watcher to prevent a stale value from carrying over between Work / Education modes. - Per-visit shuffle is stable: option lists are passed through \`randomize()\` once at module load, not on every render. ## Screenshots https://github.com/user-attachments/assets/3602a388-50dc-401e-ada9-ea9016c5052d ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11628-feat-redesign-cloud-onboarding-survey-for-ICP-and-persona-signal-34d6d73d365081f4a792cfe76a987ffb) by [Unito](https://www.unito.io) --------- Co-authored-by: Dante <bunggl@naver.com> |
||
|
|
e7e1ae25a6 |
fix(load3d): suppress error toast on 404 when loading output model file (#11807)
## Summary
- Adds `silentOnNotFound` option to `LoadModelOptions` interface,
threaded through `Load3d.loadModel` → `LoaderManager.loadModel`
- 404 errors (detected via message text or `response.status`) are
silently swallowed when `silentOnNotFound: true`; all other errors still
surface a toast
- Sets `silentOnNotFound: true` for output-folder loads in `load3d.ts`
and `saveMesh.ts` — covers shared workflows opened on a machine that
never ran them
## Test plan
- [x] `LoaderManager.test.ts` — 40 unit tests covering 404 suppression,
non-404 still toasts, stale load handling
- [x] `Load3DConfiguration.test.ts` — 4 unit tests verifying
`silentOnNotFound` propagates correctly through `configureForSaveMesh`
and `configure`
- [x] `load3d.spec.ts` — 2 E2E tests: 404 → no toast, 500 → toast
appears
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes error-handling behavior in the 3D model loading pipeline and
extends method signatures/options; risk is mainly missed call sites or
incorrectly classifying non-404 errors as 404 and hiding real failures.
>
> **Overview**
> Prevents noisy user-facing toasts when an *output* 3D model referenced
by `Preview3D`/`SaveGLB` is missing locally by adding a
`silentOnNotFound` flag and suppressing the "Error loading model" toast
specifically for HTTP 404 failures.
>
> Threads the new `LoadModelOptions` through `Load3d.loadModel` →
`LoaderManager.loadModel` and updates `Load3DConfiguration`/callers to
opt in for output-folder loads, with new unit + Playwright coverage (404
stays silent, non-404 still toasts).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
|
||
|
|
4ed00cec08 |
update: robots.txt to point to /sitemap-0.xml (#11802)
## Summary <!-- One sentence describing what changed and why. --> robots.txt at [comfy.org](https://comfy.org/) references /sitemap-index.xml which returns 404. The actual working sitemap is at /sitemap-0.xml (200, 38 URLs). This blocks search engines from discovering the sitemap. ## Changes - **What**: <!-- Core functionality added/modified --> - Update robots.txt to point to /sitemap-0.xml, OR ## Review Focus <!-- Critical design decisions or edge cases that need attention --> <!-- If this PR fixes an issue, uncomment and update the line below --> <!-- Fixes #ISSUE_NUMBER --> ## Screenshots (if applicable) <!-- Add screenshots or video recording to help explain your changes --> ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11802-update-robots-txt-to-point-to-sitemap-0-xml-3536d73d365081bb9545eb96dd1e8025) by [Unito](https://www.unito.io) |
||
|
|
f566abdd6e |
ci: extract changes-filter composite action; fix docs-only PR stall (#11785)
## Summary Extract a `.github/actions/changes-filter` composite action and adopt it across path-gated CI workflows, fixing the docs-only PR stall and removing duplicated `paths:` / `paths-ignore:` filtering across 8 workflows. ## Background Docs-only PRs stalled on required status checks because workflows using `paths-ignore: ['**/*.md']` never created a check run, while branch protection still required it. Observed on #11776 (the `test` check from `ci-tests-unit.yaml` never appeared). The fix pattern: keep the workflow triggered, gate downstream jobs on a `changes` job whose outputs are computed from a path filter. Skipped jobs count as passing under branch protection. ## What the action emits | Output | Meaning | |---|---| | `should-run` | Any file outside `apps/`, `docs/`, `.storybook/`, `**/*.md` changed. | | `app-website-changes` | Shared deps or `apps/website/**` changed. | | `app-desktop-changes` | Shared deps or `apps/desktop-ui/**` changed. | | `app-frontend-changes` | Shared deps or `src/**` changed. | | `packages-changes` | Shared deps or `packages/**` changed. | | `storybook-changes` | Shared deps or `.storybook/**` changed. | | `docs-changes` | `docs/**` or any `**/*.md` changed (deps NOT folded in). | | `dependency-changes` | Root `package.json`, `pnpm-lock.yaml`, or `pnpm-workspace.yaml` changed. | Shared deps are folded into every `app-*`, `packages-changes`, and `storybook-changes` output so a lockfile bump correctly invalidates each granular gate. Outputs default to `'true'` for non-`pull_request` events to avoid the silent-skip footgun on push / merge_group. ## Workflows migrated | Workflow | Gate | Notes | |---|---|---| | `ci-tests-unit.yaml` | `should-run` | Required check (`test`). Fixes the original stall. | | `ci-tests-e2e.yaml` | `should-run` | Required check (`e2e-status`). Replaces inline filter. | | `ci-perf-report.yaml` | `should-run` | Removes `paths-ignore`. | | `ci-website-build.yaml` | `app-website-changes \|\| packages-changes` | Refactor — not a required check, but moves to job-level gating. Filter scope broadens from `packages/{design-system}` to all `packages/**` (strictly safer). | | `ci-website-e2e.yaml` | `app-website-changes \|\| packages-changes` | Same restructure; `post-starting-comment` also gated to avoid spurious "tests are running" when E2E is skipped. | | `ci-dist-telemetry-scan.yaml` | `should-run` | New gate; was previously running on every PR including docs-only. | | `ci-oss-assets-validation.yaml` | `should-run` | Same. | | `ci-size-data.yaml` | `should-run` | Preserves existing repository guard on the new `changes` job. | | `ci-tests-storybook.yaml` | `storybook-changes \|\| app-frontend-changes \|\| packages-changes` | Gates 4 of 6 jobs. `deploy-production` (push to main) left ungated; `update-comment-with-chromatic` cascades naturally. | ## Branch protection (verified) Required status checks on `main` and `core/**`/`cloud/**`: `test`, `lint-and-format`, `e2e-status`. Only `test` and `e2e-status` use the composite — `lint-and-format` correctly stays unfiltered (must run on docs/apps too). The other 6 migrations are refactor wins (less wasted CI on docs/apps-only PRs), not stall fixes. ## Changes - **What**: New `.github/actions/changes-filter` composite + 8 workflow migrations to consume it. - **Breaking**: None. - **Dependencies**: New pin on `dorny/paths-filter@de90cc6` — already covered by `ci-validate-action-pins`. ## Review Focus - The `should-run` filter excludes `.storybook/**` (granular `storybook-changes` covers it instead). Storybook's gate combines all three: `storybook-changes || app-frontend-changes || packages-changes`. - Two `dorny/paths-filter` steps inside the composite — `predicate-quantifier=every` is required for the negated globs in `should-run` but breaks the multi-pattern OR filters. - The website filter scope intentionally broadens from `packages/{design-system,tailwind-utils}/**` to all `packages/**` for consistency and safety. Fixes #11776 ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11785-ci-extract-changes-filter-composite-action-fix-docs-only-PR-stall-3526d73d36508172a1d7fe8c30fa6453) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> |
||
|
|
3c5695fd42 |
test: add Vue node error/validation ring e2e coverage (#11727)
## Summary Add additional test coverage for vue node errors ## Changes - **What**: - add tests for showing error on missing node, execution error, validation failure & resolved on fix - move ErrorsTabHelper to fixtures dir & update refs - add SLOW_MO env var for headed local tests ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-11727-test-add-Vue-node-error-validation-ring-e2e-coverage-3506d73d365081069ff8f70f7970dd55) by [Unito](https://www.unito.io) |
||
|
|
4fff0c4b49 |
fix: report total file count, not job count, in ZIP export toast (#11737)
## Summary ZIP export toast now reports the total number of files instead of the number of selected jobs when any selected job has multiple outputs. ## Changes - **What**: In `downloadMultipleAssetsAsZip` (`src/platform/assets/composables/useMediaAssetActions.ts`), compute `fileCount` by summing each asset's `outputCount` metadata (fallback 1) and pass it to `mediaAsset.selection.exportStarted` instead of `assets.length`. The existing i18n string already handles `file`/`files` plural. - **Tests**: 3 new unit tests in `useMediaAssetActions.test.ts` covering multi-output, single-output fallback, and mixed selections. The `useToast` and `useI18n` mocks were lifted to hoisted refs so toast call args are assertable. ## Review Focus - Reduce uses `count > 1 ? count : 1`, mirroring the `hasMultiOutputJobs` gate above so a known `outputCount === 1` is still counted as 1 file (no double-counting). - Only `downloadMultipleAssetsAsZip` is touched; OSS individual-download path and direct-download path are unchanged. Fixes #11736 ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11737-fix-report-total-file-count-not-job-count-in-ZIP-export-toast-3516d73d3650811ba78dfdb0a0ae8ea1) by [Unito](https://www.unito.io) --------- Co-authored-by: Alexander Brown <drjkl@comfy.org> |
||
|
|
69dca2d600 |
test: add test coverage for workflow save settings (#11763)
## Summary Add tests for autosave/delay/node sort on save ## Changes - **What**: - add tests ┆Issue is synchronized with this [Notion page](https://app.notion.com/p/PR-11763-test-add-test-coverage-for-workflow-save-settings-3516d73d365081d1b57bc1cf4b2e2ece) by [Unito](https://www.unito.io) |
||
|
|
004530b23a |
fix: search bar layout and autocomplete clipping on Desktop at small sizes (#11713)
## Summary
Fixes two visual bugs in the Desktop app at small window sizes: the
search bar getting pushed/clipped in modal headers, and autocomplete
suggestion dropdowns being cut off by `overflow-hidden` ancestors.
## Changes
- **`SearchAutocomplete.vue`**: Wrap `ComboboxContent` in
`ComboboxPortal` so the suggestions dropdown teleports to `<body>`,
escaping `overflow-hidden` ancestors (fixes z-index clipping in Manager
dialog and other modals using `BaseModalLayout`)
- **`BaseModalLayout.vue`**: Replace `shrink-0` with `min-w-0` on the
header content container so the search bar can shrink at narrow window
sizes instead of overflowing and being clipped by the modal root's
`overflow-hidden`
- **`GraphCanvas.vue`**: Fix dead code where the native drag
(`app-drag`) div was nested inside a `v-if="workflowTabsPosition ===
'Topbar'"` block with its own mutually exclusive condition — move it
before the block and add `pointer-events-auto` so Desktop window
dragging works when tabs are in Sidebar position
## Why no E2E tests
- **`SearchAutocomplete` portal**: The fix is structural (teleport to
`<body>`). A meaningful regression test would require opening the
Manager dialog with a real or mocked extension list — that is a
substantial standalone effort tracked in #11714.
- **`BaseModalLayout` header shrink**: A viewport-resize assertion would
test CSS layout behaviour, not application logic; it would be fragile
and low-value.
- **`GraphCanvas` app-drag**: Desktop/Electron-only.
`-webkit-app-region: drag` cannot be exercised in headless Chromium.
Unit tests for `SearchAutocomplete` cover the new code paths (portal
rendering, suggestion display, item selection).
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Low risk UI-only changes: adjusts layout CSS and combobox rendering
via `ComboboxPortal`, plus adds unit tests; no business logic or data
flow changes.
>
> **Overview**
> Fixes small-window Desktop UI issues where modal-header search inputs
could be clipped and autocomplete dropdowns could be cut off by
`overflow-hidden` ancestors.
>
> `SearchAutocomplete` now renders its suggestions list inside a
`ComboboxPortal` (teleporting the popper content outside clipping
containers) and adds a focused unit test suite covering empty/non-empty
suggestions, selection behavior, and `optionLabel` handling.
>
> `BaseModalLayout` tweaks header flexbox constraints (`min-w-0` on the
header content container) to allow the search bar to shrink instead of
overflowing.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
|