SIGN IN SIGN UP

fix(view): correct remote-mode node counter, spacing, and Topology alignment (#241)

Three independent issues in `all-smi view`'s remote mode plus a README polish in one bundle:

1. **Node counter inflated by reserved tabs.** The dashboard derived `total_nodes` as `state.tabs.len() - 1`, only subtracting the "All" tab. The real tab layout — set in `remote_collector`, `ssh_strategy`, `replay_collector`, `runner` and `event_handler` — is `[All, Users, Topology, host1, …]`, so 50 hosts rendered as `50/52`. Added `is_reserved_tab` / `host_tab_count` helpers in `src/ui/tabs.rs` and switched `draw_system_view` to count only host tabs. The helper is reusable and centralizes the reserved-tab list so future cluster-level tabs can't silently inflate the denominator again.

2. **Live Statistics ↔ Tabs collision.** The remote sparkline panel ended its last row and the tab strip started on the immediately following line, hurting readability on dense clusters. Added one spacer line at the tail of `draw_remote_sparkline_panel` (placed inside the empty-history early-return so it only emits when the panel actually renders) and bumped the matching budget in `LayoutCalculator::calculate_header_lines` from 5 to 6 so the content-area math stays in sync.

3. **Topology tab box borders zig-zagging.** `center()` in `topology::graph_render` measured field width with `str::len()`, but every edge label is built from the unicode `─` (U+2500, 3 bytes / 1 cell), so `center("── NV ──", 13)` saw `len == 16 ≥ 13` and returned the label untouched at 8 visible cells — five short of the cell width. The right border `│` then slipped left and the NUMA box looked broken. Swapped to `s.chars().count()`, which equals display width for the ASCII + single-cell box-drawing characters this module emits, and documented the assumption.

Regression tests:

- `host_tab_count_excludes_reserved_tabs` and `is_reserved_tab_matches_cluster_level_tabs` in `ui::tabs::tests` — assert 50 hosts in the real `[All, Users, Topology, host-0..host-49]` shape count as 50, and pin the reserved-tab list.
- `center_uses_display_width_not_byte_length` in `ui::topology::graph_render::tests` — pins every edge label (`──`, `── NV ──`, `── NV5 ──`, `── NSW ──`, `── PXB ──`, `── NODE ──`, `── SYS ──`) to the requested cell width.
- `render_numa_box_keeps_borders_aligned_with_unicode_edge_labels` — integration check that every border-bearing line of a rendered box has identical visible width.

Also relabels the README download shields so each badge surfaces its source — previously both Crates.io and GitHub badges rendered as bare "downloads | N", which gave no visual cue which count came from which source. They now read "crates.io downloads" and "GitHub downloads".

Full library suite (1033 tests) passes; clippy clean.
J
Jeongkyu Shin committed
710be7759a828ecf51d1b4e0a2b3aa7c8cf5bb22
Parent: 4c3287b
Committed by GitHub <noreply@github.com> on 5/26/2026, 8:01:12 AM