Skip to content

Batch Drag & Drop Images#8282

Open
JemiloII wants to merge 21 commits intoComfy-Org:mainfrom
JemiloII:batch-drag-and-drop-images
Open

Batch Drag & Drop Images#8282
JemiloII wants to merge 21 commits intoComfy-Org:mainfrom
JemiloII:batch-drag-and-drop-images

Conversation

@JemiloII
Copy link
Contributor

@JemiloII JemiloII commented Jan 23, 2026

Summary

Added feature to drag and drop multiple images into the UI and connect them with a Batch Images node with tests to add convenience for users. Only works with a group of images, mixing files not supported.

Review Focus

I've updated our usage of Litegraph.createNode, honestly, that method is pretty bad, onNodeCreated option method doesn't even return the node created. I think I will probably go check out their repo to do a PR over there. Anyways, I made a createNode method to avoid race conditions when creating nodes for the paste actions. Will allow us to better programmatically create nodes that do not have workflows that also need to be connected to other nodes.

https://www.notion.so/comfy-org/Implement-Multi-image-drag-and-drop-to-canvas-2eb6d73d36508195ad8addfc4367db10

Screenshots (if applicable)

2026-01-22.04-04-39.mp4

┆Issue is synchronized with this Notion page by Unito

Summary by CodeRabbit

  • New Features

    • Batch image support: drop or paste multiple images at once; auto-create, layout, select, and connect image nodes with a batch node.
    • Improved paste flow: clipboard cloning preserves files/metadata; image pasting is now async and supports multi-file pastes.
  • Bug Fixes

    • Graceful handling of null node additions to avoid failures.
    • More robust drag-and-drop and paste handling for images.
  • Tests

    • Expanded coverage for drops, paste flows, node creation, positioning, and batch image scenarios.

@JemiloII JemiloII requested a review from a team as a code owner January 23, 2026 20:33
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jan 23, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

📝 Walkthrough

Walkthrough

Adds async node creation (createNode), DataTransfer cloning (cloneDataTransfer), batch image paste flows (pasteImageNodes), FileList-aware drag extraction, LGraph.add null-safety, and corresponding app and test updates across paste handling, litegraph utilities, event handling, and ComfyApp batch positioning.

Changes

Cohort / File(s) Summary
Node creation utilities
src/utils/litegraphUtil.ts, src/utils/litegraphUtil.test.ts
Add exported async createNode(canvas, name): Promise<LGraphNode | null> that wraps LiteGraph.createNode, awaits a microtask, sets node.pos from canvas.graph_mouse, adds to graph, triggers graph.changed; tests added/expanded for success, empty name, null graph, and positioning.
Paste & clipboard utilities
src/composables/usePaste.ts, src/composables/usePaste.test.ts
Add cloneDataTransfer(original: DataTransfer): DataTransfer; convert pasteImageNode to async Promise<LGraphNode | null>; add pasteImageNodes(canvas, fileList): Promise<LGraphNode[]>; paste handling clones DataTransfer and awaits image-node creation; tests updated for async flows and null-node mocks.
ComfyApp batch processing
src/scripts/app.ts, src/scripts/app.test.ts
Add handleFileList(fileList) and positionBatchNodes(nodes, batchNode); drop/file-load flow uses pasteImageNodes for multi-file images and createNode+pasteImageNode for single-file; tests cover batching, positioning, selection, connections, and error cases.
Drag-and-drop extraction
src/utils/eventUtils.ts, src/utils/__tests__/eventUtils.test.ts
Widen extractFileFromDragEvent return to Promise<File | FileList | undefined>; return FileList when multiple image files are dropped; add tests for multi-image and non-image drops.
LGraph null-safety
src/lib/litegraph/src/LGraph.ts, src/lib/litegraph/src/LGraph.test.ts
Extend LGraph.add signature to accept null and early-return when falsy; add tests asserting graceful handling and unchanged node count when null is added.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant EventUtils as EventUtils\n(extractFileFromDragEvent)
    participant ComfyApp as ComfyApp
    participant PasteUtils as usePaste\n(cloneDataTransfer, pasteImageNodes, pasteImageNode)
    participant CreateNode as litegraphUtil\n(createNode)
    participant LGraph as LGraph
    participant UI as UI

    User->>EventUtils: Drop images
    EventUtils-->>ComfyApp: FileList
    ComfyApp->>PasteUtils: pasteImageNodes(canvas, FileList)
    loop for each file
        PasteUtils->>CreateNode: createNode(canvas, "LoadImage")
        CreateNode->>LGraph: LiteGraph.createNode(...)
        CreateNode-->>PasteUtils: positioned LGraphNode
        PasteUtils->>PasteUtils: await paste image into node
        PasteUtils-->>ComfyApp: image LGraphNode
    end
    ComfyApp->>CreateNode: createNode(canvas, "BatchImages")
    CreateNode-->>ComfyApp: batch LGraphNode
    ComfyApp->>ComfyApp: positionBatchNodes(imageNodes, batchNode)
    ComfyApp->>LGraph: connect image nodes to batch slots
    ComfyApp->>UI: select nodes / trigger graph.changed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • DrJKL
  • jtydhr88

Poem

"I hop through code with a twitchy nose,
I clone each paste where the clipboard goes.
I nudge nodes to place in tidy rows,
Batch them, link them — see how it grows. 🐇✨"

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description covers the summary, review focus, and links; however, it lacks the structured 'Changes' section required by the template. Add a 'Changes' section detailing what was modified (core functionality, breaking changes if any, dependencies added).
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Batch Drag & Drop Images' directly describes the main feature added—support for dragging and dropping multiple images with batch processing.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Jan 23, 2026

🎨 Storybook Build Status

loading Build is starting...

⏰ Started at: 01/28/2026, 11:24:15 PM UTC

🚀 Building Storybook

  • 📦 Installing dependencies...
  • 🔧 Building Storybook components...
  • 🌐 Preparing deployment to Cloudflare Pages...

⏱️ Please wait while the Storybook build is in progress...

@github-actions
Copy link

github-actions bot commented Jan 23, 2026

🎭 Playwright Tests: ⏳ Running...

Tests started at 01/28/2026, 11:24:13 PM UTC

📊 Browser Tests
  • chromium: Running...
  • chromium-0.5x: Running...
  • chromium-2x: Running...
  • mobile-chrome: Running...

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🤖 Fix all issues with AI agents
In `@src/composables/usePaste.test.ts`:
- Around line 112-115: Replace the opaque "as unknown as LGraphNode" casts in
tests by returning a typed partial mock and casting that to LGraphNode; update
the helper createMockNode to build and return Partial<LGraphNode> and then use
vi.mocked(createNode).mockResolvedValue(createMockNode() as Partial<LGraphNode>
as LGraphNode) (or simply cast the helper's Partial to LGraphNode where used).
Locate uses around createMockNode and createNode in the test (including the
other occurrences at lines ~195-201) and switch them to the Partial<LGraphNode>
pattern so mocks are explicit and centralized.
- Around line 372-383: The cloneDataTransfer helper is adding files from both
.files and .items causing duplicate File entries; change cloneDataTransfer to
deduplicate by identity (e.g., track added files in a Set using a stable key
like file.name+file.size+file.type or track File objects with a WeakSet) before
appending to the cloned DataTransfer, and update the test in usePaste.test.ts to
assert exact counts (expect(cloned.files.length).toBe(2) and still assert the
two specific files are present).

In `@src/composables/usePaste.ts`:
- Around line 12-43: cloneDataTransfer currently adds files from both
original.files and original.items which can produce duplicates; deduplicate
file-kind entries before calling persistent.items.add. In cloneDataTransfer
collect files from original.files and those from original.items (via
item.getAsFile()), use a Set key (e.g., name + size + lastModified) or compare
File references to filter out duplicates, then add only unique files via
persistent.items.add; leave string data and properties
(dropEffect/effectAllowed) as-is.

In `@src/scripts/app.test.ts`:
- Around line 34-44: The helper createMockNode currently uses `any` and an
`unknown` cast which hides missing fields; change the function signature to
accept options: Partial<LGraphNode> (not any), merge defaults with the provided
options, and do a single explicit cast to LGraphNode on the returned object
(remove the intermediate unknown cast) so tests remain fully typed and adhere to
the repo's typing rules.
- Around line 46-52: The mock uses an unsafe "as any" for the graph; change
createMockCanvas to type the graph explicitly (e.g., use graph: Partial<LGraph>
or graph: Partial<NonNullable<LGraphCanvas['graph']>> ) so the mock implements
the expected shape rather than using any, and type graph.change as a vi.fn()
with the correct signature; update the return signature of createMockCanvas
accordingly so TypeScript infers the mock types for LGraphCanvas and its graph
instead of relying on any.
- Around line 119-124: The test fails because ComfyApp.handleFileList
dereferences fileList[0] without guarding empty lists; modify
ComfyApp.handleFileList to immediately return (no-op) when the incoming fileList
is empty (e.g., check fileList.length === 0 or !fileList || fileList.length ===
0) before any dereference, and ensure any downstream logic handles the
early-return case. Then update the test (calling app.handleFileList) to assert
that the promise resolves (e.g., not rejected or returns undefined) instead of
expecting a throw so the test verifies the new safe no-op behavior.

In `@src/scripts/app.ts`:
- Around line 1552-1568: In positionBatchNodes, avoid calling
this.canvas.graph?.change() inside the nodes.forEach loop; instead, compute and
set all node.pos values (including batchNode.pos already set) within the loop
and then invoke this.canvas.graph?.change() a single time after the loop
completes to improve performance for large drops.
- Around line 1527-1545: handleFileList currently assumes fileList[0] exists and
that all files are images; update it to first validate the FileList is non-empty
and contains only image/* entries, and if not show a localized toast (add the
new i18n key in src/locales/en/main.json) and return early. After calling
pasteImageNodes(this.canvas, fileList) check that imageNodes is non-empty before
creating/connecting the BatchImagesNode (createNode(..., 'BatchImagesNode')) and
before calling positionBatchNodes(imageNodes, batchImagesNode); if imageNodes is
empty, bail without creating the batch node. Ensure you reference the existing
functions handleFileList, pasteImageNodes, positionBatchNodes and createNode
when making changes.

In `@src/utils/__tests__/eventUtils.test.ts`:
- Around line 36-55: The test repeats type assertions for the result of
extractFileFromDragEvent; to simplify, assign the awaited result to a typed
variable (e.g., const files = await extractFileFromDragEvent(event) as FileList)
and use files.length and files[0]/files[1] in the assertions; update references
in this spec to use the new variable and keep FakeDragEvent and
extractFileFromDragEvent as the source identifiers to locate the code to change.

In `@src/utils/eventUtils.ts`:
- Line 29: Replace the arrow constant using the boxed Boolean with a plain
function declaration that returns the primitive boolean; specifically change the
const hasImageType = ({ type }: File): Boolean => type.startsWith('image'); to a
function declaration like function hasImageType(file: File): boolean { return
file.type.startsWith('image'); } (use the File parameter name `file`, reference
the hasImageType function/method name, and return primitive `boolean`).
- Around line 1-12: The helper hasImageType is currently declared as an arrow
returning a Boolean object and should be a function declaration returning a
primitive boolean; replace the existing arrow-expression version with a function
declaration named hasImageType that takes a File ({ type }: File) and returns
type.startsWith('image') as a boolean, so callers (including
extractFileFromDragEvent) follow coding guidelines and get the correct primitive
return type.

In `@src/utils/litegraphUtil.test.ts`:
- Around line 31-88: Tests use unsafe any/opaque casts (mockGraph: any, null as
any, as unknown as LGraphNode); update them to use Partial types and proper
typings: declare mockGraph as Partial<LGraph> and mockNode as
Partial<LGraphNode> (typed as LGraphNode when needed), remove or adjust the
`null as any` test (either drop it since empty string covers falsy guard or
update createNode signature to accept string | null | undefined), and ensure
vi.mocked(LiteGraph.createNode) returns the Partial mock correctly; also type
mockCanvas as Partial<LGraphCanvas> to avoid any casts and keep
useToastStore/mockAddAlert typed consistently.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/composables/usePaste.ts (1)

167-177: Consider aligning audio node creation with the new async pattern.

The audio node creation still uses LiteGraph.createNode() directly, while image nodes now use the new async createNode() utility. For consistency and to avoid race conditions mentioned in the PR objectives, consider updating this path in a follow-up.

🤖 Fix all issues with AI agents
In `@src/composables/usePaste.ts`:
- Around line 23-31: The comment above the loop incorrectly states items.add()
is idempotent; update it to accurately explain why duplicates are avoided: note
that we only iterate original.items (and only add file-kind entries) rather than
iterating both .files and .items, so duplicates are prevented by the iteration
strategy, not by items.add() itself; change the comment near the loop that
references items.add(), original.items, and persistent.items to reflect this
accurate behavior.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/composables/usePaste.ts (1)

165-176: Inconsistent node creation pattern for audio nodes.

Audio node creation still uses the synchronous LiteGraph.createNode pattern, while image handling now uses the async createNode utility. Per PR objectives, createNode was introduced to avoid race conditions with onNodeCreated callbacks. This inconsistency could lead to the same race conditions for audio paste operations.

♻️ Suggested refactor
       } else if (item.type.startsWith('audio/')) {
         if (!audioNode) {
           // No audio node selected: add a new one
-          const newNode = LiteGraph.createNode('LoadAudio')
-          if (newNode) {
-            newNode.pos = [canvas.graph_mouse[0], canvas.graph_mouse[1]]
-            audioNode = graph?.add(newNode) ?? null
-          }
-          graph?.change()
+          audioNode = await createNode(canvas as LGraphCanvas, 'LoadAudio')
         }
         pasteItemsOnNode(items, audioNode, 'audio')
         return
       }
🤖 Fix all issues with AI agents
In `@src/composables/usePaste.ts`:
- Around line 92-109: The pasteImageNodes function iterates all files but
doesn't validate they're images; update pasteImageNodes to skip non-image files
by checking each File's MIME (e.g., file.type.startsWith("image/")) before
creating a DataTransfer and calling pasteImageNode, and optionally fall back to
checking file.name extensions if file.type is empty; only call pasteImageNode
and push into nodes for files that pass this image check (reference
pasteImageNodes and pasteImageNode and the LoadImage node behavior).

@DrJKL DrJKL requested a review from AustinMroz January 23, 2026 23:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/scripts/app.test.ts`:
- Around line 38-48: The createMockNode helper currently types its options
parameter as Record<string, unknown>; change its signature to use
Partial<LGraphNode> for better type safety (function createMockNode(options:
Partial<LGraphNode> = {})). Update any related casts if needed (the final as
unknown as LGraphNode can remain) and ensure the spread of ...options onto the
returned object still compiles against LGraphNode members; this makes TypeScript
validate that provided mock fields match LGraphNode properties.
- Around line 258-275: Replace the unsafe "as unknown as ReturnType<typeof
useToastStore>" cast with a Partial-based stub for the toast store: create a
const toastStub: Partial<ReturnType<typeof useToastStore>> = { addAlert:
mockAddAlert } and pass that to vi.mocked(useToastStore).mockReturnValue (or
cast only the Partial to the exact return type in a single safe cast if the mock
API requires it); update the test around useToastStore and mockAddAlert to use
toastStub instead of the as unknown as pattern so the test uses a typed Partial
of useToastStore rather than an unsafe double-cast.
♻️ Duplicate comments (2)
src/scripts/app.ts (1)

1527-1545: Guard empty/mixed FileList drops before batching.

The existing concern from the previous review still applies: Line 1533 assumes fileList[0] exists and will throw on empty drops. Additionally, the MIME type check should use 'image/' (with trailing slash) for correctness, and imageNodes should be validated as non-empty before proceeding.

src/scripts/app.test.ts (1)

125-130: Test documents a bug rather than desired behavior.

This test expects a throw for empty file lists, which confirms the implementation bug flagged in handleFileList. Once the implementation is fixed to guard against empty lists, update this test to assert a successful no-op.

♻️ Suggested update once implementation is fixed
   it('should handle empty file list', async () => {
     const dataTransfer = new DataTransfer()

-    // The implementation doesn't check for empty list and will throw
-    await expect(app.handleFileList(dataTransfer.files)).rejects.toThrow()
+    // Empty file list should be a no-op
+    await expect(app.handleFileList(dataTransfer.files)).resolves.toBeUndefined()
   })

@github-actions
Copy link

Bundle Size Report

Summary

  • Raw size: 21.8 MB baseline 21.8 MB — 🟢 -3.57 kB
  • Gzip: 4.54 MB baseline 4.54 MB — 🟢 -1.93 kB
  • Brotli: 3.37 MB baseline 3.37 MB — 🟢 -1.98 kB
  • Bundles: 167 current • 168 baseline • 143 added / 144 removed

Category Glance
Graph Workspace 🟢 -4.13 kB (949 kB) · Data & Services 🔴 +1.98 kB (3.17 MB) · Other 🟢 -1.38 kB (6.42 MB) · App Entry Points 🟢 -34 B (22.3 kB) · Panels & Settings 🟢 -8 B (440 kB) · Vendor & Third-Party ⚪ 0 B (10.7 MB) · + 5 more

Per-category breakdown
App Entry Points — 22.3 kB (baseline 22.3 kB) • 🟢 -34 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-D3e9WOwT.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -6.73 kB 🟢 -5.92 kB
assets/index-DeWFvxGI.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +6.71 kB 🔴 +5.88 kB

Status: 1 added / 1 removed

Graph Workspace — 949 kB (baseline 953 kB) • 🟢 -4.13 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BKiFO38z.js (removed) 953 kB 🟢 -953 kB 🟢 -193 kB 🟢 -146 kB
assets/GraphView-DK9sLEqb.js (new) 949 kB 🔴 +949 kB 🔴 +192 kB 🔴 +145 kB

Status: 1 added / 1 removed

Views & Navigation — 80.7 kB (baseline 80.7 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-D9sBA109.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.6 kB 🔴 +3.05 kB
assets/CloudSurveyView-DwJcdFqX.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.6 kB 🟢 -3.06 kB
assets/CloudLoginView-MdQtVu75.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.09 kB 🟢 -2.71 kB
assets/CloudLoginView-vCGQOCSV.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.09 kB 🔴 +2.72 kB
assets/UserCheckView-C_S340bI.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.44 kB 🔴 +2.13 kB
assets/UserCheckView-CkSAa3yC.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.44 kB 🟢 -2.13 kB
assets/CloudLayoutView-BlBlrfGS.js (new) 8.54 kB 🔴 +8.54 kB 🔴 +2.24 kB 🔴 +1.95 kB
assets/CloudLayoutView-DB5m0wf1.js (removed) 8.54 kB 🟢 -8.54 kB 🟢 -2.24 kB 🟢 -1.96 kB
assets/CloudSignupView-CVkOjCm_.js (removed) 8.18 kB 🟢 -8.18 kB 🟢 -2.33 kB 🟢 -2.03 kB
assets/CloudSignupView-f1Tupxr7.js (new) 8.18 kB 🔴 +8.18 kB 🔴 +2.32 kB 🔴 +2.03 kB
assets/CloudForgotPasswordView-B0hEwNm2.js (new) 6.26 kB 🔴 +6.26 kB 🔴 +1.92 kB 🔴 +1.68 kB
assets/CloudForgotPasswordView-C0Lxj6Ij.js (removed) 6.26 kB 🟢 -6.26 kB 🟢 -1.92 kB 🟢 -1.68 kB
assets/UserSelectView-1YqfPeeY.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -1.76 kB 🟢 -1.57 kB
assets/UserSelectView-C_OCM0fB.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-Du6osG_l.js (new) 5.27 kB 🔴 +5.27 kB 🔴 +1.73 kB 🔴 +1.54 kB
assets/CloudSubscriptionRedirectView-hLOakm_j.js (removed) 5.27 kB 🟢 -5.27 kB 🟢 -1.73 kB 🟢 -1.54 kB
assets/CloudAuthTimeoutView-Cd-l1kwU.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.7 kB 🟢 -1.48 kB
assets/CloudAuthTimeoutView-lcJ6kprs.js (new) 5.24 kB 🔴 +5.24 kB 🔴 +1.7 kB 🔴 +1.48 kB
assets/CloudSorryContactSupportView-AxA3vaH4.js (removed) 1.97 kB 🟢 -1.97 kB 🟢 -702 B 🟢 -626 B
assets/CloudSorryContactSupportView-nLYfbQhS.js (new) 1.97 kB 🔴 +1.97 kB 🔴 +702 B 🔴 +627 B
assets/layout-BhmMoK9L.js (removed) 500 B 🟢 -500 B 🟢 -308 B 🟢 -265 B
assets/layout-R7hLt225.js (new) 500 B 🔴 +500 B 🔴 +309 B 🔴 +265 B

Status: 11 added / 11 removed

Panels & Settings — 440 kB (baseline 440 kB) • 🟢 -8 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settings-CcQit-ab.js (removed) 38.3 kB 🟢 -38.3 kB 🟢 -9.22 kB 🟢 -7.3 kB
assets/settings-DJTea6Ev.js (new) 38.3 kB 🔴 +38.3 kB 🔴 +9.22 kB 🔴 +7.34 kB
assets/settings-C_UvTZu3.js (removed) 34.3 kB 🟢 -34.3 kB 🟢 -7.93 kB 🟢 -6.58 kB
assets/settings-DhmTNLI9.js (new) 34.3 kB 🔴 +34.3 kB 🔴 +7.93 kB 🔴 +6.58 kB
assets/settings-B3VsXFLW.js (new) 32.1 kB 🔴 +32.1 kB 🔴 +7.68 kB 🔴 +6.22 kB
assets/settings-BTc5qzP7.js (removed) 32.1 kB 🟢 -32.1 kB 🟢 -7.68 kB 🟢 -6.22 kB
assets/settings-B4_MooYG.js (new) 31.2 kB 🔴 +31.2 kB 🔴 +8.08 kB 🔴 +6.72 kB
assets/settings-CgjSbLJ8.js (removed) 31.2 kB 🟢 -31.2 kB 🟢 -8.08 kB 🟢 -6.72 kB
assets/settings-69BUKeP-.js (removed) 30.4 kB 🟢 -30.4 kB 🟢 -7.76 kB 🟢 -6.72 kB
assets/settings-BhUxE7XO.js (new) 30.4 kB 🔴 +30.4 kB 🔴 +7.76 kB 🔴 +6.72 kB
assets/settings-2k-uW27U.js (new) 29.6 kB 🔴 +29.6 kB 🔴 +7.62 kB 🔴 +6.63 kB
assets/settings-ZeWer40V.js (removed) 29.6 kB 🟢 -29.6 kB 🟢 -7.62 kB 🟢 -6.63 kB
assets/settings-BUjoxI2p.js (removed) 29.5 kB 🟢 -29.5 kB 🟢 -7.49 kB 🟢 -6.33 kB
assets/settings-C252B0j_.js (new) 29.5 kB 🔴 +29.5 kB 🔴 +7.5 kB 🔴 +6.34 kB
assets/settings-DIlohv1U.js (new) 28.9 kB 🔴 +28.9 kB 🔴 +7.36 kB 🔴 +6.32 kB
assets/settings-JHh6sqSp.js (removed) 28.9 kB 🟢 -28.9 kB 🟢 -7.36 kB 🟢 -6.33 kB
assets/settings-BJ0CiNVJ.js (removed) 28.6 kB 🟢 -28.6 kB 🟢 -7.71 kB 🟢 -6.38 kB
assets/settings-DBhZ2LBE.js (new) 28.6 kB 🔴 +28.6 kB 🔴 +7.71 kB 🔴 +6.37 kB
assets/settings-CuiAsdhp.js (removed) 25.9 kB 🟢 -25.9 kB 🟢 -7.64 kB 🟢 -6.16 kB
assets/settings-DQsjqwD9.js (new) 25.9 kB 🔴 +25.9 kB 🔴 +7.64 kB 🔴 +6.16 kB
assets/settings-3W2Cy6cq.js (new) 25.2 kB 🔴 +25.2 kB 🔴 +7.41 kB 🔴 +5.76 kB
assets/settings-k3WiAtK4.js (removed) 25.2 kB 🟢 -25.2 kB 🟢 -7.41 kB 🟢 -5.76 kB
assets/LegacyCreditsPanel-CiEq9aiy.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.94 kB 🔴 +5.22 kB
assets/LegacyCreditsPanel-Da_WaQgT.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.94 kB 🟢 -5.22 kB
assets/SubscriptionPanel-B2veoiGj.js (new) 20.9 kB 🔴 +20.9 kB 🔴 +5.01 kB 🔴 +4.42 kB
assets/SubscriptionPanel-CPiAvMjO.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -5.01 kB 🟢 -4.42 kB
assets/KeybindingPanel-B0EE1CpI.js (removed) 14.2 kB 🟢 -14.2 kB 🟢 -3.74 kB 🟢 -3.31 kB
assets/KeybindingPanel-f-ylDrRU.js (new) 14.2 kB 🔴 +14.2 kB 🔴 +3.73 kB 🔴 +3.31 kB
assets/AboutPanel-CjQujN9-.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.68 kB 🔴 +2.42 kB
assets/AboutPanel-Il1u1KpQ.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.68 kB 🟢 -2.44 kB
assets/ExtensionPanel-DPFAv-hm.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.71 kB 🔴 +2.4 kB
assets/ExtensionPanel-DugaFxYH.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.71 kB 🟢 -2.4 kB
assets/WorkspacePanel-CAF5-fo5.js (new) 8.17 kB 🔴 +8.17 kB 🔴 +2.31 kB 🔴 +2.08 kB
assets/WorkspacePanel-oVPhRcAE.js (removed) 8.17 kB 🟢 -8.17 kB 🟢 -2.31 kB 🟢 -2.08 kB
assets/ServerConfigPanel-CHAaVyw7.js (new) 7.23 kB 🔴 +7.23 kB 🔴 +2.16 kB 🔴 +1.94 kB
assets/ServerConfigPanel-DK9YwmQC.js (removed) 7.23 kB 🟢 -7.23 kB 🟢 -2.17 kB 🟢 -1.94 kB
assets/UserPanel-B13pFTX1.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.9 kB 🔴 +1.68 kB
assets/UserPanel-Bw59l7zS.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.9 kB 🟢 -1.68 kB
assets/config-CMnP1Bm9.js (removed) 1.16 kB 🟢 -1.16 kB 🟢 -609 B 🟢 -536 B
assets/config-D02rYqWz.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +604 B 🔴 +533 B
assets/refreshRemoteConfig-BwHfPbfw.js (removed) 1.14 kB 🟢 -1.14 kB 🟢 -520 B 🟢 -452 B
assets/refreshRemoteConfig-Dc_0Bcvf.js (new) 1.14 kB 🔴 +1.14 kB 🔴 +519 B 🔴 +452 B
assets/cloudRemoteConfig-CaeMuZNK.js (new) 1.11 kB 🔴 +1.11 kB 🔴 +507 B 🔴 +444 B
assets/cloudRemoteConfig-DTgcLr8L.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -509 B 🟢 -439 B
assets/refreshRemoteConfig-BjHMPv5B.js (removed) 169 B 🟢 -169 B 🟢 -108 B 🟢 -105 B
assets/refreshRemoteConfig-DjxQATA1.js (new) 169 B 🔴 +169 B 🔴 +108 B 🔴 +106 B
assets/remoteConfig-BufOGckh.js 536 B 536 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 23 added / 23 removed

User & Accounts — 3.94 kB (baseline 3.94 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-APL_4bQt.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.24 kB 🟢 -1.06 kB
assets/auth-RBlfEaAo.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.23 kB 🔴 +1.06 kB
assets/firebaseAuthStore-B3QNjNbo.js (removed) 217 B 🟢 -217 B 🟢 -136 B 🟢 -118 B
assets/firebaseAuthStore-DhFNw891.js (new) 217 B 🔴 +217 B 🔴 +136 B 🔴 +119 B
assets/auth-B3pTp9V4.js (new) 178 B 🔴 +178 B 🔴 +142 B 🔴 +145 B
assets/auth-JWjDsfTA.js (removed) 178 B 🟢 -178 B 🟢 -142 B 🟢 -136 B

Status: 3 added / 3 removed

Editors & Dialogs — 2.83 kB (baseline 2.83 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-CNld_025.js (new) 2.65 kB 🔴 +2.65 kB 🔴 +1.26 kB 🔴 +1.12 kB
assets/useSubscriptionDialog-CRQ-Ru_L.js (removed) 2.65 kB 🟢 -2.65 kB 🟢 -1.25 kB 🟢 -1.11 kB
assets/useSubscriptionDialog-CC5j69_p.js (removed) 179 B 🟢 -179 B 🟢 -110 B 🟢 -99 B
assets/useSubscriptionDialog-DXUqPeVd.js (new) 179 B 🔴 +179 B 🔴 +110 B 🔴 +101 B

Status: 2 added / 2 removed

UI Components — 33.7 kB (baseline 33.7 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-DseqLYtx.js (new) 9.52 kB 🔴 +9.52 kB 🔴 +2.69 kB 🔴 +2.41 kB
assets/ComfyQueueButton-xz-8bjjp.js (removed) 9.52 kB 🟢 -9.52 kB 🟢 -2.69 kB 🟢 -2.42 kB
assets/TopbarBadge-CL9DeJLz.js (new) 8.36 kB 🔴 +8.36 kB 🔴 +1.97 kB 🔴 +1.76 kB
assets/TopbarBadge-DigdimM2.js (removed) 8.36 kB 🟢 -8.36 kB 🟢 -1.97 kB 🟢 -1.76 kB
assets/SubscribeButton-CAgBE82b.js (removed) 4.63 kB 🟢 -4.63 kB 🟢 -1.57 kB 🟢 -1.39 kB
assets/SubscribeButton-CMS7W8x3.js (new) 4.63 kB 🔴 +4.63 kB 🔴 +1.57 kB 🔴 +1.39 kB
assets/WidgetButton-Bfa7g-N9.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +980 B 🔴 +892 B
assets/WidgetButton-ZS6Pl-ac.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -979 B 🟢 -888 B
assets/CloudBadge-D4Onr_uy.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -721 B 🟢 -650 B
assets/CloudBadge-ut0zNg9S.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +721 B 🔴 +646 B
assets/cloudFeedbackTopbarButton-CAf77bKo.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +677 B 🔴 +578 B
assets/cloudFeedbackTopbarButton-DQfc_dmr.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -677 B 🟢 -581 B
assets/ComfyQueueButton-DESDhjSt.js (removed) 181 B 🟢 -181 B 🟢 -118 B 🟢 -120 B
assets/ComfyQueueButton-iWBoBxfL.js (new) 181 B 🔴 +181 B 🔴 +118 B 🔴 +107 B
assets/Button-CFyWbSrm.js 3.77 kB 3.77 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-wKdSR6pn.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

Data & Services — 3.17 MB (baseline 3.17 MB) • 🔴 +1.98 kB

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-Cwo0vElG.js (new) 1.99 MB 🔴 +1.99 MB 🔴 +421 kB 🔴 +321 kB
assets/dialogService-CvWV5JFU.js (removed) 1.99 MB 🟢 -1.99 MB 🟢 -420 kB 🟢 -321 kB
assets/api-BL0Rbyw4.js (removed) 1.16 MB 🟢 -1.16 MB 🟢 -241 kB 🟢 -187 kB
assets/api-Uds_lLHg.js (new) 1.16 MB 🔴 +1.16 MB 🔴 +241 kB 🔴 +187 kB
assets/releaseStore-BeUEhQ0g.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.4 kB 🔴 +2.11 kB
assets/releaseStore-Cdh0vCoR.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.4 kB 🟢 -2.12 kB
assets/keybindingService-BnhMRB7y.js (removed) 6.78 kB 🟢 -6.78 kB 🟢 -1.75 kB 🟢 -1.52 kB
assets/keybindingService-CYUJ1SuL.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +1.74 kB 🔴 +1.52 kB
assets/serverConfigStore-Brqsn51D.js (removed) 2.64 kB 🟢 -2.64 kB 🟢 -876 B 🟢 -780 B
assets/serverConfigStore-D2Rof7C_.js (new) 2.64 kB 🔴 +2.64 kB 🔴 +876 B 🔴 +780 B
assets/userStore-B-WijBWT.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -811 B 🟢 -722 B
assets/userStore-BodjNxBP.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +810 B 🔴 +723 B
assets/audioService-BMeGX5Mg.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -930 B 🟢 -821 B
assets/audioService-ShuEJvJo.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +927 B 🔴 +819 B
assets/teamWorkspaceStore-BkQsQhFJ.js (removed) 165 B 🟢 -165 B 🟢 -123 B 🟢 -115 B
assets/teamWorkspaceStore-CgdEBMhQ.js (new) 165 B 🔴 +165 B 🔴 +123 B 🔴 +106 B
assets/releaseStore-1O5IufUC.js (new) 140 B 🔴 +140 B 🔴 +106 B 🔴 +110 B
assets/releaseStore-ezuKgvyp.js (removed) 140 B 🟢 -140 B 🟢 -106 B 🟢 -109 B

Status: 9 added / 9 removed

Utilities & Hooks — 24 kB (baseline 24 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useErrorHandling-BTTi3fTG.js (new) 5.08 kB 🔴 +5.08 kB 🔴 +1.5 kB 🔴 +1.31 kB
assets/useErrorHandling-KlZllZab.js (removed) 5.08 kB 🟢 -5.08 kB 🟢 -1.5 kB 🟢 -1.31 kB
assets/useWorkspaceUI-BPmp23eO.js (new) 2.25 kB 🔴 +2.25 kB 🔴 +754 B 🔴 +659 B
assets/useWorkspaceUI-C1XrGurM.js (removed) 2.25 kB 🟢 -2.25 kB 🟢 -754 B 🟢 -655 B
assets/useSubscriptionActions-B86pMXpm.js (removed) 2.22 kB 🟢 -2.22 kB 🟢 -869 B 🟢 -764 B
assets/useSubscriptionActions-DGqYl-mX.js (new) 2.22 kB 🔴 +2.22 kB 🔴 +865 B 🔴 +764 B
assets/subscriptionCheckoutUtil-BAnDyCA5.js (removed) 1.98 kB 🟢 -1.98 kB 🟢 -863 B 🟢 -746 B
assets/subscriptionCheckoutUtil-yuNwCLqy.js (new) 1.98 kB 🔴 +1.98 kB 🔴 +859 B 🔴 +747 B
assets/useSubscriptionCredits-BRTcI3V8.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +596 B 🔴 +525 B
assets/useSubscriptionCredits-cEdLJkCO.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -597 B 🟢 -525 B
assets/audioUtils-DbRdSQA3.js (new) 970 B 🔴 +970 B 🔴 +547 B 🔴 +488 B
assets/audioUtils-DzDGeICE.js (removed) 970 B 🟢 -970 B 🟢 -549 B 🟢 -483 B
assets/useCurrentUser-BESTXPy0.js (removed) 145 B 🟢 -145 B 🟢 -114 B 🟢 -107 B
assets/useCurrentUser-DJ5lbZQk.js (new) 145 B 🔴 +145 B 🔴 +114 B 🔴 +105 B
assets/_plugin-vue_export-helper-DLRTaeJK.js 467 B 467 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-CCK-3Mky.js 7.2 kB 7.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-lUeVlENO.js 1.78 kB 1.78 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/tailwindUtil-CPQi43_-.js 488 B 488 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

Vendor & Third-Party — 10.7 MB (baseline 10.7 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-chart-OCOwIMuw.js 408 kB 408 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-9wjwspTM.js 4.1 MB 4.1 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-DfDkDSrj.js 3.04 MB 3.04 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-v0jgPg5n.js 256 kB 256 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-BKpliY5_.js 1.83 MB 1.83 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-BFRBT3RT.js 650 kB 650 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-CRvEKkVc.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-PDw3y6Aq.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 6.42 MB (baseline 6.42 MB) • 🟢 -1.38 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/nodeDefs-DktkFd8R.js (new) 440 kB 🔴 +440 kB 🔴 +68.2 kB 🔴 +43.9 kB
assets/nodeDefs-h_jQ7nTe.js (removed) 440 kB 🟢 -440 kB 🟢 -68.2 kB 🟢 -43.9 kB
assets/nodeDefs-CG0lNwST.js (removed) 405 kB 🟢 -405 kB 🟢 -62 kB 🟢 -40.9 kB
assets/nodeDefs-DEM6bbWr.js (new) 405 kB 🔴 +405 kB 🔴 +62 kB 🔴 +40.9 kB
assets/nodeDefs-BCufohiu.js (new) 405 kB 🔴 +405 kB 🔴 +64 kB 🔴 +42.1 kB
assets/nodeDefs-BtmCD4Ap.js (removed) 405 kB 🟢 -405 kB 🟢 -64 kB 🟢 -42.3 kB
assets/nodeDefs-CDhhI5kx.js (new) 376 kB 🔴 +376 kB 🔴 +62.2 kB 🔴 +40.6 kB
assets/nodeDefs-CvpOKsAt.js (removed) 376 kB 🟢 -376 kB 🟢 -62.2 kB 🟢 -40.6 kB
assets/nodeDefs-C3DlQc9w.js (new) 366 kB 🔴 +366 kB 🔴 +60.9 kB 🔴 +40.3 kB
assets/nodeDefs-CPmZncLJ.js (removed) 366 kB 🟢 -366 kB 🟢 -60.9 kB 🟢 -40.3 kB
assets/nodeDefs-BoAwAPDu.js (removed) 363 kB 🟢 -363 kB 🟢 -60.8 kB 🟢 -41.6 kB
assets/nodeDefs-CB70HGLr.js (new) 363 kB 🔴 +363 kB 🔴 +60.8 kB 🔴 +41.4 kB
assets/nodeDefs-CLZp2I7k.js (new) 363 kB 🔴 +363 kB 🔴 +59.5 kB 🔴 +40.8 kB
assets/nodeDefs-DU5Y_lx_.js (removed) 363 kB 🟢 -363 kB 🟢 -59.5 kB 🟢 -40.8 kB
assets/nodeDefs-B7pXu23d.js (new) 359 kB 🔴 +359 kB 🔴 +58.4 kB 🔴 +40 kB
assets/nodeDefs-DDuiU_FH.js (removed) 359 kB 🟢 -359 kB 🟢 -58.4 kB 🟢 -40 kB
assets/nodeDefs-BvPKtkwY.js (removed) 356 kB 🟢 -356 kB 🟢 -57.6 kB 🟢 -39.4 kB
assets/nodeDefs-CyAJTPTV.js (new) 356 kB 🔴 +356 kB 🔴 +57.6 kB 🔴 +39.4 kB
assets/nodeDefs-12U736i2.js (new) 336 kB 🔴 +336 kB 🔴 +59.8 kB 🔴 +39.3 kB
assets/nodeDefs-B6agiPX1.js (removed) 336 kB 🟢 -336 kB 🟢 -59.8 kB 🟢 -39.3 kB
assets/nodeDefs-BMl5y27M.js (new) 334 kB 🔴 +334 kB 🔴 +58.6 kB 🔴 +38 kB
assets/nodeDefs-qYujY1nz.js (removed) 334 kB 🟢 -334 kB 🟢 -58.6 kB 🟢 -38 kB
assets/core-BNIV_HaA.js (removed) 178 kB 🟢 -178 kB 🟢 -43 kB 🟢 -36 kB
assets/core-Dx3FVuxC.js (new) 178 kB 🔴 +178 kB 🔴 +43 kB 🔴 +35.9 kB
assets/main-4lckbWsV.js (removed) 168 kB 🟢 -168 kB 🟢 -44.6 kB 🟢 -35.3 kB
assets/main-C-5HPtOO.js (new) 168 kB 🔴 +168 kB 🔴 +44.6 kB 🔴 +35.3 kB
assets/main-Bc8UNWJl.js (new) 151 kB 🔴 +151 kB 🔴 +40.1 kB 🔴 +32.4 kB
assets/main-Kfo8Pw0z.js (removed) 151 kB 🟢 -151 kB 🟢 -40.1 kB 🟢 -32.4 kB
assets/main-C_Z2flfA.js (new) 146 kB 🔴 +146 kB 🔴 +40.3 kB 🔴 +32.1 kB
assets/main-DbXoj4jb.js (removed) 146 kB 🟢 -146 kB 🟢 -40.3 kB 🟢 -32.1 kB
assets/main-9QDOXbzo.js (new) 140 kB 🔴 +140 kB 🔴 +40.1 kB 🔴 +32 kB
assets/main-e04f9KyF.js (removed) 140 kB 🟢 -140 kB 🟢 -40.1 kB 🟢 -32.1 kB
assets/main-DsM3PqIA.js (removed) 129 kB 🟢 -129 kB 🟢 -38.8 kB 🟢 -32.5 kB
assets/main-DUt9sjCO.js (new) 129 kB 🔴 +129 kB 🔴 +38.8 kB 🔴 +32.5 kB
assets/main-BMqZNEiD.js (removed) 126 kB 🟢 -126 kB 🟢 -38.6 kB 🟢 -31.3 kB
assets/main-ReiZV-pH.js (new) 126 kB 🔴 +126 kB 🔴 +38.6 kB 🔴 +31.3 kB
assets/main-CZoshpks.js (removed) 124 kB 🟢 -124 kB 🟢 -37.9 kB 🟢 -31.6 kB
assets/main-D-4J6ABr.js (new) 124 kB 🔴 +124 kB 🔴 +37.9 kB 🔴 +31.6 kB
assets/main-C8VQB_yW.js (new) 122 kB 🔴 +122 kB 🔴 +37.8 kB 🔴 +31.6 kB
assets/main-CjO320gS.js (removed) 122 kB 🟢 -122 kB 🟢 -37.8 kB 🟢 -31.6 kB
assets/main-B8XX36kH.js (new) 122 kB 🔴 +122 kB 🔴 +37.3 kB 🔴 +31.3 kB
assets/main-DxcvT18G.js (removed) 122 kB 🟢 -122 kB 🟢 -37.3 kB 🟢 -31.3 kB
assets/main-CVnZPXeK.js (removed) 109 kB 🟢 -109 kB 🟢 -37.3 kB 🟢 -29.7 kB
assets/main-VpW1uLPj.js (new) 109 kB 🔴 +109 kB 🔴 +37.3 kB 🔴 +29.7 kB
assets/main-Bb7LViqw.js (new) 109 kB 🔴 +109 kB 🔴 +37.3 kB 🔴 +29.4 kB
assets/main-P2E7wvoy.js (removed) 109 kB 🟢 -109 kB 🟢 -37.3 kB 🟢 -29.4 kB
assets/Load3D-XxPi2Glp.js (new) 55.7 kB 🔴 +55.7 kB 🔴 +9.18 kB 🔴 +7.9 kB
assets/WidgetSelect-r54T2z9C.js (removed) 50.7 kB 🟢 -50.7 kB 🟢 -11.2 kB 🟢 -9.74 kB
assets/WidgetSelect-CnjZ8mxv.js (new) 50.5 kB 🔴 +50.5 kB 🔴 +11.1 kB 🔴 +9.7 kB
assets/Load3DControls-DZ_5Vv6I.js (removed) 35.9 kB 🟢 -35.9 kB 🟢 -5.87 kB 🟢 -5.09 kB
assets/SubscriptionRequiredDialogContent-A23NNy_I.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +6.78 kB 🔴 +5.92 kB
assets/SubscriptionRequiredDialogContent-BVda3DO0.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -6.77 kB 🟢 -5.91 kB
assets/CurrentUserPopoverWorkspace-CodVztNS.js (new) 21.6 kB 🔴 +21.6 kB 🔴 +4.83 kB 🔴 +4.29 kB
assets/CurrentUserPopoverWorkspace-D5M2WJqb.js (removed) 21.6 kB 🟢 -21.6 kB 🟢 -4.84 kB 🟢 -4.3 kB
assets/Load3D-BliHNYHi.js (removed) 20.9 kB 🟢 -20.9 kB 🟢 -4.59 kB 🟢 -4.02 kB
assets/commands-D7JSvcea.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +3.96 kB 🔴 +3.09 kB
assets/commands-DZxSdjFq.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -3.96 kB 🟢 -3.07 kB
assets/commands-C0ihBqw2.js (new) 19.3 kB 🔴 +19.3 kB 🔴 +3.68 kB 🔴 +2.83 kB
assets/commands-COWR9vVf.js (removed) 19.3 kB 🟢 -19.3 kB 🟢 -3.68 kB 🟢 -2.83 kB
assets/commands-DUy-2VbT.js (new) 19.3 kB 🔴 +19.3 kB 🔴 +3.69 kB 🔴 +2.9 kB
assets/commands-fiTVBhhf.js (removed) 19.3 kB 🟢 -19.3 kB 🟢 -3.69 kB 🟢 -2.9 kB
assets/commands-aJXmdzJz.js (removed) 18.8 kB 🟢 -18.8 kB 🟢 -3.79 kB 🟢 -2.95 kB
assets/commands-Cge8p8D7.js (new) 18.8 kB 🔴 +18.8 kB 🔴 +3.79 kB 🔴 +2.93 kB
assets/commands-BEOD_uzq.js (removed) 18.5 kB 🟢 -18.5 kB 🟢 -3.52 kB 🟢 -2.92 kB
assets/commands-BJLS4KsL.js (new) 18.5 kB 🔴 +18.5 kB 🔴 +3.52 kB 🔴 +2.92 kB
assets/WidgetInputNumber-Dv8iAlT_.js (new) 18.3 kB 🔴 +18.3 kB 🔴 +4.51 kB 🔴 +4.01 kB
assets/WidgetInputNumber-DxJ0W59J.js (removed) 18.3 kB 🟢 -18.3 kB 🟢 -4.51 kB 🟢 -4.02 kB
assets/WidgetRecordAudio-BGd36T9N.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.96 kB 🟢 -4.43 kB
assets/WidgetRecordAudio-Dpkmrhzx.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.96 kB 🔴 +4.43 kB
assets/commands-CVbuwW7U.js (new) 18 kB 🔴 +18 kB 🔴 +3.51 kB 🔴 +2.9 kB
assets/commands-Dln4wOTe.js (removed) 18 kB 🟢 -18 kB 🟢 -3.51 kB 🟢 -2.9 kB
assets/commands-BCMa3myQ.js (new) 18 kB 🔴 +18 kB 🔴 +3.39 kB 🔴 +2.78 kB
assets/commands-BRKb82BA.js (removed) 18 kB 🟢 -18 kB 🟢 -3.4 kB 🟢 -2.76 kB
assets/commands-BUGVA_C8.js (removed) 17.9 kB 🟢 -17.9 kB 🟢 -3.36 kB 🟢 -2.77 kB
assets/commands-DO2o9ZPA.js (new) 17.9 kB 🔴 +17.9 kB 🔴 +3.36 kB 🔴 +2.77 kB
assets/commands-Bxi6-Pt0.js (new) 17.8 kB 🔴 +17.8 kB 🔴 +3.65 kB 🔴 +2.84 kB
assets/commands-DOKSrHX8.js (removed) 17.8 kB 🟢 -17.8 kB 🟢 -3.65 kB 🟢 -2.84 kB
assets/SubscriptionPanelContentWorkspace-DKMVWAnW.js (removed) 17.7 kB 🟢 -17.7 kB 🟢 -4.34 kB 🟢 -3.78 kB
assets/SubscriptionPanelContentWorkspace-Pz7j8XGi.js (new) 17.7 kB 🔴 +17.7 kB 🔴 +4.34 kB 🔴 +3.78 kB
assets/commands-BiO29O5L.js (removed) 17.2 kB 🟢 -17.2 kB 🟢 -3.57 kB 🟢 -2.73 kB
assets/commands-CLzYTTQL.js (new) 17.2 kB 🔴 +17.2 kB 🔴 +3.57 kB 🔴 +2.73 kB
assets/WidgetImageCrop-4evCSNIa.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.14 kB 🟢 -3.62 kB
assets/WidgetImageCrop-rr4tvz-U.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.14 kB 🔴 +3.63 kB
assets/commands-DKxZF1hp.js (removed) 17 kB 🟢 -17 kB 🟢 -3.54 kB 🟢 -2.64 kB
assets/commands-wBNS4y4c.js (new) 17 kB 🔴 +17 kB 🔴 +3.54 kB 🔴 +2.64 kB
assets/PanelTemplate-CMxTTKdC.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +5.44 kB 🔴 +4.79 kB
assets/PanelTemplate-d8PzGPkd.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -5.45 kB 🟢 -4.79 kB
assets/LazyImage-Cb66OgLx.js (removed) 14.1 kB 🟢 -14.1 kB 🟢 -4 kB 🟢 -3.54 kB
assets/LazyImage-CWAjmWVI.js (new) 14.1 kB 🔴 +14.1 kB 🔴 +4 kB 🔴 +3.54 kB
assets/AudioPreviewPlayer-CM-dnrQk.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.97 kB 🟢 -2.65 kB
assets/AudioPreviewPlayer-JxJ3C4rr.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.97 kB 🔴 +2.65 kB
assets/WidgetWithControl-B5psjkaA.js (new) 8.02 kB 🔴 +8.02 kB 🔴 +2.65 kB 🔴 +2.39 kB
assets/WidgetWithControl-BQBiLsSa.js (removed) 8.02 kB 🟢 -8.02 kB 🟢 -2.65 kB 🟢 -2.38 kB
assets/CreateWorkspaceDialogContent-BJhp74CU.js (new) 5.92 kB 🔴 +5.92 kB 🔴 +1.92 kB 🔴 +1.67 kB
assets/CreateWorkspaceDialogContent-gbFmqrXd.js (removed) 5.92 kB 🟢 -5.92 kB 🟢 -1.92 kB 🟢 -1.67 kB
assets/EditWorkspaceDialogContent-BiwBkny9.js (new) 5.69 kB 🔴 +5.69 kB 🔴 +1.87 kB 🔴 +1.64 kB
assets/EditWorkspaceDialogContent-Ck53rNmr.js (removed) 5.69 kB 🟢 -5.69 kB 🟢 -1.87 kB 🟢 -1.63 kB
assets/ValueControlPopover-C8zQjHRJ.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.55 kB 🟢 -1.37 kB
assets/ValueControlPopover-DFQjy2wx.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.55 kB 🔴 +1.37 kB
assets/DeleteWorkspaceDialogContent-DL_EElH_.js (removed) 4.59 kB 🟢 -4.59 kB 🟢 -1.56 kB 🟢 -1.35 kB
assets/DeleteWorkspaceDialogContent-Dmr1CroX.js (new) 4.59 kB 🔴 +4.59 kB 🔴 +1.56 kB 🔴 +1.35 kB
assets/WidgetGalleria-DBXCpmeW.js (new) 4.57 kB 🔴 +4.57 kB 🔴 +1.56 kB 🔴 +1.42 kB
assets/WidgetGalleria-DoosKHEY.js (removed) 4.57 kB 🟢 -4.57 kB 🟢 -1.57 kB 🟢 -1.42 kB
assets/LeaveWorkspaceDialogContent-BRqbIGzD.js (new) 4.41 kB 🔴 +4.41 kB 🔴 +1.5 kB 🔴 +1.32 kB
assets/LeaveWorkspaceDialogContent-DUUzjyd2.js (removed) 4.41 kB 🟢 -4.41 kB 🟢 -1.5 kB 🟢 -1.31 kB
assets/WidgetImageCompare-D0Z-FLOB.js (removed) 3.79 kB 🟢 -3.79 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetImageCompare-DiWB5Po2.js (new) 3.79 kB 🔴 +3.79 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/WidgetColorPicker-o5zzQJj-.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.38 kB 🟢 -1.25 kB
assets/WidgetColorPicker-YiEvSPW9.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.38 kB 🔴 +1.25 kB
assets/WidgetTextarea-DJWb5MM7.js (removed) 3.52 kB 🟢 -3.52 kB 🟢 -1.33 kB 🟢 -1.17 kB
assets/WidgetTextarea-DTT-zbcW.js (new) 3.52 kB 🔴 +3.52 kB 🔴 +1.33 kB 🔴 +1.17 kB
assets/WidgetMarkdown-BZpKAnw5.js (new) 3.22 kB 🔴 +3.22 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/WidgetMarkdown-DKV1i22o.js (removed) 3.22 kB 🟢 -3.22 kB 🟢 -1.28 kB 🟢 -1.13 kB
assets/WidgetToggleSwitch-C6QklopL.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.19 kB 🔴 +1.09 kB
assets/WidgetToggleSwitch-CaP9JEnC.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.19 kB 🟢 -1.09 kB
assets/GlobalToast-BNry_pbs.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.09 kB 🔴 +940 B
assets/GlobalToast-DueEQr11.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.1 kB 🟢 -952 B
assets/SubscribeToRun-BIn3V7So.js (new) 2.96 kB 🔴 +2.96 kB 🔴 +1.15 kB 🔴 +1.01 kB
assets/SubscribeToRun-FePCxnjn.js (removed) 2.96 kB 🟢 -2.96 kB 🟢 -1.15 kB 🟢 -1.01 kB
assets/cloudSessionCookie-CrslReHI.js (new) 2.94 kB 🔴 +2.94 kB 🔴 +930 B 🔴 +800 B
assets/cloudSessionCookie-JFHE4nA_.js (removed) 2.94 kB 🟢 -2.94 kB 🟢 -935 B 🟢 -804 B
assets/MediaVideoTop-BhEl3YYq.js (removed) 2.84 kB 🟢 -2.84 kB 🟢 -1.06 kB 🟢 -916 B
assets/MediaVideoTop-To_wqfzI.js (new) 2.84 kB 🔴 +2.84 kB 🔴 +1.06 kB 🔴 +917 B
assets/WidgetChart-Bdv_mOBE.js (removed) 2.79 kB 🟢 -2.79 kB 🟢 -1.05 kB 🟢 -964 B
assets/WidgetChart-Dbj11DNq.js (new) 2.79 kB 🔴 +2.79 kB 🔴 +1.06 kB 🔴 +973 B
assets/WidgetLayoutField-D80nWHnQ.js (removed) 2.61 kB 🟢 -2.61 kB 🟢 -1.01 kB 🟢 -892 B
assets/WidgetLayoutField-DgB_EnjQ.js (new) 2.61 kB 🔴 +2.61 kB 🔴 +1 kB 🔴 +892 B
assets/WidgetInputText-B1Jj_0fq.js (removed) 2.58 kB 🟢 -2.58 kB 🟢 -1.01 kB 🟢 -910 B
assets/WidgetInputText-DZQxxwRV.js (new) 2.58 kB 🔴 +2.58 kB 🔴 +1.01 kB 🔴 +946 B
assets/BaseViewTemplate-BrA33CSd.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +941 B
assets/BaseViewTemplate-Cie20tXU.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -939 B
assets/Media3DTop-0Ncely1V.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -1.01 kB 🟢 -880 B
assets/Media3DTop-5zcsMbsP.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +1.02 kB 🔴 +902 B
assets/MediaImageTop-355zzTFX.js (removed) 2.34 kB 🟢 -2.34 kB 🟢 -1 kB 🟢 -873 B
assets/MediaImageTop-CpXmTAor.js (new) 2.34 kB 🔴 +2.34 kB 🔴 +1 kB 🔴 +871 B
assets/MediaAudioTop-DAcbk8q3.js (removed) 2 kB 🟢 -2 kB 🟢 -883 B 🟢 -758 B
assets/MediaAudioTop-yJJ6Isec.js (new) 2 kB 🔴 +2 kB 🔴 +882 B 🔴 +760 B
assets/CloudRunButtonWrapper-BOamz7T8.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +642 B 🔴 +562 B
assets/CloudRunButtonWrapper-Bu0AT9DE.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -641 B 🟢 -594 B
assets/widgetPropFilter-B2AM-H0O.js (new) 1.31 kB 🔴 +1.31 kB 🔴 +569 B 🔴 +508 B
assets/widgetPropFilter-BXooU3qU.js (removed) 1.31 kB 🟢 -1.31 kB 🟢 -569 B 🟢 -497 B
assets/cloudBadges-CmkRJhJp.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -540 B 🟢 -501 B
assets/cloudBadges-D4kWcH4p.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +537 B 🔴 +482 B
assets/graphHasMissingNodes-Dnbrydnr.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -457 B 🟢 -422 B
assets/graphHasMissingNodes-xND32Jpr.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +457 B 🔴 +420 B
assets/cloudSubscription-BD4-S7tA.js (removed) 976 B 🟢 -976 B 🟢 -460 B 🟢 -401 B
assets/cloudSubscription-BGlVKmUr.js (new) 976 B 🔴 +976 B 🔴 +459 B 🔴 +401 B
assets/previousFullPath-BFJQC27i.js (new) 838 B 🔴 +838 B 🔴 +415 B 🔴 +346 B
assets/previousFullPath-BgSMorGj.js (removed) 838 B 🟢 -838 B 🟢 -414 B 🟢 -379 B
assets/nightlyBadges-B6gTUUHi.js (new) 594 B 🔴 +594 B 🔴 +355 B 🔴 +314 B
assets/nightlyBadges-URPlQF8X.js (removed) 594 B 🟢 -594 B 🟢 -358 B 🟢 -312 B
assets/SubscriptionPanelContentWorkspace-CO6a436E.js (removed) 266 B 🟢 -266 B 🟢 -136 B 🟢 -112 B
assets/SubscriptionPanelContentWorkspace-Q5qJ_Qk4.js (new) 266 B 🔴 +266 B 🔴 +136 B 🔴 +128 B
assets/WidgetInputNumber-CQNZumr1.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +109 B
assets/WidgetInputNumber-RT1atfXX.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -110 B
assets/WidgetLegacy-4COMQujx.js (new) 164 B 🔴 +164 B 🔴 +125 B 🔴 +113 B
assets/WidgetLegacy-B8DrNZND.js (removed) 164 B 🟢 -164 B 🟢 -125 B 🟢 -122 B
assets/Load3D-BoReNUpf.js (new) 131 B 🔴 +131 B 🔴 +107 B 🔴 +119 B
assets/Load3D-DqoIKv_a.js (removed) 131 B 🟢 -131 B 🟢 -107 B 🟢 -111 B
assets/auto-ShMUXBDI.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-E4_aQOyn.js 143 B 143 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/preservedQueryNamespaces-D99dMmBP.js 3.23 kB 3.23 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-cVp-94Rc.js 1.96 kB 1.96 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-PbcJpAgB.js 4.21 kB 4.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-CD3JnB1i.js 518 B 518 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-CTWd5ZRc.js 186 B 186 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-KpJ-3L5b.js 4.71 kB 4.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 79 added / 80 removed

for (const item of items) {
if (item.type.startsWith('image/')) {
pasteImageNode(canvas as LGraphCanvas, items, imageNode)
await pasteImageNode(canvas as LGraphCanvas, items, imageNode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I know it's not introduced here, but can we clean up the type assertion?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was planning on cleaning up all the type assertion when I got to the audio/video story as it's the last drag and drop / copy & paste task. Unless there is some other type beyond that I should add to that task. I already have another task waiting with the text drag/drop/copy/paste

batchNode.pos = [ x + width + 100, y + 30 ]

// Retrieving Node Height is inconsistent
let height = nodeHeight;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see where the difficulty comes from...

Node image previews is some super mucky code. useLitegraphService().updatePreview has an optional callback modifier that's triggered after the preview image finishes loading, but it's mostly intended for use inside subgraphs and wouldn't be reliable enough to use here.

For litegraph, image previews have a fixed height and you can calc the positions in advance
My personal recommendation would be to always use 344 for height and skip the measurement entirely. This would also allow you to set the node position prior to node creation.

Nodes 2.0 makes things a good bit more difficult.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AustinMroz Updated to use just the fixed height. Sorry about the delay. I saw an approval and assumed I was done.

DrJKL
DrJKL previously approved these changes Jan 24, 2026
@DrJKL DrJKL assigned AustinMroz and unassigned DrJKL Jan 24, 2026
@DrJKL DrJKL self-requested a review January 31, 2026 00:15
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/utils/litegraphUtil.ts`:
- Around line 51-55: The code calls graph.change() even when graph.add(newNode)
may return undefined; modify the logic in the block handling newNode to capture
the result of graph.add via the variable addedNode, check if addedNode is falsy,
and if so show an alert (e.g., alert("Failed to add node")) and return null
without calling graph.change(); only call graph.change() and return addedNode
when addedNode is truthy. Ensure you reference newNode, graph.add, addedNode and
graph.change in the updated flow so the add-failure path is handled cleanly.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/scripts/app.ts`:
- Around line 1463-1464: createNode returns Promise<LGraphNode | null> but
imageNode is used unguarded; add a null-check after awaiting createNode in the
block that calls pasteImageNode to bail out or handle the error when imageNode
is null. Specifically, after const imageNode = await createNode(this.canvas,
'LoadImage') verify imageNode !== null (or throw/log and return) before calling
pasteImageNode(this.canvas, transfer.items, imageNode) so pasteImageNode never
receives a null node.
- Around line 1568-1576: positionBatchNodes currently assumes nodes is non-empty
and uses a hardcoded height for LoadImage; update it to first guard against an
empty nodes array (return early or no-op if nodes.length === 0) and then compute
node height dynamically instead of the magic 344: for example read
nodes[0].size[1] or call nodes[0].computeSize()[1] (fallback to a sensible
default if those are undefined) and use that value when positioning batchNode;
references: positionBatchNodes, nodes, batchNode, and the 'LoadImage' node type.

Copy link
Collaborator

@AustinMroz AustinMroz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must thoroughly apologize. I want to give feedback that is both directed and helpful. That I struggle with doing so has placed unfair burden on you.
The quality of the code looks sufficient to me, and I will give approval as such.

However there's a lot litegraph specific quirks at play here that I could not expect others to either be aware of or to work on fixes for.

  • Positioning of nodes in vue mode after initialization is not currently functional. #7591 was recently reverted in #8619
    • This means that the current arrangement process causes nodes to stack up on the origin point.
    • I've been working on a way to clean this up for a while now, but in the meantime, the safe way to position a newly created node is to pass the desired position for the node as an option for node creation
      • The newly introduced createNode does not include a way to pass such additional options.
    • Vue nodes currently scale height proportionally to the aspect ratio of the contained image preview. This makes programatically determining the height prior to adding nodes to the graph impossible.
      • This has caused frustration in other places as well. I've opened a separate PR to fix this, so no action is required here: #8702
  • I am conflicted about the addition of a new node creation function. I should have directed you towards litegraphService:addNodeOnGraph, but became a little too caught up in the addressing the pertinent technical complications.
  • app.ts is an old part of the code base. While the code changes to it are fine, introducing an app.test.ts feels a little misleading when its only being used to test drag and drop functionality. Perhaps a more targeted app.dropHandler.test.ts would be more appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants