feat: filter panel colors
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
"show_std_err": false,
|
||||
"show_timestamp": true,
|
||||
"timezone": "Etc/UTC",
|
||||
"timestamp_format":"%Y-%m-%dT%H:%M:%S.%8f",
|
||||
"timestamp_format": "%Y-%m-%dT%H:%M:%S.%8f",
|
||||
"use_cli": false,
|
||||
"colors": {
|
||||
"borders": {
|
||||
@@ -64,6 +64,13 @@
|
||||
"text_rx": "#FFE9C1",
|
||||
"text_tx": "#CD8C8C"
|
||||
},
|
||||
"filter": {
|
||||
"background": "reset",
|
||||
"text": "gray",
|
||||
"selected_filter_background": "gray",
|
||||
"selected_filter_text": "black",
|
||||
"highlight": "magenta"
|
||||
},
|
||||
"headers_bar": {
|
||||
"background": "magenta",
|
||||
"loading_spinner": "white",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"host": "/var/run/docker.sock",
|
||||
// Display the timestamp in a custom format, if given option is invalid, it will default to %Y-%m-%dT%H:%M:%S.%8f -> 2025-02-18T12:34:56.01234567
|
||||
// *Should* accept any valid strftime string up to 32 chars
|
||||
"timestamp_format":"%Y-%m-%dT%H:%M:%S.%8f",
|
||||
"timestamp_format": "%Y-%m-%dT%H:%M:%S.%8f",
|
||||
// Display the container logs timestamp with a given timezone, if timezone is unknown, defaults to UTC
|
||||
"timezone": "Etc/UTC",
|
||||
// Directory for saving exported logs, defaults to `$HOME`, this is automatically *correctly* calculated for Linux, Mac, and Windows
|
||||
@@ -251,6 +251,19 @@
|
||||
// Ports & IP listing text
|
||||
"text": "white"
|
||||
},
|
||||
// The filter panel
|
||||
"filter": {
|
||||
// Background color of panel
|
||||
"background": "reset",
|
||||
// color of text
|
||||
"text": "gray",
|
||||
// background color of the selected filter by item (Name/Image/Status/All)
|
||||
"selected_filter_background": "gray",
|
||||
// text color of the selected filter by item (Name/Image/Status/All)
|
||||
"selected_filter_text": "black",
|
||||
// Highlighted text color
|
||||
"highlight": "magenta"
|
||||
},
|
||||
// The logs panel, will only be applied if color_logs is false
|
||||
"logs": {
|
||||
// Background color of panel
|
||||
|
||||
@@ -163,6 +163,20 @@ running_healthy ="green"
|
||||
running_unhealthy="#FFB224"
|
||||
unknown="red"
|
||||
|
||||
# The filter panel
|
||||
[colors.filter]
|
||||
# Background color of panel
|
||||
background = "reset"
|
||||
# color of text
|
||||
text="gray"
|
||||
# background color of the selected filter by item (Name/Image/Status/All)
|
||||
selected_filter_background="gray"
|
||||
# text color of the selected filter by item (Name/Image/Status/All)
|
||||
selected_filter_text="black"
|
||||
# Highlighted text color
|
||||
highlight="magenta"
|
||||
|
||||
|
||||
# The color the of Docker commands available for each container
|
||||
[colors.commands]
|
||||
# Background color of panel
|
||||
|
||||
@@ -73,6 +73,22 @@ impl From<Option<ConfigColors>> for AppColors {
|
||||
Self::map_color(ep.text.as_deref(), &mut app_colors.popup_error.text);
|
||||
}
|
||||
|
||||
// Filter panel
|
||||
if let Some(fc) = config_colors.filter {
|
||||
Self::map_color(fc.background.as_deref(), &mut app_colors.filter.background);
|
||||
Self::map_color(fc.highlight.as_deref(), &mut app_colors.filter.highlight);
|
||||
|
||||
Self::map_color(
|
||||
fc.selected_filter_background.as_deref(),
|
||||
&mut app_colors.filter.selected_filter_background,
|
||||
);
|
||||
Self::map_color(
|
||||
fc.selected_filter_text.as_deref(),
|
||||
&mut app_colors.filter.selected_filter_text,
|
||||
);
|
||||
Self::map_color(fc.text.as_deref(), &mut app_colors.filter.text);
|
||||
}
|
||||
|
||||
// Help Popup
|
||||
if let Some(hp) = config_colors.popup_help {
|
||||
Self::map_color(
|
||||
@@ -221,6 +237,7 @@ optional_config_struct!(
|
||||
ConfigCommands, background, pause, restart, stop, delete, resume, start;
|
||||
ConfigContainers, background, icon, text, text_rx, text_tx;
|
||||
ConfigContainerState, background, dead, exited, paused, removing, restarting, running_healthy, running_unhealthy, unknown;
|
||||
ConfigFilter, background, text, selected_filter_background, selected_filter_text, highlight;
|
||||
ConfigHeadersBar, background, loading_spinner, text, text_selected;
|
||||
ConfigLogs, background, text
|
||||
);
|
||||
@@ -233,6 +250,7 @@ config_struct!(
|
||||
Commands, background, pause, restart, stop, delete, resume, start;
|
||||
Containers, background, icon, text, text_rx, text_tx;
|
||||
ContainerState, dead, exited, paused, removing, restarting, running_healthy, running_unhealthy, unknown;
|
||||
Filter, background, text, selected_filter_background, selected_filter_text, highlight;
|
||||
HeadersBar, background, text_selected, loading_spinner, text;
|
||||
Logs, background, text;
|
||||
PopupDelete, background, text, text_highlight;
|
||||
@@ -250,6 +268,7 @@ pub struct ConfigColors {
|
||||
commands: Option<ConfigCommands>,
|
||||
container_state: Option<ConfigContainerState>,
|
||||
containers: Option<ConfigContainers>,
|
||||
filter: Option<ConfigFilter>,
|
||||
headers_bar: Option<ConfigHeadersBar>,
|
||||
logs: Option<ConfigLogs>,
|
||||
popup_delete: Option<ConfigBackgroundTextHighlight>,
|
||||
@@ -365,6 +384,19 @@ impl ContainerState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Default colours for the filter panel
|
||||
impl Filter {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
background: Color::Reset,
|
||||
highlight: Color::Magenta,
|
||||
selected_filter_background: Color::Gray,
|
||||
selected_filter_text: Color::Black,
|
||||
text: Color::Gray,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Default colours for the logs panel, only applied if color_logs is false
|
||||
impl Logs {
|
||||
const fn new() -> Self {
|
||||
@@ -426,6 +458,7 @@ pub struct AppColors {
|
||||
pub commands: Commands,
|
||||
pub container_state: ContainerState,
|
||||
pub containers: Containers,
|
||||
pub filter: Filter,
|
||||
pub headers_bar: HeadersBar,
|
||||
pub logs: Logs,
|
||||
pub popup_delete: PopupDelete,
|
||||
@@ -444,6 +477,7 @@ impl AppColors {
|
||||
commands: Commands::new(),
|
||||
container_state: ContainerState::new(),
|
||||
containers: Containers::new(),
|
||||
filter: Filter::new(),
|
||||
headers_bar: HeadersBar::new(),
|
||||
logs: Logs::new(),
|
||||
popup_delete: PopupDelete::new(),
|
||||
|
||||
+15
-1
@@ -30,7 +30,7 @@ host = "/var/run/docker.sock"
|
||||
# Display the container logs timestamp with a given timezone, if timezone is unknown, defaults to UTC
|
||||
timezone = "Etc/UTC"
|
||||
|
||||
# Display the timestamp in a custom format, if given option is invalid, it will default to %Y-%m-%dT%H:%M:%S.%8f -> 2025-02-18T12:34:56.01234567
|
||||
# Display the timestamp in a custom format, if given option is invalid, it will default to %Y-%m-%dT%H:%M:%S.%8f -> 2025-02-18T12:34:56.012345678Z
|
||||
# *Should* accept any valid strftime string up to 32 chars
|
||||
timestamp_format="%Y-%m-%dT%H:%M:%S.%8f"
|
||||
|
||||
@@ -163,6 +163,20 @@ running_healthy ="green"
|
||||
running_unhealthy="#FFB224"
|
||||
unknown="red"
|
||||
|
||||
# The filter panel
|
||||
[colors.filter]
|
||||
# Background color of panel
|
||||
background = "reset"
|
||||
# color of text
|
||||
text="gray"
|
||||
# background color of the selected filter by item (Name/Image/Status/All)
|
||||
selected_filter_background="gray"
|
||||
# text color of the selected filter by item (Name/Image/Status/All)
|
||||
selected_filter_text="black"
|
||||
# Highlighted text color
|
||||
highlight="magenta"
|
||||
|
||||
|
||||
# The color the of Docker commands available for each container
|
||||
[colors.commands]
|
||||
# Background color of panel
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
use ratatui::{
|
||||
layout::Rect,
|
||||
style::{Color, Modifier, Style},
|
||||
style::{Modifier, Style, Stylize},
|
||||
text::{Line, Span},
|
||||
Frame,
|
||||
};
|
||||
|
||||
use crate::{app_data::FilterBy, ui::FrameData};
|
||||
use crate::{app_data::FilterBy, config::AppColors, ui::FrameData};
|
||||
|
||||
/// Create the filter_by by spans, coloured dependant on which one is selected
|
||||
fn filter_by_spans(fd: &FrameData) -> [Span; 4] {
|
||||
let selected = Style::default().bg(Color::Gray).fg(Color::Black);
|
||||
let not_selected = Style::default().bg(Color::Reset).fg(Color::Reset);
|
||||
fn filter_by_spans(colors: AppColors, fd: &FrameData) -> [Span; 4] {
|
||||
let selected = Style::default()
|
||||
.bg(colors.filter.selected_filter_background)
|
||||
.fg(colors.filter.selected_filter_text);
|
||||
let not_selected = Style::default()
|
||||
.bg(colors.filter.background)
|
||||
.fg(colors.filter.text);
|
||||
|
||||
let name = [" Name ", " Image ", " Status ", " All "];
|
||||
|
||||
@@ -31,9 +35,13 @@ fn filter_by_spans(fd: &FrameData) -> [Span; 4] {
|
||||
}
|
||||
|
||||
/// Draw the filter bar
|
||||
pub fn draw(area: Rect, frame: &mut Frame, fd: &FrameData) {
|
||||
let style_but = Style::default().fg(Color::Black).bg(Color::Magenta);
|
||||
let style_desc = Style::default().fg(Color::Gray).bg(Color::Reset);
|
||||
pub fn draw(area: Rect, colors: AppColors, frame: &mut Frame, fd: &FrameData) {
|
||||
let style_but = Style::default()
|
||||
.fg(colors.filter.selected_filter_text)
|
||||
.bg(colors.filter.highlight);
|
||||
let style_desc = Style::default()
|
||||
.fg(colors.filter.text)
|
||||
.bg(colors.filter.background);
|
||||
|
||||
let mut line = vec![
|
||||
Span::styled(" Esc ", style_but),
|
||||
@@ -41,22 +49,22 @@ pub fn draw(area: Rect, frame: &mut Frame, fd: &FrameData) {
|
||||
Span::styled(" ← by → ", style_but),
|
||||
Span::from(" "),
|
||||
];
|
||||
line.extend_from_slice(&filter_by_spans(fd));
|
||||
line.extend_from_slice(&filter_by_spans(colors, fd));
|
||||
line.extend_from_slice(&[
|
||||
Span::styled(
|
||||
" term: ",
|
||||
Style::default()
|
||||
.fg(Color::Magenta)
|
||||
.fg(colors.filter.highlight)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::styled(
|
||||
fd.filter_term
|
||||
.as_ref()
|
||||
.map_or(String::new(), std::clone::Clone::clone),
|
||||
Style::default().fg(Color::Gray),
|
||||
Style::default().fg(colors.filter.text),
|
||||
),
|
||||
]);
|
||||
frame.render_widget(Line::from(line), area);
|
||||
frame.render_widget(Line::from(line).bg(colors.filter.background), area);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -65,9 +73,12 @@ mod tests {
|
||||
|
||||
use ratatui::style::{Color, Modifier};
|
||||
|
||||
use crate::ui::{
|
||||
draw_blocks::tests::{expected_to_vec, get_result, test_setup},
|
||||
FrameData,
|
||||
use crate::{
|
||||
config::AppColors,
|
||||
ui::{
|
||||
draw_blocks::tests::{expected_to_vec, get_result, test_setup},
|
||||
FrameData,
|
||||
},
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -85,7 +96,7 @@ mod tests {
|
||||
setup
|
||||
.terminal
|
||||
.draw(|f| {
|
||||
super::draw(setup.area, f, &setup.fd);
|
||||
super::draw(setup.area, AppColors::new(), f, &setup.fd);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -97,12 +108,13 @@ mod tests {
|
||||
let expected_row = expected_to_vec(&expected, row_index);
|
||||
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
||||
assert_eq!(result_cell.symbol(), expected_row[result_cell_index]);
|
||||
|
||||
match result_cell_index {
|
||||
0..=4 | 12..=19 => {
|
||||
assert_eq!(result_cell.bg, Color::Magenta);
|
||||
assert_eq!(result_cell.fg, Color::Black);
|
||||
}
|
||||
5..=11 => {
|
||||
5..=11 | 27..=46 => {
|
||||
assert_eq!(result_cell.bg, Color::Reset);
|
||||
assert_eq!(result_cell.fg, Color::Gray);
|
||||
}
|
||||
@@ -131,7 +143,7 @@ mod tests {
|
||||
setup
|
||||
.terminal
|
||||
.draw(|f| {
|
||||
super::draw(setup.area, f, &fd);
|
||||
super::draw(setup.area, AppColors::new(), f, &fd);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -149,7 +161,7 @@ mod tests {
|
||||
assert_eq!(result_cell.bg, Color::Magenta);
|
||||
assert_eq!(result_cell.fg, Color::Black);
|
||||
}
|
||||
5..=11 | 54..=55 => {
|
||||
5..=11 | 27..=46 | 54..=55 => {
|
||||
assert_eq!(result_cell.bg, Color::Reset);
|
||||
assert_eq!(result_cell.fg, Color::Gray);
|
||||
}
|
||||
@@ -170,13 +182,13 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// Test when filter_by chances
|
||||
// Test when filter_by changes
|
||||
setup.app_data.lock().filter_by_next();
|
||||
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
|
||||
setup
|
||||
.terminal
|
||||
.draw(|f| {
|
||||
super::draw(setup.area, f, &fd);
|
||||
super::draw(setup.area, AppColors::new(), f, &fd);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
@@ -188,13 +200,12 @@ mod tests {
|
||||
let expected_row = expected_to_vec(&expected, row_index);
|
||||
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
||||
assert_eq!(result_cell.symbol(), expected_row[result_cell_index]);
|
||||
|
||||
match result_cell_index {
|
||||
0..=4 | 12..=19 => {
|
||||
assert_eq!(result_cell.bg, Color::Magenta);
|
||||
assert_eq!(result_cell.fg, Color::Black);
|
||||
}
|
||||
5..=11 | 54..=55 => {
|
||||
5..=11 | 21..=26 | 34..=46 | 54..=55 => {
|
||||
assert_eq!(result_cell.bg, Color::Reset);
|
||||
assert_eq!(result_cell.fg, Color::Gray);
|
||||
}
|
||||
@@ -215,4 +226,68 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// Make sure custom colors are applied
|
||||
fn test_draw_blocks_filter_row_custom_colors() {
|
||||
let (w, h) = (140, 1);
|
||||
let mut setup = test_setup(w, h, true, true);
|
||||
|
||||
setup
|
||||
.gui_state
|
||||
.lock()
|
||||
.status_push(crate::ui::Status::Filter);
|
||||
|
||||
setup.app_data.lock().filter_term_push('c');
|
||||
setup.app_data.lock().filter_term_push('d');
|
||||
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
|
||||
|
||||
let mut colors = AppColors::new();
|
||||
colors.filter.background = Color::White;
|
||||
colors.filter.highlight = Color::Blue;
|
||||
colors.filter.selected_filter_background = Color::Red;
|
||||
colors.filter.selected_filter_text = Color::Yellow;
|
||||
colors.filter.text = Color::Magenta;
|
||||
|
||||
setup
|
||||
.terminal
|
||||
.draw(|f| {
|
||||
super::draw(setup.area, colors, f, &fd);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let expected = [
|
||||
" Esc clear ← by → Name Image Status All term: cd "
|
||||
];
|
||||
|
||||
for (row_index, result_row) in get_result(&setup, w) {
|
||||
let expected_row = expected_to_vec(&expected, row_index);
|
||||
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
||||
assert_eq!(result_cell.symbol(), expected_row[result_cell_index]);
|
||||
match result_cell_index {
|
||||
0..=4 | 12..=19 => {
|
||||
assert_eq!(result_cell.bg, Color::Blue);
|
||||
assert_eq!(result_cell.fg, Color::Yellow);
|
||||
}
|
||||
5..=11 | 27..=46 | 54..=55 => {
|
||||
assert_eq!(result_cell.bg, Color::White);
|
||||
assert_eq!(result_cell.fg, Color::Magenta);
|
||||
}
|
||||
21..=26 => {
|
||||
assert_eq!(result_cell.bg, Color::Red);
|
||||
assert_eq!(result_cell.fg, Color::Yellow);
|
||||
}
|
||||
47..=53 => {
|
||||
assert_eq!(result_cell.bg, Color::White);
|
||||
assert_eq!(result_cell.fg, Color::Blue);
|
||||
assert_eq!(result_cell.modifier, Modifier::BOLD);
|
||||
}
|
||||
_ => {
|
||||
assert_eq!(result_cell.bg, Color::White);
|
||||
assert_eq!(result_cell.fg, Color::Reset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -380,7 +380,7 @@ fn draw_frame(
|
||||
|
||||
// Draw filter bar
|
||||
if let Some(rect) = whole_layout.get(2) {
|
||||
draw_blocks::filter::draw(*rect, f, fd);
|
||||
draw_blocks::filter::draw(*rect, colors, f, fd);
|
||||
}
|
||||
|
||||
if let Some(id) = fd.delete_confirm.as_ref() {
|
||||
|
||||
Reference in New Issue
Block a user