use ratatui::{ Frame, layout::Rect, style::{Color, Modifier, Style}, text::Span, widgets::{Block, Borders, Cell, Row, Table}, }; use super::format_date; use crate::app::AppState; /// Return a color for an audit action string. fn action_color(action: &str) -> Color { match action { "imported" | "import" | "created" => Color::Green, "deleted" | "delete" | "removed" => Color::Red, "tagged" | "tag_added" => Color::Cyan, "untagged" | "tag_removed" => Color::Yellow, "updated" | "modified" | "edited" => Color::Blue, "scanned" | "scan" => Color::Magenta, _ => Color::White, } } pub fn render(f: &mut Frame, state: &AppState, area: Rect) { let header = Row::new(vec!["Action", "Media ID", "Details", "Date"]).style( Style::default() .fg(Color::Yellow) .add_modifier(Modifier::BOLD), ); let rows: Vec = state .audit_log .iter() .enumerate() .map(|(i, entry)| { let style = if Some(i) == state.audit_selected { Style::default().fg(Color::Black).bg(Color::Cyan) } else { Style::default() }; let color = action_color(&entry.action); let action_cell = Cell::from(Span::styled( entry.action.clone(), Style::default().fg(color).add_modifier(Modifier::BOLD), )); // Truncate media ID for display let media_display = entry .media_id .as_deref() .map(|id| { if id.len() > 12 { format!("{}...", &id[..12]) } else { id.to_string() } }) .unwrap_or_else(|| "-".into()); Row::new(vec![ action_cell, Cell::from(media_display), Cell::from(entry.details.clone().unwrap_or_else(|| "-".into())), Cell::from(format_date(&entry.timestamp).to_string()), ]) .style(style) }) .collect(); let title = format!(" Audit Log ({}) ", state.audit_log.len()); let table = Table::new(rows, [ ratatui::layout::Constraint::Percentage(18), ratatui::layout::Constraint::Percentage(22), ratatui::layout::Constraint::Percentage(40), ratatui::layout::Constraint::Percentage(20), ]) .header(header) .block(Block::default().borders(Borders::ALL).title(title)); f.render_widget(table, area); }