Feature/extension bar and explorer tooltip - #4489
Conversation
The metric distribution strip is now fixed directly above the bottom bar instead of sitting below the toolbar. It publishes its height as --cc-file-extension-bar-height, which the floating metrics bar, the legend, both sidebars, and the screenshot capture region account for. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Separate Compare, 3D Print, and Settings with short vertical lines and point the CodeCharta logo at https://codecharta.com/ instead of the GitHub repository. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hovering a file or folder in the File Explorer shows the map's hover tooltip (node name plus active area/height/color metric values), anchored to the right edge of the hovered row. The tooltip service now accepts a minimal TooltipNode so CodeMapNode works alongside the layout Node. The native browser title tooltip on row names is removed as redundant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR implements explorer row hover tooltips using a shared tooltip service, repositions the file extension bar to measure and publish its dynamic height via CSS variables, updates layout components to account for separated bar measurements, and adds navbar polish including dividers and a branding link update. ChangesExplorer tooltip and file extension bar layout updates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
visualization/app/codeCharta/features/viewCubeToolbox/services/screenshot.service.ts (1)
73-114:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winRestore temporary label styles in a
finallyblock.If
html2canvas()orgetCroppedCanvas()throws,restoreLabelsAfterScreenshot()never runs and the map labels stay in their screenshot-only styling for the rest of the session.Suggested fix
private async buildScreenShotCanvas(renderer: WebGLRenderer): Promise<HTMLCanvasElement> { renderer.setPixelRatio(window.devicePixelRatio) renderer.setClearColor(new Color(0, 0, 0), 0) renderer.render(this.threeSceneService.scene, this.threeCameraService.camera) const savedLabelStyles = this.prepareLabelsForScreenshot() @@ - const canvas = await html2canvas(document.querySelector("body"), { - removeContainer: true, - backgroundColor: null, - scrollY: -navBarHeight, - height: Math.max(0, bodyHeight - navBarHeight - bottomBarsHeight), - ignoreElements(element) { - return ( - tagsNamesToIgnore.has(element.tagName.toLowerCase()) || - idsToIgnore.has(element.id) || - (element as HTMLElement).style.zIndex === "10000" - ) - } - }) - - this.restoreLabelsAfterScreenshot(savedLabelStyles) - - return this.getCroppedCanvas(canvas) + try { + const canvas = await html2canvas(document.querySelector("body"), { + removeContainer: true, + backgroundColor: null, + scrollY: -navBarHeight, + height: Math.max(0, bodyHeight - navBarHeight - bottomBarsHeight), + ignoreElements(element) { + return ( + tagsNamesToIgnore.has(element.tagName.toLowerCase()) || + idsToIgnore.has(element.id) || + (element as HTMLElement).style.zIndex === "10000" + ) + } + }) + + return this.getCroppedCanvas(canvas) + } finally { + this.restoreLabelsAfterScreenshot(savedLabelStyles) + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@visualization/app/codeCharta/features/viewCubeToolbox/services/screenshot.service.ts` around lines 73 - 114, The temporary label styles set by prepareLabelsForScreenshot() must always be restored; wrap the async screenshot capture and cropping in a try/finally so restoreLabelsAfterScreenshot(savedLabelStyles) runs regardless of errors: call const savedLabelStyles = this.prepareLabelsForScreenshot() before the try, then inside try await html2canvas(document.querySelector("body"), {...}) and return this.getCroppedCanvas(canvas) (or store the result), and in finally call this.restoreLabelsAfterScreenshot(savedLabelStyles); keep the ignoreElements logic and options for html2canvas unchanged.visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.ts (1)
26-29:⚠️ Potential issue | 🟠 MajorUnsubscribe from
hoveredNodeMetricDistribution$inngOnDestroy()
FileExtensionBarComponent.ngOnInit()creates a rawsubscribe()tometricDistributionService.hoveredNodeMetricDistribution$, butngOnDestroy()only disconnects theResizeObserverand removes--cc-file-extension-bar-height. Since<cc-file-extension-bar>is rendered inside@if (isInitialized())incodeCharta.component.html, the component can be recreated and each old subscriber will remain active.Suggested fix
export class FileExtensionBarComponent implements OnInit, AfterViewInit, OnDestroy { showAbsoluteValues = false metricDistribution: CategorizedMetricDistribution private readonly elementReference = inject(ElementRef<HTMLElement>) private resizeObserver?: ResizeObserver + private metricDistributionSubscription?: { unsubscribe(): void } constructor(private readonly metricDistributionService: MetricDistributionService) {} ngOnInit(): void { - this.metricDistributionService.hoveredNodeMetricDistribution$.subscribe(metricDistribution => { + this.metricDistributionSubscription = this.metricDistributionService.hoveredNodeMetricDistribution$.subscribe(metricDistribution => { this.metricDistribution = metricDistribution }) } @@ ngOnDestroy(): void { + this.metricDistributionSubscription?.unsubscribe() this.resizeObserver?.disconnect() document.documentElement.style.removeProperty("--cc-file-extension-bar-height") } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.ts` around lines 26 - 29, The component creates a raw subscription to metricDistributionService.hoveredNodeMetricDistribution$ in ngOnInit but never tears it down; add a Subscription (e.g., hoveredMetricSubscription) or a destroyed Subject and store the subscription returned from metricDistributionService.hoveredNodeMetricDistribution$.subscribe(...) in that field inside ngOnInit, then unsubscribe (or complete the Subject and use takeUntil) in ngOnDestroy alongside the existing ResizeObserver cleanup and removal of --cc-file-extension-bar-height to prevent leaked subscribers when FileExtensionBarComponent is recreated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In
`@visualization/app/codeCharta/features/viewCubeToolbox/services/screenshot.service.ts`:
- Around line 73-114: The temporary label styles set by
prepareLabelsForScreenshot() must always be restored; wrap the async screenshot
capture and cropping in a try/finally so
restoreLabelsAfterScreenshot(savedLabelStyles) runs regardless of errors: call
const savedLabelStyles = this.prepareLabelsForScreenshot() before the try, then
inside try await html2canvas(document.querySelector("body"), {...}) and return
this.getCroppedCanvas(canvas) (or store the result), and in finally call
this.restoreLabelsAfterScreenshot(savedLabelStyles); keep the ignoreElements
logic and options for html2canvas unchanged.
In
`@visualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.ts`:
- Around line 26-29: The component creates a raw subscription to
metricDistributionService.hoveredNodeMetricDistribution$ in ngOnInit but never
tears it down; add a Subscription (e.g., hoveredMetricSubscription) or a
destroyed Subject and store the subscription returned from
metricDistributionService.hoveredNodeMetricDistribution$.subscribe(...) in that
field inside ngOnInit, then unsubscribe (or complete the Subject and use
takeUntil) in ngOnDestroy alongside the existing ResizeObserver cleanup and
removal of --cc-file-extension-bar-height to prevent leaked subscribers when
FileExtensionBarComponent is recreated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 231a9679-d201-4b1f-9b6a-b64cec6244e3
📒 Files selected for processing (19)
plans/2026-06-12-explorer-hover-tooltip.mdplans/2026-06-12-navbar-extension-bar-fixes.mdvisualization/CHANGELOG.mdvisualization/app/codeCharta/codeCharta.component.htmlvisualization/app/codeCharta/features/metricsBar/components/metricsBar/metricsBar.component.tsvisualization/app/codeCharta/features/navBar/components/navBar/navBar.component.htmlvisualization/app/codeCharta/features/navBar/components/navBarLogo/navBarLogo.component.htmlvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeItemName/explorerTreeItemName.component.htmlvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeLevel/explorerTreeLevel.component.htmlvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeLevel/explorerTreeLevel.component.spec.tsvisualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeLevel/explorerTreeLevel.component.tsvisualization/app/codeCharta/features/sidebarExplorer/components/sidebarExplorer/sidebarExplorer.component.tsvisualization/app/codeCharta/features/sidebarInspector/components/sidebarInspector/sidebarInspector.component.tsvisualization/app/codeCharta/features/viewCubeToolbox/services/screenshot.service.tsvisualization/app/codeCharta/ui/codeMap/codeMap.component.scssvisualization/app/codeCharta/ui/codeMap/codeMap.component.tsvisualization/app/codeCharta/ui/codeMap/codeMap.tooltip.service.tsvisualization/app/codeCharta/ui/fileExtensionBar/fileExtensionBar.component.tsvisualization/app/codeCharta/ui/legendPanel/legendPanel.component.scss
💤 Files with no reviewable changes (1)
- visualization/app/codeCharta/features/sidebarExplorer/components/explorerTreeItemName/explorerTreeItemName.component.html



{Meaningful title}
Please read the CONTRIBUTING.md before opening a PR.
Closes: #
Description
Descriptive pull request text, answering:
Definition of Done
A PR is only ready for merge once all the following acceptance criteria are fulfilled:
Screenshots or gifs
Summary by CodeRabbit
New Features
Changed
Bug Fixes