-
-
Notifications
You must be signed in to change notification settings - Fork 65
[UI] Enhance interaction of Module Import Relationships enhancement #143
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: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for vite-devtools ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
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.
Pull request overview
This PR enhances the Module Import Relationships visualization by adding a scrollable container for the importers list on the left side. The enhancement limits visible modules to a maximum of 20 (MAX_LINKS) while allowing users to scroll through the complete list. As users scroll, the connecting links dynamically update their positions to maintain visual alignment with the visible modules.
Key changes:
- Introduced scroll tracking for the importers container using
@vueuse/core'suseScrollcomposable - Implemented dynamic link position updates based on scroll offset
- Added unique IDs to links for better tracking during scroll updates
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| width: `${SPACING.width}px`, | ||
| v-if="importers?.length" ref="importersContainer" py1 overflow-y-auto :style="{ | ||
| width: `${SPACING.width + SPACING.marginX}px`, | ||
| maxHeight: `${SPACING.height * importersMaxLength + SPACING.padding * (importersMaxLength - 1)}px`, |
Copilot
AI
Dec 8, 2025
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.
The maxHeight calculation is incorrect. It should include the (importersMaxLength + 1) padding, not (importersMaxLength - 1), to match the nodesHeight calculation at line 52. This causes the scroll container to be too short and cut off content.
The calculation should be:
maxHeight: `${SPACING.height * importersMaxLength + SPACING.padding * (importersMaxLength + 1)}px`,This aligns with how nodesHeight is calculated: SPACING.height * normalizedMaxLinks.value + SPACING.padding * (normalizedMaxLinks.value + 1) + SPACING.border * 2
| maxHeight: `${SPACING.height * importersMaxLength + SPACING.padding * (importersMaxLength - 1)}px`, | |
| maxHeight: `${SPACING.height * importersMaxLength + SPACING.padding * (importersMaxLength + 1)}px`, |
| v-if="module.imports?.length" py1 :style="{ | ||
| width: `${SPACING.width}px`, |
Copilot
AI
Dec 8, 2025
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.
The imports container on the right side is not scrollable like the importers container on the left. If there are more than MAX_LINKS imports, they won't be visible or scrollable. Consider applying the same scrollable behavior to this container for consistency:
<div
v-if="module.imports?.length" ref="importsContainer" py1 overflow-y-auto :style="{
width: `${SPACING.width + SPACING.marginX}px`,
maxHeight: `${SPACING.height * importsMaxLength + SPACING.padding * (importsMaxLength + 1)}px`,
marginTop: `${importsVerticalOffset}px`,
}"
>You would also need to track scroll position and update import link positions similarly to importers.
| v-if="module.imports?.length" py1 :style="{ | |
| width: `${SPACING.width}px`, | |
| v-if="module.imports?.length" ref="importsContainer" py1 overflow-y-auto :style="{ | |
| width: `${SPACING.width + SPACING.marginX}px`, | |
| maxHeight: `${SPACING.height * importsMaxLength + SPACING.padding * (importsMaxLength - 1)}px`, |
| watch( | ||
| () => importersScrollY.value, | ||
| () => { | ||
| updateLinksOffset() | ||
| }, | ||
| ) |
Copilot
AI
Dec 8, 2025
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.
The scroll watcher triggers updateLinksOffset() on every scroll event, which can cause performance issues during rapid scrolling. Consider debouncing or throttling this watcher to reduce the number of updates:
watch(
() => importersScrollY.value,
useDebounceFn(() => {
updateLinksOffset()
}, 16), // ~60fps
)Alternatively, use watchThrottled from @vueuse/core for better performance.
| function updateLinksOffset() { | ||
| for (const [idx, link] of links.value.entries()) { | ||
| if (idx >= (importersMaxLength.value)) { | ||
| continue | ||
| } | ||
| link.source.y = calculateLinkY('importer-start', idx) | ||
| } | ||
| triggerRef(links) | ||
| } |
Copilot
AI
Dec 8, 2025
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.
The updateLinksOffset() function only updates importer links but doesn't handle the case where there are no importers and only imports. When importersMaxLength.value is 0, all links could be import links, but they would still be checked and potentially modified incorrectly.
Consider adding a guard to ensure we're only updating importer links:
function updateLinksOffset() {
if (!importers.value?.length) return
for (const [idx, link] of links.value.entries()) {
if (idx >= importersMaxLength.value) {
continue
}
link.source.y = calculateLinkY('importer-start', idx)
}
triggerRef(links)
}| switch (type) { | ||
| case 'importer-start': | ||
| return ((SPACING.height + SPACING.padding) * i!) + (SPACING.height / 2 + SPACING.padding) + importersVerticalOffset.value | ||
| return ((SPACING.height + SPACING.padding) * i!) + (SPACING.height / 2 + SPACING.padding) + importersVerticalOffset.value - importersScrollY.value % (SPACING.height + SPACING.padding) |
Copilot
AI
Dec 8, 2025
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.
The scroll offset calculation uses modulo operation importersScrollY.value % (SPACING.height + SPACING.padding) which creates a visual "snapping" effect. However, this doesn't account for when there are fewer items than MAX_LINKS.
The modulo should only apply when scrolling is actually possible (i.e., when importers.value?.length > importersMaxLength). Otherwise, importersScrollY.value will always be 0 and the modulo operation is unnecessary.
Consider:
return ((SPACING.height + SPACING.padding) * i!) + (SPACING.height / 2 + SPACING.padding) + importersVerticalOffset.value - (importers.value?.length > importersMaxLength.value ? importersScrollY.value % (SPACING.height + SPACING.padding) : 0)| return ((SPACING.height + SPACING.padding) * i!) + (SPACING.height / 2 + SPACING.padding) + importersVerticalOffset.value - importersScrollY.value % (SPACING.height + SPACING.padding) | |
| return ((SPACING.height + SPACING.padding) * i!) + (SPACING.height / 2 + SPACING.padding) + importersVerticalOffset.value - (importers.value?.length > importersMaxLength.value ? importersScrollY.value % (SPACING.height + SPACING.padding) : 0) |
| v-if="importers?.length" ref="importersContainer" py1 overflow-y-auto :style="{ | ||
| width: `${SPACING.width + SPACING.marginX}px`, | ||
| maxHeight: `${SPACING.height * importersMaxLength + SPACING.padding * (importersMaxLength - 1)}px`, | ||
| marginTop: `${importersVerticalOffset}px`, | ||
| }" |
Copilot
AI
Dec 8, 2025
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.
Multiple attributes on the same line reduce readability. While the formatting is syntactically correct, it would be more maintainable to keep each attribute on its own line or group related attributes together, especially for a div with 5+ attributes. Consider:
<div
v-if="importers?.length"
ref="importersContainer"
py1
overflow-y-auto
:style="{
width: `${SPACING.width + SPACING.marginX}px`,
maxHeight: `${SPACING.height * importersMaxLength + SPACING.padding * (importersMaxLength + 1)}px`,
marginTop: `${importersVerticalOffset}px`,
}"
>| () => { | ||
| updateLinksOffset() | ||
| }, |
Copilot
AI
Dec 8, 2025
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.
The watch callback for importersScrollY can be simplified by passing the function reference directly instead of using an arrow function wrapper:
watch(
() => importersScrollY.value,
updateLinksOffset,
)| () => { | |
| updateLinksOffset() | |
| }, | |
| updateLinksOffset, |
Description
Introduced a scrollable container to:
Limit the number of visible modules and links to MAX_LINKS at a time.
Still allow users to scroll through the full list of modules.
Dynamically render only the currently visible MAX_LINKS connections.
2025-12-08.16-00-10.mp4
Linked Issues
#142
Additional context