Skip to content

feat: improve details view with tree hierarchy (go4dot-3re)#123

Merged
nvandessel merged 1 commit intomainfrom
polecat/nitro/go4dot-3re@mmf2psf5
Mar 6, 2026
Merged

feat: improve details view with tree hierarchy (go4dot-3re)#123
nvandessel merged 1 commit intomainfrom
polecat/nitro/go4dot-3re@mmf2psf5

Conversation

@nvandessel
Copy link
Copy Markdown
Owner

@nvandessel nvandessel commented Mar 6, 2026

Summary

  • Improves the details panel with tree hierarchy rendering for filesystem mappings

Source

  • Issue: go4dot-3re
  • Worker: nitro
  • MR: go-wisp-i0e0

Test plan

  • Pre-verified by polecat
  • Rebased cleanly on main
  • go test ./... passed (1 pre-existing failure tracked in go-56z)

Summary by CodeRabbit

  • New Features

    • Added PATHS section displaying Source and Destination paths
    • Introduced dynamic status indicators for filesystem mapping status
  • Improvements

    • Enhanced tree rendering with improved visual connectors and better hierarchy
    • Redesigned external and module dependencies display with cleaner two-column layout
    • Refined formatting consistency across dashboard sections
    • Removed legacy total stats block

- Replace flat indentation with proper tree connectors (├─, └─, │)
- Add PATHS section showing source and destination directories
- Inline linked/total stats in FILESYSTEM MAPPINGS header
- Use tree connectors for external repositories section
- Better visual consolidation throughout the details panel

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nvandessel nvandessel merged commit bbc2ab4 into main Mar 6, 2026
4 checks passed
@nvandessel nvandessel deleted the polecat/nitro/go4dot-3re@mmf2psf5 branch March 6, 2026 21:19
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 6, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3057610a-41e8-4829-b148-89693f783aad

📥 Commits

Reviewing files that changed from the base of the PR and between 96218e3 and 5f4decc.

📒 Files selected for processing (1)
  • internal/ui/dashboard/details_panel.go

📝 Walkthrough

Walkthrough

The details panel rendering in the dashboard has been refactored to improve visual hierarchy and information organization. Tree rendering now uses structural connectors (├─, └─, │) for file mappings, a PATHS section displays source and destination directories, external dependencies use a two-column tree layout, and the filesystem stats section now includes dynamic status indicators.

Changes

Cohort / File(s) Summary
Dashboard Details Panel UI Enhancement
internal/ui/dashboard/details_panel.go
Added os import; introduced PATHS section showing Source and Dest paths; enhanced filesystem mappings with dynamic stats tags (✓ or warning); refactored renderFileTree function signature to accept prefix and isRoot parameters for improved tree connectors (├─, └─, │); converted external dependencies display from bullet points to tree-like two-column layout; replaced bullet markers with space-prefixed items for consistency; removed legacy "Total: X files" stats line.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Beneath the terminal's glow, the trees now stand so tall,
With connectors neat and branches branching through it all,
Paths revealed, dependencies styled, a visual delight—
The dashboard dances with new grace, each detail shining bright!

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch polecat/nitro/go4dot-3re@mmf2psf5

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR improves the details panel by replacing the flat file list with a proper tree hierarchy using box-drawing connectors (├─, └─, ), adds a new PATHS section showing the source and destination directories, and moves the linked/total file count inline with the section header. The changes are purely in internal/ui/dashboard/details_panel.go.

Key observations:

  • Logic bug: The new [N/N ✓] stats tag fires when linked == total, which is true even when both are 0. This shows a false green success badge for configs with no tracked files. The existing IsFullyLinked() helper guards against this with && s.TotalCount > 0 but the inline check does not.
  • Hardcoded destination: The Dest: label always reads from os.Getenv("HOME"), regardless of the actual stow target configured for the package. This may display an incorrect path for non-standard setups.
  • Slice aliasing: allNames := append(dirs, files...) may alias dirs's backing array — not a current bug, but a future-proofing concern.
  • Missing VHS visual tests: AGENTS.md explicitly mandates VHS visual test updates for all TUI changes. No new tape or golden file is included in this PR.

Confidence Score: 3/5

  • Safe to merge after fixing the 0/0 false-success badge; remaining issues are style/best-practice concerns.
  • The tree rendering logic itself is well-structured and the visual improvement is real. However, the linked == total check producing a green badge when both are 0 is a clear logic bug that will misrepresent empty configs. The hardcoded $HOME destination and the slice-aliasing pattern lower confidence slightly. VHS visual tests are mandatory per project guidelines and are absent.
  • internal/ui/dashboard/details_panel.go — specifically the statsTag condition (line 207) and the Dest path derivation (line 194).

Important Files Changed

Filename Overview
internal/ui/dashboard/details_panel.go Adds a PATHS section to the details panel, upgrades the file tree to use proper box-drawing connectors (├─, └─, │), and moves the linked/total stats inline with the FILESYSTEM MAPPINGS header. Contains a logical bug where 0/0 files renders as a green success badge, a hardcoded $HOME destination, and a Go slice-aliasing pattern worth cleaning up. VHS visual tests are not included despite being mandatory for TUI changes per AGENTS.md.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    RC[renderConfigDetails] --> PATHS["PATHS section\n(Source + Dest via os.Getenv('HOME'))"]
    RC --> FM["FILESYSTEM MAPPINGS header\n+ statsTag [linked/total]"]
    FM --> BFT[buildFileTree\nfiles → fileTreeNode tree]
    BFT --> RFT["renderFileTree\nprefix='', isRoot=true"]
    RFT --> SORT["Sort: dirs first,\nthen files alphabetically"]
    SORT --> ITER["For each child:\nisLast? → connector ├─ or └─"]
    ITER -->|isDir| DIR["Render: linePrefix + connector + name/\nRecurse with childPrefix, isRoot=false"]
    ITER -->|isFile| FILE["Determine icon:\n✓ okStyle\n⚠ warnStyle (conflict/exists/elsewhere)\n✗ errStyle"]
    FILE --> ISSUE["If !isLinked && issue != ''\nRender: childPrefix + → + issue"]
    RC --> DEPS[MODULE DEPENDENCIES]
    RC --> EXTDEPS["EXTERNAL REPOSITORIES\ntree connectors ├─/└─"]
Loading

Last reviewed commit: 5f4decc

Comment on lines 203 to +211
if linkStatus != nil {
lines = append(lines, headerStyle.Render("FILESYSTEM MAPPINGS"))
linked := linkStatus.LinkedCount
total := linkStatus.TotalCount
var statsTag string
if linked == total {
statsTag = okStyle.Render(fmt.Sprintf(" [%d/%d ✓]", linked, total))
} else {
statsTag = warnStyle.Render(fmt.Sprintf(" [%d/%d]", linked, total))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

False success badge when TotalCount is 0

When linked == total == 0 (i.e., a config with no files has been loaded into linkStatus), this branch renders a green [0/0 ✓] badge, incorrectly indicating a fully-linked state. The existing IsFullyLinked() helper in stow/status.go already guards against this with && s.TotalCount > 0, but this inline check omits that guard.

Suggested change
if linkStatus != nil {
lines = append(lines, headerStyle.Render("FILESYSTEM MAPPINGS"))
linked := linkStatus.LinkedCount
total := linkStatus.TotalCount
var statsTag string
if linked == total {
statsTag = okStyle.Render(fmt.Sprintf(" [%d/%d ✓]", linked, total))
} else {
statsTag = warnStyle.Render(fmt.Sprintf(" [%d/%d]", linked, total))
}
if linkStatus != nil {
linked := linkStatus.LinkedCount
total := linkStatus.TotalCount
var statsTag string
if total > 0 && linked == total {
statsTag = okStyle.Render(fmt.Sprintf(" [%d/%d ✓]", linked, total))
} else {
statsTag = warnStyle.Render(fmt.Sprintf(" [%d/%d]", linked, total))
}

Comment on lines +194 to +199
home := os.Getenv("HOME")
if home != "" {
lines = append(lines, fmt.Sprintf("%s %s",
subtleStyle.Render("Dest: "),
pathStyle.Render(home)))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Destination hardcoded to $HOME regardless of stow target

os.Getenv("HOME") is always used as the destination, but the actual GNU stow target directory is not necessarily $HOME for all configs and setups. If the stow target is configurable (e.g., via a flag or the state), this will always display the wrong path. The p.state already carries DotfilesPath — does it also carry the stow target? If so, that should be used here instead to accurately reflect where symlinks land.

Additionally, even when $HOME is correct as a base, showing only the root directory as "Dest" is a bit coarse — all the individual file destinations can be inferred by the tree below, so consider whether this label adds enough clarity or may confuse users into thinking files are symlinked at $HOME rather than inside it.

Comment on lines +330 to +332
// Combine into ordered list for proper connector rendering
allNames := append(dirs, files...)
totalChildren := len(allNames)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Potential slice aliasing with append(dirs, files...)

In Go, append(dirs, files...) will reuse dirs's underlying array if it has sufficient capacity, making allNames alias dirs. While dirs is not modified after this point and there's no runtime bug here today, this is a classic Go footgun. If future code ever modifies dirs after this line (e.g., for a secondary sort pass or debug output), it will silently corrupt allNames. The idiomatic safe pattern is to allocate explicitly:

Suggested change
// Combine into ordered list for proper connector rendering
allNames := append(dirs, files...)
totalChildren := len(allNames)
allNames := make([]string, 0, len(dirs)+len(files))
allNames = append(allNames, dirs...)
allNames = append(allNames, files...)

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 6, 2026

Codecov Report

❌ Patch coverage is 81.53846% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.37%. Comparing base (96218e3) to head (5f4decc).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/ui/dashboard/details_panel.go 81.53% 12 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #123      +/-   ##
==========================================
+ Coverage   49.30%   49.37%   +0.06%     
==========================================
  Files         110      110              
  Lines       12946    12977      +31     
==========================================
+ Hits         6383     6407      +24     
- Misses       6563     6570       +7     
Files with missing lines Coverage Δ
internal/ui/dashboard/details_panel.go 47.02% <81.53%> (+2.92%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant