diff --git a/Cargo.toml b/Cargo.toml
index 59fce02..a26aed7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@ parking_lot = {version= "0.12.0"}
tokio = {version = "1.17.0", features=["full"]}
tracing = "0.1.32"
tracing-subscriber = "0.3.9"
-tui = "0.17"
+tui = "0.18"
[dev-dependencies]
diff --git a/README.md b/README.md
index ae524e6..4610130 100644
--- a/README.md
+++ b/README.md
@@ -21,14 +21,21 @@
-## Download
+## Download & install
See releases
+install
+```bash
+INSTALL_DIR="${HOME}/.local/bin"
+tar xzvf oxker_linux_x86_64.tar.gz oxker
+install -Dm 755 oxker -t "$INSTALL_DIR"
+rm oxker_linux_x86_64.tar.gz oxker
+```
## Run
-```./oxker```
+```oxker```
available command line arguments
| argument|result|
@@ -56,7 +63,7 @@ requires docker & Self {
Self {
- // 7 to allow for 100.00%
- cpu: (String::from("cpu"), 7),
- image: (String::from("image"), 5),
- name: (String::from("name"), 4),
state: (String::from("state"), 11),
status: (String::from("status"), 16),
+ // 7 to allow for "100.00%"
+ cpu: (String::from("cpu"), 7),
mem: (String::from("memory/limit"), 12),
+ id: (String::from("id"), 8),
+ name: (String::from("name"), 4),
+ image: (String::from("image"), 5),
net_rx: (String::from("↓ rx"), 5),
net_tx: (String::from("↑ tx"), 5),
}
diff --git a/src/app_error.rs b/src/app_error.rs
index ed28d6f..d6111cd 100644
--- a/src/app_error.rs
+++ b/src/app_error.rs
@@ -1,7 +1,5 @@
-use core::fmt;
-use tracing::error;
-
use crate::app_data::DockerControls;
+use core::fmt;
/// app errors to set in global state
#[allow(unused)]
@@ -11,25 +9,10 @@ pub enum AppError {
DockerInterval,
InputPoll,
DockerCommand(DockerControls),
+ MouseCapture(bool),
Terminal,
}
-impl AppError {
- /// for handling errors from terminal
- pub fn disp(&self) {
- match self {
- Self::DockerConnect => error!("Unable to access docker daemon"),
- Self::DockerInterval => error!("Docker update interval needs to be greater than 0"),
- Self::InputPoll => error!("Unable to poll user input"),
- Self::Terminal => error!("Unable to draw to terminal"),
- Self::DockerCommand(s) => {
- let error = format!("Unable to {} container", s);
- error!(%error);
- }
- }
- }
-}
-
/// Convert errors into strings to display
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -39,6 +22,10 @@ impl fmt::Display for AppError {
Self::InputPoll => "Unable to poll user input".to_owned(),
Self::Terminal => "Unable to draw to terminal".to_owned(),
Self::DockerCommand(s) => format!("Unable to {} container", s),
+ Self::MouseCapture(x) => {
+ let reason = if *x { "en" } else { "dis" };
+ format!("Unable to {}able mouse capture", reason)
+ }
};
write!(f, "{}", disp)
}
diff --git a/src/docker_data/mod.rs b/src/docker_data/mod.rs
index 0ab2a94..e6364c3 100644
--- a/src/docker_data/mod.rs
+++ b/src/docker_data/mod.rs
@@ -220,7 +220,7 @@ impl DockerData {
docker,
gui_state,
initialised: false,
- sleep_duration: Duration::from_millis(args.docker as u64),
+ sleep_duration: Duration::from_millis(args.docker_interval as u64),
timestamps: args.timestamp,
};
inner.initialise_container_data().await;
diff --git a/src/input_handler/mod.rs b/src/input_handler/mod.rs
index 3e14fb5..9baadc7 100644
--- a/src/input_handler/mod.rs
+++ b/src/input_handler/mod.rs
@@ -4,9 +4,14 @@ use std::sync::{
};
use bollard::{container::StartContainerOptions, Docker};
-use crossterm::event::{KeyCode, MouseButton, MouseEvent, MouseEventKind};
+use crossterm::{
+ event::{
+ DisableMouseCapture, EnableMouseCapture, KeyCode, MouseButton, MouseEvent, MouseEventKind,
+ },
+ execute,
+};
use parking_lot::Mutex;
-use tokio::sync::broadcast::Receiver;
+use tokio::{sync::broadcast::Receiver, task::JoinHandle};
use tui::layout::Rect;
mod message;
@@ -25,6 +30,8 @@ pub struct InputHandler {
gui_state: Arc>,
is_running: Arc,
rec: Receiver,
+ mouse_capture: bool,
+ info_sleep: Option>,
}
impl InputHandler {
@@ -42,6 +49,8 @@ impl InputHandler {
gui_state,
is_running,
rec,
+ mouse_capture: true,
+ info_sleep: None,
};
inner.start().await;
}
@@ -65,10 +74,46 @@ impl InputHandler {
}
}
+ fn m_button(&mut self) {
+ if self.mouse_capture {
+ match execute!(std::io::stdout(), DisableMouseCapture) {
+ Ok(_) => self
+ .gui_state
+ .lock()
+ .set_info_box("✖ mouse capture disabled".to_owned()),
+ Err(_) => self
+ .app_data
+ .lock()
+ .set_error(AppError::MouseCapture(false)),
+ }
+ } else {
+ match execute!(std::io::stdout(), EnableMouseCapture) {
+ Ok(_) => self
+ .gui_state
+ .lock()
+ .set_info_box("✓ mouse capture enabled".to_owned()),
+ Err(_) => self.app_data.lock().set_error(AppError::MouseCapture(true)),
+ }
+ };
+
+ let gui_state = Arc::clone(&self.gui_state);
+
+ if self.info_sleep.is_some() {
+ self.info_sleep.as_ref().unwrap().abort()
+ }
+ self.info_sleep = Some(tokio::spawn(async move {
+ tokio::time::sleep(std::time::Duration::from_millis(4000)).await;
+ gui_state.lock().reset_info_box()
+ }));
+
+ self.mouse_capture = !self.mouse_capture;
+ }
+
/// Handle any keyboard button events
async fn button_press(&mut self, key_code: KeyCode) {
let show_error = self.app_data.lock().show_error;
let show_info = self.gui_state.lock().show_help;
+
if show_error {
match key_code {
KeyCode::Char('q') => {
@@ -82,22 +127,16 @@ impl InputHandler {
}
} else if show_info {
match key_code {
- KeyCode::Char('q') => {
- self.is_running.store(false, Ordering::SeqCst);
- }
- KeyCode::Char('h') => {
- self.gui_state.lock().show_help = false;
- }
+ KeyCode::Char('q') => self.is_running.store(false, Ordering::SeqCst),
+ KeyCode::Char('h') => self.gui_state.lock().show_help = false,
+ KeyCode::Char('m') => self.m_button(),
_ => (),
}
} else {
match key_code {
- KeyCode::Char('q') => {
- self.is_running.store(false, Ordering::SeqCst);
- }
- KeyCode::Char('h') => {
- self.gui_state.lock().show_help = true;
- }
+ KeyCode::Char('q') => self.is_running.store(false, Ordering::SeqCst),
+ KeyCode::Char('h') => self.gui_state.lock().show_help = true,
+ KeyCode::Char('m') => self.m_button(),
KeyCode::Tab => self.gui_state.lock().next_panel(),
KeyCode::BackTab => self.gui_state.lock().previous_panel(),
KeyCode::Home => {
diff --git a/src/main.rs b/src/main.rs
index 97a3e50..112118a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,5 @@
+#![allow(unused)]
+
use app_data::AppData;
use app_error::AppError;
use bollard::Docker;
diff --git a/src/parse_args/mod.rs b/src/parse_args/mod.rs
index 351917a..524da85 100644
--- a/src/parse_args/mod.rs
+++ b/src/parse_args/mod.rs
@@ -8,13 +8,16 @@ use tracing::error;
pub struct CliArgs {
/// Docker update interval in ms, minimum 1, reccomended 500+
- #[clap(short = 'd', default_value_t = 1000)]
- pub docker: u32,
+ #[clap(short = 'd', value_name = "ms", default_value_t = 1000)]
+ pub docker_interval: u32,
/// Don't draw gui - for debugging - mostly pointless
#[clap(short = 'g')]
pub gui: bool,
+ // /// Install to ./local/bin
+ // #[clap(short = 'i')]
+ // pub install: bool,
/// Remove timestamps from Docker logs
#[clap(short = 't')]
pub timestamp: bool,
@@ -35,15 +38,16 @@ impl CliArgs {
// Quit the program if the docker update argument is 0
// Should maybe change it to check if less than 100
- if args.docker == 0 {
+ if args.docker_interval == 0 {
error!("docker args needs to be greater than 0");
process::exit(1)
}
Self {
color: args.color,
- docker: args.docker,
+ docker_interval: args.docker_interval,
gui: !args.gui,
raw: args.raw,
+ // install: args.install,
timestamp: !args.timestamp,
}
}
diff --git a/src/ui/draw_blocks.rs b/src/ui/draw_blocks.rs
index f3ac6c9..4d71af0 100644
--- a/src/ui/draw_blocks.rs
+++ b/src/ui/draw_blocks.rs
@@ -19,6 +19,7 @@ use crate::{
app_error::AppError,
};
+use super::gui_state::BoxLocation;
use super::{GuiState, SelectablePanel};
const NAME_TEXT: &str = r#"
@@ -34,17 +35,20 @@ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8
const NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");
const REPO: &str = env!("CARGO_PKG_REPOSITORY");
+const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
const ORANGE: Color = Color::Rgb(255, 178, 36);
const MARGIN: &str = " ";
-/// Generate block, add a bored if is the selected panel,
+/// Generate block, add a border if is the selected panel,
/// add custom title based on state of each panel
fn generate_block<'a>(
selectable_panel: Option,
app_data: &Arc>,
selected_panel: &SelectablePanel,
) -> Block<'a> {
- let mut block = Block::default().borders(Borders::ALL);
+ let mut block = Block::default()
+ .borders(Borders::ALL)
+ .border_type(BorderType::Rounded);
if let Some(panel) = selectable_panel {
let title = match panel {
@@ -62,11 +66,7 @@ fn generate_block<'a>(
};
block = block.title(title);
if selected_panel == &panel {
- let selected_style = Style::default().fg(Color::LightCyan);
- let selected_border = BorderType::Plain;
- block = block
- .border_style(selected_style)
- .border_type(selected_border);
+ block = block.border_style(Style::default().fg(Color::LightCyan));
}
}
block
@@ -170,6 +170,15 @@ pub fn draw_containers(
format!("{}{:>width$}", MARGIN, mems, width = widths.mem.1),
state_style,
),
+ Span::styled(
+ format!(
+ "{}{:>width$}",
+ MARGIN,
+ i.id.chars().take(8).collect::(),
+ width = widths.id.1
+ ),
+ blue,
+ ),
Span::styled(
format!("{}{:>width$}", MARGIN, i.name, width = widths.name.1),
blue,
@@ -330,7 +339,7 @@ fn make_chart(
.add_modifier(Modifier::BOLD),
))
.borders(Borders::ALL)
- .border_type(BorderType::Plain),
+ .border_type(BorderType::Rounded),
)
.x_axis(
Axis::default()
@@ -348,13 +357,12 @@ fn make_chart(
.fg(label_color),
),
])
- // add 0.01, for cases when the value is 0
.bounds([0.0, max.get_value() + 0.01]),
)
}
/// Show error popup over whole screen
-pub fn draw_info_bar(
+pub fn draw_heading_bar(
area: Rect,
columns: &Columns,
f: &mut Frame<'_, B>,
@@ -379,6 +387,8 @@ pub fn draw_info_bar(
.push_str(format!("{}{:>width$}", MARGIN, columns.cpu.0, width = columns.cpu.1).as_str());
column_headings
.push_str(format!("{}{:>width$}", MARGIN, columns.mem.0, width = columns.mem.1).as_str());
+ column_headings
+ .push_str(format!("{}{:>width$}", MARGIN, columns.id.0, width = columns.id.1).as_str());
column_headings.push_str(
format!(
"{}{:>width$}",
@@ -455,18 +465,21 @@ pub fn draw_info_bar(
pub fn draw_help_box(f: &mut Frame<'_, B>) {
let title = format!(" {} ", VERSION);
- let mut description_text =
- String::from("\n A basic docker container information viewer and controller.");
- description_text.push_str("\n Tab or Alt+Tab to change panels, arrows to change lines, enter to send docker container commands.");
- description_text.push_str("\n Mouse input also available.");
- description_text.push_str("\n ( q ) to quit at any time.");
- description_text
- .push_str("\n\n currenty an early work in progress, all and any input appreciated");
- description_text.push_str(format!("\n {}", REPO.trim()).as_str());
+ let description_text = format!("\n{}", DESCRIPTION);
+
+ let mut help_text = String::from("\n ( tab ) or ( alt+tab ) to change panels");
+ help_text.push_str("\n ( ↑ ↓ ← → ) to change selected line");
+ help_text.push_str("\n ( enter ) to send docker container commands");
+ help_text.push_str("\n ( h ) to toggle this help information");
+ help_text.push_str("\n ( m ) to toggle mouse capture - if disabled, text on screen can be selected & copied");
+ help_text.push_str("\n ( q ) to quit at any time");
+ help_text.push_str("\n mouse scrolling & clicking also available");
+ help_text.push_str("\n\n currenty an early work in progress, all and any input appreciated");
+ help_text.push_str(format!("\n {}", REPO.trim()).as_str());
let mut max_line_width = 0;
- let all_text = format!("{}{}", NAME_TEXT, description_text);
+ let all_text = format!("{}{}{}", NAME_TEXT, description_text, help_text);
all_text.lines().into_iter().for_each(|line| {
let width = line.chars().count();
@@ -486,7 +499,12 @@ pub fn draw_help_box(f: &mut Frame<'_, B>) {
.block(Block::default())
.alignment(Alignment::Center);
- let description_paragraph = Paragraph::new(description_text.as_str())
+ let description_paragrpah = Paragraph::new(description_text.as_str())
+ .style(Style::default().bg(Color::Magenta).fg(Color::Black))
+ .block(Block::default())
+ .alignment(Alignment::Center);
+
+ let help_paragraph = Paragraph::new(help_text.as_str())
.style(Style::default().bg(Color::Magenta).fg(Color::Black))
.block(Block::default())
.alignment(Alignment::Left);
@@ -497,7 +515,12 @@ pub fn draw_help_box(f: &mut Frame<'_, B>) {
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(Color::Black));
- let area = centered_info(lines as u16, max_line_width as u16, f.size());
+ let area = draw_popup(
+ lines as u16,
+ max_line_width as u16,
+ f.size(),
+ BoxLocation::MiddleCentre,
+ );
let split_popup = Layout::default()
.direction(Direction::Vertical)
@@ -505,6 +528,7 @@ pub fn draw_help_box(f: &mut Frame<'_, B>) {
[
Constraint::Max(NAME_TEXT.lines().count() as u16),
Constraint::Max(description_text.lines().count() as u16),
+ Constraint::Max(help_text.lines().count() as u16),
]
.as_ref(),
)
@@ -513,7 +537,8 @@ pub fn draw_help_box(f: &mut Frame<'_, B>) {
// Order is important here
f.render_widget(Clear, area);
f.render_widget(name_paragraph, split_popup[0]);
- f.render_widget(description_paragraph, split_popup[1]);
+ f.render_widget(description_paragrpah, split_popup[1]);
+ f.render_widget(help_paragraph, split_popup[2]);
f.render_widget(block, area);
}
@@ -560,38 +585,80 @@ pub fn draw_error(f: &mut Frame<'_, B>, error: AppError, seconds: Op
.block(block)
.alignment(Alignment::Center);
- let area = centered_info(lines as u16, max_line_width as u16, f.size());
+ let area = draw_popup(
+ lines as u16,
+ max_line_width as u16,
+ f.size(),
+ BoxLocation::MiddleCentre,
+ );
+ f.render_widget(Clear, area);
+ f.render_widget(paragraph, area);
+}
+
+/// Show info box in bottom right corner
+pub fn draw_info(f: &mut Frame<'_, B>, text: String) {
+ let block = Block::default()
+ .title("")
+ .title_alignment(Alignment::Center)
+ .borders(Borders::NONE);
+
+
+ let mut max_line_width = 0;
+ text.lines().into_iter().for_each(|line| {
+ let width = line.chars().count();
+ if width > max_line_width {
+ max_line_width = width;
+ }
+ });
+
+ let mut lines = text.lines().count();
+
+ // Add some horizontal & vertical margins
+ max_line_width += 8;
+ lines += 2;
+
+ let paragraph = Paragraph::new(text)
+ .style(Style::default().bg(Color::Blue).fg(Color::White))
+ .block(block)
+ .alignment(Alignment::Center);
+
+ let area = draw_popup(
+ lines as u16,
+ max_line_width as u16,
+ f.size(),
+ BoxLocation::BottomRight,
+ );
f.render_widget(Clear, area);
f.render_widget(paragraph, area);
}
/// draw a box in the center of the screen, based on max line width + number of lines
-fn centered_info(number_lines: u16, max_line_width: u16, r: Rect) -> Rect {
- // This can panic if number_lines or max_line_width is larger than r.height or r.width
- let blank_vertical = (r.height - number_lines) / 2;
- let blank_horizontal = (r.width - max_line_width) / 2;
+fn draw_popup(text_lines: u16, text_width: u16, r: Rect, box_location: BoxLocation) -> Rect {
+ // Make sure blank_space can't be an negative, as will crash
+ let blank_vertical = if r.height > text_lines {
+ (r.height - text_lines) / 2
+ } else {
+ 1
+ };
+ let blank_horizontal = if r.width > text_width {
+ (r.width - text_width) / 2
+ } else {
+ 1
+ };
+
+ let vertical_constraints = box_location.get_vertical_constraints(blank_vertical, text_lines);
+ let horizontal_constraints =
+ box_location.get_horizontal_constraints(blank_horizontal, text_width);
+
+ let indexes = box_location.get_indexes();
let popup_layout = Layout::default()
.direction(Direction::Vertical)
- .constraints(
- [
- Constraint::Max(blank_vertical),
- Constraint::Max(number_lines),
- Constraint::Max(blank_vertical),
- ]
- .as_ref(),
- )
+ .constraints(vertical_constraints)
.split(r);
Layout::default()
.direction(Direction::Horizontal)
- .constraints(
- [
- Constraint::Max(blank_horizontal),
- Constraint::Max(max_line_width),
- Constraint::Max(blank_horizontal),
- ]
- .as_ref(),
- )
- .split(popup_layout[1])[1]
+ .constraints(horizontal_constraints)
+ .split(popup_layout[indexes.0])[indexes.1]
}
diff --git a/src/ui/gui_state.rs b/src/ui/gui_state.rs
index eb53924..72ef238 100644
--- a/src/ui/gui_state.rs
+++ b/src/ui/gui_state.rs
@@ -1,5 +1,5 @@
use std::{collections::HashMap, fmt};
-use tui::layout::Rect;
+use tui::layout::{Constraint, Rect};
#[derive(Debug, PartialEq, std::hash::Hash, std::cmp::Eq, Clone, Copy)]
pub enum SelectablePanel {
@@ -7,7 +7,85 @@ pub enum SelectablePanel {
Commands,
Logs,
}
-#[derive(Debug)]
+
+#[derive(Debug, Clone, Copy)]
+pub enum BoxLocation {
+ TopLeft,
+ TopCentre,
+ TopRight,
+ MiddleLeft,
+ MiddleCentre,
+ MiddleRight,
+ BottomLeft,
+ BottomCentre,
+ BottomRight,
+}
+
+impl BoxLocation {
+ pub fn get_indexes(&self) -> (usize, usize) {
+ match self {
+ Self::TopLeft => (0, 0),
+ Self::TopCentre => (0, 1),
+ Self::TopRight => (0, 2),
+ Self::MiddleLeft => (1, 0),
+ Self::MiddleCentre => (1, 1),
+ Self::MiddleRight => (1, 2),
+ Self::BottomLeft => (2, 0),
+ Self::BottomCentre => (2, 1),
+ Self::BottomRight => (2, 2),
+ }
+ }
+
+ // Should combine and just return a tupple?
+ pub fn get_horizontal_constraints(
+ &self,
+ blank_vertical: u16,
+ text_width: u16,
+ ) -> [Constraint; 3] {
+ match self {
+ Self::TopLeft | Self::MiddleLeft | Self::BottomLeft => [
+ Constraint::Max(text_width),
+ Constraint::Max(blank_vertical),
+ Constraint::Max(blank_vertical),
+ ],
+ Self::TopCentre | Self::MiddleCentre | Self::BottomCentre => [
+ Constraint::Max(blank_vertical),
+ Constraint::Max(text_width),
+ Constraint::Max(blank_vertical),
+ ],
+ Self::TopRight | Self::MiddleRight | Self::BottomRight => [
+ Constraint::Max(blank_vertical),
+ Constraint::Max(blank_vertical),
+ Constraint::Max(text_width),
+ ],
+ }
+ }
+ pub fn get_vertical_constraints(
+ &self,
+ blank_vertical: u16,
+ number_lines: u16,
+ ) -> [Constraint; 3] {
+ match self {
+ Self::TopLeft | Self::TopCentre | Self::TopRight => [
+ Constraint::Max(number_lines),
+ Constraint::Max(blank_vertical),
+ Constraint::Max(blank_vertical),
+ ],
+ Self::MiddleLeft | Self::MiddleCentre | Self::MiddleRight => [
+ Constraint::Max(blank_vertical),
+ Constraint::Max(number_lines),
+ Constraint::Max(blank_vertical),
+ ],
+ Self::BottomLeft | Self::BottomCentre | Self::BottomRight => [
+ Constraint::Max(blank_vertical),
+ Constraint::Max(blank_vertical),
+ Constraint::Max(number_lines),
+ ],
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
pub enum Loading {
One,
Two,
@@ -34,20 +112,9 @@ impl Loading {
Self::Eight => Self::Nine,
Self::Nine => Self::Ten,
Self::Ten => Self::One,
- // Self::Five => Self::One
}
}
}
-// "⠋",
-// "⠙",
-// "⠹",
-// "⠸",
-// "⠼",
-// "⠴",
-// "⠦",
-// "⠧",
-// "⠇",
-// "⠏"
impl fmt::Display for Loading {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -92,7 +159,7 @@ impl SelectablePanel {
}
/// Global gui_state, stored in an Arc
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub struct GuiState {
// Think this should be a BMapTree, so can define order when iterating over potential intersects
// Is an issue if two panels are in the same space, sush as a smaller panel embedded, yet infront of, a larger panel
@@ -101,6 +168,8 @@ pub struct GuiState {
loading: Loading,
pub selected_panel: SelectablePanel,
pub show_help: bool,
+ // show_info_panel: bool,
+ pub info_box_text: Option,
}
impl GuiState {
@@ -111,6 +180,8 @@ impl GuiState {
loading: Loading::One,
selected_panel: SelectablePanel::Containers,
show_help: false,
+ // show_info_panel: false,
+ info_box_text: None,
}
}
@@ -158,4 +229,18 @@ impl GuiState {
pub fn reset_loading(&mut self) {
self.loading = Loading::One;
}
+
+ pub fn set_info_box(&mut self, text: String) {
+ self.info_box_text = Some(text);
+ // self.show_info_panel = true;
+
+ // Should spawn and after 10 seconds close?
+ // Need to copy whatever we're doing with parsing logs icon
+ }
+
+ pub fn reset_info_box(&mut self) {
+ // self.loading = Loading::One;
+ self.info_box_text = None;
+ // self.show_info_panel = false;
+ }
}
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index 002175a..7027a5a 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -11,6 +11,7 @@ use std::{
sync::{atomic::Ordering, Arc},
};
use tokio::sync::broadcast::Sender;
+use tracing::error;
use tui::{
backend::{Backend, CrosstermBackend},
layout::{Constraint, Direction, Layout},
@@ -50,7 +51,7 @@ pub async fn create_ui(
terminal.show_cursor().unwrap();
if let Err(err) = res {
- err.disp()
+ error!(%err);
}
Ok(())
}
@@ -126,6 +127,7 @@ fn ui(
let log_index = app_data.lock().get_selected_log_index();
let selected_panel = gui_state.lock().selected_panel;
let show_help = gui_state.lock().show_help;
+ let info_text = gui_state.lock().info_box_text.clone();
let whole_layout = Layout::default()
.direction(Direction::Vertical)
@@ -190,7 +192,7 @@ fn ui(
&selected_panel,
);
- draw_info_bar(
+ draw_heading_bar(
whole_layout[0],
&column_widths,
f,
@@ -203,6 +205,10 @@ fn ui(
draw_chart(f, lower_main[1], app_data, log_index);
}
+ if let Some(info) = info_text {
+ draw_info(f, info);
+ }
+
// Check if error, and show popup if so
if show_help {
draw_help_box(f);