Commit Graph

6626 Commits

Author SHA1 Message Date
Terry Jia
d9ce4ff5e0 feat: render dragging links above Vue nodes via overlay canvas (#8695)
## Summary
When vueNodesMode is enabled, the dragging link preview was rendered on
the background canvas behind DOM-based Vue nodes, making it invisible
when overlapping node bodies.

Add a new overlay canvas layer between TransformPane and
SelectionRectangle that renders the dragging link preview and snap
highlight above the Vue node DOM layer.

Static connections remain on the background canvas as before.

fix https://github.com/Comfy-Org/ComfyUI_frontend/issues/8414
discussed with @DrJKL 

## Screenshots
before

https://github.com/user-attachments/assets/94508efa-570c-4e32-a373-360b72625fdd

after

https://github.com/user-attachments/assets/4b0f924c-66ce-4f49-97d7-51e6e923a1b9

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8695-feat-render-dragging-links-above-Vue-nodes-via-overlay-canvas-2ff6d73d365081599b2fe18b87f34b7a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-02-06 21:19:18 -05:00
AustinMroz
e7932f2fc2 Tighter image sizing in vue mode (#8702)
Fixes multiple overlapping issues with both the ImagePreviews (LoadImage
node) and LivePreview (Ksampler node) to eliminate empty space and move
the bahviour to be closer to the litegraph implementation.
- NodeWidgets will no longer no longer flex-grow when it contains no
widgets capable of growing
<img width="278" height="585" alt="image"
src="https://github.com/user-attachments/assets/c4c39805-1474-457b-86d1-b64ecf01319f"
/>

- The number of element layers for LivePreview has been reduced. Sizing
is difficult to properly spread across nested flex levels.
- The ImagePreview and LivePreview now have `contain-size` set with a
min height of 220 pixels (the same as the litegraph implementation).
This allows images to "pillarbox" by increasing width without increasing
height.
  | Before | After |
  | ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/3fe38a20-47d3-4a77-a0db-63167f76b0be"/>
| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/22dc6bf6-1812-49bb-95a1-3febfb3e40dd"
/>|
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/99b24547-6850-4b46-a972-53411676c78f"
/> | <img width="360" alt="after"
src="https://github.com/user-attachments/assets/0a7783c8-cf93-47aa-8c60-608b9a4b4498"
/>|

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8702-Tighter-image-sizing-in-vue-mode-2ff6d73d3650814196f0d55d81a42e2d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-02-06 16:39:26 -08:00
Christian Byrne
f53b0879ed feat: add model-to-node mappings for cloud asset categories (#8468)
## Summary

Add mappings for 13 previously unmapped model categories in the Cloud
asset browser, enabling users to click on models to create corresponding
loader nodes on the canvas.

## Changes

### Core nodes
- `latent_upscale_models` → `LatentUpscaleModelLoader`

### Extension nodes
| Category | Node Class | Widget Key |
|----------|-----------|-----------|
| `sam2` | `DownloadAndLoadSAM2Model` | `model` |
| `sams` | `SAMLoader` | `model_name` |
| `ultralytics` | `UltralyticsDetectorProvider` | `model_name` |
| `depthanything` | `DownloadAndLoadDepthAnythingV2Model` | `model` |
| `ipadapter` | `IPAdapterModelLoader` | `ipadapter_file` |
| `segformer_b2_clothes` | `LS_LoadSegformerModel` | `model_name` |
| `segformer_b3_clothes` | `LS_LoadSegformerModel` | `model_name` |
| `segformer_b3_fashion` | `LS_LoadSegformerModel` | `model_name` |
| `nlf` | `LoadNLFModel` | `nlf_model` |
| `FlashVSR` | `FlashVSRNode` | (auto-load) |
| `FlashVSR-v1.1` | `FlashVSRNode` | (auto-load) |

### Hierarchical fallback
- `ultralytics/bbox` and `ultralytics/segm` fall back to the
`ultralytics` mapping

### Skipped categories
- `vae_approx` - No user-facing loader (used internally for latent
previews)
- `detection` - No specific loader exists

## Testing
- Added unit tests for all new mappings
- Tests verify hierarchical fallback works correctly
- All 40 tests pass

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8468-feat-add-model-to-node-mappings-for-cloud-asset-categories-2f86d73d365081389ea5fbfc52ecbfad)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
2026-02-06 16:04:27 -08:00
Alexander Brown
5441f70cd5 feat: enforce i18n import conventions via ESLint (#8701)
## Summary

Enforce i18n import conventions via ESLint: Vue components must use
`useI18n()`, non-composable `.ts` files must use the global `t` from
`@/i18n`.

## Changes

- **What**: Two new `no-restricted-imports` rules in `eslint.config.ts`
(both `warn` severity for incremental migration). Removed the disabled
`@/i18n--to-enable` placeholder from `.oxlintrc.json`.
- `.vue` files: disallow importing `t`/`d`/`st`/`te` from `@/i18n` (37
existing violations to migrate)
- Non-composable `.ts` files: disallow importing `useI18n` from
`vue-i18n` (2 existing violations)
- Composable `use*.ts`, test files, and `src/i18n.ts` are excluded from
Rule 2

## Review Focus

- The rules are placed after `oxlint.buildFromOxlintConfigFile()` to
re-enable ESLint's `no-restricted-imports` for these specific file
scopes without conflicting with oxlint's base rule (which handles
PrimeVue deprecations).
- `warn` severity chosen so CI is not blocked while existing violations
are migrated.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8701-feat-enforce-i18n-import-conventions-via-ESLint-2ff6d73d36508123b6f9edf2693fb5e0)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-06 14:03:00 -08:00
pythongosssss
0e3314bbd3 Node ghost mode when adding nodes (#8694)
## Summary

Adds option for adding a node as a "ghost" that follows the cursor until
the user left clicks to confirm, or esc/right click to cancel.

## Changes

- **What**: 
Adds option for `ghost` when calling `graph.add`  
This adds the node with a `flag` of ghost which causes it to render
transparent
Selects the node, then sets the canvas as dragging to stick the node to
the cursor

## Screenshots (if applicable)



https://github.com/user-attachments/assets/dcb5702f-aba3-4983-aa40-c51f24a4767a

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8694-Node-ghost-mode-when-adding-nodes-2ff6d73d3650815591f2c28415050463)
by [Unito](https://www.unito.io)
2026-02-06 13:42:38 -08:00
pythongosssss
8f301ec94b Fix hit detection on vue node slots (#8609)
## Summary

Vue node slots extend outside the bounds of the node:
<img width="123" height="107" alt="image"
src="https://github.com/user-attachments/assets/96f7f28b-de54-4978-bc78-f38fc1fd4ea1"
/>
When clicking on the outer half of the slot, the matching node is not
found as the click was technically not over a node, however in reality
the action should still be associated with the node the slot is for.

This specifically fixes middle click to add reroute not working on the
outer half of the slot.

## Changes

- **What**: 
- If the event is not over a node, check if is over a Vue slot, if so,
use the node associated with that slot.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8609-Fix-hit-detection-on-vue-node-slots-2fd6d73d3650815c8328f9ea8fa66b0c)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Tests**
* Added comprehensive test suite for slot hit-detection in Vue nodes
mode, covering standard and fallback interaction paths.

* **Bug Fixes**
* Improved hit-detection accuracy for slots that extend beyond node
boundaries in Vue mode, ensuring clicks map to the correct node.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-06 13:41:18 -08:00
Terry Jia
17c1b1f989 fix: prevent node height shrinking on vueNodes/litegraph mode switch (#8697)
## Summary
Three interacting bugs caused cumulative height loss (~66px per cycle):

1. useVueNodeLifecycle incorrectly subtracted NODE_TITLE_HEIGHT from
LGraphNode.size[1] during layout init, but size[1] is already
content-only (title excluded per LGraphNode.measure()).

2. ensureCorrectLayoutScale added/subtracted NODE_TITLE_HEIGHT in scale
formulas, breaking the round-trip.
Simplified to pure ratio scaling (size * scaleFactor). 
Also set LayoutSource.Canvas before batchUpdateNodeBounds to prevent
stale DOM source from triggering incorrect height normalization.

3. initSizeStyles set --node-height (min-height of the full DOM element
including title) to the content-only layout height.
Added NODE_TITLE_HEIGHT so ResizeObserver captures the correct total
height and normalization recovers the exact content height.

## Screenshots (if applicable)
before

https://github.com/user-attachments/assets/ae41124b-f9e3-4061-8127-eeacddc67a55

after

https://github.com/user-attachments/assets/5ff288a6-73a3-481a-a750-150d9bdbc8fe

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8697-fix-prevent-node-height-shrinking-on-vueNodes-litegraph-mode-switch-2ff6d73d365081c7a2acdc7ec57e2e19)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-02-06 12:52:13 -08:00
AustinMroz
a4b725b85e Fix legacy history (#8687)
Restores functionality of the history and queue sections in the legacy
"floating menu" which were broken in #7650

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8687-Fix-legacy-history-2ff6d73d3650810a8a05f2ee18cbfa1d)
by [Unito](https://www.unito.io)
2026-02-06 10:14:55 -08:00
AustinMroz
8283438ee6 Fix incorrect widgetValue migration (#8625)
Under a combination of many edge cases, the `widget_values` migration
code added in #3326 would cause the progress text on a "Recraft Text to
Image" node to incorrectly deserialize into the `control_after_generate`
- widgets_values is of length 1 greater than it should be because
progress text serializes
  - It should not, there is no code to deserialize it
- negative_prompt has force_input set and skips serialization
- Migration only applies when `widgets_values` is equal to actual inputs
length. The two above edge cases cancel to make this true
- Seed is accounted for when calculating the length of widgets, but not
when applying the migration
- Migration occurs even though we track workflow version now and have an
accurate way of determining that it can not be needed

The two primary edge cases which cause the bug are both addressed
- `options.serialize` does nothing and has never done anything. I've
been guilty of making the same mistake in the ancient past, and want to
clean up the misconception where I can.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8625-Fix-incorrect-widgetValue-migration-2fe6d73d365081a683b4c675eaeebb6c)
by [Unito](https://www.unito.io)
2026-02-05 21:27:11 -08:00
Johnpaul Chiwetelu
d05e4eac58 fix: include subfolder in asset download URL for audio/video files (#8684)
## Summary

- `getAssetUrl()` was constructing `/view` URLs without the `subfolder`
query parameter, causing backend to return "file not found" for assets
stored in subfolders (common for audio/video outputs)
- Preview/playback was unaffected because it uses `preview_url` from
`ResultItemImpl.url` which correctly includes `subfolder`
- Fixed `getAssetUrl()` to include `subfolder` from
`asset.user_metadata` when present
- Simplified download functions to prefer `preview_url` (already
correct) with `getAssetUrl` as fallback

## Test plan

- [ ] Generate audio/video output (e.g. via SaveAudio node) that saves
to a subfolder
- [ ] Right-click the asset in the assets sidebar and click Download —
should download successfully
- [ ] Select multiple audio/video assets and use bulk download — should
download all
- [ ] Verify image downloads still work as before
- [ ] Verify cloud environment downloads still work (uses `preview_url`
path)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
  * Added support for organizing and downloading assets from subfolders.

* **Refactor**
* Improved asset URL generation and download handling for better
reliability and performance.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-06 05:06:11 +01:00
Comfy Org PR Bot
7f509cc018 1.39.8 (#8678)
Patch version increment to 1.39.8

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8678-1-39-8-2ff6d73d36508144b359cdd15822f6fb)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
v1.39.8
2026-02-05 19:30:45 -08:00
Christian Byrne
23c8757447 fix: increase active node border weight from 2 to 3 (#8654)
## Summary

Increase stroke/outline weight for active node states to improve
visibility during workflow execution (COM-7770).

## Changes

- **What**: Increased border/stroke weight from 2 to 3 for active nodes
in both Vue Nodes and LiteGraph renderers
  - Vue Nodes: `outline-2` → `outline-3` in `LGraphNode.vue`
- LiteGraph: `lineWidth: 3` for `running` stroke (was default 1) and
`executionError` stroke (was 2) in `litegraphService.ts`
  - Updated test assertion to match

## Review Focus

Minimal visual change. The `executionError` lineWidth was also bumped
from 2 → 3 so error states remain at least as prominent as running
states.

> **Note:**
[#8603](https://github.com/Comfy-Org/ComfyUI_frontend/pull/8603) (by
@AustinMroz) also modifies `LGraphNode.vue` with a larger restructuring
(bottom buttons, badges, resize handle). The two PRs do not conflict —
#8603 does not touch the outline/border state classes or
`litegraphService.ts`, so both changes merge cleanly.

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
2026-02-05 17:44:19 -08:00
Johnpaul Chiwetelu
7d3d00858a feat: add download button to audio preview player (#8628)
## Summary
- Adds a download icon button to the `AudioPreviewPlayer` widget for
PreviewAudio and SaveAudio nodes
- Reuses the existing `downloadFile` utility (same as video download)
- Button appears inline next to volume/options controls, matching the
player's existing UI style

## Test plan
- [x] Add a PreviewAudio or SaveAudio node, run a workflow that produces
audio output
- [x] Verify the download icon appears in the audio player controls
- [x] Click the download button and confirm the audio file downloads
correctly
- [x] Verify the button does not appear when no audio is loaded


https://github.com/user-attachments/assets/7fb2df16-82a6-40aa-a938-aed57032e30b

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8628-feat-add-download-button-to-audio-preview-player-2fe6d73d365081e3997fc45d3bb8cffc)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-02-06 01:35:32 +01:00
Christian Byrne
478cfc0b5e feat: replace puzzle icon with extensions-blocks icon for manager button (#8644)
## Summary

Replace the manager button puzzle icon with a custom extensions-blocks
SVG icon and add a "Manage Extensions" text label to the top bar button.

## Changes

- **What**: Swap `icon-[lucide--puzzle]` →
`icon-[comfy--extensions-blocks]` in TopMenuSection, ComfyMenuButton,
and ManagerDialog. Add visible "Manage Extensions" label (hidden below
md). Align tooltip with new label text.

## Review Focus

- Visual appearance of the new icon at different sizes
- Button layout with text label at md+ breakpoints
- Red dot notification positioning with wider button

Fixes COM-12161

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8644-feat-replace-puzzle-icon-with-extensions-blocks-icon-for-manager-button-2fe6d73d3650815c8867efc5a0842ef7)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-02-05 16:33:26 -08:00
Johnpaul Chiwetelu
90a701dd67 Road to No Explicit Any Part 11 (#8565)
## Summary

This PR removes `any` types from widgets, services, stores, and test
files, replacing them with proper TypeScript types.

### Key Changes

#### Type Safety Improvements
- Replaced `any` with `unknown`, explicit types, or proper interfaces
across widgets and services
- Added proper type imports (TgpuRoot, Point, StyleValue, etc.)
- Created typed interfaces (NumericWidgetOptions, TestWindow,
ImportFailureDetail, etc.)
- Fixed function return types to be non-nullable where appropriate
- Added type guards and null checks instead of non-null assertions
- Used `ComponentProps` from vue-component-type-helpers for component
testing

#### Widget System
- Added index signature to IWidgetOptions for Record compatibility
- Centralized disabled logic in WidgetInputNumberInput
- Moved template type assertions to computed properties
- Fixed ComboWidget getOptionLabel type assertions
- Improved remote widget type handling with runtime checks

#### Services & Stores
- Fixed getOrCreateViewer to return non-nullable values
- Updated addNodeOnGraph to use specific options type `{ pos?: Point }`
- Added proper type assertions for settings store retrieval
- Fixed executionIdToCurrentId return type (string | undefined)

#### Test Infrastructure
- Exported GraphOrSubgraph from litegraph barrel to avoid circular
dependencies
- Updated test fixtures with proper TypeScript types (TestInfo,
LGraphNode)
- Replaced loose Record types with ComponentProps in tests
- Added proper error handling in WebSocket fixture

#### Code Organization
- Created shared i18n-types module for locale data types
- Made ImportFailureDetail non-exported (internal use only)
- Added @public JSDoc tag to ElectronWindow type
- Fixed console.log usage in scripts to use allowed methods

### Files Changed

**Widgets & Components:**
-
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue
-
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDefault.vue
-
src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue
- src/renderer/extensions/vueNodes/widgets/components/WidgetTextarea.vue
-
src/renderer/extensions/vueNodes/widgets/composables/useRemoteWidget.ts
- src/lib/litegraph/src/widgets/ComboWidget.ts
- src/lib/litegraph/src/types/widgets.ts
- src/components/common/LazyImage.vue
- src/components/load3d/Load3dViewerContent.vue

**Services & Stores:**
- src/services/litegraphService.ts
- src/services/load3dService.ts
- src/services/colorPaletteService.ts
- src/stores/maskEditorStore.ts
- src/stores/nodeDefStore.ts
- src/platform/settings/settingStore.ts
- src/platform/workflow/management/stores/workflowStore.ts

**Composables & Utils:**
- src/composables/node/useWatchWidget.ts
- src/composables/useCanvasDrop.ts
- src/utils/widgetPropFilter.ts
- src/utils/queueDisplay.ts
- src/utils/envUtil.ts

**Test Files:**
- browser_tests/fixtures/ComfyPage.ts
- browser_tests/fixtures/ws.ts
- browser_tests/tests/actionbar.spec.ts
-
src/workbench/extensions/manager/components/manager/skeleton/PackCardGridSkeleton.test.ts
- src/lib/litegraph/src/subgraph/subgraphUtils.test.ts
- src/components/rightSidePanel/shared.test.ts
- src/platform/cloud/subscription/composables/useSubscription.test.ts
-
src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts

**Scripts & Types:**
- scripts/i18n-types.ts (new shared module)
- scripts/diff-i18n.ts
- scripts/check-unused-i18n-keys.ts
- src/workbench/extensions/manager/types/conflictDetectionTypes.ts
- src/types/algoliaTypes.ts
- src/types/simplifiedWidget.ts

**Infrastructure:**
- src/lib/litegraph/src/litegraph.ts (added GraphOrSubgraph export)
- src/lib/litegraph/src/infrastructure/CustomEventTarget.ts
- src/platform/assets/services/assetService.ts

**Stories:**
- apps/desktop-ui/src/views/InstallView.stories.ts
- src/components/queue/job/JobDetailsPopover.stories.ts

**Extension Manager:**
- src/workbench/extensions/manager/composables/useConflictDetection.ts
- src/workbench/extensions/manager/composables/useManagerQueue.ts
- src/workbench/extensions/manager/services/comfyManagerService.ts
- src/workbench/extensions/manager/utils/conflictMessageUtil.ts

### Testing

- [x] All TypeScript type checking passes (`pnpm typecheck`)
- [x] ESLint passes without errors (`pnpm lint`)
- [x] Format checks pass (`pnpm format:check`)
- [x] Knip (unused exports) passes (`pnpm knip`)
- [x] Pre-commit and pre-push hooks pass

Part of the "Road to No Explicit Any" initiative.

### Previous PRs in this series:
- Part 2: #7401
- Part 3: #7935
- Part 4: #7970
- Part 5: #8064
- Part 6: #8083
- Part 7: #8092
- Part 8 Group 1: #8253
- Part 8 Group 2: #8258
- Part 8 Group 3: #8304
- Part 8 Group 4: #8314
- Part 8 Group 5: #8329
- Part 8 Group 6: #8344
- Part 8 Group 7: #8459
- Part 8 Group 8: #8496
- Part 9: #8498
- Part 10: #8499

---------

Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com>
Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-02-05 16:29:28 -08:00
Johnpaul Chiwetelu
7f81e1afac ci: filter snapshot update job to only run @screenshot tagged tests (#8629)
## Summary
- Adds `--grep @screenshot` to the Playwright command in the
update-snapshots CI workflow
- Skips ~146 non-screenshot tests that don't produce any snapshot files,
reducing CI time and resource usage

## Details
All tests that call `toHaveScreenshot` are already tagged with
`@screenshot` (either at the `test.describe` or individual `test`
level). The snapshot update job was previously running every test
unnecessarily.

The `--grep` CLI flag is ANDed with each project's existing
`grep`/`grepInvert` settings, so all projects continue to work
correctly:
- `chromium`: `@screenshot` AND NOT `@mobile`
- `chromium-2x`: `@screenshot` AND `@2x`
- `mobile-chrome`: `@screenshot` AND `@mobile`

## Test plan
- [x] Trigger the update-snapshots workflow on a PR with the "New
Browser Test Expectations" label and verify only screenshot-tagged tests
run
- [x] Verify snapshot files are still correctly updated
2026-02-05 15:18:21 -08:00
AustinMroz
e26283e754 Revert delay of layout initialization (#8619)
#7591 added a one tick delay to layout initialization in an attempt to
resolve some layouting discrepancies. However, it appears to have
reintroduced node scaling issues and introduced a new bug that prevents
cloning nodes with alt+drag in vue.

Alternatives methods of resolving the original issue are being
investigated, but this change was causing more harm than good.

The prior PR included other changes (like a testing fix). Those changes
remain beneficial and do not need to be reverted.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8619-Revert-delay-of-layout-initialization-2fe6d73d365081fc9111c9457ea9752d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-02-05 09:17:41 -08:00
Jin Yi
1ca6e57ac4 fix: skip node replacement API call when feature is disabled (#8618) 2026-02-05 16:37:18 +09:00
Johnpaul Chiwetelu
3adecc4ded fix: prevent duplicate context menu items by using content-based comparison (#8602)
## Summary
- Switches from reference-based to content-based duplicate detection for
context menu items
- Fixes cases where extensions create duplicate menu items (different
objects with same content)
- Improves removal detection accuracy by comparing content strings
instead of object references

## Details
The previous implementation compared menu items by object reference,
which would miss duplicates when extensions added new objects with the
same content. This change:
- Creates Sets of content strings from menu items for efficient
duplicate detection
- Filters additions by checking if their content already exists
- Provides accurate count of removed items through content comparison

## Test plan
- [x] Unit tests pass (`pnpm test:unit
src/lib/litegraph/src/contextMenuCompat.test.ts`)
- [x] TypeScript compilation succeeds (`pnpm typecheck`)
- [x] Linting passes (`pnpm lint`)
- [x] Pre-commit hooks pass

## Before
<img width="633" height="1316" alt="Screenshot 2026-02-04 045422"
src="https://github.com/user-attachments/assets/972871e2-1fd6-45a4-bb6c-9ce73ce7aed7"
/>


## After
<img width="531" height="854" alt="Screenshot 2026-02-04 045918"
src="https://github.com/user-attachments/assets/977bed37-dfb8-41d7-b659-88c477ff8a02"
/>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Improved context menu compatibility: more accurate detection of
added/removed menu items and clearer warnings when items are removed.
* **Refactor**
* Updated numeric input formatting to use locale-aware formatting logic,
preserving grouping and precision behavior.
* **Tests**
* Added a test ensuring legacy menu extraction handles items with
undefined content correctly.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8602-fix-prevent-duplicate-context-menu-items-by-using-content-based-comparison-2fd6d73d36508197aa74c3409c7425fa)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Terry Jia <terryjia88@gmail.com>
2026-02-04 20:06:58 -08:00
Comfy Org PR Bot
7404756b6d 1.39.7 (#8614)
Patch version increment to 1.39.7

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8614-1-39-7-2fe6d73d365081449fa7cc9143adf0fa)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
v1.39.7
2026-02-04 18:38:15 -08:00
Christian Byrne
7c6e2d2c7a fix: disable CodeRabbit high_level_summary to stop PR description auto-updates (#8615)
## Summary

Disables the `high_level_summary` feature in CodeRabbit's configuration.
This feature automatically modifies the PR description every time a
commit is pushed, which was causing frustration for developers.

## Changes

- Set `high_level_summary: false` in `.coderabbit.yaml`

## Context

Discussed in #frontend-code-reviews Slack channel. The team agreed that
having PR descriptions automatically modified with every commit push is
not desirable behavior.

---

Fixes
https://www.notion.so/comfy-org/Ops-Disable-high_level_summary-in-ComfyUI_frontend-coderabbit-yaml-2fd6d73d3650812b9eb8d6680fa11932

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8615-fix-disable-CodeRabbit-high_level_summary-to-stop-PR-description-auto-updates-2fe6d73d36508112ac16f5df51845fcd)
by [Unito](https://www.unito.io)
2026-02-04 18:37:44 -08:00
pythongosssss
6feb2022a4 Add support for search aliases on subgraphs (#8608)
## Summary

- add commands for setting search aliases and description when in
subgraph
- in future we can add these fields to the dialog when publishing a
subgraph
- map workflow extra metadata on save/load from from/to subgraph node to
allow access via `canvas.subgraph.extra`

## Changes

**What**: 
- new core commands for Comfy.Subgraph.SetSearchAliases &
Comfy.Subgraph.SetDescription to be called when in a subgraph context
- update Publish command to allow command metadata arg for name
- update test executeCommand to allow passing metadata arg

## Review Focus

- When saving a subgraph, the outer workflow "wrapper" is created at the
point of publishing. So unlike a normal workflow `extra` property that
is available at any point, for a subgraph this is not accessible.
To workaround this, the `extra` property that exists on the inner
subgraph node is copied to the top level on save, and restored on load
so extra properties can be set via `canvas.subgraph.extra`.
- I have kept the existing naming format matching `BlueprintDescription`
for `BlueprintSearchAliases` but i'm not sure if the description was
ever used before

## Screenshots


https://github.com/user-attachments/assets/4d4df9c1-2281-4589-aa56-ab07cdecd353

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8608-Add-support-for-search-aliases-on-subgraphs-2fd6d73d365081d083caebd6befcacdd)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Set subgraph search aliases (comma-separated) and descriptions;
aliases enable discovery by alternative names.
  * Publish subgraphs using a provided name.
* Node definitions now support search aliases so nodes can be found by
alternate names.
  * UI strings added for entering descriptions and search aliases.

* **Tests**
* Added end-to-end and unit tests covering aliases, descriptions, search
behavior, publishing, and persistence.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-04 12:52:30 -08:00
Alexander Brown
b8287f6c2f Update manifest.json to remove color properties (#8612)
Removed background and theme colors from manifest.



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Removed custom color theme settings from the app's configuration. The
app's display mode and all other properties remain unchanged.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-04 12:25:28 -08:00
Luke Mino-Altherr
036675bb49 fix: Safari compatibility issues in Secrets panel dialog (#8610)
## Summary
Fixes multiple Safari-specific issues in the Secrets panel dialog:

1. **Dropdown not opening** - Safari has issues with click events on
portaled content inside dialogs. Added `disablePortal` prop to
`SelectContent` to render content inline.
2. **Close button focused on open** - Added `autofocus` to
`SelectTrigger` so focus goes to the first form field.
3. **Buttons not focusable** - Safari doesn't focus buttons on click by
default. Added `tabindex="0"` to Cancel/Save buttons.

## Changes
- `SelectContent.vue`: Added `disablePortal` prop with explanatory
comment linking to upstream issue
- `SecretFormDialog.vue`: Applied Safari workarounds

## References
- https://github.com/chakra-ui/ark/issues/1782 (Portal issue in Safari)
- https://mayank.co/blog/safari-focus/ (Button focus behavior)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added option to disable portal rendering in select components for
greater control over component behavior.

* **Bug Fixes**
* Improved keyboard accessibility in form dialogs with enhanced focus
management, auto-focus on select triggers, and optimized tab navigation
for action buttons.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Amp <amp@ampcode.com>
2026-02-04 19:58:40 +00:00
Terry Jia
507500a9d7 fix: use Intl.NumberFormat instead of vue-i18n n() for number formatting (#8600)
## Summary

vue-i18n's n() function does not support passing
Intl.NumberFormatOptions directly as the second argument. When widgets
without precision defined (e.g., KJNodes' CreateShapeImageOnPath) were
rendered, the n() function threw a SyntaxError in parseNumberArgs.

Replace n() with native Intl.NumberFormat which properly supports
NumberFormatOptions while still using the i18n locale for localization.

## Screenshots (if applicable)
before

https://github.com/user-attachments/assets/eb48379b-fe45-4f1c-a674-b92130f0fcac

after

https://github.com/user-attachments/assets/1abcd2da-ad8b-4432-831a-2a7e91f375a5



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Enhanced number input widgets with improved locale-aware number
formatting, ensuring proper decimal and group separator display based on
user locale settings.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8600-fix-use-Intl-NumberFormat-instead-of-vue-i18n-n-for-number-formatting-2fd6d73d365081b78509e87d516c6067)
by [Unito](https://www.unito.io)
2026-02-03 20:57:49 -05:00
Comfy Org PR Bot
6499eda004 1.39.6 (#8595)
Patch version increment to 1.39.6

**Base branch:** `main`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
  * Version bumped to 1.39.6.

* **New Features**
* Added multilingual UI strings for secrets management, asset import
errors, app-mode prompts, and HitPaw tools.
* New node types for image/video/audio workflows and expanded export
formats (GLB/FBX/OBJ) for 3D/model outputs.

* **Bug Fixes / Removals**
* Removed the "Open 3D Viewer (Beta) for Selected Node" menu entry and
related 3D viewer settings.
* Added setting to enable automatic node replacement when mappings
exist.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8595-1-39-6-2fd6d73d3650818cba9cffca313909e8)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
v1.39.6
2026-02-03 17:27:52 -08:00
Christian Byrne
a7e4a86ec8 fix: correct #visibleReroutes to _visibleReroutes typo (#8597)
Fixes build failure on main caused by merge conflict typo.

- `#visibleReroutes` → `_visibleReroutes` on line 5644 of
LGraphCanvas.ts

Fixes
https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/21653103679/job/62422017295

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
  * Internal code style adjustment with no user-facing impact.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8597-fix-correct-visibleReroutes-to-_visibleReroutes-typo-2fd6d73d365081ce9202d070f80fc5c3)
by [Unito](https://www.unito.io)
2026-02-03 16:54:00 -08:00
Christian Byrne
ffc0bf00ef fix: make SubgraphNode.graph nullable to allow proper cleanup (#8180)
## Summary

Fix `SubgraphNode.graph` property to match `LGraphNode` lifecycle
contract. Previously declared as `override readonly graph` via
constructor parameter promotion, which prevented `LGraph.remove()` from
setting `node.graph = null`.

## Changes

- Remove `readonly` from `SubgraphNode.graph` constructor parameter
- Add `override graph: GraphOrSubgraph | null` as class property  
- Add `NullGraphError` guard in `rootGraph` getter with node ID for
debugging
- Add null guards in `ExecutableNodeDTO.resolveInput` and
`imagePreviewStore.revokeSubgraphPreviews`
- Add test verifying `rootGraph` throws after node removal

## Testing

- Existing subgraph tests pass
- New test confirms `NullGraphError` is thrown when accessing
`rootGraph` on removed node

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-02-03 16:18:48 -08:00
Christian Byrne
66e776774a feat: add default keybindings for toggle mode and assets panel (#8593)
## Summary
Add default keyboard shortcuts for mode toggle and assets panel access.

## Changes
- **Ctrl+Shift+A**: Toggle between Simple Mode and Graph Mode
(`Comfy.ToggleLinear`)
- **A**: Open/toggle assets panel (`Workspace.ToggleSidebarTab.assets`)
- Show keybinding in ModeToggle button tooltip (e.g. "Simple Mode
(Ctrl+Shift+A)")

## Keybinding Rationale
- `A` follows the existing pattern: `w` (workflows), `n` (node-lib), `m`
(model-lib)
- `Ctrl+Shift+A` chosen because:
  - Ctrl+Shift is the standard modifier pattern for toggle commands
  - "A" mnemonic for "App mode"
  - Does not conflict with existing keybindings

## Testing
- Verified typecheck passes
- Verified lint passes

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Tooltips now show dynamic keyboard shortcut suffixes for mode and tab
controls.
  * Added keyboard shortcut: A — toggles the assets sidebar.
  * Added keyboard shortcut: Ctrl+Shift+A — toggles linear mode.

* **Localization**
* Added a localized shortcut suffix template so displayed shortcuts
respect translations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8593-feat-add-default-keybindings-for-toggle-mode-and-assets-panel-2fc6d73d36508172bd6ed3378f43de55)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-02-03 16:06:33 -08:00
Christian Byrne
f98232c272 fix: suppress link rendering during slot sync after graph reconfigure (#8367)
## Description

Fixes link alignment issues after undo/redo operations in Vue Nodes 2.0.
When multiple connections exist from the same output to different nodes,
performing an undo would cause the connections to become misaligned with
their inputs.

## Root Cause

When undo triggers `loadGraphData`, the graph is reconfigured and Vue
node components are destroyed and recreated. The new slot elements mount
and schedule RAF-batched position syncs via `scheduleSlotLayoutSync`.
However, links are drawn **before** the RAF batch completes, causing
`getSlotPosition()` to return stale/missing positions.

## Solution

- Export a new `flushPendingSlotLayoutSyncs()` function from
`useSlotElementTracking.ts`
- Create a `useGraphConfigureSlotSync` composable that flushes pending
syncs after graph configuration
- Integrate the flush into `addAfterConfigureHandler` in `app.ts`,
called after `onAfterGraphConfigured`
- Force canvas redraw after flushing to render links with correct
positions

## Testing

- Added unit tests for `flushPendingSlotLayoutSyncs`
- Added unit tests for `useGraphConfigureSlotSync` composable
- Manual verification: connections now align correctly after undo/redo
operations

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8367-fix-flush-pending-slot-layout-syncs-after-graph-configure-2f66d73d365081a3a564fac96c44a048)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-02-03 15:56:31 -08:00
Christian Byrne
278d491030 refactor: move ellipsis and punctuation into i18n translation strings (#8573)
## Summary

Move ellipsis and punctuation characters into i18n translation strings
for proper internationalization support.

## Changes

- Add 12 new translation keys with punctuation included:
- Placeholder keys with trailing ellipsis (e.g.,
`searchNodesPlaceholder: "Search Nodes..."`)
  - `downloadWithSize` with interpolation: `"Download ({size})"`
  - `completedWithCheckmark`: `"Completed ✓"`
- Prompt keys with colons (e.g., `enterNewNamePrompt: "Enter new
name:"`)
- Update 20 files to use new translation keys instead of string
concatenation

## Review Focus

This eliminates string concatenation patterns like `$t('key') + '...'`
that break proper internationalization, since different languages may
use different punctuation or may not need ellipsis/colons in the same
contexts.

Fixes #7333


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Standardized localization across the app: unified search placeholders
and input hints; updated dialog prompt texts for renaming,
saving/exporting, and related prompts.
* **New Features**
  * Download buttons now show file size via localized text.
  * Completed status displays a localized label with a checkmark.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8573-refactor-move-ellipsis-and-punctuation-into-i18n-translation-strings-2fc6d73d365081828ad3f257bcac7799)
by [Unito](https://www.unito.io)
2026-02-03 15:50:18 -08:00
Christian Byrne
4b43eb5fff refactor: use isActiveJobState instead of duplicated cancellableStates (#8572)
## Summary

Eliminates code duplication by replacing local `cancellableStates`
arrays with the centralized `isActiveJobState` utility function.

## Changes

- Remove duplicated `cancellableStates: JobState[] = ['pending',
'initialization', 'running']` from:
  - `src/composables/queue/useJobActions.ts`
  - `src/storybook/mocks/useJobActions.ts`
- Import and use `isActiveJobState` from `src/utils/queueUtil.ts`
instead

## Testing

- Typecheck passes
- Lint passes
- Related queue tests pass

Fixes #7947

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8572-refactor-use-isActiveJobState-instead-of-duplicated-cancellableStates-2fc6d73d365081f89decfc869fa952a0)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
  * Internal code improvements to simplify job state management logic.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-03 15:49:11 -08:00
Christian Byrne
67107d6f56 fix: use consistent chevron icon in Vue node dropdown widgets (#8576)
## Summary

Fixes styling inconsistency where Vue node select widget chevrons look
different between dropdown implementations.

## Changes

- **What**: Added `#dropdownicon` slot to `WidgetSelectDefault.vue`
using Lucide chevron icon with
`text-component-node-foreground-secondary` styling, matching
`FormDropdownInput.vue`

## Review Focus

Both dropdown implementations now use identical chevron icons with
consistent sizing (`size-4`) and color tokens.

Fixes #COM-11645


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Style**
* Updated select/dropdown appearance: replaced the previous icon
rendering with a customizable dropdown icon slot, improving visual
consistency and allowing a custom icon to display in select controls
across the UI. This change affects only presentation—no behavior or data
handling was altered.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8576-fix-use-consistent-chevron-icon-in-Vue-node-dropdown-widgets-2fc6d73d3650814e923bcbee83fae498)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-02-03 15:48:25 -08:00
Christian Byrne
32da91ea32 perf: code-split xterm bundle and gate terminal features for cloud (#8528)
## Summary

Code-splits the ~400KB xterm bundle and excludes terminal features from
cloud distribution where they are not needed.

### Changes

- **bottomPanelStore.ts**: Gate terminal tab registration behind
`__DISTRIBUTION__ !== 'cloud'` check with dynamic import, enabling
tree-shaking
- **keybindingService.ts**: Skip logs-terminal keybinding registration
for cloud distribution
- **vite.config.mts**: Add `vendor-xterm` code splitting group

### Bundle Impact

| Distribution | xterm in bundle | Terminal tabs |
|--------------|-----------------|---------------|
| cloud |  No (~400KB saved) | None |
| localhost |  Yes (vendor-xterm chunk) | Logs terminal |
| desktop |  Yes (vendor-xterm chunk) | Logs + Command terminal |

### Verification Script

Run locally to verify xterm exclusion works correctly:

```bash
#!/bin/bash
set -e

echo "=== Verifying xterm bundle exclusion ==="
echo

# Clear Nx cache to ensure fresh builds
pnpm nx reset 2>/dev/null

# Build cloud distribution
echo "Building CLOUD distribution..."
rm -rf dist
DISTRIBUTION=cloud pnpm build --mode production 2>/dev/null

echo "Cloud build - checking for xterm:"
if grep -r "xterm" dist/assets/*.js >/dev/null 2>&1; then
  echo "   FAIL: xterm found in cloud bundle"
  grep -l "xterm" dist/assets/*.js | head -5
else
  echo "   PASS: xterm NOT in cloud bundle"
fi
echo

# Build localhost distribution
echo "Building LOCALHOST distribution..."
pnpm nx reset 2>/dev/null
rm -rf dist
DISTRIBUTION=localhost pnpm build --mode production 2>/dev/null

echo "Localhost build - checking for xterm:"
if grep -r "xterm" dist/assets/*.js >/dev/null 2>&1; then
  echo "   PASS: xterm found in localhost bundle"
  echo "  Files containing xterm:"
  grep -l "xterm" dist/assets/*.js | while read f; do
    size=$(wc -c < "$f")
    echo "    $(basename $f) ($(numfmt --to=iec $size))"
  done
else
  echo "   FAIL: xterm NOT in localhost bundle"
fi
echo

echo "=== Verification complete ==="
```

**Note**: Nx cache must be reset between builds with different
`DISTRIBUTION` values or it may return stale results.

## Test Plan

- [x] Quality gates pass (typecheck, lint, format, tests)
- [x] Cloud build verified: xterm NOT present
- [x] Localhost build verified: xterm present as vendor-xterm chunk

Fixes COM-14129

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8528-perf-code-split-xterm-bundle-and-gate-terminal-features-for-cloud-2fa6d73d365081a093ecc74ca7ce6e7c)
by [Unito](https://www.unito.io)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Terminal tab declarations adjusted (no user-visible behavior change).
* Bottom panel tabs now load asynchronously; panel toggle falls back to
shortcuts when terminal tabs aren’t loaded.

* **Chores**
* Terminal tabs and related keybindings suppressed in cloud deployments.
  * Core commands wired to a new utility to support widget promotion.

* **Tests**
* E2E tests updated to handle async terminal-tab loading and minor test
cleanup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-02-03 15:15:37 -08:00
Christian Byrne
cfc24e3567 docs: audit and update litegraph documentation (#8588)
## Summary

Audits and updates litegraph documentation files that came from the old
litegraph.js repo merged via git subtree (per #8341 discussion).

## Changes

- **Delete** `CONTRIBUTING.md` - completely outdated, referenced
original jagenjo/litegraph.js from 2020
- **Fix** `API.md` - remove Subgraph from "Removed public interfaces"
(actively used in 25+ files)
- **Update** `README.md` - replace standalone releasing instructions
with note about embedded subtree workflow
- **Fix** `AGENTS.md` and `__fixtures__/README.md` - correct import path
typos (`./fixtures/` → `./__fixtures__/`)

Fixes #8347

cc @DrJKL

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Documentation

* Updated release information to clarify that the library is embedded
via git subtree and managed through the parent repository's release
process
* Removed contribution guidelines documentation file
* Updated API documentation by removing Subgraph from the list of
removed public interfaces
* Updated documentation examples to align with current project structure

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8588-docs-audit-and-update-litegraph-documentation-2fc6d73d365081fca335c78ce8493d3e)
by [Unito](https://www.unito.io)
2026-02-03 15:07:43 -08:00
Christian Byrne
eb1d08e9fe feat: enable CodeRabbit reviews on draft PRs (#8587)
Enable CodeRabbit to automatically review draft pull requests.

## Changes
- Added `reviews.auto_review.drafts: true` to `.coderabbit.yaml`

This allows getting early feedback from CodeRabbit while PRs are still
in draft status.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Enabled automatic review drafting to streamline the review process.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8587-feat-enable-CodeRabbit-reviews-on-draft-PRs-2fc6d73d365081ea8f1bcae4a2a8277b)
by [Unito](https://www.unito.io)
2026-02-03 13:41:29 -08:00
Christian Byrne
a350b59361 feat: Add educational hint to favorites empty state (#8559)
## Summary

Adds an educational hint to the favorites empty state to teach users how
to favorite inputs.

## Changes

- Add new i18n key `favoritesNoneHint` with text "In the Parameters tab,
click ⋮ on any input to add it here"
- Update empty state template to show hint below the existing
description
- Hint is hidden during search to avoid redundant messaging

## Before/After

**Before:** "Inputs you favorite will show up here"

**After:**
- "Inputs you favorite will show up here"
- "In the Parameters tab, click ⋮ on any input to add it here*

## Context

Per Slack discussion, uses in-app education only (no external docs link)
to ensure text matches the user's specific version of the feature.

Fixes #2fa6d73d

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8559-feat-Add-educational-hint-to-favorites-empty-state-2fc6d73d365081f5827dfafcc1ece95c)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved empty state in the Parameters panel: message is now two
paragraphs and shows an additional hint (with an icon) when not
searching.
* **Localization**
* Added a new localized hint that explains how to add inputs to
favorites, shown in the Parameters panel empty state.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Rizumu Ayaka <rizumu@ayaka.moe>
2026-02-03 13:24:52 -08:00
Christian Byrne
1031af0ad4 feat: update user-facing 'Simple Mode' terminology to 'App Mode' (#8590)
## Summary
Updates all user-facing instances of 'Simple Mode' / 'Linear Mode' to
'App Mode' as discussed in PR #8562.

## Changes
- Updated command label in `useCoreCommands.ts`
- Updated `src/locales/en/commands.json`
- Updated all 12 locale `main.json` files with:
  - `linearMode.linearMode` → "App Mode" (translated)
  - `linearMode.beta` → "App Mode in Beta - Feedback" (translated)
  - `Toggle Simple Mode` command → `Toggle App Mode` (translated)

## Languages Updated
en, zh, zh-TW, ja, ko, fr, es, pt-BR, ru, tr, ar, fa

## Notes
Internal variable names (`linearMode`, `canvasStore.linearMode`) remain
unchanged to avoid breaking changes.

Fixes #8577

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Style**
* Renamed application terminology from "Simple Mode" to "App Mode" in
user interface labels, mode descriptions, and mode toggle command.
Updates applied consistently across all 12 supported language
translations to ensure consistent terminology throughout the
application.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8590-feat-update-user-facing-Simple-Mode-terminology-to-App-Mode-2fc6d73d36508160a19af70b228b0a7e)
by [Unito](https://www.unito.io)
2026-02-03 13:06:25 -08:00
Christian Byrne
4d8254740d refactor: replace type catch-all with generic ComponentAttrs in showLayoutDialog (#8571)
## Summary

Replaces `Record<string, unknown>` catch-all with properly typed generic
props in `showLayoutDialog`, improving type safety.

## Changes

- Made `showLayoutDialog` generic over component type `C extends
Component`
- Changed props type from `{ onClose: () => void } & Record<string,
unknown>` to `ComponentAttrs<C> & { onClose: () => void }`

This matches existing patterns used elsewhere in `dialogService.ts`
(e.g., `showLoadWorkflowWarning`, `showMissingModelsWarning`).

Fixes #8102

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Dialog handling updated to infer props per component, resulting in
more consistent and reliable dialog behavior and fewer runtime prop
mismatches when opening dialogs. Developers will have clearer, safer
dialog configuration, while end users should experience steadier dialog
interactions. No visible UI changes are expected.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8571-fix-replace-type-catch-all-with-generic-ComponentAttrs-in-showLayoutDialog-2fc6d73d36508104bf60d27c9b94af69)
by [Unito](https://www.unito.io)
2026-02-03 13:05:13 -08:00
Alexander Brown
f2d5bfab73 test(browser): refactor browser tests for reliability and maintainability (#8510)
## Summary

Major refactoring of browser tests to improve reliability,
maintainability, and type safety.

## Changes

### Test Infrastructure Decomposition
- Decomposed `ComfyPage.ts` (~1000 lines) into focused helpers:
- `CanvasHelper`, `DebugHelper`, `SubgraphHelper`,
`NodeOperationsHelper`
- `SettingsHelper`, `WorkflowHelper`, `ClipboardHelper`,
`KeyboardHelper`
- Created `ContextMenu` page object, `BaseDialog` base class, and
`BottomPanel` page object
- Extracted `DefaultGraphPositions` constants

### Locator Stability
- Added `data-testid` attributes to Vue components (sidebar, dialogs,
node library)
- Created centralized `selectors.ts` with test ID constants
- Replaced fragile CSS selectors (`.nth()`, `:nth-child()`) with
`getByTestId`/`getByRole`

### Performance & Reliability
- Removed `setTimeout` anti-patterns (replaced with `waitForFunction`)
- Replaced `waitForTimeout` with retrying assertions
- Replaced hardcoded coordinates with computed `NodeReference` positions
- Enforced LF line endings for all text files

### Type Safety
- Enabled `no-explicit-any` lint rule for browser_tests via oxlint
- Purged `as any` casts from browser_tests
- Added Window type augmentation for standardized window access
- Added proper type annotations throughout

### Bug Fixes
- Restored `ExtensionManager` API contract
- Removed test-only settings from production schema
- Fixed flaky selectors and missing test setup

## Testing
- All browser tests pass
- Typecheck passes


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Tests**
* Overhauled browser E2E test infrastructure with many new
helpers/fixtures, updated test APIs, and CI test container image bumped
for consistency.

* **Chores**
* Standardized line endings and applied stricter lint rules for browser
tests; workspace dependency version updated.

* **Documentation**
* Updated Playwright and TypeScript testing guidance and test-run
commands.

* **UI**
* Added stable data-testids to multiple components to improve
testability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-03 12:29:40 -08:00
Jin Yi
eb14a2947f style: scale down node previews in manager info panel (#8579)
## Summary
Scale down node previews in the manager info panel to 75% for better
visual fit.

## Changes
- Add 75% scale to node preview items in NodesTabPanel
- Add gap between scaled items for better spacing

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Style**
* Enhanced the visual layout of node items in the manager panel with
improved spacing and individual item scaling for better visual
presentation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8579-style-scale-down-node-previews-in-manager-info-panel-2fc6d73d36508176a307d980cd3b9329)
by [Unito](https://www.unito.io)
2026-02-03 11:41:19 -08:00
Johnpaul Chiwetelu
b2c8ea3e50 refactor: use emit events pattern instead of mutating props in widget components (#8549) 2026-02-03 11:21:14 +01:00
Terry Jia
f9af2cc4bd feat: add aspect ratio lock for ImageCrop widget (#8533)
## Summary

Add ratio preset dropdown (1:1, 3:4, 4:3, 16:9, 9:16, custom) and lock
toggle to the ImageCrop widget. When locked, only corner handles are
shown and resizing maintains the selected aspect ratio using diagonal
projection for smooth, jump-free interaction.
Locking with custom selected captures the current crop's ratio.

## Screenshots (if applicable)


https://github.com/user-attachments/assets/a7b5c0a0-c18c-4785-940f-59793702e892

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8533-feat-add-aspect-ratio-lock-for-ImageCrop-widget-2fa6d73d365081a98546e43ed0d7d4fe)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Image crop widget adds a ratio selector with preset and custom
options, plus a lock/unlock toggle to preserve aspect while cropping.
* Constrained corner-resize behavior enforces locked aspect ratios
during resizing.

* **Documentation**
* Added UI text entries for ratio controls (labels for ratio,
lock/unlock, custom).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-03 04:24:33 -05:00
Christian Byrne
a3fba58c79 refactor: move cancellable states to module-level constant (#8570)
## Summary

Moves static data outside the `useJobActions` composable to
module-level.

## Changes

- **What**: Extracted `cancellableStates` array to a module-level
`CANCELLABLE_STATES` constant. The `cancelAction` object remains inside
the composable because it depends on `t()` for i18n reactivity.

## Review Focus

This is a pure refactor with no behavior change - the constant is now
allocated once per module instead of per-composable-call.

Fixes #7946

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8570-refactor-move-cancellable-states-to-module-level-constant-2fc6d73d3650814fa1fefa172f7ace2f)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Internal code refactoring to improve maintainability of job
cancellation logic.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-02 21:46:12 -08:00
Christian Byrne
ae7728cd91 feat: add welcome message for Linear Mode (#8562)
## Summary

Adds a welcome/onboarding message for App Mode (Linear Mode) that
displays when no workflow output is selected, targeting first-time
users.


| Before | After |
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
| <img width="1914" height="1084" alt="Screenshot from 2026-02-02
20-47-30"
src="https://github.com/user-attachments/assets/f3693422-b6ee-496a-a354-d9cede501330"
/> | <img width="1919" height="1085" alt="Screenshot from 2026-02-02
21-32-20"
src="https://github.com/user-attachments/assets/dbfda4d0-251c-4099-ad36-3d7c0220d264"
/> |


## Changes

- **LinearWelcome.vue**: New component with 4 sections explaining App
Mode interface, sharing workflows, and widget control
- **LinearPreview.vue**: Replace dimmed logo fallback with LinearWelcome
component
- **i18n**: Add `linearMode.welcome.*` translation keys

## Review Focus

- Copy targets users who have never used ComfyUI—assumes no knowledge of
nodes/graphs
- Component uses semantic Tailwind classes from design system

Fixes COM-14274

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8562-feat-add-welcome-message-for-Linear-Mode-2fc6d73d365081b2b736f211152e1cce)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added a comprehensive welcome screen in App Mode that introduces users
to the simplified interface hiding node graphs, explains the layout
structure with outputs and controls, provides instructions for sharing
workflows as simple tools, and guides users on customizing which
settings are visible through widget promotion.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-02 21:44:30 -08:00
Jin Yi
5847071bc1 [feat] Add node replacement store and types (#8364)
## Summary
Add infrastructure for automatic node replacement feature that allows
missing/deprecated nodes to be replaced with their newer equivalents.

## Changes
- **Types**: `NodeReplacement`, `NodeReplacementResponse` types matching
backend API spec (PR #12014)
- **Service**: `fetchNodeReplacements()` API wrapper
- **Store**: `useNodeReplacementStore` with `getReplacementFor()`,
`hasReplacement()`, `isEnabled()`
- **Setting**: `Comfy.NodeReplacement.Enabled` toggle (experimental)
- **Tests**: 11 unit tests covering store functionality

## Related
- Backend PR: Comfy-Org/ComfyUI#12014

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8364-feat-Add-node-replacement-store-and-types-2f66d73d3650816bb771c9cc6a8e1774)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Automatic node replacement is now available, allowing missing nodes to
be replaced with their newer equivalents when replacement mappings
exist.
* Added "Enable automatic node replacement" experimental setting in
Workflow preferences (enabled by default).
  * Replacement data is loaded during app initialization.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-03 14:15:05 +09:00
Christian Byrne
cc10684c19 feat: enable linear mode toggle for nightly builds (#8569)
Enables the linear mode toggle for all nightly build users by
short-circuiting the `linearToggleEnabled` feature flag.

## Changes
- Adds `isNightly` check in `linearToggleEnabled` getter  
- Returns `true` for nightly builds, bypassing remote config/server
feature checks
- Adds unit tests for the new behavior

## Reviewers
- @AustinMroz (linear mode maintainer)
- @christian-byrne (isNightly author)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8569-feat-enable-linear-mode-toggle-for-nightly-builds-2fc6d73d3650819681f8dcdc23b6eefe)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Enabled linear toggle feature for nightly distribution builds.
* Feature flag system now respects nightly vs. standard build
configurations.

* **Tests**
* Added test coverage for nightly build feature flag behavior and remote
configuration handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-02-02 19:54:50 -08:00
Christian Byrne
380db3ee10 chore: add deprecation warning for legacy node templates extension (#8463)
## Summary

Adds the legacy `nodeTemplates` extension to the `DEPRECATED_FILES` list
in the build plugin, causing a console warning when external extensions
import from this file.

## Changes

Adds `'extensions/core/nodeTemplates'` to `DEPRECATED_FILES` in
`build/plugins/comfyAPIPlugin.ts`.

## Effect

When an external extension imports from
`extensions/core/nodeTemplates.js`, they will see:
```
[ComfyUI Deprecated] Importing from "extensions/core/nodeTemplates.js" is deprecated and will be removed in v1.34.
```

## Related

- Follows pattern from PR #6090 (feat: deprecated API alert)
- Related issue: #4056 (Migrate Node Templates to Workflows)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8463-chore-add-deprecation-warning-for-legacy-node-templates-extension-2f86d73d3650811e9f53fa3e5a572332)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-02-02 19:22:07 -08:00
Alexander Brown
cbdc7d030f feat: code splitting optimization - reduce initial bundle by 36% (#8542)
## Summary

Reduces initial module preload from 12.94 MB to 8.24 MB (-4.7 MB, -36%).

## Changes

- Split vendor chunks for better cache isolation (firebase, sentry,
i18n, zod, etc.)
- Exclude heavy optional chunks from initial preload: THREE.js, xterm,
tiptap, chart.js, yjs
- Lazy load 16 dialog components in dialogService
- Add \endor-yjs\ chunk for CRDT library

## Metrics

| Metric | Before | After |
|--------|--------|-------|
| Initial preload | 12.94 MB | 8.24 MB |
| vendor-other | 4,006 KB | 2,156 KB |
| dialogService | 1,860 KB | 1,304 KB |

All excluded chunks still load on-demand when their features are used.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8542-feat-code-splitting-optimization-reduce-initial-bundle-by-36-2fb6d73d36508146aaf7fdaed3274033)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-02-02 19:05:28 -08:00
Alexander Brown
21492ecca5 fix: update imports for VueUse v14 compatibility (#8550)
Update imports for VueUse v14 compatibility:
- `toValue` → import from `vue` (dropped from VueUse v14)
- `MaybeRef` type → import from `vue` (dropped from VueUse v14)

These APIs were deprecated in VueUse v12 and removed in v14 in favor of
Vue's native exports.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8550-fix-update-imports-for-VueUse-v14-compatibility-2fb6d73d365081b0bac1d01d4092c176)
by [Unito](https://www.unito.io)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Updated VueUse dependencies to newer versions for improved
compatibility
  * Minor package entry reorganization (no functional changes)

* **Refactor**
  * Consolidated imports to use native Vue utilities where applicable

* **Tests**
* Updated unit tests: improved outside-click simulation and cleanup;
migrated tests to use the real store setup for more realistic test
behavior
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-02-02 18:58:14 -08:00