|
|
|
|
@@ -22,10 +22,25 @@ struct ColumnVisibility {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ColumnVisibility {
|
|
|
|
|
/// Calculate actual width needed for all columns
|
|
|
|
|
const NAME_WIDTH: u16 = 23;
|
|
|
|
|
const STATUS_WIDTH: u16 = 10;
|
|
|
|
|
const RAM_WIDTH: u16 = 8;
|
|
|
|
|
const UPTIME_WIDTH: u16 = 8;
|
|
|
|
|
const RESTARTS_WIDTH: u16 = 5;
|
|
|
|
|
const COLUMN_SPACING: u16 = 1; // Space between columns
|
|
|
|
|
|
|
|
|
|
/// Determine which columns to show based on available width
|
|
|
|
|
/// Priority order: Name > Status > RAM > Uptime > Restarts
|
|
|
|
|
fn from_width(width: u16) -> Self {
|
|
|
|
|
if width >= 80 {
|
|
|
|
|
// Full layout: Name (25) + Status (10) + RAM (8) + Uptime (8) + Restarts (5) = 56 chars
|
|
|
|
|
// Calculate cumulative widths for each configuration
|
|
|
|
|
let minimal = Self::NAME_WIDTH + Self::COLUMN_SPACING + Self::STATUS_WIDTH; // 34
|
|
|
|
|
let with_ram = minimal + Self::COLUMN_SPACING + Self::RAM_WIDTH; // 43
|
|
|
|
|
let with_uptime = with_ram + Self::COLUMN_SPACING + Self::UPTIME_WIDTH; // 52
|
|
|
|
|
let full = with_uptime + Self::COLUMN_SPACING + Self::RESTARTS_WIDTH; // 58
|
|
|
|
|
|
|
|
|
|
if width >= full {
|
|
|
|
|
// Show all columns
|
|
|
|
|
Self {
|
|
|
|
|
show_name: true,
|
|
|
|
|
show_status: true,
|
|
|
|
|
@@ -33,8 +48,8 @@ impl ColumnVisibility {
|
|
|
|
|
show_uptime: true,
|
|
|
|
|
show_restarts: true,
|
|
|
|
|
}
|
|
|
|
|
} else if width >= 60 {
|
|
|
|
|
// Hide restarts: Name (25) + Status (10) + RAM (8) + Uptime (8) = 51 chars
|
|
|
|
|
} else if width >= with_uptime {
|
|
|
|
|
// Hide restarts
|
|
|
|
|
Self {
|
|
|
|
|
show_name: true,
|
|
|
|
|
show_status: true,
|
|
|
|
|
@@ -42,8 +57,8 @@ impl ColumnVisibility {
|
|
|
|
|
show_uptime: true,
|
|
|
|
|
show_restarts: false,
|
|
|
|
|
}
|
|
|
|
|
} else if width >= 45 {
|
|
|
|
|
// Hide uptime and restarts: Name (25) + Status (10) + RAM (8) = 43 chars
|
|
|
|
|
} else if width >= with_ram {
|
|
|
|
|
// Hide uptime and restarts
|
|
|
|
|
Self {
|
|
|
|
|
show_name: true,
|
|
|
|
|
show_status: true,
|
|
|
|
|
@@ -52,7 +67,7 @@ impl ColumnVisibility {
|
|
|
|
|
show_restarts: false,
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Minimal: Name (25) + Status (10) = 35 chars
|
|
|
|
|
// Minimal: Name + Status only
|
|
|
|
|
Self {
|
|
|
|
|
show_name: true,
|
|
|
|
|
show_status: true,
|
|
|
|
|
@@ -130,9 +145,11 @@ impl ServicesWidget {
|
|
|
|
|
|
|
|
|
|
/// Format parent service line - returns text without icon for span formatting
|
|
|
|
|
fn format_parent_service_line(&self, name: &str, info: &ServiceInfo, columns: ColumnVisibility) -> String {
|
|
|
|
|
// Truncate long service names to fit layout (account for icon space)
|
|
|
|
|
let short_name = if name.len() > 22 {
|
|
|
|
|
format!("{}...", &name[..19])
|
|
|
|
|
// Truncate long service names to fit layout
|
|
|
|
|
// NAME_WIDTH - 3 chars for "..." = max displayable chars
|
|
|
|
|
let max_name_len = (ColumnVisibility::NAME_WIDTH - 3) as usize;
|
|
|
|
|
let short_name = if name.len() > max_name_len {
|
|
|
|
|
format!("{}...", &name[..max_name_len.saturating_sub(3)])
|
|
|
|
|
} else {
|
|
|
|
|
name.to_string()
|
|
|
|
|
};
|
|
|
|
|
@@ -185,19 +202,19 @@ impl ServicesWidget {
|
|
|
|
|
// Build format string based on column visibility
|
|
|
|
|
let mut parts = Vec::new();
|
|
|
|
|
if columns.show_name {
|
|
|
|
|
parts.push(format!("{:<23}", short_name));
|
|
|
|
|
parts.push(format!("{:<width$}", short_name, width = ColumnVisibility::NAME_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_status {
|
|
|
|
|
parts.push(format!("{:<10}", status_str));
|
|
|
|
|
parts.push(format!("{:<width$}", status_str, width = ColumnVisibility::STATUS_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_ram {
|
|
|
|
|
parts.push(format!("{:<8}", memory_str));
|
|
|
|
|
parts.push(format!("{:<width$}", memory_str, width = ColumnVisibility::RAM_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_uptime {
|
|
|
|
|
parts.push(format!("{:<8}", uptime_str));
|
|
|
|
|
parts.push(format!("{:<width$}", uptime_str, width = ColumnVisibility::UPTIME_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_restarts {
|
|
|
|
|
parts.push(format!("{:<5}", restart_str));
|
|
|
|
|
parts.push(format!("{:<width$}", restart_str, width = ColumnVisibility::RESTARTS_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parts.join(" ")
|
|
|
|
|
@@ -550,19 +567,19 @@ impl ServicesWidget {
|
|
|
|
|
// Build header based on visible columns
|
|
|
|
|
let mut header_parts = Vec::new();
|
|
|
|
|
if columns.show_name {
|
|
|
|
|
header_parts.push(format!("{:<25}", "Service:"));
|
|
|
|
|
header_parts.push(format!("{:<width$}", "Service:", width = ColumnVisibility::NAME_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_status {
|
|
|
|
|
header_parts.push(format!("{:<10}", "Status:"));
|
|
|
|
|
header_parts.push(format!("{:<width$}", "Status:", width = ColumnVisibility::STATUS_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_ram {
|
|
|
|
|
header_parts.push(format!("{:<8}", "RAM:"));
|
|
|
|
|
header_parts.push(format!("{:<width$}", "RAM:", width = ColumnVisibility::RAM_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_uptime {
|
|
|
|
|
header_parts.push(format!("{:<8}", "Uptime:"));
|
|
|
|
|
header_parts.push(format!("{:<width$}", "Uptime:", width = ColumnVisibility::UPTIME_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
if columns.show_restarts {
|
|
|
|
|
header_parts.push(format!("{:<5}", "↻:"));
|
|
|
|
|
header_parts.push(format!("{:<width$}", "↻:", width = ColumnVisibility::RESTARTS_WIDTH as usize));
|
|
|
|
|
}
|
|
|
|
|
let header = header_parts.join(" ");
|
|
|
|
|
|
|
|
|
|
|