Commit Graph

7006 Commits

Author SHA1 Message Date
Alexander Brown
9ae85068eb feat: Transparent background for the Image and Video Previews (#9455)
## Summary

Less jarring appearance, especially with different aspect ratios or
Alpha channels.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9455-feat-Transparent-background-for-the-Image-and-Video-Previews-31b6d73d3650819eaa82def10e66da21)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
v1.41.13
2026-03-05 18:06:53 -08:00
Comfy Org PR Bot
23bb5f2afa 1.41.13 (#9452)
Patch version increment to 1.41.13

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9452-1-41-13-31b6d73d3650819db118e6455c555bce)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-03-05 18:05:01 -08:00
Christian Byrne
ef4e4a69d5 fix: enable enforce-consistent-class-order tailwind lint rule (#9428)
## Summary

Enable `better-tailwindcss/enforce-consistent-class-order` lint rule and
auto-fix all 1027 violations across 263 files. Stacked on #9427.

## Changes

- **What**: Sort Tailwind classes into consistent order via `eslint
--fix`
- Enable `enforce-consistent-class-order` as `'error'` in eslint config
- Purely cosmetic reordering — no behavioral or visual changes

## Review Focus

Mechanical auto-fix PR — all changes are class reordering only. This is
the largest diff but lowest risk since it changes no class names, only
their order.

**Stack:** #9417#9427 → **this PR**

Fixes #9300 (partial — 3 of 3 rules)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9428-fix-enable-enforce-consistent-class-order-tailwind-lint-rule-31a6d73d3650811c9065f5178ba3e724)
by [Unito](https://www.unito.io)
2026-03-05 17:24:34 -08:00
Dante
60267fc64c refactor: unify image classification and fix cloud preview param handling (#9408)
## Summary

Addresses review feedback from PR #9298 and resolves the divergence
between `ResultItemImpl.isImage` and `appendCloudResParam`'s image
classification.

### Changes

- **Unify suffix-based classification**: Replace narrow
`isImageBySuffix` (gif/webp only), `isVideoBySuffix` (webm/mp4), and
`isAudioBySuffix` with `getMediaTypeFromFilename()` from
shared-frontend-utils, using the same `IMAGE_EXTENSIONS` set (png, jpg,
jpeg, gif, webp, bmp, avif, tif, tiff) that `appendCloudResParam` uses
- **imageCompare.ts**: Pass `record.filename` to `appendCloudResParam`
(was called without filename, bypassing image-extension guard)
- **imagePreviewStore.ts**: Use per-image `image.filename` instead of
first image's filename for all images in batch
- **LinearControls.vue**: Use `resultItem.filename` (already a string)
instead of `String(filename)` which converts undefined to `"undefined"`

### Related review comments

- [imageCompare.ts — missing
filename](https://github.com/Comfy-Org/ComfyUI_frontend/pull/9298#discussion_r2886137498)
- [imagePreviewStore.ts — per-image
filename](https://github.com/Comfy-Org/ComfyUI_frontend/pull/9298#discussion_r2886138718)
- [LinearControls.vue —
String(filename)](https://github.com/Comfy-Org/ComfyUI_frontend/pull/9298#discussion_r2886140159)
- [queueStore.ts — diverging image
classification](https://github.com/Comfy-Org/ComfyUI_frontend/pull/9298#discussion_r2886142886)

## Test plan

- [x] 66 unit tests pass (queueStore + cloudPreviewUtil)
- [x] `pnpm typecheck` passes
- [x] `pnpm lint` passes

- Fixes #9386

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 17:20:18 -08:00
Christian Byrne
47f2b63628 fix: prevent persistent loading state when cycling batches with identical URLs (#8999)
## Summary

Fix persistent loading/skeleton state when cycling through batch images
or videos that share the same URL (common on Cloud).

## Changes

- **What**: In `setCurrentIndex()` for both `ImagePreview.vue` and
`VideoPreview.vue`, only start the loader when the target URL differs
from the current URL. When batch items share the same URL, the browser
doesn't fire a new `load`/`loadeddata` event since `src` didn't change,
so the loader was never dismissed.
- Also fixes `VideoPreview.vue` navigation dots using hardcoded
`bg-white` instead of semantic `bg-base-foreground` tokens.

## Review Focus

This bug has regressed 3+ times (PRs #6521, #7094, #8366). The
regression tests specifically target the root cause — cycling through
identical URLs — to prevent future reintroduction.

Fixes
https://www.notion.so/comfy-org/Bug-Cycling-through-image-batches-results-in-persistent-loading-state-on-Cloud-30c6d73d3650816e9738d5dbea52c47d

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8999-fix-prevent-persistent-loading-state-when-cycling-batches-with-identical-URLs-30d6d73d36508180831edbaf8ad8ad48)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com>
2026-03-05 17:14:40 -08:00
Christian Byrne
1221756e05 fix: enable enforce-canonical-classes tailwind lint rule (#9427)
## Summary

Enable `better-tailwindcss/enforce-canonical-classes` lint rule and
auto-fix all 611 violations across 173 files. Stacked on #9417.

## Changes

- **What**: Simplify Tailwind classes to canonical forms via `eslint
--fix`:
  - `h-X w-X` → `size-X`
  - `overflow-x-hidden overflow-y-hidden` → `overflow-hidden`
  - and other canonical simplifications
- Enable `enforce-canonical-classes` as `'error'` in eslint config

## Review Focus

Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes; canonical forms are functionally
identical.

**Stack:** #9417 → **this PR** → PR 3 (class order)

Fixes #9300 (partial — 2 of 3 rules)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9427-fix-enable-enforce-canonical-classes-tailwind-lint-rule-31a6d73d365081a49340d7d4640ede45)
by [Unito](https://www.unito.io)
2026-03-05 17:07:46 -08:00
Alexander Brown
1bac5d9bdd feat: workflow sharing and ComfyHub publish flow (#8951)
## Summary

Add workflow sharing by URL and a multi-step ComfyHub publish wizard,
gated by feature flags and an optional profile gate.

## Changes

- **What**: Share dialog with URL generation and asset warnings;
ComfyHub publish wizard (Describe → Examples → Finish) with thumbnail
upload and tags; profile gate flow; shared workflow URL loader with
confirmation dialog
- **Dependencies**: None (new `sharing/` module under
`src/platform/workflow/`)

## Review Focus

- Three new feature flags: `workflow_sharing_enabled`,
`comfyhub_upload_enabled`, `comfyhub_profile_gate_enabled`
- Share service API contract and stale-share detection
(`workflowShareService.ts`)
- Publish wizard and profile gate state management
- Shared workflow URL loading and query-param preservation

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8951-feat-share-workflow-by-URL-30b6d73d3650813ebbfafdad775bfb33)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-03-05 16:33:06 -08:00
Robin Huang
6c2680f0ba feat: Add PostHog telemetry provider (#9409)
Add PostHog as a telemetry provider for cloud builds so custom events
can be correlated with session recordings. Follows the same pattern as
MixpanelTelemetryProvider with dynamic import, event queuing, and
disabled events from remote config. Tree-shaken away in OSS builds.

The posthog-js package uses Apache-2.0 (verified from its LICENSE file)
but declares it as "SEE LICENSE IN LICENSE" in package.json, which
  the license checker can't parse.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9409-feat-Add-PostHog-telemetry-provider-31a6d73d3650818b8e86c772c6551099)
by [Unito](https://www.unito.io)
2026-03-05 16:19:35 -08:00
Dante
5843dced84 feat: add Storybook stories for WidgetInputText and WidgetTextarea (#9398)
Add Storybook stories for WidgetInputText and WidgetTextarea, aligned
with the Figma Design System spec.

Task: COM-15821

## Summary

Add comprehensive Storybook stories for text widget components and
implement missing Figma design system variants for WidgetInputText.

## Changes

- **WidgetInputText component enhancements**:
- Add `size` prop (`medium` | `large`) matching Figma size variants
(32px / 40px)
- Add `invalid` prop with destructive border style per Figma Invalid
state
- Add `loading` prop showing spinning loader icon per Figma Status state
  - Add hover background (`bg-component-node-widget-background-hovered`)
  - Fix `readonly` not being applied from `widget.options.read_only`
- **WidgetTextarea component fixes**:
  - Show copy button on hover for all states (not just read-only)
  - Apply `text-component-node-foreground` token to copy icon
  - Add hover background to wrapper
- **Storybook stories**:
- WidgetInputText: Default, Disabled, Invalid, Status, WithPlaceholder,
WithLabel stories
- WidgetTextarea: Default, Disabled, HiddenLabel, WithPlaceholder
stories
  - Interactive controls for size, readOnly, disabled, invalid, loading

## Review Focus

- Figma alignment: size/invalid/loading/status variants for
WidgetInputText
- Copy icon color token (`text-component-node-foreground`) for
light/dark theme support
- `layoutWidget` computed pattern to merge `borderStyle` with invalid
state

## Screenshots (if applicable)

<!-- Add screenshots or video recording to help explain your changes -->

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 08:42:53 +09:00
Christian Byrne
b2915ed42a refactor: extract shared createMockWidget factory for widget component tests (#9423)
## Summary

Extract a shared `createMockWidget` test factory to eliminate duplicated
`SimplifiedWidget` object construction across 13 widget component test
files.

## Changes

- **What**: Add `widgetTestUtils.ts` with a generic
`createMockWidget<T>` factory providing sensible defaults (`name`,
`type`, `options`). Refactor 13 test files to delegate to it via thin
local wrappers that supply component-specific defaults (combo values,
slider ranges, etc.).

## Review Focus

- The shared factory only covers `SimplifiedWidget`-based tests. Three
files using different base types (`NodeWidgets.test.ts`,
`useRemoteWidget.test.ts`, `useComboWidget.test.ts`) are intentionally
excluded.
- `mountComponent` helpers remain per-file since plugin/component setups
vary too much to share.

Fixes #5554

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9423-refactor-extract-shared-createMockWidget-factory-for-widget-component-tests-31a6d73d36508159b65ee0e7b49212c3)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
2026-03-05 15:39:41 -08:00
Christian Byrne
df69d6b5d4 feat: add Amp code review checks (#9445)
## Summary

Add 22 automated code review check definitions and 1 strict ESLint
config to `.agents/checks/` for Amp-powered code review.

## Changes

- **What**: 23 files in `.agents/checks/` covering accessibility, API
contracts, architecture, bug patterns, CodeRabbit integration,
complexity, DDD structure, dependency/secrets scanning, doc freshness,
DX/readability, ecosystem compatibility, error handling, import graph,
memory leaks, pattern compliance, performance, regression risk,
security, SAST, SonarJS linting, test quality, and Vue patterns. Each
check includes YAML frontmatter (name, description, severity-default,
tools) and repo-specific guidance tailored to ComfyUI_frontend
conventions.

## Review Focus

- Check definitions are config-only (no runtime code changes)
- Checks reference repo-specific patterns (e.g., `useErrorHandling`
composable, `useToastStore`, `es-toolkit`, Tailwind 4, Vue Composition
API)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9445-feat-add-Amp-code-review-checks-31a6d73d3650817a8466fe2f4440a350)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-03-05 15:29:30 -08:00
Christian Byrne
bab1d34634 fix: stabilize flaky screenshot tests that rely on search box timings (#9426)
## Summary

Fixes flaky screenshot test that was identified during the PR #9400
snapshot update, where baselines regenerated without any code changes
affecting them.

**Root cause:** `fillAndSelectFirstNode('KSampler')` selected `nth(0)`
from the autocomplete dropdown, but search result ordering is
non-deterministic when the search box opens via link release with filter
chips. Sometimes 'Preview Image' appeared as the first result instead of
'KSampler', causing a completely different node to be added.

**Fix:** Added an `exact: true` option to `fillAndSelectFirstNode` that
uses an `aria-label` selector to click the specific matching result
instead of blindly selecting the first item.

- Fixes #4658

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9426-fix-stabilize-flaky-screenshot-tests-for-search-results-and-image-preview-31a6d73d365081598167ce285416995c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-03-05 15:28:22 -08:00
Christian Byrne
e7588c33e1 refactor: rename imagePreviewStore to nodeOutputStore (#9416)
## Summary

Rename `imagePreviewStore.ts` → `nodeOutputStore.ts` to match the store
it houses (`useNodeOutputStore`, Pinia ID `nodeOutput`).

## Changes

- **What**: Rename file + test file, update all 21 import paths, mock
paths, and describe labels
- **Breaking**: None — exported symbol (`useNodeOutputStore`) and Pinia
store ID (`nodeOutput`) are unchanged

## Custom Node Ecosystem Audit

Searched the ComfyUI custom node ecosystem for `imagePreviewStore` and
`useNodeOutputStore`:
- **Not part of the public API** — neither filename nor export appear in
`comfyui_frontend_package` or `vite.types.config.mts`
- **1 external repo found:** `wallen0322/ComfyUI-AE-Animation` —
contains a full fork of the frontend source tree; it copies the file
internally and does not import from the published package. **No
breakage.**
- **No custom nodes import this store via the extension API.** This is a
safe internal-only rename.

## Review Focus

Pure mechanical rename — no logic changes. Verify no stale
`imagePreviewStore` references remain.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9416-refactor-rename-imagePreviewStore-to-nodeOutputStore-31a6d73d3650816086c5e62959861ddb)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-05 13:52:50 -08:00
Yourz
5c7851a727 fix: clean up essential node card and tab list styling (#9438)
## Summary

Remove unnecessary styling from EssentialNodeCard and
NodeLibrarySidebarTabV2 tab list.

## Changes

- **What**:
  - Remove `justify-between` from TabsList in NodeLibrarySidebarTabV2;
  - remove `border border-component-node-border` from EssentialNodeCard.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9438-fix-clean-up-essential-node-card-and-tab-list-styling-31a6d73d3650817facf1c648568ac6bd)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-03-05 12:28:25 -08:00
Alexander Brown
63399d6ec1 test: regenerate screenshot expectations (#9442)
The pixels fade, the tests turn red,
Old screenshots haunt us from the dead.
A branch is born, a label placed,
And golden images are replaced.

The shards spin up, four workers strong,
To right what rendering got wrong.
When CI turns green, the deed is done—
New expectations, freshly won.

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-03-05 19:59:44 +00:00
jaeone94
25d8384716 fix(ErrorNodeCard): show error message body in compact (single-node) mode (#9437)
## Summary
Remove the `!compact` condition that was preventing the error message
body from being displayed in compact (single-node error) mode.

## Changes
- **What**: Removed `&& !compact` guard from `v-if="error.message &&
!compact"` in `ErrorNodeCard.vue` so the error message body is always
shown when present, regardless of display mode

<img width="1209" height="605" alt="image"
src="https://github.com/user-attachments/assets/b720c9fa-2789-441d-aa4b-7850fe370436"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9437-fix-ErrorNodeCard-show-error-message-body-in-compact-single-node-mode-31a6d73d3650814683f7e6983534a4ad)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-03-05 05:03:59 -08:00
Christian Byrne
c817563cf0 feat: GLSLPreviewEngine + GLSL utility functions (#9200)
## Summary

Standalone WebGL2 rendering engine for client-side GLSL shader preview,
with utility functions that mirror the backend `nodes_glsl.py` detection
logic.

## Changes

- **What**: New `GLSLPreviewEngine` class (OffscreenCanvas + WebGL2),
`glslUtils.ts` (detectOutputCount, detectPassCount,
hasVersionDirective), and unit tests
- **GLSLPreviewEngine**: Fullscreen triangle via `gl_VertexID` (no VBO),
ping-pong FBOs for multi-pass rendering, MRT via `gl.drawBuffers()`,
blob output via `canvas.convertToBlob()`
- **glslUtils**: Pure functions ported from backend Python to
TypeScript, regex-based detection matching `_detect_output_count()` and
`_detect_pass_count()`

## Review Focus

- WebGL2 resource lifecycle (context loss, texture cleanup, FBO teardown
in `dispose()`)
- Ping-pong FBO logic for multi-pass shaders
- Engine tests are WebGL2-gated (`describe.skip` in happy-dom) — they
run in real browser environments

## Stacked PR

PR 2 of 3. Stacked on #9198 (fix: GLSLShader preview promotion).
PR 3: `feat/glsl-live-preview` (composable + LGraphNode.vue integration)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9200-feat-GLSLPreviewEngine-GLSL-utility-functions-3126d73d3650812fadc6df4a26387d0e)
by [Unito](https://www.unito.io)
2026-03-05 03:04:33 -08:00
pythongosssss
5376b7ed1e feat: App mode empty graph handling (#9393)
## Summary

Adds handling for entering app mode with an empty graph prompting the
user to load a template as a starting point

## Changes

- **What**: 
- app mode handle empty workflows, disable builder button, show
different message
- fix fitView when switching from app mode to graph

## Review Focus

Moving the fitView since the canvas is hidden in app mode until after
the workflow is loaded and the mode has been switched back to graph, I
don't see how this could cause any issues but worth a closer eye

## Screenshots (if applicable)

<img width="1057" height="916" alt="image"
src="https://github.com/user-attachments/assets/2ffe2b6d-9ce1-4218-828a-b7bc336c365a"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9393-feat-App-mode-empty-graph-handling-3196d73d3650812cab0ce878109ed5c9)
by [Unito](https://www.unito.io)
2026-03-05 02:27:05 -08:00
pythongosssss
e0089d93d0 feat: App mode progress updates (#9375)
## Summary

- move progress bar below preview thumbnail instead of overlaying it
- add interactive pending placeholder
- fix: scope in-progress items to active workflow in output history

## Screenshots (if applicable)

<img width="209" height="86" alt="image"
src="https://github.com/user-attachments/assets/46590fdc-3df9-4a40-8492-a54e63e3f44c"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9375-feat-App-mode-progress-updates-3196d73d3650817ea891c9e744893846)
by [Unito](https://www.unito.io)
2026-03-05 02:26:03 -08:00
jaeone94
5fc82823ef feat: add manager enable hint for OSS local users (#9377)
## Summary

When ComfyUI Manager is disabled, OSS local users see a hint in the
Missing Nodes panel explaining how to install and enable it.

## Changes

- **What**: Added an inline hint in `MissingNodeCard` that renders when
the user is on OSS (non-Cloud) and Manager is not active
(`showInfoButton` is false). The hint shows the pip install command and
the `--enable-manager` startup flag, formatted as inline `<code>`
snippets via `i18n-t` interpolation.

## Review Focus

- The `showManagerHint` computed is intentionally simple: `!isCloud &&
!props.showInfoButton`. `showInfoButton` is the existing signal for
whether Manager is available/enabled.
- Styling uses existing semantic tokens (`bg-comfy-menu-bg`,
`text-comfy-input-foreground`) to match the rest of the panel.

## Screenshot
<img width="642" height="452" alt="image"
src="https://github.com/user-attachments/assets/d08280d3-b4a0-4613-b092-1baa49f0b091"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9377-feat-add-manager-enable-hint-for-OSS-local-users-3196d73d365081a19037c8f55f11d1eb)
by [Unito](https://www.unito.io)
2026-03-05 00:20:25 -08:00
Jin Yi
b521e75c6a [feat] Add model metadata fetching with loading skeleton and gated repo support (#9415)
## Summary
- Fetch file sizes via HEAD requests (HuggingFace) and Civitai API with
caching and request deduplication
- Show skeleton loader while metadata is loading
- Display "Accept terms" link for gated HuggingFace models instead of
download button

## Changes
- **`missingModelsUtils.ts`**: Add `fetchModelMetadata` with Civitai API
support, HuggingFace gated repo detection, in-memory cache, and inflight
request deduplication
- **`MissingModelsContent.vue`**: Add Skeleton loading state, gated
model "Accept terms" link, extract `showSkeleton` helper
- **`missingModelsUtils.test.ts`**: Tests for HEAD/Civitai fetching,
gated repo detection, caching, and deduplication
- **`main.json`**: Add `acceptTerms` i18n key

## Related Issues
https://github.com/Comfy-Org/ComfyUI_frontend/issues/9410
https://github.com/Comfy-Org/ComfyUI_frontend/issues/9412


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9415-feat-Add-model-metadata-fetching-with-loading-skeleton-and-gated-repo-support-31a6d73d36508127859efa0b3847505e)
by [Unito](https://www.unito.io)
2026-03-04 23:59:17 -08:00
Christian Byrne
493b1e42aa fix: enable no-deprecated-classes tailwind lint rule (#9417)
## Summary

Enable `better-tailwindcss/no-deprecated-classes` lint rule and auto-fix
all 103 violations across 65 files. First PR in a stacked series for
#9300.

## Changes

- **What**: Replace deprecated Tailwind v3 classes with v4 equivalents:
  - `rounded` → `rounded-sm` (85)
  - `flex-shrink-0` → `shrink-0` (16)
  - `flex-grow` → `grow` (2)
- Enable `no-deprecated-classes` as `'error'` in eslint config
- Update one test asserting on `'rounded'` class string

## Review Focus

Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes (Tailwind v4 aliases these classes
identically).

Fixes #9300 (partial — 1 of 3 rules)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9417-fix-enable-no-deprecated-classes-tailwind-lint-rule-31a6d73d3650819eaef4cf8ad84fb186)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-05 07:41:23 +00:00
Yourz
7cd11f0da5 fix: clean up unused icons and add LoadImage lucide icon override (#9359)
## Summary

Remove 46 unused snake_case SVG icons from design-system and use lucide
icon for LoadImage.

## Changes

- **What**: Remove unreferenced snake_case SVG files, replace LoadImage
custom icon with `lucide--image-up`, add `preview-image.svg` (renamed
from `image-preview.svg` to match `kebabCase('PreviewImage')`), extract
`ESSENTIALS_ICON_OVERRIDES` to `essentialsNodes.ts`
- Remove `load-image` from safelist in `style.css`

<img width="307" height="701" alt="image"
src="https://github.com/user-attachments/assets/de5e1bde-03eb-415e-ac76-f2e653a5eeb2"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9359-fix-clean-up-unused-icons-and-add-LoadImage-lucide-icon-override-3186d73d36508159be05ce6f4145be56)
by [Unito](https://www.unito.io)
2026-03-05 15:31:41 +08:00
Jin Yi
706060a2bf [refactor] Replace PrimeVue ProgressSpinner with Lucide loader icon (#9372)
## Summary
- Replace PrimeVue `ProgressSpinner` with Lucide `loader-circle` icon in
App.vue and WorkspaceAuthGate.vue
- Use white color for loading spinner for better visibility on dark
backgrounds
- Remove `primevue/progressspinner` imports and update related test

## Changes
- **App.vue**: Replace `ProgressSpinner` with
`icon-[lucide--loader-circle]`
- **WorkspaceAuthGate.vue**: Same replacement
- **WorkspaceAuthGate.test.ts**: Remove ProgressSpinner mock, use
`.animate-spin` selector

## Review Focus
- Visual consistency of white spinner on dark background during initial
load

<img width="1596" height="1189" alt="스크린샷 2026-03-04 오후 6 28 27"
src="https://github.com/user-attachments/assets/d703db74-4123-4328-912a-45ac45cf6eeb"
/>
<img width="1680" height="1304" alt="스크린샷 2026-03-04 오후 6 28 24"
src="https://github.com/user-attachments/assets/8026d10a-7e06-4f95-849c-bc891756823c"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9372-refactor-Replace-PrimeVue-ProgressSpinner-with-Lucide-loader-icon-3196d73d3650815bb1d1d4554f7f744e)
by [Unito](https://www.unito.io)
2026-03-05 16:23:22 +09:00
Christian Byrne
c2fc0c0f03 fix: make HoneyToast responsive on small screens (#9429)
## Summary

HoneyToast overflows on screens narrower than 400px because the expanded
content uses a fixed `max(400px, 40vw)` width.

## Changes

- **What**: On small screens (`<640px`), the outer container uses
`inset-x-4` gutters with `w-auto` instead of `w-min`, and the expanded
content uses `w-full` instead of the fixed width. At `sm:` breakpoint
and above, the original centered `w-min` / `w-[max(400px,40vw)]`
behavior is preserved.

## Review Focus

The fix is mobile-first: small screens get fluid width, `sm:` restores
the original fixed behavior. No changes needed in the three consumer
components (ModelImportProgressDialog, AssetExportProgressDialog,
ManagerProgressToast).

<!-- Fixes
https://www.notion.so/comfy-org/Bug-Fix-HoneyToast-width-styling-for-responsiveness-on-all-screen-sizes-3136d73d3650814b97e2cc943a98bedb
-->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9429-fix-make-HoneyToast-responsive-on-small-screens-31a6d73d36508103ba02dcef2e5ff33b)
by [Unito](https://www.unito.io)
2026-03-04 22:42:11 -08:00
Christian Byrne
6689a1b14e fix: split perf report workflow for fork PR support (#9382)
## Summary

Perf report workflow fails on fork PRs because `GITHUB_TOKEN` is
read-only for forks, causing "Resource not accessible by integration" on
the PR comment step.

## Changes

- **What**: Split `ci-perf-report.yaml` into a data-collection workflow
+ a `workflow_run`-triggered reporter (`pr-perf-report.yaml`), matching
the existing `ci-size-data`/`pr-size-report` pattern. Added fork PR
permissions guidance to `.github/AGENTS.md`.
- **ci-perf-report.yaml**: Removed the `report` job and `pull-requests:
write` permission. Added PR metadata (number + base branch) artifact
upload.
- **pr-perf-report.yaml** (new): Triggered by `workflow_run` on the perf
workflow. Downloads metrics + metadata artifacts, generates report,
posts PR comment with write permissions from the default-branch context.

## Review Focus

- The two-workflow split follows the same pattern as `ci-size-data.yaml`
→ `pr-size-report.yaml`, which already works for fork PRs.
- The `workflow_run` trigger runs in the base repo context per [GitHub
Security Lab
guidance](https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/),
so it safely has write permissions even for fork PRs.
- AGENTS.md guidance documents this pattern to prevent recurrence.

Fixes the failure seen in
https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/22684230751/job/65763595989?pr=9380

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9382-fix-split-perf-report-workflow-for-fork-PR-support-3196d73d365081b29b35ed354e7789e2)
by [Unito](https://www.unito.io)
2026-03-04 22:09:31 -08:00
Christian Byrne
6c20d64fa9 fix: deterministic DOM widget clip-path for flaky screenshot test (#9400)
## Summary

Fix deterministic DOM widget clip-path rendering to resolve the flaky
"Can drag node" screenshot test.

## Root Cause

`useDomClipping.updateClipPath()` schedules clip-path calculation in a
`requestAnimationFrame`, but `DomWidget.vue`'s watcher reads
`clippingStyle.value` synchronously before the RAF fires. The stale
clip-path gets baked into `style.value` and never updated when the RAF
completes, causing the textarea DOM widget to non-deterministically
render in front of or behind the canvas-drawn node selection border.

## Fix

- Extract `composeStyle()` function and add a dedicated watcher on
`clippingStyle` that recomposes the final inline style whenever the
RAF-deferred clip-path updates
- Add `enableDomClipping` to the main watcher dependency array so
toggling the clipping setting immediately recomposes the style
- Add `moveMouseToEmptyArea()` call in the test as a secondary
stabilizer against hover highlight non-determinism
- Delete stale snapshot so CI regenerates it with correct clip-path
behavior

- Fixes #4658

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-03-04 21:44:20 -08:00
jaeone94
f00a65ced0 feat: add collapse/expand all toggle to right panel tabs (#9333)
## Summary
Adds a collapse/expand all toggle button to all parameter and error tabs
in the right side panel, letting users quickly collapse or expand all
accordion sections at once.

## Changes
- **New component**: `CollapseToggleButton.vue` — a reusable icon button
(list-collapse / list-tree icon) with tooltip, bound via `v-model`
- **Error tab**: Toggle collapses/expands all error groups; per-group
state is now managed through `isSectionCollapsed` /
`setSectionCollapsed` helpers
- **Nodes tab** (`TabNodes.vue`): Per-node `collapseMap`; toggle
overrides per-section state; defaults to collapsed (nodes tab default
was already collapsed)
- **Normal inputs tab** (`TabNormalInputs.vue`): Per-node `collapseMap`
+ `advancedCollapsed`; toggle covers both normal and advanced sections;
defaults to collapsed when multiple nodes selected
- **Subgraph inputs tab** (`TabSubgraphInputs.vue`): Toggle covers both
main and advanced inputs sections
- **Global parameters tab** (`TabGlobalParameters.vue`): Toggle bound to
single `SectionWidgets`
- **i18n**: Added `g.collapseAll` and `g.expandAll` keys

## Review Focus
- `isAllCollapsed` getter in each tab: reads from the same per-section
state so the toggle accurately reflects current state rather than being
independently tracked
- `TabNormalInputs`: multi-node selection default collapse behaviour is
preserved through `isSectionCollapsed` fallback logic

## Screenshots
<img width="778" height="643" alt="image"
src="https://github.com/user-attachments/assets/04d07f32-5135-47f9-b029-78ca78a996fb"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9333-feat-add-collapse-expand-all-toggle-to-right-panel-tabs-3176d73d36508123ba22d6e81983bb1b)
by [Unito](https://www.unito.io)
2026-03-04 21:41:15 -08:00
Jin Yi
d20cc82ef4 [feat] Add reusable SearchInput component (#9168)
## Summary
Add a reusable `SearchInput` component with theme-aware styling, clear
button, loading state, and configurable sizes.

## Changes
- **SearchInput.vue**: Composable search input wrapping Reka UI Combobox
with search/clear/loading icon states
- **searchInput.variants.ts**: CVA-based size variants (`sm`, `md`,
`lg`) using semantic theme tokens (`bg-secondary-background`,
`text-base-foreground`)
- **SearchInput.stories.ts**: Storybook coverage for all sizes, loading,
custom icon/placeholder, and background override

## Review Focus
- Clear button alignment with search icon (`left-3.5` for `icon-sm`
button vs `left-4` for `size-4` icon)
- Theme token choices for light/dark compatibility

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9168-feat-Add-reusable-SearchInput-component-3116d73d365081309290fe84a46852e4)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-05 14:26:00 +09:00
Johnpaul Chiwetelu
a2cb864828 chore: bump CI container to 0.0.13 (#9394)
Updates CI container from `0.0.12` to `0.0.13`

**Triggered by:** [Tag
0.0.13](https://github.com/Comfy-Org/comfyui-ci-container/tree/0.0.13)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9394-chore-bump-CI-container-to-0-0-13-3196d73d365081279c5bca477025cb5a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
2026-03-05 05:49:10 +01:00
Deep Mehta
3d99566840 feat: add model-to-node backlinks for upcoming custom nodes (#9411)
## Summary
- Add `quickRegister()` mappings for models being added in open cloud
PRs so the "Use" button works when those node packs ship

## Mappings added

| Cloud PR | Node Pack | Model Directories | Loader Node |
|----------|-----------|-------------------|-------------|
| [#2645](https://github.com/Comfy-Org/cloud/pull/2645) |
ComfyUI-HunyuanVideoWrapper | `LLM/llava-llama-3-8b-*` |
`DownloadAndLoadHyVideoTextEncoder` |
| [#2598](https://github.com/Comfy-Org/cloud/pull/2598) |
comfyui-cogvideoxwrapper | `CogVideo/GGUF`, `CogVideo/ControlNet` |
`DownloadAndLoadCogVideoGGUFModel`, `DownloadAndLoadCogVideoControlNet`
|
| [#2594](https://github.com/Comfy-Org/cloud/pull/2594) |
ComfyUI-DynamiCrafterWrapper | `checkpoints/dynamicrafter{,/controlnet}`
| `DownloadAndLoadDynamiCrafterModel`,
`DownloadAndLoadDynamiCrafterCNModel` |
| [#2537](https://github.com/Comfy-Org/cloud/pull/2537) |
ComfyUI_LayerStyle_Advance | `BEN`, `BiRefNet/pth`, `onnx/human-parts`,
`lama` | `LS_LoadBenModel`, `LS_LoadBiRefNetModel`,
`LS_HumanPartsUltra`, `LaMa` |

## Safe to merge before backend

Unknown node classes are silently skipped by `registerNodeProvider()` —
the mapping becomes a no-op until the node pack is deployed. Zero risk.

## Test plan
- [ ] Verify no runtime errors on load (unknown classes are skipped
gracefully)
- [ ] After backend PRs merge, verify "Use" button creates correct node
for each model type

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

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9411-feat-add-model-to-node-backlinks-for-upcoming-custom-nodes-31a6d73d3650811bb129e557450f263a)
by [Unito](https://www.unito.io)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 20:04:07 -08:00
Christian Byrne
6dc4a3ed1e refactor(changeTracker): use shared clone util and centralize nodeOutputs snapshot (#9387)
## Summary

Follow-up to #9380. Replaces local `clone()` with shared util and
centralizes output snapshotting.

## Changes

- **What**: Replaced local `JSON.parse(JSON.stringify)` clone in
`changeTracker.ts` with shared `clone()` from `@/scripts/utils` (prefers
`structuredClone` with JSON fallback). Added `snapshotOutputs()` to
`useNodeOutputStore` as symmetric counterpart to existing
`restoreOutputs()`, and wired `changeTracker.store()` to use it.
- **Breaking**: None

## Review Focus

Symmetry between `snapshotOutputs()` and `restoreOutputs()` in the node
output store.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9387-refactor-changeTracker-use-shared-clone-util-and-centralize-nodeOutputs-snapshot-3196d73d365081a289c3cb414f57929e)
by [Unito](https://www.unito.io)
2026-03-04 20:03:26 -08:00
Alexander Brown
5327fef29f fix: spin out workflow tab/load stability regressions (#9345)
## Summary

Spin out workflow tab/load stability fixes from the share-by-url branch
so they can merge independently and reduce regression risk.

## Changes

- **What**: Fixes duplicate tabs on repeated same-workflow loads by
making active-workflow reload idempotent in `afterLoadNewGraph`; fixes
tab flicker on save/rename by removing async detach/attach gaps in
`workflowStore`; hardens duplicate workflow path by loading before clone
and assigning a new workflow `id`.

## Review Focus

Please review the idempotency gate in `afterLoadNewGraph`
(`activeState.id === workflowData.id`) and the save/rename path update
sequencing in `workflowStore` to confirm behavior remains correct for
restoration and re-import flows.

## Screenshots (if applicable)

N/A (workflow logic and tests only)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9345-fix-spin-out-workflow-tab-load-stability-regressions-3186d73d365081fe922bdc61dcf8d8f8)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-03-04 17:35:18 -08:00
Comfy Org PR Bot
f5e1330228 1.41.12 (#9396)
Patch version increment to 1.41.12

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9396-1-41-12-31a6d73d36508145a967c7fcf5831532)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
v1.41.12
2026-03-04 17:19:30 -08:00
Christian Byrne
0196a1cf54 fix: hide all painter labels in compact mode consistently (#9397)
## Summary

Add missing `v-if="!compact"` guards to painter label divs so all labels
are hidden consistently in compact mode.

## Changes

- **What**: Added `v-if="!compact"` to the Color, Hardness, Width,
Height, and Background label divs in `WidgetPainter.vue`, matching the
existing guards on Tool and Size labels.

## Review Focus

Straightforward consistency fix — all 7 label divs now use the same
compact-mode guard.

Fixes #9235

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9397-fix-hide-all-painter-labels-in-compact-mode-consistently-31a6d73d3650811a9d3af8dd290e2bca)
by [Unito](https://www.unito.io)
2026-03-04 17:09:41 -08:00
Christian Byrne
80e31a27b1 refactor: remove redundant = false defaults on boolean props (#9155)
## Summary

Remove redundant `= false` defaults from destructured `defineProps` on
boolean props, since Vue's [Boolean
casting](https://vuejs.org/guide/components/props.html#boolean-casting)
already defaults absent boolean props to `false`.

## Changes

- **What**: Remove 10 unnecessary `= false` default values across 8
components

## Review Focus

Vue compiles `defineProps<{ myBool?: boolean }>()` to `{ myBool: { type:
Boolean, required: false } }`. Boolean casting means absent boolean
props are already `false` — the explicit `= false` in JS destructuring
defaults never triggers.

Follow-up to #9150.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9155-refactor-remove-redundant-false-defaults-on-boolean-props-3116d73d36508196af0bcba53257720a)
by [Unito](https://www.unito.io)
2026-03-04 16:59:05 -08:00
Deep Mehta
0f8473db35 feat: add model type mappings for cloud custom nodes (#9392)
## Summary

Adds model-to-node backlinks in `modelToNodeStore.ts` for all
cloud-deployed custom node models that were missing mappings. Without
these, clicking "Use" on a model in the model browser throws an error.

**17 new backlinks added** covering ~340 models across deployed node
packs:

| Category | Directories | Node | Models |
|----------|-------------|------|--------|
| Vision-Language | LLM/Qwen-VL/* (12 specific paths) | AILab_QwenVL /
AILab_QwenVL_PromptEnhancer | ~186 |
| TTS | qwen-tts/* | FB_Qwen3TTSVoiceClone | ~68 |
| Video | SEEDVR2, liveportrait/*, mimicmotion, rife | various | ~33 |
| Depth | depthanything3 | DownloadAndLoadDepthAnythingV3Model | 7 |
| Segmentation | face_parsing, sam3 | various | 4 |
| Diffusers | diffusers/* (Kolors) | DownloadAndLoadKolorsModel | 16 |
| Other | clip/*, dwpose, onnx, detection, UltraShape, sharp | various |
~26 |

**Key fix:** Replaced the top-level `LLM` fallback with specific
`LLM/Qwen-VL/*` paths. The old fallback incorrectly mapped `LLM/llava-*`
models to `AILab_QwenVL`.

Models without deployed node packs (llava/HyVideo, latentsync, sam3d,
sam3dbody, inpaint, vae_approx) are excluded — those are being removed
from `supported_models.json` in Comfy-Org/cloud#2652.

## Test plan
- [ ] Verify "Use" button works for QwenVL models in model browser
- [ ] Verify "Use" button works for TTS, video, depth, segmentation
models
- [ ] Verify no `No node provider registered for category` errors for
deployed models

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
2026-03-04 16:51:42 -08:00
Kelly Yang
120524faa1 feat(minimap): add node execution status visualization (#9187)
## Summary

Added visual indicators (colored borders) to the MiniMap to display the
real-time execution status (running, executed, or error) of nodes.

## Changes

- **What**: Added visual feedback to the MiniMap to show node execution
states (green for running/executed, red for errors) by integrating with
`useExecutionStore` and updating the canvas renderer.

## Review Focus

Confirmed that relying on the array `.includes()` check for
`executingNodeIds` in the data sources avoids unnecessary `Set`
allocations during frequent redraws.

## Screenshots 

<img width="540" height="446" alt="14949d48035db5c64cceb11f7f7f94a3"
src="https://github.com/user-attachments/assets/cac53a80-9882-43fd-a725-7003fe3fd21a"
/>

<img width="562" height="464" alt="7e922f54dea2cea4e6b66202d2ad0dd3"
src="https://github.com/user-attachments/assets/e178b981-3af0-417f-8e21-a706f192fabf"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9187-feat-minimap-add-node-execution-status-visualization-3126d73d3650816eb7b3ca415cf6a8f1)
by [Unito](https://www.unito.io)
2026-03-04 16:43:12 -08:00
Kelly Yang
fd9e774a29 feat(ui): add copy button to read-only textarea widget on hover (#9331)
## Summary

Added a `copy-to-clipboard` button that appears when hovering over
read-only textarea widgets to improve user experience.

## Changes

- **What**: Added a copy button utilizing `useCopyToClipboard` to
[WidgetTextarea.vue](cci:7://file:///Users/kelly/Documents/comfyui/ComfyUI_frontend/src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue:0:0-0:0)
that only displays when the widget is read-only and hovered.

## Screenshots 
<img width="670" height="498" alt="e30362fdc6792f3a955f3415f0f42afb"
src="https://github.com/user-attachments/assets/1b7ec5dc-3733-48b6-9708-6ae56926054a"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9331-feat-ui-add-copy-button-to-read-only-textarea-widget-on-hover-3176d73d36508159a339d567b5c33591)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Terry Jia <terryjia88@gmail.com>
Co-authored-by: Alexander Brown <DrJKL0424@gmail.com>
Co-authored-by: Dante <bunggl@naver.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-05 09:35:38 +09:00
Christian Byrne
7b316eb9a2 feat: add statistical significance to perf report with z-score thresholds (#9305)
## Summary

Replace fixed 10%/20% perf delta thresholds with dynamic σ-based
classification using z-scores, eliminating false alarms from naturally
noisy duration metrics (10-17% CV).

## Changes

- **What**:
- Run each perf test 3× (`--repeat-each=3`) and report the mean,
reducing single-run noise
- Download last 5 successful main branch perf artifacts to compute
historical μ/σ per metric
- Replace fixed threshold flags with z-score significance: `⚠️
regression` (z>2), ` neutral/improvement`, `🔇 noisy` (CV>50%)
  - Add collapsible historical variance table (μ, σ, CV) to PR comment
- Graceful cold start: falls back to simple delta table until ≥2
historical runs exist
- New `scripts/perf-stats.ts` module with `computeStats`, `zScore`,
`classifyChange`
  - 18 unit tests for stats functions

- **CI time impact**: ~3 min → ~5-6 min (repeat-each adds ~2 min,
historical download <10s)

## Review Focus

- The `gh api` call in the new "Download historical perf baselines"
step: it queries the last 5 successful push runs on the base branch. The
`gh` CLI is available natively on `ubuntu-latest` runners and
auto-authenticates with `GITHUB_TOKEN`.
- `getHistoricalStats` averages per-run measurements before computing
cross-run σ — this is intentional since historical artifacts may also
contain repeated measurements after this change lands.
- The `noisy` classification (CV>50%) suppresses metrics like `layouts`
that hover near 0 and have meaningless percentage swings.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9305-feat-add-statistical-significance-to-perf-report-with-z-score-thresholds-3156d73d3650818d9360eeafd9ae7dc1)
by [Unito](https://www.unito.io)
2026-03-04 16:16:53 -08:00
Christian Byrne
b8edb11ac1 feat: add eslint-plugin-better-tailwindcss for Tailwind v4 linting (#9245)
## Summary

Add `eslint-plugin-better-tailwindcss` to the ESLint toolchain for
Tailwind CSS v4 class linting.

## Changes

- **What**: Integrate `eslint-plugin-better-tailwindcss` (v4.3.1) with
the recommended config, pointed at the design-system CSS entry point for
v4 theme resolution. Five rules are enabled initially:
`enforce-canonical-classes`, `no-deprecated-classes`,
`no-conflicting-classes`, `no-duplicate-classes`,
`no-unnecessary-whitespace`. Three rules are disabled pending follow-up:
`no-unknown-classes` (needs PrimeIcon/custom class whitelisting),
`enforce-consistent-line-wrapping` (oxfmt conflict risk),
`enforce-consistent-class-order` (large batch change).
- **Dependencies**: `eslint-plugin-better-tailwindcss` ^4.3.1
- Fix conflicting `outline outline-1` classes in
`FormDropdownMenuActions.vue` (caught by the new
`no-conflicting-classes` rule).

## Review Focus

- Is the rule severity/enablement strategy appropriate for incremental
adoption?
- The 700 warnings (mostly `enforce-canonical-classes` and
`no-deprecated-classes`) are all auto-fixable via `eslint --fix` —
should we batch-fix them in this PR or a follow-up?

Fixes COM-15518

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9245-feat-add-eslint-plugin-better-tailwindcss-for-Tailwind-v4-linting-3136d73d365081df8a64dd55962d073f)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-03-04 15:34:23 -08:00
AustinMroz
57a919fad2 Split selection into an inputs and outputs step (#9362)
When building an app, selecting inputs and selecting outputs are now 2
separate steps. This prevents confusion where clicking on the widget of
an output node will select that widget instead of the entire output.

<img width="1673" height="773" alt="image"
src="https://github.com/user-attachments/assets/e5994479-6fcf-4572-b58b-bf8cecfb7d55"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9362-Split-selection-into-an-inputs-and-outputs-step-3196d73d36508187b4a1e51c73f1c54c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-03-04 15:18:16 -08:00
Johnpaul Chiwetelu
316a05c77f fix: replace hardcoded styles with design tokens and cache StatusBadge variants (#9349)
## Summary

Replace hardcoded color and spacing values with semantic design tokens
and cache a computed variant class in StatusBadge.

## Changes

- **What**: Use Tailwind 4 CSS spacing variables in FormDropdownMenu
layout configs, replace zinc color utilities with semantic
`node-component-border` tokens in FormDropdownInput, wrap
`statusBadgeVariants()` in a `computed` for caching in StatusBadge.

## Review Focus

Straightforward token replacements and a computed caching change -- no
behavioral differences expected.

Fixes #9087
Fixes #9086
Fixes #7910

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9349-fix-replace-hardcoded-styles-with-design-tokens-and-cache-StatusBadge-variants-3186d73d36508185aae2e0753c9d1694)
by [Unito](https://www.unito.io)
v1.41.11
2026-03-04 14:23:47 -08:00
Comfy Org PR Bot
4b70ca298a 1.41.11 (#9361)
Patch version increment to 1.41.11

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9361-1-41-11-3196d73d365081cc9b9ef730251b07b4)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-03-04 14:22:12 -08:00
Benjamin Lu
1cee6272c1 fix: add run progress toggle to job history menu (#9176)
Summary
- Add hidden setting `Comfy.Queue.ShowRunProgressBar` (default `true`).
- Add `Show run progress bar` toggle to the shared `...` job history
menu (`JobHistoryActionsMenu`), placed next to `Docked Job History`.
- Use that setting to control both the inline run progress bar and the
inline summary text under it.
- Keep queue button right-click context menu focused on queue actions.
- Add/update tests for the new toggle behavior and summary visibility.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9176-fix-add-run-progress-toggle-to-job-history-menu-3116d73d365081118202d8d67a857367)
by [Unito](https://www.unito.io)
2026-03-04 14:15:11 -08:00
Christian Byrne
bcc470642f fix: cache canvas cursor style to avoid redundant DOM writes (#9171)
## Summary

Cache `canvas.style.cursor` to avoid redundant DOM writes that dirty
Firefox's style tree.

## Changes

- **What**: Add `_lastCursor` field to
`LGraphCanvas._updateCursorStyle()` — only writes `canvas.style.cursor`
when the value changes. Eliminates ~347 redundant style mutations per
profiling session.

## Review Focus

- The fix is 2 lines (cache field + comparison). The unit test validates
the caching pattern without requiring full LGraphCanvas instantiation.
- This is one of several contributors to Firefox's cascading style
recalculation freeze. Each `canvas.style.cursor` write dirties the style
tree, which is flushed during the next paint in the canvas render loop.

## Stack

2 of 4 in Firefox perf fix stack. Depends on #9170.

<!-- Fixes #ISSUE_NUMBER -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9171-fix-cache-canvas-cursor-style-to-avoid-redundant-DOM-writes-3116d73d36508139827fe1d644fa1bd0)
by [Unito](https://www.unito.io)
2026-03-04 14:06:31 -08:00
Johnpaul Chiwetelu
df712953a3 [fix] Replace eval() with safe math expression parser (#9263)
## Summary
Replace `eval()` in `evaluateInput()` with a custom recursive descent
math parser, eliminating a security concern and enabling the `no-eval`
lint rule.

## Changes
- **New**: `mathParser.ts` — recursive descent parser for `+`, `-`, `*`,
`/`, `%`, `()`, decimals, unary operators. Zero new dependencies.
- **Modified**: `widget.ts` — replaced `eval()` call with
`evaluateMathExpression()`, use `isFinite()` instead of `isNaN()` to
reject `Infinity`
- **Modified**: `.oxlintrc.json` — `no-eval` rule changed from `"off"`
to `"error"`
- **Tests**: 59 parser tests + 23 integration tests covering complex
expressions, edge cases, and invalid input

## Review Feedback Addressed
- Renamed `unit()` → `primary()` for clarity
- Added modulo (`%`) operator support
- Normalized negative zero to positive zero
- Added depth limit (200) for nested parentheses
- Used `isFinite()` instead of `isNaN()` to reject
`Infinity`/`-Infinity`
- Added tests for edge-case number formats, unary-after-binary
operators, modulo, depth limits, scientific/hex notation, and `Infinity`

Fixes #8032
Fixes #9272
Fixes #9273
Fixes #9274
Fixes #9275

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9263-fix-Replace-eval-with-safe-math-expression-parser-3136d73d3650812f9f8dea21d1ea4f06)
by [Unito](https://www.unito.io)
2026-03-04 14:04:37 -08:00
Johnpaul Chiwetelu
82750d629d [refactor] Type createNode options parameter (#9262)
## Summary
Narrow `CreateNodeOptions` from `Partial<Omit<LGraphNode, ...>>`
(exposing hundreds of properties/methods) to an explicit interface
listing only creation-time properties.

## Changes
- Replace `Partial<Omit<LGraphNode, 'constructor' | 'inputs' |
'outputs'>>` with explicit `CreateNodeOptions` interface containing
only: `pos`, `size`, `properties`, `flags`, `mode`, `color`, `bgcolor`,
`boxcolor`, `title`, `shape`, `inputs`, `outputs`
- Rename local `CreateNodeOptions` in `createModelNodeFromAsset.ts` to
`ModelNodeCreateOptions` to avoid collision

## Ecosystem verification
GitHub code search across ~50 repos confirms only `pos` and `outputs`
are used externally. All covered by the narrowed interface.

Fixes #9276
Fixes #4740
2026-03-04 14:01:18 -08:00
jaeone94
9e2299ca65 feat(error-groups): sort execution error cards by node execution ID (#9334)
## Summary

Sort execution error cards within each error group by their node
execution ID in ascending numeric order, ensuring consistent and
predictable display order.

## Changes

- **What**: Added `compareExecutionId` utility to
`src/types/nodeIdentification.ts` that splits node IDs on `:` and
compares segments numerically left-to-right; applied it as a sort
comparator when building `ErrorGroup.cards` in `useErrorGroups.ts`

## Review Focus

- The comparison treats missing segments as `0`, so `"1"` sorts before
`"1:20"` (subgraph nodes follow their parent); confirm this ordering
matches user expectations
- All comparisons are purely numeric — non-numeric segment values would
sort as `NaN` (treated as `0`)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9334-feat-error-groups-sort-execution-error-cards-by-node-execution-ID-3176d73d365081e1b3e4e4fa8831fe16)
by [Unito](https://www.unito.io)
2026-03-04 13:59:58 -08:00
Christian Byrne
69076f35f8 test: add subgraph workflow round to performance tests (#9306)
## Summary

Add subgraph workflow performance tests to track style recalculations
and layout thrashing for nested subgraph workflows.

## Changes

- **What**: Add 3 new perf test cases (`subgraph-idle`,
`subgraph-mouse-sweep`, `subgraph-dom-widget-clipping`) that mirror the
existing default workflow tests but load the `subgraphs/nested-subgraph`
workflow. The existing perfReporter pipeline automatically picks up the
new measurements.

## Review Focus

The new tests are structurally identical to the existing 3 default
workflow tests — only the workflow loaded and measurement names differ.
No CI or config changes needed.

Fixes
https://www.notion.so/comfy-org/Implement-Add-subgraph-workflow-round-in-performance-testing-process-3156d73d365081d094efdee58215e15b

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9306-test-add-subgraph-workflow-round-to-performance-tests-3156d73d36508133b85cc53a748bc75f)
by [Unito](https://www.unito.io)
2026-03-04 13:38:48 -08:00