Compare commits

..

108 Commits

Author SHA1 Message Date
Benjamin Lu
b163d17d78 Fix slot layout validity on rendering system change 2025-09-04 23:26:23 -07:00
bymyself
c52c798817 removed unused node def type guards 2025-09-04 21:16:43 -07:00
bymyself
f6ae1b6417 remove unused typeguards 2025-09-04 21:15:20 -07:00
bymyself
896e44f66b move back test that was mistakenly moved 2025-09-04 21:14:05 -07:00
bymyself
8e098fc325 simplify widget registration 2025-09-04 21:11:30 -07:00
bymyself
85fa2f4559 removed unused type guards 2025-09-04 21:02:32 -07:00
bymyself
07b7ed9385 use camelcase for layoutStore filename 2025-09-04 19:59:49 -07:00
bymyself
817f4d036a remove redundant comment 2025-09-04 19:56:49 -07:00
Christian Byrne
6eeba70f10 - Fix memory leaks in node deletion (#5345)
- Fix TypeScript types in Yjs observers with proper YEventChange type
- Refactor nested observer logic into focused single-responsibility methods
- Consolidate duplicated link segment cleanup logic into reusable methods
- Extract findLinksConnectedToNode method for better readability
- Add explanatory comments for spatial index update ordering
- Extract REROUTE_RADIUS constant instead of magic numbers
- Maintain consistent parameter naming conventions
2025-09-04 19:56:19 -07:00
bymyself
7d8bdcb05a remove debug viewport test 2025-09-04 19:43:38 -07:00
bymyself
0aed837ff4 use camelCase for all non-component files 2025-09-04 19:38:51 -07:00
bymyself
b7fd1f476c add missing translations 2025-09-04 19:30:35 -07:00
bymyself
358d98e268 cleanup comments 2025-09-04 19:25:55 -07:00
bymyself
df36693ecb cleanup comments 2025-09-04 19:21:40 -07:00
bymyself
f6051f6634 remove event forwarding hack. todo: add link moving in vue 2025-09-04 19:19:13 -07:00
bymyself
e8dae57a6a remove debug logging and setting 2025-09-04 18:54:23 -07:00
bymyself
1e307564f0 skip all vue node operations if feature is turned off 2025-09-04 18:41:07 -07:00
bymyself
9ab075f11c remove outdated README 2025-09-04 18:33:24 -07:00
bymyself
3e5effeafc remove debug viewport visualizer prop 2025-09-04 18:32:22 -07:00
bymyself
0b941583d2 remove debug viewport visualizer 2025-09-04 18:31:52 -07:00
bymyself
7149af612a change name "transformPaneEnabled" => "isVueNodesEnabled" 2025-09-04 18:27:18 -07:00
bymyself
4fc89847ab simplify unit tests 2025-09-04 18:24:48 -07:00
bymyself
2f512b847d remove debug overlay panel 2025-09-04 18:24:07 -07:00
bymyself
b0f2a1d00a remove all unused (knip pass) 2025-09-04 18:02:13 -07:00
bymyself
73a1feea99 removed unused IMAGE widget enum value 2025-09-04 17:48:52 -07:00
bymyself
7130794cba update adr README 2025-09-04 17:37:37 -07:00
bymyself
7b7f9bbb17 remove crdt ADR (moved to separate PR) 2025-09-04 17:36:26 -07:00
github-actions
0f5315f24c Update test expectations [skip ci] 2025-09-04 23:24:48 +00:00
Benjamin Lu
2425f653e4 [Vue Nodes] Fix Node Header Tests (#5360)
* Enable VueNodes

* Use KSampler not save image
2025-09-04 15:46:40 -07:00
Benjamin Lu
1480dd748a [bugfix] Fix NodeHeader test workflow path (#5359)
The test was using an incorrect path for the workflow file. Updated to use the correct path under the nodes/ subdirectory.

Fixes test failure: ENOENT error for single_save_image_node.json
2025-09-04 14:47:53 -07:00
Benjamin Lu
f99c9de72f [fix] Disable link markers on dragged connections (#5358)
Set linkMarkerShape to None for links being actively dragged by the mouse to prevent visual artifacts.
2025-09-04 14:25:06 -07:00
Benjamin Lu
2a64f538f3 Merge remote-tracking branch 'origin/main' into vue-nodes-migration 2025-09-04 13:52:26 -07:00
Christian Byrne
6a3c075df1 Removes node's dependency on LGraph for access to layout mutations composable (#5356)
* remove DI

* remove layoutMutations property on LGraph

* remove layout mutations property from LGraph snapshot
2025-09-04 13:46:39 -07:00
Benjamin Lu
c30f5a41a9 Remove IMAGE widget cont. (#5355) 2025-09-04 13:45:49 -07:00
Christian Byrne
8a10387fdf add explicit typing on component IDs (#5352) 2025-09-04 13:21:24 -07:00
Alexander Brown
58313ea05b devex: re-add caching of playwright browser installs (#5350) 2025-09-04 12:18:11 -07:00
Rizumu Ayaka
32cffa6a83 refactor: v3 ui slots connection dots (#5316)
* refactor: v3 ui slots connection dots

* fix: use the new useTemplateRef

* fix: slot dark-theme border and hover styles

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2025-09-04 11:48:48 -07:00
Rizumu Ayaka
1dbbf20124 feat: widget styles for V3 UI (#5320)
* feat: widget input text style

* feat: widget select button style

* feat: the selection style of LGraphNode

* feat(V3 UI style): color picker + file upload + input text + multi select + select + select button + slider + textarea + tree select

* feat: placeholder

* fix: filter multi select options

* fix: direct binding, no transform for select button widget
2025-09-04 10:54:26 -07:00
Christian Byrne
f83801e998 - Convert class-based LayoutMutations to useLayoutMutations() composable (#5346)
- Remove unnecessary useLayout wrapper that added boilerplate
- Use LayoutMutations interface directly in LGraph instead of redefining types
- Update all components to use composable pattern consistently
2025-09-04 10:48:33 -07:00
Benjamin Lu
969c8e6325 [bugfix] Remove placeholder IMAGE widget to restore previous functionality (#5349)
* Remove IMAGE widget

* Remove IMAGE widget test expectations
2025-09-04 10:33:02 -07:00
filtered
ae690bbfa4 DevX: Update CSS directives for Tailwind v4 (#5347)
- Provides proper IDE hints and removes warnings from .vue SFC files.
- Replaces all the v2 info with v4.
2025-09-04 10:32:22 -07:00
filtered
9920f310be [CI] Fix action throws after pnpm change (#5342) 2025-09-04 00:27:05 -07:00
Comfy Org PR Bot
ec7de6f4c5 [release] Increment version to 1.27.0 (#5343)
Co-authored-by: benceruleanlu <162923238+benceruleanlu@users.noreply.github.com>
2025-09-03 23:58:58 -07:00
Alexander Brown
a82fcd8ec6 Knip: Enable more rules (#5309)
* knip: Simplify config

* knip: enable unlisted, fix issues

* knip: Add ignore for build dependencies (Vite plugin indirect reference)

* knip: Prune dependencies

* knip: One more Unused dep

* git: Standard line end for yaml

* [auto-fix] Apply ESLint and Prettier fixes

* knip: Add exceptions for tailwindcss post-rebase.
Not sure why we need to except it.

* Update test expectations [skip ci]

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
2025-09-03 22:57:53 -07:00
filtered
9a9f8c72f2 Fix electron types update command in CI (#5337)
Use --workspace-root flag to install at workspace level
2025-09-03 22:45:51 -07:00
filtered
065d9e82b9 [chore] Update electron-types to 0.4.69 (#5339) 2025-09-03 22:35:01 -07:00
Alexander Piskun
4748378387 add prices for ByteDance Video API nodes (#5336) 2025-09-03 22:28:19 -07:00
Simula_r
c6fc8e6f0f fix: remove clipping by removing unnecessary css contain (#5327) 2025-09-03 18:57:59 -07:00
Arjan Singh
ad64dbb81a [feat] register UNETLoader, UpscaleModelLoader, StylemModelLoader... (#5324)
* [feat] register UNETLoader, UpscaleModelLoader, StylemModelLoader, GLIGENLoader

Also added tests for modelToNodeStore

* [fix] code review feedback on tests

* [fix] typescript bikeshedding

* [fix] remove unnecessary interface mocks
2025-09-04 01:24:24 +00:00
Johnpaul Chiwetelu
3c247e57f3 Remove caching of Playwright browsers from CI workflow (#5325)
* [refactor] Remove caching of Playwright browsers from CI workflow

* restore upload artifact path

* [fix] Adjust timeout for playwright tests to allow up to 15 minutes

* [fix] Update artifact name for Playwright report to match standard naming convention
2025-09-03 23:22:36 +01:00
Christian Byrne
589c362bc6 Trigger CI (#5326)
* Trigger CI

* Update test expectations [skip ci]

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-09-03 14:34:54 -07:00
Rizumu Ayaka
3ce3b67155 feat: localization fields (#5318) 2025-09-03 13:18:30 -07:00
AustinMroz
c4bb8a1435 Improve click regions for widget interaction (#5253) 2025-09-03 12:44:13 -07:00
Simula_r
c74c1c014f Feat/adaptive lod threshold (#5249)
* feat: use a physical min font size as the LOD threshold instead of an abritrary zoom level that is different on different screens

* feat: min 1px font size, max 24ox font size

* refactor: settings text

* refactor: settings text

* refactor: version

* fix: default font size from 10 to 8

* feat: cache the threshold and move it's calculation out of the render loop

* refactor: comments

* refactor: removed package-lock

* refactor: improve how we manage deprecated settings, and removed any types

* refactor: how the migration settings formula works so we get prev settings closer to the new font size setting

* test: add in zoom and settings test for LOD

* refactor: tests to use best practices

* Update test expectations [skip ci]

---------

Co-authored-by: github-actions <github-actions@github.com>
2025-09-03 12:38:44 -07:00
Alexander Brown
85017dbba0 Upgrade: Tailwind v4 (#5246)
* temp: move tailwind calls out of the layer

* temp: ts tailwind config

* upgrade: Tailwind v4
This got a little out of hand.
Had to add a relative reference to the stylesheet in any component that uses @apply instead of the utility classes directly.

* upgrade: bg-opacity is now a modifier

* fix: Classic menu buttons assume a border

* Update test expectations [skip ci]

* fix: New preflight removal pattern

* fix: Skeletons don't have skin

* Update test expectations [skip ci]

* fix: Missing @reference

* [auto-fix] Apply ESLint and Prettier fixes

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: GitHub Action <action@github.com>
2025-09-03 12:37:43 -07:00
Johnpaul Chiwetelu
caee3832a5 Playwright Test Sharding (#5311)
* [feat] Enhance Playwright testing workflow with sharding and report merging

* feat: shard playwright tests into 8 processes
2025-09-03 12:16:37 -07:00
Christian Byrne
e1f29465a9 [fix] Enable mouse gestures over video previews (#5279)
* [fix] Enable mouse gestures over video previews - fixes ctrl+scroll zoom and space+drag panning

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [improve] Enhance code clarity in media gesture handling with descriptive constants

* [clean] Remove dangling comment in handlePointer method

* [improve] Use satisfies and partial mocking for better type safety in tests

- Replace 'as any' with vi.mocked({partial: true}) for store mocks
- Use 'satisfies Partial<Event>' for better event type checking
- Remove 'not.toThrow' test as it tests default behavior
- Improve test readability and type safety per review feedback

* [improve] Test actual canvas existence check instead of side effects

- Replace vague 'graceful handling' test with specific 'early return' test
- Verify that getCanvas() is actually called to check canvas existence
- Test early return behavior when canvas is null rather than just preventDefault side effect
- More robust test that validates the intended logic flow

* [refactor] Use localized mocking instead of global mock functions

- Replace global mockGetCanvas and mockGet with in-situ vi.mocked() calls
- Extract store functions directly in test cases for better locality
- Follow DrJKL's suggestion for cleaner test structure
- Maintains same test coverage with improved readability

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-03 12:01:45 -07:00
Comfy Org PR Bot
0afbf94eb7 [release] Increment version to 1.26.9 (#5322)
Co-authored-by: benceruleanlu <162923238+benceruleanlu@users.noreply.github.com>
2025-09-03 13:53:47 -04:00
snomiao
f7889b514e [test] Fix flaky TTL expiration test in remoteWidgets.spec.ts (#5306)
* [test] Fix flaky TTL expiration test in remoteWidgets.spec.ts

The test 'refreshes options when TTL expires' was flaky due to timing issues.
Fixed by:
- Increasing initial widget update wait from 256ms to 300ms for stability
- Extending TTL expiration wait from 512ms to 600ms to ensure TTL has fully expired
- Adding explicit click location and wait after refresh trigger
- Adding clear comments explaining the timing requirements

This should make the test more reliable by providing sufficient buffer time for the TTL to expire and the widget to refresh properly.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

* [chore] Fix formatting in remoteWidgets.spec.ts

Remove trailing whitespace as per prettier rules

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-04 02:22:11 +09:00
Christian Byrne
a704d6e56f Fix snapshot tests and update PR title (#5314)
Updates outdated snapshots to match current LiteGraph behavior.
2025-09-03 10:13:06 -07:00
Christian Byrne
9a7d8cdca5 [refactor] Enforce enum type safety by removing type assertions (#5315)
Remove type assertions (as ManagerChannel) that bypass TypeScript's type
checking and replace with explicit Record typing. This ensures invalid
enum values are caught at compile time rather than runtime.

- Replace type assertions with Record<string, ManagerChannel> typing
- Remove manual casting that bypassed TypeScript validation
- Ensure enum values are validated during compilation
2025-09-03 12:19:13 -04:00
Christian Byrne
35f5773deb [bugfix] Fix invalid ManagerChannel enum value in nodepack installation (#5312)
* [bugfix] Fix invalid ManagerChannel enum value in nodepack installation

Fix nodepack installation failure caused by using 'stable' channel value
which is not defined in the ManagerChannel enum. Changed from 'stable'
to 'default' which is a valid enum value according to the backend schema.

Fixes nodepack installation requests that were failing validation at
/v2/manager/queue/task endpoint.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [refactor] Enforce type safety for enum values without type assertions

Remove type assertions (as ManagerChannel) and use explicit Record typing
to ensure compile-time validation of enum values. This prevents invalid
enum values from being used by catching them during TypeScript compilation
rather than runtime validation failures.

- Replace type assertions with Record<string, ManagerChannel> typing
- Remove manual casting that bypassed TypeScript's type checking
- Ensure invalid enum values cause compilation errors

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-02 22:55:17 -07:00
Terry Jia
65b6b27831 add litegraph test config (#5310)
* add litegraph test config

* remove unnecessary setup file

* exclude litegraph test config

* add npm script
2025-09-02 20:57:43 -07:00
Christian Byrne
66a76c0ee0 Upstream ComfyUI Manager frontend and add custom node conflict detection (#5291)
* migrate manager menu items

* Update locales [skip ci]

* switch to v2 manager API endpoints

* re-arrange menu items

* await promises. update settings schema

* move legacy option to startup arg

* Add banner indicating how to use legacy manager UI

* Update locales [skip ci]

* add "Check for Updates", "Install Missing" menu items

* Update locales [skip ci]

* use correct response shape

* improve command names

* dont show missing nodes button in legacy manager mode

* [Update to v2 API] update WS done message

* Update locales [skip ci]

* [fix] Fix json syntax error from rebase (#4607)

* Fix errors from rebase (removed `Tag` component import and duplicated imports in api.ts) (#4608)

Co-authored-by: github-actions <github-actions@github.com>

* Update locales [skip ci]

* [Manager] "Restarting" state after clicking restart button (#4637)

* [feat] Add reactive feature flags foundation (#4817)

* [feat] Add v2/ prefix to manager service base URL (#4872)

* [cleanup] Remove unused manager route enums (#4875)

* fix: v2 prefix (#5145)

* Fix: Restore api.ts from main branch after incorrect rebase (#5150)

* fix: api.ts file is different with main branch

* Update locales [skip ci]

* fix: restore support dotprop access

* fix: apply locales based on manager/menu-items-migration

* fix: Add missing shortcuts translation section for CI tests

- Added shortcuts section with keyboardShortcuts key
- Fixes failing Playwright test looking for 'Keyboard Shortcuts' aria-label
- Issue was caused by incomplete rebase from main branch

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

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Add missing versionMismatchWarning translations for CI tests

- Added versionMismatchWarning section with all required keys
- Added general versionMismatch related keys (updateFrontend, dismiss, etc.)
- Fixes failing Playwright tests for version mismatch warnings
- These keys were lost during the rebase from main branch

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

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Claude <noreply@anthropic.com>

* feat: Add loading state to PackInstallButton and improve UI (#5153)

* [restore] conflict notification commits restore

* [fix] Restore conflict notification work and fix tests

- Fix missing footerProps property in DialogInstance interface
- Add missing InstalledPacksResponse type import in tests
- Add missing getImportFailInfoBulk method to test mock
- Remove unused ManagerComponents import causing type error
- All unit and component tests now pass successfully

* [fix] Use Vue 3.5 destructuring syntax for props with defaults

Remove deprecated withDefaults usage in NodeConflictDialogContent.vue and use destructuring with default values instead

* [feature] dual modal supported

* [fix] Fix date format in PackCard test for locale consistency

* [fix] title text modified

* [fix] Fix conflict red dot not syncing
  between components

  Resolve reactivity issue by sharing
  useStorage refs across all
  composable instances to ensure UI
  consistency.

* [fix] Add conflict detection when installed packages list updates

- Import useConflictDetection composable in comfyManagerStore
- Call performConflictDetection after refreshing installed packages list
- Ensures conflict status stays up-to-date when packages change
- Follows existing codebase patterns for composable usage

* fix: use selected target_branch for PR base in update-manager-types workflow

* [fix]  test code timeout error fixed

* [chore] Update ComfyUI-Manager API types from ComfyUI-Manager@4e6f970 (#4782)

Co-authored-by: viva-jinyi <53567196+viva-jinyi@users.noreply.github.com>

* [types] Add proper types for ImportFailInfo API endpoints (#4783)

* [fix] ci error fixed & button max-width modified

* fix: node pack card width adapted

* fix: prevent duplicate api calls & installedPacksWithVersions instead of installpackids

* feat: run conflict detection after Apply Changes

Run performConflictDetection automatically after the backend restarts from Apply Changes button to detect conflicts in newly installed packages

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: simplify PackInstallButton isInstalling state management

- Remove isInstalling prop from PackInstallButton component
- Use internal computed property with comfyManagerStore.isPackInstalling()
- Remove redundant isInstalling computations from parent components
- Fix test mocks for useConflictDetection and es-toolkit/compat
- Clean up unused imports and inject dependencies

This centralizes the installation state management in the store,
reducing code duplication and complexity across components.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: improve multi-package selection handling (#5116)

* feat: improve multi-package selection handling

- Check each package individually for conflicts in install dialog
- Show only packages with actual conflicts in warning dialog
- Hide action buttons for mixed installed/uninstalled selections
- Display dynamic status based on selected packages priority
- Deduplicate conflict information across multiple packages
- Fix PackIcon blur background opacity

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: extract multi-package logic into reusable composables

- Create usePackageSelection composable for installation state management
- Create usePackageStatus composable for status priority logic
- Refactor InfoPanelMultiItem to use new composables
- Reduce component complexity by separating business logic
- Improve code reusability across components

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

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: directory modified

* test: add comprehensive tests for multi-package selection composables

- Add tests for usePacksSelection composable
  - Test installation status filtering
  - Test selection state determination (all/none/mixed)
  - Test dynamic status changes

- Add tests for usePacksStatus composable
  - Test import failure detection
  - Test status priority handling
  - Test integration with conflict detection store

- Fix existing test mocking issues
  - Update es-toolkit/compat mock to use async import
  - Add Pinia setup for store-dependent tests
  - Update vue-i18n mock to preserve all exports

---------

Co-authored-by: Claude <noreply@anthropic.com>

* feat: Integrate ComfyUI Manager migration with v2 API and enhanced UI

This commit integrates the previously recovered ComfyUI Manager functionality
with significant enhancements from PR #3367, including:

## Core Manager System Recovery
- **v2 API Integration**: All manager endpoints now use `/v2/manager/queue/*`
- **Task Queue System**: Complete client-side task queuing with WebSocket status
- **Service Layer**: Comprehensive manager service with all CRUD operations
- **Store Integration**: Full manager store with progress dialog support

## New Features & Enhancements
- **Reactive Feature Flags**: Foundation for dynamic feature toggling
- **Enhanced UI Components**: Improved loading states, progress tracking
- **Package Management**: Install, update, enable/disable functionality
- **Version Selection**: Support for latest/nightly package versions
- **Progress Dialogs**: Real-time installation progress with logs
- **Missing Node Detection**: Automated detection and installation prompts

## Technical Improvements
- **TypeScript Definitions**: Complete type system for manager operations
- **WebSocket Integration**: Real-time status updates via `cm-queue-status`
- **Error Handling**: Comprehensive error handling with user feedback
- **Testing**: Updated test suites for new functionality
- **Documentation**: Complete backup documentation for recovery process

## API Endpoints Restored
- `manager/queue/start` - Start task queue
- `manager/queue/status` - Get queue status
- `manager/queue/task` - Queue individual tasks
- `manager/queue/install` - Install packages
- `manager/queue/update` - Update packages
- `manager/queue/disable` - Disable packages

## Breaking Changes
- Manager API base URL changed to `/v2/`
- Updated TypeScript interfaces for manager operations
- New WebSocket message format for queue status

This restores all critical manager functionality lost during the previous
rebase while integrating the latest enhancements and maintaining compatibility
with the current main branch.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Restore correct interfaces from PR #3367

- Restore original useManagerQueue, useServerLogs, and comfyManagerService interfaces
- Restore original component implementations for ManagerProgressDialogContent and ManagerProgressHeader
- Fix all TypeScript interface compatibility issues by using original PR implementations
- Remove duplicate setting that was causing runtime errors

This fixes merge errors where interfaces were incorrectly mixed between old and new implementations.

* fix: Add missing IconTextButton import in PackUninstallButton

Component was using IconTextButton in template but missing explicit import,
causing Vue runtime warning about unresolved component.

* docs: Update backup documentation with working state backup

Added manager-migration-clean-working-backup entry documenting the working state after fixing runtime issues, ready for PR integration.

* [feat] Add manager capability feature flags

Add support for manager v4 feature flag and client UI capability:
- MANAGER_SUPPORTS_V4: Server-side flag for v4 manager support
- supports_manager_v4_ui: Client-side flag for v4 UI support

These flags enable proper capability negotiation between frontend and
backend for manager UI selection (legacy vs v4).

Also fix TypeScript errors by adding @types/lodash.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [feat] Add managerStateStore for three-state manager UI logic

- Create managerStateStore to determine manager UI state (disabled, legacy, new)
- Check command line args, feature flags, and legacy API endpoints
- Update useCoreCommands to use the new store instead of async API calls
- Initialize manager state after system stats are loaded in GraphView
- Add comprehensive tests for all manager state scenarios

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [fix] Fix API URL prefix slash and add error handling

- Update comfyManagerService to use conditional API URL prefix based on manager v4 support
- Fix manager UI state handling in command menubar and workflow warning dialog
- Add proper manager state detection with fallback to settings panel
- Remove unused imports and variables

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [docs] Update backup documentation with PR #5063 integration status

- Document manager-migration-pr5063-integrated backup branch
- Add comprehensive recovery verification for all integrated features
- Update next steps to reflect current progress
- Document successful integration of both PR #4654 and PR #5063

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [fix] Fix manager button visibility when manager is disabled

- Use managerStateStore instead of legacy isLegacyManager check
- Initialize manager state on component mount to detect --disable-manager
- Hide Install All Missing Custom Nodes button when manager is disabled
- Fixes issue where buttons showed even when comfyui_manager package not installed

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [fix] Correct Install All button visibility for manager UI states

- Install All Missing Custom Nodes button only shows for NEW_UI state
- Legacy UI state only shows Open Manager button
- Disabled state shows no buttons
- Matches original PR #5063 behavior exactly

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

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: Complete manager migration with bug fixes and locale updates

- Restore proper task queue implementation with generated types
- Fix manager button visibility based on server feature flags
- Add task completion tracking with taskIdToPackId mapping
- Fix log separation with task-specific filtering
- Implement failed tab functionality with proper task partitioning
- Fix task progress status detection using actual queue state
- Add missing locale entries for all manager operations
- Remove legacy manager menu items, keep only 'Manage Extensions'
- Fix task panel expansion state and count display issues
- All TypeScript and ESLint checks pass

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

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: Complete manager migration with conflict detection integration

This completes the integration of ComfyUI Manager migration features with enhanced conflict detection system. Key changes include:

## Manager Migration & Conflict Detection
- Integrated PR #4637 (4-state manager restart workflow) with PR #4654 (comprehensive conflict detection)
- Fixed conflict detection to properly check `latest_version` fields for registry API compatibility
- Added conflict detection to PackCardFooter and InfoPanelHeader for comprehensive warning coverage
- Merged missing English locale translations from main branch with proper conflict resolution

## Bug Fixes
- Fixed double API path issue (`/api/v2/v2/`) in manager service routes
- Corrected PackUpdateButton payload structure and service method calls
- Enhanced conflict detection system to handle both installed and registry package structures

## Technical Improvements
- Updated conflict detection composable to handle both installed and registry package structures
- Enhanced manager service with proper error handling and route corrections
- Improved type safety across manager components with proper TypeScript definitions

* Remove temporary error log files from commits

* Remove temporary documentation files

- Remove MANAGER_MIGRATION_BACKUPS.md (temporary notes)
- Remove TASK_QUEUE_RESTORATION_PLAN.md (temporary notes)

These were development artifacts and shouldn't be in commits.

* feat: Complete manager migration cleanup and integration

- Remove outdated legacy manager detection from LoadWorkflowWarning
- Update InfoPanelHeader with conflict detection improvements
- Fix all failing unit tests from state management transition
- Clean up algolia search provider type mappings
- Remove unused @ts-expect-error directives
- Add .nx to .gitignore

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

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Update CustomNodesManager command to use tri-state manager system

Replace legacy isLegacyManagerUI() call with new ManagerUIState system:
- Use useManagerStateStore().managerUIState instead of async API call
- Handle DISABLED state by showing settings dialog
- Handle LEGACY_UI state with fallback to new UI on error
- Handle NEW_UI state by showing manager dialog
- Remove unused useComfyManagerService import

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Remove no-op refreshTaskState function

- Remove unused refreshTaskState function from useManagerQueue
- Function was left as no-op only to make tests pass
- Since queue is now push-based (WebSocket), no need to refresh state
- Clean up export and remove extra blank lines

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

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Replace lodash with es-toolkit/compat in useManagerQueue

Replace lodash import with es-toolkit/compat to match project standards:
- Change 'lodash' import to 'es-toolkit/compat' for pickBy function
- Add specific type helper for history task filtering
- Update JSDoc comment to remove lodash reference
- Fixes component test failures from missing lodash dependency

* fix: Add missing whats-new-dismissed event emission in WhatsNewPopup

During merge with main, the event emission was lost from the hide() function.
- Add defineEmits for 'whats-new-dismissed' event
- Emit event in hide() function to maintain test compatibility
- Fixes 3 failing unit tests in WhatsNewPopup.test.ts

* ci: Force CI run for Playwright tests

Previous commits contained [skip ci] which prevented test execution.
This empty commit ensures all CI checks run properly.

* test: Temporarily disable workflow.avif test due to missing nodes dialog

The workflow.avif test asset contains custom nodes that trigger the missing
nodes dialog, which is outside the scope of AVIF loading functionality testing.

TODO: Update test asset to use core nodes only, then re-enable the test.

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Jin Yi <jin12cc@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com>
Co-authored-by: viva-jinyi <53567196+viva-jinyi@users.noreply.github.com>
2025-09-02 19:14:36 -07:00
Comfy Org PR Bot
9f208b876c [release] Increment version to 1.26.8 (#5263)
Co-authored-by: benceruleanlu <162923238+benceruleanlu@users.noreply.github.com>
2025-09-02 22:09:16 -04:00
snomiao
7862ae4b65 [bugfix] Fix lint-and-format workflow detached HEAD issue (#5305)
* [bugfix] Fix lint-and-format workflow detached HEAD issue

- Changed checkout ref from head.sha to head.ref to properly checkout PR branch
- This fixes the 'fatal: You are not currently on a branch' error when pushing auto-fixes
- The workflow was failing because it was in detached HEAD state and couldn't push commits

* [test] Intentionally break formatting to test CI/CD auto-fix

* [auto-fix] Apply ESLint and Prettier fixes

---------

Co-authored-by: GitHub Action <action@github.com>
2025-09-02 14:41:43 -07:00
Johnpaul Chiwetelu
8f7ee4e9a3 Re-Route Support to Zendesk (#5259)
* refactor: replace feedback command with contact support in Help Center menu

* refactor: replace feedback dialog with external support link in Help menu

* refactor: simplify error reporting UI by removing send report functionality

* refactor: remove issue report dialog and update support contact method

* refactor: remove IssueReportDialog and associated components

* refactor: remove unused issue report schema

* refactor: remove unused issue report types

* refactor: remove unused issue report fields from localization files
2025-09-02 11:02:15 -07:00
pythongosssss
b091f3aa08 Add save/save as to breadcrumb root item (#5213) 2025-09-01 23:41:07 -07:00
snomiao
f215872e2e [feat] merge playwright deploy and comment workflows (#5298)
Combines pr-playwright-deploy.yaml and pr-playwright-comment.yaml into a single workflow to ensure proper dependency ordering. The comment job now waits for deployments to complete before generating comments with deployment URLs.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-01 21:34:21 -07:00
Christian Byrne
da042ae829 [refactor] Remove unused legacy mutation types from layout system (#5262)
- Remove LayoutMutationType, LayoutMutation, and related interfaces
- Remove AnyLayoutMutation union type and specific mutation interfaces
- Clean up duplicate legacy types from both layoutTypes.ts and layout/types.ts
- Fix JSON syntax error in Chinese locale file (missing comma)
- Replace lodash with es-toolkit in useFloatWidget (per project standards)
- Reduces codebase by ~120 lines of unused type definitions
- CRDT operations (LayoutOperation) remain unchanged and functional

The legacy mutation types were designed for backward compatibility
but have never been used since this code hasn't been merged to main.
Only the CRDT operation types are actually used in the implementation.
2025-09-01 19:36:45 -04:00
Arjan Singh
481e3b593a [docs] update CLAUDE.md and selected README.md files (#5293)
* docs: add Claude documentation for settings and feature flags

* docs: update services README.md

* docs: update stores README.md
2025-09-01 15:31:44 -07:00
Benjamin Lu
62096d46c1 chore: Empty commit to trigger CI checks 2025-09-01 17:59:21 -04:00
Benjamin Lu
2a5e0d231e Decouple link and slot hit-testing out of Litegraph (#5134)
* [feat] TransformPane - Viewport synchronization layer for Vue nodes (#4304)

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Benjamin Lu <benceruleanlu@proton.me>
Co-authored-by: github-actions <github-actions@github.com>

* Update locales [skip ci]

* Update locales [skip ci]

* Add vue node feature flag (#4927)

* feat: Implement CRDT-based layout system for Vue nodes (#4959)

* feat: Implement CRDT-based layout system for Vue nodes

Major refactor to solve snap-back issues and create single source of truth for node positions:

- Add Yjs-based CRDT layout store for conflict-free position management
- Implement layout mutations service with clean API
- Create Vue composables for layout access and node dragging
- Add one-way sync from layout store to LiteGraph
- Disable LiteGraph dragging when Vue nodes mode is enabled
- Add z-index management with bring-to-front on node interaction
- Add comprehensive TypeScript types for layout system
- Include unit tests for layout store operations
- Update documentation to reflect CRDT architecture

This provides a solid foundation for both single-user performance and future real-time collaboration features.

Co-Authored-By: Claude <noreply@anthropic.com>

* style: Apply linter fixes to layout system

* fix: Remove unnecessary README files and revert services README

- Remove unnecessary types/README.md file
- Revert unrelated changes to services/README.md
- Keep only relevant documentation for the layout system implementation

These were issues identified during PR review that needed to be addressed.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Clean up layout store and implement proper CRDT operations

- Created dedicated layoutOperations.ts with production-grade CRDT interfaces
- Integrated existing QuadTree spatial index instead of simple cache
- Split composables into separate files (useLayout, useNodeLayout, useLayoutSync)
- Cleaned up operation handlers using specific types instead of Extract
- Added proper operation interfaces with type guards and extensibility
- Updated all type references to use new operation structure

The layout store now properly uses the existing QuadTree infrastructure for
efficient spatial queries and follows CRDT best practices with well-defined
operation interfaces.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Extract services and split composables for better organization

- Created SpatialIndexManager to handle QuadTree operations separately
- Added LayoutAdapter interface for CRDT abstraction (Yjs, mock implementations)
- Split GraphNodeManager into focused composables:
  - useNodeWidgets: Widget state and callback management
  - useNodeChangeDetection: RAF-based geometry change detection
  - useNodeState: Node visibility and reactive state management
- Extracted constants for magic numbers and configuration values
- Updated layout store to use SpatialIndexManager and constants

This improves code organization, testability, and makes it easier to swap
CRDT implementations or mock services for testing.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Add node slots to layout tree

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* Remove slots from layoutTypes

* Totally not scuffed renderer and adapter

* Revert "Totally not scuffed renderer and adapter"

This reverts commit 2b9d83efb8.

* Revert "Remove slots from layoutTypes"

This reverts commit 18f78ff786.

* Reapply "Add node slots to layout tree"

This reverts commit 236fecb549.

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* docs: Replace architecture docs with comprehensive ADR

- Add ADR-0002 for CRDT-based layout system decision
- Follow established ADR template with persuasive reasoning
- Include performance benefits, collaboration readiness, and architectural advantages
- Update ADR index

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>

* [chore] Extract link rendering out of LGraphCanvas (#4994)

* feat: Implement CRDT-based layout system for Vue nodes

Major refactor to solve snap-back issues and create single source of truth for node positions:

- Add Yjs-based CRDT layout store for conflict-free position management
- Implement layout mutations service with clean API
- Create Vue composables for layout access and node dragging
- Add one-way sync from layout store to LiteGraph
- Disable LiteGraph dragging when Vue nodes mode is enabled
- Add z-index management with bring-to-front on node interaction
- Add comprehensive TypeScript types for layout system
- Include unit tests for layout store operations
- Update documentation to reflect CRDT architecture

This provides a solid foundation for both single-user performance and future real-time collaboration features.

Co-Authored-By: Claude <noreply@anthropic.com>

* style: Apply linter fixes to layout system

* fix: Remove unnecessary README files and revert services README

- Remove unnecessary types/README.md file
- Revert unrelated changes to services/README.md
- Keep only relevant documentation for the layout system implementation

These were issues identified during PR review that needed to be addressed.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Clean up layout store and implement proper CRDT operations

- Created dedicated layoutOperations.ts with production-grade CRDT interfaces
- Integrated existing QuadTree spatial index instead of simple cache
- Split composables into separate files (useLayout, useNodeLayout, useLayoutSync)
- Cleaned up operation handlers using specific types instead of Extract
- Added proper operation interfaces with type guards and extensibility
- Updated all type references to use new operation structure

The layout store now properly uses the existing QuadTree infrastructure for
efficient spatial queries and follows CRDT best practices with well-defined
operation interfaces.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Extract services and split composables for better organization

- Created SpatialIndexManager to handle QuadTree operations separately
- Added LayoutAdapter interface for CRDT abstraction (Yjs, mock implementations)
- Split GraphNodeManager into focused composables:
  - useNodeWidgets: Widget state and callback management
  - useNodeChangeDetection: RAF-based geometry change detection
  - useNodeState: Node visibility and reactive state management
- Extracted constants for magic numbers and configuration values
- Updated layout store to use SpatialIndexManager and constants

This improves code organization, testability, and makes it easier to swap
CRDT implementations or mock services for testing.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Add node slots to layout tree

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* Remove slots from layoutTypes

* Totally not scuffed renderer and adapter

* Revert "Totally not scuffed renderer and adapter"

This reverts commit 2b9d83efb8.

* Revert "Remove slots from layoutTypes"

This reverts commit 18f78ff786.

* Reapply "Add node slots to layout tree"

This reverts commit 236fecb549.

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* docs: Replace architecture docs with comprehensive ADR

- Add ADR-0002 for CRDT-based layout system decision
- Follow established ADR template with persuasive reasoning
- Include performance benefits, collaboration readiness, and architectural advantages
- Update ADR index

* Add node slots to layout tree

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* Remove slots from layoutTypes

* Totally not scuffed renderer and adapter

* Remove unused methods in LGLA

* Extract slot position calculations to shared utility

- Create slotCalculations.ts utility for centralized slot position logic
- Update LGraphNode to delegate to helper while maintaining compatibility
- Modify LitegraphLinkAdapter to use layout tree positions when available
- Enable link rendering to use layout system coordinates instead of litegraph positions

This allows the layout tree to control link rendering positions, enabling proper
synchronization between Vue components and canvas rendering.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [fix] Restore original link rendering behavior after refactor

This commit fixes several rendering discrepancies introduced during the link rendering refactor to ensure exact parity with the original litegraph implementation:

Path Shape Fixes:
- STRAIGHT_LINK: Now correctly applies l=10 offset to create innerA/innerB points and uses midX=(innerA.x+innerB.x)*0.5 for elbow placement, matching the original 6-segment path
- LINEAR_LINK: Restored 4-point path with l=15 directional offsets (start → innerA → innerB → end)

Arrow Rendering:
- computeConnectionPoint: Now always uses bezier math with 0.25 factor spline offsets regardless of render mode, ensuring arrow positions match original
- Arrow positions: Fixed to render at 0.25 and 0.75 positions along the path
- Arrow gating: Moved scale>=0.6 and highQuality checks to adapter layer to maintain PathRenderer purity
- Arrow shape: Restored original triangle dimensions (-5,-3) to (0,+7) to (+5,-3)

Center Marker:
- Fixed 'None' option: Center marker now correctly hidden when LinkMarkerShape.None is selected
- Center point calculation: Updated for all render modes to match original positions
- STRAIGHT_LINK center: Uses midX and average of innerA/innerB y-coordinates
- LINEAR_LINK center: Uses midpoint between innerA and innerB control points

These fixes ensure backward compatibility while maintaining the clean separation between the pure PathRenderer and litegraph-specific LitegraphLinkAdapter.

Fixes #Issue-Number

---------

Co-authored-by: bymyself <cbyrne@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>

* feat: Add slot registration and spatial indexing for hit detection

- Implement slot registration for all nodes (Vue and LiteGraph)
- Add spatial indexes for slots and reroutes to improve hit detection performance
- Register slots when nodes are drawn via new registerSlots() method
- Update LayoutStore to use spatial indexing for O(log n) queries instead of O(n)

Resolves #5125

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "feat: Add slot registration and spatial indexing for hit detection"

This reverts commit 70fbfd0f5e.

* feat: Add slot registration and spatial indexing for hit detection

- Implement slot registration for all nodes (Vue and LiteGraph)
- Add spatial indexes for slots and reroutes to improve hit detection performance
- Register slots when nodes are drawn via new registerSlots() method
- Update LayoutStore to use spatial indexing for O(log n) queries instead of O(n)

Resolves #5125

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

Co-Authored-By: Claude <noreply@anthropic.com>

* relocate slot update to layoutstore

* Revert "relocate slot update to layoutstore"

This reverts commit 0b17ef148bdded35cb231bef25b8d5c77dc14c1f.

* add useSlotLayoutSync

* feat: Extend Layout Store with CRDT support for links and reroutes

Move links and reroutes to be first-class CRDT entities in the Layout Store,
eliminating per-frame registration during rendering. This provides a ~100x
reduction in spatial index operations by using event-driven updates instead
of polling.

Key changes:
- Add CRDT maps for links and reroutes with automatic observers
- Add mutation operations for link/reroute lifecycle management
- Update LiteGraph to use mutations instead of direct store calls
- Remove per-frame updateLinkLayout and updateRerouteLayout calls

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Scuffed diff, change to dirty later

* Fix reroute move desync

* Terrible reroute fixes

* Use LinkId for LinkLayout

* refactor: Remove unused duplicate layout type files

Deleted src/types/layoutTypes.ts and src/types/layoutOperations.ts
which were duplicates of src/renderer/core/layout/types.ts. These
files had zero imports and were creating confusion in the codebase.

The active types are in src/renderer/core/layout/types.ts which
is properly integrated with the current architecture.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Extract layout source strings into LayoutSource enum

Replace hardcoded 'canvas' | 'vue' | 'external' string literals with a proper TypeScript enum for better type safety and maintainability. This change provides a single source of truth for layout source types and makes future modifications easier.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Unify CRDT layout operations under type-safe entity bases

Replace node-centric BaseOperation with a clean hierarchy:
- Add OperationMeta base containing common fields (timestamp, actor, source, type)
- Introduce entity-specific bases (NodeOpBase, LinkOpBase, RerouteOpBase)
- Each operation now extends its appropriate entity base with proper typing
- Add entity discriminator field for runtime type narrowing

Benefits:
- Eliminates duplicate meta fields across link/reroute operations
- Provides type-safe discriminated unions for each entity type
- Enables clean extension path for future operation types
- Zero breaking changes - type-only refactor with no runtime impact

Also adds helper functions:
- getAffectedNodeIds() to extract node IDs affected by any operation
- Entity-specific helper checks for operation classification

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix initial link seeding

* fix: Fix reroute hit detection and type consistency issues

- Use instanceof Reroute type guard instead of structural 'linkIds' check
- Remove unnecessary Number() conversions for reroute IDs (already numeric)
- Fix parentId truthiness bug (0 is valid parent ID)
- Pass numeric IDs directly in GraphCanvas seeding
- Add missing link/reroute methods to LayoutMutations interface
- Make hit test tolerance scale-aware using ctx.lineWidth and DPI

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Add debug logs

* Add missing reroute path

* cleanup

* feat: Implement event-driven link layout sync

Remove layout store writes from render loop and update link geometry only on
actual changes (node move/resize, link/reroute operations, collapse toggles).

Key improvements:
- No layout writes during canvas render (decoupled from draw cycle)
- Link layouts update only on causal events via useLinkLayoutSync
- Hit testing remains precise using stored Path2D objects
- Optimized adapter: calculations only when enableLayoutStoreWrites=true
- Store-level deduplication prevents spatial index churn

Performance impact:
- Render path: Zero layout work, no equality checks, no store writes
- Event path: Direct writes with cheap store-level dedup
- Significant CPU savings per frame on complex graphs

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

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: Implement DOM-based slot registration with unified position system

- Add centralized getSlotPosition() function in SlotCalculations
- Create SlotIdentifier utilities for consistent slot key generation
- Implement DOM-based slot registration composable with performance optimizations:
  - Cache slot offsets to avoid DOM reads during drag operations
  - Batch measurements via requestAnimationFrame
  - Skip redundant updates when bounds unchanged
- Update Vue slot components to register DOM positions
- Fix widget-to-input index mapping in NodeWidgets
- Prevent double registration when Vue nodes enabled

This improves slot hit-detection accuracy by using actual DOM positions
while maintaining performance through intelligent caching and batching.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove unused files

* Remove duplicated markdown file

* Remove duplicated files and address knip concerns

* Remove outdated test

* warning comment

* Update test snapshots

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
2025-09-01 17:01:17 -04:00
filtered
b592c9015e Update & clarify Node.js version requirements (#5280) 2025-09-01 11:36:29 -07:00
Alexander Piskun
f0afc261a4 add prices for Kling 2.1 model for KlingStartEndFrame node (#5264) 2025-09-01 10:54:55 -07:00
Alexander Piskun
1e6ba5c689 api_nodes: added prices for Ideogram V3 node (character reference) (#5241)
* api_nodes: added prices for Ideogram V3 node (character reference)

* Support watching changes on connections. (#5250)

* rename renderingSpeed default value from 'balanced' to 'default'

* added missing type

---------

Co-authored-by: AustinMroz <austin@comfy.org>
2025-09-01 10:54:36 -07:00
brucew4yn3rp
ddd7b4866f Fixed Square Brush, Improve Brush Hardness and Smoothing Precision (#4519)
* Fixed square brush with hardness <1; improved the effect of hardness, improved the effect of smoothing precision

* Improved square hardness and code quality with performance optimizations

* Fix brush rendering anti-aliasing and optimized square brushes using texture caching

* Switched to QuickLRU for brush cache

* Cleaned up exports from testing

* Removed SOFT_BRUSH_STEPS unused variable
2025-08-31 15:29:24 -07:00
Benjamin Lu
e731f3b833 feat: Add Playwright browser caching to CI workflows (#5272)
Improves CI performance by caching Playwright browsers between runs.
This reduces the time spent downloading browsers on each workflow execution.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-31 13:42:22 -04:00
Benjamin Lu
b99e451f91 [fix] Improve Storybook comment workflow status handling (#5273)
- Add condition to only run on version-bump branches
- Handle additional build statuses (skipped, cancelled) with appropriate icons and messages
- Improve readability by breaking long conditionals across multiple lines

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-31 13:42:09 -04:00
Benjamin Lu
08309595e0 Fix lodash import (#5269) 2025-08-30 18:00:56 -04:00
Benjamin Lu
3982f29fda Update lockfile after rebase (#5254)
* chore: Update pnpm-lock.yaml after rebase

Add new dependencies from main branch:
- chart.js@^4.5.0
- clsx@^2.1.1
- tailwind-merge@^3.3.1
- yjs@^13.6.27

* Fix SelectionOverlay rebase issue (#5255)

* fix: Remove SelectionOverlay import accidentally re-added during rebase

During the rebase, the SelectionOverlay component import and usage was accidentally
re-introduced. This component was removed in commit 84e7102f (#5158) to fix
performance issues. The SelectionToolbox should be used directly without a wrapper.

The current main branch correctly uses:
<SelectionToolbox v-if="selectionToolboxEnabled" />

Ref: https://github.com/Comfy-Org/ComfyUI_frontend/pull/5158

* Deduplicate i18n keys from rebasing (#5257)

* fix: Add missing comma in zh locale JSON

Fixes JSON syntax error introduced during rebase.

* dedup i18n keys

* fix: Restore simplified Chinese translation for Toggle Workflows Sidebar

The previous dedup commit accidentally left a traditional Chinese
translation in the simplified Chinese locale file.

* fix: Replace remaining traditional Chinese characters in simplified Chinese locale

- Changed '檔案' to '文件' (file)
- Changed '擴充功能' to '扩展功能' (extensions)
2025-08-30 17:50:55 -04:00
Rizumu Ayaka
57db10f408 feat: v3 style of node body (#5169)
* feat: v3 style of node body

* Update src/renderer/extensions/vueNodes/components/LGraphNode.vue

* fix: review's issues

* fix: review's issue
2025-08-29 14:11:41 -04:00
Benjamin Lu
1447b15f4c [bugfix] Hide center dot when dragging links (#5133)
The center dot/marker on links should not be visible when the user is dragging links to connect nodes. This fix ensures the center marker is hidden during link dragging operations.

🤖 Generated with Claude Code

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-29 14:11:25 -04:00
Benjamin Lu
4a7c955a15 [bugfix] Fix link center dot hit detection when marker is disabled (#5135)
When linkMarkerShape is set to None, clicks were still being detected on the invisible center dot. This fix adds proper checks to skip hit detection when the center marker is disabled.

Fixes center dot hit detection issue

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-29 14:11:25 -04:00
Benjamin Lu
ba1fa1be25 Revert "feat: Add slot registration and spatial indexing for hit detection"
This reverts commit 70fbfd0f5e.
2025-08-29 14:11:25 -04:00
Benjamin Lu
5171decd8b feat: Add slot registration and spatial indexing for hit detection
- Implement slot registration for all nodes (Vue and LiteGraph)
- Add spatial indexes for slots and reroutes to improve hit detection performance
- Register slots when nodes are drawn via new registerSlots() method
- Update LayoutStore to use spatial indexing for O(log n) queries instead of O(n)

Resolves #5125

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 14:06:33 -04:00
Christian Byrne
5a74c019c7 remove logging from vue node layouting modules (#5111) 2025-08-29 13:59:48 -04:00
Christian Byrne
934c650790 Remove layout logging noise from console (#5101)
- Remove loglevel import and logger setup from LayoutStore
- Remove all logger.debug() calls throughout LayoutStore
- Remove localStorage debug check for layout operations
- Remove unused DEBUG_CONFIG from layout constants
- Clean up console noise while preserving error handling

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-29 13:59:48 -04:00
bymyself
b2a828dda6 [bugfix] Fix Vue node import path after refactoring
Update LGraphNode import path from old location to new domain-driven architecture path.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 13:59:48 -04:00
Christian Byrne
d1ed5ecc0d fix: Initialize Vue node manager when first node is added to empty graph (#5086)
* fix: Initialize Vue node manager when first node is added to empty graph

When Vue nodes are enabled and the graph starts empty (0 nodes), the
node manager wasn't being initialized. This caused Vue nodes to not
render until the setting was toggled off and on again.

The fix adds a one-time event handler that listens for the first node
being added to an empty graph and initializes the node manager at that
point.

Fixes the issue where Vue nodes don't render on initial page load when
the setting is enabled.

* fix: Add TODO comment for reactive graph mutations observer

Added comment to indicate that the monkey-patching approach should be
replaced with a proper reactive graph mutations observer when available.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-29 13:59:48 -04:00
Christian Byrne
bfcbcf4873 [refactor] Reorganize Vue nodes to domain-driven design architecture (#5085)
* refactor: Reorganize Vue nodes system to domain-driven design architecture

Move Vue nodes code from scattered technical layers to domain-focused structure:

- Widget system → src/renderer/extensions/vueNodes/widgets/
- LOD optimization → src/renderer/extensions/vueNodes/lod/
- Layout logic → src/renderer/extensions/vueNodes/layout/
- Node components → src/renderer/extensions/vueNodes/components/
- Test structure mirrors source organization

Benefits:
- Clear domain boundaries instead of technical layers
- Everything Vue nodes related in renderer domain (not workbench)
- camelCase naming (vueNodes vs vue-nodes)
- Tests co-located with source domains
- All imports updated to new DDD structure

* fix: Skip spatial index performance test on CI to avoid flaky timing

Performance tests are inherently flaky on CI due to variable system
performance. This test should only run locally like the other
performance tests.
2025-08-29 13:59:48 -04:00
Christian Byrne
0dd4ff2087 refactor: Reorganize layout system into new renderer architecture (#5071)
- Move layout system to renderer/core/layout/
  - Store, operations, adapters, and sync modules organized clearly
  - Merged layoutTypes.ts and layoutOperations.ts into single types.ts
- Move canvas rendering to renderer/core/canvas/
  - LiteGraph-specific code in litegraph/ subdirectory
  - PathRenderer at canvas level
- Move spatial indexing to renderer/core/spatial/
- Move Vue node composables to renderer/extensions/vue-nodes/
- Update all import paths throughout codebase
- Apply consistent naming (renderer vs rendering)

This establishes clearer separation between core rendering concerns
and optional extensions, making the architecture more maintainable.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-29 13:59:48 -04:00
Benjamin Lu
889d136154 [chore] Extract link rendering out of LGraphCanvas (#4994)
* feat: Implement CRDT-based layout system for Vue nodes

Major refactor to solve snap-back issues and create single source of truth for node positions:

- Add Yjs-based CRDT layout store for conflict-free position management
- Implement layout mutations service with clean API
- Create Vue composables for layout access and node dragging
- Add one-way sync from layout store to LiteGraph
- Disable LiteGraph dragging when Vue nodes mode is enabled
- Add z-index management with bring-to-front on node interaction
- Add comprehensive TypeScript types for layout system
- Include unit tests for layout store operations
- Update documentation to reflect CRDT architecture

This provides a solid foundation for both single-user performance and future real-time collaboration features.

Co-Authored-By: Claude <noreply@anthropic.com>

* style: Apply linter fixes to layout system

* fix: Remove unnecessary README files and revert services README

- Remove unnecessary types/README.md file
- Revert unrelated changes to services/README.md
- Keep only relevant documentation for the layout system implementation

These were issues identified during PR review that needed to be addressed.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Clean up layout store and implement proper CRDT operations

- Created dedicated layoutOperations.ts with production-grade CRDT interfaces
- Integrated existing QuadTree spatial index instead of simple cache
- Split composables into separate files (useLayout, useNodeLayout, useLayoutSync)
- Cleaned up operation handlers using specific types instead of Extract
- Added proper operation interfaces with type guards and extensibility
- Updated all type references to use new operation structure

The layout store now properly uses the existing QuadTree infrastructure for
efficient spatial queries and follows CRDT best practices with well-defined
operation interfaces.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Extract services and split composables for better organization

- Created SpatialIndexManager to handle QuadTree operations separately
- Added LayoutAdapter interface for CRDT abstraction (Yjs, mock implementations)
- Split GraphNodeManager into focused composables:
  - useNodeWidgets: Widget state and callback management
  - useNodeChangeDetection: RAF-based geometry change detection
  - useNodeState: Node visibility and reactive state management
- Extracted constants for magic numbers and configuration values
- Updated layout store to use SpatialIndexManager and constants

This improves code organization, testability, and makes it easier to swap
CRDT implementations or mock services for testing.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Add node slots to layout tree

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* Remove slots from layoutTypes

* Totally not scuffed renderer and adapter

* Revert "Totally not scuffed renderer and adapter"

This reverts commit 2b9d83efb8.

* Revert "Remove slots from layoutTypes"

This reverts commit 18f78ff786.

* Reapply "Add node slots to layout tree"

This reverts commit 236fecb549.

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* docs: Replace architecture docs with comprehensive ADR

- Add ADR-0002 for CRDT-based layout system decision
- Follow established ADR template with persuasive reasoning
- Include performance benefits, collaboration readiness, and architectural advantages
- Update ADR index

* Add node slots to layout tree

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* Remove slots from layoutTypes

* Totally not scuffed renderer and adapter

* Remove unused methods in LGLA

* Extract slot position calculations to shared utility

- Create slotCalculations.ts utility for centralized slot position logic
- Update LGraphNode to delegate to helper while maintaining compatibility
- Modify LitegraphLinkAdapter to use layout tree positions when available
- Enable link rendering to use layout system coordinates instead of litegraph positions

This allows the layout tree to control link rendering positions, enabling proper
synchronization between Vue components and canvas rendering.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* [fix] Restore original link rendering behavior after refactor

This commit fixes several rendering discrepancies introduced during the link rendering refactor to ensure exact parity with the original litegraph implementation:

Path Shape Fixes:
- STRAIGHT_LINK: Now correctly applies l=10 offset to create innerA/innerB points and uses midX=(innerA.x+innerB.x)*0.5 for elbow placement, matching the original 6-segment path
- LINEAR_LINK: Restored 4-point path with l=15 directional offsets (start → innerA → innerB → end)

Arrow Rendering:
- computeConnectionPoint: Now always uses bezier math with 0.25 factor spline offsets regardless of render mode, ensuring arrow positions match original
- Arrow positions: Fixed to render at 0.25 and 0.75 positions along the path
- Arrow gating: Moved scale>=0.6 and highQuality checks to adapter layer to maintain PathRenderer purity
- Arrow shape: Restored original triangle dimensions (-5,-3) to (0,+7) to (+5,-3)

Center Marker:
- Fixed 'None' option: Center marker now correctly hidden when LinkMarkerShape.None is selected
- Center point calculation: Updated for all render modes to match original positions
- STRAIGHT_LINK center: Uses midX and average of innerA/innerB y-coordinates
- LINEAR_LINK center: Uses midpoint between innerA and innerB control points

These fixes ensure backward compatibility while maintaining the clean separation between the pure PathRenderer and litegraph-specific LitegraphLinkAdapter.

Fixes #Issue-Number

---------

Co-authored-by: bymyself <cbyrne@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
2025-08-29 13:59:48 -04:00
Christian Byrne
c773230b21 feat: Implement CRDT-based layout system for Vue nodes (#4959)
* feat: Implement CRDT-based layout system for Vue nodes

Major refactor to solve snap-back issues and create single source of truth for node positions:

- Add Yjs-based CRDT layout store for conflict-free position management
- Implement layout mutations service with clean API
- Create Vue composables for layout access and node dragging
- Add one-way sync from layout store to LiteGraph
- Disable LiteGraph dragging when Vue nodes mode is enabled
- Add z-index management with bring-to-front on node interaction
- Add comprehensive TypeScript types for layout system
- Include unit tests for layout store operations
- Update documentation to reflect CRDT architecture

This provides a solid foundation for both single-user performance and future real-time collaboration features.

Co-Authored-By: Claude <noreply@anthropic.com>

* style: Apply linter fixes to layout system

* fix: Remove unnecessary README files and revert services README

- Remove unnecessary types/README.md file
- Revert unrelated changes to services/README.md
- Keep only relevant documentation for the layout system implementation

These were issues identified during PR review that needed to be addressed.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Clean up layout store and implement proper CRDT operations

- Created dedicated layoutOperations.ts with production-grade CRDT interfaces
- Integrated existing QuadTree spatial index instead of simple cache
- Split composables into separate files (useLayout, useNodeLayout, useLayoutSync)
- Cleaned up operation handlers using specific types instead of Extract
- Added proper operation interfaces with type guards and extensibility
- Updated all type references to use new operation structure

The layout store now properly uses the existing QuadTree infrastructure for
efficient spatial queries and follows CRDT best practices with well-defined
operation interfaces.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: Extract services and split composables for better organization

- Created SpatialIndexManager to handle QuadTree operations separately
- Added LayoutAdapter interface for CRDT abstraction (Yjs, mock implementations)
- Split GraphNodeManager into focused composables:
  - useNodeWidgets: Widget state and callback management
  - useNodeChangeDetection: RAF-based geometry change detection
  - useNodeState: Node visibility and reactive state management
- Extracted constants for magic numbers and configuration values
- Updated layout store to use SpatialIndexManager and constants

This improves code organization, testability, and makes it easier to swap
CRDT implementations or mock services for testing.

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

Co-Authored-By: Claude <noreply@anthropic.com>

* Add node slots to layout tree

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* Remove slots from layoutTypes

* Totally not scuffed renderer and adapter

* Revert "Totally not scuffed renderer and adapter"

This reverts commit 2b9d83efb8.

* Revert "Remove slots from layoutTypes"

This reverts commit 18f78ff786.

* Reapply "Add node slots to layout tree"

This reverts commit 236fecb549.

* Revert "Add node slots to layout tree"

This reverts commit 460493a620.

* docs: Replace architecture docs with comprehensive ADR

- Add ADR-0002 for CRDT-based layout system decision
- Follow established ADR template with persuasive reasoning
- Include performance benefits, collaboration readiness, and architectural advantages
- Update ADR index

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
2025-08-29 13:59:48 -04:00
Benjamin Lu
8df41ab040 Add vue node feature flag (#4927) 2025-08-29 13:51:53 -04:00
Benjamin Lu
2b9a9e2371 test(ci): skip transformPerformance suite on CI (#4843) 2025-08-29 13:49:27 -04:00
Benjamin Lu
4171219402 Revert "refactor(litegraph): decouple render-time state from models for reroutes and links\n\nIntroduce RenderedLinkSegment; compute reroute render params without mutating model; render into ephemeral segments instead of writing to Reroute/LLink."
This reverts commit d7ed1d36ed.
2025-08-29 13:49:27 -04:00
Benjamin Lu
301355e018 refactor(litegraph): decouple render-time state from models for reroutes and links\n\nIntroduce RenderedLinkSegment; compute reroute render params without mutating model; render into ephemeral segments instead of writing to Reroute/LLink. 2025-08-29 13:49:27 -04:00
github-actions
ac17752c0b Update locales [skip ci] 2025-08-29 13:49:27 -04:00
Christian Byrne
fc6943cdd3 Fix TransformPane pos/size (#4826) 2025-08-29 13:37:44 -04:00
github-actions
9db96f2dcc Update locales [skip ci] 2025-08-29 13:37:44 -04:00
Christian Byrne
19084e2799 [feat] TransformPane - Viewport synchronization layer for Vue nodes (#4304)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Benjamin Lu <benceruleanlu@proton.me>
Co-authored-by: github-actions <github-actions@github.com>
2025-08-29 13:17:40 -04:00
bymyself
6e04cb72b0 [feat] Add Vue action widgets
- WidgetButton: Action button with Button component and callback handling
- WidgetFileUpload: File upload interface with FileUpload component
2025-08-29 05:07:50 -04:00
bymyself
9c4d782b30 [feat] Add Vue visual widgets
- WidgetColorPicker: Color selection with ColorPicker component
- WidgetImage: Single image display with Image component
- WidgetImageCompare: Before/after comparison with ImageCompare component
- WidgetGalleria: Image gallery/carousel with Galleria component
- WidgetChart: Data visualization with Chart component
2025-08-29 05:07:50 -04:00
bymyself
ac60d1ceb4 [feat] Add Vue selection widgets
- WidgetSelect: Dropdown selection with Select component
- WidgetMultiSelect: Multiple selection with MultiSelect component
- WidgetSelectButton: Button group selection with SelectButton component
- WidgetTreeSelect: Hierarchical selection with TreeSelect component
2025-08-29 05:07:50 -04:00
bymyself
06d0a63a2f [feat] Add Vue input widgets
- WidgetInputText: Single-line text input with InputText component
- WidgetTextarea: Multi-line text input with Textarea component
- WidgetSlider: Numeric range input with Slider component
- WidgetToggleSwitch: Boolean toggle with ToggleSwitch component
2025-08-29 05:07:50 -04:00
bymyself
2dcfe84e99 [feat] Add Vue widget registry system
- Complete widget type enum with all 15 widget types
- Component mapping registry for dynamic widget rendering
- Helper function for type-safe widget component resolution
2025-08-29 05:07:50 -04:00
bymyself
f42a4dd6cc [feat] Add core Vue widget infrastructure
- SimplifiedWidget interface for Vue-based node widgets
- widgetPropFilter utility with component-specific exclusion lists
- Removes DOM manipulation and positioning concerns
- Provides clean API for value binding and prop filtering
2025-08-29 05:07:50 -04:00
585 changed files with 47729 additions and 28050 deletions

View File

@@ -128,17 +128,20 @@ echo "Last stable release: $LAST_STABLE"
### Step 4: Analyze Dependency Updates
1. **Use npm's built-in dependency analysis:**
1. **Use pnpm's built-in dependency analysis:**
```bash
# Get outdated dependencies with npm
npm outdated --format table > outdated-deps-${NEW_VERSION}.txt || echo "No outdated dependencies"
# Get outdated dependencies with pnpm
pnpm outdated --format table > outdated-deps-${NEW_VERSION}.txt
# Check for license compliance
pnpm licenses ls --json > licenses-${NEW_VERSION}.json
# Analyze why specific dependencies exist
echo "Dependency analysis:" > dep-analysis-${NEW_VERSION}.md
MAJOR_DEPS=("vue" "vite" "@vitejs/plugin-vue" "typescript" "pinia")
for dep in "${MAJOR_DEPS[@]}"; do
echo -e "\n## $dep\n\`\`\`" >> dep-analysis-${NEW_VERSION}.md
npm ls "$dep" >> dep-analysis-${NEW_VERSION}.md 2>&1 || echo "Not found" >> dep-analysis-${NEW_VERSION}.md
pnpm why "$dep" >> dep-analysis-${NEW_VERSION}.md || echo "Not found" >> dep-analysis-${NEW_VERSION}.md
echo "\`\`\`" >> dep-analysis-${NEW_VERSION}.md
done
```
@@ -269,14 +272,15 @@ echo "Last stable release: $LAST_STABLE"
### Step 7: Security and Dependency Audit
1. Run npm security audit:
1. Run pnpm security audit:
```bash
npm audit --audit-level moderate
pnpm audit --audit-level moderate
pnpm licenses ls --summary
```
2. Check for known vulnerabilities in dependencies
3. Run comprehensive dependency health check:
```bash
npm doctor
pnpm doctor
```
4. Scan for hardcoded secrets or credentials:
```bash
@@ -289,21 +293,21 @@ echo "Last stable release: $LAST_STABLE"
1. Run complete test suite:
```bash
npm run test:unit
npm run test:component
pnpm test:unit
pnpm test:component
```
2. Run type checking:
```bash
npm run typecheck
pnpm typecheck
```
3. Run linting (may have issues with missing packages):
```bash
npm run lint || echo "Lint issues - verify if critical"
pnpm lint || echo "Lint issues - verify if critical"
```
4. Test build process:
```bash
npm run build
npm run build:types
pnpm build
pnpm build:types
```
5. **QUALITY GATE**: All tests and builds passing?
@@ -533,7 +537,7 @@ echo "Workflow triggered. Waiting for PR creation..."
```bash
# Check npm availability
for i in {1..10}; do
if npm view @comfyorg/comfyui-frontend-types@${NEW_VERSION} version >/dev/null 2>&1; then
if pnpm view @comfyorg/comfyui-frontend-types@${NEW_VERSION} version >/dev/null 2>&1; then
echo "✅ npm package available"
break
fi

View File

@@ -80,7 +80,7 @@ For each commit:
- **CONFIRMATION REQUIRED**: Conflicts resolved correctly?
3. After successful cherry-pick:
- Show the changes: `git show HEAD`
- Run validation: `npm run typecheck && npm run lint`
- Run validation: `pnpm typecheck && pnpm lint`
4. **CONFIRMATION REQUIRED**: Cherry-pick successful and valid?
### Step 6: Create PR to Core Branch
@@ -211,7 +211,7 @@ For each commit:
```
3. Verify npm package:
```bash
npm view @comfyorg/comfyui-frontend-types@1.23.5
pnpm view @comfyorg/comfyui-frontend-types@1.23.5
```
4. Generate release summary with:
- Version released

View File

@@ -5,10 +5,11 @@ Bootstrap the ComfyUI Frontend monorepo with all necessary dependencies and veri
## Overview
This command will:
1. Install all project dependencies using npm
2. Verify the project builds successfully
3. Run unit tests to ensure functionality
4. Start development server to verify frontend boots correctly
1. Install pnpm package manager (if not present)
2. Install all project dependencies
3. Verify the project builds successfully
4. Run unit tests to ensure functionality
5. Start development server to verify frontend boots correctly
## Prerequisites Check
@@ -22,38 +23,51 @@ node --version
git status
```
## Step 1: Install Dependencies
## Step 1: Install pnpm
```bash
# Install all dependencies using npm
# Check if pnpm is already installed
pnpm --version 2>/dev/null || {
echo "Installing pnpm..."
npm install -g pnpm
}
# Verify pnpm installation
pnpm --version
```
## Step 2: Install Dependencies
```bash
# Install all dependencies using pnpm
echo "Installing project dependencies..."
npm install
pnpm install
# Verify node_modules exists and has packages
ls -la node_modules | head -5
```
## Step 2: Verify Build
## Step 3: Verify Build
```bash
# Run TypeScript type checking
echo "Running TypeScript checks..."
npm run typecheck
pnpm typecheck
# Build the project
echo "Building project..."
npm run build
pnpm build
# Verify dist folder was created
ls -la dist/
```
## Step 3: Run Unit Tests
## Step 4: Run Unit Tests
```bash
# Run unit tests
echo "Running unit tests..."
npm run test:unit
pnpm test:unit
# If tests fail, show the output and stop
if [ $? -ne 0 ]; then
@@ -64,12 +78,12 @@ fi
echo "✅ Unit tests passed successfully"
```
## Step 4: Verify Development Server
## Step 5: Verify Development Server
```bash
# Start development server in background
echo "Starting development server..."
npm run dev &
pnpm dev &
SERVER_PID=$!
# Wait for server to start (check for port 5173 or similar)
@@ -91,28 +105,28 @@ else
fi
```
## Step 5: Final Verification
## Step 6: Final Verification
```bash
# Run linting to ensure code quality
echo "Running linter..."
npm run lint
pnpm lint
# Show project status
echo ""
echo "🎉 Repository setup complete!"
echo ""
echo "Available commands:"
echo " npm run dev - Start development server"
echo " npm run build - Build for production"
echo " npm run test:unit - Run unit tests"
echo " npm run test:component - Run component tests"
echo " npm run typecheck - Run TypeScript checks"
echo " npm run lint - Run ESLint"
echo " npm run format - Format code with Prettier"
echo " pnpm dev - Start development server"
echo " pnpm build - Build for production"
echo " pnpm test:unit - Run unit tests"
echo " pnpm test:component - Run component tests"
echo " pnpm typecheck - Run TypeScript checks"
echo " pnpm lint - Run ESLint"
echo " pnpm format - Format code with Prettier"
echo ""
echo "Next steps:"
echo "1. Run 'npm run dev' to start developing"
echo "1. Run 'pnpm dev' to start developing"
echo "2. Open http://localhost:5173 in your browser"
echo "3. Check README.md for additional setup instructions"
```
@@ -121,7 +135,8 @@ echo "3. Check README.md for additional setup instructions"
If any step fails:
1. **Dependencies fail to install**: Try clearing cache with `npm cache clean --force` and retry
1. **pnpm installation fails**: Try using `curl -fsSL https://get.pnpm.io/install.sh | sh -`
2. **Dependencies fail to install**: Try clearing cache with `pnpm store prune` and retry
3. **Build fails**: Check for TypeScript errors and fix them first
4. **Tests fail**: Review test output and fix failing tests
5. **Dev server fails**: Check if port 5173 is already in use

View File

@@ -5,7 +5,7 @@ Follow these steps systematically to verify our changes:
1. **Server Setup**
- Check if the dev server is running on port 5173 using browser navigation or port checking
- If not running, start it with `npm run dev` from the root directory
- If not running, start it with `pnpm dev` from the root directory
- If the server fails to start, provide detailed troubleshooting steps by reading package.json and README.md for accurate instructions
- Wait for the server to be fully ready before proceeding

1
.gitattributes vendored
View File

@@ -9,6 +9,7 @@
*.mts text eol=lf
*.ts text eol=lf
*.vue text eol=lf
*.yaml text eol=lf
# Generated files
src/types/comfyRegistryTypes.ts linguist-generated=true

View File

@@ -18,11 +18,16 @@ jobs:
with:
fetch-depth: 0 # Required for Chromatic baseline
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
@@ -32,14 +37,14 @@ jobs:
.cache
storybook-static
tsconfig.tsbuildinfo
key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }}
key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }}
restore-keys: |
storybook-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-
storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
storybook-cache-${{ runner.os }}-
storybook-tools-cache-${{ runner.os }}-
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Build Storybook and run Chromatic
id: chromatic

View File

@@ -53,15 +53,20 @@ jobs:
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache: 'pnpm'
- name: Install dependencies for analysis tools
run: |
npm install -g typescript @vue/compiler-sfc
pnpm install -g typescript @vue/compiler-sfc
- name: Run Claude PR Review
uses: anthropics/claude-code-action@main

View File

@@ -16,10 +16,14 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
uses: actions/cache@v4
@@ -28,7 +32,7 @@ jobs:
.cache
dist
tsconfig.tsbuildinfo
key: dev-release-tools-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
key: dev-release-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
dev-release-tools-cache-${{ runner.os }}-
@@ -42,9 +46,9 @@ jobs:
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
USE_PROD_CONFIG: 'true'
run: |
npm ci
npm run build
npm run zipdist
pnpm install --frozen-lockfile
pnpm build
pnpm zipdist
- name: Upload dist artifact
uses: actions/upload-artifact@v4
with:

View File

@@ -42,10 +42,14 @@ jobs:
with:
repository: ${{ inputs.owner }}/${{ inputs.repository }}
path: 'ComfyUI/custom_nodes/${{ inputs.repository }}'
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'
cache: 'pnpm'
- uses: actions/setup-python@v4
with:
python-version: '3.10'
@@ -64,8 +68,8 @@ jobs:
working-directory: ComfyUI/custom_nodes/${{ inputs.repository }}
- name: Build & Install ComfyUI_frontend
run: |
npm ci
npm run build
pnpm install --frozen-lockfile
pnpm build
rm -rf ../ComfyUI/web/*
mv dist/* ../ComfyUI/web/
working-directory: ComfyUI_frontend
@@ -80,18 +84,18 @@ jobs:
- name: Start dev server
# Run electron dev server as it is a superset of the web dev server
# We do want electron specific UIs to be translated.
run: npm run dev:electron &
run: pnpm dev:electron &
working-directory: ComfyUI_frontend
- name: Capture base i18n
run: npx tsx scripts/diff-i18n capture
working-directory: ComfyUI_frontend
- name: Update en.json
run: npm run collect-i18n
run: pnpm collect-i18n
env:
PLAYWRIGHT_TEST_URL: http://localhost:5173
working-directory: ComfyUI_frontend
- name: Update translations
run: npm run locale
run: pnpm locale
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
working-directory: ComfyUI_frontend

View File

@@ -20,15 +20,15 @@ jobs:
- name: Start dev server
# Run electron dev server as it is a superset of the web dev server
# We do want electron specific UIs to be translated.
run: npm run dev:electron &
run: pnpm dev:electron &
working-directory: ComfyUI_frontend
- name: Update en.json
run: npm run collect-i18n -- scripts/collect-i18n-node-defs.ts
run: pnpm collect-i18n -- scripts/collect-i18n-node-defs.ts
env:
PLAYWRIGHT_TEST_URL: http://localhost:5173
working-directory: ComfyUI_frontend
- name: Update translations
run: npm run locale
run: pnpm locale
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
working-directory: ComfyUI_frontend

View File

@@ -22,24 +22,31 @@ jobs:
path: |
ComfyUI_frontend/.cache
ComfyUI_frontend/.cache
key: i18n-tools-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/package-lock.json') }}
key: i18n-tools-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}
restore-keys: |
i18n-tools-cache-${{ runner.os }}-
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}
restore-keys: |
playwright-browsers-${{ runner.os }}-
- name: Install Playwright Browsers
run: npx playwright install chromium --with-deps
working-directory: ComfyUI_frontend
- name: Start dev server
# Run electron dev server as it is a superset of the web dev server
# We do want electron specific UIs to be translated.
run: npm run dev:electron &
run: pnpm dev:electron &
working-directory: ComfyUI_frontend
- name: Update en.json
run: npm run collect-i18n
run: pnpm collect-i18n
env:
PLAYWRIGHT_TEST_URL: http://localhost:5173
working-directory: ComfyUI_frontend
- name: Update translations
run: npm run locale
run: pnpm locale
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
working-directory: ComfyUI_frontend

View File

@@ -16,14 +16,19 @@ jobs:
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.event.pull_request.head.sha }}
ref: ${{ github.event.pull_request.head.ref }}
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
uses: actions/cache@v4
@@ -34,20 +39,20 @@ jobs:
tsconfig.tsbuildinfo
.prettierCache
.knip-cache
key: lint-format-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('src/**/*.{ts,vue,js,mts}', '*.config.*', '.eslintrc.*', '.prettierrc.*', 'tsconfig.json') }}
key: lint-format-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js,mts}', '*.config.*', '.eslintrc.*', '.prettierrc.*', 'tsconfig.json') }}
restore-keys: |
lint-format-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-
lint-format-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
lint-format-cache-${{ runner.os }}-
ci-tools-cache-${{ runner.os }}-
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Run ESLint with auto-fix
run: npm run lint:fix
run: pnpm lint:fix
- name: Run Prettier with auto-format
run: npm run format
run: pnpm format
- name: Check for changes
id: verify-changed-files
@@ -69,9 +74,9 @@ jobs:
- name: Final validation
run: |
npm run lint
npm run format:check
npm run knip
pnpm lint
pnpm format:check
pnpm knip
- name: Comment on PR about auto-fix
if: steps.verify-changed-files.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository

View File

@@ -1,163 +0,0 @@
name: PR Playwright Comment
on:
workflow_run:
workflows: ['Tests CI']
types: [requested, completed]
env:
DATE_FORMAT: '+%m/%d/%Y, %I:%M:%S %p'
jobs:
comment-summary:
runs-on: ubuntu-latest
if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request'
permissions:
pull-requests: write
actions: read
steps:
- name: Get PR number
id: pr
uses: actions/github-script@v7
with:
script: |
const { data: pullRequests } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`,
});
if (pullRequests.length === 0) {
console.log('No open PR found for this branch');
return null;
}
return pullRequests[0].number;
- name: Log when no PR found
if: steps.pr.outputs.result == 'null'
run: |
echo "⚠️ No open PR found for branch: ${{ github.event.workflow_run.head_branch }}"
echo "Workflow run ID: ${{ github.event.workflow_run.id }}"
echo "Repository: ${{ github.event.workflow_run.repository.full_name }}"
echo "Event: ${{ github.event.workflow_run.event }}"
- name: Generate comment body for start
if: steps.pr.outputs.result != 'null' && github.event.action == 'requested'
id: comment-body-start
run: |
echo "<!-- PLAYWRIGHT_TEST_STATUS -->" > comment.md
echo "## 🎭 Playwright Test Results" >> comment.md
echo "" >> comment.md
echo "<img alt='comfy-loading-gif' src='https://github.com/user-attachments/assets/755c86ee-e445-4ea8-bc2c-cca85df48686' width='14px' height='14px' style='vertical-align: middle; margin-right: 4px;' /> **Tests are starting...** " >> comment.md
echo "" >> comment.md
echo "⏰ Started at: ${{ steps.completion-time.outputs.time }} UTC" >> comment.md
echo "" >> comment.md
echo "### 🚀 Running Tests" >> comment.md
echo "- 🧪 **chromium**: Running tests..." >> comment.md
echo "- 🧪 **chromium-0.5x**: Running tests..." >> comment.md
echo "- 🧪 **chromium-2x**: Running tests..." >> comment.md
echo "- 🧪 **mobile-chrome**: Running tests..." >> comment.md
echo "" >> comment.md
echo "---" >> comment.md
echo "⏱️ Please wait while tests are running across all browsers..." >> comment.md
- name: Download all deployment info
if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
uses: actions/download-artifact@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
pattern: deployment-info-*
merge-multiple: true
path: deployment-info
- name: Get completion time
id: completion-time
run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
- name: Generate comment body for completion
if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
id: comment-body-completed
run: |
echo "<!-- PLAYWRIGHT_TEST_STATUS -->" > comment.md
echo "## 🎭 Playwright Test Results" >> comment.md
echo "" >> comment.md
# Check if all tests passed
ALL_PASSED=true
for file in deployment-info/*.txt; do
if [ -f "$file" ]; then
browser=$(basename "$file" .txt)
info=$(cat "$file")
exit_code=$(echo "$info" | cut -d'|' -f2)
if [ "$exit_code" != "0" ]; then
ALL_PASSED=false
break
fi
fi
done
if [ "$ALL_PASSED" = "true" ]; then
echo "✅ **All tests passed across all browsers!**" >> comment.md
else
echo "❌ **Some tests failed!**" >> comment.md
fi
echo "" >> comment.md
echo "⏰ Completed at: ${{ steps.completion-time.outputs.time }} UTC" >> comment.md
echo "" >> comment.md
echo "### 📊 Test Reports by Browser" >> comment.md
for file in deployment-info/*.txt; do
if [ -f "$file" ]; then
browser=$(basename "$file" .txt)
info=$(cat "$file")
exit_code=$(echo "$info" | cut -d'|' -f2)
url=$(echo "$info" | cut -d'|' -f3)
# Validate URLs before using them in comments
sanitized_url=$(echo "$url" | grep -E '^https://[a-z0-9.-]+\.pages\.dev(/.*)?$' || echo "INVALID_URL")
if [ "$sanitized_url" = "INVALID_URL" ]; then
echo "Invalid deployment URL detected: $url"
url="#" # Use safe fallback
fi
if [ "$exit_code" = "0" ]; then
status="✅"
else
status="❌"
fi
echo "- $status **$browser**: [View Report]($url)" >> comment.md
fi
done
echo "" >> comment.md
echo "---" >> comment.md
if [ "$ALL_PASSED" = "true" ]; then
echo "🎉 Your tests are passing across all browsers!" >> comment.md
else
echo "⚠️ Please check the test reports for details on failures." >> comment.md
fi
- name: Comment PR - Tests Started
if: steps.pr.outputs.result != 'null' && github.event.action == 'requested'
uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
with:
issue-number: ${{ steps.pr.outputs.result }}
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
comment-author: 'github-actions[bot]'
edit-mode: replace
body-path: comment.md
- name: Comment PR - Tests Complete
if: steps.pr.outputs.result != 'null' && github.event.action == 'completed'
uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
with:
issue-number: ${{ steps.pr.outputs.result }}
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
comment-author: 'github-actions[bot]'
edit-mode: replace
body-path: comment.md

View File

@@ -1,14 +1,17 @@
name: PR Playwright Deploy
name: PR Playwright Deploy and Comment
on:
workflow_run:
workflows: ["Tests CI"]
types: [completed]
types: [requested, completed]
env:
DATE_FORMAT: '+%m/%d/%Y, %I:%M:%S %p'
jobs:
deploy-reports:
runs-on: ubuntu-latest
if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request'
if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request' && github.event.action == 'completed'
permissions:
actions: read
strategy:
@@ -98,4 +101,180 @@ jobs:
fi
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
comment-tests-starting:
runs-on: ubuntu-latest
if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request' && github.event.action == 'requested'
permissions:
pull-requests: write
actions: read
steps:
- name: Get PR number
id: pr
uses: actions/github-script@v7
with:
script: |
const { data: pullRequests } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`,
});
if (pullRequests.length === 0) {
console.log('No open PR found for this branch');
return null;
}
return pullRequests[0].number;
- name: Get completion time
id: completion-time
run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
- name: Generate comment body for start
if: steps.pr.outputs.result != 'null'
id: comment-body-start
run: |
echo "<!-- PLAYWRIGHT_TEST_STATUS -->" > comment.md
echo "## 🎭 Playwright Test Results" >> comment.md
echo "" >> comment.md
echo "<img alt='comfy-loading-gif' src='https://github.com/user-attachments/assets/755c86ee-e445-4ea8-bc2c-cca85df48686' width='14px' height='14px' style='vertical-align: middle; margin-right: 4px;' /> **Tests are starting...** " >> comment.md
echo "" >> comment.md
echo "⏰ Started at: ${{ steps.completion-time.outputs.time }} UTC" >> comment.md
echo "" >> comment.md
echo "### 🚀 Running Tests" >> comment.md
echo "- 🧪 **chromium**: Running tests..." >> comment.md
echo "- 🧪 **chromium-0.5x**: Running tests..." >> comment.md
echo "- 🧪 **chromium-2x**: Running tests..." >> comment.md
echo "- 🧪 **mobile-chrome**: Running tests..." >> comment.md
echo "" >> comment.md
echo "---" >> comment.md
echo "⏱️ Please wait while tests are running across all browsers..." >> comment.md
- name: Comment PR - Tests Started
if: steps.pr.outputs.result != 'null'
uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
with:
issue-number: ${{ steps.pr.outputs.result }}
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
comment-author: 'github-actions[bot]'
edit-mode: replace
body-path: comment.md
comment-tests-completed:
runs-on: ubuntu-latest
needs: deploy-reports
if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request' && github.event.action == 'completed' && always()
permissions:
pull-requests: write
actions: read
steps:
- name: Get PR number
id: pr
uses: actions/github-script@v7
with:
script: |
const { data: pullRequests } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${context.payload.workflow_run.head_branch}`,
});
if (pullRequests.length === 0) {
console.log('No open PR found for this branch');
return null;
}
return pullRequests[0].number;
- name: Download all deployment info
if: steps.pr.outputs.result != 'null'
uses: actions/download-artifact@v4
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
pattern: deployment-info-*
merge-multiple: true
path: deployment-info
- name: Get completion time
id: completion-time
run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
- name: Generate comment body for completion
if: steps.pr.outputs.result != 'null'
id: comment-body-completed
run: |
echo "<!-- PLAYWRIGHT_TEST_STATUS -->" > comment.md
echo "## 🎭 Playwright Test Results" >> comment.md
echo "" >> comment.md
# Check if all tests passed
ALL_PASSED=true
for file in deployment-info/*.txt; do
if [ -f "$file" ]; then
browser=$(basename "$file" .txt)
info=$(cat "$file")
exit_code=$(echo "$info" | cut -d'|' -f2)
if [ "$exit_code" != "0" ]; then
ALL_PASSED=false
break
fi
fi
done
if [ "$ALL_PASSED" = "true" ]; then
echo "✅ **All tests passed across all browsers!**" >> comment.md
else
echo "❌ **Some tests failed!**" >> comment.md
fi
echo "" >> comment.md
echo "⏰ Completed at: ${{ steps.completion-time.outputs.time }} UTC" >> comment.md
echo "" >> comment.md
echo "### 📊 Test Reports by Browser" >> comment.md
for file in deployment-info/*.txt; do
if [ -f "$file" ]; then
browser=$(basename "$file" .txt)
info=$(cat "$file")
exit_code=$(echo "$info" | cut -d'|' -f2)
url=$(echo "$info" | cut -d'|' -f3)
# Validate URLs before using them in comments
sanitized_url=$(echo "$url" | grep -E '^https://[a-z0-9.-]+\.pages\.dev(/.*)?$' || echo "INVALID_URL")
if [ "$sanitized_url" = "INVALID_URL" ]; then
echo "Invalid deployment URL detected: $url"
url="#" # Use safe fallback
fi
if [ "$exit_code" = "0" ]; then
status="✅"
else
status="❌"
fi
echo "- $status **$browser**: [View Report]($url)" >> comment.md
fi
done
echo "" >> comment.md
echo "---" >> comment.md
if [ "$ALL_PASSED" = "true" ]; then
echo "🎉 Your tests are passing across all browsers!" >> comment.md
else
echo "⚠️ Please check the test reports for details on failures." >> comment.md
fi
- name: Comment PR - Tests Complete
if: steps.pr.outputs.result != 'null'
uses: edumserrano/find-create-or-update-comment@82880b65c8a3a6e4c70aa05a204995b6c9696f53 # v3.0.0
with:
issue-number: ${{ steps.pr.outputs.result }}
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
comment-author: 'github-actions[bot]'
edit-mode: replace
body-path: comment.md

View File

@@ -8,7 +8,10 @@ on:
jobs:
comment-storybook:
runs-on: ubuntu-latest
if: github.repository == 'Comfy-Org/ComfyUI_frontend' && github.event.workflow_run.event == 'pull_request'
if: >-
github.repository == 'Comfy-Org/ComfyUI_frontend'
&& github.event.workflow_run.event == 'pull_request'
&& startsWith(github.event.workflow_run.head_branch, 'version-bump-')
permissions:
pull-requests: write
actions: read
@@ -97,7 +100,17 @@ jobs:
<!-- STORYBOOK_BUILD_STATUS -->
## 🎨 Storybook Build Status
${{ fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && '✅' || '❌' }} **${{ fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && 'Build completed successfully!' || 'Build failed!' }}**
${{
fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && '✅'
|| fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && '⏭️'
|| fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && '🚫'
|| '❌'
}} **${{
fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && 'Build completed successfully!'
|| fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && 'Build skipped.'
|| fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && 'Build cancelled.'
|| 'Build failed!'
}}**
⏰ Completed at: ${{ steps.completion-time.outputs.time }} UTC
@@ -105,4 +118,9 @@ jobs:
- [📊 View Workflow Run](${{ fromJSON(steps.workflow-run.outputs.result).html_url }})
---
${{ fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && '🎉 Your Storybook is ready for review!' || '⚠️ Please check the workflow logs for error details.' }}
${{
fromJSON(steps.workflow-run.outputs.result).conclusion == 'success' && '🎉 Your Storybook is ready for review!'
|| fromJSON(steps.workflow-run.outputs.result).conclusion == 'skipped' && ' Chromatic was skipped for this PR.'
|| fromJSON(steps.workflow-run.outputs.result).conclusion == 'cancelled' && ' The Chromatic run was cancelled.'
|| '⚠️ Please check the workflow logs for error details.'
}}

View File

@@ -19,10 +19,14 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
uses: actions/cache@v4
@@ -30,7 +34,7 @@ jobs:
path: |
.cache
tsconfig.tsbuildinfo
key: release-tools-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
key: release-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
release-tools-cache-${{ runner.os }}-
@@ -53,9 +57,9 @@ jobs:
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
USE_PROD_CONFIG: 'true'
run: |
npm ci
npm run build
npm run zipdist
pnpm install --frozen-lockfile
pnpm build
pnpm zipdist
- name: Upload dist artifact
uses: actions/upload-artifact@v4
with:
@@ -125,10 +129,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'
cache: 'pnpm'
registry-url: https://registry.npmjs.org
- name: Cache tool outputs
@@ -138,14 +146,14 @@ jobs:
.cache
tsconfig.tsbuildinfo
dist
key: types-tools-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
key: types-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
types-tools-cache-${{ runner.os }}-
- run: npm ci
- run: npm run build:types
- run: pnpm install --frozen-lockfile
- run: pnpm build:types
- name: Publish package
run: npm publish --access public
run: pnpm publish --access public
working-directory: dist
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -11,6 +11,13 @@ jobs:
if: github.event.label.name == 'New Browser Test Expectations'
steps:
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}
restore-keys: |
playwright-browsers-${{ runner.os }}-
- name: Install Playwright Browsers
run: npx playwright install chromium --with-deps
working-directory: ComfyUI_frontend

View File

@@ -2,7 +2,7 @@ name: Tests CI
on:
push:
branches: [main, master, core/*, desktop/*, sno-fix-playwright-pnpm]
branches: [main, master, core/*, desktop/*]
pull_request:
branches-ignore:
[wip/*, draft/*, temp/*, vue-nodes-migration, sno-playwright-*]
@@ -12,6 +12,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.cache-key.outputs.key }}
playwright-version: ${{ steps.playwright-version.outputs.PLAYWRIGHT_VERSION }}
steps:
- name: Checkout ComfyUI
uses: actions/checkout@v4
@@ -33,12 +34,16 @@ jobs:
path: 'ComfyUI/custom_nodes/ComfyUI_devtools'
ref: 'd05fd48dd787a4192e16802d4244cfcc0e2f9684'
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: lts/*
cache: 'npm'
cache-dependency-path: 'ComfyUI_frontend/package-lock.json'
cache: 'pnpm'
cache-dependency-path: 'ComfyUI_frontend/pnpm-lock.yaml'
- name: Cache tool outputs
uses: actions/cache@v4
@@ -46,22 +51,29 @@ jobs:
path: |
ComfyUI_frontend/.cache
ComfyUI_frontend/tsconfig.tsbuildinfo
key: playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/package-lock.json') }}-${{ hashFiles('ComfyUI_frontend/src/**/*.{ts,vue,js}', 'ComfyUI_frontend/*.config.*') }}
key: playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-${{ hashFiles('ComfyUI_frontend/src/**/*.{ts,vue,js}', 'ComfyUI_frontend/*.config.*') }}
restore-keys: |
playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/package-lock.json') }}-
playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-
playwright-setup-cache-${{ runner.os }}-
playwright-tools-cache-${{ runner.os }}-
- name: Build ComfyUI_frontend
run: |
npm ci
npm run build
pnpm install --frozen-lockfile
pnpm build
working-directory: ComfyUI_frontend
- name: Generate cache key
id: cache-key
run: echo "key=$(date +%s)" >> $GITHUB_OUTPUT
- name: Playwright Version
id: playwright-version
run: |
PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --json | jq --raw-output '.[0].devDependencies["@playwright/test"].version')
echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_OUTPUT
working-directory: ComfyUI_frontend
- name: Save cache
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684
with:
@@ -70,7 +82,8 @@ jobs:
ComfyUI_frontend
key: comfyui-setup-${{ steps.cache-key.outputs.key }}
playwright-tests:
# Sharded chromium tests
playwright-tests-chromium-sharded:
needs: setup
runs-on: ubuntu-latest
permissions:
@@ -78,7 +91,8 @@ jobs:
strategy:
fail-fast: false
matrix:
browser: [chromium, chromium-2x, chromium-0.5x, mobile-chrome]
shardIndex: [1, 2, 3, 4, 5, 6, 7, 8]
shardTotal: [8]
steps:
- name: Wait for cache propagation
run: sleep 10
@@ -92,12 +106,16 @@ jobs:
ComfyUI_frontend
key: comfyui-setup-${{ needs.setup.outputs.cache-key }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
- name: Install requirements
run: |
python -m pip install --upgrade pip
@@ -106,34 +124,163 @@ jobs:
pip install wait-for-it
working-directory: ComfyUI
- name: Cache Playwright Browsers
uses: actions/cache@v4
id: cache-playwright-browsers
with:
path: '~/.cache/ms-playwright'
key: '${{ runner.os }}-playwright-browsers-${{ needs.setup.outputs.playwright-version }}'
- name: Install Playwright Browsers
if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
run: pnpm exec playwright install chromium --with-deps
working-directory: ComfyUI_frontend
- name: Install Playwright Browsers (operating system dependencies)
if: steps.cache-playwright-browsers.outputs.cache-hit == 'true'
run: pnpm exec playwright install-deps
working-directory: ComfyUI_frontend
- name: Start ComfyUI server
run: |
python main.py --cpu --multi-user --front-end-root ../ComfyUI_frontend/dist &
wait-for-it --service 127.0.0.1:8188 -t 600
working-directory: ComfyUI
- name: Cache Playwright browsers
uses: actions/cache@v4
- name: Run Playwright tests (Shard ${{ matrix.shardIndex }}/${{ matrix.shardTotal }})
id: playwright
run: npx playwright test --project=chromium --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --reporter=blob
working-directory: ComfyUI_frontend
env:
PLAYWRIGHT_BLOB_OUTPUT_DIR: ../blob-report
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/package-lock.json') }}-${{ matrix.browser }}
restore-keys: |
playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/package-lock.json') }}-
playwright-browsers-${{ runner.os }}-
name: blob-report-chromium-${{ matrix.shardIndex }}
path: blob-report/
retention-days: 1
playwright-tests:
# Ideally, each shard runs test in 6 minutes, but allow up to 15 minutes
timeout-minutes: 15
needs: setup
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
browser: [chromium-2x, chromium-0.5x, mobile-chrome]
steps:
- name: Wait for cache propagation
run: sleep 10
- name: Restore cached setup
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684
with:
fail-on-cache-miss: true
path: |
ComfyUI
ComfyUI_frontend
key: comfyui-setup-${{ needs.setup.outputs.cache-key }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
- name: Install requirements
run: |
python -m pip install --upgrade pip
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install -r requirements.txt
pip install wait-for-it
working-directory: ComfyUI
- name: Cache Playwright Browsers
uses: actions/cache@v4
id: cache-playwright-browsers
with:
path: '~/.cache/ms-playwright'
key: '${{ runner.os }}-playwright-browsers-${{ needs.setup.outputs.playwright-version }}'
- name: Install Playwright Browsers
run: npx playwright install chromium --with-deps
if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
run: pnpm exec playwright install chromium --with-deps
working-directory: ComfyUI_frontend
- name: Install Playwright Browsers (operating system dependencies)
if: steps.cache-playwright-browsers.outputs.cache-hit == 'true'
run: pnpm exec playwright install-deps
working-directory: ComfyUI_frontend
- name: Start ComfyUI server
run: |
python main.py --cpu --multi-user --front-end-root ../ComfyUI_frontend/dist &
wait-for-it --service 127.0.0.1:8188 -t 600
working-directory: ComfyUI
- name: Run Playwright tests (${{ matrix.browser }})
id: playwright
run: npx playwright test --project=${{ matrix.browser }} --reporter=html
working-directory: ComfyUI_frontend
- uses: actions/upload-artifact@v4
if: always() # note: use always() to allow results to be upload/report even tests failed.
if: always()
with:
name: playwright-report-${{ matrix.browser }}
path: ComfyUI_frontend/playwright-report/
retention-days: 30
# Merge sharded test reports
merge-reports:
needs: [playwright-tests-chromium-sharded]
runs-on: ubuntu-latest
if: ${{ !cancelled() }}
steps:
- name: Checkout ComfyUI_frontend
uses: actions/checkout@v4
with:
repository: 'Comfy-Org/ComfyUI_frontend'
path: 'ComfyUI_frontend'
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: lts/*
cache: 'pnpm'
cache-dependency-path: 'ComfyUI_frontend/pnpm-lock.yaml'
- name: Install dependencies
run: |
pnpm install --frozen-lockfile
working-directory: ComfyUI_frontend
- name: Download blob reports
uses: actions/download-artifact@v4
with:
path: ComfyUI_frontend/all-blob-reports
pattern: blob-report-chromium-*
merge-multiple: true
- name: Merge into HTML Report
run: npx playwright merge-reports --reporter html ./all-blob-reports
working-directory: ComfyUI_frontend
- name: Upload HTML report
uses: actions/upload-artifact@v4
with:
name: playwright-report-chromium
path: ComfyUI_frontend/playwright-report/
retention-days: 30

View File

@@ -14,28 +14,33 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
uses: actions/cache@v4
with:
path: |
.cache
key: electron-types-tools-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
key: electron-types-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
electron-types-tools-cache-${{ runner.os }}-
- name: Update electron types
run: npm install @comfyorg/comfyui-electron-types@latest
run: pnpm install --workspace-root @comfyorg/comfyui-electron-types@latest
- name: Get new version
id: get-version
run: |
NEW_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('./package-lock.json')).packages['node_modules/@comfyorg/comfyui-electron-types'].version)")
NEW_VERSION=$(pnpm list @comfyorg/comfyui-electron-types --json --depth=0 | jq -r '.[0].version')
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT
- name: Create Pull Request

View File

@@ -19,23 +19,28 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
uses: actions/cache@v4
with:
path: |
.cache
key: update-manager-tools-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
key: update-manager-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
update-manager-tools-cache-${{ runner.os }}-
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Cache ComfyUI-Manager repository
uses: actions/cache@v4
@@ -81,7 +86,7 @@ jobs:
- name: Lint generated types
run: |
echo "Linting generated ComfyUI-Manager API types..."
npm run lint:fix:no-cache -- ./src/types/generatedManagerTypes.ts
pnpm lint:fix:no-cache -- ./src/types/generatedManagerTypes.ts
- name: Check for changes
id: check-changes
@@ -116,4 +121,4 @@ jobs:
labels: Manager
delete-branch: true
add-paths: |
src/types/generatedManagerTypes.ts
src/types/generatedManagerTypes.ts

View File

@@ -18,23 +18,28 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
uses: actions/cache@v4
with:
path: |
.cache
key: update-registry-tools-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
key: update-registry-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
update-registry-tools-cache-${{ runner.os }}-
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Cache comfy-api repository
uses: actions/cache@v4
@@ -81,7 +86,7 @@ jobs:
- name: Lint generated types
run: |
echo "Linting generated Comfy Registry API types..."
npm run lint:fix:no-cache -- ./src/types/comfyRegistryTypes.ts
pnpm lint:fix:no-cache -- ./src/types/comfyRegistryTypes.ts
- name: Check for changes
id: check-changes

View File

@@ -26,16 +26,21 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: 'npm'
cache: 'pnpm'
- name: Bump version
id: bump-version
run: |
npm version ${{ github.event.inputs.version_type }} --preid ${{ github.event.inputs.pre_release }} --no-git-tag-version
pnpm version ${{ github.event.inputs.version_type }} --preid ${{ github.event.inputs.pre_release }} --no-git-tag-version
NEW_VERSION=$(node -p "require('./package.json').version")
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT

View File

@@ -13,11 +13,16 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
cache: 'npm'
cache: 'pnpm'
- name: Cache tool outputs
uses: actions/cache@v4
@@ -26,16 +31,16 @@ jobs:
.cache
coverage
.vitest-cache
key: vitest-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('src/**/*.{ts,vue,js}', 'vitest.config.*', 'tsconfig.json') }}
key: vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', 'vitest.config.*', 'tsconfig.json') }}
restore-keys: |
vitest-cache-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}-
vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
vitest-cache-${{ runner.os }}-
test-tools-cache-${{ runner.os }}-
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Run Vitest tests
run: |
npm run test:component
npm run test:unit
pnpm test:component
pnpm test:unit

View File

@@ -2,9 +2,9 @@
## Quick Commands
- `npm run storybook`: Start Storybook development server
- `npm run build-storybook`: Build static Storybook
- `npm run test:component`: Run component tests (includes Storybook components)
- `pnpm storybook`: Start Storybook development server
- `pnpm build-storybook`: Build static Storybook
- `pnpm test:component`: Run component tests (includes Storybook components)
## Development Workflow for Storybook
@@ -19,8 +19,8 @@
- Ensure proper theming and styling
3. **Code Quality**:
- Run `npm run typecheck` to verify TypeScript
- Run `npm run lint` to check for linting issues
- Run `pnpm typecheck` to verify TypeScript
- Run `pnpm lint` to check for linting issues
- Follow existing story patterns and conventions
## Story Creation Guidelines
@@ -138,13 +138,13 @@ The Storybook preview is configured with:
```bash
# Check TypeScript issues
npm run typecheck
pnpm typecheck
# Lint Storybook files
npm run lint .storybook/
pnpm lint .storybook/
# Build to check for production issues
npm run build-storybook
pnpm build-storybook
```
## File Organization

View File

@@ -40,10 +40,10 @@ Storybook is a frontend workshop for building UI components and pages in isolati
```bash
# Start Storybook development server
npm run storybook
pnpm storybook
# Build static Storybook for deployment
npm run build-storybook
pnpm build-storybook
```
### Creating Stories

44
.vscode/tailwind.json vendored
View File

@@ -2,12 +2,32 @@
"version": 1.1,
"atDirectives": [
{
"name": "@tailwind",
"description": "Use the `@tailwind` directive to insert Tailwind's `base`, `components`, `utilities` and `screens` styles into your CSS.",
"name": "@import",
"description": "Use the `@import` directive to inline CSS files, including Tailwind itself, into your stylesheet.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#tailwind"
"url": "https://tailwindcss.com/docs/functions-and-directives#import"
}
]
},
{
"name": "@theme",
"description": "Use the `@theme` directive to define custom design tokens like fonts, colors, and breakpoints.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#theme"
}
]
},
{
"name": "@layer",
"description": "Use the `@layer` directive inside `@theme` to organize custom styles into different layers like `base`, `components`, and `utilities`.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#layer"
}
]
},
@@ -22,32 +42,32 @@
]
},
{
"name": "@responsive",
"description": "You can generate responsive variants of your own classes by wrapping their definitions in the `@responsive` directive:\n```css\n@responsive {\n .alert {\n background-color: #E53E3E;\n }\n}\n```\n",
"name": "@config",
"description": "Use the `@config` directive to load a legacy JavaScript-based Tailwind configuration file.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#responsive"
"url": "https://tailwindcss.com/docs/functions-and-directives#config"
}
]
},
{
"name": "@screen",
"description": "The `@screen` directive allows you to create media queries that reference your breakpoints by **name** instead of duplicating their values in your own CSS:\n```css\n@screen sm {\n /* ... */\n}\n```\n…gets transformed into this:\n```css\n@media (min-width: 640px) {\n /* ... */\n}\n```\n",
"name": "@reference",
"description": "Use the `@reference` directive to import theme variables, custom utilities, and custom variants from other files without duplicating CSS.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#screen"
"url": "https://tailwindcss.com/docs/functions-and-directives#reference"
}
]
},
{
"name": "@variants",
"description": "Generate `hover`, `focus`, `active` and other **variants** of your own utilities by wrapping their definitions in the `@variants` directive:\n```css\n@variants hover, focus {\n .btn-brand {\n background-color: #3182CE;\n }\n}\n```\n",
"name": "@plugin",
"description": "Use the `@plugin` directive to load a legacy JavaScript-based Tailwind plugin.",
"references": [
{
"name": "Tailwind Documentation",
"url": "https://tailwindcss.com/docs/functions-and-directives#variants"
"url": "https://tailwindcss.com/docs/functions-and-directives#plugin"
}
]
}

View File

@@ -8,19 +8,19 @@
- Config: `vite.config.mts`, `vitest.config.ts`, `playwright.config.ts`, `eslint.config.js`, `.prettierrc`.
## Build, Test, and Development Commands
- `npm run dev`: Start Vite dev server.
- `npm run dev:electron`: Dev server with Electron API mocks.
- `npm run build`: Type-check then production build to `dist/`.
- `npm run preview`: Preview the production build locally.
- `npm run test:unit`: Run Vitest unit tests (`tests-ui/`).
- `npm run test:component`: Run component tests (`src/components/`).
- `npm run test:browser`: Run Playwright E2E tests (`browser_tests/`).
- `npm run lint` / `npm run lint:fix`: Lint (ESLint). `npm run format` / `format:check`: Prettier.
- `npm run typecheck`: Vue TSC type checking.
- `pnpm dev`: Start Vite dev server.
- `pnpm dev:electron`: Dev server with Electron API mocks.
- `pnpm build`: Type-check then production build to `dist/`.
- `pnpm preview`: Preview the production build locally.
- `pnpm test:unit`: Run Vitest unit tests (`tests-ui/`).
- `pnpm test:component`: Run component tests (`src/components/`).
- `pnpm test:browser`: Run Playwright E2E tests (`browser_tests/`).
- `pnpm lint` / `pnpm lint:fix`: Lint (ESLint). `pnpm format` / `format:check`: Prettier.
- `pnpm typecheck`: Vue TSC type checking.
## Coding Style & Naming Conventions
- Language: TypeScript, Vue SFCs (`.vue`). Indent 2 spaces; single quotes; no semicolons; width 80 (see `.prettierrc`).
- Imports: sorted/grouped by plugin; run `npm run format` before committing.
- Imports: sorted/grouped by plugin; run `pnpm format` before committing.
- ESLint: Vue + TS rules; no floating promises; unused imports disallowed; i18n raw text restrictions in templates.
- Naming: Vue components in PascalCase (e.g., `MenuHamburger.vue`); composables `useXyz.ts`; Pinia stores `*Store.ts`.
@@ -33,7 +33,7 @@
## Commit & Pull Request Guidelines
- Commits: Prefer Conventional Commits (e.g., `feat(ui): add sidebar`), `refactor(litegraph): …`. Use `[skip ci]` for locale-only updates when appropriate.
- PRs: Include clear description, linked issues (`Fixes #123`), and screenshots/GIFs for UI changes. Add/adjust tests and i18n strings when applicable.
- Quality gates: `npm run lint`, `npm run typecheck`, and relevant tests must pass. Keep PRs focused and small.
- Quality gates: `pnpm lint`, `pnpm typecheck`, and relevant tests must pass. Keep PRs focused and small.
## Security & Configuration Tips
- Secrets: Use `.env` (see `.env_example`); do not commit secrets.

View File

@@ -12,18 +12,18 @@ This bootstraps the monorepo with dependencies, builds, tests, and dev server ve
## Quick Commands
- `npm run`: See all available commands
- `npm run dev`: Start development server (port 5173, via nx)
- `npm run typecheck`: Type checking
- `npm run build`: Build for production (via nx)
- `npm run lint`: Linting (via nx)
- `npm run format`: Prettier formatting
- `npm run test:component`: Run component tests with browser environment
- `npm run test:unit`: Run all unit tests
- `npm run test:browser`: Run E2E tests via Playwright
- `npm run test:unit -- tests-ui/tests/example.test.ts`: Run single test file
- `npm run storybook`: Start Storybook development server (port 6006)
- `npm run knip`: Detect unused code and dependencies
- `pnpm`: See all available commands
- `pnpm dev`: Start development server (port 5173, via nx)
- `pnpm typecheck`: Type checking
- `pnpm build`: Build for production (via nx)
- `pnpm lint`: Linting (via nx)
- `pnpm format`: Prettier formatting
- `pnpm test:component`: Run component tests with browser environment
- `pnpm test:unit`: Run all unit tests
- `pnpm test:browser`: Run E2E tests via Playwright
- `pnpm test:unit -- tests-ui/tests/example.test.ts`: Run single test file
- `pnpm storybook`: Start Storybook development server (port 6006)
- `pnpm knip`: Detect unused code and dependencies
## Monorepo Architecture
@@ -82,6 +82,44 @@ When referencing Comfy-Org repos:
2. Use GitHub API for branches/PRs/metadata
3. Curl GitHub website if needed
## Settings and Feature Flags Quick Reference
### Settings Usage
```typescript
const settingStore = useSettingStore()
const value = settingStore.get('Comfy.SomeSetting') // Get setting
await settingStore.set('Comfy.SomeSetting', newValue) // Update setting
```
### Dynamic Defaults
```typescript
{
id: 'Comfy.Example.Setting',
defaultValue: () => window.innerWidth < 1024 ? 'small' : 'large' // Runtime context
}
```
### Version-Based Defaults
```typescript
{
id: 'Comfy.Example.Feature',
defaultValue: 'legacy',
defaultsByInstallVersion: { '1.25.0': 'enhanced' } // Gradual rollout
}
```
### Feature Flags
```typescript
if (api.serverSupportsFeature('feature_name')) { // Check capability
// Use enhanced feature
}
const value = api.getServerFeature('config_name', defaultValue) // Get config
```
**Documentation:**
- Settings system: `docs/SETTINGS.md`
- Feature flags system: `docs/FEATURE_FLAGS.md`
## Common Pitfalls
- NEVER use `any` type - use proper TypeScript types
@@ -89,3 +127,6 @@ When referencing Comfy-Org repos:
- NEVER use `--no-verify` flag when committing
- NEVER delete or disable tests to make them pass
- NEVER circumvent quality checks
- NEVER use `dark:` prefix - always use `dark-theme:` for dark mode styles, for example: `dark-theme:text-white dark-theme:bg-black`
- NEVER use `:class="[]"` to merge class names - always use `import { cn } from '@/utils/tailwindUtil'`, for example: `<div :class="cn('bg-red-500', { 'bg-blue-500': condition })" />`

View File

@@ -17,7 +17,7 @@ Have another idea? Drop into Discord or open an issue, and let's chat!
### Prerequisites & Technology Stack
- **Required Software**:
- Node.js (v16 or later; v24 strongly recommended) and npm
- Node.js (v18 or later to build; v24 for vite dev server) and pnpm
- Git for version control
- A running ComfyUI backend instance
@@ -39,7 +39,7 @@ Have another idea? Drop into Discord or open an issue, and let's chat!
2. Install dependencies:
```bash
npm install
pnpm install
```
3. Configure environment (optional):
@@ -57,13 +57,13 @@ python main.py --port 8188
### Git pre-commit hooks
Run `npm run prepare` to install Git pre-commit hooks. Currently, the pre-commit hook is used to auto-format code on commit.
Run `pnpm prepare` to install Git pre-commit hooks. Currently, the pre-commit hook is used to auto-format code on commit.
### Dev Server
- Start local ComfyUI backend at `localhost:8188`
- Run `npm run dev` to start the dev server
- Run `npm run dev:electron` to start the dev server with electron API mocked
- Run `pnpm dev` to start the dev server
- Run `pnpm dev:electron` to start the dev server with electron API mocked
#### Access dev server on touch devices
@@ -155,7 +155,7 @@ For ComfyUI_frontend development, you can ask coding assistants to use Playwrigh
##### Setup for Claude Code
After installing dependencies with `npm install`, the Playwright MCP server will be automatically available when you start Claude Code locally.
After installing dependencies with `pnpm i`, the Playwright MCP server will be automatically available when you start Claude Code locally.
Here's how Claude Code can use the Playwright MCP server to inspect the interface of the local development server (assuming you're running the dev server at `localhost:5173`):
@@ -210,14 +210,14 @@ Here's how Claude Code can use the Playwright MCP server to inspect the interfac
### Unit Tests
- `npm install` to install all dependencies
- `npm run test:unit` to execute all unit tests
- `pnpm i` to install all dependencies
- `pnpm test:unit` to execute all unit tests
### Component Tests
Component tests verify Vue components in `src/components/`.
- `npm run test:component` to execute all component tests
- `pnpm test:component` to execute all component tests
### Playwright Tests
@@ -228,12 +228,12 @@ Playwright tests verify the whole app. See [browser_tests/README.md](browser_tes
Before submitting a PR, ensure all tests pass:
```bash
npm run test:unit
npm run test:component
npm run test:browser
npm run typecheck
npm run lint
npm run format
pnpm test:unit
pnpm test:component
pnpm test:browser
pnpm typecheck
pnpm lint
pnpm format
```
## Code Style Guidelines

View File

@@ -1,5 +1,4 @@
import { test as base } from '@playwright/test'
import { Page } from 'playwright'
import { Page, test as base } from '@playwright/test'
export class UserSelectPage {
constructor(

View File

@@ -1,7 +1,7 @@
import type { Request, Route } from '@playwright/test'
import _ from 'es-toolkit/compat'
import fs from 'fs'
import path from 'path'
import type { Request, Route } from 'playwright'
import { v4 as uuidv4 } from 'uuid'
import type {

View File

@@ -0,0 +1,131 @@
import type { Locator, Page } from '@playwright/test'
import type { NodeReference } from './litegraphUtils'
/**
* VueNodeFixture provides Vue-specific testing utilities for interacting with
* Vue node components. It bridges the gap between litegraph node references
* and Vue UI components.
*/
export class VueNodeFixture {
constructor(
private readonly nodeRef: NodeReference,
private readonly page: Page
) {}
/**
* Get the node's header element using data-testid
*/
async getHeader(): Promise<Locator> {
const nodeId = this.nodeRef.id
return this.page.locator(`[data-testid="node-header-${nodeId}"]`)
}
/**
* Get the node's title element
*/
async getTitleElement(): Promise<Locator> {
const header = await this.getHeader()
return header.locator('[data-testid="node-title"]')
}
/**
* Get the current title text
*/
async getTitle(): Promise<string> {
const titleElement = await this.getTitleElement()
return (await titleElement.textContent()) || ''
}
/**
* Set a new title by double-clicking and entering text
*/
async setTitle(newTitle: string): Promise<void> {
const titleElement = await this.getTitleElement()
await titleElement.dblclick()
const input = (await this.getHeader()).locator(
'[data-testid="node-title-input"]'
)
await input.fill(newTitle)
await input.press('Enter')
}
/**
* Cancel title editing
*/
async cancelTitleEdit(): Promise<void> {
const titleElement = await this.getTitleElement()
await titleElement.dblclick()
const input = (await this.getHeader()).locator(
'[data-testid="node-title-input"]'
)
await input.press('Escape')
}
/**
* Check if the title is currently being edited
*/
async isEditingTitle(): Promise<boolean> {
const header = await this.getHeader()
const input = header.locator('[data-testid="node-title-input"]')
return await input.isVisible()
}
/**
* Get the collapse/expand button
*/
async getCollapseButton(): Promise<Locator> {
const header = await this.getHeader()
return header.locator('[data-testid="node-collapse-button"]')
}
/**
* Toggle the node's collapsed state
*/
async toggleCollapse(): Promise<void> {
const button = await this.getCollapseButton()
await button.click()
}
/**
* Get the collapse icon element
*/
async getCollapseIcon(): Promise<Locator> {
const button = await this.getCollapseButton()
return button.locator('i')
}
/**
* Get the collapse icon's CSS classes
*/
async getCollapseIconClass(): Promise<string> {
const icon = await this.getCollapseIcon()
return (await icon.getAttribute('class')) || ''
}
/**
* Check if the collapse button is visible
*/
async isCollapseButtonVisible(): Promise<boolean> {
const button = await this.getCollapseButton()
return await button.isVisible()
}
/**
* Get the node's body/content element
*/
async getBody(): Promise<Locator> {
const nodeId = this.nodeRef.id
return this.page.locator(`[data-testid="node-body-${nodeId}"]`)
}
/**
* Check if the node body is visible (not collapsed)
*/
async isBodyVisible(): Promise<boolean> {
const body = await this.getBody()
return await body.isVisible()
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

View File

@@ -59,18 +59,6 @@ test.describe('Execution error', () => {
const executionError = comfyPage.page.locator('.comfy-error-report')
await expect(executionError).toBeVisible()
})
test('Can display Issue Report form', async ({ comfyPage }) => {
await comfyPage.loadWorkflow('nodes/execution_error')
await comfyPage.queueButton.click()
await comfyPage.nextFrame()
await comfyPage.page.getByLabel('Help Fix This').click()
const issueReportForm = comfyPage.page.getByText(
'Submit Error Report (Optional)'
)
await expect(issueReportForm).toBeVisible()
})
})
test.describe('Missing models warning', () => {
@@ -303,37 +291,16 @@ test.describe('Settings', () => {
})
})
test.describe('Feedback dialog', () => {
test('Should open from topmenu help command', async ({ comfyPage }) => {
// Open feedback dialog from top menu
test.describe('Support', () => {
test('Should open external zendesk link', async ({ comfyPage }) => {
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
await comfyPage.menu.topbar.triggerTopbarCommand(['Help', 'Feedback'])
const pagePromise = comfyPage.page.context().waitForEvent('page')
await comfyPage.menu.topbar.triggerTopbarCommand(['Help', 'Support'])
const newPage = await pagePromise
// Verify feedback dialog content is visible
const feedbackHeader = comfyPage.page.getByRole('heading', {
name: 'Feedback'
})
await expect(feedbackHeader).toBeVisible()
})
test('Should close when close button clicked', async ({ comfyPage }) => {
// Open feedback dialog
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
await comfyPage.menu.topbar.triggerTopbarCommand(['Help', 'Feedback'])
const feedbackHeader = comfyPage.page.getByRole('heading', {
name: 'Feedback'
})
// Close feedback dialog
await comfyPage.page
.getByLabel('', { exact: true })
.getByLabel('Close')
.click()
await feedbackHeader.waitFor({ state: 'hidden' })
// Verify dialog is closed
await expect(feedbackHeader).not.toBeVisible()
await newPage.waitForLoadState('networkidle')
await expect(newPage).toHaveURL(/.*support\.comfy\.org.*/)
await newPage.close()
})
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Some files were not shown because too many files have changed in this diff Show More