use std::time::{SystemTime, UNIX_EPOCH};
use ratatui::style::Color;
use crate::monitor::dashboard::PalaceRow;
pub const INDEXING_SPINNER: [char; 10] = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
pub const DREAMING_SPINNER: [char; 8] = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PalaceActivity {
Idle,
Indexing,
Active,
Dreaming,
Error,
}
impl PalaceActivity {
pub fn prefix(self, tick: usize) -> char {
match self {
PalaceActivity::Idle => ' ',
PalaceActivity::Indexing => INDEXING_SPINNER[tick % INDEXING_SPINNER.len()],
PalaceActivity::Active => '⠿',
PalaceActivity::Dreaming => DREAMING_SPINNER[tick % DREAMING_SPINNER.len()],
PalaceActivity::Error => '✗',
}
}
pub fn color(self) -> Option<Color> {
match self {
PalaceActivity::Idle => None,
PalaceActivity::Indexing => Some(Color::Yellow),
PalaceActivity::Active => Some(Color::Cyan),
PalaceActivity::Dreaming => Some(Color::Magenta),
PalaceActivity::Error => Some(Color::Red),
}
}
}
pub fn spinner_tick() -> usize {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| (d.as_millis() / 100) as usize)
.unwrap_or(0)
}
pub fn palace_activity_state(
palace: &PalaceRow,
now: chrono::DateTime<chrono::Utc>,
) -> PalaceActivity {
if palace.is_compacting {
return PalaceActivity::Dreaming;
}
match palace.last_write_at {
Some(ts) => {
let delta = now.signed_duration_since(ts);
let secs = delta.num_seconds();
if secs < 10 {
PalaceActivity::Indexing
} else if secs < 60 {
PalaceActivity::Active
} else {
PalaceActivity::Idle
}
}
None => PalaceActivity::Idle,
}
}
pub fn activity_label(activity: PalaceActivity) -> &'static str {
match activity {
PalaceActivity::Idle => "Idle",
PalaceActivity::Indexing => "Indexing",
PalaceActivity::Active => "Active",
PalaceActivity::Dreaming => "Dreaming",
PalaceActivity::Error => "Error",
}
}
pub fn format_relative_time(
now: chrono::DateTime<chrono::Utc>,
ts: chrono::DateTime<chrono::Utc>,
) -> String {
let secs = now.signed_duration_since(ts).num_seconds();
if secs < 5 {
return "just now".to_string();
}
if secs < 60 {
return format!("{secs}s ago");
}
let mins = secs / 60;
if mins < 60 {
return format!("{mins}m ago");
}
let hours = mins / 60;
if hours < 24 {
return format!("{hours}h ago");
}
let days = hours / 24;
format!("{days}d ago")
}