refactor(tui): show sysctl variables on a table

This commit is contained in:
Orhun Parmaksız 2022-01-09 14:15:21 +03:00
parent c94df7a689
commit 6a828cb35b
No known key found for this signature in database
GPG key ID: F83424824B3E4B90
3 changed files with 61 additions and 38 deletions

View file

@ -1,6 +1,6 @@
use crate::command::Command;
use crate::error::Result;
use crate::widgets::StatefulList;
use crate::widgets::StatefulTable;
use std::str::FromStr;
use std::time::Instant;
use systeroid_core::sysctl::controller::Sysctl;
@ -19,7 +19,7 @@ pub struct App<'a> {
/// Time tracker for measuring the time for clearing the input.
pub input_time: Option<Instant>,
/// List of sysctl variables.
pub variable_list: StatefulList<Parameter>,
pub variable_list: StatefulTable<Parameter>,
/// Sysctl controller.
sysctl: &'a mut Sysctl,
}
@ -31,7 +31,7 @@ impl<'a> App<'a> {
running: true,
input: None,
input_time: None,
variable_list: StatefulList::with_items(sysctl.parameters.clone()),
variable_list: StatefulTable::with_items(sysctl.parameters.clone()),
sysctl,
}
}
@ -89,7 +89,7 @@ impl<'a> App<'a> {
Command::Refresh => {
self.input = None;
*self.sysctl = Sysctl::init(self.sysctl.config.clone())?;
self.variable_list = StatefulList::with_items(self.sysctl.parameters.clone());
self.variable_list = StatefulTable::with_items(self.sysctl.parameters.clone());
}
Command::Exit => {
self.running = false;

View file

@ -2,8 +2,7 @@ use crate::app::App;
use tui::backend::Backend;
use tui::layout::{Constraint, Direction, Layout, Rect};
use tui::style::{Color, Style};
use tui::text::Span;
use tui::widgets::{Block, BorderType, Borders, List, ListItem, Paragraph};
use tui::widgets::{Block, BorderType, Borders, Cell, Paragraph, Row, Table};
use tui::Frame;
use unicode_width::UnicodeWidthStr;
@ -11,33 +10,57 @@ use unicode_width::UnicodeWidthStr;
pub fn render<B: Backend>(frame: &mut Frame<'_, B>, app: &mut App) {
let rect = frame.size();
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(rect.height - 3), Constraint::Min(3)].as_ref())
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(rect);
render_variable_list(frame, chunks[0], app);
render_input_prompt(frame, chunks[1], rect.height - 2, app);
{
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(rect.height - 3), Constraint::Min(3)].as_ref())
.split(chunks[0]);
render_variable_list(frame, chunks[0], app);
render_input_prompt(frame, chunks[1], rect.height - 2, app);
}
}
/// Renders the list that contains the sysctl variables.
fn render_variable_list<B: Backend>(frame: &mut Frame<'_, B>, rect: Rect, app: &mut App) {
let max_width = app
.variable_list
.items
.iter()
.map(|p| p.name.len())
.max_by(|x, y| x.cmp(y))
.and_then(|v| u16::try_from(v).ok())
.unwrap_or(1);
let minimize_rows = rect.width < max_width + 10;
let rows = app.variable_list.items.iter().map(|item| {
Row::new(if minimize_rows {
vec![Cell::from(format!("{} = {}", item.name, item.value))]
} else {
vec![
Cell::from(item.name.clone()),
Cell::from(item.value.clone()),
]
})
.height(1)
.bottom_margin(1)
});
frame.render_stateful_widget(
List::new(
app.variable_list
.items
.iter()
.map(|variable| {
ListItem::new(Span::raw(format!("{} = {}", variable.name, variable.value)))
})
.collect::<Vec<ListItem<'_>>>(),
)
.block(
Block::default()
.borders(Borders::all())
.border_style(Style::default().fg(Color::White))
.border_type(BorderType::Rounded)
.style(Style::default().bg(Color::Black)),
)
.highlight_symbol("> "),
Table::new(rows)
.block(
Block::default()
.borders(Borders::all())
.border_style(Style::default().fg(Color::White))
.border_type(BorderType::Rounded)
.style(Style::default().bg(Color::Black)),
)
.highlight_style(Style::default().bg(Color::White).fg(Color::Black))
.widths(&if minimize_rows {
[Constraint::Percentage(100), Constraint::Min(0)]
} else {
[Constraint::Min(max_width), Constraint::Percentage(100)]
}),
rect,
&mut app.variable_list.state,
);

View file

@ -1,24 +1,24 @@
use tui::widgets::ListState;
use tui::widgets::TableState;
/// List widget with TUI controlled states.
#[derive(Debug)]
pub struct StatefulList<T> {
pub struct StatefulTable<T> {
/// List items (states).
pub items: Vec<T>,
/// State that can be modified by TUI.
pub state: ListState,
pub state: TableState,
}
impl<T> StatefulList<T> {
/// Constructs a new instance of `StatefulList`.
pub fn new(items: Vec<T>, mut state: ListState) -> StatefulList<T> {
impl<T> StatefulTable<T> {
/// Constructs a new instance of `StatefulTable`.
pub fn new(items: Vec<T>, mut state: TableState) -> StatefulTable<T> {
state.select(Some(0));
Self { items, state }
}
/// Construct a new `StatefulList` with given items.
pub fn with_items(items: Vec<T>) -> StatefulList<T> {
Self::new(items, ListState::default())
/// Construct a new `StatefulTable` with given items.
pub fn with_items(items: Vec<T>) -> StatefulTable<T> {
Self::new(items, TableState::default())
}
/// Returns the selected item.
@ -62,8 +62,8 @@ mod tests {
use super::*;
#[test]
fn test_stateful_list() {
let mut list = StatefulList::with_items(vec!["data1", "data2", "data3"]);
fn test_stateful_table() {
let mut list = StatefulTable::with_items(vec!["data1", "data2", "data3"]);
list.state.select(Some(1));
assert_eq!(Some(&"data2"), list.selected());
list.next();