Skip to content

fix(ui): local mode Activity panel polish — border off-by-one, P/E gauge alignment, @hostname suppression, ANE row always-on, and Processes header restyle#166

Merged
inureyes merged 8 commits into
mainfrom
fix/issue-165-local-mode-activity-panel-polish
Apr 10, 2026
Merged

fix(ui): local mode Activity panel polish — border off-by-one, P/E gauge alignment, @hostname suppression, ANE row always-on, and Processes header restyle#166
inureyes merged 8 commits into
mainfrom
fix/issue-165-local-mode-activity-panel-polish

Conversation

@inureyes

Copy link
Copy Markdown
Member

Summary

Fixes #165 — seven small but visible issues in the local-mode Activity panel and device list rendering on Apple Silicon.

  • Border off-by-one: Fix CPU Cores panel bottom border emitting panel_width + 1 columns instead of panel_width, which also broke the GPU Metrics panel alignment on the same row.
  • P/E gauge alignment: Compute one shared bar_width in draw_pe_cluster_bars using the larger block section so P-CPU and E-CPU gauges end at the same column.
  • Thermal badge removal: Drop the "Nominal" thermal pressure badge from the GPU Temp sparkline row. This also fixes the GPU Temp sparkline being shorter than the rows above it.
  • Hostname suppression: Add show_hostname: bool parameter to print_gpu_info, print_cpu_info, print_memory_info, and print_storage_info. Skip @ hostname in local mode. Also skip hostname scroll animation in local mode.
  • ANE always-on: Replace has_ane_data (gated on ane_utilization > 0) with show_ane_row returning true whenever Apple Silicon is detected. Add show_npu_row scaffolding for future Intel NPU support.
  • Processes header restyle: Replace bare Processes: with styled title rule ── Processes ──────────.

Test plan

  • cargo fmt --check passes
  • cargo clippy passes with no warnings
  • cargo test passes (325 tests, 0 failures)
  • Visual check: CPU Cores panel borders align top to bottom
  • Visual check: P-CPU and E-CPU gauges end at the same column
  • Visual check: GPU Temp sparkline same length as GPU Util/GPU Mem rows
  • Visual check: @ hostname not shown on GPU/CPU/Memory/Disk rows in local mode
  • Visual check: ANE row present in GPU Metrics panel even when idle
  • Visual check: Processes section opens with styled title rule

…nment

Fix bottom border emitting panel_width+1 columns instead of panel_width
by changing the dash loop from 0..(inner_width+1) to 0..inner_width.

Compute one shared bar_width in draw_pe_cluster_bars using the larger
block section so P-CPU and E-CPU gauges end at the same column.
Drop the Nominal/Fair/Serious/Critical thermal badge from the GPU Temp
row in the GPU Metrics panel. The row already shows a numeric die
temperature in degrees C, and the badge was the only row with a trailing
badge, causing the GPU Temp sparkline to be shorter than the rows above.
Add show_hostname parameter to print_gpu_info, print_cpu_info,
print_memory_info, and print_storage_info. In local mode, skip the
@ hostname segment entirely so the rest of the line shifts left to
fill the gap. Also skip advancing the hostname scroll animation in
local mode to avoid wasting CPU on invisible marquee animation.
Replace has_ane_data (which gated on ane_utilization > 0) with
show_ane_row that returns true whenever Apple Silicon is detected.
An ANE at 0 W is a meaningful idle reading, and the row reflects
real hardware layout even when the Neural Engine is completely idle.

Add show_npu_row scaffolding that returns false for future Intel
NPU telemetry support.
Replace bare "Processes:" text with a styled horizontal rule that
matches the rest of the UI: "── Processes ──────────────"
@inureyes inureyes added type:bug Something isn't working priority:medium Medium priority issue device:apple-silicon Apple Silicon related status:review Under review labels Apr 10, 2026
@inureyes

Copy link
Copy Markdown
Member Author

Implementation Review Summary

Intent

Fix seven visual polish issues in the local-mode Activity panel and device list rendering on Apple Silicon: border off-by-one, P/E gauge alignment, thermal badge removal, hostname suppression, ANE always-on, NPU scaffolding, and Processes header restyle.

Verification

  • All stated requirements implemented
  • No placeholder/mock code remaining
  • Integrated into project code flow
  • Project conventions followed
  • Existing modules reused where applicable
  • No unintended structural changes
  • Tests pass (325 unit + 385 integration, 0 failures)

Detailed findings

All seven issue requirements are correctly and completely implemented:

Fix 1 - Border off-by-one (activity_panel.rs:214): Changed 0..(inner_width + 1) to 0..inner_width, making the bottom border emit panel_width columns matching top border and content rows. Correct.

Fix 2 - P/E gauge shared bar_width (activity_panel.rs:376-378): Pre-computes shared_bar_width using p_block_width.max(e_block_width), then passes it to both draw_cluster_line calls. The function signature was updated to accept bar_width: usize directly. Correct.

Fix 3 - Thermal badge removal (gpu_sparkline_panel.rs): Removed thermal_pressure_badge helper, thermal_badge computation in build_rows, and thermal_pressure from test fixtures. All badge fields set to None. GPU Temp row now has badge: None. Correct.

Fix 4 - GPU Temp sparkline width (resolved by Fix 3): With badge_len = 0 for all rows, sparkline_width is now identical across GPU Util, GPU Mem, and GPU Temp. Correct.

Fix 5 - Hostname suppression (4 renderers + frame_renderer.rs + ui_loop.rs): Added show_hostname: bool to print_gpu_info, print_cpu_info, print_memory_info, print_storage_info. All call sites pass true in remote mode and false in local mode. format_hostname_with_scroll is properly gated inside the conditional. Hostname scroll animation in ui_loop.rs is skipped in local mode for both GPU and CPU hostname updates. Chassis renderer is untouched per spec. Correct.

Fix 6 - ANE always-on + NPU scaffolding (gpu_sparkline_panel.rs): has_ane_data renamed to show_ane_row, now returns detect_apple_silicon(state) (no power gate). show_npu_row added, returns false with doc comment pointing to src/api/metrics/npu/common.rs. Both are wired into gpu_content_rows and build_rows. Tests cover ANE-idle case and NPU scaffolding. Correct.

Fix 7 - Processes header restyle (process_renderer.rs:62-74): Replaced bare "Processes:\r\n" with styled title rule using Cyan for prefix/title and DarkGrey for trailing dashes. Still emits exactly 1 row, so RESERVED_HEADER_ROWS = 4 is unchanged. Correct.

Minor observations (LOW, not blocking)

  • #[allow(clippy::unnecessary_wraps)] on show_npu_row is a no-op since the function returns bool, not Option/Result. Harmless but unnecessary.
  • Comment at process_renderer.rs:194 still says "Processes:" title -- could say "styled title rule" to match the new implementation. Purely cosmetic.

Remaining Items

None -- all seven fixes are correctly implemented with no issues found.

The lint only fires for Option/Result returns, not bool. The attribute
was a no-op and misleading about the function's return type semantics.
@inureyes

Copy link
Copy Markdown
Member Author

Security & Performance Review -- PR #166

Scope

Reviewed all 9 changed files (171 additions, 111 deletions) for security vulnerabilities, performance regressions, and code quality issues.

Findings

FIXED -- LOW: Dead clippy allow attribute (commit 3759566)

#[allow(clippy::unnecessary_wraps)] on show_npu_row in src/ui/gpu_sparkline_panel.rs was a no-op. The unnecessary_wraps lint only fires on functions returning Option or Result, not bool. The attribute was misleading about the function's semantics. Removed.

INFO -- LOW: Minor block-width formula inconsistency

In src/ui/activity_panel.rs, the p_block_width formula at line 376 (cores.len() + cores.len() / 4) does not subtract 1 for the trailing-group-of-4 case, while the blocks_printed formula at line 426 does. This means shared_bar_width is 1 column shorter than necessary when the core count is a multiple of 4. The lost column becomes right-side padding, so the visual output is correct and panel width is maintained. No fix needed -- the inconsistency is cosmetic (1 pixel of bar) and the conservative direction (shorter bar, not overflow).

INFO -- Pre-existing: Byte-index slice on Unicode header

src/ui/process_renderer.rs:174 uses header_format[horizontal_scroll_offset..] which is a byte-index slice. The header contains multi-byte Unicode sort arrows (3 bytes each). If horizontal_scroll_offset lands mid-character, this would panic. This is pre-existing code not introduced by this PR, but worth tracking for a future hardening pass.

Verified Clean

  • cargo test -- all 325 tests pass (0 failures)
  • cargo clippy -- -D warnings -- no warnings
  • cargo fmt --check -- clean
  • All show_hostname call sites in frame_renderer.rs are consistent: true for remote-mode renderers, false (or !view_state.is_local_mode) for local-mode renderers
  • saturating_sub is used correctly throughout for width calculations -- no integer underflow risk
  • No new unwrap() calls on fallible data paths
  • No memory leaks: hostname scroll animation correctly skipped in local mode (no growing offset map entries)
  • No security concerns: pure UI rendering code with no user input parsing, no file I/O, no network access

Overall Assessment

This PR is well-written. The changes are straightforward UI polish with proper use of saturating_sub for safe arithmetic, correct gating of hostname animations to avoid wasted work, and clean separation of local/remote rendering paths. One dead attribute was removed.

…nderers

Cover the new show_hostname: bool parameter added to print_cpu_info,
print_memory_info, and print_storage_info in the local-mode polish PR.
Each renderer gains smoke tests verifying hostname appears when show_hostname
is true and is suppressed when false, plus scrolling and narrow-width cases.

18 new tests (343 total, all passing).
@inureyes inureyes added status:done Completed and removed status:review Under review labels Apr 10, 2026
@inureyes inureyes merged commit d268a3c into main Apr 10, 2026
2 checks passed
@inureyes inureyes deleted the fix/issue-165-local-mode-activity-panel-polish branch April 10, 2026 05:12
@inureyes inureyes self-assigned this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

device:apple-silicon Apple Silicon related priority:medium Medium priority issue status:done Completed type:bug Something isn't working

Projects

None yet

1 participant