use std::collections::HashMap;
use super::app::{DashState, LogMonitor};
use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, List, ListItem},
Frame,
};
use strfmt::{strfmt,strfmt_builder};
#[derive(Copy, Clone)]
pub enum NodeMetric {
Index,
StoragePayments,
StorageCost,
Puts,
Gets,
Errors,
Peers,
Memory,
Status,
}
pub const COLUMN_HEADERS: [(NodeMetric, &str, &str); 9] = [
(NodeMetric::Index, "Node", "{index:>4} "),
(NodeMetric::StoragePayments, "Earned nanos", "{storage_payments:>17} "),
(NodeMetric::StorageCost, "StoreCost", "{storage_cost:>11} "),
(NodeMetric::Puts, "PUTS", "{puts:>11} "),
(NodeMetric::Gets, "GETS", "{gets:>11} "),
(NodeMetric::Errors, "Errors", "{errors:>11} "),
(NodeMetric::Peers, "Connections", "{connections:>11} "),
(NodeMetric::Memory, "MB RAM", "{memory:>11} "),
(NodeMetric::Status, "Status", " {status:<500} "),
];
pub fn sort_nodes_by_column(dash_state: &mut DashState, monitors: &mut HashMap<String, LogMonitor>) {
use std::cmp::Ordering;
let sort_by = COLUMN_HEADERS[dash_state.summary_window_heading_selected].0;
dash_state.logfile_names_sorted.sort_by(|a, b| {
let mut ordering = Ordering::Equal;
if let Some(a) = monitors.get(a) {
if let Some(b) = monitors.get(b) {
ordering = match sort_by {
NodeMetric::Index => { a.index.cmp(&b.index) },
NodeMetric::StoragePayments => { a.metrics.storage_payments.total.cmp(&b.metrics.storage_payments.total) },
NodeMetric::StorageCost => { a.metrics.storage_cost.most_recent.cmp(&b.metrics.storage_cost.most_recent) },
NodeMetric::Puts => { a.metrics.activity_puts.total.cmp(&b.metrics.activity_puts.total) },
NodeMetric::Gets => { a.metrics.activity_gets.total.cmp(&b.metrics.activity_gets.total) },
NodeMetric::Errors => { a.metrics.activity_errors.total.cmp(&b.metrics.activity_errors.total) },
NodeMetric::Peers => { a.metrics.peers_connected.most_recent.cmp(&b.metrics.peers_connected.most_recent) },
NodeMetric::Memory => { a.metrics.memory_used_mb.most_recent.cmp(&b.metrics.memory_used_mb.most_recent) },
NodeMetric::Status => { a.metrics.node_status_string.cmp(&b.metrics.node_status_string) },
}
}
};
if dash_state.logfile_names_sorted_ascending { ordering } else { ordering.reverse() }
});
}
pub fn format_table_row(monitor: &mut LogMonitor) -> String {
let mut row_text = String::from("");
for i in 0..COLUMN_HEADERS.len() {
let (metric, _heading, format_string) = &COLUMN_HEADERS[i];
row_text += &match metric {
NodeMetric::Index => { strfmt!(format_string, index => monitor.index + 1).unwrap() },
NodeMetric::StoragePayments => { strfmt!(format_string, storage_payments => monitor.metrics.storage_payments.total).unwrap() },
NodeMetric::StorageCost => { strfmt!(format_string, storage_cost => monitor.metrics.storage_cost.most_recent).unwrap() },
NodeMetric::Puts => { strfmt!(format_string, puts => monitor.metrics.activity_puts.total).unwrap() },
NodeMetric::Gets => { strfmt!(format_string, gets => monitor.metrics.activity_gets.total).unwrap() },
NodeMetric::Errors => { strfmt!(format_string, errors => monitor.metrics.activity_errors.total).unwrap() },
NodeMetric::Peers => { strfmt!(format_string, connections => monitor.metrics.peers_connected.most_recent).unwrap() },
NodeMetric::Memory => { strfmt!(format_string, memory => monitor.metrics.memory_used_mb.most_recent).unwrap() },
NodeMetric::Status => { strfmt!(format_string, status => monitor.metrics.node_status_string.clone()).unwrap() },
};
};
row_text
}
pub fn draw_summary_table_window(f: &mut Frame, area: Rect, dash_state: &mut DashState, monitors: &mut HashMap<String, LogMonitor>) {
let constraints = [
Constraint::Length(1), Constraint::Min(0), ];
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints(constraints.as_ref())
.split(area);
draw_summary_headings(f, chunks[0], dash_state, monitors);
draw_summary_rows(f, chunks[1], dash_state, monitors);
}
pub fn initialise_summary_headings(dash_state: &mut DashState) {
for i in 0..COLUMN_HEADERS.len() {
let (metric, heading, format_string) = &COLUMN_HEADERS[i];
dash_state.summary_window_headings.items.push(
match metric {
NodeMetric::Index => { strfmt!(format_string, index => *heading).unwrap() },
NodeMetric::StoragePayments => { strfmt!(format_string, storage_payments => *heading).unwrap() },
NodeMetric::StorageCost => { strfmt!(format_string, storage_cost => *heading).unwrap() },
NodeMetric::Puts => { strfmt!(format_string, puts => *heading).unwrap() },
NodeMetric::Gets => { strfmt!(format_string, gets => *heading).unwrap() },
NodeMetric::Errors => { strfmt!(format_string, errors => *heading).unwrap() },
NodeMetric::Peers => { strfmt!(format_string, connections => *heading).unwrap() },
NodeMetric::Memory => { strfmt!(format_string, memory => *heading).unwrap() },
NodeMetric::Status => { strfmt!(format_string, status => *heading).unwrap() },
});
};
}
fn draw_summary_headings(f: &mut Frame, area: Rect, dash_state: &mut DashState, _monitors: &mut HashMap<String, LogMonitor>) {
let heading_style = Style::default().fg(Color::White).bg(Color::Black);
let highlight_style = Style::default()
.bg(Color::LightGreen)
.add_modifier(Modifier::BOLD);
let mut index = 0;
let spans: Vec<Span> = dash_state
.summary_window_headings
.items
.iter()
.map(|s| {
Span::styled(s.clone(),
if dash_state.summary_window_heading_selected != index {
index += 1; heading_style
} else {
index += 1; highlight_style
})
})
.collect();
let summary_header_widget = List::new(vec![ListItem::new(vec![Line::from(spans)])])
.block( Block::default())
.highlight_style(highlight_style);
f.render_widget(
summary_header_widget,
area,
);
}
fn draw_summary_rows(f: &mut Frame, area: Rect, dash_state: &mut DashState, _monitors: &mut HashMap<String, LogMonitor>) {
let highlight_style = Style::default()
.bg(Color::LightGreen)
.add_modifier(Modifier::BOLD);
let items: Vec<ListItem> = dash_state
.summary_window_rows
.items
.iter()
.map(|s| {
ListItem::new(vec![Line::from(s.clone())])
.style(Style::default().fg(Color::White))
})
.collect();
let summary_window_widget = List::new(items)
.block( Block::default())
.highlight_style(highlight_style);
f.render_stateful_widget(
summary_window_widget,
area,
&mut dash_state.summary_window_rows.state,
);
}