From b4488e4bdb0252f5c5680cee6a46427f22a282ab Mon Sep 17 00:00:00 2001 From: Jack Wills <32690432+mrjackwills@users.noreply.github.com> Date: Sat, 28 Jan 2023 20:44:09 +0000 Subject: [PATCH] refactor: major refactor of internal data handling What started off as an inquisitive look at how the gui drawing blocks get the data they require in order to draw to the screen, ended up as a realisation that it could be achieved in a better manner. Basically just use x.get(y), instead of using x[y] all over the place --- src/app_data/mod.rs | 292 +++++++++++++++++++++++---------------- src/docker_data/mod.rs | 31 ++--- src/input_handler/mod.rs | 16 +-- src/ui/draw_blocks.rs | 131 ++++++++---------- src/ui/gui_state.rs | 1 + src/ui/mod.rs | 16 +-- 6 files changed, 251 insertions(+), 236 deletions(-) diff --git a/src/app_data/mod.rs b/src/app_data/mod.rs index fc106f4..d8be8be 100644 --- a/src/app_data/mod.rs +++ b/src/app_data/mod.rs @@ -1,7 +1,9 @@ use bollard::models::ContainerSummary; use core::fmt; use std::time::{SystemTime, UNIX_EPOCH}; -use tui::widgets::ListItem; +use tui::{ + widgets::{ListItem, ListState}, +}; mod container_state; @@ -11,10 +13,10 @@ pub use container_state::*; /// Global app_state, stored in an Arc #[derive(Debug, Clone)] pub struct AppData { + containers: StatefulList, error: Option, sorted_by: Option<(Header, SortedOrder)>, pub args: CliArgs, - pub containers: StatefulList, } #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -69,6 +71,34 @@ impl AppData { self.sorted_by } + pub fn has_containers(&self) -> bool { + self.containers.items.is_empty() + } + + pub fn container_title(&self) -> String { + self.containers.get_state_title() + } + + /// Select the first container + pub fn containers_start(&mut self) { + self.containers.start(); + } + + // select the last container + pub fn containers_end(&mut self) { + self.containers.end(); + } + + /// Select the next container + pub fn containers_next(&mut self) { + self.containers.next(); + } + + // select the previous container + pub fn containers_previous(&mut self) { + self.containers.previous(); + } + /// Remove the sorted header & order, and sort by default - created datetime pub fn reset_sorted(&mut self) { self.set_sorted(None); @@ -109,55 +139,122 @@ impl AppData { .as_secs() } - /// Get the current select docker command + /// Get the current selected docker command /// So know which command to execute - pub fn get_docker_command(&self) -> Option { - let mut output = None; - if let Some(index) = self.containers.state.selected() { - if let Some(control_index) = self.containers.items[index] - .docker_controls - .state - .selected() - { - output = Some(self.containers.items[index].docker_controls.items[control_index]); - } - } - output + pub fn selected_docker_command(&self) -> Option { + self.get_selected_container().and_then(|i| { + i.docker_controls.state.selected().and_then(|x| { + i.docker_controls + .items + .get(x) + .map(std::borrow::ToOwned::to_owned) + }) + }) + } + + /// Get Option of the current selected container + pub fn get_selected_container(&self) -> Option<&ContainerItem> { + self.containers + .state + .selected() + .and_then(|i| self.containers.items.get(i)) + } + + /// Get Option of the current selected container + pub const fn get_container_items(&self) -> &Vec { + &self.containers.items + } + + pub fn get_container_state(&mut self) -> &mut ListState { + &mut self.containers.state + } + + /// Get mutable Option of the current selected container + fn get_mut_selected_container(&mut self) -> Option<&mut ContainerItem> { + self.containers + .state + .selected() + .and_then(|i| self.containers.items.get_mut(i)) + } + + /// Get mutable Option of the currently selected container chart data + pub fn get_chart_data(&mut self) -> Option<(CpuTuple, MemTuple)> { + self.containers + .state + .selected() + .and_then(|i| self.containers.items.get_mut(i)) + .map(|i| i.get_chart_data()) + } + + /// Get mutable Vec of current containers logs + pub fn get_logs(&mut self) -> Vec> { + self.containers + .state + .selected() + .and_then(|i| self.containers.items.get_mut(i)) + .map_or(vec![], |i| i.logs.to_vec()) + } + + /// Get mutable Option of the currently selected container Logs state + pub fn get_log_state(&mut self) -> Option<&mut ListState> { + self.containers + .state + .selected() + .and_then(|i| self.containers.items.get_mut(i)) + .map(|i| i.logs.state()) + } + + /// Get mutable Option of the currently selected container DockerControls state + pub fn get_control_state(&mut self) -> Option<&mut ListState> { + self.get_mut_selected_container() + .map(|i| &mut i.docker_controls.state) + } + + /// Get mutable Option of the currently selected container DockerControls items + pub fn get_control_items(&mut self) -> Option<&mut Vec> { + self.get_mut_selected_container() + .map(|i| &mut i.docker_controls.items) + } + + /// Get all containers ids + pub fn get_all_ids(&self) -> Vec { + self.containers + .items + .iter() + .map(|i| i.id.clone()) + .collect::>() + } + + /// return a mutable container by given id + fn get_container_by_id(&mut self, id: &ContainerId) -> Option<&mut ContainerItem> { + self.containers.items.iter_mut().find(|i| &i.id == id) } /// Change selected choice of docker commands of selected container pub fn docker_command_next(&mut self) { - if let Some(index) = self.containers.state.selected() { - if let Some(i) = self.containers.items.get_mut(index) { - i.docker_controls.next(); - } + if let Some(i) = self.get_mut_selected_container() { + i.docker_controls.next(); } } /// Change selected choice of docker commands of selected container pub fn docker_command_previous(&mut self) { - if let Some(index) = self.containers.state.selected() { - if let Some(i) = self.containers.items.get_mut(index) { - i.docker_controls.previous(); - } + if let Some(i) = self.get_mut_selected_container() { + i.docker_controls.previous(); } } /// Change selected choice of docker commands of selected container pub fn docker_command_start(&mut self) { - if let Some(index) = self.containers.state.selected() { - if let Some(i) = self.containers.items.get_mut(index) { - i.docker_controls.start(); - } + if let Some(i) = self.get_mut_selected_container() { + i.docker_controls.start(); } } /// Change selected choice of docker commands of selected container pub fn docker_command_end(&mut self) { - if let Some(index) = self.containers.state.selected() { - if let Some(i) = self.containers.items.get_mut(index) { - i.docker_controls.end(); - } + if let Some(i) = self.get_mut_selected_container() { + i.docker_controls.end(); } } @@ -180,25 +277,14 @@ impl AppData { /// If any containers on system, will always return a ContainerId /// Only returns None when no containers found. pub fn get_selected_container_id(&self) -> Option { - let mut output = None; - if let Some(index) = self.containers.state.selected() { - if let Some(x) = self.containers.items.get(index) { - output = Some(x.id.clone()); - } - } - output + self.get_selected_container().map(|i| i.id.clone()) } /// Check if the selected container is a dockerised version of oxker /// So that can disallow commands to be send /// Is a shabby way of implementing this pub fn selected_container_is_oxker(&self) -> bool { - if let Some(index) = self.containers.state.selected() { - if let Some(x) = self.containers.items.get(index) { - return x.is_oxker; - } - } - false + self.get_selected_container().map_or(false, |i| i.is_oxker) } /// Sort the containers vec, based on a heading, either ascending or descending, @@ -276,68 +362,48 @@ impl AppData { } } - /// Find the index of the currently selected single log line - pub fn get_selected_log_index(&self) -> Option { - let mut output = None; - if let Some(id) = self.get_selected_container_id() { - if let Some(index) = self.containers.items.iter().position(|i| i.id == id) { - output = Some(index); - } - } - output - } - - /// Get the title for log panel for selected container - /// will be either + /// Get the title for log panel for selected container, will be either /// 1) "logs x/x - container_name" where container_name is 32 chars max /// 2) "logs - container_name" when no logs found, again 32 chars max + /// 3) "" no container currently selected - aka no containers on system pub fn get_log_title(&self) -> String { - self.get_selected_log_index() - .map_or(String::new(), |index| { - let logs_len = self.containers.items[index].logs.get_state_title(); - let mut name = self.containers.items[index].name.clone(); - name.truncate(32); - if logs_len.is_empty() { - format!("- {name} ") - } else { - format!("{logs_len} - {name}") - } - }) + self.get_selected_container().map_or_else(String::new, |y| { + let logs_len = y.logs.get_state_title(); + let mut name = y.name.clone(); + name.truncate(32); + if logs_len.is_empty() { + format!("- {name} ") + } else { + format!("{logs_len} - {name}") + } + }) } /// select next selected log line pub fn log_next(&mut self) { - if let Some(index) = self.get_selected_log_index() { - if let Some(i) = self.containers.items.get_mut(index) { - i.logs.next(); - } + if let Some(i) = self.get_mut_selected_container() { + i.logs.next(); } } /// select previous selected log line pub fn log_previous(&mut self) { - if let Some(index) = self.get_selected_log_index() { - if let Some(i) = self.containers.items.get_mut(index) { - i.logs.previous(); - } + if let Some(i) = self.get_mut_selected_container() { + i.logs.previous(); } } /// select last selected log line pub fn log_end(&mut self) { - if let Some(index) = self.get_selected_log_index() { - if let Some(i) = self.containers.items.get_mut(index) { - i.logs.end(); - } + if let Some(i) = self.get_mut_selected_container() { + i.logs.end(); } } /// select first selected log line pub fn log_start(&mut self) { - if let Some(index) = self.get_selected_log_index() { - if let Some(i) = self.containers.items.get_mut(index) { - i.logs.start(); - } + if let Some(i) = self.get_mut_selected_container() { + i.logs.start(); } } @@ -361,7 +427,7 @@ impl AppData { /// Find the widths for the strings in the containers panel. /// So can display nicely and evenly pub fn get_width(&self) -> Columns { - let mut output = Columns::new(); + let mut columns = Columns::new(); let count = |x: &String| u8::try_from(x.chars().count()).unwrap_or(12); // Should probably find a refactor here somewhere @@ -389,49 +455,35 @@ impl AppData { ); let mem_limit_count = count(&container.mem_limit.to_string()); - if cpu_count > output.cpu.1 { - output.cpu.1 = cpu_count; + if cpu_count > columns.cpu.1 { + columns.cpu.1 = cpu_count; }; - if image_count > output.image.1 { - output.image.1 = image_count; + if image_count > columns.image.1 { + columns.image.1 = image_count; }; - if mem_current_count > output.mem.1 { - output.mem.1 = mem_current_count; + if mem_current_count > columns.mem.1 { + columns.mem.1 = mem_current_count; }; - if mem_limit_count > output.mem.2 { - output.mem.2 = mem_limit_count; + if mem_limit_count > columns.mem.2 { + columns.mem.2 = mem_limit_count; }; - if name_count > output.name.1 { - output.name.1 = name_count; + if name_count > columns.name.1 { + columns.name.1 = name_count; }; - if state_count > output.state.1 { - output.state.1 = state_count; + if state_count > columns.state.1 { + columns.state.1 = state_count; }; - if status_count > output.status.1 { - output.status.1 = status_count; + if status_count > columns.status.1 { + columns.status.1 = status_count; }; - if rx_count > output.net_rx.1 { - output.net_rx.1 = rx_count; + if rx_count > columns.net_rx.1 { + columns.net_rx.1 = rx_count; }; - if tx_count > output.net_tx.1 { - output.net_tx.1 = tx_count; + if tx_count > columns.net_tx.1 { + columns.net_tx.1 = tx_count; }; } - output - } - - /// Get all containers ids - pub fn get_all_ids(&self) -> Vec { - self.containers - .items - .iter() - .map(|i| i.id.clone()) - .collect::>() - } - - /// return a mutable container by given id - fn get_container_by_id(&mut self, id: &ContainerId) -> Option<&mut ContainerItem> { - self.containers.items.iter_mut().find(|i| &i.id == id) + columns } /// Update container mem, cpu, & network stats, in single function so only need to call .lock() once @@ -563,7 +615,7 @@ impl AppData { } /// update logs of a given container, based on id - pub fn update_log_by_id(&mut self, output: Vec, id: &ContainerId) { + pub fn update_log_by_id(&mut self, logs: Vec, id: &ContainerId) { let color = self.args.color; let raw = self.args.raw; @@ -573,7 +625,7 @@ impl AppData { container.last_updated = Self::get_systemtime(); let current_len = container.logs.len(); - for mut i in output { + for mut i in logs { let tz = LogsTz::from(&i); // Strip the timestamp if `-t` flag set if !timestamp { diff --git a/src/docker_data/mod.rs b/src/docker_data/mod.rs index 1bc10d7..09ee6e7 100644 --- a/src/docker_data/mod.rs +++ b/src/docker_data/mod.rs @@ -267,25 +267,18 @@ impl DockerData { /// Update all cpu_mem, and selected container log (if a log update join_handle isn't currently being executed) async fn update_everything(&mut self) { let all_ids = self.update_all_containers().await; - let optional_index = self.app_data.lock().get_selected_log_index(); - if let Some(index) = optional_index { - if let Some(container) = self.app_data.lock().containers.items.get(index) { - self.spawns - .lock() - .entry(SpawnId::Log(container.id.clone())) - .or_insert_with(|| { - let docker = Arc::clone(&self.docker); - let app_data = Arc::clone(&self.app_data); - let spawns = Arc::clone(&self.spawns); - tokio::spawn(Self::update_log( - app_data, - docker, - container.id.clone(), - container.last_updated, - spawns, - )) - }); - } + if let Some(container) = self.app_data.lock().get_selected_container() { + let id = container.id.clone(); + let last_updated = container.last_updated; + self.spawns + .lock() + .entry(SpawnId::Log(id.clone())) + .or_insert_with(|| { + let docker = Arc::clone(&self.docker); + let app_data = Arc::clone(&self.app_data); + let spawns = Arc::clone(&self.spawns); + tokio::spawn(Self::update_log(app_data, docker, id, last_updated, spawns)) + }); }; self.update_all_container_stats(&all_ids); self.app_data.lock().sort_containers(); diff --git a/src/input_handler/mod.rs b/src/input_handler/mod.rs index 9d88df9..97472b9 100644 --- a/src/input_handler/mod.rs +++ b/src/input_handler/mod.rs @@ -207,7 +207,7 @@ impl InputHandler { KeyCode::Home => { let mut locked_data = self.app_data.lock(); match self.gui_state.lock().selected_panel { - SelectablePanel::Containers => locked_data.containers.start(), + SelectablePanel::Containers => locked_data.containers_start(), SelectablePanel::Logs => locked_data.log_start(), SelectablePanel::Commands => locked_data.docker_command_start(), } @@ -215,7 +215,7 @@ impl InputHandler { KeyCode::End => { let mut locked_data = self.app_data.lock(); match self.gui_state.lock().selected_panel { - SelectablePanel::Containers => locked_data.containers.end(), + SelectablePanel::Containers => locked_data.containers_end(), SelectablePanel::Logs => locked_data.log_end(), SelectablePanel::Commands => locked_data.docker_command_end(), } @@ -236,7 +236,7 @@ impl InputHandler { // This isn't great, just means you can't send docker commands before full initialization of the program let panel = self.gui_state.lock().selected_panel; if panel == SelectablePanel::Commands { - let option_command = self.app_data.lock().get_docker_command(); + let option_command = self.app_data.lock().selected_docker_command(); if let Some(command) = option_command { let option_id = self.app_data.lock().get_selected_container_id(); @@ -287,14 +287,12 @@ impl InputHandler { MouseEventKind::ScrollUp => self.previous(), MouseEventKind::ScrollDown => self.next(), MouseEventKind::Down(MouseButton::Left) => { - let header_intersects = self.gui_state.lock().header_intersect(Rect::new( + if let Some(header) = self.gui_state.lock().header_intersect(Rect::new( mouse_event.column, mouse_event.row, 1, 1, - )); - - if let Some(header) = header_intersects { + )) { self.sort(header); } @@ -313,7 +311,7 @@ impl InputHandler { fn next(&mut self) { let mut locked_data = self.app_data.lock(); match self.gui_state.lock().selected_panel { - SelectablePanel::Containers => locked_data.containers.next(), + SelectablePanel::Containers => locked_data.containers_next(), SelectablePanel::Logs => locked_data.log_next(), SelectablePanel::Commands => locked_data.docker_command_next(), }; @@ -323,7 +321,7 @@ impl InputHandler { fn previous(&mut self) { let mut locked_data = self.app_data.lock(); match self.gui_state.lock().selected_panel { - SelectablePanel::Containers => locked_data.containers.previous(), + SelectablePanel::Containers => locked_data.containers_previous(), SelectablePanel::Logs => locked_data.log_previous(), SelectablePanel::Commands => locked_data.docker_command_previous(), } diff --git a/src/ui/draw_blocks.rs b/src/ui/draw_blocks.rs index 6f48b2e..a3d384c 100644 --- a/src/ui/draw_blocks.rs +++ b/src/ui/draw_blocks.rs @@ -57,11 +57,7 @@ fn generate_block<'a>( let current_selected_panel = gui_state.lock().selected_panel; let mut title = match panel { SelectablePanel::Containers => { - format!( - "{} {}", - panel.title(), - app_data.lock().containers.get_state_title() - ) + format!("{} {}", panel.title(), app_data.lock().container_title()) } SelectablePanel::Logs => { format!("{} {}", panel.title(), app_data.lock().get_log_title()) @@ -87,35 +83,31 @@ pub fn commands( area: Rect, f: &mut Frame<'_, B>, gui_state: &Arc>, - index: Option, ) { - let block = generate_block(app_data, area, gui_state, SelectablePanel::Commands); - if let Some(i) = index { - let items = app_data.lock().containers.items[i] - .docker_controls - .items - .iter() - .map(|i| { + let block = || generate_block(app_data, area, gui_state, SelectablePanel::Commands); + let items = app_data.lock().get_control_items().map_or(vec![], |i| { + i.iter() + .map(|c| { let lines = Spans::from(vec![Span::styled( - i.to_string(), - Style::default().fg(i.get_color()), + c.to_string(), + Style::default().fg(c.get_color()), )]); ListItem::new(lines) }) - .collect::>(); + .collect::>() + }); - let items = List::new(items) - .block(block) - .highlight_style(Style::default().add_modifier(Modifier::BOLD)) - .highlight_symbol(ARROW); + let items = List::new(items) + .block(block()) + .highlight_style(Style::default().add_modifier(Modifier::BOLD)) + .highlight_symbol(ARROW); - f.render_stateful_widget( - items, - area, - &mut app_data.lock().containers.items[i].docker_controls.state, - ); + if let Some(i) = app_data.lock().get_control_state() { + f.render_stateful_widget(items, area, i); } else { - let paragraph = Paragraph::new("").block(block).alignment(Alignment::Center); + let paragraph = Paragraph::new("") + .block(block()) + .alignment(Alignment::Center); f.render_widget(paragraph, area); } } @@ -132,8 +124,7 @@ pub fn containers( let items = app_data .lock() - .containers - .items + .get_container_items() .iter() .map(|i| { let state_style = Style::default().fg(i.state.get_color()); @@ -204,6 +195,7 @@ pub fn containers( ListItem::new(lines) }) .collect::>(); + if items.is_empty() { let paragraph = Paragraph::new("no containers running") .block(block) @@ -215,7 +207,7 @@ pub fn containers( .highlight_style(Style::default().add_modifier(Modifier::BOLD)) .highlight_symbol(CIRCLE); - f.render_stateful_widget(items, area, &mut app_data.lock().containers.state); + f.render_stateful_widget(items, area, app_data.lock().get_container_state()); } } @@ -225,69 +217,58 @@ pub fn logs( area: Rect, f: &mut Frame<'_, B>, gui_state: &Arc>, - index: Option, loading_icon: &str, ) { - let block = generate_block(app_data, area, gui_state, SelectablePanel::Logs); - let contains_init = gui_state.lock().status_contains(&[Status::Init]); - if contains_init { + let block = || generate_block(app_data, area, gui_state, SelectablePanel::Logs); + if gui_state.lock().status_contains(&[Status::Init]) { let paragraph = Paragraph::new(format!("parsing logs {loading_icon}")) .style(Style::default()) - .block(block) + .block(block()) .alignment(Alignment::Center); f.render_widget(paragraph, area); - } else if let Some(index) = index { - let items = List::new(app_data.lock().containers.items[index].logs.to_vec()) - .block(block) + } else { + let items = app_data.lock().get_logs(); + let items = List::new(items) + .block(block()) .highlight_symbol(ARROW) .highlight_style(Style::default().add_modifier(Modifier::BOLD)); - f.render_stateful_widget( - items, - area, - app_data.lock().containers.items[index].logs.state(), - ); - } else { - let paragraph = Paragraph::new("no logs found") - .block(block) - .alignment(Alignment::Center); - f.render_widget(paragraph, area); + + if let Some(i) = app_data.lock().get_log_state() { + f.render_stateful_widget(items, area, i); + } else { + let paragraph = Paragraph::new("no logs found") + .block(block()) + .alignment(Alignment::Center); + f.render_widget(paragraph, area); + } } } /// Draw the cpu + mem charts -pub fn chart( - f: &mut Frame<'_, B>, - area: Rect, - app_data: &Arc>, - index: Option, -) { - if let Some(index) = index { +pub fn chart(f: &mut Frame<'_, B>, area: Rect, app_data: &Arc>) { + if let Some((cpu, mem)) = app_data.lock().get_chart_data() { let area = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) .split(area); - // Check is some, else can cause out of bounds error, if containers get removed before a docker update - if let Some(data) = app_data.lock().containers.items.get(index) { - let (cpu, mem) = data.get_chart_data(); - let cpu_dataset = vec![Dataset::default() - .marker(symbols::Marker::Dot) - .style(Style::default().fg(Color::Magenta)) - .graph_type(GraphType::Line) - .data(&cpu.0)]; - let mem_dataset = vec![Dataset::default() - .marker(symbols::Marker::Dot) - .style(Style::default().fg(Color::Cyan)) - .graph_type(GraphType::Line) - .data(&mem.0)]; - let cpu_stats = CpuStats::new(cpu.0.last().map_or(0.00, |f| f.1)); - let mem_stats = ByteStats::new(mem.0.last().map_or(0, |f| f.1 as u64)); - let cpu_chart = make_chart(cpu.2, "cpu", cpu_dataset, &cpu_stats, &cpu.1); - let mem_chart = make_chart(mem.2, "memory", mem_dataset, &mem_stats, &mem.1); + let cpu_dataset = vec![Dataset::default() + .marker(symbols::Marker::Dot) + .style(Style::default().fg(Color::Magenta)) + .graph_type(GraphType::Line) + .data(&cpu.0)]; + let mem_dataset = vec![Dataset::default() + .marker(symbols::Marker::Dot) + .style(Style::default().fg(Color::Cyan)) + .graph_type(GraphType::Line) + .data(&mem.0)]; + let cpu_stats = CpuStats::new(cpu.0.last().map_or(0.00, |f| f.1)); + let mem_stats = ByteStats::new(mem.0.last().map_or(0, |f| f.1 as u64)); + let cpu_chart = make_chart(cpu.2, "cpu", cpu_dataset, &cpu_stats, &cpu.1); + let mem_chart = make_chart(mem.2, "memory", mem_dataset, &mem_stats, &mem.1); - f.render_widget(cpu_chart, area[0]); - f.render_widget(mem_chart, area[1]); - } + f.render_widget(cpu_chart, area[0]); + f.render_widget(mem_chart, area[1]); } } @@ -490,8 +471,6 @@ pub fn heading_bar( // If no containers, don't display the headers, could maybe do this first? let help_index = if has_containers { 2 } else { 0 }; - // render help info - f.render_widget(help_paragraph, split_bar[help_index]); } diff --git a/src/ui/gui_state.rs b/src/ui/gui_state.rs index 1c197ef..923c15a 100644 --- a/src/ui/gui_state.rs +++ b/src/ui/gui_state.rs @@ -242,6 +242,7 @@ impl GuiState { } /// Check if the current gui_status contains any of the given status' + /// Don't really like this methodology for gui state, needs a re-think pub fn status_contains(&self, status: &[Status]) -> bool { status.iter().any(|i| self.status.contains(i)) } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 43ff005..32d387e 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -141,9 +141,8 @@ fn ui( let height = if height < 12 { height + 4 } else { 12 }; let column_widths = app_data.lock().get_width(); - let has_containers = !app_data.lock().containers.items.is_empty(); + let has_containers = !app_data.lock().has_containers(); let has_error = app_data.lock().get_error(); - let log_index = app_data.lock().get_selected_log_index(); let sorted_by = app_data.lock().get_sorted(); let show_help = gui_state.lock().status_contains(&[Status::Help]); @@ -193,17 +192,10 @@ fn ui( draw_blocks::containers(app_data, top_panel[0], f, gui_state, &column_widths); if has_containers { - draw_blocks::commands(app_data, top_panel[1], f, gui_state, log_index); + draw_blocks::commands(app_data, top_panel[1], f, gui_state); } - draw_blocks::logs( - app_data, - lower_main[0], - f, - gui_state, - log_index, - &loading_icon, - ); + draw_blocks::logs(app_data, lower_main[0], f, gui_state, &loading_icon); draw_blocks::heading_bar( whole_layout[0], @@ -217,7 +209,7 @@ fn ui( // only draw charts if there are containers if has_containers { - draw_blocks::chart(f, lower_main[1], app_data, log_index); + draw_blocks::chart(f, lower_main[1], app_data); } if let Some(info) = info_text {