wip: sort by
This commit is contained in:
@@ -5,9 +5,12 @@ use tui::{
|
|||||||
widgets::{ListItem, ListState},
|
widgets::{ListItem, ListState},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::Header;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StatefulList<T> {
|
pub struct StatefulList<T> {
|
||||||
pub state: ListState,
|
pub state: ListState,
|
||||||
|
// HASH MAP!
|
||||||
pub items: Vec<T>,
|
pub items: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,18 +117,18 @@ impl State {
|
|||||||
_ => Color::Red,
|
_ => Color::Red,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn as_text(&self) -> &'static str {
|
pub fn as_text(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Dead => "dead",
|
Self::Dead => "dead",
|
||||||
Self::Exited => "exited",
|
Self::Exited => "exited",
|
||||||
Self::Paused => "paused",
|
Self::Paused => "paused",
|
||||||
Self::Removing => "removing",
|
Self::Removing => "removing",
|
||||||
Self::Restarting => "restarting",
|
Self::Restarting => "restarting",
|
||||||
Self::Running => "running",
|
Self::Running => "running",
|
||||||
Self::Unknown => "unknown",
|
Self::Unknown => "unknown",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for State {
|
impl From<&str> for State {
|
||||||
fn from(input: &str) -> Self {
|
fn from(input: &str) -> Self {
|
||||||
@@ -420,31 +423,31 @@ impl ContainerItem {
|
|||||||
/// Container information panel headings + widths, for nice pretty formatting
|
/// Container information panel headings + widths, for nice pretty formatting
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Columns {
|
pub struct Columns {
|
||||||
pub state: (String, usize),
|
pub state: (Header, usize),
|
||||||
pub status: (String, usize),
|
pub status: (Header, usize),
|
||||||
pub cpu: (String, usize),
|
pub cpu: (Header, usize),
|
||||||
pub mem: (String, usize),
|
pub mem: (Header, usize),
|
||||||
pub id: (String, usize),
|
pub id: (Header, usize),
|
||||||
pub name: (String, usize),
|
pub name: (Header, usize),
|
||||||
pub image: (String, usize),
|
pub image: (Header, usize),
|
||||||
pub net_rx: (String, usize),
|
pub net_rx: (Header, usize),
|
||||||
pub net_tx: (String, usize),
|
pub net_tx: (Header, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Columns {
|
impl Columns {
|
||||||
//. (Column titles, minimum header string length)
|
// (Column titles, minimum header string length)
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: (String::from("state"), 11),
|
state: (Header::State, 11),
|
||||||
status: (String::from("status"), 16),
|
status: (Header::Status, 16),
|
||||||
// 7 to allow for "100.00%"
|
// 7 to allow for "100.00%"
|
||||||
cpu: (String::from("cpu"), 7),
|
cpu: (Header::Cpu, 7),
|
||||||
mem: (String::from("memory/limit"), 12),
|
mem: (Header::Memory, 12),
|
||||||
id: (String::from("id"), 8),
|
id: (Header::Id, 8),
|
||||||
name: (String::from("name"), 4),
|
name: (Header::Name, 4),
|
||||||
image: (String::from("image"), 5),
|
image: (Header::Image, 5),
|
||||||
net_rx: (String::from("↓ rx"), 5),
|
net_rx: (Header::Rx, 5),
|
||||||
net_tx: (String::from("↑ tx"), 5),
|
net_tx: (Header::Tx, 5),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+136
-96
@@ -1,4 +1,5 @@
|
|||||||
use bollard::models::ContainerSummary;
|
use bollard::models::ContainerSummary;
|
||||||
|
use core::fmt;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use tui::widgets::ListItem;
|
use tui::widgets::ListItem;
|
||||||
|
|
||||||
@@ -16,31 +17,58 @@ pub struct AppData {
|
|||||||
pub containers: StatefulList<ContainerItem>,
|
pub containers: StatefulList<ContainerItem>,
|
||||||
pub init: bool,
|
pub init: bool,
|
||||||
pub show_error: bool,
|
pub show_error: bool,
|
||||||
// todo
|
sorted_by: Option<(Header, SortedOrder)>,
|
||||||
sort_by: Header
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SortedOrder{
|
pub enum SortedOrder {
|
||||||
Asc,
|
Asc,
|
||||||
Desc
|
Desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Header{
|
pub enum Header {
|
||||||
State,
|
State,
|
||||||
Status,
|
Status,
|
||||||
Cpu,
|
Cpu,
|
||||||
Memory,
|
Memory,
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
Image,
|
Image,
|
||||||
Rx,
|
Rx,
|
||||||
Tx
|
Tx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert errors into strings to display
|
||||||
|
impl fmt::Display for Header {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let disp = match self {
|
||||||
|
Self::State => "state",
|
||||||
|
Self::Status => "status",
|
||||||
|
Self::Cpu => "cpu",
|
||||||
|
Self::Memory => "memory/limit",
|
||||||
|
Self::Id => "id",
|
||||||
|
Self::Name => "name",
|
||||||
|
Self::Image => "image",
|
||||||
|
Self::Rx => "↓ rx",
|
||||||
|
Self::Tx => "↑ tx",
|
||||||
|
};
|
||||||
|
write!(f, "{:>x$}", disp, x = f.width().unwrap_or(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AppData {
|
impl AppData {
|
||||||
|
pub fn get_sorted(&self) -> Option<(Header, SortedOrder)> {
|
||||||
|
self.sorted_by.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the sorted order, also set the selected pointer!
|
||||||
|
pub fn set_sorted(&mut self, x: Option<(Header, SortedOrder)>) {
|
||||||
|
self.sorted_by = x;
|
||||||
|
let id = self.get_selected_container_id();
|
||||||
|
self.sort_containers();
|
||||||
|
self.containers.state.select(self.containers.items.iter().position(|i| Some(i.id.to_owned()) == id));
|
||||||
|
}
|
||||||
/// Generate a default app_state
|
/// Generate a default app_state
|
||||||
pub fn default(args: CliArgs) -> Self {
|
pub fn default(args: CliArgs) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -50,7 +78,7 @@ impl AppData {
|
|||||||
init: false,
|
init: false,
|
||||||
logs_parsed: false,
|
logs_parsed: false,
|
||||||
show_error: false,
|
show_error: false,
|
||||||
sort_by: Header::Memory,
|
sorted_by: Some((Header::Memory, SortedOrder::Asc)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,85 +169,97 @@ impl AppData {
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sort the containers vec, based on a heading, either ascending or descending
|
||||||
pub fn sort_containers(&mut self, so: SortedOrder) {
|
pub fn sort_containers(&mut self) {
|
||||||
|
if let Some((head, so)) = self.sorted_by.as_ref() {
|
||||||
// State,
|
match head {
|
||||||
// Status,
|
Header::State => match so {
|
||||||
// Cpu,
|
SortedOrder::Asc => self
|
||||||
// Memory,
|
.containers
|
||||||
// Id,
|
.items
|
||||||
// Name,
|
.sort_by(|a, b| a.state.as_text().cmp(b.state.as_text())),
|
||||||
// Image,
|
SortedOrder::Desc => self
|
||||||
// Rx,
|
.containers
|
||||||
// Tx
|
.items
|
||||||
match self.sort_by {
|
.sort_by(|a, b| b.state.as_text().cmp(a.state.as_text())),
|
||||||
Header::State => {
|
},
|
||||||
match so {
|
Header::Status => match so {
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|a.state.as_text().cmp(b.state.as_text())),
|
SortedOrder::Asc => self
|
||||||
SortedOrder::Desc => self.containers.items.sort_by(|a,b|b.state.as_text().cmp(a.state.as_text())),
|
.containers
|
||||||
}
|
.items
|
||||||
|
.sort_by(|a, b| a.status.cmp(&b.status)),
|
||||||
},
|
SortedOrder::Desc => self
|
||||||
Header::Status => {
|
.containers
|
||||||
match so {
|
.items
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|a.status.cmp(&b.status)),
|
.sort_by(|a, b| b.status.cmp(&a.status)),
|
||||||
SortedOrder::Desc => self.containers.items.sort_by(|a,b|b.status.cmp(&a.status)),
|
},
|
||||||
}
|
Header::Status => match so {
|
||||||
},
|
SortedOrder::Asc => self
|
||||||
|
.containers
|
||||||
Header::Status => {
|
.items
|
||||||
match so {
|
.sort_by(|a, b| a.status.cmp(&b.status)),
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|a.status.cmp(&b.status)),
|
SortedOrder::Desc => self
|
||||||
SortedOrder::Desc => self.containers.items.sort_by(|a,b|b.status.cmp(&a.status)),
|
.containers
|
||||||
}
|
.items
|
||||||
},
|
.sort_by(|a, b| b.status.cmp(&a.status)),
|
||||||
|
},
|
||||||
Header::Cpu => {
|
Header::Cpu => match so {
|
||||||
match so {
|
SortedOrder::Desc => self
|
||||||
SortedOrder::Desc =>
|
.containers
|
||||||
self.containers.items.sort_by(|a,b|a.cpu_stats.back().cmp(&b.cpu_stats.back())),
|
.items
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|b.cpu_stats.back().cmp(&a.cpu_stats.back()))
|
.sort_by(|a, b| a.cpu_stats.back().cmp(&b.cpu_stats.back())),
|
||||||
}
|
SortedOrder::Asc => self
|
||||||
},
|
.containers
|
||||||
|
.items
|
||||||
Header::Memory => {
|
.sort_by(|a, b| b.cpu_stats.back().cmp(&a.cpu_stats.back())),
|
||||||
match so {
|
},
|
||||||
SortedOrder::Desc =>
|
Header::Memory => match so {
|
||||||
self.containers.items.sort_by(|a,b|a.mem_stats.back().cmp(&b.mem_stats.back())),
|
SortedOrder::Desc => self
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|b.mem_stats.back().cmp(&a.mem_stats.back()))
|
.containers
|
||||||
}
|
.items
|
||||||
},
|
.sort_by(|a, b| a.mem_stats.back().cmp(&b.mem_stats.back())),
|
||||||
Header::Image => {
|
SortedOrder::Asc => self
|
||||||
match so {
|
.containers
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|a.image.cmp(&b.image)),
|
.items
|
||||||
SortedOrder::Desc => self.containers.items.sort_by(|a,b|b.image.cmp(&a.image)),
|
.sort_by(|a, b| b.mem_stats.back().cmp(&a.mem_stats.back())),
|
||||||
}
|
},
|
||||||
},
|
Header::Id => match so {
|
||||||
Header::Name => {
|
SortedOrder::Asc => self.containers.items.sort_by(|a, b| a.id.cmp(&b.id)),
|
||||||
match so {
|
SortedOrder::Desc => self.containers.items.sort_by(|a, b| b.id.cmp(&a.id)),
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|a.name.cmp(&b.name)),
|
},
|
||||||
SortedOrder::Desc => self.containers.items.sort_by(|a,b|b.name.cmp(&a.name)),
|
Header::Image => match so {
|
||||||
}
|
SortedOrder::Asc => self.containers.items.sort_by(|a, b| a.image.cmp(&b.image)),
|
||||||
},
|
SortedOrder::Desc => {
|
||||||
_ => ()
|
self.containers.items.sort_by(|a, b| b.image.cmp(&a.image))
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
Header::Name => match so {
|
||||||
|
SortedOrder::Asc => self.containers.items.sort_by(|a, b| a.name.cmp(&b.name)),
|
||||||
|
SortedOrder::Desc => self.containers.items.sort_by(|a, b| b.name.cmp(&a.name)),
|
||||||
// match so {
|
},
|
||||||
// SortedOrder::Asc => self.containers.items.sort_by(|a,b|b.name.cmp(&a.name)),
|
Header::Rx => match so {
|
||||||
// SortedOrder::Desc => self.containers.items.sort_by(|a,b|a.name.cmp(&b.name))
|
SortedOrder::Asc => self
|
||||||
// }
|
.containers
|
||||||
// }
|
.items
|
||||||
|
.sort_by(|a, b| a.net_rx.cmp(&b.net_rx)),
|
||||||
pub fn sort_by_id(&mut self, so: SortedOrder) {
|
SortedOrder::Desc => self
|
||||||
match so {
|
.containers
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a,b|b.id.cmp(&a.id)),
|
.items
|
||||||
SortedOrder::Desc => self.containers.items.sort_by(|a,b|a.id.cmp(&b.id))
|
.sort_by(|a, b| b.net_rx.cmp(&a.net_rx)),
|
||||||
}
|
},
|
||||||
}
|
Header::Tx => match so {
|
||||||
|
SortedOrder::Asc => self
|
||||||
|
.containers
|
||||||
|
.items
|
||||||
|
.sort_by(|a, b| a.net_tx.cmp(&b.net_tx)),
|
||||||
|
SortedOrder::Desc => self
|
||||||
|
.containers
|
||||||
|
.items
|
||||||
|
.sort_by(|a, b| b.net_tx.cmp(&a.net_tx)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Find the index of the currently selected single log line
|
/// Find the index of the currently selected single log line
|
||||||
pub fn get_selected_log_index(&self) -> Option<usize> {
|
pub fn get_selected_log_index(&self) -> Option<usize> {
|
||||||
|
|||||||
+24
-25
@@ -1,6 +1,7 @@
|
|||||||
use bollard::{
|
use bollard::{
|
||||||
container::{ListContainersOptions, LogsOptions, StartContainerOptions, Stats, StatsOptions},
|
container::{ListContainersOptions, LogsOptions, StartContainerOptions, Stats, StatsOptions},
|
||||||
Docker, models::ContainerSummary,
|
models::ContainerSummary,
|
||||||
|
Docker,
|
||||||
};
|
};
|
||||||
use futures_util::{future::join_all, StreamExt};
|
use futures_util::{future::join_all, StreamExt};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@@ -8,7 +9,7 @@ use std::sync::Arc;
|
|||||||
use tokio::{sync::mpsc::Receiver, task::JoinHandle};
|
use tokio::{sync::mpsc::Receiver, task::JoinHandle};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_data::{AppData, DockerControls, SortedOrder, Header},
|
app_data::{AppData, DockerControls, Header, SortedOrder},
|
||||||
app_error::AppError,
|
app_error::AppError,
|
||||||
parse_args::CliArgs,
|
parse_args::CliArgs,
|
||||||
ui::GuiState,
|
ui::GuiState,
|
||||||
@@ -123,25 +124,25 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn sort_containers(i: &mut [ContainerSummary], so: SortedOrder, header: Header) -> &[ContainerSummary] {
|
// pub fn sort_containers(i: &mut [ContainerSummary], so: SortedOrder, header: Header) -> &[ContainerSummary] {
|
||||||
// match header {
|
// match header {
|
||||||
// Header::State => {
|
// Header::State => {
|
||||||
// match so {
|
// match so {
|
||||||
// SortedOrder::Asc => i.sort_by(|a,b|b.state.cmp(&a.state)),
|
// SortedOrder::Asc => i.sort_by(|a,b|b.state.cmp(&a.state)),
|
||||||
// SortedOrder::Desc => i.sort_by(|a,b|a.state.cmp(&b.state)),
|
// SortedOrder::Desc => i.sort_by(|a,b|a.state.cmp(&b.state)),
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// },
|
// },
|
||||||
// Header::Image => {
|
// Header::Image => {
|
||||||
// match so {
|
// match so {
|
||||||
// SortedOrder::Asc => i.sort_by(|a,b|b.image.cmp(&a.image)),
|
// SortedOrder::Asc => i.sort_by(|a,b|b.image.cmp(&a.image)),
|
||||||
// SortedOrder::Desc => i.sort_by(|a,b|a.image.cmp(&b.image)),
|
// SortedOrder::Desc => i.sort_by(|a,b|a.image.cmp(&b.image)),
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// _ => ()
|
// _ => ()
|
||||||
// }
|
// }
|
||||||
// i
|
// i
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
||||||
/// Just make sure that items sent are guaranteed to have an id
|
/// Just make sure that items sent are guaranteed to have an id
|
||||||
@@ -163,13 +164,12 @@ impl DockerData {
|
|||||||
.filter(|i| i.id.is_some())
|
.filter(|i| i.id.is_some())
|
||||||
.for_each(|c| output.push(c.to_owned()));
|
.for_each(|c| output.push(c.to_owned()));
|
||||||
|
|
||||||
|
// containers.so
|
||||||
// containers.so
|
// let a = Self::sort_containers(&mut output, SortedOrder::Asc, Header::State);
|
||||||
// let a = Self::sort_containers(&mut output, SortedOrder::Asc, Header::State);
|
|
||||||
|
|
||||||
self.app_data.lock().update_containers(&output);
|
self.app_data.lock().update_containers(&output);
|
||||||
|
|
||||||
// self.app_data.lock().sort_containers(SortedOrder::Asc, Header::State);
|
// self.app_data.lock().sort_containers(SortedOrder::Asc, Header::State);
|
||||||
|
|
||||||
output
|
output
|
||||||
.iter()
|
.iter()
|
||||||
@@ -241,7 +241,6 @@ impl DockerData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.update_all_container_stats(&all_ids).await;
|
self.update_all_container_stats(&all_ids).await;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Animate the loading icon
|
/// Animate the loading icon
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use tui::layout::Rect;
|
|||||||
|
|
||||||
mod message;
|
mod message;
|
||||||
use crate::{
|
use crate::{
|
||||||
app_data::{AppData, DockerControls},
|
app_data::{AppData, DockerControls, Header, SortedOrder},
|
||||||
app_error::AppError,
|
app_error::AppError,
|
||||||
docker_data::DockerMessage,
|
docker_data::DockerMessage,
|
||||||
ui::{GuiState, SelectablePanel},
|
ui::{GuiState, SelectablePanel},
|
||||||
@@ -115,6 +115,20 @@ impl InputHandler {
|
|||||||
self.mouse_capture = !self.mouse_capture;
|
self.mouse_capture = !self.mouse_capture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sort(&self, header: Header) {
|
||||||
|
let mut locked_data = self.app_data.lock();
|
||||||
|
if let Some((s, h)) = locked_data.get_sorted().as_ref() {
|
||||||
|
match (s, h) {
|
||||||
|
(header, SortedOrder::Asc) => {
|
||||||
|
locked_data.set_sorted(Some((header.to_owned(), SortedOrder::Desc)))
|
||||||
|
}
|
||||||
|
_ => locked_data.set_sorted(Some((header, SortedOrder::Asc))),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
locked_data.set_sorted(Some((header, SortedOrder::Asc)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle any keyboard button events
|
/// Handle any keyboard button events
|
||||||
async fn button_press(&mut self, key_code: KeyCode) {
|
async fn button_press(&mut self, key_code: KeyCode) {
|
||||||
let show_error = self.app_data.lock().show_error;
|
let show_error = self.app_data.lock().show_error;
|
||||||
@@ -140,6 +154,15 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match key_code {
|
match key_code {
|
||||||
|
KeyCode::Char('1') => self.sort(Header::State),
|
||||||
|
KeyCode::Char('2') => self.sort(Header::Status),
|
||||||
|
KeyCode::Char('3') => self.sort(Header::Cpu),
|
||||||
|
KeyCode::Char('4') => self.sort(Header::Memory),
|
||||||
|
KeyCode::Char('5') => self.sort(Header::Id),
|
||||||
|
KeyCode::Char('6') => self.sort(Header::Image),
|
||||||
|
KeyCode::Char('7') => self.sort(Header::Name),
|
||||||
|
KeyCode::Char('8') => self.sort(Header::Rx),
|
||||||
|
KeyCode::Char('9') => self.sort(Header::Tx),
|
||||||
KeyCode::Char('q') => self.is_running.store(false, Ordering::SeqCst),
|
KeyCode::Char('q') => self.is_running.store(false, Ordering::SeqCst),
|
||||||
KeyCode::Char('h') => self.gui_state.lock().show_help = true,
|
KeyCode::Char('h') => self.gui_state.lock().show_help = true,
|
||||||
KeyCode::Char('m') => self.m_button(),
|
KeyCode::Char('m') => self.m_button(),
|
||||||
|
|||||||
+38
-13
@@ -14,7 +14,7 @@ use tui::{
|
|||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::app_data::{SortedOrder, Header};
|
use crate::app_data::{Header, SortedOrder};
|
||||||
use crate::{
|
use crate::{
|
||||||
app_data::{AppData, ByteStats, Columns, CpuStats, State, Stats},
|
app_data::{AppData, ByteStats, Columns, CpuStats, State, Stats},
|
||||||
app_error::AppError,
|
app_error::AppError,
|
||||||
@@ -124,9 +124,6 @@ pub fn draw_containers<B: Backend>(
|
|||||||
widths: &Columns,
|
widths: &Columns,
|
||||||
) {
|
) {
|
||||||
let block = generate_block(app_data, area, gui_state, SelectablePanel::Containers);
|
let block = generate_block(app_data, area, gui_state, SelectablePanel::Containers);
|
||||||
app_data.lock().sort_containers(SortedOrder::Asc);
|
|
||||||
|
|
||||||
|
|
||||||
let items = app_data
|
let items = app_data
|
||||||
.lock()
|
.lock()
|
||||||
.containers
|
.containers
|
||||||
@@ -361,12 +358,39 @@ pub fn draw_heading_bar<B: Backend>(
|
|||||||
has_containers: bool,
|
has_containers: bool,
|
||||||
loading_icon: String,
|
loading_icon: String,
|
||||||
info_visible: bool,
|
info_visible: bool,
|
||||||
|
sorted_by: Option<(Header, SortedOrder)>,
|
||||||
) {
|
) {
|
||||||
let block = || Block::default().style(Style::default().bg(Color::Magenta).fg(Color::Black));
|
let block = || Block::default().style(Style::default().bg(Color::Magenta).fg(Color::Black));
|
||||||
|
|
||||||
f.render_widget(block(), area);
|
f.render_widget(block(), area);
|
||||||
|
|
||||||
let mut column_headings = format!(
|
let aaa = |x: &Header| {
|
||||||
|
let mut output = "";
|
||||||
|
if let Some((a, b)) = sorted_by.as_ref() {
|
||||||
|
if x == a {
|
||||||
|
output = match b {
|
||||||
|
SortedOrder::Asc => "A",
|
||||||
|
SortedOrder::Desc => "B",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
output
|
||||||
|
};
|
||||||
|
|
||||||
|
// need to split this into blocks, and put each block in the split block, and set color to white if is selected
|
||||||
|
// then just put in the split in a horizontal fashion, with a width equal to widtrh, or char count?
|
||||||
|
// let white = "\x1b[37m";
|
||||||
|
// let reset = "\x1b[0m";
|
||||||
|
|
||||||
|
// let mut column_headings = format!(
|
||||||
|
// " {}{:>width$}{}",
|
||||||
|
// loading_icon,
|
||||||
|
// columns.state.0,
|
||||||
|
// width = columns.state.1,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// Each
|
||||||
|
let mut column_headings = format!(
|
||||||
" {}{:>width$}",
|
" {}{:>width$}",
|
||||||
loading_icon,
|
loading_icon,
|
||||||
columns.state.0,
|
columns.state.0,
|
||||||
@@ -381,6 +405,9 @@ pub fn draw_heading_bar<B: Backend>(
|
|||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Get selected and sorted
|
||||||
|
// Maybe each heading needs to be its own boock
|
||||||
column_headings
|
column_headings
|
||||||
.push_str(format!("{}{:>width$}", MARGIN, columns.cpu.0, width = columns.cpu.1).as_str());
|
.push_str(format!("{}{:>width$}", MARGIN, columns.cpu.0, width = columns.cpu.1).as_str());
|
||||||
column_headings
|
column_headings
|
||||||
@@ -425,16 +452,13 @@ pub fn draw_heading_bar<B: Backend>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let suffix = if info_visible { "exit" } else { "show" };
|
let suffix = if info_visible { "exit" } else { "show" };
|
||||||
let info_text = format!("( h ) to {} help {}", suffix, MARGIN);
|
let info_text = format!("( h ) {} help {}", suffix, MARGIN);
|
||||||
let info_width = info_text.chars().count();
|
let info_width = info_text.chars().count() as u16;
|
||||||
|
|
||||||
let column_width = column_headings.chars().count();
|
|
||||||
|
|
||||||
|
let x = area.width - info_width;
|
||||||
|
let column_width = if x > 0 { x } else { 1 };
|
||||||
let splits = if has_containers {
|
let splits = if has_containers {
|
||||||
vec![
|
vec![Constraint::Min(column_width), Constraint::Min(info_width)]
|
||||||
Constraint::Min(column_width as u16),
|
|
||||||
Constraint::Min(info_width as u16),
|
|
||||||
]
|
|
||||||
} else {
|
} else {
|
||||||
vec![Constraint::Percentage(100)]
|
vec![Constraint::Percentage(100)]
|
||||||
};
|
};
|
||||||
@@ -482,6 +506,7 @@ pub fn draw_help_box<B: Backend>(f: &mut Frame<'_, B>) {
|
|||||||
.push_str("\n ( ↑ ↓ ) or ( j k ) or (PgUp PgDown) or (Home End) to change selected line");
|
.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 ( enter ) to send docker container commands");
|
||||||
help_text.push_str("\n ( h ) to toggle this help information");
|
help_text.push_str("\n ( h ) to toggle this help information");
|
||||||
|
help_text.push_str("\n ( 1 - 9 ) order headers");
|
||||||
help_text.push_str(
|
help_text.push_str(
|
||||||
"\n ( m ) to toggle mouse capture - if disabled, text on screen can be selected & copied",
|
"\n ( m ) to toggle mouse capture - if disabled, text on screen can be selected & copied",
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ fn ui<B: Backend>(
|
|||||||
let show_help = gui_state.lock().show_help;
|
let show_help = gui_state.lock().show_help;
|
||||||
let info_text = gui_state.lock().info_box_text.clone();
|
let info_text = gui_state.lock().info_box_text.clone();
|
||||||
let loading_icon = gui_state.lock().get_loading();
|
let loading_icon = gui_state.lock().get_loading();
|
||||||
|
let sorted_by = app_data.lock().get_sorted();
|
||||||
|
|
||||||
let whole_layout = Layout::default()
|
let whole_layout = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
@@ -214,6 +215,7 @@ fn ui<B: Backend>(
|
|||||||
has_containers,
|
has_containers,
|
||||||
loading_icon,
|
loading_icon,
|
||||||
show_help,
|
show_help,
|
||||||
|
sorted_by,
|
||||||
);
|
);
|
||||||
|
|
||||||
// only draw charts if there are containers
|
// only draw charts if there are containers
|
||||||
|
|||||||
Reference in New Issue
Block a user