use crate::{lifecycle_status_color, style::*, InspectorModel, KeyCode, PAGE_SCROLL_STEP};
use nodo_runtime::proto::nodo as nodo_pb;
use ratatui::{
prelude::{Buffer, Constraint, Rect},
style::{Color, Modifier, Style},
text::Span,
widgets::{Cell, Row, StatefulWidget, Table, Widget},
};
use std::{cell::RefCell, sync::Arc};
pub struct ScheduleController {
pub model: Arc<RefCell<InspectorModel>>,
}
impl ScheduleController {
pub fn on_key(&mut self, key: KeyCode) {
match key {
KeyCode::Down => self.select_next(),
KeyCode::Up => self.select_previous(),
KeyCode::PageDown => self.on_page_down(),
KeyCode::PageUp => self.on_page_up(),
KeyCode::Enter => {}
_ => {}
}
}
fn select_next(&mut self) {
self.model.borrow_mut().schedule_table_state.select_next();
}
fn select_previous(&mut self) {
self.model
.borrow_mut()
.schedule_table_state
.select_previous();
}
fn on_page_down(&mut self) {
for _ in 0..PAGE_SCROLL_STEP {
self.select_next()
}
}
fn on_page_up(&mut self) {
for _ in 0..PAGE_SCROLL_STEP {
self.select_previous()
}
}
}
pub struct ScheduleView {
pub model: Arc<RefCell<InspectorModel>>,
}
impl Widget for &ScheduleView {
fn render(self, area: Rect, buf: &mut Buffer) {
let mut model = self.model.borrow_mut();
let combined_rows: Vec<_> = model
.tree
.schedules
.iter()
.map(|(_, sched)| {
Row::new(vec![
{
Cell::from(Span::styled(
format!("{}", sched.id.0),
Style::default().fg(STYLE_COLOR_VALUE_DEFAULT),
))
},
{
Cell::from(Span::styled(
format!("{}", sched.name),
Style::default().fg(STYLE_COLOR_VALUE_DEFAULT),
))
},
{
if sched.status.has_panicked {
Cell::from(Span::styled("PANIC", Style::default().fg(STYLE_COLOR_ERR)))
} else if sched.status.has_finished {
Cell::from(Span::styled(
"FINISHED",
Style::default().fg(STYLE_COLOR_UNAVAILABLE),
))
} else {
let lifecycle_status: nodo_pb::LifecycleStatus = sched
.status
.lifecycle_status
.try_into()
.unwrap_or(nodo_pb::LifecycleStatus::Unspecified);
Cell::from(Span::styled(
format!("{lifecycle_status:?}"),
Style::default().fg(lifecycle_status_color(lifecycle_status)),
))
}
},
{
match sched.target_period {
Some(period) => Cell::from(Span::styled(
format!("{} ms", 1000. * period),
Style::default().fg(STYLE_COLOR_VALUE_DEFAULT),
)),
None => Cell::from(Span::styled(
"N/A",
Style::default().fg(STYLE_COLOR_UNAVAILABLE),
)),
}
},
{
match sched.status.last_period {
Some(period) => Cell::from(Span::styled(
format!("{} ms", 1000. * period),
Style::default().fg(STYLE_COLOR_VALUE_DEFAULT),
)),
None => Cell::from(Span::styled(
"N/A",
Style::default().fg(STYLE_COLOR_UNAVAILABLE),
)),
}
},
{
match &sched.status.last_error {
Some(text) => Cell::from(Span::styled(
text.clone(),
Style::default().fg(STYLE_COLOR_ERR),
)),
None => Cell::from(Span::styled(
"NONE",
Style::default().fg(STYLE_COLOR_UNAVAILABLE),
)),
}
},
])
})
.collect();
let table = Table::new(
combined_rows,
&[
Constraint::Fill(1),
Constraint::Fill(2),
Constraint::Fill(2),
Constraint::Fill(2),
Constraint::Fill(2),
Constraint::Fill(5),
],
)
.header(
Row::new(vec![
"ID".into(),
"Name".into(),
"Status".into(),
"Target Period".to_string(),
"Actual Period".to_string(),
"Last Error".to_string(),
])
.style(
Style::default()
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::REVERSED),
),
)
.style(Style::new().fg(Color::White))
.row_highlight_style(Style::new().add_modifier(Modifier::REVERSED));
StatefulWidget::render(table, area, buf, &mut model.schedule_table_state);
}
}