use super::{App, Popup};
use crate::db::{UsageByBackend, UsageByModel, UsageRow, UsageTotals};
pub struct UsageData {
pub totals: UsageTotals,
pub by_backend: Vec<UsageByBackend>,
pub by_model: Vec<UsageByModel>,
pub recent: Vec<UsageRow>,
}
impl App {
pub fn open_usage_popup(&mut self) {
let _ = self.db.backfill_usage_costs();
self.usage_data = Some(self.load_usage());
self.usage_scroll = 0;
self.popup = Popup::Usage;
if self
.usage_data
.as_ref()
.is_some_and(|d| d.totals.requests == 0)
{
self.push_status(self.usage_range.empty_message().to_string());
}
}
pub fn refresh_usage(&mut self) {
let _ = self.db.backfill_usage_costs();
self.usage_data = Some(self.load_usage());
}
pub fn cycle_usage_range(&mut self, dir: i32) {
self.usage_range = if dir >= 0 {
self.usage_range.next()
} else {
self.usage_range.prev()
};
let _ = self.db.set_setting("usage_range", self.usage_range.key());
self.usage_scroll = 0;
self.refresh_usage();
}
pub fn scroll_usage(&mut self, delta: i32) {
let Some(data) = &self.usage_data else { return };
let max = data.recent.len().saturating_sub(1);
self.usage_scroll = if delta >= 0 {
self.usage_scroll.saturating_add(delta as usize).min(max)
} else {
self.usage_scroll
.saturating_sub(delta.unsigned_abs() as usize)
};
}
fn load_usage(&self) -> UsageData {
let since = self.usage_range.since().map(|t| t.to_rfc3339());
UsageData {
totals: self.db.usage_totals(since.as_deref()).unwrap_or_default(),
by_backend: self
.db
.usage_by_backend(since.as_deref())
.unwrap_or_default(),
by_model: self
.db
.usage_by_model(10, since.as_deref())
.unwrap_or_default(),
recent: self
.db
.usage_recent(200, since.as_deref())
.unwrap_or_default(),
}
}
}