feat: horizontally scroll across log
By default, use left and right arrow keys to horizontally scroll over the lines of logs, also has various refactors to reduced to size of the vec of logs sent to the ui renderer
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
/target
|
/target
|
||||||
/releases
|
/releases
|
||||||
|
/binaries
|
||||||
# Used in the zigbuild for aarch64-apple-darwin
|
# Used in the zigbuild for aarch64-apple-darwin
|
||||||
.intentionally-empty-file.o
|
.intentionally-empty-file.o
|
||||||
@@ -100,6 +100,13 @@
|
|||||||
"up",
|
"up",
|
||||||
"k"
|
"k"
|
||||||
],
|
],
|
||||||
|
// Horizontal scroll of the logs
|
||||||
|
"log_scroll_forward": [
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
"log_scroll_back": [
|
||||||
|
"left"
|
||||||
|
],
|
||||||
// Select next panel
|
// Select next panel
|
||||||
"select_next_panel": [
|
"select_next_panel": [
|
||||||
"tab"
|
"tab"
|
||||||
|
|||||||
@@ -86,6 +86,9 @@ scroll_start = ["home"]
|
|||||||
scroll_up_many = ["pageup"]
|
scroll_up_many = ["pageup"]
|
||||||
# scroll up a list by one item
|
# scroll up a list by one item
|
||||||
scroll_up_one = ["up", "k"]
|
scroll_up_one = ["up", "k"]
|
||||||
|
# Horizontal scroll of the logs
|
||||||
|
log_scroll_forward = ["right"]
|
||||||
|
log_scroll_back = ["left"]
|
||||||
# Select next panel
|
# Select next panel
|
||||||
select_next_panel = ["tab"]
|
select_next_panel = ["tab"]
|
||||||
# Select previous panel
|
# Select previous panel
|
||||||
|
|||||||
+160
-40
@@ -7,10 +7,7 @@ use std::{
|
|||||||
|
|
||||||
use bollard::service::Port;
|
use bollard::service::Port;
|
||||||
use jiff::{Timestamp, tz::TimeZone};
|
use jiff::{Timestamp, tz::TimeZone};
|
||||||
use ratatui::{
|
use ratatui::{layout::Size, style::Color, text::Text, widgets::ListState};
|
||||||
style::Color,
|
|
||||||
widgets::{ListItem, ListState},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::config::AppColors;
|
use crate::config::AppColors;
|
||||||
|
|
||||||
@@ -563,81 +560,166 @@ impl LogsTz {
|
|||||||
/// stateful list dependent on whether the timestamp is in the HashSet or not
|
/// stateful list dependent on whether the timestamp is in the HashSet or not
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Logs {
|
pub struct Logs {
|
||||||
logs: StatefulList<ListItem<'static>>,
|
// should just be list of spans?
|
||||||
|
lines: StatefulList<Text<'static>>,
|
||||||
tz: HashSet<LogsTz>,
|
tz: HashSet<LogsTz>,
|
||||||
|
// could probably be a u16
|
||||||
|
offset: u16,
|
||||||
|
max_log_len: usize,
|
||||||
|
adjusted_max_width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Logs {
|
impl Default for Logs {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut logs = StatefulList::new(vec![]);
|
let mut lines = StatefulList::new(vec![]);
|
||||||
logs.end();
|
lines.end();
|
||||||
Self {
|
Self {
|
||||||
logs,
|
lines,
|
||||||
tz: HashSet::new(),
|
tz: HashSet::new(),
|
||||||
|
offset: 0,
|
||||||
|
adjusted_max_width: 0,
|
||||||
|
max_log_len: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Logs {
|
impl Logs {
|
||||||
/// Only allow a new log line to be inserted if the log timestamp isn't in the tz HashSet
|
/// Only allow a new log line to be inserted if the log timestamp isn't in the tz HashSet
|
||||||
pub fn insert(&mut self, line: ListItem<'static>, tz: LogsTz) {
|
pub fn insert(&mut self, line: Text<'static>, tz: LogsTz) {
|
||||||
if self.tz.insert(tz) {
|
if self.tz.insert(tz) {
|
||||||
self.logs.items.push(line);
|
self.max_log_len = self.max_log_len.max(line.width());
|
||||||
|
self.lines.items.push(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the logs vec, but instead of cloning to whole vec, only clone items with x of the currently selected index
|
/// If scrolling horiztonally along the logs, display a counter of the position in the in the scroll, `x/y`
|
||||||
|
pub fn get_scroll_title(&self) -> Option<String> {
|
||||||
|
if self.offset > 0 {
|
||||||
|
Some(format!(" {}/{} ", self.offset, self.adjusted_max_width))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format a log lone. Only return screen width amount of chars
|
||||||
|
/// If offset set, remove `char_offset` number of chars from a Text
|
||||||
|
/// `text` *should* only be a single line, so just use the .first() method rather than trying to iterate
|
||||||
|
fn format_log_line(text: &Text<'static>, char_offset: usize, width: u16) -> Text<'static> {
|
||||||
|
let mut skipped = 0;
|
||||||
|
Text::from(
|
||||||
|
text.lines
|
||||||
|
.first()
|
||||||
|
.map(|line| {
|
||||||
|
ratatui::text::Line::from(
|
||||||
|
line.spans
|
||||||
|
.iter()
|
||||||
|
.filter_map(|span| {
|
||||||
|
if skipped >= char_offset {
|
||||||
|
return Some(ratatui::text::Span::styled(
|
||||||
|
span.content.chars().take(width.into()).collect::<String>(),
|
||||||
|
span.style,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let span_len = span.content.chars().count();
|
||||||
|
if skipped + span_len <= char_offset {
|
||||||
|
skipped += span_len;
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let start_index = char_offset - skipped;
|
||||||
|
skipped = char_offset;
|
||||||
|
let new_content = span
|
||||||
|
.content
|
||||||
|
.chars()
|
||||||
|
.skip(start_index)
|
||||||
|
.take(width.into())
|
||||||
|
.collect::<String>();
|
||||||
|
Some(ratatui::text::Span::styled(new_content, span.style))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the logs vec, but instead of cloning to whole vec, only clone items within x of the currently selected index, as ell as only the current screen widths number of chars
|
||||||
/// Where x is the abs different of the index plus the panel height & a padding
|
/// Where x is the abs different of the index plus the panel height & a padding
|
||||||
|
/// Take into account the char offset, so that can scroll a line
|
||||||
/// The rest can be just empty list items
|
/// The rest can be just empty list items
|
||||||
pub fn to_vec(&self, height: usize, padding: usize) -> Vec<ListItem<'static>> {
|
pub fn get_visible_logs(&self, size: Size, padding: usize) -> Vec<Text<'static>> {
|
||||||
let current_index = self.logs.state.selected().unwrap_or_default();
|
let current_index = self.lines.state.selected().unwrap_or_default();
|
||||||
self.logs
|
let height_padding = usize::from(size.height) + padding;
|
||||||
|
let char_offset = if usize::from(self.offset) > self.max_log_len {
|
||||||
|
self.max_log_len
|
||||||
|
} else {
|
||||||
|
self.offset.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.lines
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, item)| {
|
.map(|(index, item)| {
|
||||||
if current_index.abs_diff(index) <= height + padding {
|
if current_index.abs_diff(index) <= height_padding {
|
||||||
item.clone()
|
Self::format_log_line(item, char_offset, size.width)
|
||||||
} else {
|
} else {
|
||||||
ListItem::from("")
|
Text::from("")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The rest of the methods are basically forwarding from the underlying StatefulList
|
/// The rest of the methods are basically forwarding from the underlying StatefulList
|
||||||
pub fn get_state_title(&self) -> String {
|
pub fn get_state_title(&self) -> String {
|
||||||
self.logs.get_state_title()
|
self.lines.get_state_title()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a padding so one char will always be visilbe?
|
||||||
|
/// +6 is to account for borders & the selection triangle and a little bit of padding
|
||||||
|
pub fn forward(&mut self, width: u16) {
|
||||||
|
let offset = usize::from(self.offset);
|
||||||
|
self.adjusted_max_width = self.max_log_len.saturating_sub(width.into()) + 6;
|
||||||
|
if self.adjusted_max_width > 0 && offset < self.adjusted_max_width {
|
||||||
|
self.offset = self.offset.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reduce the char offset
|
||||||
|
pub const fn back(&mut self) {
|
||||||
|
self.offset = self.offset.saturating_sub(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) {
|
||||||
self.logs.next();
|
self.lines.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn previous(&mut self) {
|
pub fn previous(&mut self) {
|
||||||
self.logs.previous();
|
self.lines.previous();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end(&mut self) {
|
pub fn end(&mut self) {
|
||||||
self.logs.end();
|
self.lines.end();
|
||||||
}
|
}
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.logs.start();
|
self.lines.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove this once zigbuild uses Rust v1.87.0
|
// // TODO remove this once zigbuild uses Rust v1.87.0
|
||||||
#[cfg(target_os = "macos")]
|
// #[cfg(target_os = "macos")]
|
||||||
#[allow(clippy::missing_const_for_fn)]
|
// #[allow(clippy::missing_const_for_fn)]
|
||||||
pub fn len(&self) -> usize {
|
// pub fn len(&self) -> usize {
|
||||||
self.logs.items.len()
|
// self.logs.items.len()
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
// #[cfg(not(target_os = "macos"))]
|
||||||
pub const fn len(&self) -> usize {
|
pub const fn len(&self) -> usize {
|
||||||
self.logs.items.len()
|
self.lines.items.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn state(&mut self) -> &mut ListState {
|
pub const fn state(&mut self) -> &mut ListState {
|
||||||
&mut self.logs.state
|
&mut self.lines.state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,7 +883,10 @@ impl Columns {
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use jiff::tz::TimeZone;
|
use jiff::tz::TimeZone;
|
||||||
use ratatui::widgets::ListItem;
|
use ratatui::{
|
||||||
|
layout::Size,
|
||||||
|
text::{Line, Text},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_data::{ContainerImage, Logs, LogsTz, RunningState},
|
app_data::{ContainerImage, Logs, LogsTz, RunningState},
|
||||||
@@ -941,21 +1026,21 @@ mod tests {
|
|||||||
let mut logs = Logs::default();
|
let mut logs = Logs::default();
|
||||||
let line = log_sanitizer::remove_ansi(input);
|
let line = log_sanitizer::remove_ansi(input);
|
||||||
|
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line), tz);
|
logs.insert(Text::from(line), tz);
|
||||||
|
|
||||||
assert_eq!(logs.logs.items.len(), 1);
|
assert_eq!(logs.lines.items.len(), 1);
|
||||||
|
|
||||||
let input = "2023-01-15T19:13:30.783138328Z Lorem ipsum dolor sit amet";
|
let input = "2023-01-15T19:13:30.783138328Z Lorem ipsum dolor sit amet";
|
||||||
let (tz, _) = LogsTz::splitter(input);
|
let (tz, _) = LogsTz::splitter(input);
|
||||||
let line = log_sanitizer::remove_ansi(input);
|
let line = log_sanitizer::remove_ansi(input);
|
||||||
|
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line), tz);
|
logs.insert(Text::from(line), tz);
|
||||||
|
|
||||||
assert_eq!(logs.logs.items.len(), 2);
|
assert_eq!(logs.lines.items.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1008,4 +1093,39 @@ mod tests {
|
|||||||
let input = State::from(("oxker", &healthy));
|
let input = State::from(("oxker", &healthy));
|
||||||
assert_eq!(input, State::Unknown);
|
assert_eq!(input, State::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Test the format_log_line methods, should ideally check colours are being correct kept as well
|
||||||
|
fn test_to_vec() {
|
||||||
|
let mut logs = Logs::default();
|
||||||
|
|
||||||
|
let input = "2023-01-14T19:13:30.783138328Z Hello world some long line".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
let input = "2023-01-14T19:13:31.783138328Z Hello world some line".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
let input = "2023-01-14T19:13:32.783138328Z Hello world".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
logs.offset = 43;
|
||||||
|
let result = logs.get_visible_logs(
|
||||||
|
Size {
|
||||||
|
width: 14,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
Text::from(Line::from("some long line")),
|
||||||
|
Text::from(Line::from("some line")),
|
||||||
|
Text::from(Line::default())
|
||||||
|
],
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-19
@@ -1,7 +1,7 @@
|
|||||||
use bollard::models::ContainerSummary;
|
use bollard::models::ContainerSummary;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use ratatui::widgets::{ListItem, ListState};
|
use ratatui::{layout::Size, text::Text, widgets::ListState};
|
||||||
use std::{
|
use std::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@@ -644,6 +644,28 @@ impl AppData {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If scrolling horiztonally along the logs, display a counter of the position in the in the scroll, `x/y`
|
||||||
|
pub fn get_scroll_title(&self) -> Option<String> {
|
||||||
|
self.get_selected_container()
|
||||||
|
.and_then(|i| i.logs.get_scroll_title())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase the logs offset, basically moving an invisible cursor back
|
||||||
|
pub fn log_back(&mut self) {
|
||||||
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
|
i.logs.back();
|
||||||
|
self.redraw.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase the logs offset, basically moving an invisible cursor forward
|
||||||
|
pub fn log_forward(&mut self, width: u16) {
|
||||||
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
|
i.logs.forward(width);
|
||||||
|
self.redraw.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
@@ -677,12 +699,12 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get mutable Vec of current containers logs
|
/// Get mutable Vec of current containers logs
|
||||||
pub fn get_logs(&self, height: u16, padding: usize) -> Vec<ListItem<'static>> {
|
pub fn get_logs(&self, size: Size, padding: usize) -> Vec<Text<'static>> {
|
||||||
self.containers
|
self.containers
|
||||||
.state
|
.state
|
||||||
.selected()
|
.selected()
|
||||||
.and_then(|i| self.containers.items.get(i))
|
.and_then(|i| self.containers.items.get(i))
|
||||||
.map_or(vec![], |i| i.logs.to_vec(height.into(), padding))
|
.map_or(vec![], |i| i.logs.get_visible_logs(size, padding))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get mutable Option of the currently selected container Logs state
|
/// Get mutable Option of the currently selected container Logs state
|
||||||
@@ -965,7 +987,7 @@ impl AppData {
|
|||||||
} else {
|
} else {
|
||||||
log_sanitizer::remove_ansi(&i)
|
log_sanitizer::remove_ansi(&i)
|
||||||
};
|
};
|
||||||
container.logs.insert(ListItem::new(lines), log_tz);
|
container.logs.insert(Text::from(lines), log_tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the logs selected row for each container
|
// Set the logs selected row for each container
|
||||||
@@ -1945,14 +1967,19 @@ mod tests {
|
|||||||
let logs = (1..=3).map(|i| format!("{i} {i}")).collect::<Vec<_>>();
|
let logs = (1..=3).map(|i| format!("{i} {i}")).collect::<Vec<_>>();
|
||||||
|
|
||||||
app_data.update_log_by_id(logs, &ids[0]);
|
app_data.update_log_by_id(logs, &ids[0]);
|
||||||
// app_data.log_start();
|
|
||||||
|
|
||||||
let result = app_data.get_log_state();
|
let result = app_data.get_log_state();
|
||||||
assert!(result.is_some());
|
assert!(result.is_some());
|
||||||
assert_eq!(result.as_ref().unwrap().selected(), Some(2));
|
assert_eq!(result.as_ref().unwrap().selected(), Some(2));
|
||||||
assert_eq!(result.unwrap().offset(), 0);
|
assert_eq!(result.unwrap().offset(), 0);
|
||||||
|
|
||||||
let result = app_data.get_logs(4, 1);
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 4,
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
);
|
||||||
assert_eq!(result.len(), 3);
|
assert_eq!(result.len(), 3);
|
||||||
|
|
||||||
let result = app_data.get_log_title();
|
let result = app_data.get_log_title();
|
||||||
@@ -2340,44 +2367,68 @@ mod tests {
|
|||||||
|
|
||||||
app_data.update_log_by_id(logs, &ids[0]);
|
app_data.update_log_by_id(logs, &ids[0]);
|
||||||
|
|
||||||
let result = app_data.get_logs(10, 10);
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if index < 979 {
|
if index < 979 {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = app_data.get_logs(100, 20);
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
|
20,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if index < 879 {
|
if index < 879 {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app_data.log_start();
|
app_data.log_start();
|
||||||
let result = app_data.get_logs(10, 10);
|
|
||||||
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if index > 20 {
|
if index > 20 {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..=500 {
|
for _ in 0..=500 {
|
||||||
app_data.log_next();
|
app_data.log_next();
|
||||||
}
|
}
|
||||||
|
let result = app_data.get_logs(
|
||||||
let result = app_data.get_logs(10, 10);
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if (481..=521).contains(&index) {
|
if (481..=521).contains(&index) {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ save_logs = ["s"]
|
|||||||
scroll_down_many = ["pagedown"]
|
scroll_down_many = ["pagedown"]
|
||||||
# scroll down a list by one item
|
# scroll down a list by one item
|
||||||
scroll_down_one = ["down", "j"]
|
scroll_down_one = ["down", "j"]
|
||||||
|
|
||||||
# scroll down to the end of a list
|
# scroll down to the end of a list
|
||||||
scroll_end = ["end"]
|
scroll_end = ["end"]
|
||||||
# scroll up to the start of a list
|
# scroll up to the start of a list
|
||||||
@@ -85,6 +86,9 @@ scroll_start = ["home"]
|
|||||||
scroll_up_many = ["pageup"]
|
scroll_up_many = ["pageup"]
|
||||||
# scroll up a list by one item
|
# scroll up a list by one item
|
||||||
scroll_up_one = ["up", "k"]
|
scroll_up_one = ["up", "k"]
|
||||||
|
# Horizontal scroll of the logs
|
||||||
|
log_scroll_forward = ["right"]
|
||||||
|
log_scroll_back = ["left"]
|
||||||
# Select next panel
|
# Select next panel
|
||||||
select_next_panel = ["tab"]
|
select_next_panel = ["tab"]
|
||||||
# Select previous panel
|
# Select previous panel
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ optional_config_struct!(
|
|||||||
log_section_height_increase,
|
log_section_height_increase,
|
||||||
log_section_height_decrease,
|
log_section_height_decrease,
|
||||||
log_section_toggle,
|
log_section_toggle,
|
||||||
|
log_scroll_forward,
|
||||||
|
log_scroll_back,
|
||||||
quit,
|
quit,
|
||||||
save_logs,
|
save_logs,
|
||||||
scroll_down_many,
|
scroll_down_many,
|
||||||
@@ -76,6 +78,8 @@ config_struct!(
|
|||||||
log_section_height_increase,
|
log_section_height_increase,
|
||||||
log_section_height_decrease,
|
log_section_height_decrease,
|
||||||
log_section_toggle,
|
log_section_toggle,
|
||||||
|
log_scroll_forward,
|
||||||
|
log_scroll_back,
|
||||||
quit,
|
quit,
|
||||||
save_logs,
|
save_logs,
|
||||||
scroll_down_many,
|
scroll_down_many,
|
||||||
@@ -111,6 +115,8 @@ impl Keymap {
|
|||||||
log_section_height_decrease: (KeyCode::Char('-'), None),
|
log_section_height_decrease: (KeyCode::Char('-'), None),
|
||||||
log_section_height_increase: (KeyCode::Char('='), None),
|
log_section_height_increase: (KeyCode::Char('='), None),
|
||||||
log_section_toggle: (KeyCode::Char('\\'), None),
|
log_section_toggle: (KeyCode::Char('\\'), None),
|
||||||
|
log_scroll_back: (KeyCode::Left, None),
|
||||||
|
log_scroll_forward: (KeyCode::Right, None),
|
||||||
quit: (KeyCode::Char('q'), None),
|
quit: (KeyCode::Char('q'), None),
|
||||||
save_logs: (KeyCode::Char('s'), None),
|
save_logs: (KeyCode::Char('s'), None),
|
||||||
scroll_down_many: (KeyCode::PageDown, None),
|
scroll_down_many: (KeyCode::PageDown, None),
|
||||||
@@ -201,6 +207,12 @@ impl From<Option<ConfigKeymap>> for Keymap {
|
|||||||
update_keymap(ck.scroll_start, &mut keymap.scroll_start, &mut clash);
|
update_keymap(ck.scroll_start, &mut keymap.scroll_start, &mut clash);
|
||||||
update_keymap(ck.scroll_up_many, &mut keymap.scroll_up_many, &mut clash);
|
update_keymap(ck.scroll_up_many, &mut keymap.scroll_up_many, &mut clash);
|
||||||
update_keymap(ck.scroll_up_one, &mut keymap.scroll_up_one, &mut clash);
|
update_keymap(ck.scroll_up_one, &mut keymap.scroll_up_one, &mut clash);
|
||||||
|
update_keymap(
|
||||||
|
ck.log_scroll_forward,
|
||||||
|
&mut keymap.log_scroll_forward,
|
||||||
|
&mut clash,
|
||||||
|
);
|
||||||
|
update_keymap(ck.log_scroll_back, &mut keymap.log_scroll_back, &mut clash);
|
||||||
update_keymap(
|
update_keymap(
|
||||||
ck.select_next_panel,
|
ck.select_next_panel,
|
||||||
&mut keymap.select_next_panel,
|
&mut keymap.select_next_panel,
|
||||||
@@ -366,6 +378,8 @@ mod tests {
|
|||||||
exec: None,
|
exec: None,
|
||||||
log_section_height_decrease: None,
|
log_section_height_decrease: None,
|
||||||
log_section_height_increase: None,
|
log_section_height_increase: None,
|
||||||
|
log_scroll_forward: None,
|
||||||
|
log_scroll_back: None,
|
||||||
filter_mode: None,
|
filter_mode: None,
|
||||||
quit: None,
|
quit: None,
|
||||||
save_logs: None,
|
save_logs: None,
|
||||||
@@ -410,6 +424,8 @@ mod tests {
|
|||||||
filter_mode: gen_v(("i", "j")),
|
filter_mode: gen_v(("i", "j")),
|
||||||
log_section_height_decrease: gen_v(("-", "Z")),
|
log_section_height_decrease: gen_v(("-", "Z")),
|
||||||
log_section_height_increase: gen_v(("=", "X")),
|
log_section_height_increase: gen_v(("=", "X")),
|
||||||
|
log_scroll_forward: gen_v(("right", "R")),
|
||||||
|
log_scroll_back: gen_v(("left", "L")),
|
||||||
log_section_toggle: gen_v(("Y", "W")),
|
log_section_toggle: gen_v(("Y", "W")),
|
||||||
quit: gen_v(("k", "l")),
|
quit: gen_v(("k", "l")),
|
||||||
save_logs: gen_v(("m", "n")),
|
save_logs: gen_v(("m", "n")),
|
||||||
@@ -444,6 +460,8 @@ mod tests {
|
|||||||
log_section_height_decrease: (KeyCode::Char('-'), Some(KeyCode::Char('Z'))),
|
log_section_height_decrease: (KeyCode::Char('-'), Some(KeyCode::Char('Z'))),
|
||||||
log_section_height_increase: (KeyCode::Char('='), Some(KeyCode::Char('X'))),
|
log_section_height_increase: (KeyCode::Char('='), Some(KeyCode::Char('X'))),
|
||||||
log_section_toggle: (KeyCode::Char('Y'), Some(KeyCode::Char('W'))),
|
log_section_toggle: (KeyCode::Char('Y'), Some(KeyCode::Char('W'))),
|
||||||
|
log_scroll_forward: (KeyCode::Right, Some(KeyCode::Char('R'))),
|
||||||
|
log_scroll_back: (KeyCode::Left, Some(KeyCode::Char('L'))),
|
||||||
exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))),
|
exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))),
|
||||||
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
||||||
quit: (KeyCode::Char('k'), Some(KeyCode::Char('l'))),
|
quit: (KeyCode::Char('k'), Some(KeyCode::Char('l'))),
|
||||||
|
|||||||
@@ -286,6 +286,23 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Advance the "cursor" along the logs
|
||||||
|
fn logs_forward(&self) {
|
||||||
|
let panel = self.gui_state.lock().get_selected_panel();
|
||||||
|
if panel == SelectablePanel::Logs {
|
||||||
|
let width = self.gui_state.lock().get_screen_width();
|
||||||
|
self.app_data.lock().log_forward(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retreat the "cursor" along the logs
|
||||||
|
fn logs_back(&self) {
|
||||||
|
let panel = self.gui_state.lock().get_selected_panel();
|
||||||
|
if panel == SelectablePanel::Logs {
|
||||||
|
self.app_data.lock().log_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Change the the "next" selectable panel
|
/// Change the the "next" selectable panel
|
||||||
/// If no containers, and on Commands panel, skip to next panel, as Commands panel isn't visible in this state
|
/// If no containers, and on Commands panel, skip to next panel, as Commands panel isn't visible in this state
|
||||||
fn next_panel_key(&self) {
|
fn next_panel_key(&self) {
|
||||||
@@ -467,6 +484,7 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle button presses in all other scenarios
|
/// Handle button presses in all other scenarios
|
||||||
|
#[allow(clippy::cognitive_complexity)]
|
||||||
async fn handle_others(&mut self, key_code: KeyCode) {
|
async fn handle_others(&mut self, key_code: KeyCode) {
|
||||||
self.handle_sort(key_code);
|
self.handle_sort(key_code);
|
||||||
// shift key plus arrows
|
// shift key plus arrows
|
||||||
@@ -537,28 +555,28 @@ impl InputHandler {
|
|||||||
_ if self.keymap.scroll_up_one.0 == key_code
|
_ if self.keymap.scroll_up_one.0 == key_code
|
||||||
|| self.keymap.scroll_up_one.1 == Some(key_code) =>
|
|| self.keymap.scroll_up_one.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
self.previous();
|
self.scroll_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if self.keymap.scroll_up_many.0 == key_code
|
_ if self.keymap.scroll_up_many.0 == key_code
|
||||||
|| self.keymap.scroll_up_many.1 == Some(key_code) =>
|
|| self.keymap.scroll_up_many.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.previous();
|
self.scroll_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if self.keymap.scroll_down_one.0 == key_code
|
_ if self.keymap.scroll_down_one.0 == key_code
|
||||||
|| self.keymap.scroll_down_one.1 == Some(key_code) =>
|
|| self.keymap.scroll_down_one.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
self.next();
|
self.scroll_down();
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if self.keymap.scroll_down_many.0 == key_code
|
_ if self.keymap.scroll_down_many.0 == key_code
|
||||||
|| self.keymap.scroll_down_many.1 == Some(key_code) =>
|
|| self.keymap.scroll_down_many.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.next();
|
self.scroll_down();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,6 +587,18 @@ impl InputHandler {
|
|||||||
self.docker_tx.send(DockerMessage::Update).await.ok();
|
self.docker_tx.send(DockerMessage::Update).await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ if self.keymap.log_scroll_back.0 == key_code
|
||||||
|
|| self.keymap.log_scroll_back.1 == Some(key_code) =>
|
||||||
|
{
|
||||||
|
self.logs_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
_ if self.keymap.log_scroll_forward.0 == key_code
|
||||||
|
|| self.keymap.log_scroll_forward.1 == Some(key_code) =>
|
||||||
|
{
|
||||||
|
self.logs_forward();
|
||||||
|
}
|
||||||
|
|
||||||
KeyCode::Enter => self.enter_key().await,
|
KeyCode::Enter => self.enter_key().await,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -638,8 +668,8 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match mouse_event.kind {
|
match mouse_event.kind {
|
||||||
MouseEventKind::ScrollUp => self.previous(),
|
MouseEventKind::ScrollUp => self.scroll_up(),
|
||||||
MouseEventKind::ScrollDown => self.next(),
|
MouseEventKind::ScrollDown => self.scroll_down(),
|
||||||
MouseEventKind::Down(MouseButton::Left) => {
|
MouseEventKind::Down(MouseButton::Left) => {
|
||||||
let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1);
|
let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1);
|
||||||
let header = self.gui_state.lock().get_intersect_header(mouse_point);
|
let header = self.gui_state.lock().get_intersect_header(mouse_point);
|
||||||
@@ -659,7 +689,7 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Change state to next, depending which panel is currently in focus
|
/// Change state to next, depending which panel is currently in focus
|
||||||
fn next(&self) {
|
fn scroll_down(&self) {
|
||||||
let selected_panel = self.gui_state.lock().get_selected_panel();
|
let selected_panel = self.gui_state.lock().get_selected_panel();
|
||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => self.app_data.lock().containers_next(),
|
SelectablePanel::Containers => self.app_data.lock().containers_next(),
|
||||||
@@ -669,7 +699,7 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Change state to previous, depending which panel is currently in focus
|
/// Change state to previous, depending which panel is currently in focus
|
||||||
fn previous(&self) {
|
fn scroll_up(&self) {
|
||||||
let selected_panel = self.gui_state.lock().get_selected_panel();
|
let selected_panel = self.gui_state.lock().get_selected_panel();
|
||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => self.app_data.lock().containers_previous(),
|
SelectablePanel::Containers => self.app_data.lock().containers_previous(),
|
||||||
|
|||||||
+123
-105
@@ -84,6 +84,7 @@ impl HelpInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo ← → for log moving
|
||||||
/// Generate the button information span + metadata
|
/// Generate the button information span + metadata
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn gen_keymap_info(colors: AppColors, zone: Option<&TimeZone>, show_timestamp: bool) -> Self {
|
fn gen_keymap_info(colors: AppColors, zone: Option<&TimeZone>, show_timestamp: bool) -> Self {
|
||||||
@@ -111,6 +112,11 @@ impl HelpInfo {
|
|||||||
button_item("Home End"),
|
button_item("Home End"),
|
||||||
button_desc("change selected line"),
|
button_desc("change selected line"),
|
||||||
]),
|
]),
|
||||||
|
Line::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("← →"),
|
||||||
|
button_desc("horizontal scroll across logs"),
|
||||||
|
]),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
space(),
|
space(),
|
||||||
button_item("enter"),
|
button_item("enter"),
|
||||||
@@ -268,6 +274,8 @@ impl HelpInfo {
|
|||||||
or_secondary(km.scroll_up_many, "scroll list by up many"),
|
or_secondary(km.scroll_up_many, "scroll list by up many"),
|
||||||
or_secondary(km.scroll_end, "scroll list to end"),
|
or_secondary(km.scroll_end, "scroll list to end"),
|
||||||
or_secondary(km.scroll_start, "scroll list to start"),
|
or_secondary(km.scroll_start, "scroll list to start"),
|
||||||
|
or_secondary(km.log_scroll_forward, "horizontal scroll logs right"),
|
||||||
|
or_secondary(km.log_scroll_back, "horizontal scroll logs left"),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
space(),
|
space(),
|
||||||
button_item("enter"),
|
button_item("enter"),
|
||||||
@@ -436,6 +444,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// This will cause issues once the version has more than the current 5 chars (0.5.0)
|
/// This will cause issues once the version has more than the current 5 chars (0.5.0)
|
||||||
|
/// println!("{} {} {} {} {}", row_index, result_cell_index, result_cell.symbol(), result_cell.bg, result_cell.fg);
|
||||||
|
/// TODO broken wihh the horizonal scrolls!
|
||||||
fn test_draw_blocks_help() {
|
fn test_draw_blocks_help() {
|
||||||
let mut setup = test_setup(87, 35, true, true);
|
let mut setup = test_setup(87, 35, true, true);
|
||||||
let tz = setup.app_data.lock().config.timezone.clone();
|
let tz = setup.app_data.lock().config.timezone.clone();
|
||||||
@@ -463,30 +473,30 @@ mod tests {
|
|||||||
assert_eq!(result_cell.bg, Color::Reset);
|
assert_eq!(result_cell.bg, Color::Reset);
|
||||||
assert_eq!(result_cell.fg, Color::Reset);
|
assert_eq!(result_cell.fg, Color::Reset);
|
||||||
}
|
}
|
||||||
// border is black on magenta
|
// border is red on black
|
||||||
(1 | 32, _) | (1..=31, 1 | 85) => {
|
(1 | 32, _) | (1..=31, 1 | 85) => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::Black);
|
assert_eq!(result_cell.fg, Color::Black);
|
||||||
}
|
}
|
||||||
// oxker logo && description
|
// Buttons
|
||||||
(2..=10, 2..=85)
|
(2..=10, 2..=85)
|
||||||
| (12, 19..=66)
|
| (12, 19..=66)
|
||||||
| (14, 2..=10 | 13..=27)
|
| (14, 2..=10 | 13..=27)
|
||||||
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
||||||
| (16 | 23, 2..=12)
|
| (16 | 25 | 27, 2..=10)
|
||||||
| (17..=20 | 22 | 25 | 27, 2..=8)
|
| (17 | 24, 2..=12)
|
||||||
| (21, 2..=9 | 12..=18)
|
| (18 | 19 | 20 | 21 | 23 | 26 | 28, 2..=8)
|
||||||
| (24 | 26, 2..=10) => {
|
| (22, 2..=9 | 12..=18) => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::White);
|
assert_eq!(result_cell.fg, Color::White);
|
||||||
}
|
}
|
||||||
// The URL is white and underlined
|
// The URL is yellow and underlined
|
||||||
(30, 25..=60) => {
|
(31, 25..=60) => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::White);
|
assert_eq!(result_cell.fg, Color::White);
|
||||||
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
||||||
}
|
}
|
||||||
// The rest is black on magenta
|
// The rest is red on black
|
||||||
_ => {
|
_ => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::Black);
|
assert_eq!(result_cell.fg, Color::Black);
|
||||||
@@ -498,6 +508,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// Test that the help panel gets drawn with custom colors
|
/// Test that the help panel gets drawn with custom colors
|
||||||
|
/// This test is annoying
|
||||||
|
/// println!("{} {} {} {} {}", row_index, result_cell_index, result_cell.symbol(), result_cell.bg, result_cell.fg);
|
||||||
fn test_draw_blocks_help_custom_colors() {
|
fn test_draw_blocks_help_custom_colors() {
|
||||||
let mut setup = test_setup(87, 35, true, true);
|
let mut setup = test_setup(87, 35, true, true);
|
||||||
let mut colors = AppColors::new();
|
let mut colors = AppColors::new();
|
||||||
@@ -535,20 +547,20 @@ mod tests {
|
|||||||
assert_eq!(result_cell.bg, Color::Black);
|
assert_eq!(result_cell.bg, Color::Black);
|
||||||
assert_eq!(result_cell.fg, Color::Red);
|
assert_eq!(result_cell.fg, Color::Red);
|
||||||
}
|
}
|
||||||
// oxker logo && description
|
// Buttons
|
||||||
(2..=10, 2..=85)
|
(2..=10, 2..=85)
|
||||||
| (12, 19..=66)
|
| (12, 19..=66)
|
||||||
| (14, 2..=10 | 13..=27)
|
| (14, 2..=10 | 13..=27)
|
||||||
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
||||||
| (16 | 23, 2..=12)
|
| (16 | 25 | 27, 2..=10)
|
||||||
| (17..=20 | 22 | 25 | 27, 2..=8)
|
| (17 | 24, 2..=12)
|
||||||
| (21, 2..=9 | 12..=18)
|
| (18 | 19 | 20 | 21 | 23 | 26 | 28, 2..=8)
|
||||||
| (24 | 26, 2..=10) => {
|
| (22, 2..=9 | 12..=18) => {
|
||||||
assert_eq!(result_cell.bg, Color::Black);
|
assert_eq!(result_cell.bg, Color::Black);
|
||||||
assert_eq!(result_cell.fg, Color::Yellow);
|
assert_eq!(result_cell.fg, Color::Yellow);
|
||||||
}
|
}
|
||||||
// The URL is yellow and underlined
|
// The URL is yellow and underlined
|
||||||
(30, 25..=60) => {
|
(31, 25..=60) => {
|
||||||
assert_eq!(result_cell.bg, Color::Black);
|
assert_eq!(result_cell.bg, Color::Black);
|
||||||
assert_eq!(result_cell.fg, Color::Yellow);
|
assert_eq!(result_cell.fg, Color::Yellow);
|
||||||
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
||||||
@@ -566,39 +578,41 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
/// Help panel will show custom keymap if in use, with one definition for each entry
|
/// Help panel will show custom keymap if in use, with one definition for each entry
|
||||||
fn test_draw_blocks_help_custom_keymap_one_definition() {
|
fn test_draw_blocks_help_custom_keymap_one_definition() {
|
||||||
let mut setup = test_setup(98, 47, true, true);
|
let mut setup = test_setup(98, 49, true, true);
|
||||||
|
|
||||||
let input = Keymap {
|
let input = Keymap {
|
||||||
clear: (KeyCode::Char('a'), None),
|
clear: (KeyCode::Char('a'), None),
|
||||||
|
delete_confirm: (KeyCode::Char('b'), None),
|
||||||
delete_deny: (KeyCode::Char('c'), None),
|
delete_deny: (KeyCode::Char('c'), None),
|
||||||
delete_confirm: (KeyCode::Char('e'), None),
|
exec: (KeyCode::Char('d'), None),
|
||||||
exec: (KeyCode::Char('g'), None),
|
filter_mode: (KeyCode::Char('e'), None),
|
||||||
log_section_height_decrease: (KeyCode::Char('z'), None),
|
log_scroll_back: (KeyCode::Char('f'), None),
|
||||||
log_section_height_increase: (KeyCode::Char('x'), None),
|
log_scroll_forward: (KeyCode::Char('g'), None),
|
||||||
log_section_toggle: (KeyCode::Char('W'), None),
|
log_section_height_decrease: (KeyCode::Char('h'), None),
|
||||||
filter_mode: (KeyCode::Char('i'), None),
|
log_section_height_increase: (KeyCode::Char('i'), None),
|
||||||
|
log_section_toggle: (KeyCode::Char('j'), None),
|
||||||
quit: (KeyCode::Char('k'), None),
|
quit: (KeyCode::Char('k'), None),
|
||||||
save_logs: (KeyCode::Char('m'), None),
|
save_logs: (KeyCode::Char('l'), None),
|
||||||
scroll_down_many: (KeyCode::Char('o'), None),
|
scroll_down_many: (KeyCode::Char('m'), None),
|
||||||
scroll_down_one: (KeyCode::Char('q'), None),
|
scroll_down_one: (KeyCode::Char('n'), None),
|
||||||
scroll_end: (KeyCode::Char('s'), None),
|
scroll_end: (KeyCode::Char('o'), None),
|
||||||
scroll_start: (KeyCode::Char('u'), None),
|
scroll_start: (KeyCode::Char('p'), None),
|
||||||
scroll_up_many: (KeyCode::Char('w'), None),
|
scroll_up_many: (KeyCode::Char('q'), None),
|
||||||
scroll_up_one: (KeyCode::Char('y'), None),
|
scroll_up_one: (KeyCode::Char('r'), None),
|
||||||
select_next_panel: (KeyCode::Char('0'), None),
|
select_next_panel: (KeyCode::Char('s'), None),
|
||||||
select_previous_panel: (KeyCode::Char('2'), None),
|
select_previous_panel: (KeyCode::Char('t'), None),
|
||||||
sort_by_name: (KeyCode::Char('4'), None),
|
sort_by_cpu: (KeyCode::Char('u'), None),
|
||||||
sort_by_state: (KeyCode::Char('6'), None),
|
sort_by_id: (KeyCode::Char('v'), None),
|
||||||
sort_by_status: (KeyCode::Char('8'), None),
|
sort_by_image: (KeyCode::Char('w'), None),
|
||||||
sort_by_cpu: (KeyCode::F(1), None),
|
sort_by_memory: (KeyCode::Char('x'), None),
|
||||||
sort_by_memory: (KeyCode::Char('#'), None),
|
sort_by_name: (KeyCode::Char('y'), None),
|
||||||
sort_by_id: (KeyCode::Char('/'), None),
|
sort_by_rx: (KeyCode::Char('z'), None),
|
||||||
sort_by_image: (KeyCode::Char(','), None),
|
sort_by_state: (KeyCode::Char('0'), None),
|
||||||
sort_by_rx: (KeyCode::Char('.'), None),
|
sort_by_status: (KeyCode::Char('1'), None),
|
||||||
sort_by_tx: (KeyCode::Insert, None),
|
sort_by_tx: (KeyCode::Char('2'), None),
|
||||||
sort_reset: (KeyCode::Up, None),
|
sort_reset: (KeyCode::Char('3'), None),
|
||||||
toggle_help: (KeyCode::Home, None),
|
toggle_help: (KeyCode::Char('4'), None),
|
||||||
toggle_mouse_capture: (KeyCode::PageDown, None),
|
toggle_mouse_capture: (KeyCode::Char('5'), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
setup
|
setup
|
||||||
@@ -614,39 +628,41 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
/// Help panel will show custom keymap if in use, with two definition for each entry
|
/// Help panel will show custom keymap if in use, with two definition for each entry
|
||||||
fn test_draw_blocks_help_custom_keymap_two_definitions() {
|
fn test_draw_blocks_help_custom_keymap_two_definitions() {
|
||||||
let mut setup = test_setup(110, 47, true, true);
|
let mut setup = test_setup(110, 49, true, true);
|
||||||
|
|
||||||
let keymap = Keymap {
|
let keymap = Keymap {
|
||||||
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
|
clear: (KeyCode::Char('a'), Some(KeyCode::Char('A'))),
|
||||||
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('d'))),
|
delete_confirm: (KeyCode::Char('b'), Some(KeyCode::Char('B'))),
|
||||||
delete_confirm: (KeyCode::Char('e'), Some(KeyCode::Char('f'))),
|
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('C'))),
|
||||||
exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))),
|
exec: (KeyCode::Char('d'), Some(KeyCode::Char('D'))),
|
||||||
log_section_height_decrease: (KeyCode::Char('A'), Some(KeyCode::Char('Z'))),
|
filter_mode: (KeyCode::Char('e'), Some(KeyCode::Char('E'))),
|
||||||
log_section_height_increase: (KeyCode::Char('B'), Some(KeyCode::Char('X'))),
|
log_scroll_back: (KeyCode::Char('f'), Some(KeyCode::Char('F'))),
|
||||||
log_section_toggle: (KeyCode::Char('C'), Some(KeyCode::Char('W'))),
|
log_scroll_forward: (KeyCode::Char('g'), Some(KeyCode::Char('G'))),
|
||||||
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
log_section_height_decrease: (KeyCode::Char('h'), Some(KeyCode::Char('H'))),
|
||||||
quit: (KeyCode::Char('k'), Some(KeyCode::Char('l'))),
|
log_section_height_increase: (KeyCode::Char('i'), Some(KeyCode::Char('I'))),
|
||||||
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
|
log_section_toggle: (KeyCode::Char('j'), Some(KeyCode::Char('J'))),
|
||||||
scroll_down_many: (KeyCode::Char('o'), Some(KeyCode::Char('p'))),
|
quit: (KeyCode::Char('k'), Some(KeyCode::Char('K'))),
|
||||||
scroll_down_one: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
|
save_logs: (KeyCode::Char('l'), Some(KeyCode::Char('L'))),
|
||||||
scroll_end: (KeyCode::Char('s'), Some(KeyCode::Char('t'))),
|
scroll_down_many: (KeyCode::Char('m'), Some(KeyCode::Char('M'))),
|
||||||
scroll_start: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
|
scroll_down_one: (KeyCode::Char('n'), Some(KeyCode::Char('N'))),
|
||||||
scroll_up_many: (KeyCode::Char('w'), Some(KeyCode::Char('x'))),
|
scroll_end: (KeyCode::Char('o'), Some(KeyCode::Char('O'))),
|
||||||
scroll_up_one: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
|
scroll_start: (KeyCode::Char('p'), Some(KeyCode::Char('P'))),
|
||||||
select_next_panel: (KeyCode::Char('0'), Some(KeyCode::Char('1'))),
|
scroll_up_many: (KeyCode::Char('q'), Some(KeyCode::Char('Q'))),
|
||||||
select_previous_panel: (KeyCode::Char('2'), Some(KeyCode::Char('3'))),
|
scroll_up_one: (KeyCode::Char('r'), Some(KeyCode::Char('R'))),
|
||||||
sort_by_name: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
|
select_next_panel: (KeyCode::Char('s'), Some(KeyCode::Char('S'))),
|
||||||
sort_by_state: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
|
select_previous_panel: (KeyCode::Char('t'), Some(KeyCode::Char('T'))),
|
||||||
sort_by_status: (KeyCode::Char('8'), Some(KeyCode::Char('9'))),
|
sort_by_cpu: (KeyCode::Char('u'), Some(KeyCode::Char('U'))),
|
||||||
sort_by_cpu: (KeyCode::F(1), Some(KeyCode::F(12))),
|
sort_by_id: (KeyCode::Char('v'), Some(KeyCode::Char('V'))),
|
||||||
sort_by_memory: (KeyCode::Char('#'), Some(KeyCode::Char('-'))),
|
sort_by_image: (KeyCode::Char('w'), Some(KeyCode::Char('W'))),
|
||||||
sort_by_id: (KeyCode::Char('/'), Some(KeyCode::Char('='))),
|
sort_by_memory: (KeyCode::Char('x'), Some(KeyCode::Char('X'))),
|
||||||
sort_by_image: (KeyCode::Char(','), Some(KeyCode::Char('\\'))),
|
sort_by_name: (KeyCode::Char('y'), Some(KeyCode::Char('Y'))),
|
||||||
sort_by_rx: (KeyCode::Char('.'), Some(KeyCode::Char(']'))),
|
sort_by_rx: (KeyCode::Char('z'), Some(KeyCode::Char('Z'))),
|
||||||
sort_by_tx: (KeyCode::Insert, Some(KeyCode::BackTab)),
|
sort_by_state: (KeyCode::Char('0'), Some(KeyCode::Char('9'))),
|
||||||
sort_reset: (KeyCode::Up, Some(KeyCode::Down)),
|
sort_by_status: (KeyCode::Char('1'), Some(KeyCode::Char('8'))),
|
||||||
toggle_help: (KeyCode::Home, Some(KeyCode::End)),
|
sort_by_tx: (KeyCode::Char('2'), Some(KeyCode::Char('7'))),
|
||||||
toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)),
|
sort_reset: (KeyCode::Char('3'), Some(KeyCode::Char('6'))),
|
||||||
|
toggle_help: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
|
||||||
|
toggle_mouse_capture: (KeyCode::Char('5'), Some(KeyCode::PageDown)),
|
||||||
};
|
};
|
||||||
|
|
||||||
setup
|
setup
|
||||||
@@ -662,39 +678,41 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
/// Help panel will show custom keymap if in use, with either one or two definition for each entry
|
/// Help panel will show custom keymap if in use, with either one or two definition for each entry
|
||||||
fn test_draw_blocks_help_one_and_two_definitions() {
|
fn test_draw_blocks_help_one_and_two_definitions() {
|
||||||
let mut setup = test_setup(110, 47, true, true);
|
let mut setup = test_setup(110, 49, true, true);
|
||||||
|
|
||||||
let keymap = Keymap {
|
let keymap = Keymap {
|
||||||
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
|
clear: (KeyCode::Char('a'), Some(KeyCode::Char('A'))),
|
||||||
delete_deny: (KeyCode::Char('c'), None),
|
delete_confirm: (KeyCode::Char('b'), None),
|
||||||
delete_confirm: (KeyCode::Char('e'), Some(KeyCode::Char('f'))),
|
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('C'))),
|
||||||
exec: (KeyCode::Char('g'), None),
|
exec: (KeyCode::Char('d'), None),
|
||||||
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
filter_mode: (KeyCode::Char('e'), Some(KeyCode::Char('E'))),
|
||||||
log_section_height_decrease: (KeyCode::Char('A'), Some(KeyCode::Char('Z'))),
|
log_scroll_back: (KeyCode::Char('f'), None),
|
||||||
log_section_height_increase: (KeyCode::Char('B'), Some(KeyCode::Char('X'))),
|
log_scroll_forward: (KeyCode::Char('g'), Some(KeyCode::Char('G'))),
|
||||||
log_section_toggle: (KeyCode::Char('C'), Some(KeyCode::Char('W'))),
|
log_section_height_decrease: (KeyCode::Char('h'), None),
|
||||||
quit: (KeyCode::Char('k'), None),
|
log_section_height_increase: (KeyCode::Char('i'), Some(KeyCode::Char('I'))),
|
||||||
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
|
log_section_toggle: (KeyCode::Char('j'), None),
|
||||||
scroll_down_many: (KeyCode::Char('o'), None),
|
quit: (KeyCode::Char('k'), Some(KeyCode::Char('K'))),
|
||||||
scroll_down_one: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
|
save_logs: (KeyCode::Char('l'), None),
|
||||||
scroll_end: (KeyCode::Char('s'), None),
|
scroll_down_many: (KeyCode::Char('m'), Some(KeyCode::Char('M'))),
|
||||||
scroll_start: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
|
scroll_down_one: (KeyCode::Char('n'), None),
|
||||||
scroll_up_many: (KeyCode::Char('w'), None),
|
scroll_end: (KeyCode::Char('o'), Some(KeyCode::Char('O'))),
|
||||||
scroll_up_one: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
|
scroll_start: (KeyCode::Char('p'), None),
|
||||||
select_next_panel: (KeyCode::Char('0'), None),
|
scroll_up_many: (KeyCode::Char('q'), Some(KeyCode::Char('Q'))),
|
||||||
select_previous_panel: (KeyCode::Char('2'), Some(KeyCode::Char('3'))),
|
scroll_up_one: (KeyCode::Char('r'), None),
|
||||||
sort_by_name: (KeyCode::Char('4'), None),
|
select_next_panel: (KeyCode::Char('s'), Some(KeyCode::Char('S'))),
|
||||||
sort_by_state: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
|
select_previous_panel: (KeyCode::Char('t'), None),
|
||||||
sort_by_status: (KeyCode::Char('8'), None),
|
sort_by_cpu: (KeyCode::Char('u'), Some(KeyCode::Char('U'))),
|
||||||
sort_by_cpu: (KeyCode::F(1), Some(KeyCode::F(12))),
|
sort_by_id: (KeyCode::Char('v'), None),
|
||||||
sort_by_memory: (KeyCode::Char('#'), None),
|
sort_by_image: (KeyCode::Char('w'), Some(KeyCode::Char('W'))),
|
||||||
sort_by_id: (KeyCode::Char('/'), Some(KeyCode::Char('='))),
|
sort_by_memory: (KeyCode::Char('x'), None),
|
||||||
sort_by_image: (KeyCode::Char(','), None),
|
sort_by_name: (KeyCode::Char('y'), Some(KeyCode::Char('Y'))),
|
||||||
sort_by_rx: (KeyCode::Char('.'), Some(KeyCode::Char(']'))),
|
sort_by_rx: (KeyCode::Char('z'), None),
|
||||||
sort_by_tx: (KeyCode::Insert, None),
|
sort_by_state: (KeyCode::Char('0'), Some(KeyCode::Char('9'))),
|
||||||
sort_reset: (KeyCode::Up, Some(KeyCode::Down)),
|
sort_by_status: (KeyCode::Char('1'), None),
|
||||||
toggle_help: (KeyCode::Home, None),
|
sort_by_tx: (KeyCode::Char('2'), Some(KeyCode::Char('7'))),
|
||||||
toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)),
|
sort_reset: (KeyCode::Char('3'), None),
|
||||||
|
toggle_help: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
|
||||||
|
toggle_mouse_capture: (KeyCode::Char('5'), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tz = setup.app_data.lock().config.timezone.clone();
|
let tz = setup.app_data.lock().config.timezone.clone();
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ pub fn draw(
|
|||||||
f.render_widget(paragraph, area);
|
f.render_widget(paragraph, area);
|
||||||
} else {
|
} else {
|
||||||
let padding = usize::from(area.height / 5);
|
let padding = usize::from(area.height / 5);
|
||||||
let logs = app_data.lock().get_logs(area.height, padding);
|
let logs = app_data.lock().get_logs(area.as_size(), padding);
|
||||||
if logs.is_empty() {
|
if logs.is_empty() {
|
||||||
let mut paragraph = Paragraph::new("no logs found")
|
let mut paragraph = Paragraph::new("no logs found")
|
||||||
.block(block)
|
.block(block)
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ pub fn max_line_width(text: &str) -> usize {
|
|||||||
.max()
|
.max()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate block, add a border if is the selected panel,
|
/// Generate block, add a border if is the selected panel,
|
||||||
/// add custom title based on state of each panel
|
/// add custom title based on state of each panel
|
||||||
fn generate_block<'a>(
|
fn generate_block<'a>(
|
||||||
@@ -101,7 +100,15 @@ fn generate_block<'a>(
|
|||||||
let mut block = Block::default()
|
let mut block = Block::default()
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
.title(title);
|
.title(ratatui::text::Line::from(title).left_aligned());
|
||||||
|
|
||||||
|
if panel == SelectablePanel::Logs {
|
||||||
|
if let Some(x) = fd.scroll_title.as_ref() {
|
||||||
|
block = block
|
||||||
|
.title_bottom(x.to_owned())
|
||||||
|
.title_alignment(ratatui::layout::Alignment::Right);
|
||||||
|
}
|
||||||
|
}
|
||||||
if !fd.status.contains(&Status::Filter) {
|
if !fd.status.contains(&Status::Filter) {
|
||||||
if fd.selected_panel == panel {
|
if fd.selected_panel == panel {
|
||||||
block = block.border_style(Style::default().fg(colors.borders.selected));
|
block = block.border_style(Style::default().fg(colors.borders.selected));
|
||||||
@@ -178,6 +185,7 @@ pub mod tests {
|
|||||||
loading_icon: gui_data.get_loading().to_string(),
|
loading_icon: gui_data.get_loading().to_string(),
|
||||||
log_height: gui_data.get_log_height(),
|
log_height: gui_data.get_log_height(),
|
||||||
log_title: app_data.get_log_title(),
|
log_title: app_data.get_log_title(),
|
||||||
|
scroll_title: app_data.get_scroll_title(),
|
||||||
port_max_lens: app_data.get_longest_port(),
|
port_max_lens: app_data.get_longest_port(),
|
||||||
ports: app_data.get_selected_ports(),
|
ports: app_data.get_selected_ports(),
|
||||||
selected_panel: gui_data.get_selected_panel(),
|
selected_panel: gui_data.get_selected_panel(),
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
assertion_line: 456
|
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" "
|
" "
|
||||||
@@ -19,6 +18,7 @@ expression: setup.terminal.backend()
|
|||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( tab ) or ( shift+tab ) change panels │ "
|
" │ ( tab ) or ( shift+tab ) change panels │ "
|
||||||
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
||||||
|
" │ ( ← → ) horizontal scroll across logs │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( e ) exec into a container │ "
|
" │ ( e ) exec into a container │ "
|
||||||
" │ ( h ) toggle this help information - or click heading │ "
|
" │ ( h ) toggle this help information - or click heading │ "
|
||||||
@@ -35,6 +35,5 @@ expression: setup.terminal.backend()
|
|||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ │ "
|
|
||||||
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
" "
|
" "
|
||||||
|
|||||||
+1
-1
@@ -18,6 +18,7 @@ expression: setup.terminal.backend()
|
|||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( tab ) or ( shift+tab ) change panels │ "
|
" │ ( tab ) or ( shift+tab ) change panels │ "
|
||||||
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
||||||
|
" │ ( ← → ) horizontal scroll across logs │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( e ) exec into a container │ "
|
" │ ( e ) exec into a container │ "
|
||||||
" │ ( h ) toggle this help information - or click heading │ "
|
" │ ( h ) toggle this help information - or click heading │ "
|
||||||
@@ -34,6 +35,5 @@ expression: setup.terminal.backend()
|
|||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ │ "
|
|
||||||
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
" "
|
" "
|
||||||
|
|||||||
+49
-47
@@ -2,50 +2,52 @@
|
|||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────────────╮ "
|
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
||||||
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
||||||
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
||||||
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
||||||
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( 0 ) select next panel │ "
|
" │ ( s ) select next panel │ "
|
||||||
" │ ( 2 ) select previous panel │ "
|
" │ ( t ) select previous panel │ "
|
||||||
" │ ( q ) scroll list down by one │ "
|
" │ ( n ) scroll list down by one │ "
|
||||||
" │ ( y ) scroll list up by one │ "
|
" │ ( r ) scroll list up by one │ "
|
||||||
" │ ( o ) scroll list down by many │ "
|
" │ ( m ) scroll list down by many │ "
|
||||||
" │ ( w ) scroll list by up many │ "
|
" │ ( q ) scroll list by up many │ "
|
||||||
" │ ( s ) scroll list to end │ "
|
" │ ( o ) scroll list to end │ "
|
||||||
" │ ( u ) scroll list to start │ "
|
" │ ( p ) scroll list to start │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( g ) horizontal scroll logs right │ "
|
||||||
" │ ( g ) exec into a container │ "
|
" │ ( f ) horizontal scroll logs left │ "
|
||||||
" │ ( Home ) toggle this help information - or click heading │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( m ) save logs to file │ "
|
" │ ( d ) exec into a container │ "
|
||||||
" │ ( Page Down ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( 4 ) toggle this help information - or click heading │ "
|
||||||
" │ ( i ) enter filter mode │ "
|
" │ ( l ) save logs to file │ "
|
||||||
" │ ( Up ) reset container sorting │ "
|
" │ ( 5 ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
" │ ( 4 ) sort containers by name │ "
|
" │ ( e ) enter filter mode │ "
|
||||||
" │ ( 6 ) sort containers by state │ "
|
" │ ( 3 ) reset container sorting │ "
|
||||||
" │ ( 8 ) sort containers by status │ "
|
" │ ( y ) sort containers by name │ "
|
||||||
" │ ( F1 ) sort containers by cpu │ "
|
" │ ( 0 ) sort containers by state │ "
|
||||||
" │ ( # ) sort containers by memory │ "
|
" │ ( 1 ) sort containers by status │ "
|
||||||
" │ ( / ) sort containers by id │ "
|
" │ ( u ) sort containers by cpu │ "
|
||||||
" │ ( , ) sort containers by image │ "
|
" │ ( x ) sort containers by memory │ "
|
||||||
" │ ( . ) sort containers by rx │ "
|
" │ ( v ) sort containers by id │ "
|
||||||
" │ ( Insert ) sort containers by tx │ "
|
" │ ( w ) sort containers by image │ "
|
||||||
" │ ( z ) decrease log section height │ "
|
" │ ( z ) sort containers by rx │ "
|
||||||
" │ ( x ) increase log section height │ "
|
" │ ( 2 ) sort containers by tx │ "
|
||||||
" │ ( W ) toggle log section visibility │ "
|
" │ ( h ) decrease log section height │ "
|
||||||
" │ ( a ) close dialog │ "
|
" │ ( i ) increase log section height │ "
|
||||||
" │ ( k ) quit at any time │ "
|
" │ ( j ) toggle log section visibility │ "
|
||||||
" │ │ "
|
" │ ( a ) close dialog │ "
|
||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ ( k ) quit at any time │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ │ "
|
||||||
" │ │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" ╰────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
|
" │ │ "
|
||||||
|
" ╰────────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
|
|||||||
+49
-47
@@ -2,50 +2,52 @@
|
|||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" ╭ 0.00.000 ────────────────────────────────────────────────────────────────────────────────────────────────╮ "
|
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────────────────────╮ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
||||||
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
||||||
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
||||||
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
||||||
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( 0 ) or ( 1 ) select next panel │ "
|
" │ ( s ) or ( S ) select next panel │ "
|
||||||
" │ ( 2 ) or ( 3 ) select previous panel │ "
|
" │ ( t ) or ( T ) select previous panel │ "
|
||||||
" │ ( q ) or ( r ) scroll list down by one │ "
|
" │ ( n ) or ( N ) scroll list down by one │ "
|
||||||
" │ ( y ) or ( z ) scroll list up by one │ "
|
" │ ( r ) or ( R ) scroll list up by one │ "
|
||||||
" │ ( o ) or ( p ) scroll list down by many │ "
|
" │ ( m ) or ( M ) scroll list down by many │ "
|
||||||
" │ ( w ) or ( x ) scroll list by up many │ "
|
" │ ( q ) or ( Q ) scroll list by up many │ "
|
||||||
" │ ( s ) or ( t ) scroll list to end │ "
|
" │ ( o ) or ( O ) scroll list to end │ "
|
||||||
" │ ( u ) or ( v ) scroll list to start │ "
|
" │ ( p ) or ( P ) scroll list to start │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( g ) or ( G ) horizontal scroll logs right │ "
|
||||||
" │ ( g ) or ( h ) exec into a container │ "
|
" │ ( f ) or ( F ) horizontal scroll logs left │ "
|
||||||
" │ ( Home ) or ( End ) toggle this help information - or click heading │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( m ) or ( n ) save logs to file │ "
|
" │ ( d ) or ( D ) exec into a container │ "
|
||||||
" │ ( Page Down ) or ( Page Up ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( 4 ) or ( 5 ) toggle this help information - or click heading │ "
|
||||||
" │ ( i ) or ( j ) enter filter mode │ "
|
" │ ( l ) or ( L ) save logs to file │ "
|
||||||
" │ ( Up ) or ( Down ) reset container sorting │ "
|
" │ ( 5 ) or ( Page Down ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
" │ ( 4 ) or ( 5 ) sort containers by name │ "
|
" │ ( e ) or ( E ) enter filter mode │ "
|
||||||
" │ ( 6 ) or ( 7 ) sort containers by state │ "
|
" │ ( 3 ) or ( 6 ) reset container sorting │ "
|
||||||
" │ ( 8 ) or ( 9 ) sort containers by status │ "
|
" │ ( y ) or ( Y ) sort containers by name │ "
|
||||||
" │ ( F1 ) or ( F12 ) sort containers by cpu │ "
|
" │ ( 0 ) or ( 9 ) sort containers by state │ "
|
||||||
" │ ( # ) or ( - ) sort containers by memory │ "
|
" │ ( 1 ) or ( 8 ) sort containers by status │ "
|
||||||
" │ ( / ) or ( = ) sort containers by id │ "
|
" │ ( u ) or ( U ) sort containers by cpu │ "
|
||||||
" │ ( , ) or ( \ ) sort containers by image │ "
|
" │ ( x ) or ( X ) sort containers by memory │ "
|
||||||
" │ ( . ) or ( ] ) sort containers by rx │ "
|
" │ ( v ) or ( V ) sort containers by id │ "
|
||||||
" │ ( Insert ) or ( Back Tab ) sort containers by tx │ "
|
" │ ( w ) or ( W ) sort containers by image │ "
|
||||||
" │ ( A ) or ( Z ) decrease log section height │ "
|
" │ ( z ) or ( Z ) sort containers by rx │ "
|
||||||
" │ ( B ) or ( X ) increase log section height │ "
|
" │ ( 2 ) or ( 7 ) sort containers by tx │ "
|
||||||
" │ ( C ) or ( W ) toggle log section visibility │ "
|
" │ ( h ) or ( H ) decrease log section height │ "
|
||||||
" │ ( a ) or ( b ) close dialog │ "
|
" │ ( i ) or ( I ) increase log section height │ "
|
||||||
" │ ( k ) or ( l ) quit at any time │ "
|
" │ ( j ) or ( J ) toggle log section visibility │ "
|
||||||
" │ │ "
|
" │ ( a ) or ( A ) close dialog │ "
|
||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ ( k ) or ( K ) quit at any time │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ │ "
|
||||||
" │ │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
|
" │ │ "
|
||||||
|
" ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
|
|||||||
+49
-47
@@ -2,50 +2,52 @@
|
|||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" ╭ 0.00.000 ────────────────────────────────────────────────────────────────────────────────────────────────╮ "
|
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
||||||
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
||||||
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
||||||
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
||||||
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( 0 ) select next panel │ "
|
" │ ( s ) or ( S ) select next panel │ "
|
||||||
" │ ( 2 ) or ( 3 ) select previous panel │ "
|
" │ ( t ) select previous panel │ "
|
||||||
" │ ( q ) or ( r ) scroll list down by one │ "
|
" │ ( n ) scroll list down by one │ "
|
||||||
" │ ( y ) or ( z ) scroll list up by one │ "
|
" │ ( r ) scroll list up by one │ "
|
||||||
" │ ( o ) scroll list down by many │ "
|
" │ ( m ) or ( M ) scroll list down by many │ "
|
||||||
" │ ( w ) scroll list by up many │ "
|
" │ ( q ) or ( Q ) scroll list by up many │ "
|
||||||
" │ ( s ) scroll list to end │ "
|
" │ ( o ) or ( O ) scroll list to end │ "
|
||||||
" │ ( u ) or ( v ) scroll list to start │ "
|
" │ ( p ) scroll list to start │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( g ) or ( G ) horizontal scroll logs right │ "
|
||||||
" │ ( g ) exec into a container │ "
|
" │ ( f ) horizontal scroll logs left │ "
|
||||||
" │ ( Home ) toggle this help information - or click heading │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( m ) or ( n ) save logs to file │ "
|
" │ ( d ) exec into a container │ "
|
||||||
" │ ( Page Down ) or ( Page Up ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( 4 ) or ( 5 ) toggle this help information - or click heading │ "
|
||||||
" │ ( i ) or ( j ) enter filter mode │ "
|
" │ ( l ) save logs to file │ "
|
||||||
" │ ( Up ) or ( Down ) reset container sorting │ "
|
" │ ( 5 ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
" │ ( 4 ) sort containers by name │ "
|
" │ ( e ) or ( E ) enter filter mode │ "
|
||||||
" │ ( 6 ) or ( 7 ) sort containers by state │ "
|
" │ ( 3 ) reset container sorting │ "
|
||||||
" │ ( 8 ) sort containers by status │ "
|
" │ ( y ) or ( Y ) sort containers by name │ "
|
||||||
" │ ( F1 ) or ( F12 ) sort containers by cpu │ "
|
" │ ( 0 ) or ( 9 ) sort containers by state │ "
|
||||||
" │ ( # ) sort containers by memory │ "
|
" │ ( 1 ) sort containers by status │ "
|
||||||
" │ ( / ) or ( = ) sort containers by id │ "
|
" │ ( u ) or ( U ) sort containers by cpu │ "
|
||||||
" │ ( , ) sort containers by image │ "
|
" │ ( x ) sort containers by memory │ "
|
||||||
" │ ( . ) or ( ] ) sort containers by rx │ "
|
" │ ( v ) sort containers by id │ "
|
||||||
" │ ( Insert ) sort containers by tx │ "
|
" │ ( w ) or ( W ) sort containers by image │ "
|
||||||
" │ ( A ) or ( Z ) decrease log section height │ "
|
" │ ( z ) sort containers by rx │ "
|
||||||
" │ ( B ) or ( X ) increase log section height │ "
|
" │ ( 2 ) or ( 7 ) sort containers by tx │ "
|
||||||
" │ ( C ) or ( W ) toggle log section visibility │ "
|
" │ ( h ) decrease log section height │ "
|
||||||
" │ ( a ) or ( b ) close dialog │ "
|
" │ ( i ) or ( I ) increase log section height │ "
|
||||||
" │ ( k ) quit at any time │ "
|
" │ ( j ) toggle log section visibility │ "
|
||||||
" │ │ "
|
" │ ( a ) or ( A ) close dialog │ "
|
||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ ( k ) or ( K ) quit at any time │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ │ "
|
||||||
" │ │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
|
" │ │ "
|
||||||
|
" ╰────────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
|
|||||||
+1
-1
@@ -20,6 +20,7 @@ expression: setup.terminal.backend()
|
|||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( tab ) or ( shift+tab ) change panels │ "
|
" │ ( tab ) or ( shift+tab ) change panels │ "
|
||||||
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
||||||
|
" │ ( ← → ) horizontal scroll across logs │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( e ) exec into a container │ "
|
" │ ( e ) exec into a container │ "
|
||||||
" │ ( h ) toggle this help information - or click heading │ "
|
" │ ( h ) toggle this help information - or click heading │ "
|
||||||
@@ -36,6 +37,5 @@ expression: setup.terminal.backend()
|
|||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ │ "
|
|
||||||
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
" "
|
" "
|
||||||
|
|||||||
+10
-10
@@ -5,22 +5,22 @@ expression: setup.terminal.backend()
|
|||||||
" name state status cpu memory/limit id image ↓ rx ↑ tx ( h ) exit help "
|
" name state status cpu memory/limit id image ↓ rx ↑ tx ( h ) exit help "
|
||||||
"╭ Containers 1/3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮╭──────────────╮"
|
"╭ Containers 1/3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮╭──────────────╮"
|
||||||
"│⚪ container_1 ✓ running Up 1 hour 03.00% 30.00 kB / 30.00 kB 1 image_1 0.00 kB 0.00 kB ││▶ pause │" Hidden by multi-width symbols: [(2, " ")]
|
"│⚪ container_1 ✓ running Up 1 hour 03.00% 30.00 kB / 30.00 kB 1 image_1 0.00 kB 0.00 kB ││▶ pause │" Hidden by multi-width symbols: [(2, " ")]
|
||||||
"│ container_2 ✓ running Up 2 hour 00.00% 0.00 kB / 0.00 kB 2 image_2 0.00 kB 0.00 kB ││ restart │"
|
"│ container_2 ✓ running Up 2 ho╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ ││ restart │"
|
||||||
"│ container_3 ✓ running Up 3 ho╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ ││ stop │"
|
"│ container_3 ✓ running Up 3 ho│ │ ││ stop │"
|
||||||
"│ │ │ ││ delete │"
|
"│ │ 88 │ ││ delete │"
|
||||||
"│ │ 88 │ ││ │"
|
"│ │ 88 │ ││ │"
|
||||||
"╰────────────────────────────────────│ 88 │────────────────────╯╰──────────────╯"
|
"╰────────────────────────────────────│ 88 │────────────────────╯╰──────────────╯"
|
||||||
"╭ Logs 3/3 - container_1 - image_1 ──│ 88 │────────────────────────────────────╮"
|
"╭ Logs 3/3 - container_1 - image_1 ──│ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │────────────────────────────────────╮"
|
||||||
"│ line 1 │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ │"
|
"│ line 1 │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ │"
|
||||||
"│ line 2 │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ │"
|
"│ line 2 │ 8b d8 )888( 8888[ 8PP""""""" 88 │ │"
|
||||||
"│▶ line 3 │ 8b d8 )888( 8888[ 8PP""""""" 88 │ │"
|
"│▶ line 3 │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ │"
|
||||||
"│ │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ │"
|
|
||||||
"│ │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ │"
|
"│ │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ │"
|
||||||
"│ │ │ │"
|
"│ │ │ │"
|
||||||
"│ │ A simple tui to view & control docker containers │ │"
|
"│ │ A simple tui to view & control docker containers │ │"
|
||||||
"│ │ │ │"
|
"│ │ │ │"
|
||||||
"│ │ ( tab ) or ( shift+tab ) change panels │ │"
|
"│ │ ( tab ) or ( shift+tab ) change panels │ │"
|
||||||
"│ │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ │"
|
"│ │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ │"
|
||||||
|
"│ │ ( ← → ) horizontal scroll across logs │ │"
|
||||||
"│ │ ( enter ) send docker container command │ │"
|
"│ │ ( enter ) send docker container command │ │"
|
||||||
"│ │ ( e ) exec into a container │ │"
|
"│ │ ( e ) exec into a container │ │"
|
||||||
"│ │ ( h ) toggle this help information - or click heading │ │"
|
"│ │ ( h ) toggle this help information - or click heading │ │"
|
||||||
@@ -37,8 +37,8 @@ expression: setup.terminal.backend()
|
|||||||
"│ │ • • │ currently an early work in progress, all and any input appreciated │ ││ 8001 │"
|
"│ │ • • │ currently an early work in progress, all and any input appreciated │ ││ 8001 │"
|
||||||
"│ │ •• • │ https://github.com/mrjackwills/oxker │ ││127.0.0.1 8003 8003│"
|
"│ │ •• • │ https://github.com/mrjackwills/oxker │ ││127.0.0.1 8003 8003│"
|
||||||
"│ │ • • │ │ ││ │"
|
"│ │ • • │ │ ││ │"
|
||||||
"│ │ •• • • ╰────────────────────────────────────────────────────────────────────────────────────╯ ││ │"
|
"│ │ •• • • │ │ ││ │"
|
||||||
"│ │• •• ││ │• •• ││ │"
|
"│ │• •• ╰────────────────────────────────────────────────────────────────────────────────────╯ ││ │"
|
||||||
"│ │• • ││ │• • ││ │"
|
"│ │• • ││ │• • ││ │"
|
||||||
"│ │ ││ │ ││ │"
|
"│ │ ││ │ ││ │"
|
||||||
"╰───────────────────────────────────────────────────────────────╯╰───────────────────────────────────────────────────────────────╯╰────────────────────────────╯"
|
"╰───────────────────────────────────────────────────────────────╯╰───────────────────────────────────────────────────────────────╯╰────────────────────────────╯"
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ pub struct GuiState {
|
|||||||
log_height: u16,
|
log_height: u16,
|
||||||
rerender: Arc<Rerender>,
|
rerender: Arc<Rerender>,
|
||||||
selected_panel: SelectablePanel,
|
selected_panel: SelectablePanel,
|
||||||
|
screen_width: u16,
|
||||||
show_logs: bool,
|
show_logs: bool,
|
||||||
status: HashSet<Status>,
|
status: HashSet<Status>,
|
||||||
pub info_box_text: Option<(String, Instant)>,
|
pub info_box_text: Option<(String, Instant)>,
|
||||||
@@ -205,6 +206,7 @@ impl GuiState {
|
|||||||
loading_index: 0,
|
loading_index: 0,
|
||||||
loading_set: HashSet::new(),
|
loading_set: HashSet::new(),
|
||||||
log_height: 75,
|
log_height: 75,
|
||||||
|
screen_width: 0,
|
||||||
rerender: Arc::clone(redraw),
|
rerender: Arc::clone(redraw),
|
||||||
selected_panel: SelectablePanel::default(),
|
selected_panel: SelectablePanel::default(),
|
||||||
show_logs,
|
show_logs,
|
||||||
@@ -232,6 +234,16 @@ impl GuiState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the screen width, used for offset char calculations
|
||||||
|
pub const fn set_screen_width(&mut self, width: u16) {
|
||||||
|
self.screen_width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the screen width, used for offset char calculations
|
||||||
|
pub const fn get_screen_width(&self) -> u16 {
|
||||||
|
self.screen_width
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn get_show_logs(&self) -> bool {
|
pub const fn get_show_logs(&self) -> bool {
|
||||||
self.show_logs
|
self.show_logs
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -205,6 +205,10 @@ impl Ui {
|
|||||||
let docker_interval_ms = u128::from(self.app_data.lock().config.docker_interval_ms);
|
let docker_interval_ms = u128::from(self.app_data.lock().config.docker_interval_ms);
|
||||||
let mut drawn_at = std::time::Instant::now();
|
let mut drawn_at = std::time::Instant::now();
|
||||||
|
|
||||||
|
if let Ok(size) = self.terminal.size() {
|
||||||
|
self.gui_state.lock().set_screen_width(size.width);
|
||||||
|
}
|
||||||
|
|
||||||
while self.is_running.load(Ordering::SeqCst) {
|
while self.is_running.load(Ordering::SeqCst) {
|
||||||
if self.should_redraw(&mut drawn_at, docker_interval_ms) {
|
if self.should_redraw(&mut drawn_at, docker_interval_ms) {
|
||||||
let fd = FrameData::from(&*self);
|
let fd = FrameData::from(&*self);
|
||||||
@@ -243,11 +247,14 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
} else if let Event::Resize(_, _) = event {
|
} else if let Event::Resize(width, _) = event {
|
||||||
self.gui_state.lock().clear_area_map();
|
self.gui_state.lock().clear_area_map();
|
||||||
|
|
||||||
// self.gui_state.lock().set_window_height(row);
|
// self.gui_state.lock().set_window_height(row);
|
||||||
|
|
||||||
self.terminal.autoresize().ok();
|
self.terminal.autoresize().ok();
|
||||||
|
// todo set screen width
|
||||||
|
self.gui_state.lock().set_screen_width(width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -279,7 +286,6 @@ pub struct FrameData {
|
|||||||
filter_by: FilterBy,
|
filter_by: FilterBy,
|
||||||
filter_term: Option<String>,
|
filter_term: Option<String>,
|
||||||
has_containers: bool,
|
has_containers: bool,
|
||||||
// container_section_height: u16,
|
|
||||||
log_height: u16,
|
log_height: u16,
|
||||||
show_logs: bool,
|
show_logs: bool,
|
||||||
has_error: Option<AppError>,
|
has_error: Option<AppError>,
|
||||||
@@ -290,6 +296,7 @@ pub struct FrameData {
|
|||||||
port_max_lens: (usize, usize, usize),
|
port_max_lens: (usize, usize, usize),
|
||||||
ports: Option<(Vec<ContainerPorts>, State)>,
|
ports: Option<(Vec<ContainerPorts>, State)>,
|
||||||
selected_panel: SelectablePanel,
|
selected_panel: SelectablePanel,
|
||||||
|
scroll_title: Option<String>,
|
||||||
sorted_by: Option<(Header, SortedOrder)>,
|
sorted_by: Option<(Header, SortedOrder)>,
|
||||||
status: HashSet<Status>,
|
status: HashSet<Status>,
|
||||||
}
|
}
|
||||||
@@ -317,6 +324,7 @@ impl From<&Ui> for FrameData {
|
|||||||
log_title: app_data.get_log_title(),
|
log_title: app_data.get_log_title(),
|
||||||
port_max_lens: app_data.get_longest_port(),
|
port_max_lens: app_data.get_longest_port(),
|
||||||
ports: app_data.get_selected_ports(),
|
ports: app_data.get_selected_ports(),
|
||||||
|
scroll_title: app_data.get_scroll_title(),
|
||||||
selected_panel: gui_data.get_selected_panel(),
|
selected_panel: gui_data.get_selected_panel(),
|
||||||
sorted_by: app_data.get_sorted(),
|
sorted_by: app_data.get_sorted(),
|
||||||
status: gui_data.get_status(),
|
status: gui_data.get_status(),
|
||||||
|
|||||||
Reference in New Issue
Block a user