Skip to content

Conversation

benceruleanlu
Copy link
Member

@benceruleanlu benceruleanlu commented Sep 21, 2025

Summary

Increase functionality for slots and links, covered with playwright tests.

Features

  • Allow for reroute anchors to work when dragging from input slot
  • Allow for dragging existing links from input slot
  • Allow for ctrl/command + alt to create new link from input slot
  • Allow shift to drag all connected links on output slot
  • Connect links with reroutes (only when dragged from vue slot)

Tests Added

Playwright

  • Dragging input to input drags existing link
  • Dropping an input link back on its slot restores the original connection
  • Ctrl+alt drag from an input starts a fresh link
  • Should reuse the existing origin when dragging an input link
  • Shift-dragging an output with multiple links should drag all links
  • Rerouted input drag preview remains anchored to reroute
  • Rerouted output shift-drag preview remains anchored to reroute

Notes

The double rendering system for links being dragged, it works right now, maybe they can be coalesced later.

Edit: As in the adapter, can be removed in a followup PR

Also, it's known that more features will arrive in smaller PRs, this PR actually should've been much smaller.

The next ones coming up are drop on canvas support, snap to node, type compatibility highlighting, and working with subgraphs.

┆Issue is synchronized with this Notion page by Unito

Copy link

github-actions bot commented Sep 21, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 09/26/2025, 02:56:06 AM UTC

📈 Summary

  • Total Tests: 468
  • Passed: 436 ✅
  • Failed: 0
  • Flaky: 3 ⚠️
  • Skipped: 29 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 429 / ❌ 0 / ⚠️ 3 / ⏭️ 29
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 4 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@benceruleanlu
Copy link
Member Author

the two failing tests are screenshot expectations that I added that were bugged from the overlapping dirty workflow dot indicator and the close workflow button

@benceruleanlu benceruleanlu marked this pull request as ready for review September 24, 2025 05:31
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Sep 24, 2025
Copy link
Contributor

Choose a reason for hiding this comment

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

question (non-blocking): Can you explain these changes briefly?

Copy link
Member Author

Choose a reason for hiding this comment

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

this was for testing/iteration, and was supposed to be removed in the 'those who know' commit, but wasn't cleaned up fully

it didn't have any callers, I just removed it now

Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

LGTM with nits

Comment on lines 143 to 171
type InputConnectableLink = RenderLink & {
toType: 'input'
canConnectToInput: (node: LGraphNode, input: INodeInputSlot) => boolean
}

type OutputConnectableLink = RenderLink & {
toType: 'output'
canConnectToOutput: (node: LGraphNode, output: INodeOutputSlot) => boolean
}

function isInputConnectableLink(
link: RenderLink
): link is InputConnectableLink {
return (
link.toType === 'input' &&
typeof (link as { canConnectToInput?: unknown }).canConnectToInput ===
'function'
)
}

function isOutputConnectableLink(
link: RenderLink
): link is OutputConnectableLink {
return (
link.toType === 'output' &&
typeof (link as { canConnectToOutput?: unknown }).canConnectToOutput ===
'function'
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (non-blocking): We could consider using more robust type guards and/or discriminated unions for link types.

Copy link
Member Author

Choose a reason for hiding this comment

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

true, changed this to intersection typed, and I think a true discriminated union for RenderLink can be done in another PR

Comment on lines +108 to +121
const adapter = ensureActiveAdapter()
if (graph && adapter) {
if (layout.type === 'input') {
candidate.compatible = adapter.isInputValidDrop(
layout.nodeId,
layout.index
)
} else if (layout.type === 'output') {
candidate.compatible = adapter.isOutputValidDrop(
layout.nodeId,
layout.index
)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

question: What is the lifecycle of the adapter like? Is it necessary to have explicit cleanup?

Copy link
Member Author

Choose a reason for hiding this comment

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

ignoring the quoted code, the adapter is a weakmap per graph

we need the explicit cleanup because the adapter has its own linkconnector, so the regular linkconnector won't reset for us, and reset is used for things like _dragging flags and anything using listenUntilReset

outputNode: LGraphNode,
output: INodeOutputSlot,
events: CustomEventTarget<LinkConnectorEventMap>
): LLink | null | undefined {
Copy link
Contributor

Choose a reason for hiding this comment

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

question: Is it possible to make the meaning of the return types more explicit?

The API contract might be somewhat confusing if undefined and null have different semantics. If they are the same, would it be possible to only return null or only return undefined?

Copy link
Member Author

Choose a reason for hiding this comment

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

this code was removed after addressing other review comments

// This avoids relying on an exact path hit-test position.
await comfyPage.page.evaluate(
([targetNodeId, targetSlot, clientPoint]) => {
const app = (window as any)['app']
Copy link
Contributor

Choose a reason for hiding this comment

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

nit (non-blocking): could we use "expect-error" directive so this is easier to cleanup/refactor/audit later on?

Copy link
Member Author

Choose a reason for hiding this comment

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

wouldn't that get flagged when linting? also, I think the PR that will switch off of as any will have a simple script to prepend with expect error

const colour = resolveConnectingLinkColor(sourceSlot?.type)
const adapter = createLinkConnectorAdapter()
const renderLinks = adapter?.renderLinks
if (!adapter || !renderLinks || renderLinks.length === 0) return
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: if adapter is falsy here, then so is renderLinks by necessity.

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:links area:vue-migration size:XXL This PR changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants