Merge branch 'chore/linting' into dev
This commit is contained in:
@@ -68,15 +68,10 @@ impl<T> StatefulList<T> {
|
|||||||
String::from("")
|
String::from("")
|
||||||
} else {
|
} else {
|
||||||
let len = self.items.len();
|
let len = self.items.len();
|
||||||
let c = if let Some(value) = self.state.selected() {
|
let c = self
|
||||||
if len > 0 {
|
.state
|
||||||
value + 1
|
.selected()
|
||||||
} else {
|
.map_or(0, |value| if len > 0 { value + 1 } else { value });
|
||||||
value
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
format!("{}/{}", c, self.items.len())
|
format!("{}/{}", c, self.items.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +90,7 @@ pub enum State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn get_color(&self) -> Color {
|
pub const fn get_color(&self) -> Color {
|
||||||
match self {
|
match self {
|
||||||
Self::Running => Color::Green,
|
Self::Running => Color::Green,
|
||||||
Self::Removing => Color::LightRed,
|
Self::Removing => Color::LightRed,
|
||||||
@@ -105,7 +100,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dirty way to create order for the state, rather than impl Ord
|
// Dirty way to create order for the state, rather than impl Ord
|
||||||
pub fn order(&self) -> &'static str {
|
pub const fn order(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Running => "a",
|
Self::Running => "a",
|
||||||
Self::Paused => "b",
|
Self::Paused => "b",
|
||||||
@@ -158,7 +153,7 @@ pub enum DockerControls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DockerControls {
|
impl DockerControls {
|
||||||
pub fn get_color(&self) -> Color {
|
pub const fn get_color(&self) -> Color {
|
||||||
match self {
|
match self {
|
||||||
Self::Start => Color::Green,
|
Self::Start => Color::Green,
|
||||||
Self::Stop => Color::Red,
|
Self::Stop => Color::Red,
|
||||||
@@ -205,7 +200,7 @@ pub struct CpuStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CpuStats {
|
impl CpuStats {
|
||||||
pub fn new(value: f64) -> Self {
|
pub const fn new(value: f64) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,7 +223,7 @@ impl Ord for CpuStats {
|
|||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
if self.value > other.value {
|
if self.value > other.value {
|
||||||
Ordering::Greater
|
Ordering::Greater
|
||||||
} else if self.value == other.value {
|
} else if (self.value - other.value).abs() < 0.01 {
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
} else {
|
} else {
|
||||||
Ordering::Less
|
Ordering::Less
|
||||||
@@ -276,7 +271,7 @@ impl Ord for ByteStats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ByteStats {
|
impl ByteStats {
|
||||||
pub fn new(value: u64) -> Self {
|
pub const fn new(value: u64) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
pub fn update(&mut self, value: u64) {
|
pub fn update(&mut self, value: u64) {
|
||||||
@@ -352,7 +347,7 @@ impl ContainerItem {
|
|||||||
/// Find the max value in the last 30 items in the cpu stats vec
|
/// Find the max value in the last 30 items in the cpu stats vec
|
||||||
fn max_cpu_stats(&self) -> CpuStats {
|
fn max_cpu_stats(&self) -> CpuStats {
|
||||||
match self.cpu_stats.iter().max() {
|
match self.cpu_stats.iter().max() {
|
||||||
Some(value) => value.to_owned(),
|
Some(value) => value.clone(),
|
||||||
None => CpuStats::new(0.0),
|
None => CpuStats::new(0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +355,7 @@ impl ContainerItem {
|
|||||||
/// Find the max value in the last 30 items in the mem stats vec
|
/// Find the max value in the last 30 items in the mem stats vec
|
||||||
fn max_mem_stats(&self) -> ByteStats {
|
fn max_mem_stats(&self) -> ByteStats {
|
||||||
match self.mem_stats.iter().max() {
|
match self.mem_stats.iter().max() {
|
||||||
Some(value) => value.to_owned(),
|
Some(value) => value.clone(),
|
||||||
None => ByteStats::new(0),
|
None => ByteStats::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,8 +418,8 @@ pub struct Columns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Columns {
|
impl Columns {
|
||||||
// (Column titles, minimum header string length)
|
/// (Column titles, minimum header string length)
|
||||||
pub fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: (Header::State, 11),
|
state: (Header::State, 11),
|
||||||
status: (Header::Status, 16),
|
status: (Header::Status, 16),
|
||||||
|
|||||||
+44
-45
@@ -71,7 +71,7 @@ impl AppData {
|
|||||||
self.containers
|
self.containers
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.position(|i| Some(i.id.to_owned()) == id),
|
.position(|i| Some(i.id.clone()) == id),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/// Generate a default app_state
|
/// Generate a default app_state
|
||||||
@@ -87,8 +87,9 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current time as unix timestamp
|
/// Current time as unix timestamp
|
||||||
fn get_systemtime(&self) -> u64 {
|
#[allow(clippy::expect_used)]
|
||||||
|
fn get_systemtime() -> u64 {
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.expect("In our known reality, this error should never occur")
|
.expect("In our known reality, this error should never occur")
|
||||||
@@ -106,7 +107,7 @@ impl AppData {
|
|||||||
.selected()
|
.selected()
|
||||||
{
|
{
|
||||||
output =
|
output =
|
||||||
Some(self.containers.items[index].docker_controls.items[control_index].clone())
|
Some(self.containers.items[index].docker_controls.items[control_index].clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
@@ -115,28 +116,28 @@ impl AppData {
|
|||||||
/// Change selected choice of docker commands of selected container
|
/// Change selected choice of docker commands of selected container
|
||||||
pub fn docker_command_next(&mut self) {
|
pub fn docker_command_next(&mut self) {
|
||||||
if let Some(index) = self.containers.state.selected() {
|
if let Some(index) = self.containers.state.selected() {
|
||||||
self.containers.items[index].docker_controls.next()
|
self.containers.items[index].docker_controls.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change selected choice of docker commands of selected container
|
/// Change selected choice of docker commands of selected container
|
||||||
pub fn docker_command_previous(&mut self) {
|
pub fn docker_command_previous(&mut self) {
|
||||||
if let Some(index) = self.containers.state.selected() {
|
if let Some(index) = self.containers.state.selected() {
|
||||||
self.containers.items[index].docker_controls.previous()
|
self.containers.items[index].docker_controls.previous();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change selected choice of docker commands of selected container
|
/// Change selected choice of docker commands of selected container
|
||||||
pub fn docker_command_start(&mut self) {
|
pub fn docker_command_start(&mut self) {
|
||||||
if let Some(index) = self.containers.state.selected() {
|
if let Some(index) = self.containers.state.selected() {
|
||||||
self.containers.items[index].docker_controls.start()
|
self.containers.items[index].docker_controls.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change selected choice of docker commands of selected container
|
/// Change selected choice of docker commands of selected container
|
||||||
pub fn docker_command_end(&mut self) {
|
pub fn docker_command_end(&mut self) {
|
||||||
if let Some(index) = self.containers.state.selected() {
|
if let Some(index) = self.containers.state.selected() {
|
||||||
self.containers.items[index].docker_controls.end()
|
self.containers.items[index].docker_controls.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,9 +168,9 @@ impl AppData {
|
|||||||
.iter()
|
.iter()
|
||||||
.skip(index)
|
.skip(index)
|
||||||
.take(1)
|
.take(1)
|
||||||
.map(|i| i.id.to_owned())
|
.map(|i| i.id.clone())
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
output = Some(id)
|
output = Some(id);
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
@@ -225,7 +226,7 @@ impl AppData {
|
|||||||
Header::Image => match so {
|
Header::Image => match so {
|
||||||
SortedOrder::Asc => self.containers.items.sort_by(|a, b| a.image.cmp(&b.image)),
|
SortedOrder::Asc => self.containers.items.sort_by(|a, b| a.image.cmp(&b.image)),
|
||||||
SortedOrder::Desc => {
|
SortedOrder::Desc => {
|
||||||
self.containers.items.sort_by(|a, b| b.image.cmp(&a.image))
|
self.containers.items.sort_by(|a, b| b.image.cmp(&a.image));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Header::Name => match so {
|
Header::Name => match so {
|
||||||
@@ -258,38 +259,37 @@ impl AppData {
|
|||||||
/// Get the title for log panel for selected container
|
/// Get the title for log panel for selected container
|
||||||
/// will be "logs x/x"
|
/// will be "logs x/x"
|
||||||
pub fn get_log_title(&self) -> String {
|
pub fn get_log_title(&self) -> String {
|
||||||
if let Some(index) = self.get_selected_log_index() {
|
self.get_selected_log_index().map_or_else(
|
||||||
self.containers.items[index].logs.get_state_title()
|
|| String::from(""),
|
||||||
} else {
|
|index| self.containers.items[index].logs.get_state_title(),
|
||||||
String::from("")
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// select next selected log line
|
/// select next selected log line
|
||||||
pub fn log_next(&mut self) {
|
pub fn log_next(&mut self) {
|
||||||
if let Some(index) = self.get_selected_log_index() {
|
if let Some(index) = self.get_selected_log_index() {
|
||||||
self.containers.items[index].logs.next()
|
self.containers.items[index].logs.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// select previous selected log line
|
/// select previous selected log line
|
||||||
pub fn log_previous(&mut self) {
|
pub fn log_previous(&mut self) {
|
||||||
if let Some(index) = self.get_selected_log_index() {
|
if let Some(index) = self.get_selected_log_index() {
|
||||||
self.containers.items[index].logs.previous()
|
self.containers.items[index].logs.previous();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// select last selected log line
|
/// select last selected log line
|
||||||
pub fn log_end(&mut self) {
|
pub fn log_end(&mut self) {
|
||||||
if let Some(index) = self.get_selected_log_index() {
|
if let Some(index) = self.get_selected_log_index() {
|
||||||
self.containers.items[index].logs.end()
|
self.containers.items[index].logs.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// select first selected log line
|
/// select first selected log line
|
||||||
pub fn log_start(&mut self) {
|
pub fn log_start(&mut self) {
|
||||||
if let Some(index) = self.get_selected_log_index() {
|
if let Some(index) = self.get_selected_log_index() {
|
||||||
self.containers.items[index].logs.start()
|
self.containers.items[index].logs.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ impl AppData {
|
|||||||
let mut output = Columns::new();
|
let mut output = Columns::new();
|
||||||
let count = |x: &String| x.chars().count();
|
let count = |x: &String| x.chars().count();
|
||||||
|
|
||||||
for container in self.containers.items.iter() {
|
for container in &self.containers.items {
|
||||||
let cpu_count = count(
|
let cpu_count = count(
|
||||||
&container
|
&container
|
||||||
.cpu_stats
|
.cpu_stats
|
||||||
@@ -329,8 +329,8 @@ impl AppData {
|
|||||||
container.mem_limit
|
container.mem_limit
|
||||||
));
|
));
|
||||||
|
|
||||||
let net_rx_count = count(&container.rx.to_string());
|
let rx_count = count(&container.rx.to_string());
|
||||||
let net_tx_count = count(&container.tx.to_string());
|
let tx_count = count(&container.tx.to_string());
|
||||||
let image_count = count(&container.image);
|
let image_count = count(&container.image);
|
||||||
let name_count = count(&container.name);
|
let name_count = count(&container.name);
|
||||||
let state_count = count(&container.state.to_string());
|
let state_count = count(&container.state.to_string());
|
||||||
@@ -354,11 +354,11 @@ impl AppData {
|
|||||||
if status_count > output.status.1 {
|
if status_count > output.status.1 {
|
||||||
output.status.1 = status_count;
|
output.status.1 = status_count;
|
||||||
};
|
};
|
||||||
if net_rx_count > output.net_rx.1 {
|
if rx_count > output.net_rx.1 {
|
||||||
output.net_rx.1 = net_rx_count;
|
output.net_rx.1 = rx_count;
|
||||||
};
|
};
|
||||||
if net_tx_count > output.net_tx.1 {
|
if tx_count > output.net_tx.1 {
|
||||||
output.net_tx.1 = net_tx_count;
|
output.net_tx.1 = tx_count;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
@@ -369,7 +369,7 @@ impl AppData {
|
|||||||
self.containers
|
self.containers
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|i| i.id.to_owned())
|
.map(|i| i.id.clone())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,14 +381,14 @@ impl AppData {
|
|||||||
/// Update container mem, cpu, & network stats, in single function so only need to call .lock() once
|
/// Update container mem, cpu, & network stats, in single function so only need to call .lock() once
|
||||||
pub fn update_stats(
|
pub fn update_stats(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: String,
|
id: &str,
|
||||||
cpu_stat: Option<f64>,
|
cpu_stat: Option<f64>,
|
||||||
mem_stat: Option<u64>,
|
mem_stat: Option<u64>,
|
||||||
mem_limit: u64,
|
mem_limit: u64,
|
||||||
rx: u64,
|
rx: u64,
|
||||||
tx: u64,
|
tx: u64,
|
||||||
) {
|
) {
|
||||||
if let Some(container) = self.get_container_by_id(&id) {
|
if let Some(container) = self.get_container_by_id(id) {
|
||||||
if container.cpu_stats.len() >= 60 {
|
if container.cpu_stats.len() >= 60 {
|
||||||
container.cpu_stats.pop_front();
|
container.cpu_stats.pop_front();
|
||||||
}
|
}
|
||||||
@@ -443,7 +443,7 @@ impl AppData {
|
|||||||
.unwrap_or(&vec!["".to_owned()])
|
.unwrap_or(&vec!["".to_owned()])
|
||||||
.get(0)
|
.get(0)
|
||||||
.unwrap_or(&String::from(""))
|
.unwrap_or(&String::from(""))
|
||||||
.to_owned();
|
.clone();
|
||||||
if let Some(c) = name.chars().next() {
|
if let Some(c) = name.chars().next() {
|
||||||
if c == '/' {
|
if c == '/' {
|
||||||
name.remove(0);
|
name.remove(0);
|
||||||
@@ -460,10 +460,10 @@ impl AppData {
|
|||||||
let image = i.image.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 let Some(current_container) = self.get_container_by_id(id) {
|
||||||
if current_container.name != name {
|
if current_container.name != name {
|
||||||
current_container.name = name
|
current_container.name = name;
|
||||||
};
|
};
|
||||||
if current_container.status != status {
|
if current_container.status != status {
|
||||||
current_container.status = status
|
current_container.status = status;
|
||||||
};
|
};
|
||||||
if current_container.state != state {
|
if current_container.state != state {
|
||||||
current_container.docker_controls.items = DockerControls::gen_vec(&state);
|
current_container.docker_controls.items = DockerControls::gen_vec(&state);
|
||||||
@@ -471,18 +471,17 @@ impl AppData {
|
|||||||
// Update the list state, needs to be None if the gen_vec returns an empty vec
|
// Update the list state, needs to be None if the gen_vec returns an empty vec
|
||||||
match state {
|
match state {
|
||||||
State::Removing | State::Restarting | State::Unknown => {
|
State::Removing | State::Restarting | State::Unknown => {
|
||||||
current_container.docker_controls.state.select(None)
|
current_container.docker_controls.state.select(None);
|
||||||
}
|
}
|
||||||
_ => current_container.docker_controls.start(),
|
_ => current_container.docker_controls.start(),
|
||||||
};
|
};
|
||||||
current_container.state = state;
|
current_container.state = state;
|
||||||
};
|
};
|
||||||
if current_container.image != image {
|
if current_container.image != image {
|
||||||
current_container.image = image
|
current_container.image = image;
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
let mut container =
|
let mut container = ContainerItem::new(id.clone(), status, image, state, name);
|
||||||
ContainerItem::new(id.to_owned(), status, image, state, name);
|
|
||||||
container.logs.end();
|
container.logs.end();
|
||||||
self.containers.items.push(container);
|
self.containers.items.push(container);
|
||||||
}
|
}
|
||||||
@@ -491,25 +490,25 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// update logs of a given container, based on id
|
/// update logs of a given container, based on id
|
||||||
pub fn update_log_by_id(&mut self, output: Vec<String>, id: String) {
|
pub fn update_log_by_id(&mut self, output: &[String], id: &str) {
|
||||||
let tz = self.get_systemtime();
|
let tz = Self::get_systemtime();
|
||||||
let color = self.args.color;
|
let color = self.args.color;
|
||||||
let raw = self.args.raw;
|
let raw = self.args.raw;
|
||||||
|
|
||||||
if let Some(container) = self.get_container_by_id(&id) {
|
if let Some(container) = self.get_container_by_id(id) {
|
||||||
container.last_updated = tz;
|
container.last_updated = tz;
|
||||||
let current_len = container.logs.items.len();
|
let current_len = container.logs.items.len();
|
||||||
|
|
||||||
output.iter().for_each(|i| {
|
for i in output.iter() {
|
||||||
let lines = if color {
|
let lines = if color {
|
||||||
log_sanitizer::colorize_logs(i.to_owned())
|
log_sanitizer::colorize_logs(i)
|
||||||
} else if raw {
|
} else if raw {
|
||||||
log_sanitizer::raw(i.to_owned())
|
log_sanitizer::raw(i.clone())
|
||||||
} else {
|
} else {
|
||||||
log_sanitizer::remove_ansi(i.to_owned())
|
log_sanitizer::remove_ansi(i)
|
||||||
};
|
};
|
||||||
container.logs.items.push(ListItem::new(lines));
|
container.logs.items.push(ListItem::new(lines));
|
||||||
});
|
}
|
||||||
|
|
||||||
if container.logs.state.selected().is_none()
|
if container.logs.state.selected().is_none()
|
||||||
|| container.logs.state.selected().unwrap_or_default() + 1 == current_len
|
|| container.logs.state.selected().unwrap_or_default() + 1 == current_len
|
||||||
|
|||||||
+32
-35
@@ -102,11 +102,10 @@ impl DockerData {
|
|||||||
let mem_stat = stats.memory_stats.usage.unwrap_or(0);
|
let mem_stat = stats.memory_stats.usage.unwrap_or(0);
|
||||||
let mem_limit = stats.memory_stats.limit.unwrap_or(0);
|
let mem_limit = stats.memory_stats.limit.unwrap_or(0);
|
||||||
|
|
||||||
let some_key = if let Some(networks) = &stats.networks {
|
let some_key = stats
|
||||||
networks.keys().next().map(|x| x.to_owned())
|
.networks
|
||||||
} else {
|
.as_ref()
|
||||||
None
|
.and_then(|networks| networks.keys().next().cloned());
|
||||||
};
|
|
||||||
|
|
||||||
let cpu_stats = Self::calculate_usage(&stats);
|
let cpu_stats = Self::calculate_usage(&stats);
|
||||||
|
|
||||||
@@ -122,7 +121,7 @@ impl DockerData {
|
|||||||
|
|
||||||
if is_running {
|
if is_running {
|
||||||
app_data.lock().update_stats(
|
app_data.lock().update_stats(
|
||||||
id.clone(),
|
&id,
|
||||||
Some(cpu_stats),
|
Some(cpu_stats),
|
||||||
Some(mem_stat),
|
Some(mem_stat),
|
||||||
mem_limit,
|
mem_limit,
|
||||||
@@ -132,10 +131,9 @@ impl DockerData {
|
|||||||
} else {
|
} else {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.update_stats(id.clone(), None, None, mem_limit, rx, tx);
|
.update_stats(&id, None, None, mem_limit, rx, tx);
|
||||||
}
|
}
|
||||||
let key = SpawnId::Stats(id.to_owned());
|
spawns.lock().remove(&SpawnId::Stats(id.clone()));
|
||||||
spawns.lock().remove(&key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,13 +144,13 @@ impl DockerData {
|
|||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
let spawns = Arc::clone(&self.spawns);
|
let spawns = Arc::clone(&self.spawns);
|
||||||
let is_running = *is_running;
|
let is_running = *is_running;
|
||||||
let id = id.to_owned();
|
let id = id.clone();
|
||||||
|
|
||||||
let key = SpawnId::Stats(id.to_owned());
|
let key = SpawnId::Stats(id.clone());
|
||||||
let spawn_contains_id = spawns.lock().contains_key(&key);
|
let spawn_contains_id = spawns.lock().contains_key(&key);
|
||||||
let s = tokio::spawn(Self::update_container_stat(
|
let s = tokio::spawn(Self::update_container_stat(
|
||||||
docker,
|
docker,
|
||||||
id.to_owned(),
|
id.clone(),
|
||||||
app_data,
|
app_data,
|
||||||
is_running,
|
is_running,
|
||||||
spawns,
|
spawns,
|
||||||
@@ -180,7 +178,7 @@ impl DockerData {
|
|||||||
containers
|
containers
|
||||||
.iter()
|
.iter()
|
||||||
.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.clone()));
|
||||||
|
|
||||||
self.app_data.lock().update_containers(&output);
|
self.app_data.lock().update_containers(&output);
|
||||||
|
|
||||||
@@ -193,7 +191,7 @@ impl DockerData {
|
|||||||
i.id.as_ref().map(|id| {
|
i.id.as_ref().map(|id| {
|
||||||
(
|
(
|
||||||
i.state.as_ref().unwrap_or(&String::new()) == "running",
|
i.state.as_ref().unwrap_or(&String::new()) == "running",
|
||||||
id.to_owned(),
|
id.clone(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -230,9 +228,8 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let key = SpawnId::Log(id.to_owned());
|
spawns.lock().remove(&SpawnId::Log(id.clone()));
|
||||||
spawns.lock().remove(&key);
|
app_data.lock().update_log_by_id(&output, &id);
|
||||||
app_data.lock().update_log_by_id(output, id.to_owned());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update all logs, spawn each container into own tokio::spawn thread
|
/// Update all logs, spawn each container into own tokio::spawn thread
|
||||||
@@ -240,10 +237,10 @@ impl DockerData {
|
|||||||
for (_, id) in all_ids.iter() {
|
for (_, id) in all_ids.iter() {
|
||||||
let docker = Arc::clone(&self.docker);
|
let docker = Arc::clone(&self.docker);
|
||||||
let timestamps = self.timestamps;
|
let timestamps = self.timestamps;
|
||||||
let id = id.to_owned();
|
let id = id.clone();
|
||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
let spawns = Arc::clone(&self.spawns);
|
let spawns = Arc::clone(&self.spawns);
|
||||||
let key = SpawnId::Log(id.to_owned());
|
let key = SpawnId::Log(id.clone());
|
||||||
let s = tokio::spawn(Self::update_log(
|
let s = tokio::spawn(Self::update_log(
|
||||||
docker, id, timestamps, 0, app_data, spawns,
|
docker, id, timestamps, 0, app_data, spawns,
|
||||||
));
|
));
|
||||||
@@ -256,9 +253,9 @@ impl DockerData {
|
|||||||
let all_ids = self.update_all_containers().await;
|
let all_ids = self.update_all_containers().await;
|
||||||
let optional_index = self.app_data.lock().get_selected_log_index();
|
let optional_index = self.app_data.lock().get_selected_log_index();
|
||||||
if let Some(index) = optional_index {
|
if let Some(index) = optional_index {
|
||||||
let id = self.app_data.lock().containers.items[index].id.to_owned();
|
let id = self.app_data.lock().containers.items[index].id.clone();
|
||||||
|
|
||||||
let key = SpawnId::Log(id.to_owned());
|
let key = SpawnId::Log(id.clone());
|
||||||
let running = self.spawns.lock().contains_key(&key);
|
let running = self.spawns.lock().contains_key(&key);
|
||||||
|
|
||||||
if !running {
|
if !running {
|
||||||
@@ -290,7 +287,7 @@ impl DockerData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Stop the loading_spin function, and reset gui loading status
|
/// Stop the loading_spin function, and reset gui loading status
|
||||||
fn stop_loading_spin(&mut self, handle: JoinHandle<()>) {
|
fn stop_loading_spin(&mut self, handle: &JoinHandle<()>) {
|
||||||
handle.abort();
|
handle.abort();
|
||||||
self.gui_state.lock().reset_loading();
|
self.gui_state.lock().reset_loading();
|
||||||
}
|
}
|
||||||
@@ -315,7 +312,7 @@ impl DockerData {
|
|||||||
self.initialised = self.app_data.lock().initialised(&all_ids);
|
self.initialised = self.app_data.lock().initialised(&all_ids);
|
||||||
}
|
}
|
||||||
self.app_data.lock().init = true;
|
self.app_data.lock().init = true;
|
||||||
self.stop_loading_spin(loading_spin);
|
self.stop_loading_spin(&loading_spin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle incoming messages, container controls & all container information update
|
/// Handle incoming messages, container controls & all container information update
|
||||||
@@ -329,9 +326,9 @@ impl DockerData {
|
|||||||
docker.pause_container(&id).await.unwrap_or_else(|_| {
|
docker.pause_container(&id).await.unwrap_or_else(|_| {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Pause))
|
.set_error(AppError::DockerCommand(DockerControls::Pause));
|
||||||
});
|
});
|
||||||
self.stop_loading_spin(loading_spin);
|
self.stop_loading_spin(&loading_spin);
|
||||||
}
|
}
|
||||||
DockerMessage::Restart(id) => {
|
DockerMessage::Restart(id) => {
|
||||||
let loading_spin = self.loading_spin().await;
|
let loading_spin = self.loading_spin().await;
|
||||||
@@ -341,9 +338,9 @@ impl DockerData {
|
|||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Restart))
|
.set_error(AppError::DockerCommand(DockerControls::Restart));
|
||||||
});
|
});
|
||||||
self.stop_loading_spin(loading_spin);
|
self.stop_loading_spin(&loading_spin);
|
||||||
}
|
}
|
||||||
DockerMessage::Start(id) => {
|
DockerMessage::Start(id) => {
|
||||||
let loading_spin = self.loading_spin().await;
|
let loading_spin = self.loading_spin().await;
|
||||||
@@ -353,28 +350,28 @@ impl DockerData {
|
|||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Start))
|
.set_error(AppError::DockerCommand(DockerControls::Start));
|
||||||
});
|
});
|
||||||
self.stop_loading_spin(loading_spin);
|
self.stop_loading_spin(&loading_spin);
|
||||||
}
|
}
|
||||||
DockerMessage::Stop(id) => {
|
DockerMessage::Stop(id) => {
|
||||||
let loading_spin = self.loading_spin().await;
|
let loading_spin = self.loading_spin().await;
|
||||||
docker.stop_container(&id, None).await.unwrap_or_else(|_| {
|
docker.stop_container(&id, None).await.unwrap_or_else(|_| {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Stop))
|
.set_error(AppError::DockerCommand(DockerControls::Stop));
|
||||||
});
|
});
|
||||||
self.stop_loading_spin(loading_spin);
|
self.stop_loading_spin(&loading_spin);
|
||||||
}
|
}
|
||||||
DockerMessage::Unpause(id) => {
|
DockerMessage::Unpause(id) => {
|
||||||
let loading_spin = self.loading_spin().await;
|
let loading_spin = self.loading_spin().await;
|
||||||
docker.unpause_container(&id).await.unwrap_or_else(|_| {
|
docker.unpause_container(&id).await.unwrap_or_else(|_| {
|
||||||
app_data
|
app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::DockerCommand(DockerControls::Unpause))
|
.set_error(AppError::DockerCommand(DockerControls::Unpause));
|
||||||
});
|
});
|
||||||
self.stop_loading_spin(loading_spin);
|
self.stop_loading_spin(&loading_spin);
|
||||||
self.update_everything().await
|
self.update_everything().await;
|
||||||
}
|
}
|
||||||
DockerMessage::Update => self.update_everything().await,
|
DockerMessage::Update => self.update_everything().await,
|
||||||
DockerMessage::Quit => {
|
DockerMessage::Quit => {
|
||||||
@@ -382,7 +379,7 @@ impl DockerData {
|
|||||||
.lock()
|
.lock()
|
||||||
.values()
|
.values()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|i| i.abort());
|
.for_each(tokio::task::JoinHandle::abort);
|
||||||
self.is_running.store(false, Ordering::SeqCst);
|
self.is_running.store(false, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ impl InputHandler {
|
|||||||
// Show the info box - with "mouse capture enabled / disabled", for 4000 ms
|
// Show the info box - with "mouse capture enabled / disabled", for 4000 ms
|
||||||
self.info_sleep = Some(tokio::spawn(async move {
|
self.info_sleep = Some(tokio::spawn(async move {
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(4000)).await;
|
tokio::time::sleep(std::time::Duration::from_millis(4000)).await;
|
||||||
gui_state.lock().reset_info_box()
|
gui_state.lock().reset_info_box();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.mouse_capture = !self.mouse_capture;
|
self.mouse_capture = !self.mouse_capture;
|
||||||
@@ -118,14 +118,14 @@ impl InputHandler {
|
|||||||
|
|
||||||
/// Sort containers based on a given header, switch asc to desc if already sorted, else always desc
|
/// Sort containers based on a given header, switch asc to desc if already sorted, else always desc
|
||||||
fn sort(&self, header: Header) {
|
fn sort(&self, header: Header) {
|
||||||
let mut output = Some((header.to_owned(), SortedOrder::Desc));
|
let mut output = Some((header.clone(), SortedOrder::Desc));
|
||||||
let mut locked_data = self.app_data.lock();
|
let mut locked_data = self.app_data.lock();
|
||||||
if let Some((h, order)) = locked_data.get_sorted().as_ref() {
|
if let Some((h, order)) = locked_data.get_sorted().as_ref() {
|
||||||
if &SortedOrder::Desc == order && h == &header {
|
if &SortedOrder::Desc == order && h == &header {
|
||||||
output = Some((header, SortedOrder::Asc))
|
output = Some((header, SortedOrder::Asc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
locked_data.set_sorted(output)
|
locked_data.set_sorted(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a quit message to docker, to abort all spawns, if error, quit here instead
|
/// Send a quit message to docker, to abort all spawns, if error, quit here instead
|
||||||
@@ -219,13 +219,13 @@ impl InputHandler {
|
|||||||
KeyCode::Up | KeyCode::Char('k') => self.previous(),
|
KeyCode::Up | KeyCode::Char('k') => self.previous(),
|
||||||
KeyCode::PageUp => {
|
KeyCode::PageUp => {
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.previous()
|
self.previous();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Down | KeyCode::Char('j') => self.next(),
|
KeyCode::Down | KeyCode::Char('j') => self.next(),
|
||||||
KeyCode::PageDown => {
|
KeyCode::PageDown => {
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.next()
|
self.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Enter => {
|
KeyCode::Enter => {
|
||||||
|
|||||||
+37
-22
@@ -1,3 +1,13 @@
|
|||||||
|
#![forbid(unsafe_code)]
|
||||||
|
#![warn(clippy::unused_async, clippy::unwrap_used, clippy::expect_used)]
|
||||||
|
// Wanring - These are indeed pedantic
|
||||||
|
// #![warn(clippy::pedantic)]
|
||||||
|
// #![warn(clippy::nursery)]
|
||||||
|
// #![allow(clippy::module_name_repetitions, clippy::doc_markdown)]
|
||||||
|
|
||||||
|
// Only allow when debugging
|
||||||
|
// #![allow(unused)]
|
||||||
|
|
||||||
use app_data::AppData;
|
use app_data::AppData;
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
@@ -35,23 +45,28 @@ async fn main() {
|
|||||||
let (docker_sx, docker_rx) = tokio::sync::mpsc::channel(16);
|
let (docker_sx, docker_rx) = tokio::sync::mpsc::channel(16);
|
||||||
|
|
||||||
// Create docker daemon handler, and only spawn up the docker data handler if ping returns non-error
|
// Create docker daemon handler, and only spawn up the docker data handler if ping returns non-error
|
||||||
let docker = Arc::new(Docker::connect_with_socket_defaults().unwrap());
|
|
||||||
match docker.ping().await {
|
match Docker::connect_with_socket_defaults() {
|
||||||
Ok(_) => {
|
Ok(docker) => {
|
||||||
let docker = Arc::clone(&docker);
|
let docker = Arc::new(docker);
|
||||||
let is_running = Arc::clone(&is_running);
|
match docker.ping().await {
|
||||||
tokio::spawn(DockerData::init(
|
Ok(_) => {
|
||||||
docker_args,
|
let docker = Arc::clone(&docker);
|
||||||
docker_app_data,
|
let is_running = Arc::clone(&is_running);
|
||||||
docker,
|
tokio::spawn(DockerData::init(
|
||||||
docker_gui_state,
|
docker_args,
|
||||||
docker_rx,
|
docker_app_data,
|
||||||
is_running,
|
docker,
|
||||||
));
|
docker_gui_state,
|
||||||
|
docker_rx,
|
||||||
|
is_running,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Err(_) => app_data.lock().set_error(AppError::DockerConnect),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(_) => app_data.lock().set_error(AppError::DockerConnect),
|
Err(_) => app_data.lock().set_error(AppError::DockerConnect),
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_app_data = Arc::clone(&app_data);
|
let input_app_data = Arc::clone(&app_data);
|
||||||
|
|
||||||
let (input_sx, input_rx) = tokio::sync::mpsc::channel(16);
|
let (input_sx, input_rx) = tokio::sync::mpsc::channel(16);
|
||||||
@@ -70,13 +85,8 @@ async fn main() {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Debug mode for testing, mostly pointless, doesn't take terminal nor draw gui
|
// Debug mode for testing, mostly pointless, doesn't take terminal nor draw gui
|
||||||
if !args.gui {
|
if args.gui {
|
||||||
loop {
|
let update_duration = std::time::Duration::from_millis(u64::from(args.docker_interval));
|
||||||
info!("in debug mode");
|
|
||||||
tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let update_duration = std::time::Duration::from_millis(args.docker_interval as u64);
|
|
||||||
create_ui(
|
create_ui(
|
||||||
app_data,
|
app_data,
|
||||||
input_sx,
|
input_sx,
|
||||||
@@ -86,6 +96,11 @@ async fn main() {
|
|||||||
update_duration,
|
update_duration,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(())
|
.unwrap_or(());
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
info!("in debug mode");
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub struct CliArgs {
|
|||||||
impl CliArgs {
|
impl CliArgs {
|
||||||
/// Parse cli arguments
|
/// Parse cli arguments
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let args = CliArgs::parse();
|
let args = Self::parse();
|
||||||
|
|
||||||
// Quit the program if the docker update argument is 0
|
// Quit the program if the docker update argument is 0
|
||||||
// Should maybe change it to check if less than 100
|
// Should maybe change it to check if less than 100
|
||||||
|
|||||||
+9
-11
@@ -7,9 +7,9 @@ pub mod log_sanitizer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Attempt to colorize the given string to tui-rs standars
|
/// Attempt to colorize the given string to tui-rs standars
|
||||||
pub fn colorize_logs(input: String) -> Vec<Spans<'static>> {
|
pub fn colorize_logs(input: &str) -> Vec<Spans<'static>> {
|
||||||
vec![Spans::from(
|
vec![Spans::from(
|
||||||
categorise_text(&input)
|
categorise_text(input)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let fg_color = color_ansi_to_tui(i.fg.unwrap_or(CansiColor::White));
|
let fg_color = color_ansi_to_tui(i.fg.unwrap_or(CansiColor::White));
|
||||||
@@ -24,7 +24,7 @@ pub mod log_sanitizer {
|
|||||||
if i.reversed.is_some() {
|
if i.reversed.is_some() {
|
||||||
style.add_modifier(Modifier::REVERSED);
|
style.add_modifier(Modifier::REVERSED);
|
||||||
}
|
}
|
||||||
if i.intensity == Some(Intensity::Bold) {
|
if i.intensity == Some(Intensity::Bold) {
|
||||||
style.add_modifier(Modifier::BOLD);
|
style.add_modifier(Modifier::BOLD);
|
||||||
}
|
}
|
||||||
if i.hidden.is_some() {
|
if i.hidden.is_some() {
|
||||||
@@ -40,10 +40,10 @@ pub mod log_sanitizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Remove all ansi formatting from a given string and create tui-rs spans
|
/// Remove all ansi formatting from a given string and create tui-rs spans
|
||||||
pub fn remove_ansi(input: String) -> Vec<Spans<'static>> {
|
pub fn remove_ansi(input: &str) -> Vec<Spans<'static>> {
|
||||||
let mut output = String::from("");
|
let mut output = String::from("");
|
||||||
for i in categorise_text(&input) {
|
for i in categorise_text(input) {
|
||||||
output.push_str(i.text)
|
output.push_str(i.text);
|
||||||
}
|
}
|
||||||
raw(output)
|
raw(output)
|
||||||
}
|
}
|
||||||
@@ -54,24 +54,22 @@ pub mod log_sanitizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Change from ansi to tui colors
|
/// Change from ansi to tui colors
|
||||||
fn color_ansi_to_tui(color: CansiColor) -> Color {
|
const fn color_ansi_to_tui(color: CansiColor) -> Color {
|
||||||
match color {
|
match color {
|
||||||
CansiColor::Black => Color::Black,
|
CansiColor::Black | CansiColor::BrightBlack => Color::Black,
|
||||||
CansiColor::Red => Color::Red,
|
CansiColor::Red => Color::Red,
|
||||||
CansiColor::Green => Color::Green,
|
CansiColor::Green => Color::Green,
|
||||||
CansiColor::Yellow => Color::Yellow,
|
CansiColor::Yellow => Color::Yellow,
|
||||||
CansiColor::Blue => Color::Blue,
|
CansiColor::Blue => Color::Blue,
|
||||||
CansiColor::Magenta => Color::Magenta,
|
CansiColor::Magenta => Color::Magenta,
|
||||||
CansiColor::Cyan => Color::Cyan,
|
CansiColor::Cyan => Color::Cyan,
|
||||||
CansiColor::White => Color::White,
|
CansiColor::White | CansiColor::BrightWhite => Color::White,
|
||||||
CansiColor::BrightBlack => Color::Black,
|
|
||||||
CansiColor::BrightRed => Color::LightRed,
|
CansiColor::BrightRed => Color::LightRed,
|
||||||
CansiColor::BrightGreen => Color::LightGreen,
|
CansiColor::BrightGreen => Color::LightGreen,
|
||||||
CansiColor::BrightYellow => Color::LightYellow,
|
CansiColor::BrightYellow => Color::LightYellow,
|
||||||
CansiColor::BrightBlue => Color::LightBlue,
|
CansiColor::BrightBlue => Color::LightBlue,
|
||||||
CansiColor::BrightMagenta => Color::LightMagenta,
|
CansiColor::BrightMagenta => Color::LightMagenta,
|
||||||
CansiColor::BrightCyan => Color::LightCyan,
|
CansiColor::BrightCyan => Color::LightCyan,
|
||||||
CansiColor::BrightWhite => Color::White,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-48
@@ -64,7 +64,7 @@ fn generate_block<'a>(
|
|||||||
SelectablePanel::Logs => {
|
SelectablePanel::Logs => {
|
||||||
format!(" {} {} ", panel.title(), app_data.lock().get_log_title())
|
format!(" {} {} ", panel.title(), app_data.lock().get_log_title())
|
||||||
}
|
}
|
||||||
_ => String::from(""),
|
SelectablePanel::Commands => String::from(""),
|
||||||
};
|
};
|
||||||
block = block.title(title);
|
block = block.title(title);
|
||||||
if current_selected_panel == panel {
|
if current_selected_panel == panel {
|
||||||
@@ -74,7 +74,7 @@ fn generate_block<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the command panel
|
/// Draw the command panel
|
||||||
pub fn draw_commands<B: Backend>(
|
pub fn commands<B: Backend>(
|
||||||
app_data: &Arc<Mutex<AppData>>,
|
app_data: &Arc<Mutex<AppData>>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
f: &mut Frame<'_, B>,
|
f: &mut Frame<'_, B>,
|
||||||
@@ -111,12 +111,12 @@ pub fn draw_commands<B: Backend>(
|
|||||||
let paragraph = Paragraph::new(debug_text)
|
let paragraph = Paragraph::new(debug_text)
|
||||||
.block(block)
|
.block(block)
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
f.render_widget(paragraph, area)
|
f.render_widget(paragraph, area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the containers panel
|
/// Draw the containers panel
|
||||||
pub fn draw_containers<B: Backend>(
|
pub fn containers<B: Backend>(
|
||||||
app_data: &Arc<Mutex<AppData>>,
|
app_data: &Arc<Mutex<AppData>>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
f: &mut Frame<'_, B>,
|
f: &mut Frame<'_, B>,
|
||||||
@@ -196,7 +196,7 @@ pub fn draw_containers<B: Backend>(
|
|||||||
let paragraph = Paragraph::new(debug_text)
|
let paragraph = Paragraph::new(debug_text)
|
||||||
.block(block)
|
.block(block)
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
f.render_widget(paragraph, area)
|
f.render_widget(paragraph, area);
|
||||||
} else {
|
} else {
|
||||||
let items = List::new(items)
|
let items = List::new(items)
|
||||||
.block(block)
|
.block(block)
|
||||||
@@ -208,13 +208,13 @@ pub fn draw_containers<B: Backend>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the logs panel
|
/// Draw the logs panel
|
||||||
pub fn draw_logs<B: Backend>(
|
pub fn logs<B: Backend>(
|
||||||
app_data: &Arc<Mutex<AppData>>,
|
app_data: &Arc<Mutex<AppData>>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
f: &mut Frame<'_, B>,
|
f: &mut Frame<'_, B>,
|
||||||
gui_state: &Arc<Mutex<GuiState>>,
|
gui_state: &Arc<Mutex<GuiState>>,
|
||||||
index: Option<usize>,
|
index: Option<usize>,
|
||||||
loading_icon: String,
|
loading_icon: &str,
|
||||||
) {
|
) {
|
||||||
let block = generate_block(app_data, area, gui_state, SelectablePanel::Logs);
|
let block = generate_block(app_data, area, gui_state, SelectablePanel::Logs);
|
||||||
|
|
||||||
@@ -225,14 +225,14 @@ pub fn draw_logs<B: Backend>(
|
|||||||
.style(Style::default())
|
.style(Style::default())
|
||||||
.block(block)
|
.block(block)
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
f.render_widget(paragraph, area)
|
f.render_widget(paragraph, area);
|
||||||
} else if let Some(index) = index {
|
} else if let Some(index) = index {
|
||||||
let items = app_data.lock().containers.items[index]
|
let items = app_data.lock().containers.items[index]
|
||||||
.logs
|
.logs
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|i| i.1.to_owned())
|
.map(|i| i.1.clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let items = List::new(items)
|
let items = List::new(items)
|
||||||
@@ -249,12 +249,12 @@ pub fn draw_logs<B: Backend>(
|
|||||||
let paragraph = Paragraph::new(debug_text)
|
let paragraph = Paragraph::new(debug_text)
|
||||||
.block(block)
|
.block(block)
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
f.render_widget(paragraph, area)
|
f.render_widget(paragraph, area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the cpu + mem charts
|
/// Draw the cpu + mem charts
|
||||||
pub fn draw_chart<B: Backend>(
|
pub fn chart<B: Backend>(
|
||||||
f: &mut Frame<'_, B>,
|
f: &mut Frame<'_, B>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
app_data: &Arc<Mutex<AppData>>,
|
app_data: &Arc<Mutex<AppData>>,
|
||||||
@@ -279,20 +279,10 @@ pub fn draw_chart<B: Backend>(
|
|||||||
.style(Style::default().fg(Color::Cyan))
|
.style(Style::default().fg(Color::Cyan))
|
||||||
.graph_type(GraphType::Line)
|
.graph_type(GraphType::Line)
|
||||||
.data(&mem.0)];
|
.data(&mem.0)];
|
||||||
let cpu_chart = make_chart(
|
let cpu_stats = CpuStats::new(cpu.0.last().unwrap_or(&(0.00, 0.00)).1);
|
||||||
cpu.2,
|
let mem_stats = ByteStats::new(mem.0.last().unwrap_or(&(0.0, 0.0)).1 as u64);
|
||||||
String::from("cpu"),
|
let cpu_chart = make_chart(&cpu.2, "cpu", cpu_dataset, &cpu_stats, &cpu.1);
|
||||||
cpu_dataset,
|
let mem_chart = make_chart(&mem.2, "memory", mem_dataset, &mem_stats, &mem.1);
|
||||||
CpuStats::new(cpu.0.last().unwrap_or(&(0.00, 0.00)).1),
|
|
||||||
cpu.1,
|
|
||||||
);
|
|
||||||
let mem_chart = make_chart(
|
|
||||||
mem.2,
|
|
||||||
String::from("memory"),
|
|
||||||
mem_dataset,
|
|
||||||
ByteStats::new(mem.0.last().unwrap_or(&(0.0, 0.0)).1 as u64),
|
|
||||||
mem.1,
|
|
||||||
);
|
|
||||||
|
|
||||||
f.render_widget(cpu_chart, area[0]);
|
f.render_widget(cpu_chart, area[0]);
|
||||||
f.render_widget(mem_chart, area[1]);
|
f.render_widget(mem_chart, area[1]);
|
||||||
@@ -301,13 +291,13 @@ pub fn draw_chart<B: Backend>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create charts
|
/// Create charts
|
||||||
fn make_chart<T: Stats + Display>(
|
fn make_chart<'a, T: Stats + Display>(
|
||||||
state: State,
|
state: &State,
|
||||||
name: String,
|
name: &'a str,
|
||||||
dataset: Vec<Dataset>,
|
dataset: Vec<Dataset<'a>>,
|
||||||
current: T,
|
current: &'a T,
|
||||||
max: T,
|
max: &'a T,
|
||||||
) -> Chart {
|
) -> Chart<'a> {
|
||||||
let title_color = match state {
|
let title_color = match state {
|
||||||
State::Running => Color::Green,
|
State::Running => Color::Green,
|
||||||
_ => state.get_color(),
|
_ => state.get_color(),
|
||||||
@@ -351,13 +341,13 @@ fn make_chart<T: Stats + Display>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw heading bar at top of program, always visible
|
/// Draw heading bar at top of program, always visible
|
||||||
pub fn draw_heading_bar<B: Backend>(
|
pub fn heading_bar<B: Backend>(
|
||||||
area: Rect,
|
area: Rect,
|
||||||
columns: &Columns,
|
columns: &Columns,
|
||||||
f: &mut Frame<'_, B>,
|
f: &mut Frame<'_, B>,
|
||||||
has_containers: bool,
|
has_containers: bool,
|
||||||
loading_icon: String,
|
loading_icon: &str,
|
||||||
sorted_by: Option<(Header, SortedOrder)>,
|
sorted_by: &Option<(Header, SortedOrder)>,
|
||||||
gui_state: &Arc<Mutex<GuiState>>,
|
gui_state: &Arc<Mutex<GuiState>>,
|
||||||
) {
|
) {
|
||||||
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));
|
||||||
@@ -377,7 +367,7 @@ pub fn draw_heading_bar<B: Backend>(
|
|||||||
SortedOrder::Desc => suffix = " ⌄",
|
SortedOrder::Desc => suffix = " ⌄",
|
||||||
}
|
}
|
||||||
suffix_margin = 2;
|
suffix_margin = 2;
|
||||||
color = Color::White
|
color = Color::White;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
(
|
(
|
||||||
@@ -439,11 +429,7 @@ pub fn draw_heading_bar<B: Backend>(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let header_block = gen_header(&i.0, i.1);
|
let header_block = gen_header(&i.0, i.1);
|
||||||
(
|
(header_block.0, i.0.clone(), Constraint::Max(header_block.1))
|
||||||
header_block.0,
|
|
||||||
i.0.to_owned(),
|
|
||||||
Constraint::Max(header_block.1),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -500,7 +486,7 @@ fn max_line_width(text: &str) -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the help box in the centre of the screen
|
/// Draw the help box in the centre of the screen
|
||||||
pub fn draw_help_box<B: Backend>(f: &mut Frame<'_, B>) {
|
pub fn help_box<B: Backend>(f: &mut Frame<'_, B>) {
|
||||||
let title = format!(" {} ", VERSION);
|
let title = format!(" {} ", VERSION);
|
||||||
|
|
||||||
let description_text = format!("\n{}", DESCRIPTION);
|
let description_text = format!("\n{}", DESCRIPTION);
|
||||||
@@ -550,7 +536,7 @@ pub fn draw_help_box<B: Backend>(f: &mut Frame<'_, B>) {
|
|||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
.border_style(Style::default().fg(Color::Black));
|
.border_style(Style::default().fg(Color::Black));
|
||||||
|
|
||||||
let area = draw_popup(
|
let area = popup(
|
||||||
lines as u16,
|
lines as u16,
|
||||||
max_line_width as u16,
|
max_line_width as u16,
|
||||||
f.size(),
|
f.size(),
|
||||||
@@ -578,7 +564,7 @@ pub fn draw_help_box<B: Backend>(f: &mut Frame<'_, B>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw an error popup over whole screen
|
/// Draw an error popup over whole screen
|
||||||
pub fn draw_error<B: Backend>(f: &mut Frame<'_, B>, error: AppError, seconds: Option<u8>) {
|
pub fn error<B: Backend>(f: &mut Frame<'_, B>, error: &AppError, seconds: Option<u8>) {
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.title(" Error ")
|
.title(" Error ")
|
||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
@@ -614,7 +600,7 @@ pub fn draw_error<B: Backend>(f: &mut Frame<'_, B>, error: AppError, seconds: Op
|
|||||||
.block(block)
|
.block(block)
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
|
|
||||||
let area = draw_popup(
|
let area = popup(
|
||||||
lines as u16,
|
lines as u16,
|
||||||
max_line_width as u16,
|
max_line_width as u16,
|
||||||
f.size(),
|
f.size(),
|
||||||
@@ -625,7 +611,7 @@ pub fn draw_error<B: Backend>(f: &mut Frame<'_, B>, error: AppError, seconds: Op
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Draw info box in one of the 9 BoxLocations
|
/// Draw info box in one of the 9 BoxLocations
|
||||||
pub fn draw_info<B: Backend>(f: &mut Frame<'_, B>, text: String) {
|
pub fn info<B: Backend>(f: &mut Frame<'_, B>, text: String) {
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.title("")
|
.title("")
|
||||||
.title_alignment(Alignment::Center)
|
.title_alignment(Alignment::Center)
|
||||||
@@ -643,7 +629,7 @@ pub fn draw_info<B: Backend>(f: &mut Frame<'_, B>, text: String) {
|
|||||||
.block(block)
|
.block(block)
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
|
|
||||||
let area = draw_popup(
|
let area = popup(
|
||||||
lines as u16,
|
lines as u16,
|
||||||
max_line_width as u16,
|
max_line_width as u16,
|
||||||
f.size(),
|
f.size(),
|
||||||
@@ -654,7 +640,7 @@ pub fn draw_info<B: Backend>(f: &mut Frame<'_, B>, text: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// draw a box in the one of the BoxLocations, based on max line width + number of lines
|
/// draw a box in the one of the BoxLocations, based on max line width + number of lines
|
||||||
fn draw_popup(text_lines: u16, text_width: u16, r: Rect, box_location: BoxLocation) -> Rect {
|
fn 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
|
// Make sure blank_space can't be an negative, as will crash
|
||||||
let blank_vertical = if r.height > text_lines {
|
let blank_vertical = if r.height > text_lines {
|
||||||
(r.height - text_lines) / 2
|
(r.height - text_lines) / 2
|
||||||
|
|||||||
+11
-11
@@ -30,7 +30,7 @@ pub enum BoxLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BoxLocation {
|
impl BoxLocation {
|
||||||
pub fn get_indexes(&self) -> (usize, usize) {
|
pub const fn get_indexes(self) -> (usize, usize) {
|
||||||
match self {
|
match self {
|
||||||
Self::TopLeft => (0, 0),
|
Self::TopLeft => (0, 0),
|
||||||
Self::TopCentre => (0, 1),
|
Self::TopCentre => (0, 1),
|
||||||
@@ -45,8 +45,8 @@ impl BoxLocation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should combine and just return a tuple?
|
// Should combine and just return a tuple?
|
||||||
pub fn get_horizontal_constraints(
|
pub const fn get_horizontal_constraints(
|
||||||
&self,
|
self,
|
||||||
blank_vertical: u16,
|
blank_vertical: u16,
|
||||||
text_width: u16,
|
text_width: u16,
|
||||||
) -> [Constraint; 3] {
|
) -> [Constraint; 3] {
|
||||||
@@ -68,8 +68,8 @@ impl BoxLocation {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_vertical_constraints(
|
pub const fn get_vertical_constraints(
|
||||||
&self,
|
self,
|
||||||
blank_vertical: u16,
|
blank_vertical: u16,
|
||||||
number_lines: u16,
|
number_lines: u16,
|
||||||
) -> [Constraint; 3] {
|
) -> [Constraint; 3] {
|
||||||
@@ -108,7 +108,7 @@ pub enum Loading {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Loading {
|
impl Loading {
|
||||||
pub fn next(&self) -> Self {
|
pub const fn next(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::One => Self::Two,
|
Self::One => Self::Two,
|
||||||
Self::Two => Self::Three,
|
Self::Two => Self::Three,
|
||||||
@@ -143,21 +143,21 @@ impl fmt::Display for Loading {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SelectablePanel {
|
impl SelectablePanel {
|
||||||
pub fn title(self) -> &'static str {
|
pub const fn title(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Containers => "Containers",
|
Self::Containers => "Containers",
|
||||||
Self::Logs => "Logs",
|
Self::Logs => "Logs",
|
||||||
_ => "",
|
Self::Commands => "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn next(self) -> Self {
|
pub const fn next(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Containers => Self::Commands,
|
Self::Containers => Self::Commands,
|
||||||
Self::Commands => Self::Logs,
|
Self::Commands => Self::Logs,
|
||||||
Self::Logs => Self::Containers,
|
Self::Logs => Self::Containers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn prev(self) -> Self {
|
pub const fn prev(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Containers => Self::Logs,
|
Self::Containers => Self::Logs,
|
||||||
Self::Commands => Self::Containers,
|
Self::Commands => Self::Containers,
|
||||||
@@ -221,7 +221,7 @@ impl GuiState {
|
|||||||
.filter(|i| i.1.intersects(rect))
|
.filter(|i| i.1.intersects(rect))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.get(0)
|
.get(0)
|
||||||
.map(|data| data.0.to_owned())
|
.map(|data| data.0.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert, or updatem header area panel into heading_map
|
/// Insert, or updatem header area panel into heading_map
|
||||||
|
|||||||
+26
-22
@@ -30,7 +30,6 @@ use crate::{
|
|||||||
app_data::AppData, app_error::AppError, docker_data::DockerMessage,
|
app_data::AppData, app_error::AppError, docker_data::DockerMessage,
|
||||||
input_handler::InputMessages,
|
input_handler::InputMessages,
|
||||||
};
|
};
|
||||||
use draw_blocks::*;
|
|
||||||
|
|
||||||
/// Take control of the terminal in order to draw gui
|
/// Take control of the terminal in order to draw gui
|
||||||
pub async fn create_ui(
|
pub async fn create_ui(
|
||||||
@@ -73,7 +72,7 @@ pub async fn create_ui(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Run a loop to draw the gui
|
/// Run a loop to draw the gui
|
||||||
async fn run_app<B: Backend>(
|
async fn run_app<B: Backend + Send>(
|
||||||
terminal: &mut Terminal<B>,
|
terminal: &mut Terminal<B>,
|
||||||
app_data: Arc<Mutex<AppData>>,
|
app_data: Arc<Mutex<AppData>>,
|
||||||
sender: Sender<InputMessages>,
|
sender: Sender<InputMessages>,
|
||||||
@@ -94,9 +93,12 @@ async fn run_app<B: Backend>(
|
|||||||
is_running.store(false, Ordering::SeqCst);
|
is_running.store(false, Ordering::SeqCst);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
terminal
|
if terminal
|
||||||
.draw(|f| draw_error(f, AppError::DockerConnect, Some(seconds)))
|
.draw(|f| draw_blocks::error(f, &AppError::DockerConnect, Some(seconds)))
|
||||||
.unwrap();
|
.is_err()
|
||||||
|
{
|
||||||
|
return Err(AppError::Terminal);
|
||||||
|
}
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
seconds -= 1;
|
seconds -= 1;
|
||||||
}
|
}
|
||||||
@@ -104,7 +106,9 @@ async fn run_app<B: Backend>(
|
|||||||
} else {
|
} else {
|
||||||
let mut now = Instant::now();
|
let mut now = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
terminal.draw(|f| ui(f, &app_data, &gui_state)).unwrap();
|
if terminal.draw(|f| ui(f, &app_data, &gui_state)).is_err() {
|
||||||
|
return Err(AppError::Terminal);
|
||||||
|
}
|
||||||
if crossterm::event::poll(input_poll_rate).unwrap_or_default() {
|
if crossterm::event::poll(input_poll_rate).unwrap_or_default() {
|
||||||
if let Ok(event) = event::read() {
|
if let Ok(event) = event::read() {
|
||||||
if let Event::Key(key) = event {
|
if let Event::Key(key) = event {
|
||||||
@@ -143,12 +147,12 @@ fn ui<B: Backend>(
|
|||||||
gui_state: &Arc<Mutex<GuiState>>,
|
gui_state: &Arc<Mutex<GuiState>>,
|
||||||
) {
|
) {
|
||||||
// set max height for container section, needs +4 to deal with docker commands list and borders
|
// set max height for container section, needs +4 to deal with docker commands list and borders
|
||||||
let mut height = app_data.lock().get_container_len();
|
let height = app_data.lock().get_container_len();
|
||||||
if height < 12 {
|
let height = if height < 12 {
|
||||||
height += 4;
|
(height + 4) as u16
|
||||||
} else {
|
} else {
|
||||||
height = 12
|
12
|
||||||
}
|
};
|
||||||
|
|
||||||
let column_widths = app_data.lock().get_width();
|
let column_widths = app_data.lock().get_width();
|
||||||
let has_containers = !app_data.lock().containers.items.is_empty();
|
let has_containers = !app_data.lock().containers.items.is_empty();
|
||||||
@@ -194,47 +198,47 @@ fn ui<B: Backend>(
|
|||||||
.constraints(lower_split.as_ref())
|
.constraints(lower_split.as_ref())
|
||||||
.split(upper_main[1]);
|
.split(upper_main[1]);
|
||||||
|
|
||||||
draw_containers(app_data, top_panel[0], f, gui_state, &column_widths);
|
draw_blocks::containers(app_data, top_panel[0], f, gui_state, &column_widths);
|
||||||
|
|
||||||
if has_containers {
|
if has_containers {
|
||||||
draw_commands(app_data, top_panel[1], f, gui_state, log_index);
|
draw_blocks::commands(app_data, top_panel[1], f, gui_state, log_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_logs(
|
draw_blocks::logs(
|
||||||
app_data,
|
app_data,
|
||||||
lower_main[0],
|
lower_main[0],
|
||||||
f,
|
f,
|
||||||
gui_state,
|
gui_state,
|
||||||
log_index,
|
log_index,
|
||||||
loading_icon.to_owned(),
|
&loading_icon,
|
||||||
);
|
);
|
||||||
|
|
||||||
draw_heading_bar(
|
draw_blocks::heading_bar(
|
||||||
whole_layout[0],
|
whole_layout[0],
|
||||||
&column_widths,
|
&column_widths,
|
||||||
f,
|
f,
|
||||||
has_containers,
|
has_containers,
|
||||||
loading_icon,
|
&loading_icon,
|
||||||
sorted_by,
|
&sorted_by,
|
||||||
gui_state,
|
gui_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
// only draw charts if there are containers
|
// only draw charts if there are containers
|
||||||
if has_containers {
|
if has_containers {
|
||||||
draw_chart(f, lower_main[1], app_data, log_index);
|
draw_blocks::chart(f, lower_main[1], app_data, log_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(info) = info_text {
|
if let Some(info) = info_text {
|
||||||
draw_info(f, info);
|
draw_blocks::info(f, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if error, and show popup if so
|
// Check if error, and show popup if so
|
||||||
if show_help {
|
if show_help {
|
||||||
draw_help_box(f);
|
draw_blocks::help_box(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(error) = has_error {
|
if let Some(error) = has_error {
|
||||||
app_data.lock().show_error = true;
|
app_data.lock().show_error = true;
|
||||||
draw_error(f, error, None);
|
draw_blocks::error(f, &error, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user