diff --git a/CHANGELOG.md b/CHANGELOG.md index c536147..049df74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ### Docs -+ Readme one-liner to download & install latest version, [] ++ Readme one-liner to download & install latest version, [11d5ba361ee4c11d080f1c3c14d8bb677cbfd1fc] + +### Fixes ++ Help panel typo, [e497f3f2d9e1dca99469860c2e728c99e29353ad] # v0.0.4 ### 2022-05-08 diff --git a/README.md b/README.md index 8735c24..8d8db64 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ using docker-compose.yml; or individually -```docker run --name redis -d redis:alpine3.15``` +```docker run --name redis -d redis:alpine3.16``` ```docker run --name postgres -e POSTGRES_PASSWORD=never_use_this_password_in_production -d postgres:alpine``` diff --git a/src/app_data/container_state.rs b/src/app_data/container_state.rs index aca3744..4c1ec93 100644 --- a/src/app_data/container_state.rs +++ b/src/app_data/container_state.rs @@ -160,6 +160,7 @@ impl DockerControls { match state { State::Dead | State::Exited => vec![Self::Start, Self::Restart], State::Paused => vec![Self::Unpause, Self::Stop], + State::Restarting => vec![Self::Stop], State::Running => vec![Self::Pause, Self::Restart, Self::Stop], _ => vec![], } diff --git a/src/app_data/mod.rs b/src/app_data/mod.rs index 06dc806..5e6863a 100644 --- a/src/app_data/mod.rs +++ b/src/app_data/mod.rs @@ -99,9 +99,9 @@ impl AppData { self.error = Some(error); } - /// Find the if of the currently selected container - /// If any containers on system, will always return - /// Only returns None when no containers found + /// Find the if of the currently selected container. + /// If any containers on system, will always return a string. + /// 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() { @@ -296,7 +296,7 @@ impl AppData { for (index, id) in all_ids.iter().enumerate() { if !containers .iter() - .map(|i| i.id.as_ref().unwrap()) + .filter_map(|i| i.id.as_ref()) .any(|x| x == id) { // If removed container is currently selected, then change selected to previous @@ -310,54 +310,56 @@ impl AppData { } for i in containers.iter() { - let id = i.id.as_ref().unwrap().to_owned(); - let mut name = i - .names - .as_ref() - .unwrap_or(&vec!["".to_owned()]) - .get(0) - .unwrap() - .to_owned(); - if let Some(c) = name.chars().next() { - if c == '/' { - name.remove(0); + if let Some(id) = i.id.as_ref() { + let mut name = i + .names + .as_ref() + .unwrap_or(&vec!["".to_owned()]) + .get(0) + .unwrap() + .to_owned(); + if let Some(c) = name.chars().next() { + if c == '/' { + name.remove(0); + } } - } - let state = State::from(i.state.as_ref().unwrap_or(&"dead".to_owned()).trim()); - let status = i - .status - .as_ref() - .unwrap_or(&"".to_owned()) - .trim() - .to_owned(); - let image = i.image.as_ref().unwrap_or(&"".to_owned()).trim().to_owned(); - if let Some(current_container) = self.get_container_by_id(&id) { - if current_container.name != name { - current_container.name = name - }; - if current_container.status != status { - current_container.status = status - }; - if current_container.state != state { - current_container.docker_controls.items = DockerControls::gen_vec(&state); - - // Update the list state, needs to be None if the gen_vec returns an empty vec - match state { - State::Removing | State::Restarting | State::Unknown => { - current_container.docker_controls.state.select(None) - } - _ => current_container.docker_controls.start(), + let state = State::from(i.state.as_ref().unwrap_or(&"dead".to_owned()).trim()); + let status = i + .status + .as_ref() + .unwrap_or(&"".to_owned()) + .trim() + .to_owned(); + let image = i.image.as_ref().unwrap_or(&"".to_owned()).trim().to_owned(); + if let Some(current_container) = self.get_container_by_id(id) { + if current_container.name != name { + current_container.name = name }; - current_container.state = state; - }; - if current_container.image != image { - current_container.image = image - }; - } else { - let mut container = ContainerItem::new(id, status, image, state, name); - container.logs.end(); - self.containers.items.push(container); + if current_container.status != status { + current_container.status = status + }; + if current_container.state != state { + current_container.docker_controls.items = DockerControls::gen_vec(&state); + + // Update the list state, needs to be None if the gen_vec returns an empty vec + match state { + State::Removing | State::Restarting | State::Unknown => { + current_container.docker_controls.state.select(None) + } + _ => current_container.docker_controls.start(), + }; + current_container.state = state; + }; + if current_container.image != image { + current_container.image = image + }; + } else { + let mut container = + ContainerItem::new(id.to_owned(), status, image, state, name); + container.logs.end(); + self.containers.items.push(container); + } } } } @@ -379,7 +381,7 @@ impl AppData { container.logs.items.push(ListItem::new(lines)); }); if container.logs.state.selected().is_none() - || container.logs.state.selected().unwrap() + 1 == current_len + || container.logs.state.selected().unwrap_or_default() + 1 == current_len { container.logs.end(); } diff --git a/src/docker_data/mod.rs b/src/docker_data/mod.rs index 71375ec..0074d1e 100644 --- a/src/docker_data/mod.rs +++ b/src/docker_data/mod.rs @@ -34,8 +34,8 @@ impl DockerData { if stats.cpu_stats.system_cpu_usage.is_some() && stats.precpu_stats.system_cpu_usage.is_some() { - let system_delta = (stats.cpu_stats.system_cpu_usage.unwrap() - - stats.precpu_stats.system_cpu_usage.unwrap()) + let system_delta = (stats.cpu_stats.system_cpu_usage.unwrap_or(0) + - stats.precpu_stats.system_cpu_usage.unwrap_or(0)) as f64; let online_cpus = stats.cpu_stats.online_cpus.unwrap_or_else(|| { stats @@ -75,7 +75,7 @@ impl DockerData { let mem_stat = stats.memory_stats.usage.unwrap_or(0); let mem_limit = stats.memory_stats.limit.unwrap_or(0); - let key = if let Some(networks) = &stats.networks { + let some_key = if let Some(networks) = &stats.networks { networks.keys().next().map(|x| x.to_owned()) } else { None @@ -83,12 +83,14 @@ impl DockerData { let cpu_stats = Self::calculate_usage(&stats); - let (rx, tx) = if let Some(k) = key { - let ii = stats.networks.unwrap(); - let v = ii.get(&k).unwrap(); - (v.rx_bytes.to_owned(), v.tx_bytes.to_owned()) + let no_bytes = (0, 0); + let (rx, tx) = if let Some(key) = some_key { + match stats.networks.unwrap_or_default().get(&key) { + Some(data) => (data.rx_bytes.to_owned(), data.tx_bytes.to_owned()), + None => no_bytes, + } } else { - (0, 0) + no_bytes }; if is_running { @@ -131,7 +133,7 @@ impl DockerData { ..Default::default() })) .await - .unwrap(); + .unwrap_or_default(); let mut output = vec![]; // iter over containers, to only send ones which have an id, as use ID for extensivley! @@ -143,11 +145,13 @@ impl DockerData { self.app_data.lock().update_containers(&output); output .iter() - .map(|i| { - ( - i.state.as_ref().unwrap() == "running", - i.id.as_ref().unwrap().to_owned(), - ) + .filter_map(|i| { + i.id.as_ref().map(|id| { + ( + i.state.as_ref().unwrap_or(&String::new()) == "running", + id.to_owned(), + ) + }) }) .collect::>() } diff --git a/src/input_handler/mod.rs b/src/input_handler/mod.rs index f0b90e8..d8b863e 100644 --- a/src/input_handler/mod.rs +++ b/src/input_handler/mod.rs @@ -99,11 +99,14 @@ impl InputHandler { } }; - let gui_state = Arc::clone(&self.gui_state); - - if self.info_sleep.is_some() { - self.info_sleep.as_ref().unwrap().abort() + // If the info box sleep handle is currently being executed, as in m is pressed twice within a 4000ms window + // then cancel the first handle, as a new handle will be invoked + if let Some(info_sleep_timer) = self.info_sleep.as_ref() { + info_sleep_timer.abort(); } + + let gui_state = Arc::clone(&self.gui_state); + // Show the info box - with "mouse capture enabled / disabled", for 4000 ms self.info_sleep = Some(tokio::spawn(async move { tokio::time::sleep(std::time::Duration::from_millis(4000)).await; gui_state.lock().reset_info_box() @@ -176,39 +179,37 @@ impl InputHandler { // Does is matter though? let panel = self.gui_state.lock().selected_panel; if panel == SelectablePanel::Commands { - let command = self.app_data.lock().get_docker_command(); + let option_command = self.app_data.lock().get_docker_command(); - if command.is_some() { - let id = self.app_data.lock().get_selected_container_id(); - if id.is_some() { - let id = id.unwrap(); - match command.unwrap() { - // TODO handle theses errors? + if let Some(command) = option_command { + let option_id = self.app_data.lock().get_selected_container_id(); + if let Some(id) = option_id { + match command { DockerControls::Pause => self .docker_sender .send(DockerMessage::Pause(id)) .await - .unwrap(), + .unwrap_or(()), DockerControls::Unpause => self .docker_sender .send(DockerMessage::Unpause(id)) .await - .unwrap(), + .unwrap_or(()), DockerControls::Start => self .docker_sender .send(DockerMessage::Start(id)) .await - .unwrap(), + .unwrap_or(()), DockerControls::Stop => self .docker_sender .send(DockerMessage::Stop(id)) .await - .unwrap(), + .unwrap_or(()), DockerControls::Restart => self .docker_sender .send(DockerMessage::Restart(id)) .await - .unwrap(), + .unwrap_or(()), } } } diff --git a/src/ui/draw_blocks.rs b/src/ui/draw_blocks.rs index bec51e4..0fe2370 100644 --- a/src/ui/draw_blocks.rs +++ b/src/ui/draw_blocks.rs @@ -460,7 +460,8 @@ pub fn draw_help_box(f: &mut Frame<'_, B>) { 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 ( ↑ ↓ ) or ( j k ) or (PgUp PgDown) or (Home End) to change selected line"); + help_text + .push_str("\n ( ↑ ↓ ) or ( j k ) or (PgUp PgDown) or (Home End) 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( diff --git a/src/ui/mod.rs b/src/ui/mod.rs index fcec35d..8a41d72 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -58,13 +58,13 @@ pub async fn create_ui( ) .await; - disable_raw_mode().unwrap(); + disable_raw_mode().unwrap_or(()); execute!( terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture )?; - terminal.show_cursor().unwrap(); + terminal.show_cursor().unwrap_or(()); if let Err(err) = res { println!("{}", err); @@ -105,26 +105,27 @@ async fn run_app( let mut now = Instant::now(); loop { terminal.draw(|f| ui(f, &app_data, &gui_state)).unwrap(); - if crossterm::event::poll(input_poll_rate).unwrap() { - let event = event::read().unwrap(); - if let Event::Key(key) = event { - sender - .send(InputMessages::ButtonPress(key.code)) - .await - .unwrap_or(()); - } else if let Event::Mouse(m) = event { - sender - .send(InputMessages::MouseEvent(m)) - .await - .unwrap_or(()); - } else if let Event::Resize(_, _) = event { - gui_state.lock().clear_area_map(); - terminal.autoresize().unwrap_or(()); + if crossterm::event::poll(input_poll_rate).unwrap_or_default() { + if let Ok(event) = event::read() { + if let Event::Key(key) = event { + sender + .send(InputMessages::ButtonPress(key.code)) + .await + .unwrap_or(()); + } else if let Event::Mouse(m) = event { + sender + .send(InputMessages::MouseEvent(m)) + .await + .unwrap_or(()); + } else if let Event::Resize(_, _) = event { + gui_state.lock().clear_area_map(); + terminal.autoresize().unwrap_or(()); + } } } if now.elapsed() >= update_duration { - docker_sx.send(DockerMessage::Update).await.unwrap(); + docker_sx.send(DockerMessage::Update).await.unwrap_or(()); now = Instant::now(); }