Skip to content

Commit 5f8f95c

Browse files
committed
feat: refactor container metrics display and remove unused metric badge function
1 parent 8c3f74a commit 5f8f95c

2 files changed

Lines changed: 90 additions & 73 deletions

File tree

crates/aetheris-app/src/app/object_detail.rs

Lines changed: 90 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -404,90 +404,125 @@ pub(super) fn rebuild_container_metrics(list: &gtk::ListBox, detail: &ObjectDeta
404404
pub(super) fn container_metric_row(
405405
resources: &ContainerResources,
406406
usage: Option<&ContainerUsage>,
407-
) -> adw::ExpanderRow {
408-
let action = adw::ExpanderRow::builder()
407+
) -> adw::ActionRow {
408+
let action = adw::ActionRow::builder()
409409
.title(resources.name.as_str())
410-
.expanded(false)
410+
.subtitle(if usage.is_some() {
411+
tr("Current / Request / Limit")
412+
} else {
413+
tr("Metrics unavailable; showing requests and limits")
414+
})
411415
.build();
412-
if let Some(usage) = usage {
413-
let metrics = gtk::Box::new(gtk::Orientation::Horizontal, 12);
414-
metrics.set_valign(gtk::Align::Center);
415-
metrics.set_margin_start(12);
416-
metrics.append(&metric_badge(
417-
"applications-engineering-symbolic",
418-
&tr("CPU usage"),
419-
&format_cpu_quantity(&usage.cpu),
420-
&usage.cpu,
421-
));
422-
metrics.append(&metric_badge(
423-
"drive-harddisk-symbolic",
424-
&tr("Memory usage"),
425-
&format_memory_quantity(&usage.memory),
426-
&usage.memory,
427-
));
428-
action.add_suffix(&metrics);
429-
} else {
430-
action.set_subtitle(&tr("Metrics unavailable"));
431-
}
432-
action.add_row(&container_resource_row(
416+
417+
let metrics = gtk::Box::new(gtk::Orientation::Horizontal, 12);
418+
metrics.set_valign(gtk::Align::Center);
419+
metrics.set_margin_start(12);
420+
metrics.append(&resource_usage_chip(
433421
&tr("CPU"),
434422
usage.map(|usage| usage.cpu.as_str()),
435423
&resources.cpu_request,
436424
&resources.cpu_limit,
437425
"applications-engineering-symbolic",
438426
format_cpu_quantity,
439427
));
440-
action.add_row(&container_resource_row(
428+
metrics.append(&resource_usage_chip(
441429
&tr("Memory"),
442430
usage.map(|usage| usage.memory.as_str()),
443431
&resources.memory_request,
444432
&resources.memory_limit,
445433
"drive-harddisk-symbolic",
446434
format_memory_quantity,
447435
));
436+
action.add_suffix(&metrics);
448437
action
449438
}
450439

451-
fn container_resource_row(
440+
fn resource_usage_chip(
452441
title: &str,
453442
current: Option<&str>,
454443
request: &str,
455444
limit: &str,
456445
icon_name: &str,
457446
formatter: fn(&str) -> String,
458-
) -> adw::ActionRow {
459-
let row = adw::ActionRow::builder().title(title).build();
460-
row.add_prefix(&gtk::Image::from_icon_name(available_icon_name(
447+
) -> gtk::Box {
448+
let chip = gtk::Box::new(gtk::Orientation::Horizontal, 6);
449+
chip.set_valign(gtk::Align::Center);
450+
chip.set_size_request(150, -1);
451+
452+
let icon = gtk::Image::from_icon_name(available_icon_name(
461453
icon_name,
462454
"applications-system-symbolic",
463-
)));
464-
row.add_suffix(&resource_text_pair(
465-
&tr("Current"),
466-
current.unwrap_or("-"),
467-
formatter,
468455
));
469-
row.add_suffix(&resource_text_pair(&tr("Request"), request, formatter));
470-
row.add_suffix(&resource_text_pair(&tr("Limit"), limit, formatter));
471-
row
472-
}
456+
icon.add_css_class("dim-label");
457+
icon.set_tooltip_text(Some(title));
458+
chip.append(&icon);
459+
460+
let text = gtk::Box::new(gtk::Orientation::Vertical, 1);
461+
let heading = gtk::Label::new(Some(title));
462+
heading.add_css_class("caption");
463+
heading.add_css_class("dim-label");
464+
heading.set_xalign(0.0);
465+
text.append(&heading);
466+
467+
let bar_row = gtk::Box::new(gtk::Orientation::Horizontal, 6);
468+
bar_row.set_valign(gtk::Align::Center);
469+
let bar = gtk::LevelBar::new();
470+
bar.set_size_request(76, -1);
471+
bar.set_valign(gtk::Align::Center);
472+
bar.set_min_value(0.0);
473+
bar.set_max_value(1.0);
474+
bar.remove_offset_value(Some("low"));
475+
bar.remove_offset_value(Some("high"));
476+
bar.add_offset_value("lb-normal", 0.85);
477+
bar.add_offset_value("lb-warning", 0.95);
478+
bar.add_offset_value("lb-error", 1.0);
479+
480+
let raw_current = current.unwrap_or("-");
481+
let base = super::utils::parse_quantity(request)
482+
.filter(|value| *value > 0.0)
483+
.or_else(|| super::utils::parse_quantity(limit).filter(|value| *value > 0.0));
484+
let current_value = super::utils::parse_quantity(raw_current);
485+
let percent = current_value
486+
.zip(base)
487+
.map(|(current, base)| current / base);
488+
let formatted_current = format_resource_value(raw_current, formatter);
489+
let formatted_request = format_resource_value(request, formatter);
490+
let formatted_limit = format_resource_value(limit, formatter);
491+
492+
if let Some(percent) = percent {
493+
bar.set_value(percent.clamp(0.0, 1.0));
494+
} else {
495+
bar.set_value(0.0);
496+
}
473497

474-
fn resource_text_pair(label: &str, value: &str, formatter: fn(&str) -> String) -> gtk::Box {
475-
let pair = gtk::Box::new(gtk::Orientation::Vertical, 2);
476-
pair.set_valign(gtk::Align::Center);
477-
pair.set_margin_start(10);
478-
479-
let title = gtk::Label::new(Some(label));
480-
title.add_css_class("caption");
481-
title.add_css_class("dim-label");
482-
title.set_xalign(1.0);
483-
pair.append(&title);
484-
485-
let value_label = gtk::Label::new(Some(&format_resource_value(value, formatter)));
486-
value_label.add_css_class("caption");
487-
value_label.set_xalign(1.0);
488-
value_label.set_tooltip_text(Some(value));
489-
pair.append(&value_label);
490-
pair
498+
let tooltip = if let Some(percent) = percent {
499+
tr_format(
500+
"{resource}: {percent}% used. Current {current}, Request {request}, Limit {limit}",
501+
&[
502+
("{resource}", title.to_owned()),
503+
("{percent}", format!("{:.0}", percent * 100.0)),
504+
("{current}", formatted_current.clone()),
505+
("{request}", formatted_request),
506+
("{limit}", formatted_limit),
507+
],
508+
)
509+
} else {
510+
tr_format(
511+
"{resource}: Current {current}, Request {request}, Limit {limit}",
512+
&[
513+
("{resource}", title.to_owned()),
514+
("{current}", formatted_current.clone()),
515+
("{request}", formatted_request),
516+
("{limit}", formatted_limit),
517+
],
518+
)
519+
};
520+
chip.set_tooltip_text(Some(&tooltip));
521+
bar.set_tooltip_text(Some(&tooltip));
522+
bar_row.append(&bar);
523+
text.append(&bar_row);
524+
chip.append(&text);
525+
chip
491526
}
492527

493528
fn format_resource_value(value: &str, formatter: fn(&str) -> String) -> String {

crates/aetheris-app/src/app/widgets.rs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,24 +1093,6 @@ fn metric_bar_with_width(
10931093
cell.upcast()
10941094
}
10951095

1096-
pub(super) fn metric_badge(icon_name: &str, label: &str, value: &str, raw_value: &str) -> gtk::Box {
1097-
let badge = gtk::Box::new(gtk::Orientation::Horizontal, 6);
1098-
badge.set_valign(gtk::Align::Center);
1099-
badge.set_tooltip_text(Some(&format!("{label}: {raw_value}")));
1100-
let icon = gtk::Image::from_icon_name(available_icon_name(
1101-
icon_name,
1102-
"applications-system-symbolic",
1103-
));
1104-
icon.add_css_class("dim-label");
1105-
icon.set_tooltip_text(Some(label));
1106-
badge.append(&icon);
1107-
let label = gtk::Label::new(Some(value));
1108-
label.add_css_class("caption");
1109-
label.set_tooltip_text(Some(raw_value));
1110-
badge.append(&label);
1111-
badge
1112-
}
1113-
11141096
pub(super) fn available_icon_name<'a>(preferred: &'a str, fallback: &'a str) -> &'a str {
11151097
let Some(display) = gtk::gdk::Display::default() else {
11161098
return fallback;

0 commit comments

Comments
 (0)