-
Notifications
You must be signed in to change notification settings - Fork 376
Implement drop-on-canvas + linkconnectoradapter consolidation #5898
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: bl-snap
Are you sure you want to change the base?
Conversation
🎭 Playwright Test Results❌ Some tests failed ⏰ Completed at: 10/03/2025, 11:35:16 AM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
y: number | ||
} | ||
|
||
const pointerHistory = new Map<number, PointerOffsets>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[performance] medium Priority
Issue: Pointer history map grows unbounded without cleanup of stale entries
Context: pointerHistory Map on line 13 accumulates entries for all pointer IDs but only explicitly cleans up when clearCanvasPointerHistory is called, which may not happen for all pointers
Suggestion: Add periodic cleanup or use WeakMap if possible, or implement automatic cleanup in pointerup/pointercancel events
event.clientY | ||
]) | ||
|
||
const canvas = useCanvasStore().getCanvas() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[quality] low Priority
Issue: Potential undefined canvas access without null check
Context: useCanvasStore().getCanvas() could return undefined, then accessing .ds property would throw
Suggestion: Add null check: const canvas = useCanvasStore().getCanvas(); if (!canvas) return defaultEnhancement;
if (cached != null) { | ||
candidate.compatible = cached | ||
} else { | ||
const nodeId = Number(layout.nodeId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[quality] medium Priority
Issue: Inconsistent nodeId types - mixing string and number conversions
Context: Layout.nodeId is string (line 34) but converted to number for graph.getNodeById calls throughout the codebase
Suggestion: Establish consistent type discipline - either use NodeId type consistently or create utility functions for safe conversion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is something I'm working on to fix, it's scuffed right now but works, it's because of the terrible group node code that forces it to be number or string type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is something I'm working on to fix, it's scuffed right now but works, it's because of the terrible group node code that forces it to be number or string type
|
||
if (!adapter || !graph) return null | ||
|
||
const nodeId = Number(nodeIdStr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[quality] medium Priority
Issue: No validation that Number() conversion succeeded before using nodeId
Context: Number(layout.nodeId) could return NaN if layout.nodeId contains non-numeric data, which would cause graph.getNodeById to fail silently
Suggestion: Add validation: const nodeId = Number(layout.nodeId); if (isNaN(nodeId)) return null;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We technically support string-based node IDs (like "nodeName") if you look at the backend code - esp. for subgraphs or virtual nodes on the backend IIRC.
import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events' | ||
import { app } from '@/scripts/app' | ||
|
||
// Keep one adapter per graph so rendering and interaction share state. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[architecture] low Priority
Issue: WeakMap usage might cause adapter recreation if LGraph is temporarily dereferenced
Context: WeakMap allows garbage collection which could cause adapter recreation, potentially breaking the singleton pattern intended by the comment above
Suggestion: Consider if explicit cleanup on graph destruction would be more predictable than relying on GC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if that happens i think that should be fixed and not making this more resilient
|
||
app.canvas?.setDirty(true, true) | ||
} | ||
const raf = createRafBatch(processPointerMoveFrame) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[performance] medium Priority
Issue: Heavy computation in RAF callback could cause frame drops
Context: processPointerMoveFrame performs expensive DOM queries, layout lookups, and cache operations on every animation frame
Suggestion: Consider debouncing DOM queries or pre-caching hover targets to reduce per-frame work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true, let me recheck perf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Review Summary
PR: Implement drop-on-canvas + linkconnectoradapter consolidation (#5898)
Impact: 469 additions, 240 deletions across 15 files
Issue Distribution
- Critical: 0
- High: 0
- Medium: 4
- Low: 3
Category Breakdown
- Architecture: 1 issues
- Security: 0 issues
- Performance: 2 issues
- Code Quality: 4 issues
Key Findings
Architecture & Design
This PR implements a significant refactor of the link interaction system with good architectural principles:
- LinkConnectorAdapter consolidation: Good move to eliminate duplicate state by wrapping the live canvas linkConnector rather than creating new instances
- Drop orchestrator pattern: Clean separation of concerns with specialized functions for slot and node surface candidate resolution
- Canvas pointer event abstraction: Well-designed abstraction for canvas coordinate conversion and pointer history
The WeakMap usage for adapter caching follows a reasonable pattern, though the garbage collection behavior might cause unexpected adapter recreation.
Performance Impact
The RAF-based pointer movement processing is well-architected but could benefit from optimization:
- Heavy DOM querying operations on every animation frame
- Unbounded pointer history growth without cleanup mechanisms
- Consider debouncing expensive operations or pre-caching hover targets
Bundle impact appears minimal with mostly refactoring existing functionality.
Integration Points
- Backward compatibility: Preserved existing Vue composable behavior patterns
- Extension compatibility: Maintained existing public APIs that extensions depend on
- Test coverage: Excellent Playwright test coverage for the new shift-drop functionality
Positive Observations
- Comprehensive E2E test coverage including edge cases and error scenarios
- Clean TypeScript interfaces and proper type safety throughout
- Good use of caching patterns to avoid repeated expensive operations
- Proper cleanup patterns with pointer history management
- Well-structured composable following Vue 3 best practices
References
- Repository Architecture Guide
- Vue 3 Composition API patterns
- ComfyUI Frontend Guidelines (CLAUDE.md)
Next Steps
- Address medium priority issues for better robustness (pointer history cleanup, number validation)
- Consider performance optimizations for RAF callbacks
- Validate comprehensive test coverage passes
- Consider documenting the event propagation patterns
This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review.
@codex review |
Codex Review: Didn't find any major issues. 👍 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting |
Implements droponcanvas functionality and a linkconnectoradapter refactor.
There are some followup PRs that will fix/refactor some more noncritical things, like the terrible slotid, the number/string nodeid confusion, etc.
#5898 <-- #5903