Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ Notable changes are documented here. The format follows

## [Unreleased]

## [0.1.7] - 2026-07-26

### Changed

- The OSD map state column now combines daemon state and CRUSH membership as
`up/in`, `up/out`, `down/in`, or `down/out`.
- The dashboard header shows the running version instead of repeating the
project name.

## [0.1.6] - 2026-07-26

### Added
Expand Down Expand Up @@ -127,7 +136,8 @@ Initial release.
- Cross-platform controller (Linux, macOS, Windows) with cargo-dist release
archives that bundle the cephtrace tracers.

[Unreleased]: https://github.com/xtrusia/cephlens/compare/v0.1.6...HEAD
[Unreleased]: https://github.com/xtrusia/cephlens/compare/v0.1.7...HEAD
[0.1.7]: https://github.com/xtrusia/cephlens/compare/v0.1.6...v0.1.7
[0.1.6]: https://github.com/xtrusia/cephlens/compare/v0.1.5...v0.1.6
[0.1.5]: https://github.com/xtrusia/cephlens/compare/v0.1.4...v0.1.5
[0.1.4]: https://github.com/xtrusia/cephlens/compare/v0.1.3...v0.1.4
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cephlens"
version = "0.1.6"
version = "0.1.7"
edition = "2024"
rust-version = "1.88.0"
authors = ["cephlens contributors"]
Expand Down
40 changes: 34 additions & 6 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,10 @@ fn draw_header(frame: &mut Frame<'_>, app: &App, area: Rect) {
})
.unwrap_or_else(|| "rd 0 0 B/s wr 0 0 B/s".to_owned());
let mut spans = vec![
Span::styled(" cephlens ", Style::default().fg(ACCENT).bold()),
Span::styled(
format!(" v{} ", env!("CARGO_PKG_VERSION")),
Style::default().fg(ACCENT).bold(),
),
Span::styled(mode, Style::default().fg(BLUE).bold()),
Span::raw(" "),
pill(health, health_color(health)),
Expand Down Expand Up @@ -1642,8 +1645,9 @@ fn draw_osds(frame: &mut Frame<'_>, app: &App, area: Rect) {
let total = osds.len();
let scroll = clamp_top_scroll(app.osds_scroll, total, visible);
let rows = osds.iter().skip(scroll).take(visible).map(|osd| {
let (map_state, map_state_color) = osd_map_state(&osd.status, osd.reweight);
let status_style = Style::default()
.fg(if osd.status == "up" { OK } else { BAD })
.fg(map_state_color)
.add_modifier(Modifier::BOLD);
let pg_bar = bar(
osd.pgs as f64 / max_pgs as f64,
Expand All @@ -1654,15 +1658,15 @@ fn draw_osds(frame: &mut Frame<'_>, app: &App, area: Rect) {
Row::new(vec![
Cell::from(osd.name.clone()).style(Style::default().fg(ACCENT).bold()),
Cell::from(osd.host.clone()).style(Style::default().fg(TEXT)),
Cell::from(osd.status.clone()).style(status_style),
Cell::from(map_state).style(status_style),
Cell::from(osd.pgs.to_string()),
Cell::from(pg_bar).style(Style::default().fg(BLUE)),
])
} else {
Row::new(vec![
Cell::from(osd.name.clone()).style(Style::default().fg(ACCENT).bold()),
Cell::from(osd.host.clone()).style(Style::default().fg(TEXT)),
Cell::from(osd.status.clone()).style(status_style),
Cell::from(map_state).style(status_style),
Cell::from(format!("{:.3}%", osd.utilization)),
Cell::from(osd.pgs.to_string()),
Cell::from(pg_bar).style(Style::default().fg(BLUE)),
Expand All @@ -1681,7 +1685,7 @@ fn draw_osds(frame: &mut Frame<'_>, app: &App, area: Rect) {
vec![
Constraint::Length(7),
Constraint::Length(12),
Constraint::Length(7),
Constraint::Length(8),
Constraint::Length(5),
Constraint::Length(10),
],
Expand All @@ -1692,7 +1696,7 @@ fn draw_osds(frame: &mut Frame<'_>, app: &App, area: Rect) {
vec![
Constraint::Length(7),
Constraint::Length(12),
Constraint::Length(7),
Constraint::Length(8),
Constraint::Length(9),
Constraint::Length(5),
Constraint::Length(16),
Expand Down Expand Up @@ -1726,6 +1730,21 @@ fn draw_osds(frame: &mut Frame<'_>, app: &App, area: Rect) {
frame.render_widget(table, area);
}

fn osd_map_state(status: &str, reweight: f64) -> (String, Color) {
let is_up = status == "up";
let is_in = reweight > 0.0;
let color = match (is_up, is_in) {
(true, true) => OK,
(true, false) => WARN,
(false, true) => BAD,
(false, false) => BAD,
};
(
format!("{status}/{}", if is_in { "in" } else { "out" }),
color,
)
}

fn draw_logs(frame: &mut Frame<'_>, app: &App, area: Rect) {
let visible = area.height.saturating_sub(2) as usize;
let total = app.logs.len();
Expand Down Expand Up @@ -1996,6 +2015,15 @@ mod tests {
));
}

#[test]
fn osd_map_state_combines_daemon_and_crush_membership() {
assert_eq!(osd_map_state("up", 1.0), ("up/in".to_owned(), OK));
assert_eq!(osd_map_state("up", 0.5), ("up/in".to_owned(), OK));
assert_eq!(osd_map_state("up", 0.0), ("up/out".to_owned(), WARN));
assert_eq!(osd_map_state("down", 1.0), ("down/in".to_owned(), BAD));
assert_eq!(osd_map_state("down", 0.0), ("down/out".to_owned(), BAD));
}

#[test]
fn flow_row_renders_a_directional_path_without_tree_glyphs() {
let path = FlowPath {
Expand Down
Loading