Compare commits

...

141 Commits

Author SHA1 Message Date
Comfy Org PR Bot
1b7565559a [backport cloud/1.38] fix: prevent XSS vulnerability in context menu labels (#8923)
Backport of #8887 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8923-backport-cloud-1-38-fix-prevent-XSS-vulnerability-in-context-menu-labels-3096d73d365081baa2dce3b6c8027736)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: github-actions <github-actions@github.com>
2026-02-17 02:25:07 -08:00
Comfy Org PR Bot
4d1645931c [backport cloud/1.38] fix: clear draft on workflow close to prevent stale state on reopen (#8869)
Backport of #8854 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8869-backport-cloud-1-38-fix-clear-draft-on-workflow-close-to-prevent-stale-state-on-reopen-3076d73d365081a7b0f5f602c2a609ea)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-02-14 02:58:44 -08:00
Comfy Org PR Bot
2279bc0276 [backport cloud/1.38] fix: default onboardingSurveyEnabled flag to false (#8830)
Backport of #8829 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8830-backport-cloud-1-38-fix-default-onboardingSurveyEnabled-flag-to-false-3056d73d3650817fa52bd33647f04e90)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-12 00:09:30 -08:00
Comfy Org PR Bot
f9e526e4a8 [backport cloud/1.38] feat: invite member upsell for single-seat plans (#8822)
Backport of #8801 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8822-backport-cloud-1-38-feat-invite-member-upsell-for-single-seat-plans-3056d73d3650815586bdfdaba8a7ae2e)
by [Unito](https://www.unito.io)

Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
2026-02-11 21:51:49 -08:00
Comfy Org PR Bot
7afe45fdf8 [backport cloud/1.38] fix: credit display and top up and other UI display if personal membe… (#8811)
Backport of #8784 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8811-backport-cloud-1-38-fix-credit-display-and-top-up-and-other-UI-display-if-personal-mem-3046d73d365081feb075e6c712aced3e)
by [Unito](https://www.unito.io)

Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com>
2026-02-11 14:34:42 -08:00
Comfy Org PR Bot
450e75ff83 [backport cloud/1.38] Fix hit detection on vue node slots (#8799)
Backport of #8609 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8799-backport-cloud-1-38-Fix-hit-detection-on-vue-node-slots-3046d73d365081379ed5dcdf359e8610)
by [Unito](https://www.unito.io)

Co-authored-by: pythongosssss <125205205+pythongosssss@users.noreply.github.com>
2026-02-10 19:38:54 -08:00
Comfy Org PR Bot
e3391c7895 [backport cloud/1.38] fix(download): Use content-disposition filename (#8796)
Backport of #8785 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8796-backport-cloud-1-38-fix-download-Use-content-disposition-filename-3046d73d365081389899ebc4e6712415)
by [Unito](https://www.unito.io)

Co-authored-by: guill <jacob.e.segal@gmail.com>
2026-02-10 18:58:43 -08:00
Comfy Org PR Bot
6d21aad1f9 [backport cloud/1.38] fix: handle RIFF padding for odd-sized WEBP chunks (#8795)
Backport of #8527 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8795-backport-cloud-1-38-fix-handle-RIFF-padding-for-odd-sized-WEBP-chunks-3046d73d365081cc85bae4ada8541965)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
2026-02-10 18:51:59 -08:00
Comfy Org PR Bot
6b4334759f [backport cloud/1.38] Austin/fix move subgraph input (#8793)
Backport of #8777 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8793-backport-cloud-1-38-Austin-fix-move-subgraph-input-3046d73d365081c1a6c0d1983c433b50)
by [Unito](https://www.unito.io)

Co-authored-by: AustinMroz <austin@comfy.org>
2026-02-10 18:51:18 -08:00
Comfy Org PR Bot
9c8f815b05 [backport cloud/1.38] Remove comfy logo splash screen. (#8789)
Backport of #8786 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8789-backport-cloud-1-38-Remove-comfy-logo-splash-screen-3046d73d3650810c8c72d40bf86d900c)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-02-10 16:54:01 -08:00
Comfy Org PR Bot
e2744868a4 [backport cloud/1.38] feat: sort workspaces (#8776)
Backport of #8770 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8776-backport-cloud-1-38-feat-sort-workspaces-3036d73d36508173bb59f3b4ac8e463f)
by [Unito](https://www.unito.io)

Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com>
2026-02-10 10:31:40 -08:00
Comfy Org PR Bot
c12aa37599 [backport cloud/1.38] feat: wire renewal_date from cloud billing status (#8755)
Backport of #8754 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8755-backport-cloud-1-38-feat-wire-renewal_date-from-cloud-billing-status-3026d73d3650818e8281cf0778dc0137)
by [Unito](https://www.unito.io)

Co-authored-by: Hunter <huntcsg@users.noreply.github.com>
2026-02-09 13:18:27 -08:00
Comfy Org PR Bot
9d89a405cf [backport cloud/1.38] fix: show credit balance for unsubscribed personal workspaces (#8738)
Backport of #8719 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Hunter <huntcsg@users.noreply.github.com>
2026-02-07 20:30:25 -08:00
Comfy Org PR Bot
47d5001833 [backport cloud/1.38] fix(vue-nodes): hide slot labels for reroute nodes with empty names (#8728)
Backport of #8574 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8728-backport-cloud-1-38-fix-vue-nodes-hide-slot-labels-for-reroute-nodes-with-empty-names-3006d73d3650816a9d83d96fe00389b2)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-02-07 20:03:42 -08:00
Simula_r
9691f5fd00 [backport cloud/1.38] Feat/workspaces 6 billing (#8713)
Backport of #8508 to `cloud/1.38`

Automatically created by manual backport (cherry-pick of
c5431de123).

Conflicts resolved:
-
`src/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts`
— accepted PR version (uses `useBillingContext` mock instead of
pinia/firebase auth)
- `src/services/dialogService.ts` — merged: kept cloud/1.38 eager
imports for dialog components, replaced `TopUpCreditsDialogContent` with
Legacy/Workspace variants, replaced `useSubscription` with
`useBillingContext`, added workspace/legacy component selection in
`showTopUpCreditsDialog`; skipped lazy loader refactor (separate PR, not
part of #8508)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 21:16:21 -08:00
Comfy Org PR Bot
5c43c933d7 [backport cloud/1.38] feat: add model-to-node mappings for cloud asset categories (#8706)
Backport of #8468 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
2026-02-06 16:13:36 -08:00
Comfy Org PR Bot
155548c1b8 [backport cloud/1.38] fix: include subfolder in asset download URL for audio/video files (#8685)
Backport of #8684 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com>
2026-02-06 05:27:09 +01:00
Comfy Org PR Bot
a51ba16e5a [backport cloud/1.38] fix: prevent duplicate context menu items by using content-based comparison (#8617) 2026-02-05 14:58:40 +01:00
Comfy Org PR Bot
1b3127bb0d [backport cloud/1.38] Update manifest.json to remove color properties (#8613)
Backport of #8612 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-02-04 20:31:54 +00:00
Comfy Org PR Bot
45a0bf1e89 [backport cloud/1.38] fix: Safari compatibility issues in Secrets panel dialog (#8611)
Backport of #8610 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Luke Mino-Altherr <luke@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
2026-02-04 20:09:28 +00:00
AustinMroz
ab96fec96e [backport cloud/1.38] fix: localize node definition filter names and descriptions (#8563)
Backport of #8540 to cloud/1.38

Does not include dev-node changes since that has not been backported.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8563-backport-cloud-1-38-fix-localize-node-definition-filter-names-and-descriptions-2fc6d73d36508171b11cfa01d522438b)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-02-03 11:02:49 -08:00
Comfy Org PR Bot
aca98890b2 [backport cloud/1.38] feat: remove obsolete model asset feature flags (#8568)
Backport of #8566 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Luke Mino-Altherr <luke@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
2026-02-03 03:12:25 +00:00
Comfy Org PR Bot
cb86a1c94e [backport cloud/1.38] fix: dedupe queueStore.update() to prevent race conditions (#8558)
Backport of #8523 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8558-backport-cloud-1-38-fix-dedupe-queueStore-update-to-prevent-race-conditions-2fc6d73d3650812494dec497cc6b01fa)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
2026-02-02 17:39:41 -08:00
Luke Mino-Altherr
6eb8aa4820 [backport cloud/1.38] feat: add user secrets management panel (#8560)
Backport of #8473 to cloud/1.38

Cherry-picked merge commit bc19bb60fb

## Conflicts resolved
- `src/locales/en/main.json`: Added missing closing brace for `nightly`
section and accepted PR's new `nodeFilters` and `secrets` sections

Co-authored-by: Amp <amp@ampcode.com>
2026-02-03 01:39:33 +00:00
Comfy Org PR Bot
020ad868ce [backport cloud/1.38] fix: node header on preview has a gap on the right (not flush) (#8556)
Backport of #8487 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8556-backport-cloud-1-38-fix-node-header-on-preview-has-a-gap-on-the-right-not-flush-2fc6d73d3650812e8502edb5aaf64bd2)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-02-02 17:38:51 -08:00
Comfy Org PR Bot
02b3bb840e [backport cloud/1.38] fix: add Frame Nodes to core menu items for multi-selection context menu (#8554)
Backport of #8524 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8554-backport-cloud-1-38-fix-add-Frame-Nodes-to-core-menu-items-for-multi-selection-context-2fc6d73d365081c9b5c7cd6f6c4d5335)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
2026-02-02 17:37:51 -08:00
Comfy Org PR Bot
942ffbe896 [backport cloud/1.38] fix: update reactive ref after merge in imagePreviewStore (#8503)
Backport of #8479 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8503-backport-cloud-1-38-fix-update-reactive-ref-after-merge-in-imagePreviewStore-2f96d73d3650812088c8edfb5b919a27)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Austin Mroz <austin@comfy.org>
2026-01-31 23:40:10 -08:00
Comfy Org PR Bot
d30e1a882e [backport cloud/1.38] fix(cloud): disable legacy node templates feature on cloud (#8504)
Backport of #8462 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8504-backport-cloud-1-38-fix-cloud-disable-legacy-node-templates-feature-on-cloud-2f96d73d3650815993ebc15eb076744e)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-31 23:22:31 -08:00
Comfy Org PR Bot
7fc0b55bb8 [backport cloud/1.38] fix: remove delete account button and direct users to support (#8522)
Backport of #8515 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8522-backport-cloud-1-38-fix-remove-delete-account-button-and-direct-users-to-support-2fa6d73d3650813da43eeb404f9918cd)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-31 20:01:54 -08:00
Comfy Org PR Bot
7d114577b5 [backport cloud/1.38] Update control_after_generate schema (#8507)
Backport of #8505 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8507-backport-cloud-1-38-Update-control_after_generate-schema-2f96d73d365081d399f3f459a843709e)
by [Unito](https://www.unito.io)

Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-30 21:43:00 -08:00
Comfy Org PR Bot
26bf6d324e [backport cloud/1.38] fix: prevent image/video preview reset on dynamic widget addition (#8493)
Backport of #8366 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8493-backport-cloud-1-38-fix-prevent-image-video-preview-reset-on-dynamic-widget-addition-2f86d73d36508192b27fc55a29d6d02e)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-30 08:37:41 -08:00
Comfy Org PR Bot
77f94a3357 [backport cloud/1.38] fix: properties panel obscures menus in legacy layout (#8491)
Backport of #8474 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8491-backport-cloud-1-38-fix-properties-panel-obscures-menus-in-legacy-layout-2f86d73d365081aea778f7573e1202f8)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-30 08:23:47 -08:00
Comfy Org PR Bot
29a0071b4e [backport cloud/1.38] Fix: Hide Jobs in Assets Panel when Queue V2 is disabled. (#8486)
Backport of #8450 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-30 08:03:35 +00:00
AustinMroz
99f85d9b04 Revert matchtype slot reactivity on cloud/1.38 (#8477)
Fixes a bug where canvas functionality is lost if a multitype input
(like the native switch) is added to the graph in litegraph mode.

This issue is properly fixed by #8440, but this single revision is
easier and safer to backport

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8477-Revert-matchtype-slot-reactivity-on-cloud-1-38-2f86d73d365081279285e6d86ded9e43)
by [Unito](https://www.unito.io)
2026-01-29 21:47:12 -08:00
Comfy Org PR Bot
1631f22efb [backport cloud/1.38] feat: add category support for blueprints and protect global blueprints (#8466)
Backport of #8378 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8466-backport-cloud-1-38-feat-add-category-support-for-blueprints-and-protect-global-bluepr-2f86d73d3650814da4b4d8d773d2ffe5)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-29 19:15:47 -08:00
Comfy Org PR Bot
a5577a7f45 [backport cloud/1.38] Improve template search input performance issue (#8472)
Backport of #8343 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8472-backport-cloud-1-38-Improve-template-search-input-performance-issue-2f86d73d3650815ba8dfef1ea135c4a3)
by [Unito](https://www.unito.io)

Co-authored-by: Kelly Yang <124ykl@gmail.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-29 19:12:28 -08:00
Comfy Org PR Bot
519bd2f166 [backport cloud/1.38] fix: default image input for the template is displayed as empty on dropdown selection (#8456)
Backport of #8276 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8456-backport-cloud-1-38-fix-default-image-input-for-the-template-is-displayed-as-empty-on--2f86d73d365081098415f75295ce33eb)
by [Unito](https://www.unito.io)

Co-authored-by: Rizumu Ayaka <rizumu@ayaka.moe>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: github-actions <github-actions@github.com>
2026-01-29 16:59:25 -08:00
Comfy Org PR Bot
679fa1b354 [backport cloud/1.38] feat: add Chatterbox model support for Cloud asset browser (#8453)
Backport of #8418 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8453-backport-cloud-1-38-feat-add-Chatterbox-model-support-for-Cloud-asset-browser-2f86d73d36508158a791f6063485fd3c)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
2026-01-29 16:45:10 -08:00
Comfy Org PR Bot
fa2879b523 [backport cloud/1.38] Fix invalid keybind flash (#8452)
Backport of #8435 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8452-backport-cloud-1-38-Fix-invalid-keybind-flash-2f86d73d365081efbc2ec6ea01e37b80)
by [Unito](https://www.unito.io)

Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-29 16:34:53 -08:00
Comfy Org PR Bot
7175663efd [backport cloud/1.38] Fix Help Center display in linear mode (#8449)
Backport of #8438 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8449-backport-cloud-1-38-Fix-Help-Center-display-in-linear-mode-2f86d73d365081179c5be03a8d1a522d)
by [Unito](https://www.unito.io)

Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-29 16:23:03 -08:00
Comfy Org PR Bot
0367e33a76 [backport cloud/1.38] make new queue panel disabled by default (#8446)
Backport of #8444 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8446-backport-cloud-1-38-make-new-queue-panel-disabled-by-default-2f76d73d365081f3a0b3dd32ed39e03c)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-01-29 16:16:11 -08:00
Comfy Org PR Bot
b057f69501 [backport cloud/1.38] fix: dragging (e.g., when selecting text) in Markdown note causes node to drag (#8428)
Backport of #8413 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8428-backport-cloud-1-38-fix-dragging-e-g-when-selecting-text-in-Markdown-note-causes-n-2f76d73d36508132b067e6cee1122dc8)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-29 10:05:04 -08:00
Comfy Org PR Bot
6e5b72a685 [backport cloud/1.38] fix: use getAuthHeader in createCustomer to support API key auth (#8426)
Backport of #8408 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8426-backport-cloud-1-38-fix-use-getAuthHeader-in-createCustomer-to-support-API-key-auth-2f76d73d365081ad948ffed429f3714b)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-29 10:04:22 -08:00
Comfy Org PR Bot
ecb778dfe1 [backport cloud/1.38] Disable logs button in sidebar on cloud (#8430)
Backport of #8429 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-29 18:04:15 +00:00
Comfy Org PR Bot
e9dc3c0e41 [backport cloud/1.38] fix: add ResizeObserver to fix Preview3D initial render stretch (#8424)
Backport of #8351 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8424-backport-cloud-1-38-fix-add-ResizeObserver-to-fix-Preview3D-initial-render-stretch-2f76d73d365081a9974fe055b2a5894d)
by [Unito](https://www.unito.io)

Co-authored-by: Terry Jia <terryjia88@gmail.com>
2026-01-29 10:03:32 -08:00
Comfy Org PR Bot
fc9b78fce3 [backport cloud/1.38] Fix flake hidream test (#8421)
Backport of #8406 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8421-backport-cloud-1-38-Fix-flake-hidream-test-2f76d73d365081ceaff8cf1fd2d3f102)
by [Unito](https://www.unito.io)

Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-29 08:39:49 -08:00
Comfy Org PR Bot
0466f16b89 [backport cloud/1.38] [bugfix] Fix manager missing node tab with shared composable (#8411)
Backport of #8409 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8411-backport-cloud-1-38-bugfix-Fix-manager-missing-node-tab-with-shared-composable-2f76d73d365081b584b8f6134e624d38)
by [Unito](https://www.unito.io)

Co-authored-by: Jin Yi <jin12cc@gmail.com>
2026-01-29 00:05:20 -08:00
Comfy Org PR Bot
3060423e27 [backport cloud/1.38] fix: add null check in getCanvasCenter to prevent crash on asset insert (#8404)
Backport of #8399 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8404-backport-cloud-1-38-fix-add-null-check-in-getCanvasCenter-to-prevent-crash-on-asset-in-2f76d73d365081de80dac9abcc3c53b5)
by [Unito](https://www.unito.io)

Co-authored-by: Jin Yi <jin12cc@gmail.com>
2026-01-28 20:45:03 -08:00
Comfy Org PR Bot
dd0b2dc9cb [backport cloud/1.38] fix: increase Vue node resize handle size for better usability (#8395)
Backport of #8391 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8395-backport-cloud-1-38-fix-increase-Vue-node-resize-handle-size-for-better-usability-2f76d73d3650813eb26af9adf00abe2e)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
2026-01-28 19:50:09 -08:00
Comfy Org PR Bot
0c02573ff9 [backport cloud/1.38] fix: move WorkspaceAuthGate to LayoutDefault for proper re-login hand… (#8389)
Backport of #8381 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8389-backport-cloud-1-38-fix-move-WorkspaceAuthGate-to-LayoutDefault-for-proper-re-login-ha-2f76d73d365081d4ae00fc2cbbf1c362)
by [Unito](https://www.unito.io)

Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 18:41:33 -08:00
Comfy Org PR Bot
0f8925e95a [backport cloud/1.38] feat: Change the card description to the filename (#8380)
Backport of #8348 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8380-backport-cloud-1-38-feat-Change-the-card-description-to-the-filename-2f66d73d365081a989a3f793bb72605d)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-01-28 15:23:08 -08:00
Comfy Org PR Bot
c8aac69f6c [backport cloud/1.38] CI: Add formatting after generating locales. (#8362)
Backport of #8360 to `cloud/1.38`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8362-backport-cloud-1-38-CI-Add-formatting-after-generating-locales-2f66d73d365081c4837bc748aa0abcd5)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-27 22:42:16 -08:00
Christian Byrne
5c99f89e9d test: improve refreshRemoteConfig test quality (#8356)
Addresses review feedback from #8266:

- Use vi.stubGlobal for global fetch mock
- Extract mockSuccessResponse and mockErrorResponse helpers to reduce
duplication
- Add test verifying 500 responses preserve existing config (only
401/403 clear config)

Related: #8266

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8356-test-improve-refreshRemoteConfig-test-quality-2f66d73d365081f7b207c2fd2b8a8179)
by [Unito](https://www.unito.io)
2026-01-27 22:18:34 -07:00
Jin Yi
4cf55a7215 [refactor] Manager dialog design improvements (#8247)
## Summary
Refactored Manager dialog components for cleaner button rendering logic
and improved visibility.

## Changes
- **InfoPanelHeader**: Centralized button rendering logic (try update,
uninstall, install) instead of using slot overrides
- **PackTryUpdateButton**: Changed variant from `textonly` to `inverted`
for better visibility
- **InfoPanel**: Removed slot override and unused imports, simplified
component
- **ManagerDialog**: Design modifications for improved UX
- **PackCard/PackBanner**: Component refinements
- **useManagerDisplayPacks**: New composable for display pack management

## Review Focus
- Button visibility and styling with `inverted` variant
- Centralized button logic in InfoPanelHeader

## Before

[manager-before.webm](https://github.com/user-attachments/assets/4cef5f10-9cb2-4a31-a095-b170643e481d)

## After

[manager-after.webm](https://github.com/user-attachments/assets/9b693b32-59ca-4c88-b7e7-9a78aba19df7)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8247-refactor-Manager-dialog-design-improvements-2f06d73d365081bf9f07efa043caa378)
by [Unito](https://www.unito.io)
2026-01-28 14:11:46 +09:00
Christian Byrne
e8b088ce50 feat: add composable to determine if user is eligible for nightly survey(s) (#8189)
## Summary

Adds `useSurveyEligibility` composable that determines whether a user
should see a survey based on multiple criteria: nightly localhost build
only (`isNightly && !isCloud && !isDesktop`), configurable usage
threshold (default 3), 14-day global cooldown between any surveys,
once-per-feature-ever display, optional percentage-based sampling, and
user opt-out support. All state persists to localStorage. Includes
extensive unit tests covering all eligibility conditions.

See:

- https://github.com/Comfy-Org/ComfyUI_frontend/pull/8149
- https://github.com/Comfy-Org/ComfyUI_frontend/pull/8175

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8189-feat-add-composable-to-determine-if-user-is-eligible-for-nightly-survey-s-2ee6d73d365081f088f2fd76032cc60a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-27 21:31:00 -07:00
Simula_r
34fc28a39d Feat/workspaces 5 auth gate check (#8350)
## Summary

- Fix auth related race conditions with a new WorkspaceAuthGate in
App.vue
- De dup initialization calls 
- Add state machine to track state of refreshRemoteConfig
- Fix websocket not using new workspace jwt
- Misc improvments

## Changes

- **What**: Mainly WorkspaceAuthGate.vue
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8350-Feat-workspaces-5-auth-gate-check-2f66d73d365081b1a49afcd418fab3e7)
by [Unito](https://www.unito.io)
2026-01-27 20:28:44 -08:00
pythongosssss
d890e7568a Add asset deletion progress indicator (#7906)
## Summary

Currently the delay between user action and visual response is too long
and it looks like it hasn't worked.
This adds a visual indicator that the action is processing.

## Changes

- add loading indicator while asset is deleting

## Screenshots (if applicable)
(Artifically delayed deletion)


https://github.com/user-attachments/assets/a9a8b9fe-896d-4666-b643-ec8b990f6444

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7906-Add-asset-deletion-progress-indicator-2e26d73d365081ed82b8e770ba3d0615)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Jin Yi <jin12cc@gmail.com>
2026-01-27 21:21:50 -07:00
Benjamin Lu
2c54b0dab0 Revert/undo-788f5083-ef8657bb (#8353)
This reverts the addition of GTM for 1.38, as it was still present in
the built files.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8353-Revert-undo-788f5083-ef8657bb-2f66d73d365081818d43fcaab220a4ef)
by [Unito](https://www.unito.io)
2026-01-28 03:48:31 +00:00
Jin Yi
17bd5f527a feat: Add cancel button to active job card in grid view (#8264)
## Summary
Add a cancel (x) button overlay to active job cards in grid view,
matching the existing list view behavior.

## Changes
- **What**: Added hover-triggered cancel button to `ActiveJobCard.vue`
using the existing `useJobActions` composable
- Button appears on hover for jobs in cancellable states (pending,
initialization, running)

<img width="1710" height="1107" alt="스크린샷 2026-01-23 오후 5 11 04"
src="https://github.com/user-attachments/assets/31a6b6d1-46e7-49c4-a253-92260cb28514"
/>
<img width="1710" height="1107" alt="스크린샷 2026-01-23 오후 5 10 59"
src="https://github.com/user-attachments/assets/b559a81e-8e62-4858-b8e7-92de9caa2919"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8264-feat-Add-cancel-button-to-active-job-card-in-grid-view-2f16d73d3650817d83f0dd3b955759cb)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-01-28 12:25:57 +09:00
AustinMroz
89571c7a64 Prevent configuring a node to a placeholder nodeId (#8342)
Litegraph uses `-1 ` as a placeholder node id to indicate that a node
should be assigned a new node id when added to the graph. Under some
unknown circumstances it's possible for a node to have this placeholder
id saved in a workflow file.

When this occurs, the node is loaded and assigned a new id, but then
configured back to the placeholder id. This PR makes it so the newly
assigned id is kept instead.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8342-Prevent-configuring-a-node-to-a-placehodler-nodeId-2f56d73d365081ed8217e989187b15c8)
by [Unito](https://www.unito.io)
2026-01-27 19:01:06 -08:00
Alexander Brown
a7862fc4b7 feat: Asset Browser Placeholder update (#8349)
## Summary

Remind Creators that they can add models that they don't have available
yet

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8349-feat-Asset-Browser-Placeholder-update-2f66d73d3650815f83b4e7ce3587740c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-01-27 18:58:50 -08:00
AustinMroz
803062bccd Prevent partial copy of custom widgets when performing linked promotion on subgraphs (#6079)
The `toConcrete` call creates a restricted view of a widget that extends
from `BaseWidget`. A copy of the widget created by `createCopyForNode`
will also inherit this restricted view. This creates two problems
- Some widget properties (like `displayValue`) have been judged unsafe
and are explicitly blacklisted from being copied
- The widget now extends from `BaseWidget`. This results in the widget
being processed differently in some logic, such as `#processWidgetClick`
- Because `LegacyWidget` provides an implementation for `onClick`, the
presence of click handlers can not be used to determine which should be
used.

As a proposed, minimal workaround. Widgets which do not already extend
from BaseWidget are no longer cloned through `createCopyForNode`.

Because this PR involves side-stepping properties which have been
explicitly blacklisted. I'd recommend waiting to merge/backport until
after the release of 1.28.7

Resolves Kosinkadink/ComfyUI-VideoHelperSuite#569

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6079-Prevent-partial-copy-of-custom-widgets-when-performing-linked-promotion-on-subgraphs-28d6d73d36508198950efd401186ddef)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
2026-01-27 18:45:48 -08:00
Jin Yi
e3bad033ed [refactor] SearchBox and MultiSelect style improvements (#8328) 2026-01-28 02:11:45 +00:00
Johnpaul Chiwetelu
3b5d285fe2 Fix: Implement scope-aware filtering for template modal (#8335)
## Summary
- Fixes template filtering to be scope-aware, preventing empty results
when switching categories
- Filters now only show as selected when they exist in the current
category scope
- User selections are still persisted in localStorage for convenience

## Problem
When users selected filters (e.g., Image-specific filters) and switched
to a different category (e.g., Video), the persisted filters would cause
empty results because those filter values didn't exist in the new scope.

## Solution
- Modified `useTemplateFiltering` composable to track which filters are
"active" (applicable to current scope)
- Only active filters are shown as selected in the UI
- Only active filters are applied to the filtering logic
- All user selections are still persisted in localStorage
- When returning to a category, previously selected filters
automatically reactivate if applicable

## Test Plan
Tested manually in browser:
1. Navigate to Image category
2. Select filters like "Image" and "Image Edit" from Tasks dropdown
3. Switch to Video category - filters show as "0 selected" (Image/Image
Edit don't exist in Video)
4. Return to Image category - filters are automatically reselected (2
selected)
5. No empty results when switching between categories

## Changes
- `useTemplateFiltering.ts`: Added scope-aware filtering logic with
active/inactive filter distinction
- `WorkflowTemplateSelectorDialog.vue`: Pass navigation context and use
active filters for UI
- `useTemplateFiltering.test.ts`: Added comprehensive tests for
scope-aware behavior



https://github.com/user-attachments/assets/706ddabf-abad-4ff9-a378-6603d275d15a
2026-01-28 03:03:30 +01:00
Alexander Brown
aa5125cef6 Chore: Oxfmt formatting pass (#8341)
## Summary

Expanding the covered files to format. One-time formatting pass. To be
added to the `.git-blame-ignore-revs`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8341-Chore-Oxfmt-formatting-pass-2f56d73d365081f2988fcb7570f9a2a1)
by [Unito](https://www.unito.io)
2026-01-27 17:59:19 -08:00
Kelly Yang
f0eecdfdfa Refactor DropZone to use VueUse useDropZone (#8174)
## Summary

Refactor DropZone to use VueUse useDropZone. (#7971, #7734)

## Changes

- **What**: Replaced `@dragover`, `@dragleave`, and `@drop` bindings
with `useDropZone`.

## Review Focus

## Screenshots

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8174-Refactor-DropZone-to-use-VueUse-useDropZone-2ee6d73d365081ed9d31d68f7cf42263)
by [Unito](https://www.unito.io)
2026-01-27 20:25:58 -05:00
Zhiqi Yao
68f3f2f537 Fix Chinese translation "paste" misspelling (#8316)
## Summary

Fixed the `站贴` misspelling. The original translation is a common
misspelling using Pinyin IME because they are pronounced the same in
Chinese.

## Changes

- Change translation: `站贴` to `粘贴`

## Review Focus

Check the fact that `粘贴` is correct in Chinese. If you're not a Chinese
speaker, copy `粘贴` to Google Translate, and it should be `paste`
exactly.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8316-Fix-Chinese-translation-paste-misspelling-2f46d73d3650814884e3e4adf8edeb5d)
by [Unito](https://www.unito.io)
2026-01-27 17:43:31 -07:00
Alexander Brown
bcb4d6e403 fix: await needsLogin (#8340)
## Summary

Add additional protection for bootstrap order issues.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8340-fix-await-needsLogin-2f56d73d365081c9b3c6d5a091c1eb8d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-27 14:04:35 -08:00
Alexander Brown
50461d401a Add a placeholder logo. (#8321)
## Summary

We could also color it.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8321-Add-a-placeholder-logo-2f46d73d3650819496a2f46d805afc4e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-27 13:22:35 -08:00
Benjamin Lu
ef8657bb5d fix: include items array in purchase dataLayer (#8339)
Include GA4-style `items` payload for subscription purchase events so
GTM receives the full item array.

So, to align with GA4's ecommerce standards, we changed it to an items
array:
https://developers.google.com/analytics/devguides/collection/ga4/item-scoped-ecommerce
2026-01-27 13:04:50 -08:00
Alexander Brown
14369c08a3 refactor: parallelize bootstrap and simplify lifecycle with VueUse (#8307)
## Summary

Refactors bootstrap and lifecycle management to parallelize
initialization, use Vue best practices, and fix a logout state bug.

## Changes

### Bootstrap Store (`bootstrapStore.ts`)
- Extract early bootstrap logic into a dedicated store using
`useAsyncState`
- Parallelize settings, i18n, and workflow sync loading (previously
sequential)
- Handle multi-user login scenarios by deferring settings/workflows
until authenticated

### GraphCanvas Refactoring
- Move non-DOM composables (`useGlobalLitegraph`, `useCopy`, `usePaste`,
etc.) to script setup level for earlier initialization
- Move `watch` and `whenever` declarations outside `onMounted` (Vue best
practice)
- Use `until()` from VueUse to await bootstrap store readiness instead
of direct async calls

### GraphView Simplification
- Replace manual `addEventListener`/`removeEventListener` with
`useEventListener`
- Replace `setInterval` with `useIntervalFn` for automatic cleanup
- Move core command registration to script setup level

### Bug Fix
Using `router.push()` for logout caused `isSettingsReady` to persist as
`true`, making new users inherit the previous user's cached settings.
Reverted to `window.location.reload()` with TODOs for future store reset
implementation.

## Testing

- Verified login/logout cycle clears settings correctly
- Verified bootstrap sequence completes without errors

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-27 12:50:13 -08:00
Benjamin Lu
788f50834c feat: add cloud gtm injection (#8311)
## Summary

Add GTM injection for cloud distribution builds and push SPA page view +
signup events.

## Changes

- **What**: Inject GTM script into head-prepend and noscript iframe into
body-prepend for cloud builds
- **What**: Push `page_view` to `dataLayer` on cloud route changes
(page_location + page_title)
- **What**: Push `sign_up` to `dataLayer` after successful account
creation (email/google/github)
- **Dependencies**: None

## Review Focus

- Placement order for head-prepend/body-prepend and cloud-only gating
- Route-change page_view payload shape
- Signup event emission only for new users

## Screenshots (if applicable)

<img width="1512" height="860" alt="Screenshot 2026-01-26 at 11 38
11 AM"
src="https://github.com/user-attachments/assets/03fb61db-5ca4-4432-9704-bbdcc4c6c1b7"
/>

<img width="1512" height="862" alt="Screenshot 2026-01-26 at 11 38
26 AM"
src="https://github.com/user-attachments/assets/6e46c855-a552-4e52-9800-17898a512d4d"
/>
2026-01-27 12:44:15 -08:00
Alexander Brown
75fd4f0e67 feat: Make the text for the value control a clickable label (#8334)
## Summary

More clickable!

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8334-feat-Make-the-text-for-the-value-control-a-clickable-label-2f56d73d365081e79886eddeec03458e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-01-27 20:16:06 +00:00
Johnpaul Chiwetelu
3946d7b5ff Road to no explicit any part 8 group 5 (#8329)
## Summary
- Add `createMockLLink` and `createMockLinks` factory functions to
handle hybrid Map/Record types
- Replace `as any` assertions with type-safe factory functions in
minimap tests
- Implement proper Pinia store mocking using `vi.hoisted()` pattern
- Remove unused `createMockSubgraph` export (shadowed by local
implementations)

## Test plan
- [x] All minimap tests pass (29 tests)
- [x] `pnpm typecheck` passes
- [x] `pnpm lint` passes
- [x] `pnpm knip` passes

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8329-Road-to-no-explicit-any-part-8-group-5-2f56d73d365081218882de81d5526220)
by [Unito](https://www.unito.io)

---------

Co-authored-by: AustinMroz <austin@comfy.org>
2026-01-27 19:25:15 +01:00
Alexander Brown
440e25e232 fix(test): Mobile Settings (#8332)
## Summary

Bigger mask.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8332-fix-test-Mobile-Settings-2f56d73d3650813b8e39ea5d77e39c18)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-27 00:21:15 -08:00
Comfy Org PR Bot
7ad43c689c 1.38.12 (#8313)
Patch version increment to 1.38.12

**Base branch:** `main`

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-27 04:44:39 +00:00
Alexander Brown
c8785c32dd feat: add Hugging Face model source support (#8330)
Add support for Hugging Face as a model source in the Model Info Panel.

- Display HF logo for Hugging Face sources
- Extract source URL from `repo_url` metadata field

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8330-feat-add-Hugging-Face-model-source-support-2f56d73d3650816b8a01d903411ee3a1)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 20:37:18 -08:00
Christian Byrne
02c20786b8 perf: remove autoplay from assets cards (#8325)
## Summary

It's rare that someone has enabled autoplay -- but when they have,
scrolling through a large grid of videos and trying to play them all
onload can cause extreme lag. We don't need the asset cards to be
autoplaying, so the fix here is fine for perf and UX.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8325-perf-remove-autoplay-from-assets-cards-2f56d73d3650814e8103f01b1f21b2e2)
by [Unito](https://www.unito.io)
2026-01-26 20:03:45 -07:00
Rizumu Ayaka
e5e51c8e00 fix: image selection modal Inputs Outputs filtering is not working (#8272)
filteredItems only updates during search, and does not update when the
filter changes. Trigger a re-search when items change through the
updateKey prop chain.
2026-01-26 19:40:33 -07:00
Rizumu Ayaka
88fba25617 fix: group recompute in item selection for properties panel (#8274)
Group first click displays an empty node list in Right Side Panel. The
reason is that when clicking the group, only `processSelect()` is
called, and `recomputeInsideNodes()` is not called.

related https://github.com/Comfy-Org/ComfyUI_frontend/pull/8275

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8274-fix-group-recompute-in-item-selection-for-properties-panel-2f16d73d3650812ca394dc9de3d6855b)
by [Unito](https://www.unito.io)
2026-01-26 19:36:37 -07:00
Rizumu Ayaka
01362d5ff1 fix: recomputeInsideNodes does not support nested group processing (#8275)
related https://github.com/Comfy-Org/ComfyUI_frontend/pull/8274

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8275-fix-recomputeInsideNodes-does-not-support-nested-group-processing-2f16d73d3650815e9b44dbd182f8dd74)
by [Unito](https://www.unito.io)
2026-01-26 19:34:49 -07:00
Rizumu Ayaka
4370979bc4 fix: add tooltips for various settings in the right side panel (#8278)
<img width="1264" height="730" alt="CleanShot 2026-01-23 at 21 27 45@2x"
src="https://github.com/user-attachments/assets/9834b673-8467-44c0-b487-d9dd9e4475d0"
/>



┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8278-fix-add-tooltips-for-various-settings-in-the-right-side-panel-2f16d73d365081e2816cfdf24fa7687f)
by [Unito](https://www.unito.io)
2026-01-26 19:31:18 -07:00
Simula_r
5eda23b7aa fix: workspace icon flash and credits showing 0 while workspace is in… (#8323)
## Summary

- Fix: flash of wrong workspace icon (replaced with loader)
- Fix: personal workspace showing 0 credits

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8323-fix-workspace-icon-flash-and-credits-showing-0-while-workspace-is-in-2f46d73d36508159b52fec3fa0c17e35)
by [Unito](https://www.unito.io)
2026-01-26 16:33:00 -08:00
Alexander Brown
6a5b5c968f refactor: replace vi.doMock with vi.mock + vi.hoisted (#8319)
Replace `vi.doMock` with `vi.mock` + `vi.hoisted` pattern for cleaner
test mocking.

- Add ESLint rule to prevent future `doMock` usage
- Refactor `versionUtil.test.ts` and `firebaseAuthStore.test.ts`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8319-refactor-replace-vi-doMock-with-vi-mock-vi-hoisted-2f46d73d365081ae9fccf2fa7471a75b)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-01-26 14:08:54 -08:00
Johnpaul Chiwetelu
b551064a6a Road to No Explicit Any Part 8 (Group4) (#8314)
## Summary

Removes all `as unknown as Type` double-cast patterns from group 4 files
as part of the ongoing TypeScript cleanup effort.

## Changes

### Type Safety Improvements
- Replaced `as unknown as Type` with `as Partial<Type> as Type` for
valid mock objects
- Added proper null/undefined validation in `Subgraph.addInput()` and
`Subgraph.addOutput()`
- Updated test expectations to match new validation behavior

### Files Modified (17 files)
**Core Implementation:**
- `src/lib/litegraph/src/LGraph.ts` - Added input validation for
subgraph add methods
- `src/lib/litegraph/src/interfaces.ts` - Cleaned up type definitions
- `src/lib/litegraph/src/subgraph/ExecutableNodeDTO.ts` - Improved type
safety
- `src/platform/telemetry/types.ts` - Better type definitions
- `src/platform/telemetry/utils/surveyNormalization.ts` - Type cleanup

**Test Files:**
- `src/lib/litegraph/src/subgraph/SubgraphEdgeCases.test.ts` - Updated
to expect validation errors
- `src/lib/litegraph/src/subgraph/SubgraphMemory.test.ts` - Proper mock
typing
- `src/lib/litegraph/src/subgraph/SubgraphNode.test.ts` - Type
improvements
- `src/lib/litegraph/src/subgraph/SubgraphNode.titleButton.test.ts` -
Mock type fixes
- `src/lib/litegraph/src/subgraph/SubgraphSlotVisualFeedback.test.ts` -
Proper typing
- `src/lib/litegraph/src/subgraph/SubgraphWidgetPromotion.test.ts` -
Type cleanup
- `src/lib/litegraph/src/utils/textUtils.test.ts` - Mock improvements
- `src/lib/litegraph/src/widgets/ComboWidget.test.ts` - Type safety
updates
- `src/platform/assets/services/assetService.test.ts` - Type
improvements
- `src/platform/settings/composables/useSettingSearch.test.ts` - Mock
type fixes
- `src/platform/settings/settingStore.test.ts` - Type cleanup
- `src/platform/telemetry/utils/__tests__/surveyNormalization.test.ts` -
Type improvements

## Testing
-  All modified test files pass
-  TypeScript compilation passes
-  Linting passes

## Related
Part of the TypeScript cleanup effort. Follows patterns from groups 1-3.

Previous PRs:
- Group 1: (merged)
- Group 2: (merged)
- Group 3: #8304

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8314-Road-to-No-Explicit-Any-Part-8-Group4-2f46d73d36508172a9d4e53b2c5cbadd)
by [Unito](https://www.unito.io)
2026-01-26 19:30:54 +00:00
Johnpaul Chiwetelu
5769f96f55 fix: resolve no-misused-spread lint warnings in test files (#8318)
## Summary

Replace spread operators with Object.assign() to fix 3 no-misused-spread
lint warnings in test utilities and test files.

## Changes

- **What**: Replaced spread operators with Object.assign() in
createMockFileList and mock node creation functions to avoid spreading
arrays into objects and class instances that could lose prototypes.
Simplified BypassButton.test.ts by removing redundant type annotations.
- **Breaking**: None

## Review Focus

Type safety is preserved without using weak TypeScript patterns (no
`any`, `as unknown as`, or unnecessary casts).

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8318-fix-resolve-no-misused-spread-lint-warnings-in-test-files-2f46d73d365081aca3f6cf208556d492)
by [Unito](https://www.unito.io)
2026-01-26 19:26:35 +01:00
AustinMroz
3d41d555ff Frontend code for custom number nodes (#7768)
Allows creation of Int and Float widgets with configurable, min, max,
step, and precision.
This PR has been fairly heavily reworked. Options are no longer exposed
as widgets, but set as properties on the node.

Since the changes no longer modify the sizing or serialization of the
node, backend changes are no longer required and the extended
functionality has been added directly onto the existing PrimitiveFloat
and PrimitiveInt nodes.

There's intent to expose these configuration parameters on the new
properties panel, but this PR can be merged as is.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7768-Frontend-code-for-custom-number-nodes-2d66d73d365081879541cbda7db3c24f)
by [Unito](https://www.unito.io)
2026-01-26 10:24:53 -08:00
Christian Byrne
d3e664b2dd Feat: Persist all unsaved workflow tabs (#6050)
## Summary

- Keep all drafts in localStorage, mirroring the logic from VSCode.

- Fix a bug where newly created blank workflow tabs would incorrectly
restore as defaultGraph instead of blankGraph after page refresh.

Resolves https://github.com/Comfy-Org/desktop/issues/910, Resolves
https://github.com/Comfy-Org/ComfyUI_frontend/issues/4057, Fixes
https://github.com/Comfy-Org/ComfyUI_frontend/issues/3665

## Changes

### What
- Fix `restoreWorkflowTabsState` to parse and pass workflow data from
drafts when recreating temporary workflows
- Add error handling for invalid draft data with fallback to default
workflow
- Fix E2E test `should not serialize color adjustments in workflow` to
wait for workflow persistence before assertions
- Add proper validation for workflow nodes array in test assertions

### Breaking
- None

### Dependencies
- No new dependencies added

## Review Focus

1. **Workflow restoration**: Verify that blank workflows correctly
restore as blankGraph after page refresh
2. **Error handling**: Check that invalid draft data gracefully falls
back to default workflow
3. **Test coverage**: Ensure E2E test correctly waits for workflow
persistence before checking node properties
4. **Edge cases**: Test with multiple tabs, switching between tabs, and
rapid refresh scenarios

---------

Co-authored-by: Yourz <crazilou@vip.qq.com>
2026-01-26 09:35:38 -08:00
Johnpaul Chiwetelu
29220f6562 Road to No explicit any Part 8 (Group 3): Improve type safety in Group 3 test mocks (#8304)
## Summary

- Eliminated all `as unknown as` type assertions from Group 3 test files
- Created reusable factory functions in `litegraphTestUtils.ts` for
better type safety
- Improved test mock composition using `Partial` types with single `as`
casts
- Fixed LGraphNode tests to use proper API methods instead of direct
property assignment

## Changes by Category

### New Factory Functions in `litegraphTestUtils.ts`

- `createMockLGraphNodeWithArrayBoundingRect()` - Creates LGraphNode
with proper boundingRect for position tests
- `createMockFileList()` - Creates mock FileList with proper structure
including `item()` method

### Test File Improvements

**Composables:**
- `useLoad3dDrag.test.ts` - Used `createMockFileList` factory
- `useLoad3dViewer.test.ts` - Created local `MockSceneManager` interface
with proper typing

**LiteGraph Tests:**
- `LGraphNode.test.ts` - Replaced direct `boundingRect` assignments with
`updateArea()` calls
- `LinkConnector.test.ts` - Improved mock composition with proper
Partial types
- `ToOutputRenderLink.test.ts` - Added `MockEvents` interface for
type-safe event mocking
- Updated integration and core tests to use new factory functions

**Extension Tests:**
- `contextMenuFilter.test.ts` - Updated menu factories to accept
`(IContextMenuValue | null)[]`

## Type Safety Improvements

- Zero `as unknown as` instances (was: multiple instances across 17
files)
- All mocks use proper `Partial<T>` composition with single `as T` casts
- Improved IntelliSense and type checking in test files
- Centralized mock creation reduces duplication and improves
maintainability

## Test Plan

-  All TypeScript type checks pass
-  ESLint passes with no new errors  
-  Pre-commit hooks (format, lint, typecheck) all pass
-  Knip unused export check passes
-  No behavioral changes to actual tests (only type improvements)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8304-Road-to-No-explicit-any-Improve-type-safety-in-Group-3-test-mocks-2f36d73d365081ab841de96e5f01306d)
by [Unito](https://www.unito.io)
2026-01-26 18:13:18 +01:00
Comfy Org PR Bot
ba5380395d 1.38.11 (#8285)
Patch version increment to 1.38.11

**Base branch:** `main`

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-25 01:49:24 -08:00
Alexander Brown
702c917e57 feat: add getAssetFilename util with fallback chain (#8309)
## Summary

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8309-feat-add-getAssetFilename-util-with-fallback-chain-2f36d73d36508141be81ecc52c0a2858)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-24 17:50:00 -08:00
Alexander Brown
7b0830a4ca fix: fallback to asset metadata/name when filename missing (#8302)
## Summary

Fix model node creation failing when `user_metadata.filename` is missing
by falling back to `asset.metadata.filename` or `asset.name`.

## Changes

- Add fallback chain for filename: `userMetadata.filename ||
validAsset.metadata?.filename || validAsset.name`

## Testing

Manual testing with assets that have filename in different metadata
locations.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8302-fix-fallback-to-asset-metadata-name-when-filename-missing-2f36d73d365081478299e2f2c1abde81)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-25 00:27:42 +00:00
Simula_r
4771565486 Workspaces 4 members invites (#8245)
## Summary

  Add team workspace member management and invite system.

## Changes

- Add members panel with role management (owner/admin/member) and member
removal
- Add invite system with email invites, pending invite display, and
revoke functionality
   - Add invite URL loading for accepting invites
  - Add subscription panel updates for member management
  - Add i18n translations for member and invite features

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8245-Workspaces-4-members-invites-2f06d73d36508176b2caf852a1505c4a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
2026-01-24 15:52:40 -08:00
Benjamin Lu
aa6f9b7009 fix: persist assets sidebar view mode (#8299) 2026-01-24 15:17:34 -08:00
Alexander Brown
133427b08e Fix: Background Image fix for dark theme loading change. (#8292)
## Summary

The variable whose name implied it was just an image URL bundled other
background pieces.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8292-Fix-Background-Image-fix-for-dark-theme-loading-change-2f26d73d36508177ae7bc24ae3cb027b)
by [Unito](https://www.unito.io)
2026-01-24 15:03:51 -08:00
Alexander Brown
e8022f9dee Style: Dark mode body on load alternative (#8287)
## Summary

Alternative to https://github.com/Comfy-Org/ComfyUI_frontend/pull/8077

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8287-Style-Dark-mode-body-on-load-alternative-2f26d73d365081fb8231f167e75beb83)
by [Unito](https://www.unito.io)
2026-01-23 22:23:10 -08:00
AustinMroz
3bfd62b9fc Linear: progressbar, tooltips, and output fixes (#8250)
- Fixes only the first output being displayed in linear mode after the
jobs migration
- Fixes selected output no longer scrolling into view in history
- Adds a progress bar indicator on running job
<img width="113" height="102" alt="image"
src="https://github.com/user-attachments/assets/ca684dbe-12c8-44aa-98f0-2985c0159156"
/>
- Moves linear toggle button to v-tooltip
- Fixes placeholder sometimes continuing to display after a new output.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8250-Linear-progressbar-tooltips-and-output-fixes-2f06d73d365081ca9fa3ebf0e2516487)
by [Unito](https://www.unito.io)
2026-01-23 21:08:31 -08:00
Alexander Brown
15655ddb76 Updates: More Modal Modification (#8256)
Refactors modal dialog layouts for improved flexibility and consistency.

**Changes:**
- Add dedicated slot for left panel header title with dynamic
content/icons
- Consolidate side panel rendering within `BaseModalLayout`
- Remove redundant `PanelHeader` and `RightSidePanel` components
- Apply `select-none` to text elements to prevent accidental selection

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-23 20:41:35 -08:00
729_GM
e5583fe955 docs(locale zh): confused with the original EmptyImageLatent, two identical options are displayed on the interface but they aren't the same. (#8273)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8273-docs-locale-zh-confused-with-the-original-EmptyImageLatent-two-identical-options-are-d-2f16d73d3650811b9a01dcfd058c1348)
by [Unito](https://www.unito.io)
2026-01-24 05:11:50 +01:00
Johnpaul Chiwetelu
b1d8bf0b13 refactor: eliminate unsafe type assertions from Group 2 test files (#8258)
## Summary
Improved type safety in test files by eliminating unsafe type assertions
and adopting official testing patterns. Reduced unsafe `as unknown as`
type assertions and eliminated all `null!` assertions.

## Changes
- **Adopted @pinia/testing patterns**
- Replaced manual Pinia store mocking with `createTestingPinia()` in
`useSelectionState.test.ts`
  - Eliminated ~120 lines of mock boilerplate
- Created `createMockSettingStore()` helper to replace duplicated store
mocks in `useCoreCommands.test.ts`

- **Eliminated unsafe null assertions**
- Created explicit `MockMaskEditorStore` interface with proper nullable
types in `useCanvasTools.test.ts`
- Replaced `null!` initializations with `null` and used `!` at point of
use or `?.` for optional chaining

- **Made partial mock intent explicit**
- Updated test utilities in `litegraphTestUtils.ts` to use explicit
`Partial<T>` typing
- Changed cast pattern from `as T` to `as Partial<T> as T` to show
incomplete mock intent
- Applied to `createMockLGraphNode()`, `createMockPositionable()`, and
`createMockLGraphGroup()`

- **Created centralized mock utilities** in
`src/utils/__tests__/litegraphTestUtils.ts`
- `createMockLGraphNode()`, `createMockPositionable()`,
`createMockLGraphGroup()`, `createMockSubgraphNode()`
  - Updated 8+ test files to use centralized utilities
- Used union types `Partial<T> | Record<string, unknown>` for flexible
mock creation

## Results
-  0 typecheck errors
-  0 lint errors  
-  All tests passing in modified files
-  Eliminated all `null!` assertions
-  Reduced unsafe double-cast patterns significantly

## Files Modified (18)
- `src/components/graph/SelectionToolbox.test.ts`
-
`src/components/graph/selectionToolbox/{BypassButton,ColorPickerButton,ExecuteButton}.test.ts`
- `src/components/sidebar/tabs/queue/ResultGallery.test.ts`
- `src/composables/canvas/useSelectedLiteGraphItems.test.ts`
- `src/composables/graph/{useGraphHierarchy,useSelectionState}.test.ts`
-
`src/composables/maskeditor/{useCanvasHistory,useCanvasManager,useCanvasTools,useCanvasTransform}.test.ts`
- `src/composables/node/{useNodePricing,useWatchWidget}.test.ts`
- `src/composables/{useBrowserTabTitle,useCoreCommands}.test.ts`
- `src/utils/__tests__/litegraphTestUtils.ts`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8258-refactor-eliminate-unsafe-type-assertions-from-Group-2-test-files-2f16d73d365081549c65fd546cc7c765)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: AustinMroz <austin@comfy.org>
Co-authored-by: Christian Byrne <cbyrne@comfy.org>
Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
2026-01-24 05:10:35 +01:00
Rizumu Ayaka
6b6b467e68 feat: implement fuzzy search for widgets and nodes using Fuse in Right Side Panel (#8043)
related
https://github.com/Comfy-Org/ComfyUI_frontend/pull/7812#discussion_r2685117810

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8043-feat-implement-fuzzy-search-for-widgets-and-nodes-using-Fuse-in-Right-Side-Panel-2e86d73d365081d7869cfa1956dfc0ad)
by [Unito](https://www.unito.io)
2026-01-23 20:43:09 -07:00
AustinMroz
ef2d34c560 Add 3d control buttons to linear mode (#8178)
Adds control buttons to the top left of the 3d preview in linear mode.
<img width="460" alt="image"
src="https://github.com/user-attachments/assets/35a83b9c-65af-46c3-a910-be5ad30c428e"
/>


This was deprioritized because I forgot the secret to magically
unwrapping a set of refs (wrap them in another ref).

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8178-Add-3d-control-buttons-to-linear-mode-2ee6d73d3650816ab1a8e73ace1bdbc7)
by [Unito](https://www.unito.io)
2026-01-23 20:24:48 -07:00
Rizumu Ayaka
1b1356951e feat: add settings option to always show advanced widgets on all nodes (#8244)
Solved issue:
Currently, the display status of advanced widgets can only be set
individually for each node, but users would like to have a global switch
to always display all advanced widgets.

I also adjusted some related code to solve the issue of code
duplication.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8244-feat-add-settings-option-to-always-show-advanced-widgets-on-all-nodes-2f06d73d365081358023efa3e1ff3094)
by [Unito](https://www.unito.io)
2026-01-23 19:47:51 -07:00
Rizumu Ayaka
3e9a390c25 fix: letter sorting in image dropdown (#8277)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8277-fix-letter-sorting-in-image-dropdown-2f16d73d3650818ea82dff944d345ec7)
by [Unito](https://www.unito.io)
2026-01-23 19:30:20 -07:00
Benjamin Lu
7c61dadaf2 Replace QPO with opening assets tab (#8260)
Route the queue progress button to toggle the Assets sidebar when QPO V2
is enabled.

This effectively "removes" the QPO for users with QPOV2 enabled.


https://github.com/user-attachments/assets/fa76482d-2dc7-4c28-8810-c15c338c51e4

---------

Co-authored-by: Benjamin Lu <ben@Mac.lan>
2026-01-23 18:52:06 -07:00
Alexander Brown
7246ec7f1c Templates: Search speed (#8286)
## Summary

...

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8286-Templates-Search-speed-2f26d73d365081dab3d1cccd7878a1de)
by [Unito](https://www.unito.io)
2026-01-23 16:57:55 -08:00
Christian Byrne
2d0980cb1c fix: use authenticated API for remote config polling (#8266)
## Summary
- Fixes remote config polling to use authenticated API
- Consolidates `loadRemoteConfig` into `refreshRemoteConfig` with auth
control
- Adds unit tests for both auth modes

## Problem
The cloud extension's polling interval was using unauthenticated
`fetch`, causing it to receive only default feature flags instead of
user-specific configurations.

**Root cause:**
1. Bootstrap called `loadRemoteConfig()` (raw `fetch`, no auth) -
correct, auth not initialized yet
2. Extension watch called `refreshRemoteConfig()` (`api.fetchApi`, with
auth) - correct
3. Extension interval called `loadRemoteConfig()` (raw `fetch`, no auth)
- **bug**

## Solution
- Consolidate into single `refreshRemoteConfig()` with optional
`useAuth` parameter (defaults to `true`)
- Bootstrap: `refreshRemoteConfig({ useAuth: false })`
- Polling: `refreshRemoteConfig()` (authenticated by default)

## Test Plan
- Unit tests verify both auth modes
- `pnpm typecheck`, `pnpm lint`, `pnpm test:unit` all pass

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8266-fix-use-authenticated-API-for-remote-config-polling-2f16d73d3650817ea7b0e3a7e3ccf12a)
by [Unito](https://www.unito.io)
2026-01-23 15:41:21 -08:00
Terry Jia
d9e1122677 fix: replace vite preload error reload with error logging (#8261)
## Summary
The reload approach didn't fully work because CSS and other preload
errors emit different error types. Log errors for Sentry tracking
instead, to be solved on the backend by serving chunks from past
deployments.

fix https://github.com/Comfy-Org/ComfyUI_frontend/issues/8153

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8261-fix-replace-vite-preload-error-reload-with-error-logging-2f16d73d365081e3b309f5470412506a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-23 15:16:13 -08:00
Comfy Org PR Bot
69b57eaba5 1.38.10 (#8254)
Patch version increment to 1.38.10

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8254-1-38-10-2f16d73d36508183a716cc1ad72e2819)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-23 15:00:19 -08:00
Jin Yi
f647c8f9ee [bugfix] Fix inconsistent menu icon sizes in ComfyMenuButton (#8268)
## Summary
Replace MDI font icons with Tailwind Iconify (Lucide) icons for Settings
and Manage Extensions menu items to fix size inconsistency with Browse
Template icon.

## Changes
- **What**: MDI font icons (`mdi mdi-cog-outline`, `mdi
mdi-puzzle-outline`) rendered at 14px (`text-sm` font-size), while the
Tailwind Iconify icon (`icon-[comfy--template]`) rendered at ~16.8px due
to `scale: 1.2` in the Tailwind plugin config. Replaced with
`icon-[lucide--settings]` and `icon-[lucide--puzzle]` so all icons use
the same rendering pipeline.
2026-01-23 15:47:50 +09:00
AustinMroz
7952eb477e Add telemetry for entering linear mode (#8263)
Standard disclaimer: Telemetry only applies on cloud builds

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8263-Add-telemetry-for-entering-linear-mode-2f16d73d3650819ea53efeeb562ea095)
by [Unito](https://www.unito.io)
2026-01-22 22:28:41 -07:00
Jin Yi
df85c4d463 [refactor] Move ActiveJobCard to platform/assets and add ActiveMediaAssetCard story (#8242) 2026-01-23 13:49:33 +09:00
Benjamin Lu
6bbea48d8e feat: active jobs context menu (#8216)
Add a right-click context menu to the active jobs button that clears the
queue and matches the Queue Progress modal styling.

Per
[design](https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3407-41345&m=dev)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8216-feat-active-jobs-context-menu-2ef6d73d365081e68386cf0f7c3c23f2)
by [Unito](https://www.unito.io)
2026-01-22 18:46:21 -08:00
Christian Byrne
219d86db2c feat: Add search_aliases to node search (#8223)
Adds `search_aliases` to Fuse.js search keys, enabling users to find
nodes by alternative names.



https://github.com/user-attachments/assets/6bde3e5d-29c7-4cb0-b102-e600a92c7019



## Changes
- Add `search_aliases` to Fuse.js keys in `nodeSearchService.ts`
- Add type definition for `search_aliases` field in `nodeDefSchema.ts`

**Depends on:** Comfy-Org/ComfyUI#12010

## Related PRs
- **Backend:** Comfy-Org/ComfyUI#12010,
https://github.com/Comfy-Org/ComfyUI/pull/12035/
- **Adding aliases**:
  - https://github.com/Comfy-Org/ComfyUI/pull/12016
  - https://github.com/Comfy-Org/ComfyUI/pull/12017
  - https://github.com/Comfy-Org/ComfyUI/pull/12018
  - https://github.com/Comfy-Org/ComfyUI/pull/12019
- **Docs:** https://github.com/Comfy-Org/docs/pull/729

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8223-feat-Add-search_aliases-to-node-search-2ef6d73d365081d89bcccffb33659a88)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-01-22 19:06:05 -07:00
Johnpaul Chiwetelu
941cd2b4a5 refactor: improve TypeScript patterns in test files (Group 1/8) (#8253)
## Summary
Improves type safety in test files by replacing unsafe type patterns
with proper TypeScript idioms.

## Changes
- Define typed `TestWindow` interface extending `Window` for Playwright
tests with custom properties
- Use `Partial<HTMLElement>` with single type assertion for DOM element
mocks
- Remove redundant type imports
- Fix `console.log` → `console.warn` in test fixture

## Files Changed
16 test files across browser_tests, packages, and src/components

## Test Plan
-  `pnpm typecheck` passes
-  No new `any` types introduced
-  All pre-commit hooks pass

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8253-refactor-improve-TypeScript-patterns-in-test-files-Group-1-8-2f16d73d365081548f9ece7bcf0525ee)
by [Unito](https://www.unito.io)

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-23 02:35:09 +01:00
AustinMroz
9efcbe682f Further number widget fixes (#8251)
- The slider indicator is now only rounded at the ends and doesn't
display outside the widget at small values
- Prevents a bug where scrubbing would result in a 1/10 chance of
causing text selection after a completed scrub.

| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/94d1a232-4667-4f99-8fce-93567a10b2f3"
/> | <img width="360" alt="after"
src="https://github.com/user-attachments/assets/66a44109-906f-4c1e-809e-118c9c96eb4a"
/>|

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8251-Further-number-widget-fixes-2f06d73d3650811f9548ded527ca16ae)
by [Unito](https://www.unito.io)
2026-01-22 16:29:17 -08:00
Alexander Brown
4b1a30e330 Updates: Model Management (#8248)
## Summary

Model management improvements: refactored tag API, enhanced UX for
trigger phrases and editing.

## Changes

### API Refactor
- Add `addAssetTags` (POST) and `removeAssetTags` (DELETE) endpoints in
assetService
- `updateAssetTags` now computes diff and calls remove/add serially
- Add `TagsOperationResult` schema; cache syncs with server response

### UX Improvements
- **Trigger phrases**: click to copy individual phrases, copy-all button
in header
- **Display name**: show edit icon on hover instead of relying on
double-click
- **Model type**: show plain text when immutable instead of disabled
select
- **Tags input**: only show edit icon on hover
- **Field labels**: updated styling to use muted foreground color
- **Optimistic update** for model type selection

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-01-23 00:10:54 +00:00
Johnpaul Chiwetelu
524c7e9b95 feat: enable feedback button on nightly releases (#8220)
## Summary

Enables the feedback button on nightly releases to collect user feedback
and distinguish it from stable releases in Zendesk.

## Changes

- Add distribution tracking to feedback URL (cloud/nightly/stable)
- Export `getDistribution()` and `ZENDESK_FIELDS` from support config
for reuse
- Enable feedback button for both cloud and nightly builds
- Track distribution in Zendesk as: `ccloud`, `oss-nightly`, or `oss`
- Fix type signatures for `normalizeIndustry`/`normalizeUseCase` to
accept `unknown`

## Requirements

- [ ] Support team needs to add `oss-nightly` as a valid value for the
distribution field in Zendesk

## Test plan

- [ ] Build and run nightly version, verify feedback button appears
- [ ] Click feedback button, verify Zendesk form opens with correct
distribution parameter
- [ ] Verify cloud builds still show feedback button as before
- [ ] Verify stable OSS builds don't show feedback button

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8220-feat-enable-feedback-button-on-nightly-releases-2ef6d73d3650816db81ef970919770a4)
by [Unito](https://www.unito.io)
2026-01-22 16:12:25 -07:00
Simula_r
a08ccb55c1 Workspaces 3 create a workspace (#8221)
## Summary

Add workspace creation and management (create, edit, delete, leave,
switch workspaces).

  Follow-up PR will add invite and membership flow.

  ## Changes

  - Workspace CRUD dialogs
  - Workspace switcher popover in topbar
  - Workspace settings panel
  - Subscription panel for workspace context
  

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8221-Workspaces-3-create-a-workspace-2ef6d73d36508155975ffa6e315971ec)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 14:54:41 -07:00
Alexander Piskun
5c142275ad Move price badges to python nodes (#7816)
## Summary

Backend part: https://github.com/Comfy-Org/ComfyUI/pull/11582

- Move API node pricing definitions from hardcoded frontend functions to
backend-defined JSONata expressions
- Add `price_badge` field to node definition schema containing JSONata
expression and dependency declarations
- Implement async JSONata evaluation with signature-based caching for
efficient reactive updates
- Show one decimal in credit badges when meaningful (e.g., 1.5 credits
instead of 2 credits)

## Screenshots (if applicable)

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

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7816-Move-price-badges-to-python-nodes-2da6d73d365081ec815ef61f7e3c65f7)
by [Unito](https://www.unito.io)
2026-01-22 09:17:07 -08:00
AustinMroz
4a5e7c8bcb Further dynamic input fixes (#8026)
- Fix deserialization of matchtype inputs spawned by autogrow.
- Rotate multitype slot indicators to align with design changes.
- Fix several instance of incorrect group matching
- MatchType reactively updates input type in vue
- Support the "hollow circle" optional input indicator in vue
- Custom combo sends index of selection to backend

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8026-Further-dynamic-input-fixes-2e76d73d3650819680fef327a94f4294)
by [Unito](https://www.unito.io)
2026-01-22 00:02:49 -08:00
Benjamin Lu
df93277802 refactor: use orderBy for queue list sorting (#8228)
Use es-toolkit orderBy for queue list sorting.

The queue overlay list already sorts by create time, but the
implementation used Array.sort with a custom comparator and mutated the
array in place. Switch to es-toolkit's orderBy to make the sort intent
explicit, avoid mutation, and align with the utility set we already
depend on. Sorting keys and direction remain the same, so behavior is
unchanged.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8228-fix-use-orderBy-for-queue-list-sorting-2f06d73d365081e791fff7d2212537f8)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-21 20:21:39 -08:00
Comfy Org PR Bot
db16cfbb2b 1.38.9 (#8226)
Patch version increment to 1.38.9

**Base branch:** `main`

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8226-1-38-9-2f06d73d3650817d9770f965c3497200)
by [Unito](https://www.unito.io)

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-21 20:11:03 -08:00
Benjamin Lu
92357445e4 feat: show active jobs label in top menu (#8169)
Replace the top-menu queue history icon with a localized “N active”
label so active jobs are visible at a glance.

Requested as part of the new
[designs](https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3381-6181&m=dev).

I checked all failing snapshots and they are all expected (1 flaky).

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8169-feat-show-active-jobs-label-in-top-menu-2ee6d73d3650812cbf0cda389395c563)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-21 20:45:29 -07:00
Alexander Brown
93e7a4f9f9 feat(assets): add ModelInfoPanel for asset browser right panel (#8090)
## Summary

Adds an editable Model Info Panel to show and modify asset details in
the asset browser.

## Changes

- Add `ModelInfoPanel` component with editable display name,
description, model type, base models, and tags
- Add `updateAssetMetadata` action in `assetsStore` with optimistic
cache updates
- Add shadcn-vue `Select` components with design system styling
- Add utility functions in `assetMetadataUtils` for extracting model
metadata
- Convert `BaseModalLayout` right panel state to `defineModel` pattern
- Add slide-in animation and collapse button for right panel
- Add `class` prop to `PropertiesAccordionItem` for custom styling
- Fix keyboard handling: Escape in TagsInput/TextArea doesn't close
parent modal

## Testing

- Unit tests for `ModelInfoPanel` component
- Unit tests for `assetMetadataUtils` functions

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-01-21 19:43:56 -08:00
Johnpaul Chiwetelu
8261e1d187 feat: add preview version badge for nightly builds (#8222)
## Summary

Adds a "Preview Version" badge to the topbar on nightly builds to help
users identify when they're using an unreleased version and encourage
feedback.

## Changes

- Add `nightly.badge` i18n translations (label and tooltip)
- Create `nightlyBadges.ts` extension with info variant badge
- Load nightly badges extension when `isNightly` is true
- Badge tooltip encourages users to provide feedback via the feedback
button

## Test plan

- [ ] Build and run nightly version, verify "NIGHTLY | Preview Version"
badge appears in topbar
- [ ] Hover over badge, verify tooltip shows: "You are using a nightly
version of ComfyUI. Please use the feedback button to share your
thoughts about these features."
- [ ] Verify stable OSS builds don't show the badge
- [ ] Verify cloud builds don't show the nightly badge

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8222-feat-add-preview-version-badge-for-nightly-builds-2ef6d73d36508102aa0dfc22ef14c9c1)
by [Unito](https://www.unito.io)
2026-01-22 03:32:52 +01:00
Jin Yi
e4d2bc2b59 [feat] Add active jobs display to grid view (#8209)
## Summary
Show active jobs in grid view matching the list view behavior, with
refactored component structure.

## Changes
- **ActiveJobCard**: New component for grid view job display with
progress bar
- **AssetsSidebarGridView**: Extracted grid view logic from
AssetsSidebarTab (matching ListView pattern)
- **Progress styling**: Use `useProgressBarBackground` composable for
consistent progress bar styling
- **Assets header**: Add "Generated/Imported assets" header in grid view
2026-01-22 11:02:28 +09:00
Alexander Brown
482159957e feat: implement progressive pagination for Asset Browser model assets (#8212)
## Summary

Implements progressive pagination for model assets - returns the first
batch immediately while loading remaining batches in the background.

## Changes

### Store (`assetsStore.ts`)
- Adds `ModelPaginationState` tracking (assets Map, offset, hasMore,
loading, error)
- `updateModelsForKey()` returns first batch, then calls
`loadRemainingBatches()` to fetch the rest
- Accessor functions `getAssets(key)`, `isModelLoading(key)` replace
direct Map access

### API (`assetService.ts`)
- Adds `PaginationOptions` interface (`{ limit?, offset? }`)

### Components
- `AssetBrowserModal.vue` uses new accessor API

### Tests
- Updated mocks for new accessor pattern

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8212-feat-implement-progressive-pagination-for-Asset-Browser-model-assets-2ef6d73d36508157af04d1264780997e)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-21 17:59:08 -08:00
Alexander Brown
f08b0f44ef fix: Mark comfy-api-plugin as build-time only (#8224)
## Summary

Marks the `comfy-api-plugin` Vite plugin as build-time only by adding
`apply: 'build'`.

This prevents the plugin's transform from running during development
(`vite dev`), improving dev server startup time and avoiding unnecessary
processing when the plugin's output is not needed in development mode.

Also updates `build/tsconfig.json` to use `moduleResolution: "bundler"`
which is the recommended setting for Vite projects.

## Changes

- **build/plugins/comfyAPIPlugin.ts**: Add `apply: 'build'` to restrict
plugin to production builds
- **build/tsconfig.json**: Update `moduleResolution` from `"node"` to
`"bundler"`

## Testing

- `pnpm typecheck` passes
- `pnpm build` produces correct output

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8224-fix-Mark-comfy-api-plugin-as-build-time-only-2ef6d73d36508145a48ae849087fbad7)
by [Unito](https://www.unito.io)
2026-01-21 16:38:18 -08:00
Alexander Brown
f1d1747582 feat: add session download tracking to assetDownloadStore (#8213)
## Summary

Add session download tracking to track which assets were downloaded
during the current session. This enables UI features like:
- Badge count on "Imported" nav showing newly downloaded assets
- Visual indicator on asset cards for recently downloaded items

## Changes

- Add `acknowledged` flag to `AssetDownload` interface
- Add `unacknowledgedDownloads` computed for filtering
- Add `sessionDownloadCount` computed for badge display
- Add `isDownloadedThisSession(identifier)` to check individual assets
- Add `acknowledgeDownload(identifier)` to mark assets as seen

## Testing

- 6 new unit tests covering all session tracking functionality
- Run: `pnpm test:unit -- src/stores/assetDownloadStore.test.ts`

## Related

- Part of Asset Browser improvements (#8090)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8213-feat-add-session-download-tracking-to-assetDownloadStore-2ef6d73d365081538045e8544d26bafa)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-21 16:32:30 -08:00
Benjamin Lu
d12c6d7814 fix: sort queue jobs by create time (#8225)
Sort queue overlay ordering by create_time instead of priority so queued
jobs keep their order when completions arrive.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8225-fix-sort-queue-jobs-by-create-time-2ef6d73d3650815a8a81ec9d0b23a4e6)
by [Unito](https://www.unito.io)
2026-01-21 23:13:27 +00:00
Alexander Brown
2db246f494 refactor: restructure BaseModalLayout from flexbox to CSS Grid (#8211)
## Summary

Refactors `BaseModalLayout` from a flexbox-based layout to CSS Grid,
enabling smoother panel transitions and improved layout control.

## Changes

### Layout Restructure

- **Flexbox → CSS Grid**: Replaced nested flexbox with a 3-column CSS
Grid (`nav | main | aside`)
- **Smooth panel transitions**: Panel show/hide now animates via
`grid-template-columns` instead of Vue `<Transition>` with `translateX`
- **Removed transition CSS**: Deleted `.slide-panel-*` and `.fade-*`
transition styles (no longer needed with grid approach)

### Right Panel Improvements

- **Dedicated header**: Added header with close button, right panel
toggle, and customizable title slot (`rightPanelHeaderTitle`,
`rightPanelHeaderActions`)
- **New prop**: Added `rightPanelTitle` prop for simple text title in
right panel header

### UX & Accessibility

- **ESC key handling**: Pressing Escape closes the right panel (if open)
before closing the dialog
- **Accessibility**: Added `aria-label` attributes to all panel toggle
and close buttons
- **i18n**: Added translation keys: `showLeftPanel`, `hideLeftPanel`,
`showRightPanel`, `hideRightPanel`, `closeDialog`

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-21 13:20:39 -08:00
Simula_r
66e6f24980 feat: add workspace session, auth, and store infrastructure (#8194)
## Summary
- Add `teamWorkspaceStore` Pinia store for workspace state management
(workspaces, members, invites, current workspace)
- Add `workspaceApi` client for workspace CRUD, member management, and
invite operations
- Update `useWorkspaceSwitch` composable for workspace switching logic
- Update `useSessionCookie` for workspace-aware sessions
- Update `firebaseAuthStore` for workspace aware auth
- Use `workspaceAuthStore` for workspace auth flow

## Test plan
- [x] 59 unit tests passing (50 store tests + 9 switch tests)
- [x] Typecheck passing
- [x] Lint passing
- [x] Knip passing

Note: This PR depends on the `team_workspaces_enabled` feature flag
being available (already in main).

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

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8194-feat-add-workspace-session-auth-and-store-infrastructure-2ef6d73d3650814984afe8ee7ba0a209)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 13:18:47 -07:00
Alexander Brown
fcf2e0e639 feat: add badge support to NavItem component (#8207)
## Summary

Adds optional badge support to the `NavItem` component and `NavItemData`
interface, enabling navigation items in the left sidebar of the Asset
Browser Modal to display counts or status indicators.

## Changes

- **`src/types/navTypes.ts`**: Added optional `badge?: string | number`
property to `NavItemData` interface
- **`src/components/widget/nav/NavItem.vue`**: Added `StatusBadge`
rendering when `badge` prop is provided
- **`src/components/widget/panel/LeftSidePanel.vue`**: Wired `badge`
prop from `NavItemData` to `NavItem` for both grouped and ungrouped
items

## Usage

```ts
const navItem: NavItemData = {
  id: 'assets',
  label: 'Assets',
  icon: 'pi pi-folder',
  badge: 5  // Optional - displays count badge
}
```

## Related

- Builds on #8170 which added queue badge functionality

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8207-feat-add-badge-support-to-NavItem-component-2ef6d73d365081669f86fe2fc618e87f)
by [Unito](https://www.unito.io)
2026-01-21 11:48:22 -08:00
Alexander Brown
7b701ad07b fix: Consistent keydown handling for EditableText and TagsInput escape key (#8204)
## Summary

This PR improves keyboard event handling consistency and fixes an issue
where pressing Escape in nested input components would unintentionally
close parent modals/dialogs.

## Changes

### Keyboard Event Fixes

**TagsInput Escape Key Handling**
- Added `@keydown.escape.stop` handler to `TagsInputInput.vue` to
prevent Escape from bubbling up and closing parent modals
- The handler blurs the input and exits editing mode without propagating
the event

**EditableText keyup → keydown Migration**
- Changed `@keyup.enter` to `@keydown.enter` and `@keyup.escape` to
`@keydown.escape`
- Using `keydown` is more consistent with how other UI frameworks handle
these events and provides more responsive feedback
- Updated corresponding unit tests to use `keydown` triggers

### Why keydown over keyup?

- `keydown` fires immediately when the key is pressed, providing faster
perceived response
- Better consistency with browser/OS conventions for action triggers
- Prevents default behaviors (like form submission) more reliably when
needed
- Aligns with other keyboard handlers in the codebase

## Testing

- Updated `EditableText.test.ts` to use `keydown` events
- Updated `NodeHeader.test.ts` to use `keydown.enter`
- Manual testing: Escape in TagsInput no longer closes parent modal

## Checklist

- [x] Unit tests updated
- [x] Keyboard event handlers consistent
- [x] No breaking changes to component API

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8204-fix-Consistent-keydown-handling-for-EditableText-and-TagsInput-escape-key-2ef6d73d365081f0ac6bed8bcae57657)
by [Unito](https://www.unito.io)
2026-01-21 09:16:13 -08:00
AustinMroz
9a6ead37cb Fix doubled player on VHS LoadAudio in vue (#8206)
In vue mode, the VHS Load Audio (Upload) node had 2 audio previews. This
occurred because the native AudioPreview widget was being applied to any
combo widget with the name `audio`. This native preview does not support
the advanced preview functions VHS provides like seeking to specific
start time, trimming to a target duration, or converting from formats
the browser may not support.

This is fixed through a fairly involved cleanup to instead display the
litegraph AudioUI widget as an AudioPreview widget when in vue mode.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8206-Fix-doubled-player-on-VHS-LoadAudio-in-vue-2ef6d73d365081ce8907dca2706214a1)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-01-21 00:14:37 -08:00
Alexander Brown
7a1a2c1abb feat(ui): add shadcn-vue Select components (#8205)
## Summary

Adds shadcn-vue Select components built on Reka UI primitives with
design system styling.

## Changes

**New Components** (`src/components/ui/select/`):
- `Select.vue` - Root wrapper using `SelectRoot` from Reka UI
- `SelectTrigger.vue` - Styled trigger with chevron icon
- `SelectContent.vue` - Dropdown content with scroll buttons, z-index
3000 for PrimeVue dialog compatibility
- `SelectItem.vue` - Individual option with check icon
- `SelectGroup.vue`, `SelectLabel.vue`, `SelectSeparator.vue` - Grouping
support
- `SelectScrollUpButton.vue`, `SelectScrollDownButton.vue` - Overflow
navigation
- `SelectValue.vue` - Placeholder/value display

**Styling**:
- Uses design tokens (`bg-secondary-background`,
`text-muted-foreground`, `border-border-default`)
- Iconify icons via `icon-[lucide--*]` classes
- Smooth transitions and focus states

**Documentation**:
- Comprehensive Storybook stories covering all variants
- `AGENTS.md` with component creation guidelines

## Testing

- [x] Storybook stories work correctly
- [x] Components build without errors

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8205-feat-ui-add-shadcn-vue-Select-components-2ef6d73d365081fd994ddb1123c063e7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-20 23:17:53 -08:00
Alexander Brown
e503482c6f feat: add maxColumns prop to VirtualGrid for responsive column capping (#8210)
## Summary

Add `maxColumns` prop to VirtualGrid for responsive column capping.

## Changes

- **VirtualGrid**: Add `maxColumns` prop to cap grid columns; refactor
inline styles to Tailwind classes; extract spacer height computation to
helper function
- **AssetGrid**: Use `useBreakpoints` to set responsive `maxColumns`
(1-5 based on Tailwind breakpoints)

## Review Focus

- `maxColumns` behavior when `Infinity` vs finite: does
`gridTemplateColumns` override work correctly?
- Tailwind scrollbar classes replacing scoped CSS
2026-01-20 23:17:06 -08:00
Christian Byrne
c7b5f47055 feat(canvas): hide widgets marked advanced unless node.showAdvanced is true (#8147)
Hides widgets marked with `options.advanced = true` on the Vue Node
canvas unless `node.showAdvanced` is true.

## Changes
- Updates `NodeWidgets.vue` template to check `widget.options.advanced`
combined with `nodeData.showAdvanced`
- Updates `gridTemplateRows` computed to exclude hidden advanced widgets
- Adds `showAdvanced` to `VueNodeData` interface in
`useGraphNodeManager.ts`

## Related
- Backend PR that adds `advanced` flag: comfyanonymous/ComfyUI#11939
- Toggle button PR: feat/advanced-widgets-toggle-button

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8147-feat-canvas-hide-widgets-marked-advanced-unless-node-showAdvanced-is-true-2ec6d73d36508179931ce78a6ffd6b0a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-01-20 23:02:16 -07:00
Jin Yi
d9e5b07c73 [bugfix] Clear queue button now properly removes initializing jobs from UI (#8203)
## Summary

- Fix: Initializing jobs now properly disappear from UI when cancelled
or cleared
- Add `clearInitializationByPromptIds` batch function for optimized Set
operations
- Handle Cloud vs local environment correctly (use `api.deleteItem` for
Cloud, `api.interrupt` for local)

## Problem

When clicking 'Clear queue' button or X button on initializing jobs, the
jobs remained visible in both AssetsSidebarListView and JobQueue
components until page refresh.

## Root Cause

1. `initializingPromptIds` in `executionStore` was not being cleared
when jobs were cancelled/deleted
2. Cloud environment requires `api.deleteItem()` instead of
`api.interrupt()` for cancellation

## Changes

- `src/stores/executionStore.ts`: Export `clearInitializationByPromptId`
and add batch `clearInitializationByPromptIds` function
- `src/composables/queue/useJobMenu.ts`: Add Cloud branch handling and
initialization cleanup
- `src/components/queue/QueueProgressOverlay.vue`: Fix `onCancelItem()`,
`cancelQueuedWorkflows()`, `interruptAll()`
- `src/components/sidebar/tabs/AssetsSidebarTab.vue`: Add initialization
cleanup to `handleClearQueue()`


[screen-capture.webm](https://github.com/user-attachments/assets/0bf911c2-d8f4-427c-96e0-4784e8fe0f08)


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

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8203-bugfix-Clear-queue-button-now-properly-removes-initializing-jobs-from-UI-2ef6d73d36508162a55bd84ad39ab49c)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 14:15:58 +09:00
Alexander Brown
73cfbd9833 feat(StatusBadge): add dot mode with CVA variants (#8202)
## Summary

Refactors StatusBadge to use CVA (class-variance-authority) for variant
management and adds a new `dot` mode for label-free status indicators.

## Changes

- **CVA variants** (`statusBadge.variants.ts`): Extracts styling logic
into a CVA config with:
  - `severity`: `default` | `secondary` | `warn` | `danger` | `contrast`
- `variant`: `label` (text badge) | `dot` (small indicator) | `circle`
(numeric badge)
- **StatusBadge.vue**: Simplified component using CVA; auto-selects
`dot` variant when no label provided
- **Storybook stories**: Comprehensive coverage of all severities and
variants

## Breaking Changes

- `label` prop is now optional (was required)
- `label` accepts `string | number` (was `string` only)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8202-feat-StatusBadge-add-dot-mode-with-CVA-variants-2ef6d73d36508120beedd04b2c277227)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-20 20:59:45 -08:00
668 changed files with 36347 additions and 15836 deletions

View File

@@ -3,12 +3,15 @@
## Task: Add English translations for all new localized strings
### Step 1: Identify new translation keys
Find all translation keys that were added in the current branch's changes. These keys appear as arguments to translation functions: `t()`, `st()`, `$t()`, or similar i18n functions.
### Step 2: Add translations to English locale file
For each new translation key found, add the corresponding English text to the file `src/locales/en/main.json`.
### Key-to-JSON mapping rules:
- Translation keys use dot notation to represent nested JSON structure
- Convert dot notation to nested JSON objects when adding to the locale file
- Example: The key `g.user.name` maps to:
@@ -23,6 +26,7 @@ For each new translation key found, add the corresponding English text to the fi
```
### Important notes:
1. **Only modify the English locale file** (`src/locales/en/main.json`)
2. **Do not modify other locale files** - translations for other languages are automatically generated by the `i18n.yaml` workflow
3. **Exception for manual translations**: Only add translations to non-English locale files if:
@@ -30,6 +34,7 @@ For each new translation key found, add the corresponding English text to the fi
- The automated translation would likely be incorrect due to technical terminology or context-specific meaning
### Example workflow:
1. If you added `t('settings.advanced.enable')` in a Vue component
2. Add to `src/locales/en/main.json`:
```json

View File

@@ -15,6 +15,7 @@ To post inline comments, you will use the GitHub API via the `gh` command. Here'
- Run: `gh pr view $PR_NUMBER --json commits --jq '.commits[-1].oid'` to get the latest commit SHA
2. For each issue you find, post an inline comment using this exact command structure (as a single line):
```
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/OWNER/REPO/pulls/$PR_NUMBER/comments -f body="YOUR_COMMENT_BODY" -f commit_id="COMMIT_SHA" -f path="FILE_PATH" -F line=LINE_NUMBER -f side="RIGHT"
```
@@ -22,13 +23,15 @@ To post inline comments, you will use the GitHub API via the `gh` command. Here'
3. Format your comment body using actual newlines in the command. Use a heredoc or construct the body with proper line breaks:
```
COMMENT_BODY="**[category] severity Priority**
```
**Issue**: Brief description of the problem
**Context**: Why this matters
**Suggestion**: How to fix it"
```
Then use: `-f body="$COMMENT_BODY"`
```
Then use: `-f body="$COMMENT_BODY"`
## Phase 1: Environment Setup and PR Context
@@ -58,10 +61,12 @@ This is critical for better file inspection:
1. Get PR metadata: `gh pr view $PR_NUMBER --json files,title,body,additions,deletions,baseRefName,headRefName > pr_info.json`
2. Extract branch names from pr_info.json using jq
3. Fetch and checkout the PR branch:
```
git fetch origin "pull/$PR_NUMBER/head:pr-$PR_NUMBER"
git checkout "pr-$PR_NUMBER"
```
```
git fetch origin "pull/$PR_NUMBER/head:pr-$PR_NUMBER"
git checkout "pr-$PR_NUMBER"
```
### Step 1.4: Get Changed Files and Diffs
@@ -100,9 +105,9 @@ Intelligently load only relevant knowledge:
1. Use GitHub API to discover available knowledge folders: `https://api.github.com/repos/Comfy-Org/comfy-claude-prompt-library/contents/.claude/knowledge`
2. For each knowledge folder, check if it's relevant by searching for the folder name in:
- Changed file paths
- PR title
- PR body
- Changed file paths
- PR title
- PR body
3. If relevant, download all files from that knowledge folder
### Step 2.4: Load Validation Rules
@@ -193,12 +198,14 @@ Consider:
For each issue found, create a concise inline comment with this structure:
```
**[category] severity Priority**
**Issue**: Brief description of the problem
**Context**: Why this matters
**Suggestion**: How to fix it
```
````
Categories: architecture/security/performance/quality
Severities: critical/high/medium/low
@@ -214,7 +221,7 @@ For EACH issue:
```bash
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/OWNER/REPO/pulls/$PR_NUMBER/comments -f body="$COMMENT_BODY" -f commit_id="COMMIT_SHA" -f path="FILE_PATH" -F line=LINE_NUMBER -f side="RIGHT"
```
````
CRITICAL: The entire command must be on one line. Use actual values, not placeholders.
@@ -223,12 +230,14 @@ CRITICAL: The entire command must be on one line. Use actual values, not placeho
Here's an example of how to review a file with a security issue:
1. First, get the repository info:
```bash
gh repo view --json owner,name
# Output: {"owner":{"login":"Comfy-Org"},"name":"ComfyUI_frontend"}
```
2. Get the commit SHA:
```bash
gh pr view $PR_NUMBER --json commits --jq '.commits[-1].oid'
# Output: abc123def456
@@ -240,14 +249,17 @@ Here's an example of how to review a file with a security issue:
```bash
# First, create the comment body with proper newlines
COMMENT_BODY="**[security] critical Priority**
```
**Issue**: SQL injection vulnerability - user input directly concatenated into query
**Context**: Allows attackers to execute arbitrary SQL commands
**Suggestion**: Use parameterized queries or prepared statements"
# Then post the comment (as a single line)
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/Comfy-Org/ComfyUI_frontend/pulls/$PR_NUMBER/comments -f body="$COMMENT_BODY" -f commit_id="abc123def456" -f path="src/db/queries.js" -F line=42 -f side="RIGHT"
```
# Then post the comment (as a single line)
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/Comfy-Org/ComfyUI_frontend/pulls/$PR_NUMBER/comments -f body="$COMMENT_BODY" -f commit_id="abc123def456" -f path="src/db/queries.js" -F line=42 -f side="RIGHT"
```
Repeat this process for every issue you find in the PR.
@@ -282,9 +294,9 @@ Analyze the PR to determine its type:
1. Extract PR title and body from pr_info.json
2. Count files, additions, and deletions
3. Determine PR type:
- Feature: Check for tests, documentation, backward compatibility
- Bug fix: Verify root cause addressed, includes regression tests
- Refactor: Ensure behavior preservation, tests still pass
- Feature: Check for tests, documentation, backward compatibility
- Bug fix: Verify root cause addressed, includes regression tests
- Refactor: Ensure behavior preservation, tests still pass
## Phase 7: Generate Comprehensive Summary
@@ -292,16 +304,17 @@ After ALL inline comments are posted, create a summary:
1. Calculate total issues by category and severity
2. Use `gh pr review $PR_NUMBER --comment` to post a summary with:
- Review disclaimer
- Issue distribution (counts by severity)
- Category breakdown
- Key findings for each category
- Positive observations
- References to guidelines
- Next steps
- Review disclaimer
- Issue distribution (counts by severity)
- Category breakdown
- Key findings for each category
- Positive observations
- References to guidelines
- Next steps
Include in the summary:
```
# Comprehensive PR Review
This review is generated by Claude. It may not always be accurate, as with human reviewers. If you believe that any of the comments are invalid or incorrect, please state why for each. For others, please implement the changes in one way or another.
@@ -312,12 +325,14 @@ This review is generated by Claude. It may not always be accurate, as with human
**Impact**: [X] additions, [Y] deletions across [Z] files
### Issue Distribution
- Critical: [CRITICAL_COUNT]
- High: [HIGH_COUNT]
- Medium: [MEDIUM_COUNT]
- Low: [LOW_COUNT]
### Category Breakdown
- Architecture: [ARCHITECTURE_ISSUES] issues
- Security: [SECURITY_ISSUES] issues
- Performance: [PERFORMANCE_ISSUES] issues
@@ -326,33 +341,42 @@ This review is generated by Claude. It may not always be accurate, as with human
## Key Findings
### Architecture & Design
[Detailed architectural analysis based on repository patterns]
### Security Considerations
[Security implications beyond basic vulnerabilities]
### Performance Impact
[Performance analysis including bundle size, render impact]
### Integration Points
[How this affects other systems, extensions, etc.]
## Positive Observations
[What was done well, good patterns followed]
## References
- [Repository Architecture Guide](https://github.com/Comfy-Org/comfy-claude-prompt-library/blob/master/project-summaries-for-agents/ComfyUI_frontend/REPOSITORY_GUIDE.md)
- [Frontend Standards](https://github.com/Comfy-Org/comfy-claude-prompt-library/blob/master/.claude/commands/validation/frontend-code-standards.md)
- [Security Guidelines](https://github.com/Comfy-Org/comfy-claude-prompt-library/blob/master/.claude/commands/validation/security-audit.md)
## Next Steps
1. Address critical issues before merge
2. Consider architectural feedback for long-term maintainability
3. Add tests for uncovered scenarios
4. Update documentation if needed
---
*This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review.*
_This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review._
```
## Important Guidelines
@@ -375,4 +399,5 @@ This is a COMPREHENSIVE review, not a linting pass. Provide the same quality fee
5. Phase 6: Consider PR type for additional checks
6. Phase 7: Post comprehensive summary ONLY after all inline comments
Remember: Individual inline comments for each issue, then one final summary. Never batch issues into a single comment.
Remember: Individual inline comments for each issue, then one final summary. Never batch issues into a single comment.
```

View File

@@ -7,8 +7,9 @@ Create a frontend release with version type: $ARGUMENTS
Expected format: Version increment type and optional description
Examples:
- `patch` - Bug fixes only
- `minor` - New features, backward compatible
- `minor` - New features, backward compatible
- `major` - Breaking changes
- `prerelease` - Alpha/beta/rc releases
- `patch "Critical security fixes"` - With custom description
@@ -21,8 +22,9 @@ If no arguments provided, the command will always perform prerelease if the curr
## Prerequisites
Before starting, ensure:
- You have push access to the repository
- GitHub CLI (`gh`) is authenticated
- GitHub CLI (`gh`) is authenticated
- You're on a clean main branch working tree
- All intended changes are merged to main
- You understand the scope of changes being released
@@ -30,6 +32,7 @@ Before starting, ensure:
## Critical Checks Before Starting
### 1. Check Current Version Status
```bash
# Get current version and check if it's a pre-release
CURRENT_VERSION=$(node -p "require('./package.json').version")
@@ -40,6 +43,7 @@ fi
```
### 2. Find Last Stable Release
```bash
# Get last stable release tag (no pre-release suffix)
LAST_STABLE=$(git tag -l "v*" | grep -v "\-" | sort -V | tail -1)
@@ -49,6 +53,7 @@ echo "Last stable release: $LAST_STABLE"
## Configuration Options
**Environment Variables:**
- `RELEASE_SKIP_SECURITY_SCAN=true` - Skip security audit
- `RELEASE_AUTO_APPROVE=true` - Skip some confirmation prompts
- `RELEASE_DRY_RUN=true` - Simulate release without executing
@@ -129,13 +134,14 @@ echo "Last stable release: $LAST_STABLE"
### Step 4: Analyze Dependency Updates
1. **Use pnpm's built-in dependency analysis:**
```bash
# 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")
@@ -147,22 +153,23 @@ echo "Last stable release: $LAST_STABLE"
```
2. **Check for significant dependency updates:**
```bash
# Extract all dependency changes for major version bumps
OTHER_DEP_CHANGES=""
# Compare major dependency versions (you can extend this list)
MAJOR_DEPS=("vue" "vite" "@vitejs/plugin-vue" "typescript" "pinia")
for dep in "${MAJOR_DEPS[@]}"; do
PREV_VER=$(echo "$PREV_PACKAGE_JSON" | grep -o "\"$dep\": \"[^\"]*\"" | grep -o '[0-9][^"]*' | head -1 || echo "")
CURR_VER=$(echo "$CURRENT_PACKAGE_JSON" | grep -o "\"$dep\": \"[^\"]*\"" | grep -o '[0-9][^"]*' | head -1 || echo "")
if [ "$PREV_VER" != "$CURR_VER" ] && [ -n "$PREV_VER" ] && [ -n "$CURR_VER" ]; then
# Check if it's a major version change
PREV_MAJOR=$(echo "$PREV_VER" | cut -d. -f1 | sed 's/[^0-9]//g')
CURR_MAJOR=$(echo "$CURR_VER" | cut -d. -f1 | sed 's/[^0-9]//g')
if [ "$PREV_MAJOR" != "$CURR_MAJOR" ]; then
OTHER_DEP_CHANGES="${OTHER_DEP_CHANGES}\n- **${dep}**: ${PREV_VER} → ${CURR_VER} (Major version change)"
fi
@@ -173,11 +180,12 @@ echo "Last stable release: $LAST_STABLE"
### Step 5: Generate GTM Feature Summary
1. **Collect PR data for analysis:**
```bash
# Get list of PR numbers from commits
PR_NUMBERS=$(git log ${BASE_TAG}..HEAD --oneline --no-merges --first-parent | \
grep -oE "#[0-9]+" | tr -d '#' | sort -u)
# Save PR data for each PR
echo "[" > prs-${NEW_VERSION}.json
first=true
@@ -189,16 +197,17 @@ echo "Last stable release: $LAST_STABLE"
```
2. **Analyze for GTM-worthy features:**
```
<task>
Review these PRs to identify features worthy of marketing attention.
A feature is GTM-worthy if it meets ALL of these criteria:
- Introduces a NEW capability users didn't have before (not just improvements)
- Would be a compelling reason for users to upgrade to this version
- Can be demonstrated visually or has clear before/after comparison
- Affects a significant portion of the user base
NOT GTM-worthy:
- Bug fixes (even important ones)
- Minor UI tweaks or color changes
@@ -206,19 +215,20 @@ echo "Last stable release: $LAST_STABLE"
- Internal refactoring
- Small convenience features
- Features that only improve existing functionality marginally
For each GTM-worthy feature, note:
- PR number, title, and author
- Media links from the PR description
- One compelling sentence on why users should care
If there are no GTM-worthy features, just say "No marketing-worthy features in this release."
</task>
PR data: [contents of prs-${NEW_VERSION}.json]
```
3. **Generate GTM notification using this EXACT Slack-compatible format:**
```bash
# Only create file if GTM-worthy features exist:
if [ "$GTM_FEATURES_FOUND" = "true" ]; then
@@ -252,8 +262,8 @@ echo "Last stable release: $LAST_STABLE"
```
**CRITICAL Formatting Requirements:**
- Use single asterisk (*) for emphasis, NOT double (**)
- Use underscore (_) for italics
- Use single asterisk (\*) for emphasis, NOT double (\*\*)
- Use underscore (\_) for italics
- Use 4 spaces for indentation (not tabs)
- Convert author names to @username format (e.g., "John Smith" → "@john")
- No section headers (#), no code language specifications
@@ -263,6 +273,7 @@ echo "Last stable release: $LAST_STABLE"
### Step 6: Version Preview
**Version Preview:**
- Current: `${CURRENT_VERSION}`
- Proposed: Show exact version number based on analysis:
- Major version if breaking changes detected
@@ -326,6 +337,7 @@ echo "Last stable release: $LAST_STABLE"
done
```
3. Create standardized release notes using this exact template:
```bash
cat > release-notes-${NEW_VERSION}.md << 'EOF'
## ⚠️ Breaking Changes
@@ -359,6 +371,7 @@ echo "Last stable release: $LAST_STABLE"
**Full Changelog**: https://github.com/Comfy-Org/ComfyUI_frontend/compare/${BASE_TAG}...v${NEW_VERSION}
EOF
```
4. **Parse commits and populate template:**
- Group commits by conventional commit type (feat:, fix:, chore:, etc.)
- Extract PR numbers from commit messages
@@ -375,6 +388,7 @@ echo "Last stable release: $LAST_STABLE"
### Step 10: Create Version Bump PR
**For standard version bumps (patch/minor/major):**
```bash
# Trigger the workflow
gh workflow run version-bump.yaml -f version_type=${VERSION_TYPE}
@@ -384,7 +398,9 @@ echo "Workflow triggered. Waiting for PR creation..."
```
**For releasing a stable version:**
1. Must manually create branch and update version:
```bash
git checkout -b version-bump-${NEW_VERSION}
# Edit package.json to remove pre-release suffix
@@ -394,23 +410,25 @@ echo "Workflow triggered. Waiting for PR creation..."
```
2. Wait for PR creation (if using workflow) or create manually:
```bash
# For workflow-created PRs - wait and find it
sleep 30
# Look for PR from comfy-pr-bot (not github-actions)
PR_NUMBER=$(gh pr list --author comfy-pr-bot --limit 1 --json number --jq '.[0].number')
# Verify we got the PR
if [ -z "$PR_NUMBER" ]; then
echo "PR not found yet. Checking recent PRs..."
gh pr list --limit 5 --json number,title,author
fi
# For manual PRs
gh pr create --title "${NEW_VERSION}" \
--body-file release-notes-${NEW_VERSION}.md \
--label "Release"
```
3. **Update PR with release notes:**
```bash
# For workflow-created PRs, update the body with our release notes
@@ -468,14 +486,14 @@ echo "Workflow triggered. Waiting for PR creation..."
# Monitor branch creation (for minor/major releases)
gh run list --workflow=release-branch-create.yaml --limit=1
```
4. If workflow didn't trigger due to [skip ci]:
5. If workflow didn't trigger due to [skip ci]:
```bash
echo "ERROR: Release workflow didn't trigger!"
echo "Options:"
echo "1. Create patch release (e.g., 1.24.1) to trigger workflow"
echo "2. Investigate manual release options"
```
5. If workflow triggered, monitor execution:
6. If workflow triggered, monitor execution:
```bash
WORKFLOW_RUN_ID=$(gh run list --workflow=release-draft-create.yaml --limit=1 --json databaseId --jq '.[0].databaseId')
gh run watch ${WORKFLOW_RUN_ID}
@@ -484,6 +502,7 @@ echo "Workflow triggered. Waiting for PR creation..."
### Step 14: Enhance GitHub Release
1. Wait for automatic release creation:
```bash
# Wait for release to be created
while ! gh release view v${NEW_VERSION} >/dev/null 2>&1; do
@@ -493,13 +512,14 @@ echo "Workflow triggered. Waiting for PR creation..."
```
2. **Enhance the GitHub release:**
```bash
# Update release with our release notes
gh release edit v${NEW_VERSION} \
--title "🚀 ComfyUI Frontend v${NEW_VERSION}" \
--notes-file release-notes-${NEW_VERSION}.md \
--latest
# Add any additional assets if needed
# gh release upload v${NEW_VERSION} additional-assets.zip
```
@@ -512,14 +532,17 @@ echo "Workflow triggered. Waiting for PR creation..."
### Step 15: Verify Multi-Channel Distribution
1. **GitHub Release:**
```bash
gh release view v${NEW_VERSION} --json assets,body,createdAt,tagName
```
- ✅ Check release notes
- ✅ Verify dist.zip attachment
- ✅ Confirm release marked as latest (for main branch)
2. **PyPI Package:**
```bash
# Check PyPI availability (may take a few minutes)
for i in {1..10}; do
@@ -533,6 +556,7 @@ echo "Workflow triggered. Waiting for PR creation..."
```
3. **npm Package:**
```bash
# Check npm availability
for i in {1..10}; do
@@ -550,15 +574,17 @@ echo "Workflow triggered. Waiting for PR creation..."
### Step 16: Post-Release Monitoring Setup
1. **Monitor immediate release health:**
```bash
# Check for immediate issues
gh issue list --label "bug" --state open --limit 5 --json title,number,createdAt
# Monitor download metrics (if accessible)
gh release view v${NEW_VERSION} --json assets --jq '.assets[].downloadCount'
```
2. **Update documentation tracking:**
```bash
cat > post-release-checklist.md << EOF
# Post-Release Checklist for v${NEW_VERSION}
@@ -589,6 +615,7 @@ echo "Workflow triggered. Waiting for PR creation..."
```
3. **Create release summary:**
```bash
cat > release-summary-${NEW_VERSION}.md << EOF
# Release Summary: ComfyUI Frontend v${NEW_VERSION}
@@ -626,6 +653,7 @@ echo "Workflow triggered. Waiting for PR creation..."
### Step 17: Create Release Summary
1. **Create comprehensive release summary:**
```bash
cat > release-summary-${NEW_VERSION}.md << EOF
# Release Summary: ComfyUI Frontend v${NEW_VERSION}
@@ -665,6 +693,7 @@ echo "Workflow triggered. Waiting for PR creation..."
### Rollback Procedures
**Pre-Merge Rollback:**
```bash
# Close version bump PR and reset
gh pr close ${PR_NUMBER}
@@ -673,6 +702,7 @@ git clean -fd
```
**Post-Merge Rollback:**
```bash
# Create immediate patch release with reverts
git revert ${RELEASE_COMMIT}
@@ -680,6 +710,7 @@ git revert ${RELEASE_COMMIT}
```
**Emergency Procedures:**
```bash
# Document incident
cat > release-incident-${NEW_VERSION}.md << EOF
@@ -713,31 +744,39 @@ The command implements multiple quality gates:
## Common Scenarios
### Scenario 1: Regular Feature Release
```bash
/project:create-frontend-release minor
```
- Analyzes features since last release
- Generates changelog automatically
- Creates comprehensive release notes
### Scenario 2: Critical Security Patch
```bash
/project:create-frontend-release patch "Security fixes for CVE-2024-XXXX"
```
- Expedited security scanning
- Enhanced monitoring setup
### Scenario 3: Major Version with Breaking Changes
```bash
/project:create-frontend-release major
```
- Comprehensive breaking change analysis
- Migration guide generation
### Scenario 4: Pre-release Testing
```bash
/project:create-frontend-release prerelease
```
- Creates alpha/beta/rc versions
- Draft release status
- Python package specs require that prereleases use alpha/beta/rc as the preid
@@ -747,10 +786,12 @@ The command implements multiple quality gates:
When executing this release process, pay attention to these key aspects:
### Version Handling
- For pre-release versions (e.g., 1.24.0-rc.1), the next stable release should be the same version without the suffix (1.24.0)
- Never skip version numbers - follow semantic versioning strictly
### Commit History Analysis
- **ALWAYS** use `--first-parent` flag with git log to avoid including commits from merged feature branches
- Verify PR merge targets before including them in changelogs:
```bash
@@ -758,6 +799,7 @@ When executing this release process, pay attention to these key aspects:
```
### Release Workflow Triggers
- The "Release" label on the PR is **CRITICAL** - without it, PyPI/npm publishing won't occur
- Check for `[skip ci]` in commit messages before merging - this blocks the release workflow
- If you encounter `[skip ci]`, push an empty commit to override it:
@@ -766,11 +808,13 @@ When executing this release process, pay attention to these key aspects:
```
### PR Creation Details
- Version bump PRs come from `comfy-pr-bot`, not `github-actions`
- The workflow typically completes in 20-30 seconds
- Always wait for the PR to be created before trying to edit it
### Breaking Changes Detection
- Analyze changes to public-facing APIs:
- The `app` object and its methods
- The `api` module exports
@@ -779,9 +823,10 @@ When executing this release process, pay attention to these key aspects:
- Any modifications to these require marking as breaking changes
### Recovery Procedures
If the release workflow fails to trigger:
1. Create a revert PR to restore the previous version
2. Merge the revert
3. Re-run the version bump workflow
4. This approach is cleaner than creating extra version numbers

View File

@@ -3,10 +3,11 @@
This command creates patch/hotfix releases for ComfyUI Frontend by backporting fixes to stable core branches. It handles both automated backports (preferred) and manual cherry-picking (fallback).
**Process Overview:**
1. **Check automated backports first** (via labels)
2. **Skip to version bump** if backports already merged
3. **Manual cherry-picking** if automation failed
4. **Create patch release** with version bump
4. **Create patch release** with version bump
5. **Publish GitHub release** (manually uncheck "latest")
6. **Update ComfyUI requirements.txt** via PR
@@ -14,7 +15,8 @@ This command creates patch/hotfix releases for ComfyUI Frontend by backporting f
Create a hotfix release by backporting commits/PRs from main to a core branch: $ARGUMENTS
Expected format: Comma-separated list of commits or PR numbers
Examples:
Examples:
- `#1234,#5678` (PRs - preferred)
- `abc123,def456` (commit hashes)
- `#1234,abc123` (mixed)
@@ -25,7 +27,7 @@ If no arguments provided, the command will guide you through identifying commits
## Prerequisites
- Push access to repository
- GitHub CLI (`gh`) authenticated
- GitHub CLI (`gh`) authenticated
- Clean working tree
- Understanding of what fixes need backporting
@@ -36,11 +38,13 @@ If no arguments provided, the command will guide you through identifying commits
**Check if automated backports were attempted:**
1. **For each PR, check existing backport labels:**
```bash
gh pr view #1234 --json labels | jq -r '.labels[].name'
```
2. **If no backport labels exist, add them now:**
```bash
# Add backport labels (this triggers automated backports)
gh pr edit #1234 --add-label "needs-backport"
@@ -48,6 +52,7 @@ If no arguments provided, the command will guide you through identifying commits
```
3. **Check for existing backport PRs:**
```bash
# Check for backport PRs created by automation
PR_NUMBER=${ARGUMENTS%%,*} # Extract first PR number from arguments
@@ -58,18 +63,22 @@ If no arguments provided, the command will guide you through identifying commits
4. **Handle existing backport scenarios:**
**Scenario A: Automated backports already merged**
```bash
# Check if backport PRs were merged to core branches
gh pr list --search "backport-${PR_NUMBER}-to" --state merged
```
- If backport PRs are merged → Skip to Step 10 (Version Bump)
- **CONFIRMATION**: Automated backports completed, proceeding to version bump?
**Scenario B: Automated backport PRs exist but not merged**
```bash
# Show open backport PRs that need merging
gh pr list --search "backport-${PR_NUMBER}-to" --state open
```
- **ACTION REQUIRED**: Merge the existing backport PRs first
- Use: `gh pr merge [PR_NUMBER] --merge` for each backport PR
- After merging, return to this command and skip to Step 10 (Version Bump)
@@ -127,6 +136,7 @@ If no arguments provided, the command will guide you through identifying commits
### Step 6: Cherry-pick Changes
For each commit:
1. Attempt cherry-pick: `git cherry-pick <commit>`
2. If conflicts occur:
- Display conflict details
@@ -198,6 +208,7 @@ For each commit:
```
3. **CRITICAL**: Verify "Release" label is added
4. Create standardized release notes:
```bash
cat > release-notes-${NEW_VERSION}.md << 'EOF'
## ⚠️ Breaking Changes
@@ -231,12 +242,14 @@ For each commit:
**Full Changelog**: https://github.com/Comfy-Org/ComfyUI_frontend/compare/v${CURRENT_VERSION}...v${NEW_VERSION}
EOF
```
- For hotfixes, typically only populate the "Bug Fixes" section
- Include links to the cherry-picked PRs/commits
- Update the PR body with the release notes:
```bash
gh pr edit ${PR_NUMBER} --body-file release-notes-${NEW_VERSION}.md
```
5. **CONFIRMATION REQUIRED**: Release PR has "Release" label?
### Step 12: Monitor Release Process
@@ -262,7 +275,7 @@ For each commit:
2. **Find the DRAFT release** (e.g., "v1.23.5 Draft")
3. **Click "Edit release"**
4. **UNCHECK "Set as the latest release"** ⚠️ **CRITICAL**
- This prevents the hotfix from showing as "latest"
- This prevents the hotfix from showing as "latest"
- Main branch should always be "latest release"
5. **Click "Publish release"**
6. **CONFIRMATION REQUIRED**: Draft release published with "latest" unchecked?
@@ -272,6 +285,7 @@ For each commit:
**IMPORTANT**: Create PR to update ComfyUI's requirements.txt via fork:
1. **Setup fork (if needed):**
```bash
# Check if fork already exists
if gh repo view ComfyUI --json owner | jq -r '.owner.login' | grep -q "$(gh api user --jq .login)"; then
@@ -284,30 +298,32 @@ For each commit:
```
2. **Clone fork and create branch:**
```bash
# Clone your fork (or use existing clone)
GITHUB_USER=$(gh api user --jq .login)
if [ ! -d "ComfyUI-fork" ]; then
gh repo clone ${GITHUB_USER}/ComfyUI ComfyUI-fork
fi
cd ComfyUI-fork
git checkout master
git pull origin master
# Create update branch
BRANCH_NAME="update-frontend-${NEW_VERSION}"
git checkout -b ${BRANCH_NAME}
```
3. **Update requirements.txt:**
```bash
# Update the version in requirements.txt
sed -i "s/comfyui-frontend-package==[0-9].*$/comfyui-frontend-package==${NEW_VERSION}/" requirements.txt
# Verify the change
grep "comfyui-frontend-package" requirements.txt
# Commit the change
git add requirements.txt
git commit -m "Bump frontend to ${NEW_VERSION}"
@@ -321,7 +337,8 @@ For each commit:
--repo comfyanonymous/ComfyUI \
--title "Bump frontend to ${NEW_VERSION}" \
--body "$(cat <<EOF
Bump frontend to ${NEW_VERSION}
Bump frontend to ${NEW_VERSION}
```
\`\`\`
python main.py --front-end-version Comfy-Org/ComfyUI_frontend@${NEW_VERSION}
@@ -334,15 +351,19 @@ python main.py --front-end-version Comfy-Org/ComfyUI_frontend@${NEW_VERSION}
## Changes
- Fix: [Brief description of hotfixes included]
EOF
)"
```
EOF
)"
```
```
5. **Clean up:**
```bash
# Return to original directory
cd ..
# Keep fork directory for future updates
echo "Fork directory 'ComfyUI-fork' kept for future use"
```
@@ -375,6 +396,7 @@ EOF
## Safety Checks
Throughout the process:
- Always verify core branch matches ComfyUI's requirements.txt
- For PRs: Ensure using correct commits (merge vs individual)
- Check version numbers follow semantic versioning
@@ -385,6 +407,7 @@ Throughout the process:
## Rollback Procedures
If something goes wrong:
- Before push: `git reset --hard origin/core/X.Y`
- After PR creation: Close PR and start over
- After failed release: Create new patch version with fixes
@@ -404,16 +427,16 @@ If something goes wrong:
## Modern Workflow Context
**Primary Backport Method:** Automated via `needs-backport` + `X.YY` labels
**This Command Usage:**
**This Command Usage:**
- Smart path detection - skip to version bump if backports already merged
- Fallback to manual cherry-picking only when automation fails/has conflicts
**Complete Hotfix:** Includes GitHub release publishing + ComfyUI requirements.txt integration
**Complete Hotfix:** Includes GitHub release publishing + ComfyUI requirements.txt integration
## Workflow Paths
- **Path A:** Backports already merged → Skip to Step 10 (Version Bump)
- **Path B:** Backport PRs need merging → Merge them → Skip to Step 10 (Version Bump)
- **Path B:** Backport PRs need merging → Merge them → Skip to Step 10 (Version Bump)
- **Path C:** No/failed backports → Manual cherry-picking (Steps 2-9) → Version Bump (Step 10)
This process ensures a complete hotfix release with proper GitHub publishing, ComfyUI integration, and multiple safety checkpoints.
This process ensures a complete hotfix release with proper GitHub publishing, ComfyUI integration, and multiple safety checkpoints.

View File

@@ -5,6 +5,7 @@ Bootstrap the ComfyUI Frontend monorepo with all necessary dependencies and veri
## Overview
This command will:
1. Install pnpm package manager (if not present)
2. Install all project dependencies
3. Verify the project builds successfully
@@ -93,7 +94,7 @@ sleep 10
# Check if server is running
if curl -s http://localhost:5173 > /dev/null 2>&1; then
echo "✅ Development server started successfully at http://localhost:5173"
# Kill the background server
kill $SERVER_PID
wait $SERVER_PID 2>/dev/null
@@ -154,4 +155,4 @@ After running the setup, manually verify:
- Node.js >= 24
- Git repository
- Internet connection for package downloads
- Available ports (typically 5173 for dev server)
- Available ports (typically 5173 for dev server)

View File

@@ -12,10 +12,10 @@ Follow these steps systematically to verify our changes:
2. **Visual Testing Process**
- Navigate to http://localhost:5173/
- For each target page (specified in arguments or recently changed files):
* Navigate to the page using direct URL or site navigation
* Take a high-quality screenshot
* Analyze the screenshot for the specific changes we implemented
* Document any visual issues or improvements needed
- Navigate to the page using direct URL or site navigation
- Take a high-quality screenshot
- Analyze the screenshot for the specific changes we implemented
- Document any visual issues or improvements needed
3. **Quality Verification**
Check each page for:
@@ -27,7 +27,7 @@ Follow these steps systematically to verify our changes:
- Typography and readability
- Color scheme consistency
- Interactive elements (buttons, links, forms)
</instructions>
</instructions>
<examples>
Common issues to watch for:
@@ -48,10 +48,11 @@ For each page tested, provide:
4. Overall assessment of visual quality
If you find issues, be specific about:
- Exact location of the problem
- Expected vs actual behavior
- Severity level (critical, important, minor)
- Suggested fix if obvious
</reporting>
</reporting>
Remember: Take your time with each screenshot and analysis. Visual quality directly impacts user experience and our project's professional appearance.
Remember: Take your time with each screenshot and analysis. Visual quality directly impacts user experience and our project's professional appearance.

1
.github/AGENTS.md vendored
View File

@@ -5,6 +5,7 @@ Context for automated PR review system.
## Review Scope
This automated review performs comprehensive analysis:
- Architecture and design patterns
- Security vulnerabilities
- Performance implications

1
.github/CLAUDE.md vendored
View File

@@ -1,3 +1,4 @@
<!-- A rose by any other name would smell as sweet,
But Claude insists on files named for its own conceit. -->
@AGENTS.md

View File

@@ -60,7 +60,7 @@ body:
attributes:
label: ComfyUI Frontend Version
description: Found in Settings > About (e.g., "1.3.45")
placeholder: "1.3.45"
placeholder: '1.3.45'
validations:
required: true

View File

@@ -34,4 +34,4 @@ Follow Vue 3 style guide and naming conventions
Use Vite for fast development and building
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json.
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json.

View File

@@ -1,5 +1,5 @@
# Description: Validates JSON syntax in all tracked .json files (excluding tsconfig*.json) using jq
name: "CI: JSON Validation"
name: 'CI: JSON Validation'
on:
push:

View File

@@ -1,5 +1,5 @@
# Description: Linting and code formatting validation for pull requests
name: "CI: Lint Format"
name: 'CI: Lint Format'
on:
pull_request:

View File

@@ -1,5 +1,5 @@
# Description: Validates Python code in tools/devtools directory
name: "CI: Python Validation"
name: 'CI: Python Validation'
on:
pull_request:

View File

@@ -1,5 +1,5 @@
# Description: Runs shellcheck on tracked shell scripts when they change
name: "CI: Shell Validation"
name: 'CI: Shell Validation'
on:
push:

View File

@@ -1,4 +1,4 @@
name: "CI: Size Data"
name: 'CI: Size Data'
on:
push:

View File

@@ -1,9 +1,9 @@
# Description: Deploys Storybook previews from forked PRs (forks can't access deployment secrets)
name: "CI: Tests Storybook (Deploy for Forks)"
name: 'CI: Tests Storybook (Deploy for Forks)'
on:
workflow_run:
workflows: ["CI: Tests Storybook"]
workflows: ['CI: Tests Storybook']
types: [requested, completed]
env:

View File

@@ -1,8 +1,8 @@
# Description: Builds Storybook and runs visual regression testing via Chromatic, deploys previews to Cloudflare Pages
name: "CI: Tests Storybook"
name: 'CI: Tests Storybook'
on:
workflow_dispatch: # Allow manual triggering
workflow_dispatch: # Allow manual triggering
pull_request:
jobs:
@@ -88,7 +88,7 @@ jobs:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0 # Required for Chromatic baseline
fetch-depth: 0 # Required for Chromatic baseline
- name: Install pnpm
uses: pnpm/action-setup@v4
@@ -110,9 +110,9 @@ jobs:
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
buildScriptName: build-storybook
autoAcceptChanges: 'main' # Auto-accept changes on main branch
exitOnceUploaded: true # Don't wait for UI tests to complete
onlyChanged: true # Only capture changed stories
autoAcceptChanges: 'main' # Auto-accept changes on main branch
exitOnceUploaded: true # Don't wait for UI tests to complete
onlyChanged: true # Only capture changed stories
- name: Set job status
id: job-status

View File

@@ -1,5 +1,5 @@
# Description: Unit and component testing with Vitest
name: "CI: Tests Unit"
name: 'CI: Tests Unit'
on:
push:
@@ -26,8 +26,8 @@ jobs:
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
cache: "pnpm"
node-version: 'lts/*'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile

View File

@@ -1,5 +1,5 @@
# Description: Validates YAML syntax and style using yamllint with relaxed rules
name: "CI: YAML Validation"
name: 'CI: YAML Validation'
on:
push:

View File

@@ -1,5 +1,5 @@
# Description: Generates and updates translations for core ComfyUI components using OpenAI
name: "i18n: Update Core"
name: 'i18n: Update Core'
on:
# Manual dispatch for urgent translation updates
@@ -41,7 +41,7 @@ jobs:
env:
PLAYWRIGHT_TEST_URL: http://localhost:5173
- name: Update translations
run: pnpm locale
run: pnpm locale && pnpm format
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Commit updated locales

View File

@@ -43,8 +43,8 @@ jobs:
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
with:
token: ${{ secrets.PR_GH_TOKEN }}
commit-message: "Update locales for node definitions"
title: "Update locales for node definitions"
commit-message: 'Update locales for node definitions'
title: 'Update locales for node definitions'
body: |
Automated PR to update locales for node definitions

View File

@@ -462,7 +462,6 @@ jobs:
fi
done < "$FILE"
- name: Remove needs-backport label
if: steps.filter-targets.outputs.skip != 'true' && success()
run: gh pr edit ${{ github.event_name == 'workflow_dispatch' && inputs.pr_number || github.event.pull_request.number }} --remove-label "needs-backport"

View File

@@ -1,5 +1,5 @@
# Description: AI-powered code review triggered by adding the 'claude-review' label to a PR
name: "PR: Claude Review"
name: 'PR: Claude Review'
permissions:
contents: read
@@ -46,7 +46,7 @@ jobs:
- name: Run Claude PR Review
uses: anthropics/claude-code-action@v1.0.6
with:
label_trigger: "claude-review"
label_trigger: 'claude-review'
prompt: |
Read the file .claude/commands/comprehensive-pr-review.md and follow ALL the instructions exactly.

View File

@@ -1,4 +1,4 @@
name: "PR: Size Report"
name: 'PR: Size Report'
on:
workflow_run:

View File

@@ -1,5 +1,5 @@
# Setting test expectation screenshots for Playwright
name: "PR: Update Playwright Expectations"
name: 'PR: Update Playwright Expectations'
on:
pull_request:
@@ -39,11 +39,11 @@ jobs:
- name: Find Update Comment
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad
id: "find-update-comment"
id: 'find-update-comment'
with:
issue-number: ${{ steps.pr-info.outputs.pr-number }}
comment-author: "github-actions[bot]"
body-includes: "Updating Playwright Expectations"
comment-author: 'github-actions[bot]'
body-includes: 'Updating Playwright Expectations'
- name: Add Starting Reaction
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9

View File

@@ -1,5 +1,5 @@
# Automated bi-weekly workflow to bump ComfyUI frontend RC releases
name: "Release: Bi-weekly ComfyUI"
name: 'Release: Bi-weekly ComfyUI'
on:
# Schedule for Monday at 12:00 PM PST (20:00 UTC)

View File

@@ -1,5 +1,5 @@
# Description: Manual workflow to increment package version with semantic versioning support
name: "Release: Version Bump"
name: 'Release: Version Bump'
on:
workflow_dispatch:

View File

@@ -1,5 +1,5 @@
# Description: Automated weekly documentation accuracy check and update via Claude
name: "Weekly Documentation Check"
name: 'Weekly Documentation Check'
permissions:
contents: write

2
.gitignore vendored
View File

@@ -96,3 +96,5 @@ vitest.config.*.timestamp*
# Weekly docs check output
/output.txt
.amp

View File

@@ -7,14 +7,8 @@
"printWidth": 80,
"ignorePatterns": [
"packages/registry-types/src/comfyRegistryTypes.ts",
"public/materialdesignicons.min.css",
"src/types/generatedManagerTypes.ts",
"**/*.md",
"**/*.json",
"**/*.css",
"**/*.yaml",
"**/*.yml",
"**/*.html",
"**/*.svg",
"**/*.xml"
"**/__fixtures__/**/*.json"
]
}

View File

@@ -31,10 +31,7 @@
"no-console": [
"error",
{
"allow": [
"warn",
"error"
]
"allow": ["warn", "error"]
}
],
"no-control-regex": "off",
@@ -66,12 +63,7 @@
},
{
"name": "@/i18n--to-enable",
"importNames": [
"st",
"t",
"te",
"d"
],
"importNames": ["st", "t", "te", "d"],
"message": "Don't import `@/i18n` directly, prefer `useI18n()`"
}
]
@@ -85,10 +77,7 @@
"import/export": "error",
"import/namespace": "error",
"import/no-duplicates": "error",
"import/consistent-type-specifier-style": [
"error",
"prefer-top-level"
],
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"jest/expect-expect": "off",
"jest/no-conditional-expect": "off",
"jest/no-disabled-tests": "off",
@@ -117,13 +106,10 @@
},
"overrides": [
{
"files": [
"**/*.{stories,test,spec}.ts",
"**/*.stories.vue"
],
"files": ["**/*.{stories,test,spec}.ts", "**/*.stories.vue"],
"rules": {
"no-console": "allow"
}
}
]
}
}

View File

@@ -5,6 +5,7 @@ See `@docs/guidance/storybook.md` for story patterns (auto-loaded for `*.stories
## Available Context
Stories have access to:
- All ComfyUI stores
- PrimeVue with ComfyUI theming
- i18n system

View File

@@ -1,3 +1,4 @@
<!-- Though standards bloom in open fields so wide,
Anthropic walks a path of lonely pride. -->
@AGENTS.md

View File

@@ -12,16 +12,17 @@ Storybook is a frontend workshop for building UI components and pages in isolati
## Storybook vs Other Testing Tools
| Tool | Purpose | Use Case |
|------|---------|----------|
| **Storybook** | Component isolation & documentation | Developing, testing, and showcasing individual UI components |
| **Playwright** | End-to-end testing | Full user workflow testing across multiple pages |
| **Vitest** | Unit testing | Testing business logic, utilities, and component behavior |
| **Vue Testing Library** | Component testing | Testing component interactions and DOM output |
| Tool | Purpose | Use Case |
| ----------------------- | ----------------------------------- | ------------------------------------------------------------ |
| **Storybook** | Component isolation & documentation | Developing, testing, and showcasing individual UI components |
| **Playwright** | End-to-end testing | Full user workflow testing across multiple pages |
| **Vitest** | Unit testing | Testing business logic, utilities, and component behavior |
| **Vue Testing Library** | Component testing | Testing component interactions and DOM output |
### When to Use Storybook
**✅ Use Storybook for:**
- Developing new UI components in isolation
- Creating component documentation and examples
- Testing different component states and props
@@ -30,6 +31,7 @@ Storybook is a frontend workshop for building UI components and pages in isolati
- Building a component library or design system
**❌ Don't use Storybook for:**
- Testing complex user workflows (use Playwright)
- Testing business logic (use Vitest)
- Integration testing between components (use Vue Testing Library)
@@ -96,6 +98,7 @@ export const WithVariant: Story = {
## ComfyUI Storybook Guidelines
### Scope When to Create Stories
- **PrimeVue components**:
No need to create stories. Just refer to the official PrimeVue documentation.
- **Custom shared components (design system components)**:
@@ -104,6 +107,7 @@ export const WithVariant: Story = {
Do not create stories. Only the underlying pure UI components should be included in Storybook.
### Maintenance Philosophy
- Stories are lightweight and generally stable.
Once created, they rarely need updates unless:
- The design changes
@@ -111,10 +115,12 @@ export const WithVariant: Story = {
- For existing usage patterns, simply copy real code examples into Storybook to create stories.
### File Placement
- Keep `*.stories.ts` files at the **same level as the component** (similar to test files).
- Keep `*.stories.ts` files at the **same level as the component** (similar to test files).
- This makes it easier to check usage examples without navigating to another directory.
### Developer/Designer Workflow
- **UI vs Container**: Separate pure UI components from container components.
Only UI components should live in Storybook.
- **Communication Tool**: Storybook is not just about code quality—it enables designers and developers to see:
@@ -126,9 +132,10 @@ export const WithVariant: Story = {
→ Only create a story for the base UI button, not for the wrapper.
### Suggested Workflow
1. Use PrimeVue docs for standard components
2. Use Storybook for **shared/custom components** that define our design system
3. Keep story files alongside components
1. Use PrimeVue docs for standard components
2. Use Storybook for **shared/custom components** that define our design system
3. Keep story files alongside components
4. When in doubt, focus on components reused across the app or those that need to be showcased to designers
### Best Practices
@@ -211,13 +218,12 @@ This Storybook setup includes:
## Icon Usage in Storybook
In this project, only the `<i class="icon-[lucide--folder]" />` syntax from unplugin-icons is supported in Storybook.
In this project, only the `<i class="icon-[lucide--folder]" />` syntax from unplugin-icons is supported in Storybook.
**Example:**
```vue
<script setup lang="ts">
</script>
<script setup lang="ts"></script>
<template>
<i class="icon-[lucide--trophy] text-neutral size-4" />
@@ -226,4 +232,3 @@ In this project, only the `<i class="icon-[lucide--folder]" />` syntax from unpl
```
This approach ensures icons render correctly in Storybook and remain consistent with the rest of the app.

View File

@@ -1,7 +1,9 @@
<style>
body {
overflow-y: auto !important;
transition: background-color 0.3s ease, color 0.3s ease;
transition:
background-color 0.3s ease,
color 0.3s ease;
}
/* Light theme default - with explicit color to override media queries */
@@ -57,8 +59,8 @@
/* Override Storybook's problematic & selector styles */
/* Reset only the specific properties that Storybook injects */
li+li {
li + li {
margin: 0;
padding: revert-layer;
}
</style>
</style>

View File

@@ -47,4 +47,4 @@
"status": "obsolete"
}
]
}
}

View File

@@ -1,6 +1,6 @@
# Repository Guidelines
See @docs/guidance/*.md for file-type-specific conventions (auto-loaded by glob).
See @docs/guidance/\*.md for file-type-specific conventions (auto-loaded by glob).
## Project Structure & Module Organization
@@ -93,7 +93,6 @@ The project uses **Nx** for build orchestration and task management
- composables `useXyz.ts`
- Pinia stores `*Store.ts`
## Commit & Pull Request Guidelines
- PRs:
@@ -131,8 +130,8 @@ The project uses **Nx** for build orchestration and task management
```typescript
const { nodes, showTotal = true } = defineProps<{
nodes: ApiNodeCost[]
showTotal?: boolean
nodes: ApiNodeCost[]
showTotal?: boolean
}>()
```
@@ -178,7 +177,7 @@ The project uses **Nx** for build orchestration and task management
## Testing Guidelines
See @docs/testing/*.md for detailed patterns.
See @docs/testing/\*.md for detailed patterns.
- Frameworks:
- Vitest (unit/component, happy-dom)
@@ -300,6 +299,13 @@ When referencing Comfy-Org repos:
Rules for agent-based coding tasks.
### Chrome DevTools MCP
When using `take_snapshot` to inspect dropdowns, listboxes, or other components with dynamic options:
- Use `verbose: true` to see the full accessibility tree including list items
- Non-verbose snapshots often omit nested options in comboboxes/listboxes
### Temporary Files
- Put planning documents under `/temp/plans/`

View File

@@ -24,12 +24,14 @@ Have another idea? Drop into Discord or open an issue, and let's chat!
### Initial Setup
1. Clone the repository:
```bash
git clone https://github.com/Comfy-Org/ComfyUI_frontend.git
cd ComfyUI_frontend
```
2. Install dependencies:
```bash
pnpm install
```
@@ -83,8 +85,7 @@ Make sure your desktop machine and touch device are on the same network. On your
navigate to `http://<server_ip>:5173` (e.g. `http://192.168.2.20:5173` here), to access the ComfyUI frontend.
> ⚠️ IMPORTANT:
The dev server will NOT load JavaScript extensions from custom nodes. Only core extensions (built into the frontend) will be loaded. This is because the shim system that allows custom node JavaScript to import frontend modules only works in production builds. Python custom nodes still function normally. See [Extension Development Guide](docs/extensions/development.md) for details and workarounds. And See [Extension Overview](docs/extensions/README.md) for extensions overview.
> The dev server will NOT load JavaScript extensions from custom nodes. Only core extensions (built into the frontend) will be loaded. This is because the shim system that allows custom node JavaScript to import frontend modules only works in production builds. Python custom nodes still function normally. See [Extension Development Guide](docs/extensions/development.md) for details and workarounds. And See [Extension Overview](docs/extensions/README.md) for extensions overview.
## Development Workflow
@@ -109,7 +110,6 @@ When you fix a bug that affects a version in feature freeze, we use an automated
2. Before merging, add these labels to your PR:
- `needs-backport` - triggers the automated backport workflow
- `core/1.24` - targets the `core/1.24` release candidate branch
3. Merge your PR normally
4. The automated workflow will:
- Create a new branch from `core/1.24`
@@ -127,6 +127,7 @@ When you fix a bug that affects a version in feature freeze, we use an automated
#### Handling Conflicts
If the automated cherry-pick fails due to conflicts, the workflow will comment on your PR with:
- The list of conflicting files
- Instructions to manually cherry-pick to the release candidate branch
@@ -241,6 +242,7 @@ The original litegraph repository (https://github.com/Comfy-Org/litegraph.js) is
## Questions?
If you have questions about contributing:
- Check existing issues and discussions
- Ask in our [Discord](https://discord.com/invite/comfyorg)
- Open a new issue for clarification

189
README.md
View File

@@ -13,7 +13,6 @@
[![][github-downloads-shield]][github-downloads-link]
[![][github-downloads-latest-shield]][github-downloads-link]
[github-release-shield]: https://img.shields.io/github/v/release/Comfy-Org/ComfyUI_frontend?style=flat&sort=semver
[github-release-link]: https://github.com/Comfy-Org/ComfyUI_frontend/releases
[github-release-date-shield]: https://img.shields.io/github/release-date/Comfy-Org/ComfyUI_frontend?style=flat
@@ -47,6 +46,7 @@ The project follows a structured release process for each minor version, consist
- Version is finalized and made available to all users
### Nightly Releases
Nightly releases are published daily at [https://github.com/Comfy-Org/ComfyUI_frontend/releases](https://github.com/Comfy-Org/ComfyUI_frontend/releases).
To use the latest nightly release, add the following command line argument to your ComfyUI launch script:
@@ -56,16 +56,17 @@ To use the latest nightly release, add the following command line argument to yo
```
## Overlapping Release Cycles
The development of successive minor versions overlaps. For example, while version 1.1 is in feature freeze, development for version 1.2 begins simultaneously. Each feature has approximately 4 weeks from merge to ComfyUI stable release (2 weeks on main, 2 weeks frozen on RC).
### Example Release Cycle
| Week | Date Range | Version 1.1 | Version 1.2 | Version 1.3 | Patch Releases |
|------|------------|-------------|-------------|-------------|----------------|
| 1-2 | Mar 1-14 | Development | - | - | - |
| 3-4 | Mar 15-28 | Feature Freeze | Development | - | 1.1.0 through 1.1.13 (daily) |
| 5-6 | Mar 29-Apr 11 | Released | Feature Freeze | Development | 1.1.14+ (daily)<br>1.2.0 through 1.2.13 (daily) |
| 7-8 | Apr 12-25 | - | Released | Feature Freeze | 1.2.14+ (daily)<br>1.3.0 through 1.3.13 (daily) |
| Week | Date Range | Version 1.1 | Version 1.2 | Version 1.3 | Patch Releases |
| ---- | ------------- | -------------- | -------------- | -------------- | ----------------------------------------------- |
| 1-2 | Mar 1-14 | Development | - | - | - |
| 3-4 | Mar 15-28 | Feature Freeze | Development | - | 1.1.0 through 1.1.13 (daily) |
| 5-6 | Mar 29-Apr 11 | Released | Feature Freeze | Development | 1.1.14+ (daily)<br>1.2.0 through 1.2.13 (daily) |
| 7-8 | Apr 12-25 | - | Released | Feature Freeze | 1.2.14+ (daily)<br>1.3.0 through 1.3.13 (daily) |
## Release Summary
@@ -74,19 +75,21 @@ The development of successive minor versions overlaps. For example, while versio
<details id='feature-native-translation'>
<summary>v1.5: Native translation (i18n)</summary>
ComfyUI now includes built-in translation support, replacing the need for third-party translation extensions. Select your language
in `Comfy > Locale > Language` to translate the interface into English, Chinese (Simplified), Russian, Japanese, Korean, or Arabic. This native
implementation offers better performance, reliability, and maintainability compared to previous solutions.<br>
ComfyUI now includes built-in translation support, replacing the need for third-party translation extensions. Select your language
in `Comfy > Locale > Language` to translate the interface into English, Chinese (Simplified), Russian, Japanese, Korean, or Arabic. This native
implementation offers better performance, reliability, and maintainability compared to previous solutions.<br>
More details available here: https://blog.comfy.org/p/native-localization-support-i18n
More details available here: https://blog.comfy.org/p/native-localization-support-i18n
</details>
<details id='feature-mask-editor'>
<summary>v1.4: New mask editor</summary>
https://github.com/Comfy-Org/ComfyUI_frontend/pull/1284 implements a new mask editor.
https://github.com/Comfy-Org/ComfyUI_frontend/pull/1284 implements a new mask editor.
![image](https://github.com/user-attachments/assets/f0ea6ee5-00ee-4e5d-a09c-6938e86a1f17)
![image](https://github.com/user-attachments/assets/f0ea6ee5-00ee-4e5d-a09c-6938e86a1f17)
</details>
<details id='feature-integrated-server-terminal'>
@@ -95,18 +98,22 @@ The development of successive minor versions overlaps. For example, while versio
Press Ctrl + ` to toggle integrated terminal.
https://github.com/user-attachments/assets/eddedc6a-07a3-4a83-9475-63b3977f6d94
</details>
<details id='feature-keybinding-customization'>
<summary>v1.3.7: Keybinding customization</summary>
## Basic UI
![image](https://github.com/user-attachments/assets/c84a1609-3880-48e0-a746-011f36beda68)
## Reset button
![image](https://github.com/user-attachments/assets/4d2922da-bb4f-4f90-8017-a8e4a0db07c7)
## Edit Keybinding
![image](https://github.com/user-attachments/assets/77626b7a-cb46-48f8-9465-e03120aac66a)
![image](https://github.com/user-attachments/assets/79131a4e-75c6-4715-bd11-c6aaed887779)
@@ -117,27 +124,34 @@ https://github.com/user-attachments/assets/eddedc6a-07a3-4a83-9475-63b3977f6d94
<details id='feature-node-library-sidebar'>
<summary>v1.2.4: Node library sidebar tab</summary>
#### Drag & Drop
#### Drag & Drop
https://github.com/user-attachments/assets/853e20b7-bc0e-49c9-bbce-a2ba7566f92f
#### Filter
#### Filter
https://github.com/user-attachments/assets/4bbca3ee-318f-4cf0-be32-a5a5541066cf
</details>
<details id='feature-queue-sidebar'>
<summary>v1.2.0: Queue/History sidebar tab</summary>
https://github.com/user-attachments/assets/86e264fe-4d26-4f07-aa9a-83bdd2d02b8f
https://github.com/user-attachments/assets/86e264fe-4d26-4f07-aa9a-83bdd2d02b8f
</details>
<details id='feature-node-search'>
<summary>v1.1.0: Node search box</summary>
#### Fuzzy search & Node preview
![image](https://github.com/user-attachments/assets/94733e32-ea4e-4a9c-b321-c1a05db48709)
#### Fuzzy search & Node preview
![image](https://github.com/user-attachments/assets/94733e32-ea4e-4a9c-b321-c1a05db48709)
#### Release link with shift
https://github.com/user-attachments/assets/a1b2b5c3-10d1-4256-b620-345de6858f25
#### Release link with shift
https://github.com/user-attachments/assets/a1b2b5c3-10d1-4256-b620-345de6858f25
</details>
### QoL changes
@@ -146,12 +160,14 @@ https://github.com/user-attachments/assets/4bbca3ee-318f-4cf0-be32-a5a5541066cf
<summary>v1.3.32: **Litegraph** Nested group</summary>
https://github.com/user-attachments/assets/f51adeb1-028e-40af-81e4-0ac13075198a
</details>
<details id='feature-group-selection'>
<summary>v1.3.24: **Litegraph** Group selection</summary>
https://github.com/user-attachments/assets/e6230a94-411e-4fba-90cb-6c694200adaa
</details>
<details id='feature-toggle-link-visibility'>
@@ -227,17 +243,21 @@ https://github.com/user-attachments/assets/c142c43f-2fe9-4030-8196-b3bfd4c6977d
<details id='feature-auto-connect-link'>
<summary>v1.2.2: **Litegraph** auto connects to correct slot</summary>
#### Before
https://github.com/user-attachments/assets/c253f778-82d5-4e6f-aec0-ea2ccf421651
#### Before
https://github.com/user-attachments/assets/c253f778-82d5-4e6f-aec0-ea2ccf421651
#### After
https://github.com/user-attachments/assets/b6360ac0-f0d2-447c-9daa-8a2e20c0dc1d
#### After
https://github.com/user-attachments/assets/b6360ac0-f0d2-447c-9daa-8a2e20c0dc1d
</details>
<details id='feature-hide-text-overflow'>
<summary>v1.1.8: **Litegraph** hides text overflow on widget value</summary>
https://github.com/user-attachments/assets/5696a89d-4a47-4fcc-9e8c-71e1264943f2
https://github.com/user-attachments/assets/5696a89d-4a47-4fcc-9e8c-71e1264943f2
</details>
### Developer APIs
@@ -283,8 +303,7 @@ window['app'].extensionManager.dialog
```js
// window.alert
window['app'].extensionManager.toast
.addAlert("Test Alert")
window['app'].extensionManager.toast.addAlert('Test Alert')
```
![image](https://github.com/user-attachments/assets/9b18bdca-76ef-4432-95de-5cd2369684f2)
@@ -383,28 +402,28 @@ app.extensionManager.setting.set('TestSetting', 'Hello, universe!')
<details id='extension-api-commands-keybindings'>
<summary>v1.3.7: Register commands and keybindings</summary>
Extensions can call the following API to register commands and keybindings. Do
note that keybindings defined in core cannot be overwritten, and some keybindings
are reserved by the browser.
Extensions can call the following API to register commands and keybindings. Do
note that keybindings defined in core cannot be overwritten, and some keybindings
are reserved by the browser.
```js
app.registerExtension({
name: 'TestExtension1',
commands: [
{
id: 'TestCommand',
function: () => {
alert('TestCommand')
}
app.registerExtension({
name: 'TestExtension1',
commands: [
{
id: 'TestCommand',
function: () => {
alert('TestCommand')
}
],
keybindings: [
{
combo: { key: 'k' },
commandId: 'TestCommand'
}
]
})
}
],
keybindings: [
{
combo: { key: 'k' },
commandId: 'TestCommand'
}
]
})
```
</details>
@@ -412,66 +431,69 @@ app.extensionManager.setting.set('TestSetting', 'Hello, universe!')
<details id='extension-api-topbar-menu'>
<summary>v1.3.1: Extension API to register custom topbar menu items</summary>
Extensions can call the following API to register custom topbar menu items.
Extensions can call the following API to register custom topbar menu items.
```js
app.registerExtension({
name: 'TestExtension1',
commands: [
{
id: 'foo-id',
label: 'foo',
function: () => {
alert(1)
}
app.registerExtension({
name: 'TestExtension1',
commands: [
{
id: 'foo-id',
label: 'foo',
function: () => {
alert(1)
}
],
menuCommands: [
{
path: ['ext', 'ext2'],
commands: ['foo-id']
}
]
})
}
],
menuCommands: [
{
path: ['ext', 'ext2'],
commands: ['foo-id']
}
]
})
```
![image](https://github.com/user-attachments/assets/ae7b082f-7ce9-4549-a446-4563567102fe)
</details>
<details id='extension-api-toast'>
<summary>v1.2.27: Extension API to add toast message</summary>i
Extensions can call the following API to add toast messages.
Extensions can call the following API to add toast messages.
```js
app.extensionManager.toast.add({
severity: 'info',
summary: 'Loaded!',
detail: 'Extension loaded!',
life: 3000
})
app.extensionManager.toast.add({
severity: 'info',
summary: 'Loaded!',
detail: 'Extension loaded!',
life: 3000
})
```
Documentation of all supported options can be found here: <https://primevue.org/toast/#api.toast.interfaces.ToastMessageOptions>
![image](https://github.com/user-attachments/assets/de02cd7e-cd81-43d1-a0b0-bccef92ff487)
</details>
<details id='extension-api-sidebar-tab'>
<summary>v1.2.4: Extension API to register custom sidebar tab</summary>
Extensions now can call the following API to register a sidebar tab.
Extensions now can call the following API to register a sidebar tab.
```js
app.extensionManager.registerSidebarTab({
id: "search",
icon: "pi pi-search",
title: "search",
tooltip: "search",
type: "custom",
render: (el) => {
el.innerHTML = "<div>Custom search tab</div>";
},
});
app.extensionManager.registerSidebarTab({
id: 'search',
icon: 'pi pi-search',
title: 'search',
tooltip: 'search',
type: 'custom',
render: (el) => {
el.innerHTML = '<div>Custom search tab</div>'
}
})
```
The list of supported icons can be found here: <https://primevue.org/icons/#list>
@@ -479,6 +501,7 @@ The list of supported icons can be found here: <https://primevue.org/icons/#list
We will support custom icons later.
![image](https://github.com/user-attachments/assets/7bff028a-bf91-4cab-bf97-55c243b3f5e0)
</details>
<details id='extension-api-selection-toolbox'>
@@ -539,4 +562,4 @@ For comprehensive troubleshooting and technical support, please refer to our off
- **[General Troubleshooting Guide](https://docs.comfy.org/troubleshooting/overview)** - Common issues, performance optimization, and reporting bugs
- **[Custom Node Issues](https://docs.comfy.org/troubleshooting/custom-node-issues)** - Debugging custom node problems and conflicts
- **[Desktop Installation Guide](https://docs.comfy.org/installation/desktop/windows)** - Desktop-specific installation and troubleshooting
- **[Desktop Installation Guide](https://docs.comfy.org/installation/desktop/windows)** - Desktop-specific installation and troubleshooting

View File

@@ -1 +1 @@
AMD and the AMD Arrow logo are trademarks of Advanced Micro Devices, Inc.
AMD and the AMD Arrow logo are trademarks of Advanced Micro Devices, Inc.

View File

@@ -1,9 +1,12 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>ComfyUI</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
</head>
<body>
<div id="desktop-app"></div>

View File

@@ -2,6 +2,36 @@
"name": "@comfyorg/desktop-ui",
"version": "0.0.6",
"type": "module",
"scripts": {
"lint": "nx run @comfyorg/desktop-ui:lint",
"typecheck": "nx run @comfyorg/desktop-ui:typecheck",
"storybook": "storybook dev -p 6007",
"build-storybook": "storybook build -o dist/storybook"
},
"dependencies": {
"@comfyorg/comfyui-electron-types": "catalog:",
"@comfyorg/shared-frontend-utils": "workspace:*",
"@primevue/core": "catalog:",
"@primevue/themes": "catalog:",
"@vueuse/core": "catalog:",
"pinia": "catalog:",
"primeicons": "catalog:",
"primevue": "catalog:",
"vue": "catalog:",
"vue-i18n": "catalog:",
"vue-router": "catalog:"
},
"devDependencies": {
"@tailwindcss/vite": "catalog:",
"@vitejs/plugin-vue": "catalog:",
"dotenv": "catalog:",
"unplugin-icons": "catalog:",
"unplugin-vue-components": "catalog:",
"vite": "catalog:",
"vite-plugin-html": "catalog:",
"vite-plugin-vue-devtools": "catalog:",
"vue-tsc": "catalog:"
},
"nx": {
"tags": [
"scope:desktop",
@@ -85,35 +115,5 @@
}
}
}
},
"scripts": {
"lint": "nx run @comfyorg/desktop-ui:lint",
"typecheck": "nx run @comfyorg/desktop-ui:typecheck",
"storybook": "storybook dev -p 6007",
"build-storybook": "storybook build -o dist/storybook"
},
"dependencies": {
"@comfyorg/comfyui-electron-types": "catalog:",
"@comfyorg/shared-frontend-utils": "workspace:*",
"@primevue/core": "catalog:",
"@primevue/themes": "catalog:",
"@vueuse/core": "catalog:",
"pinia": "catalog:",
"primeicons": "catalog:",
"primevue": "catalog:",
"vue": "catalog:",
"vue-i18n": "catalog:",
"vue-router": "catalog:"
},
"devDependencies": {
"@tailwindcss/vite": "catalog:",
"@vitejs/plugin-vue": "catalog:",
"dotenv": "catalog:",
"unplugin-icons": "catalog:",
"unplugin-vue-components": "catalog:",
"vite": "catalog:",
"vite-plugin-html": "catalog:",
"vite-plugin-vue-devtools": "catalog:",
"vue-tsc": "catalog:"
}
}

View File

@@ -1,3 +1,4 @@
<!-- In gardens where the agents freely play,
One stubborn flower turns the other way. -->
@AGENTS.md

View File

@@ -17,9 +17,10 @@ Without this flag, parallel tests will conflict and fail randomly.
### ComfyUI devtools
ComfyUI_devtools is included in this repository under `tools/devtools/`. During CI/CD, these files are automatically copied to the `custom_nodes` directory.
_ComfyUI_devtools adds additional API endpoints and nodes to ComfyUI for browser testing._
ComfyUI_devtools adds additional API endpoints and nodes to ComfyUI for browser testing.
For local development, copy the devtools files to your ComfyUI installation:
```bash
cp -r tools/devtools/* /path/to/your/ComfyUI/custom_nodes/ComfyUI_devtools/
```
@@ -119,13 +120,11 @@ export default defineConfig({
Browser tests in this project follow a specific organization pattern:
- **Fixtures**: Located in `fixtures/` - These provide test setup and utilities
- `ComfyPage.ts` - The main fixture for interacting with ComfyUI
- `ComfyMouse.ts` - Utility for mouse interactions with the canvas
- Components fixtures in `fixtures/components/` - Page object models for UI components
- **Tests**: Located in `tests/` - The actual test specifications
- Organized by functionality (e.g., `widget.spec.ts`, `interaction.spec.ts`)
- Snapshot directories (e.g., `widget.spec.ts-snapshots/`) contain reference screenshots
@@ -263,7 +262,6 @@ Most common testing needs are already addressed by these helpers, which will mak
```
Available debug methods:
- `debugAddMarker(position)` - Red circle at position
- `debugAttachScreenshot(testInfo, name)` - Attach to test report
- `debugShowCanvasOverlay()` - Show canvas as overlay

View File

@@ -52,7 +52,9 @@
"flags": {},
"order": 1,
"mode": 0,
"outputs": [{ "name": "LATENT", "type": "LATENT", "links": [2], "slot_index": 0 }],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [2], "slot_index": 0 }
],
"properties": {},
"widgets_values": [512, 512, 1]
},
@@ -70,7 +72,9 @@
{ "name": "negative", "type": "CONDITIONING", "link": 6 },
{ "name": "latent_image", "type": "LATENT", "link": 2 }
],
"outputs": [{ "name": "LATENT", "type": "LATENT", "links": [7], "slot_index": 0 }],
"outputs": [
{ "name": "LATENT", "type": "LATENT", "links": [7], "slot_index": 0 }
],
"properties": {},
"widgets_values": [156680208700286, true, 20, 8, "euler", "normal", 1]
},
@@ -86,7 +90,9 @@
{ "name": "samples", "type": "LATENT", "link": 7 },
{ "name": "vae", "type": "VAE", "link": 8 }
],
"outputs": [{ "name": "IMAGE", "type": "IMAGE", "links": [9], "slot_index": 0 }],
"outputs": [
{ "name": "IMAGE", "type": "IMAGE", "links": [9], "slot_index": 0 }
],
"properties": {}
},
{

View File

@@ -5,14 +5,8 @@
{
"id": 19,
"type": "workflow>two_VAE_decode",
"pos": [
1368.800048828125,
768.7999877929688
],
"size": [
418.1999816894531,
86
],
"pos": [1368.800048828125, 768.7999877929688],
"size": [418.1999816894531, 86],
"flags": {},
"order": 0,
"mode": 0,
@@ -49,10 +43,7 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
},
"node_versions": {},
"ue_links": [],
@@ -62,14 +53,8 @@
{
"id": -1,
"type": "VAEDecode",
"pos": [
1368.800048828125,
768.7999877929688
],
"size": [
210,
46
],
"pos": [1368.800048828125, 768.7999877929688],
"size": [210, 46],
"flags": {},
"order": 0,
"mode": 0,
@@ -103,14 +88,8 @@
{
"id": -1,
"type": "VAEDecode",
"pos": [
1368.800048828125,
873.7999877929688
],
"size": [
210,
46
],
"pos": [1368.800048828125, 873.7999877929688],
"size": [210, 46],
"flags": {},
"order": 1,
"mode": 0,

View File

@@ -76,11 +76,7 @@
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
],
"widgets_values": [512, 512, 1],
"index": 0
},
{
@@ -121,9 +117,7 @@
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly.ckpt"
],
"widgets_values": ["v1-5-pruned-emaonly.ckpt"],
"index": 1
},
{
@@ -195,9 +189,7 @@
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
],
"widgets_values": ["text, watermark"],
"index": 3
},
{
@@ -320,85 +312,20 @@
],
"outputs": [],
"properties": {},
"widgets_values": [
"ComfyUI"
],
"widgets_values": ["ComfyUI"],
"index": 6
}
],
"links": [
[
1,
1,
2,
0,
4,
"CLIP"
],
[
1,
1,
3,
0,
4,
"CLIP"
],
[
1,
0,
4,
0,
4,
"MODEL"
],
[
2,
0,
4,
1,
6,
"CONDITIONING"
],
[
3,
0,
4,
2,
7,
"CONDITIONING"
],
[
0,
0,
4,
3,
5,
"LATENT"
],
[
4,
0,
5,
0,
3,
"LATENT"
],
[
1,
2,
5,
1,
4,
"VAE"
],
[
5,
0,
6,
0,
8,
"IMAGE"
]
[1, 1, 2, 0, 4, "CLIP"],
[1, 1, 3, 0, 4, "CLIP"],
[1, 0, 4, 0, 4, "MODEL"],
[2, 0, 4, 1, 6, "CONDITIONING"],
[3, 0, 4, 2, 7, "CONDITIONING"],
[0, 0, 4, 3, 5, "LATENT"],
[4, 0, 5, 0, 3, "LATENT"],
[1, 2, 5, 1, 4, "VAE"],
[5, 0, 6, 0, 8, "IMAGE"]
],
"external": []
}

View File

@@ -235,15 +235,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
],
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1],
"index": 1
}
],

View File

@@ -48,15 +48,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": 3,
@@ -104,15 +96,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": 1,
@@ -160,15 +144,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
}
],
"links": [],
@@ -177,10 +153,7 @@
"id": 0,
"title": "Group",
"bounding": [
406.9701232910156,
59.079444885253906,
335,
345.6000061035156
406.9701232910156, 59.079444885253906, 335, 345.6000061035156
],
"color": "#3f789e",
"font_size": 24,
@@ -190,10 +163,7 @@
"id": 3,
"title": "Group Parent",
"bounding": [
796.9703979492188,
14.796443939208984,
355,
399.20001220703125
796.9703979492188, 14.796443939208984, 355, 399.20001220703125
],
"color": "#3f789e",
"font_size": 24,
@@ -203,10 +173,7 @@
"id": 2,
"title": "Group Child",
"bounding": [
806.9703979492188,
58.39643096923828,
335,
345.6000061035156
806.9703979492188, 58.39643096923828, 335, 345.6000061035156
],
"color": "#3f789e",
"font_size": 24,
@@ -217,11 +184,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 17,
"type": "VAEDecode",
"pos": [
318.8446183157076,
355.3961392345528
],
"size": [
225,
102
],
"pos": [318.8446183157076, 355.3961392345528],
"size": [225, 102],
"flags": {},
"order": 0,
"mode": 0,
@@ -49,9 +43,7 @@
"id": 4,
"title": "Outer Group",
"bounding": [
-46.25245366331014,
-150.82497138023245,
1034.4034361963616,
-46.25245366331014, -150.82497138023245, 1034.4034361963616,
1007.338460439933
],
"color": "#3f789e",
@@ -62,9 +54,7 @@
"id": 3,
"title": "Inner Group",
"bounding": [
80.96059074101554,
28.123757436778178,
718.286373661183,
80.96059074101554, 28.123757436778178, 718.286373661183,
691.2397164539732
],
"color": "#3f789e",
@@ -76,10 +66,7 @@
"extra": {
"ds": {
"scale": 0.7121393732101533,
"offset": [
289.18242848011835,
367.0747755524199
]
"offset": [289.18242848011835, 367.0747755524199]
},
"frontendVersion": "1.35.5",
"VHS_latentpreview": false,
@@ -89,4 +76,4 @@
"workflowRendererVersion": "Vue"
},
"version": 0.4
}
}

View File

@@ -5,14 +5,8 @@
{
"id": 3,
"type": "KSampler",
"pos": [
37,
98
],
"size": [
315,
262
],
"pos": [37, 98],
"size": [315, 262],
"flags": {},
"order": 0,
"mode": 0,
@@ -65,12 +59,7 @@
{
"id": 1,
"title": "Group",
"bounding": [
23,
23,
900,
825
],
"bounding": [23, 23, 900, 825],
"color": "#3f789e",
"font_size": 24,
"flags": {}
@@ -80,11 +69,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -64,12 +64,7 @@
"groups": [
{
"title": "Group",
"bounding": [
0,
0,
335,
346
],
"bounding": [0, 0, 335, 346],
"color": "#3f789e",
"font_size": 24
}
@@ -78,11 +73,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -6,12 +6,7 @@
"groups": [
{
"title": "Group",
"bounding": [
0,
0,
335,
346
],
"bounding": [0, 0, 335, 346],
"color": "#3f789e",
"font_size": 24
}
@@ -20,11 +15,8 @@
"extra": {
"ds": {
"scale": 1.2100000000000006,
"offset": [
104.34159172650945,
241.35965953210126
]
"offset": [104.34159172650945, 241.35965953210126]
}
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 6,
"type": "DevToolsNodeWithDefaultInput",
"pos": [
8.39722728729248,
29.727279663085938
],
"size": [
315,
82
],
"pos": [8.39722728729248, 29.727279663085938],
"size": [315, 82],
"flags": {},
"order": 0,
"mode": 0,
@@ -30,11 +24,7 @@
"properties": {
"Node name for S&R": "DevToolsNodeWithDefaultInput"
},
"widgets_values": [
0,
1,
0
]
"widgets_values": [0, 1, 0]
}
],
"links": [],
@@ -43,10 +33,7 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4

View File

@@ -5,10 +5,7 @@
{
"id": 3,
"type": "KSampler",
"pos": [
0,
30
],
"pos": [0, 30],
"size": {
"0": 315,
"1": 262
@@ -36,7 +33,7 @@
"name": "latent_image",
"type": "LATENT",
"link": null
} ,
},
{
"name": "dynamic_input",
"type": "FLOAT",
@@ -72,11 +69,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -39,11 +39,7 @@
"properties": {
"Node name for S&R": "DevToolsNodeWithForceInput"
},
"widgets_values": [
0,
1,
0
]
"widgets_values": [0, 1, 0]
}
],
"links": [],
@@ -52,11 +48,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -9,10 +9,7 @@
"0": 449,
"1": 204
},
"size": [
340.20001220703125,
166
],
"size": [340.20001220703125, 166],
"flags": {},
"order": 1,
"mode": 0,
@@ -61,11 +58,7 @@
"properties": {
"Node name for S&R": "ControlNetApplyAdvanced"
},
"widgets_values": [
1,
0,
1
]
"widgets_values": [1, 0, 1]
},
{
"id": 2,
@@ -74,10 +67,7 @@
"0": 177,
"1": 265
},
"size": [
210,
82
],
"size": [210, 82],
"flags": {},
"order": 0,
"mode": 0,
@@ -86,9 +76,7 @@
{
"name": "FLOAT",
"type": "FLOAT",
"links": [
1
],
"links": [1],
"widget": {
"name": "strength"
}
@@ -97,22 +85,10 @@
"properties": {
"Run widget replace on values": false
},
"widgets_values": [
1,
"fixed"
]
"widgets_values": [1, "fixed"]
}
],
"links": [
[
1,
2,
0,
1,
4,
"FLOAT"
]
],
"links": [[1, 2, 0, 1, 4, "FLOAT"]],
"groups": [],
"config": {},
"extra": {
@@ -125,4 +101,4 @@
}
},
"version": 0.4
}
}

View File

@@ -29,9 +29,7 @@
"properties": {
"Node name for S&R": "DevToolsNodeWithOnlyOptionalInput"
},
"widgets_values": [
""
]
"widgets_values": [""]
}
],
"links": [],

View File

@@ -47,11 +47,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -46,11 +46,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -47,11 +47,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -5,14 +5,8 @@
{
"id": 15,
"type": "DevToolsRemoteWidgetNode",
"pos": [
495,
735
],
"size": [
315,
58
],
"pos": [495, 735],
"size": [315, 58],
"flags": {},
"order": 0,
"mode": 0,
@@ -27,9 +21,7 @@
"properties": {
"Node name for S&R": "DevToolsRemoteWidgetNode"
},
"widgets_values": [
"v1-5-pruned-emaonly-fp16.safetensors"
]
"widgets_values": ["v1-5-pruned-emaonly-fp16.safetensors"]
}
],
"links": [],
@@ -38,11 +30,8 @@
"extra": {
"ds": {
"scale": 0.8008869919566275,
"offset": [
538.9801226576359,
-55.24554581806672
]
"offset": [538.9801226576359, -55.24554581806672]
}
},
"version": 0.4
}
}

View File

@@ -5,14 +5,8 @@
{
"id": 3,
"type": "EmptyLatentImage",
"pos": [
380.51641845703125,
191.39659118652344
],
"size": [
315,
106
],
"pos": [380.51641845703125, 191.39659118652344],
"size": [315, 106],
"flags": {},
"order": 1,
"mode": 0,
@@ -36,23 +30,13 @@
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
"widgets_values": [512, 512, 1]
},
{
"id": 4,
"type": "PrimitiveNode",
"pos": [
73.6164321899414,
197.9966278076172
],
"size": [
210,
82
],
"pos": [73.6164321899414, 197.9966278076172],
"size": [210, 82],
"flags": {},
"order": 0,
"mode": 0,
@@ -64,31 +48,17 @@
"widget": {
"name": "bredth"
},
"links": [
2
]
"links": [2]
}
],
"title": "breadth",
"properties": {
"Run widget replace on values": false
},
"widgets_values": [
512,
"fixed"
]
"widgets_values": [512, "fixed"]
}
],
"links": [
[
2,
4,
0,
3,
0,
"INT"
]
],
"links": [[2, 4, 0, 3, 0, "INT"]],
"groups": [],
"config": {},
"extra": {

View File

@@ -5,14 +5,8 @@
{
"id": 12,
"type": "DevToolsSimpleSlider",
"pos": [
50,
50
],
"size": [
315,
58
],
"pos": [50, 50],
"size": [315, 58],
"flags": {},
"order": 0,
"mode": 0,
@@ -28,9 +22,7 @@
"properties": {
"Node name for S&R": "DevToolsSimpleSlider"
},
"widgets_values": [
0.5
]
"widgets_values": [0.5]
}
],
"links": [],
@@ -39,11 +31,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -5,14 +5,8 @@
{
"id": 1,
"type": "DevToolsNodeWithStringInput",
"pos": [
15,
48
],
"size": [
315,
58
],
"pos": [15, 48],
"size": [315, 58],
"flags": {},
"order": 0,
"mode": 0,
@@ -21,9 +15,7 @@
"properties": {
"Node name for S&R": "DevToolsNodeWithStringInput"
},
"widgets_values": [
""
]
"widgets_values": [""]
}
],
"links": [],
@@ -32,11 +24,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 4,
"type": "KSampler",
"pos": [
867.4669799804688,
347.22369384765625
],
"size": [
315,
262
],
"pos": [867.4669799804688, 347.22369384765625],
"size": [315, 262],
"flags": {},
"order": 1,
"mode": 0,
@@ -58,27 +52,13 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": 5,
"type": "PrimitiveInt",
"pos": [
443.0852355957031,
441.131591796875
],
"size": [
315,
82
],
"pos": [443.0852355957031, 441.131591796875],
"size": [315, 82],
"flags": {},
"order": 0,
"mode": 0,
@@ -87,40 +67,23 @@
{
"name": "INT",
"type": "INT",
"links": [
3
]
"links": [3]
}
],
"properties": {
"Node name for S&R": "PrimitiveInt"
},
"widgets_values": [
0,
"randomize"
]
"widgets_values": [0, "randomize"]
}
],
"links": [
[
3,
5,
0,
4,
5,
"INT"
]
],
"links": [[3, 5, 0, 4, 5, "INT"]],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1.9487171000000016,
"offset": [
-325.57196748514497,
-168.13150517966463
]
"offset": [-325.57196748514497, -168.13150517966463]
}
},
"version": 0.4
}
}

View File

@@ -5,10 +5,7 @@
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
0,
92
],
"pos": [0, 92],
"size": {
"0": 315,
"1": 98
@@ -26,10 +23,7 @@
{
"name": "CLIP",
"type": "CLIP",
"links": [
3,
5
],
"links": [3, 5],
"slot_index": 1
},
{
@@ -42,17 +36,12 @@
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"3Guofeng3_v32Light.safetensors"
]
"widgets_values": ["3Guofeng3_v32Light.safetensors"]
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
460,
92
],
"pos": [460, 92],
"size": {
"0": 422.84503173828125,
"1": 164.31304931640625
@@ -85,10 +74,7 @@
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
460,
368
],
"pos": [460, 368],
"size": {
"0": 425.27801513671875,
"1": 180.6060791015625
@@ -114,17 +100,12 @@
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
"widgets_values": ["text, watermark"]
},
{
"id": 10,
"type": "CheckpointLoaderSimple",
"pos": [
0,
276
],
"pos": [0, 276],
"size": {
"0": 315,
"1": 98
@@ -155,39 +136,20 @@
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"3Guofeng3_v32Light.safetensors"
]
"widgets_values": ["3Guofeng3_v32Light.safetensors"]
}
],
"links": [
[
3,
4,
1,
6,
0,
"CLIP"
],
[
5,
4,
1,
7,
0,
"CLIP"
]
[3, 4, 1, 6, 0, "CLIP"],
[5, 4, 1, 7, 0, "CLIP"]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -5,10 +5,7 @@
{
"id": 1,
"type": "KSampler",
"pos": [
590,
40
],
"pos": [590, 40],
"size": {
"0": 315,
"1": 262
@@ -53,23 +50,12 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": 4,
"type": "CLIPTextEncode",
"pos": [
20,
50
],
"pos": [20, 50],
"size": {
"0": 400,
"1": 200
@@ -88,26 +74,19 @@
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
3
],
"links": [3],
"shape": 3
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
]
"widgets_values": [""]
},
{
"id": 5,
"type": "CLIPTextEncode",
"pos": [
20,
320
],
"pos": [20, 320],
"size": {
"0": 400,
"1": 200
@@ -134,31 +113,17 @@
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
]
"widgets_values": [""]
}
],
"links": [
[
3,
4,
0,
1,
1,
"CONDITIONING"
]
],
"links": [[3, 4, 0, 1, 1, "CONDITIONING"]],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -8,10 +8,7 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"models": [
@@ -22,4 +19,4 @@
}
],
"version": 0.4
}
}

View File

@@ -5,10 +5,7 @@
{
"id": 1,
"type": "UNKNOWN NODE",
"pos": [
48,
86
],
"pos": [48, 86],
"size": {
"0": 358.80780029296875,
"1": 314.7989501953125
@@ -36,14 +33,7 @@
"properties": {
"Node name for S&R": "UNKNOWN NODE"
},
"widgets_values": [
"wd-v1-4-moat-tagger-v2",
0.35,
0.85,
false,
false,
""
]
"widgets_values": ["wd-v1-4-moat-tagger-v2", 0.35, 0.85, false, false, ""]
}
],
"links": [],
@@ -52,10 +42,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0, 0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -5,10 +5,7 @@
{
"id": 1,
"type": "UNKNOWN NODE",
"pos": [
48,
86
],
"pos": [48, 86],
"size": {
"0": 358.80780029296875,
"1": 314.7989501953125

View File

@@ -179,4 +179,4 @@
}
},
"version": 0.4
}
}

View File

@@ -42,9 +42,7 @@
{
"name": "LATENT",
"type": "LATENT",
"links": [
7
],
"links": [7],
"slot_index": 0
}
],
@@ -82,35 +80,26 @@
{
"name": "MODEL",
"type": "MODEL",
"links": [
1
],
"links": [1],
"slot_index": 0
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
3,
5
],
"links": [3, 5],
"slot_index": 1
},
{
"name": "VAE",
"type": "VAE",
"links": [
8
],
"links": [8],
"slot_index": 2
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"Stable-diffusion/v1-5-pruned-emaonly.safetensors"
],
"widgets_values": ["Stable-diffusion/v1-5-pruned-emaonly.safetensors"],
"color": "#322",
"bgcolor": "#533"
},
@@ -133,20 +122,14 @@
{
"name": "LATENT",
"type": "LATENT",
"links": [
2
],
"links": [2],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
],
"widgets_values": [512, 512, 1],
"color": "#323",
"bgcolor": "#535"
},
@@ -175,9 +158,7 @@
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
4
],
"links": [4],
"slot_index": 0
}
],
@@ -215,18 +196,14 @@
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
6
],
"links": [6],
"slot_index": 0
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
],
"widgets_values": ["text, watermark"],
"color": "#323",
"bgcolor": "#535"
},
@@ -260,9 +237,7 @@
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
9
],
"links": [9],
"slot_index": 0
}
],
@@ -280,10 +255,7 @@
"0": 857,
"1": 611
},
"size": [
214.2000732421875,
59.4000244140625
],
"size": [214.2000732421875, 59.4000244140625],
"flags": {},
"order": 9,
"mode": 0,
@@ -296,9 +268,7 @@
],
"outputs": [],
"properties": {},
"widgets_values": [
"ComfyUI"
]
"widgets_values": ["ComfyUI"]
},
{
"id": 10,
@@ -335,9 +305,7 @@
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"Stable-diffusion/v1-5-pruned-emaonly.safetensors"
],
"widgets_values": ["Stable-diffusion/v1-5-pruned-emaonly.safetensors"],
"color": "#332922",
"bgcolor": "#593930"
},
@@ -376,9 +344,7 @@
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"Stable-diffusion/v1-5-pruned-emaonly.safetensors"
],
"widgets_values": ["Stable-diffusion/v1-5-pruned-emaonly.safetensors"],
"color": "#223",
"bgcolor": "#335"
},
@@ -413,89 +379,21 @@
"properties": {
"Node name for S&R": "ImageScale"
},
"widgets_values": [
"nearest-exact",
512,
512,
"disabled"
],
"widgets_values": ["nearest-exact", 512, 512, "disabled"],
"color": "#2a363b",
"bgcolor": "#3f5159"
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
3,
4,
1,
6,
0,
"CLIP"
],
[
4,
6,
0,
3,
1,
"CONDITIONING"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
],
[
9,
8,
0,
9,
0,
"IMAGE"
]
[1, 4, 0, 3, 0, "MODEL"],
[2, 5, 0, 3, 3, "LATENT"],
[3, 4, 1, 6, 0, "CLIP"],
[4, 6, 0, 3, 1, "CONDITIONING"],
[5, 4, 1, 7, 0, "CLIP"],
[6, 7, 0, 3, 2, "CONDITIONING"],
[7, 3, 0, 8, 0, "LATENT"],
[8, 4, 2, 8, 1, "VAE"],
[9, 8, 0, 9, 0, "IMAGE"]
],
"groups": [],
"config": {},

View File

@@ -47,9 +47,7 @@
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
15
],
"links": [15],
"slot_index": 0,
"shape": 3
}
@@ -59,26 +57,14 @@
}
}
],
"links": [
[
15,
17,
0,
14,
0,
"IMAGE"
]
],
"links": [[15, 17, 0, 14, 0, "IMAGE"]],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1,
"offset": [
117.20766722169206,
472.69035116826046
]
"offset": [117.20766722169206, 472.69035116826046]
}
},
"version": 0.4
}
}

View File

@@ -5,44 +5,30 @@
{
"id": 1,
"type": "Note",
"pos": [
50, 50
],
"size": [
322.3645935058594,
167.91612243652344
],
"pos": [50, 50],
"size": [322.3645935058594, 167.91612243652344],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"Foo\n123"
],
"widgets_values": ["Foo\n123"],
"color": "#432",
"bgcolor": "#653"
},
{
"id": 2,
"type": "MarkdownNote",
"pos": [
50, 300
],
"size": [
320.9985656738281,
179.52735900878906
],
"pos": [50, 300],
"size": [320.9985656738281, 179.52735900878906],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {},
"widgets_values": [
"# Bar\n123"
],
"widgets_values": ["# Bar\n123"],
"color": "#432",
"bgcolor": "#653"
}

View File

@@ -5,10 +5,7 @@
{
"id": 3,
"type": "KSampler",
"pos": [
0,
30
],
"pos": [0, 30],
"size": {
"0": 315,
"1": 262
@@ -66,11 +63,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -25,9 +25,7 @@
],
"outputs": [],
"properties": {},
"widgets_values": [
"ComfyUI"
]
"widgets_values": ["ComfyUI"]
}
],
"links": [],
@@ -36,11 +34,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -21,35 +21,26 @@
{
"name": "MODEL",
"type": "MODEL",
"links": [
12
],
"links": [12],
"shape": 3
},
{
"name": "CLIP",
"type": "CLIP",
"links": [
10,
11
],
"links": [10, 11],
"shape": 3
},
{
"name": "VAE",
"type": "VAE",
"links": [
17
],
"links": [17],
"shape": 3
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly.ckpt"
]
"widgets_values": ["v1-5-pruned-emaonly.ckpt"]
},
{
"id": "CLIPTextEncode.0",
@@ -76,9 +67,7 @@
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
13
],
"links": [13],
"shape": 3
}
],
@@ -114,18 +103,14 @@
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
14
],
"links": [14],
"shape": 3
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
"widgets_values": ["text, watermark"]
},
{
"id": "EmptyLatentImage.0",
@@ -146,20 +131,14 @@
{
"name": "LATENT",
"type": "LATENT",
"links": [
15
],
"links": [15],
"shape": 3
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
"widgets_values": [512, 512, 1]
},
{
"id": "KSampler.0",
@@ -201,24 +180,14 @@
{
"name": "LATENT",
"type": "LATENT",
"links": [
16
],
"links": [16],
"shape": 3
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
3,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [3, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": "VAEDecode.0",
@@ -250,9 +219,7 @@
{
"name": "IMAGE",
"type": "IMAGE",
"links": [
18
],
"links": [18],
"shape": 3
}
],
@@ -283,94 +250,26 @@
],
"outputs": [],
"properties": {},
"widgets_values": [
"ComfyUI"
]
"widgets_values": ["ComfyUI"]
}
],
"links": [
[
10,
"CheckpointLoaderSimple.0",
1,
"CLIPTextEncode.0",
0,
"CLIP"
],
[
11,
"CheckpointLoaderSimple.0",
1,
"CLIPTextEncode.1",
0,
"CLIP"
],
[
12,
"CheckpointLoaderSimple.0",
0,
"KSampler.0",
0,
"MODEL"
],
[
13,
"CLIPTextEncode.0",
0,
"KSampler.0",
1,
"CONDITIONING"
],
[
14,
"CLIPTextEncode.1",
0,
"KSampler.0",
2,
"CONDITIONING"
],
[
15,
"EmptyLatentImage.0",
0,
"KSampler.0",
3,
"LATENT"
],
[
16,
"KSampler.0",
0,
"VAEDecode.0",
0,
"LATENT"
],
[
17,
"CheckpointLoaderSimple.0",
2,
"VAEDecode.0",
1,
"VAE"
],
[
18,
"VAEDecode.0",
0,
"SaveImage.0",
0,
"IMAGE"
]
[10, "CheckpointLoaderSimple.0", 1, "CLIPTextEncode.0", 0, "CLIP"],
[11, "CheckpointLoaderSimple.0", 1, "CLIPTextEncode.1", 0, "CLIP"],
[12, "CheckpointLoaderSimple.0", 0, "KSampler.0", 0, "MODEL"],
[13, "CLIPTextEncode.0", 0, "KSampler.0", 1, "CONDITIONING"],
[14, "CLIPTextEncode.1", 0, "KSampler.0", 2, "CONDITIONING"],
[15, "EmptyLatentImage.0", 0, "KSampler.0", 3, "LATENT"],
[16, "KSampler.0", 0, "VAEDecode.0", 0, "LATENT"],
[17, "CheckpointLoaderSimple.0", 2, "VAEDecode.0", 1, "VAE"],
[18, "VAEDecode.0", 0, "SaveImage.0", 0, "IMAGE"]
],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4

View File

@@ -65,15 +65,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": 1,
@@ -90,10 +82,7 @@
"8": 0,
"9": 0
},
"size": [
446.96645387135936,
108.34243389566905
],
"size": [446.96645387135936, 108.34243389566905],
"flags": {},
"order": 0,
"mode": 0,
@@ -102,9 +91,7 @@
{
"name": "INT",
"type": "INT",
"links": [
1
],
"links": [1],
"slot_index": 0,
"widget": {
"name": "steps"
@@ -114,32 +101,17 @@
"properties": {
"Run widget replace on values": false
},
"widgets_values": [
20,
"fixed"
]
"widgets_values": [20, "fixed"]
}
],
"links": [
[
1,
1,
0,
2,
4,
"INT"
]
],
"links": [[1, 1, 0, 2, 4, "INT"]],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -9,10 +9,7 @@
"0": 304.3653259277344,
"1": 42.15586471557617
},
"size": [
315,
262
],
"size": [315, 262],
"flags": {},
"order": 0,
"mode": 0,
@@ -49,15 +46,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": 1,
@@ -66,10 +55,7 @@
"0": 14,
"1": 43
},
"size": [
203.1999969482422,
40.368401303242536
],
"size": [203.1999969482422, 40.368401303242536],
"flags": {},
"order": 1,
"mode": 0,
@@ -94,11 +80,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -9,10 +9,7 @@
"0": 304.3653259277344,
"1": 42.15586471557617
},
"size": [
315,
262
],
"size": [315, 262],
"flags": {},
"order": 0,
"mode": 0,
@@ -49,15 +46,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"normal",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "normal", 1]
},
{
"id": 1,
@@ -66,10 +55,7 @@
"0": 14,
"1": 43
},
"size": [
203.1999969482422,
40.368401303242536
],
"size": [203.1999969482422, 40.368401303242536],
"flags": {},
"order": 1,
"mode": 0,
@@ -94,11 +80,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 2,
"type": "e5fb1765-9323-4548-801a-5aead34d879e",
"pos": [
627.5973510742188,
423.0972900390625
],
"size": [
144.15234375,
46
],
"pos": [627.5973510742188, 423.0972900390625],
"size": [144.15234375, 46],
"flags": {},
"order": 0,
"mode": 0,
@@ -54,30 +48,18 @@
"name": "New Subgraph",
"inputNode": {
"id": -10,
"bounding": [
347.90441582814213,
417.3822440655296,
120,
60
]
"bounding": [347.90441582814213, 417.3822440655296, 120, 60]
},
"outputNode": {
"id": -20,
"bounding": [
892.5973510742188,
416.0972900390625,
120,
60
]
"bounding": [892.5973510742188, 416.0972900390625, 120, 60]
},
"inputs": [
{
"id": "c5cc99d8-a2b6-4bf3-8be7-d4949ef736cd",
"name": "positive",
"type": "CONDITIONING",
"linkIds": [
1
],
"linkIds": [1],
"pos": {
"0": 447.9044189453125,
"1": 437.3822326660156
@@ -89,9 +71,7 @@
"id": "9bd488b9-e907-4c95-a7a4-85c5597a87af",
"name": "LATENT",
"type": "LATENT",
"linkIds": [
2
],
"linkIds": [2],
"pos": {
"0": 912.5973510742188,
"1": 436.0972900390625
@@ -103,14 +83,8 @@
{
"id": 1,
"type": "KSampler",
"pos": [
554.8743286132812,
100.95539093017578
],
"size": [
270,
262
],
"pos": [554.8743286132812, 100.95539093017578],
"size": [270, 262],
"flags": {},
"order": 1,
"mode": 0,
@@ -145,35 +119,19 @@
"localized_name": "LATENT",
"name": "LATENT",
"type": "LATENT",
"links": [
2
]
"links": [2]
}
],
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"simple",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "simple", 1]
},
{
"id": 2,
"type": "VAEEncode",
"pos": [
685.1265869140625,
439.1734619140625
],
"size": [
140,
46
],
"pos": [685.1265869140625, 439.1734619140625],
"size": [140, 46],
"flags": {},
"order": 0,
"mode": 0,
@@ -196,9 +154,7 @@
"localized_name": "LATENT",
"name": "LATENT",
"type": "LATENT",
"links": [
4
]
"links": [4]
}
],
"properties": {
@@ -233,12 +189,9 @@
"extra": {
"ds": {
"scale": 0.8894351682943402,
"offset": [
58.7671207025881,
137.7124650620126
]
"offset": [58.7671207025881, 137.7124650620126]
},
"frontendVersion": "1.24.1"
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 10,
"type": "8beb610f-ddd1-4489-ae0d-2f732a4042ae",
"pos": [
532,
412.5
],
"size": [
140,
46
],
"pos": [532, 412.5],
"size": [140, 46],
"flags": {},
"order": 0,
"mode": 0,
@@ -23,16 +17,12 @@
{
"name": "LATENT",
"type": "LATENT",
"links": [
10
]
"links": [10]
},
{
"name": "VAE",
"type": "VAE",
"links": [
11
]
"links": [11]
}
],
"title": "subgraph 2",
@@ -42,14 +32,8 @@
{
"id": 8,
"type": "VAEDecode",
"pos": [
758.2109985351562,
398.3681335449219
],
"size": [
210,
46
],
"pos": [758.2109985351562, 398.3681335449219],
"size": [210, 46],
"flags": {},
"order": 1,
"mode": 0,
@@ -70,9 +54,7 @@
"name": "IMAGE",
"type": "IMAGE",
"slot_index": 0,
"links": [
9
]
"links": [9]
}
],
"properties": {
@@ -83,14 +65,8 @@
{
"id": 9,
"type": "SaveImage",
"pos": [
1028.9615478515625,
381.83746337890625
],
"size": [
210,
270
],
"pos": [1028.9615478515625, 381.83746337890625],
"size": [210, 270],
"flags": {},
"order": 2,
"mode": 0,
@@ -103,36 +79,13 @@
],
"outputs": [],
"properties": {},
"widgets_values": [
"ComfyUI"
]
"widgets_values": ["ComfyUI"]
}
],
"links": [
[
9,
8,
0,
9,
0,
"IMAGE"
],
[
10,
10,
0,
8,
0,
"LATENT"
],
[
11,
10,
1,
8,
1,
"VAE"
]
[9, 8, 0, 9, 0, "IMAGE"],
[10, 10, 0, 8, 0, "LATENT"],
[11, 10, 1, 8, 1, "VAE"]
],
"groups": [],
"definitions": {
@@ -151,21 +104,11 @@
"name": "subgraph 2",
"inputNode": {
"id": -10,
"bounding": [
-154,
415.5,
120,
40
]
"bounding": [-154, 415.5, 120, 40]
},
"outputNode": {
"id": -20,
"bounding": [
1238,
395.5,
120,
80
]
"bounding": [1238, 395.5, 120, 80]
},
"inputs": [],
"outputs": [
@@ -173,9 +116,7 @@
"id": "4d6c7e4e-971e-4f78-9218-9a604db53a4b",
"name": "LATENT",
"type": "LATENT",
"linkIds": [
7
],
"linkIds": [7],
"localized_name": "LATENT",
"pos": {
"0": 1258,
@@ -186,9 +127,7 @@
"id": "f8201d4f-7fc6-4a1b-b8c9-9f0716d9c09a",
"name": "VAE",
"type": "VAE",
"linkIds": [
14
],
"linkIds": [14],
"localized_name": "VAE",
"pos": {
"0": 1258,
@@ -201,14 +140,8 @@
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
415,
186
],
"size": [
422.84503173828125,
164.31304931640625
],
"pos": [415, 186],
"size": [422.84503173828125, 164.31304931640625],
"flags": {},
"order": 0,
"mode": 0,
@@ -226,9 +159,7 @@
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
4
]
"links": [4]
}
],
"properties": {
@@ -241,14 +172,8 @@
{
"id": 3,
"type": "KSampler",
"pos": [
863,
186
],
"size": [
315,
262
],
"pos": [863, 186],
"size": [315, 262],
"flags": {},
"order": 2,
"mode": 0,
@@ -284,9 +209,7 @@
"name": "LATENT",
"type": "LATENT",
"slot_index": 0,
"links": [
7
]
"links": [7]
}
],
"properties": {
@@ -305,14 +228,8 @@
{
"id": 10,
"type": "dbe5763f-440b-47b4-82ac-454f1f98b0e3",
"pos": [
194.13900756835938,
657.3333740234375
],
"size": [
140,
106
],
"pos": [194.13900756835938, 657.3333740234375],
"size": [140, 106],
"flags": {},
"order": 1,
"mode": 0,
@@ -322,41 +239,31 @@
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
10
]
"links": [10]
},
{
"localized_name": "LATENT",
"name": "LATENT",
"type": "LATENT",
"links": [
11
]
"links": [11]
},
{
"localized_name": "MODEL",
"name": "MODEL",
"type": "MODEL",
"links": [
12
]
"links": [12]
},
{
"localized_name": "CLIP",
"name": "CLIP",
"type": "CLIP",
"links": [
13
]
"links": [13]
},
{
"localized_name": "VAE",
"name": "VAE",
"type": "VAE",
"links": [
14
]
"links": [14]
}
],
"title": "subgraph 3",
@@ -439,21 +346,11 @@
"name": "subgraph 3",
"inputNode": {
"id": -10,
"bounding": [
-154,
517,
120,
40
]
"bounding": [-154, 517, 120, 40]
},
"outputNode": {
"id": -20,
"bounding": [
898.2780151367188,
467,
128.6640625,
140
]
"bounding": [898.2780151367188, 467, 128.6640625, 140]
},
"inputs": [],
"outputs": [
@@ -461,9 +358,7 @@
"id": "b4882169-329b-43f6-a373-81abfbdea55b",
"name": "CONDITIONING",
"type": "CONDITIONING",
"linkIds": [
6
],
"linkIds": [6],
"localized_name": "CONDITIONING",
"pos": {
"0": 918.2780151367188,
@@ -474,9 +369,7 @@
"id": "01f51f96-a741-428e-8772-9557ee50b609",
"name": "LATENT",
"type": "LATENT",
"linkIds": [
2
],
"linkIds": [2],
"localized_name": "LATENT",
"pos": {
"0": 918.2780151367188,
@@ -487,9 +380,7 @@
"id": "47fa906e-d80b-45c3-a596-211a0e59d4a1",
"name": "MODEL",
"type": "MODEL",
"linkIds": [
1
],
"linkIds": [1],
"localized_name": "MODEL",
"pos": {
"0": 918.2780151367188,
@@ -500,9 +391,7 @@
"id": "f03dccd7-10e8-4513-9994-15854a92d192",
"name": "CLIP",
"type": "CLIP",
"linkIds": [
3
],
"linkIds": [3],
"localized_name": "CLIP",
"pos": {
"0": 918.2780151367188,
@@ -513,9 +402,7 @@
"id": "a666877f-e34f-49bc-8a78-b26156656b83",
"name": "VAE",
"type": "VAE",
"linkIds": [
8
],
"linkIds": [8],
"localized_name": "VAE",
"pos": {
"0": 918.2780151367188,
@@ -528,14 +415,8 @@
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
413,
389
],
"size": [
425.27801513671875,
180.6060791015625
],
"pos": [413, 389],
"size": [425.27801513671875, 180.6060791015625],
"flags": {},
"order": 2,
"mode": 0,
@@ -553,29 +434,19 @@
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
6
]
"links": [6]
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
"text, watermark"
]
"widgets_values": ["text, watermark"]
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
473,
609
],
"size": [
315,
106
],
"pos": [473, 609],
"size": [315, 106],
"flags": {},
"order": 0,
"mode": 0,
@@ -586,31 +457,19 @@
"name": "LATENT",
"type": "LATENT",
"slot_index": 0,
"links": [
2
]
"links": [2]
}
],
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
"widgets_values": [512, 512, 1]
},
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
26,
474
],
"size": [
315,
98
],
"pos": [26, 474],
"size": [315, 98],
"flags": {},
"order": 1,
"mode": 0,
@@ -621,36 +480,27 @@
"name": "MODEL",
"type": "MODEL",
"slot_index": 0,
"links": [
1
]
"links": [1]
},
{
"localized_name": "CLIP",
"name": "CLIP",
"type": "CLIP",
"slot_index": 1,
"links": [
3,
5
]
"links": [3, 5]
},
{
"localized_name": "VAE",
"name": "VAE",
"type": "VAE",
"slot_index": 2,
"links": [
8
]
"links": [8]
}
],
"properties": {
"Node name for S&R": "CheckpointLoaderSimple"
},
"widgets_values": [
"v1-5-pruned-emaonly-fp16.safetensors"
]
"widgets_values": ["v1-5-pruned-emaonly-fp16.safetensors"]
}
],
"groups": [],
@@ -713,4 +563,4 @@
"frontendVersion": "1.24.0-1"
},
"version": 0.4
}
}

View File

@@ -7,30 +7,17 @@
{
"id": 2,
"type": "8bfe4227-f272-49e1-a892-0a972a86867c",
"pos": [
-317,
-336
],
"size": [
210,
58
],
"pos": [-317, -336],
"size": [210, 58],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [],
"outputs": [],
"properties": {
"proxyWidgets": [
[
"-1",
"batch_size"
]
]
"proxyWidgets": [["-1", "batch_size"]]
},
"widgets_values": [
1
]
"widgets_values": [1]
}
],
"links": [],
@@ -51,34 +38,19 @@
"name": "New Subgraph",
"inputNode": {
"id": -10,
"bounding": [
-562,
-358,
120,
60
]
"bounding": [-562, -358, 120, 60]
},
"outputNode": {
"id": -20,
"bounding": [
-52,
-358,
120,
40
]
"bounding": [-52, -358, 120, 40]
},
"inputs": [
{
"id": "b4a8bc2a-8e9f-41aa-938d-c567a11d2c00",
"name": "batch_size",
"type": "INT",
"linkIds": [
1
],
"pos": [
-462,
-338
]
"linkIds": [1],
"pos": [-462, -338]
}
],
"outputs": [],
@@ -87,14 +59,8 @@
{
"id": 1,
"type": "EmptyLatentImage",
"pos": [
-382,
-376
],
"size": [
270,
106
],
"pos": [-382, -376],
"size": [270, 106],
"flags": {},
"order": 0,
"mode": 0,
@@ -120,11 +86,7 @@
"properties": {
"Node name for S&R": "EmptyLatentImage"
},
"widgets_values": [
512,
512,
1
]
"widgets_values": [512, 512, 1]
}
],
"groups": [],
@@ -147,4 +109,4 @@
"frontendVersion": "1.35.1"
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 11,
"type": "422723e8-4bf6-438c-823f-881ca81acead",
"pos": [
791.59912109375,
386.13336181640625
],
"size": [
210,
202
],
"pos": [791.59912109375, 386.13336181640625],
"size": [210, 202],
"flags": {},
"order": 0,
"mode": 0,
@@ -48,10 +42,7 @@
}
],
"properties": {},
"widgets_values": [
"",
""
]
"widgets_values": ["", ""]
}
],
"links": [],
@@ -72,30 +63,18 @@
"name": "New Subgraph",
"inputNode": {
"id": -10,
"bounding": [
481.59912109375,
379.13336181640625,
120,
160
]
"bounding": [481.59912109375, 379.13336181640625, 120, 160]
},
"outputNode": {
"id": -20,
"bounding": [
1121.59912109375,
379.13336181640625,
128.6640625,
60
]
"bounding": [1121.59912109375, 379.13336181640625, 128.6640625, 60]
},
"inputs": [
{
"id": "0f07c10e-5705-4764-9b24-b69606c6dbcc",
"name": "text",
"type": "STRING",
"linkIds": [
10
],
"linkIds": [10],
"pos": {
"0": 581.59912109375,
"1": 399.13336181640625
@@ -105,9 +84,7 @@
"id": "736e5a03-0f7f-4e48-93e4-fd66ea6c30f1",
"name": "text_1",
"type": "STRING",
"linkIds": [
11
],
"linkIds": [11],
"pos": {
"0": 581.59912109375,
"1": 419.13336181640625
@@ -117,9 +94,7 @@
"id": "b62e7a0b-cc7e-4ca5-a4e1-c81607a13f58",
"name": "model",
"type": "MODEL",
"linkIds": [
13
],
"linkIds": [13],
"pos": {
"0": 581.59912109375,
"1": 439.13336181640625
@@ -129,9 +104,7 @@
"id": "7a2628da-4879-4f82-a7d3-7b1c00db50a5",
"name": "positive",
"type": "CONDITIONING",
"linkIds": [
14
],
"linkIds": [14],
"pos": {
"0": 581.59912109375,
"1": 459.13336181640625
@@ -141,9 +114,7 @@
"id": "651cf4ad-e8bf-47f6-b181-8f8aeacd6669",
"name": "negative",
"type": "CONDITIONING",
"linkIds": [
15
],
"linkIds": [15],
"pos": {
"0": 581.59912109375,
"1": 479.13336181640625
@@ -153,9 +124,7 @@
"id": "c41765ea-61ef-4a77-8cc6-74113903078f",
"name": "latent_image",
"type": "LATENT",
"linkIds": [
16
],
"linkIds": [16],
"pos": {
"0": 581.59912109375,
"1": 499.13336181640625
@@ -167,9 +136,7 @@
"id": "55dd1505-12bd-4cb4-8e75-031a97bb4387",
"name": "CONDITIONING",
"type": "CONDITIONING",
"linkIds": [
12
],
"linkIds": [12],
"pos": {
"0": 1141.59912109375,
"1": 399.13336181640625
@@ -181,14 +148,8 @@
{
"id": 10,
"type": "CLIPTextEncode",
"pos": [
661.59912109375,
314.13336181640625
],
"size": [
400,
200
],
"pos": [661.59912109375, 314.13336181640625],
"size": [400, 200],
"flags": {},
"order": 1,
"mode": 0,
@@ -220,21 +181,13 @@
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
]
"widgets_values": [""]
},
{
"id": 11,
"type": "CLIPTextEncode",
"pos": [
668.755859375,
571.7766723632812
],
"size": [
400,
200
],
"pos": [668.755859375, 571.7766723632812],
"size": [400, 200],
"flags": {},
"order": 2,
"mode": 0,
@@ -260,29 +213,19 @@
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": [
12
]
"links": [12]
}
],
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
]
"widgets_values": [""]
},
{
"id": 12,
"type": "KSampler",
"pos": [
671.7379760742188,
1.621593713760376
],
"size": [
270,
262
],
"pos": [671.7379760742188, 1.621593713760376],
"size": [270, 262],
"flags": {},
"order": 0,
"mode": 0,
@@ -323,15 +266,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"simple",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "simple", 1]
}
],
"groups": [],
@@ -401,12 +336,9 @@
"extra": {
"ds": {
"scale": 0.9581355200690549,
"offset": [
184.687451089395,
80.38288288288285
]
"offset": [184.687451089395, 80.38288288288285]
},
"frontendVersion": "1.24.1"
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 11,
"type": "422723e8-4bf6-438c-823f-881ca81acead",
"pos": [
400,
300
],
"size": [
210,
168
],
"pos": [400, 300],
"size": [210, 168],
"flags": {},
"order": 0,
"mode": 0,
@@ -47,9 +41,7 @@
],
"outputs": [],
"properties": {},
"widgets_values": [
""
]
"widgets_values": [""]
}
],
"links": [],
@@ -70,30 +62,18 @@
"name": "New Subgraph",
"inputNode": {
"id": -10,
"bounding": [
481.59912109375,
379.13336181640625,
120,
160
]
"bounding": [481.59912109375, 379.13336181640625, 120, 160]
},
"outputNode": {
"id": -20,
"bounding": [
1121.59912109375,
379.13336181640625,
120,
40
]
"bounding": [1121.59912109375, 379.13336181640625, 120, 40]
},
"inputs": [
{
"id": "0f07c10e-5705-4764-9b24-b69606c6dbcc",
"name": "text",
"type": "STRING",
"linkIds": [
10
],
"linkIds": [10],
"pos": {
"0": 581.59912109375,
"1": 399.13336181640625
@@ -103,9 +83,7 @@
"id": "214a5060-24dd-4299-ab78-8027dc5b9c59",
"name": "clip",
"type": "CLIP",
"linkIds": [
11
],
"linkIds": [11],
"pos": {
"0": 581.59912109375,
"1": 419.13336181640625
@@ -115,9 +93,7 @@
"id": "8ab94c5d-e7df-433c-9177-482a32340552",
"name": "model",
"type": "MODEL",
"linkIds": [
12
],
"linkIds": [12],
"pos": {
"0": 581.59912109375,
"1": 439.13336181640625
@@ -127,9 +103,7 @@
"id": "8a4cd719-8c67-473b-9b44-ac0582d02641",
"name": "positive",
"type": "CONDITIONING",
"linkIds": [
13
],
"linkIds": [13],
"pos": {
"0": 581.59912109375,
"1": 459.13336181640625
@@ -139,9 +113,7 @@
"id": "a78d6b3a-ad40-4300-b0a5-2cdbdb8dc135",
"name": "negative",
"type": "CONDITIONING",
"linkIds": [
14
],
"linkIds": [14],
"pos": {
"0": 581.59912109375,
"1": 479.13336181640625
@@ -151,9 +123,7 @@
"id": "4c7abe0c-902d-49ef-a5b0-cbf02b50b693",
"name": "latent_image",
"type": "LATENT",
"linkIds": [
15
],
"linkIds": [15],
"pos": {
"0": 581.59912109375,
"1": 499.13336181640625
@@ -166,14 +136,8 @@
{
"id": 10,
"type": "CLIPTextEncode",
"pos": [
661.59912109375,
314.13336181640625
],
"size": [
400,
200
],
"pos": [661.59912109375, 314.13336181640625],
"size": [400, 200],
"flags": {},
"order": 1,
"mode": 0,
@@ -205,21 +169,13 @@
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
]
"widgets_values": [""]
},
{
"id": 11,
"type": "KSampler",
"pos": [
674.1234741210938,
570.5839233398438
],
"size": [
270,
262
],
"pos": [674.1234741210938, 570.5839233398438],
"size": [270, 262],
"flags": {},
"order": 0,
"mode": 0,
@@ -260,15 +216,7 @@
"properties": {
"Node name for S&R": "KSampler"
},
"widgets_values": [
0,
"randomize",
20,
8,
"euler",
"simple",
1
]
"widgets_values": [0, "randomize", 20, 8, "euler", "simple", 1]
}
],
"groups": [],
@@ -330,12 +278,9 @@
"extra": {
"ds": {
"scale": 0.9581355200690549,
"offset": [
258.6405769416877,
147.17927927927929
]
"offset": [258.6405769416877, 147.17927927927929]
},
"frontendVersion": "1.24.1"
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 11,
"type": "422723e8-4bf6-438c-823f-881ca81acead",
"pos": [
791.59912109375,
386.13336181640625
],
"size": [
140,
26
],
"pos": [791.59912109375, 386.13336181640625],
"size": [140, 26],
"flags": {},
"order": 0,
"mode": 0,
@@ -48,30 +42,18 @@
"name": "New Subgraph",
"inputNode": {
"id": -10,
"bounding": [
481.59912109375,
379.13336181640625,
120,
60
]
"bounding": [481.59912109375, 379.13336181640625, 120, 60]
},
"outputNode": {
"id": -20,
"bounding": [
1121.59912109375,
379.13336181640625,
120,
40
]
"bounding": [1121.59912109375, 379.13336181640625, 120, 40]
},
"inputs": [
{
"id": "79e69fca-ad12-499b-8d9b-9f1656b85354",
"name": "clip",
"type": "CLIP",
"linkIds": [
10
],
"linkIds": [10],
"pos": {
"0": 581.59912109375,
"1": 399.13336181640625
@@ -84,14 +66,8 @@
{
"id": 10,
"type": "CLIPTextEncode",
"pos": [
661.59912109375,
314.13336181640625
],
"size": [
400,
200
],
"pos": [661.59912109375, 314.13336181640625],
"size": [400, 200],
"flags": {},
"order": 0,
"mode": 0,
@@ -114,9 +90,7 @@
"properties": {
"Node name for S&R": "CLIPTextEncode"
},
"widgets_values": [
""
]
"widgets_values": [""]
}
],
"groups": [],
@@ -143,11 +117,8 @@
"VHS_KeepIntermediate": true,
"ds": {
"scale": 0.9581355200690549,
"offset": [
258.6405769416877,
147.17927927927929
]
"offset": [258.6405769416877, 147.17927927927929]
}
},
"version": 0.4
}
}

View File

@@ -7,14 +7,8 @@
{
"id": 4,
"type": "CheckpointLoaderSimple",
"pos": [
60,
200
],
"size": [
315,
98
],
"pos": [60, 200],
"size": [315, 98],
"flags": {},
"order": 0,
"mode": 0,
@@ -24,26 +18,19 @@
"name": "MODEL",
"type": "MODEL",
"slot_index": 0,
"links": [
1
]
"links": [1]
},
{
"name": "CLIP",
"type": "CLIP",
"slot_index": 1,
"links": [
3,
5
]
"links": [3, 5]
},
{
"name": "VAE",
"type": "VAE",
"slot_index": 2,
"links": [
8
]
"links": [8]
}
],
"properties": {
@@ -58,21 +45,13 @@
}
]
},
"widgets_values": [
"v1-5-pruned-emaonly-fp16.safetensors"
]
"widgets_values": ["v1-5-pruned-emaonly-fp16.safetensors"]
},
{
"id": 3,
"type": "KSampler",
"pos": [
870,
170
],
"size": [
315,
474
],
"pos": [870, 170],
"size": [315, 474],
"flags": {},
"order": 4,
"mode": 0,
@@ -103,9 +82,7 @@
"name": "LATENT",
"type": "LATENT",
"slot_index": 0,
"links": [
7
]
"links": [7]
}
],
"properties": {
@@ -126,14 +103,8 @@
{
"id": 8,
"type": "VAEDecode",
"pos": [
975,
700
],
"size": [
210,
46
],
"pos": [975, 700],
"size": [210, 46],
"flags": {},
"order": 5,
"mode": 0,
@@ -167,14 +138,8 @@
{
"id": 7,
"type": "CLIPTextEncode",
"pos": [
410,
410
],
"size": [
425.27801513671875,
180.6060791015625
],
"pos": [410, 410],
"size": [425.27801513671875, 180.6060791015625],
"flags": {},
"order": 3,
"mode": 0,
@@ -190,9 +155,7 @@
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
6
]
"links": [6]
}
],
"properties": {
@@ -200,23 +163,15 @@
"cnr_id": "comfy-core",
"ver": "0.3.65"
},
"widgets_values": [
"text, watermark"
],
"widgets_values": ["text, watermark"],
"color": "#223",
"bgcolor": "#335"
},
{
"id": 5,
"type": "EmptyLatentImage",
"pos": [
520,
690
],
"size": [
315,
106
],
"pos": [520, 690],
"size": [315, 106],
"flags": {},
"order": 1,
"mode": 0,
@@ -226,9 +181,7 @@
"name": "LATENT",
"type": "LATENT",
"slot_index": 0,
"links": [
2
]
"links": [2]
}
],
"properties": {
@@ -236,23 +189,13 @@
"cnr_id": "comfy-core",
"ver": "0.3.65"
},
"widgets_values": [
512,
512,
1
]
"widgets_values": [512, 512, 1]
},
{
"id": 6,
"type": "CLIPTextEncode",
"pos": [
411.21649169921875,
203.68695068359375
],
"size": [
422.84503173828125,
164.31304931640625
],
"pos": [411.21649169921875, 203.68695068359375],
"size": [422.84503173828125, 164.31304931640625],
"flags": {},
"order": 2,
"mode": 0,
@@ -268,9 +211,7 @@
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
4
]
"links": [4]
}
],
"properties": {
@@ -286,81 +227,20 @@
}
],
"links": [
[
1,
4,
0,
3,
0,
"MODEL"
],
[
2,
5,
0,
3,
3,
"LATENT"
],
[
3,
4,
1,
6,
0,
"CLIP"
],
[
4,
6,
0,
3,
1,
"CONDITIONING"
],
[
5,
4,
1,
7,
0,
"CLIP"
],
[
6,
7,
0,
3,
2,
"CONDITIONING"
],
[
7,
3,
0,
8,
0,
"LATENT"
],
[
8,
4,
2,
8,
1,
"VAE"
]
[1, 4, 0, 3, 0, "MODEL"],
[2, 5, 0, 3, 3, "LATENT"],
[3, 4, 1, 6, 0, "CLIP"],
[4, 6, 0, 3, 1, "CONDITIONING"],
[5, 4, 1, 7, 0, "CLIP"],
[6, 7, 0, 3, 2, "CONDITIONING"],
[7, 3, 0, 8, 0, "LATENT"],
[8, 4, 2, 8, 1, "VAE"]
],
"groups": [
{
"id": 1,
"title": "Step 1 - Load model",
"bounding": [
50,
130,
335,
181.60000610351562
],
"bounding": [50, 130, 335, 181.60000610351562],
"color": "#3f789e",
"font_size": 24,
"flags": {}
@@ -368,12 +248,7 @@
{
"id": 2,
"title": "Step 3 - Image size",
"bounding": [
510,
620,
335,
189.60000610351562
],
"bounding": [510, 620, 335, 189.60000610351562],
"color": "#3f789e",
"font_size": 24,
"flags": {}
@@ -381,12 +256,7 @@
{
"id": 3,
"title": "Step 2 - Prompt",
"bounding": [
400,
130,
445.27801513671875,
467.2060852050781
],
"bounding": [400, 130, 445.27801513671875, 467.2060852050781],
"color": "#3f789e",
"font_size": 24,
"flags": {}
@@ -396,10 +266,7 @@
"extra": {
"ds": {
"scale": 0.44218252181616574,
"offset": [
-666.5670907104311,
-2227.894644048147
]
"offset": [-666.5670907104311, -2227.894644048147]
},
"frontendVersion": "1.35.3",
"VHS_latentpreview": false,
@@ -409,4 +276,4 @@
"workflowRendererVersion": "LG"
},
"version": 0.4
}
}

View File

@@ -1 +1,166 @@
{"id":"4412323e-2509-4258-8abc-68ddeea8f9e1","revision":0,"last_node_id":39,"last_link_id":29,"nodes":[{"id":37,"type":"KSampler","pos":[3635.923095703125,870.237548828125],"size":[428,437],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"model","name":"model","type":"MODEL","link":null},{"localized_name":"positive","name":"positive","type":"CONDITIONING","link":null},{"localized_name":"negative","name":"negative","type":"CONDITIONING","link":null},{"localized_name":"latent_image","name":"latent_image","type":"LATENT","link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"steps","name":"steps","type":"INT","widget":{"name":"steps"},"link":null},{"localized_name":"cfg","name":"cfg","type":"FLOAT","widget":{"name":"cfg"},"link":null},{"localized_name":"sampler_name","name":"sampler_name","type":"COMBO","widget":{"name":"sampler_name"},"link":null},{"localized_name":"scheduler","name":"scheduler","type":"COMBO","widget":{"name":"scheduler"},"link":null},{"localized_name":"denoise","name":"denoise","type":"FLOAT","widget":{"name":"denoise"},"link":null}],"outputs":[{"localized_name":"LATENT","name":"LATENT","type":"LATENT","links":null}],"properties":{"Node name for S&R":"KSampler"},"widgets_values":[0,"randomize",20,8,"euler","simple",1]},{"id":38,"type":"VAEDecode","pos":[4164.01611328125,925.5230712890625],"size":[193.25,107],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"samples","name":"samples","type":"LATENT","link":null},{"localized_name":"vae","name":"vae","type":"VAE","link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":null}],"properties":{"Node name for S&R":"VAEDecode"}},{"id":39,"type":"CLIPTextEncode","pos":[3259.289794921875,927.2508544921875],"size":[239.9375,155],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"clip","name":"clip","type":"CLIP","link":null},{"localized_name":"text","name":"text","type":"STRING","widget":{"name":"text"},"link":null}],"outputs":[{"localized_name":"CONDITIONING","name":"CONDITIONING","type":"CONDITIONING","links":null}],"properties":{"Node name for S&R":"CLIPTextEncode"},"widgets_values":[""]}],"links":[],"groups":[],"config":{},"extra":{"ds":{"scale":1.1576250000000001,"offset":[-2808.366467322067,-478.34316506594797]}},"version":0.4}
{
"id": "4412323e-2509-4258-8abc-68ddeea8f9e1",
"revision": 0,
"last_node_id": 39,
"last_link_id": 29,
"nodes": [
{
"id": 37,
"type": "KSampler",
"pos": [3635.923095703125, 870.237548828125],
"size": [428, 437],
"flags": {},
"order": 0,
"mode": 0,
"inputs": [
{
"localized_name": "model",
"name": "model",
"type": "MODEL",
"link": null
},
{
"localized_name": "positive",
"name": "positive",
"type": "CONDITIONING",
"link": null
},
{
"localized_name": "negative",
"name": "negative",
"type": "CONDITIONING",
"link": null
},
{
"localized_name": "latent_image",
"name": "latent_image",
"type": "LATENT",
"link": null
},
{
"localized_name": "seed",
"name": "seed",
"type": "INT",
"widget": { "name": "seed" },
"link": null
},
{
"localized_name": "steps",
"name": "steps",
"type": "INT",
"widget": { "name": "steps" },
"link": null
},
{
"localized_name": "cfg",
"name": "cfg",
"type": "FLOAT",
"widget": { "name": "cfg" },
"link": null
},
{
"localized_name": "sampler_name",
"name": "sampler_name",
"type": "COMBO",
"widget": { "name": "sampler_name" },
"link": null
},
{
"localized_name": "scheduler",
"name": "scheduler",
"type": "COMBO",
"widget": { "name": "scheduler" },
"link": null
},
{
"localized_name": "denoise",
"name": "denoise",
"type": "FLOAT",
"widget": { "name": "denoise" },
"link": null
}
],
"outputs": [
{
"localized_name": "LATENT",
"name": "LATENT",
"type": "LATENT",
"links": null
}
],
"properties": { "Node name for S&R": "KSampler" },
"widgets_values": [0, "randomize", 20, 8, "euler", "simple", 1]
},
{
"id": 38,
"type": "VAEDecode",
"pos": [4164.01611328125, 925.5230712890625],
"size": [193.25, 107],
"flags": {},
"order": 1,
"mode": 0,
"inputs": [
{
"localized_name": "samples",
"name": "samples",
"type": "LATENT",
"link": null
},
{ "localized_name": "vae", "name": "vae", "type": "VAE", "link": null }
],
"outputs": [
{
"localized_name": "IMAGE",
"name": "IMAGE",
"type": "IMAGE",
"links": null
}
],
"properties": { "Node name for S&R": "VAEDecode" }
},
{
"id": 39,
"type": "CLIPTextEncode",
"pos": [3259.289794921875, 927.2508544921875],
"size": [239.9375, 155],
"flags": {},
"order": 2,
"mode": 0,
"inputs": [
{
"localized_name": "clip",
"name": "clip",
"type": "CLIP",
"link": null
},
{
"localized_name": "text",
"name": "text",
"type": "STRING",
"widget": { "name": "text" },
"link": null
}
],
"outputs": [
{
"localized_name": "CONDITIONING",
"name": "CONDITIONING",
"type": "CONDITIONING",
"links": null
}
],
"properties": { "Node name for S&R": "CLIPTextEncode" },
"widgets_values": [""]
}
],
"links": [],
"groups": [],
"config": {},
"extra": {
"ds": {
"scale": 1.1576250000000001,
"offset": [-2808.366467322067, -478.34316506594797]
}
},
"version": 0.4
}

View File

@@ -7,14 +7,8 @@
{
"id": 1,
"type": "LoadAudio",
"pos": [
41.52964782714844,
16.930862426757812
],
"size": [
444,
125
],
"pos": [41.52964782714844, 16.930862426757812],
"size": [444, 125],
"flags": {},
"order": 0,
"mode": 0,
@@ -29,23 +23,13 @@
"properties": {
"Node name for S&R": "LoadAudio"
},
"widgets_values": [
null,
null,
""
]
"widgets_values": [null, null, ""]
},
{
"id": 2,
"type": "LoadVideo",
"pos": [
502.28570556640625,
16.857147216796875
],
"size": [
444,
525
],
"pos": [502.28570556640625, 16.857147216796875],
"size": [444, 525],
"flags": {},
"order": 1,
"mode": 0,
@@ -60,22 +44,13 @@
"properties": {
"Node name for S&R": "LoadVideo"
},
"widgets_values": [
null,
"image"
]
"widgets_values": [null, "image"]
},
{
"id": 3,
"type": "DevToolsLoadAnimatedImageTest",
"pos": [
41.71427917480469,
188.0000457763672
],
"size": [
444,
553
],
"pos": [41.71427917480469, 188.0000457763672],
"size": [444, 553],
"flags": {},
"order": 2,
"mode": 0,
@@ -95,22 +70,13 @@
"properties": {
"Node name for S&R": "DevToolsLoadAnimatedImageTest"
},
"widgets_values": [
null,
"image"
]
"widgets_values": [null, "image"]
},
{
"id": 5,
"type": "LoadImage",
"pos": [
958.285888671875,
16.57145118713379
],
"size": [
444,
553
],
"pos": [958.285888671875, 16.57145118713379],
"size": [444, 553],
"flags": {},
"order": 3,
"mode": 0,
@@ -130,22 +96,13 @@
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
null,
"image"
]
"widgets_values": [null, "image"]
},
{
"id": 6,
"type": "LoadImageMask",
"pos": [
503.4285888671875,
588
],
"size": [
444,
563
],
"pos": [503.4285888671875, 588],
"size": [444, 563],
"flags": {},
"order": 4,
"mode": 0,
@@ -160,23 +117,13 @@
"properties": {
"Node name for S&R": "LoadImageMask"
},
"widgets_values": [
null,
"alpha",
"image"
]
"widgets_values": [null, "alpha", "image"]
},
{
"id": 7,
"type": "LoadImageOutput",
"pos": [
965.1429443359375,
612
],
"size": [
444,
553
],
"pos": [965.1429443359375, 612],
"size": [444, 553],
"flags": {},
"order": 5,
"mode": 0,
@@ -196,12 +143,7 @@
"properties": {
"Node name for S&R": "LoadImageOutput"
},
"widgets_values": [
null,
false,
"refresh",
"image"
]
"widgets_values": [null, false, "refresh", "image"]
}
],
"links": [],
@@ -210,12 +152,9 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
},
"frontendVersion": "1.28.3"
},
"version": 0.4
}
}

View File

@@ -5,14 +5,8 @@
{
"id": 11,
"type": "DevToolsNodeWithBooleanInput",
"pos": [
0,
30
],
"size": [
315,
58
],
"pos": [0, 30],
"size": [315, 58],
"flags": {
"collapsed": false
},
@@ -23,9 +17,7 @@
"properties": {
"Node name for S&R": "DevToolsNodeWithBooleanInput"
},
"widgets_values": [
false
]
"widgets_values": [false]
}
],
"links": [],

View File

@@ -5,14 +5,8 @@
{
"id": 10,
"type": "LoadImage",
"pos": [
50,
50
],
"size": [
315,
314
],
"pos": [50, 50],
"size": [315, 314],
"flags": {},
"order": 0,
"mode": 0,
@@ -32,10 +26,7 @@
"properties": {
"Node name for S&R": "LoadImage"
},
"widgets_values": [
"example.png",
"image"
]
"widgets_values": ["example.png", "image"]
}
],
"links": [],

View File

@@ -5,14 +5,8 @@
{
"id": 10,
"type": "DevToolsNodeWithSeedInput",
"pos": [
20,
50
],
"size": [
315,
82
],
"pos": [20, 50],
"size": [315, 82],
"flags": {},
"order": 1,
"mode": 0,
@@ -21,10 +15,7 @@
"properties": {
"Node name for S&R": "DevToolsNodeWithSeedInput"
},
"widgets_values": [
0,
"randomize"
]
"widgets_values": [0, "randomize"]
}
],
"links": [],
@@ -33,11 +24,8 @@
"extra": {
"ds": {
"scale": 1,
"offset": [
0,
0
]
"offset": [0, 0]
}
},
"version": 0.4
}
}

View File

@@ -119,8 +119,7 @@ class NodeSlotReference {
window['app'].canvas.ds.convertOffsetToCanvas(rawPos)
// Debug logging - convert Float64Arrays to regular arrays for visibility
// eslint-disable-next-line no-console
console.log(
console.warn(
`NodeSlotReference debug for ${type} slot ${index} on node ${id}:`,
{
nodePos: [node.pos[0], node.pos[1]],

View File

@@ -232,11 +232,25 @@ test.describe('Node Color Adjustments', () => {
}) => {
await comfyPage.setSetting('Comfy.Node.Opacity', 0.5)
await comfyPage.setSetting('Comfy.ColorPalette', 'light')
const saveWorkflowInterval = 1000
const workflow = await comfyPage.page.evaluate(() => {
return localStorage.getItem('workflow')
})
for (const node of JSON.parse(workflow ?? '{}').nodes) {
await comfyPage.nextFrame()
const parsed = await (
await comfyPage.page.waitForFunction(
() => {
const workflow = localStorage.getItem('workflow')
if (!workflow) return null
try {
const data = JSON.parse(workflow)
return Array.isArray(data?.nodes) ? data : null
} catch {
return null
}
},
{ timeout: 3000 }
)
).jsonValue()
expect(parsed.nodes).toBeDefined()
expect(Array.isArray(parsed.nodes)).toBe(true)
for (const node of parsed.nodes) {
if (node.bgcolor) expect(node.bgcolor).not.toMatch(/hsla/)
if (node.color) expect(node.color).not.toMatch(/hsla/)
}

View File

@@ -27,7 +27,7 @@ test.describe('Feature Flags', () => {
try {
const parsed = JSON.parse(data)
if (parsed.type === 'feature_flags') {
window.__capturedMessages.clientFeatureFlags = parsed
window.__capturedMessages!.clientFeatureFlags = parsed
}
} catch (e) {
// Not JSON, ignore
@@ -41,7 +41,7 @@ test.describe('Feature Flags', () => {
window['app']?.api?.serverFeatureFlags &&
Object.keys(window['app'].api.serverFeatureFlags).length > 0
) {
window.__capturedMessages.serverFeatureFlags =
window.__capturedMessages!.serverFeatureFlags =
window['app'].api.serverFeatureFlags
clearInterval(checkInterval)
}
@@ -57,8 +57,8 @@ test.describe('Feature Flags', () => {
// Wait for both client and server feature flags
await newPage.waitForFunction(
() =>
window.__capturedMessages.clientFeatureFlags !== null &&
window.__capturedMessages.serverFeatureFlags !== null,
window.__capturedMessages!.clientFeatureFlags !== null &&
window.__capturedMessages!.serverFeatureFlags !== null,
{ timeout: 10000 }
)
@@ -66,27 +66,27 @@ test.describe('Feature Flags', () => {
const messages = await newPage.evaluate(() => window.__capturedMessages)
// Verify client sent feature flags
expect(messages.clientFeatureFlags).toBeTruthy()
expect(messages.clientFeatureFlags).toHaveProperty('type', 'feature_flags')
expect(messages.clientFeatureFlags).toHaveProperty('data')
expect(messages.clientFeatureFlags.data).toHaveProperty(
expect(messages!.clientFeatureFlags).toBeTruthy()
expect(messages!.clientFeatureFlags).toHaveProperty('type', 'feature_flags')
expect(messages!.clientFeatureFlags).toHaveProperty('data')
expect(messages!.clientFeatureFlags!.data).toHaveProperty(
'supports_preview_metadata'
)
expect(
typeof messages.clientFeatureFlags.data.supports_preview_metadata
typeof messages!.clientFeatureFlags!.data.supports_preview_metadata
).toBe('boolean')
// Verify server sent feature flags back
expect(messages.serverFeatureFlags).toBeTruthy()
expect(messages.serverFeatureFlags).toHaveProperty(
expect(messages!.serverFeatureFlags).toBeTruthy()
expect(messages!.serverFeatureFlags).toHaveProperty(
'supports_preview_metadata'
)
expect(typeof messages.serverFeatureFlags.supports_preview_metadata).toBe(
expect(typeof messages!.serverFeatureFlags!.supports_preview_metadata).toBe(
'boolean'
)
expect(messages.serverFeatureFlags).toHaveProperty('max_upload_size')
expect(typeof messages.serverFeatureFlags.max_upload_size).toBe('number')
expect(Object.keys(messages.serverFeatureFlags).length).toBeGreaterThan(0)
expect(messages!.serverFeatureFlags).toHaveProperty('max_upload_size')
expect(typeof messages!.serverFeatureFlags!.max_upload_size).toBe('number')
expect(Object.keys(messages!.serverFeatureFlags!).length).toBeGreaterThan(0)
await newPage.close()
})
@@ -96,7 +96,7 @@ test.describe('Feature Flags', () => {
}) => {
// Get the actual server feature flags from the backend
const serverFlags = await comfyPage.page.evaluate(() => {
return window['app'].api.serverFeatureFlags
return window['app']!.api.serverFeatureFlags
})
// Verify we received real feature flags from the backend
@@ -115,7 +115,7 @@ test.describe('Feature Flags', () => {
}) => {
// Test serverSupportsFeature with real backend flags
const supportsPreviewMetadata = await comfyPage.page.evaluate(() => {
return window['app'].api.serverSupportsFeature(
return window['app']!.api.serverSupportsFeature(
'supports_preview_metadata'
)
})
@@ -124,15 +124,17 @@ test.describe('Feature Flags', () => {
// Test non-existent feature - should always return false
const supportsNonExistent = await comfyPage.page.evaluate(() => {
return window['app'].api.serverSupportsFeature('non_existent_feature_xyz')
return window['app']!.api.serverSupportsFeature(
'non_existent_feature_xyz'
)
})
expect(supportsNonExistent).toBe(false)
// Test that the method only returns true for boolean true values
const testResults = await comfyPage.page.evaluate(() => {
// Temporarily modify serverFeatureFlags to test behavior
const original = window['app'].api.serverFeatureFlags
window['app'].api.serverFeatureFlags = {
const original = window['app']!.api.serverFeatureFlags
window['app']!.api.serverFeatureFlags = {
bool_true: true,
bool_false: false,
string_value: 'yes',
@@ -141,15 +143,15 @@ test.describe('Feature Flags', () => {
}
const results = {
bool_true: window['app'].api.serverSupportsFeature('bool_true'),
bool_false: window['app'].api.serverSupportsFeature('bool_false'),
string_value: window['app'].api.serverSupportsFeature('string_value'),
number_value: window['app'].api.serverSupportsFeature('number_value'),
null_value: window['app'].api.serverSupportsFeature('null_value')
bool_true: window['app']!.api.serverSupportsFeature('bool_true'),
bool_false: window['app']!.api.serverSupportsFeature('bool_false'),
string_value: window['app']!.api.serverSupportsFeature('string_value'),
number_value: window['app']!.api.serverSupportsFeature('number_value'),
null_value: window['app']!.api.serverSupportsFeature('null_value')
}
// Restore original
window['app'].api.serverFeatureFlags = original
window['app']!.api.serverFeatureFlags = original
return results
})
@@ -166,20 +168,20 @@ test.describe('Feature Flags', () => {
}) => {
// Test getServerFeature method
const previewMetadataValue = await comfyPage.page.evaluate(() => {
return window['app'].api.getServerFeature('supports_preview_metadata')
return window['app']!.api.getServerFeature('supports_preview_metadata')
})
expect(typeof previewMetadataValue).toBe('boolean')
// Test getting max_upload_size
const maxUploadSize = await comfyPage.page.evaluate(() => {
return window['app'].api.getServerFeature('max_upload_size')
return window['app']!.api.getServerFeature('max_upload_size')
})
expect(typeof maxUploadSize).toBe('number')
expect(maxUploadSize).toBeGreaterThan(0)
// Test getServerFeature with default value for non-existent feature
const defaultValue = await comfyPage.page.evaluate(() => {
return window['app'].api.getServerFeature(
return window['app']!.api.getServerFeature(
'non_existent_feature_xyz',
'default'
)
@@ -192,7 +194,7 @@ test.describe('Feature Flags', () => {
}) => {
// Test getServerFeatures returns all flags
const allFeatures = await comfyPage.page.evaluate(() => {
return window['app'].api.getServerFeatures()
return window['app']!.api.getServerFeatures()
})
expect(allFeatures).toBeTruthy()
@@ -205,14 +207,14 @@ test.describe('Feature Flags', () => {
test('Client feature flags are immutable', async ({ comfyPage }) => {
// Test that getClientFeatureFlags returns a copy
const immutabilityTest = await comfyPage.page.evaluate(() => {
const flags1 = window['app'].api.getClientFeatureFlags()
const flags2 = window['app'].api.getClientFeatureFlags()
const flags1 = window['app']!.api.getClientFeatureFlags()
const flags2 = window['app']!.api.getClientFeatureFlags()
// Modify the first object
flags1.test_modification = true
// Get flags again to check if original was modified
const flags3 = window['app'].api.getClientFeatureFlags()
const flags3 = window['app']!.api.getClientFeatureFlags()
return {
areEqual: flags1 === flags2,
@@ -238,14 +240,14 @@ test.describe('Feature Flags', () => {
}) => {
const immutabilityTest = await comfyPage.page.evaluate(() => {
// Get a copy of server features
const features1 = window['app'].api.getServerFeatures()
const features1 = window['app']!.api.getServerFeatures()
// Try to modify it
features1.supports_preview_metadata = false
features1.new_feature = 'added'
// Get another copy
const features2 = window['app'].api.getServerFeatures()
const features2 = window['app']!.api.getServerFeatures()
return {
modifiedValue: features1.supports_preview_metadata,
@@ -274,7 +276,8 @@ test.describe('Feature Flags', () => {
// Set up monitoring before navigation
await newPage.addInitScript(() => {
// Track when various app components are ready
;(window as any).__appReadiness = {
window.__appReadiness = {
featureFlagsReceived: false,
apiInitialized: false,
appInitialized: false
@@ -286,7 +289,10 @@ test.describe('Feature Flags', () => {
window['app']?.api?.serverFeatureFlags?.supports_preview_metadata !==
undefined
) {
;(window as any).__appReadiness.featureFlagsReceived = true
window.__appReadiness = {
...window.__appReadiness,
featureFlagsReceived: true
}
clearInterval(checkFeatureFlags)
}
}, 10)
@@ -294,7 +300,10 @@ test.describe('Feature Flags', () => {
// Monitor API initialization
const checkApi = setInterval(() => {
if (window['app']?.api) {
;(window as any).__appReadiness.apiInitialized = true
window.__appReadiness = {
...window.__appReadiness,
apiInitialized: true
}
clearInterval(checkApi)
}
}, 10)
@@ -302,7 +311,10 @@ test.describe('Feature Flags', () => {
// Monitor app initialization
const checkApp = setInterval(() => {
if (window['app']?.graph) {
;(window as any).__appReadiness.appInitialized = true
window.__appReadiness = {
...window.__appReadiness,
appInitialized: true
}
clearInterval(checkApp)
}
}, 10)
@@ -331,8 +343,8 @@ test.describe('Feature Flags', () => {
// Get readiness state
const readiness = await newPage.evaluate(() => {
return {
...(window as any).__appReadiness,
currentFlags: window['app'].api.serverFeatureFlags
...window.__appReadiness,
currentFlags: window['app']!.api.serverFeatureFlags
}
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

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