use std::sync::Arc;
use parking_lot::Mutex;
use ratatui::{
Frame,
layout::{Alignment, Rect},
style::{Modifier, Style, Stylize},
widgets::{List, Paragraph},
};
use crate::{
app_data::AppData,
config::AppColors,
ui::{FrameData, GuiState, SelectablePanel, Status},
};
use super::{SELECT_ARROW, generate_block};
pub fn draw(
app_data: &Arc<Mutex<AppData>>,
area: Rect,
colors: AppColors,
f: &mut Frame,
fd: &FrameData,
gui_state: &Arc<Mutex<GuiState>>,
) {
let mut block = generate_block(area, colors, fd, gui_state, SelectablePanel::Logs);
if !fd.color_logs {
block = block.bg(colors.logs.background);
}
if fd.status.contains(&Status::Init) {
let mut paragraph = Paragraph::new(format!("parsing logs {}", fd.loading_icon))
.block(block)
.alignment(Alignment::Center);
if !fd.color_logs {
paragraph = paragraph.fg(colors.logs.text);
}
f.render_widget(paragraph, area);
} else {
let padding = usize::from(area.height / 5);
let logs = app_data.lock().get_logs(area.as_size(), padding);
if logs.is_empty() {
let mut paragraph = Paragraph::new("no logs found")
.block(block)
.alignment(Alignment::Center);
if !fd.color_logs {
paragraph = paragraph.fg(colors.logs.text);
}
f.render_widget(paragraph, area);
} else if fd.color_logs {
let items = List::new(logs)
.block(block)
.highlight_symbol(SELECT_ARROW)
.scroll_padding(padding)
.highlight_style(Style::default().add_modifier(Modifier::BOLD));
if let Some(log_state) = app_data.lock().get_log_state() {
f.render_stateful_widget(items, area, log_state);
}
} else {
let items = List::new(logs)
.fg(colors.logs.text)
.block(block)
.highlight_symbol(SELECT_ARROW)
.highlight_style(Style::default().add_modifier(Modifier::BOLD));
if let Some(log_state) = app_data.lock().get_log_state() {
f.render_stateful_widget(items, area, log_state);
}
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use insta::assert_snapshot;
use ratatui::style::{Color, Modifier};
use uuid::Uuid;
use crate::{
app_data::{ContainerImage, ContainerName, ScrollDirection},
config::AppColors,
ui::{
FrameData, Status,
draw_blocks::tests::{BORDER_CHARS, get_result, insert_logs, test_setup},
},
};
#[test]
fn test_draw_blocks_logs_none() {
let mut setup = test_setup(35, 6, true, true);
let colors = setup.app_data.lock().config.app_colors;
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&setup.fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
match (row_index, result_cell_index) {
(0 | 5, 0..=34) | (1..=4, 0) | (1..=5, 34) => {
assert_eq!(result_cell.bg, Color::Reset);
assert_eq!(result_cell.fg, Color::Gray);
}
_ => {
assert_eq!(result_cell.fg, Color::Reset);
assert_eq!(result_cell.bg, Color::Reset);
}
}
}
}
setup
.gui_state
.lock()
.selectable_panel_next(&setup.app_data);
setup
.gui_state
.lock()
.selectable_panel_next(&setup.app_data);
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
for (_, result_row) in get_result(&setup) {
for result_cell in result_row {
if BORDER_CHARS.contains(&result_cell.symbol()) {
assert_eq!(result_cell.fg, Color::LightCyan);
}
}
}
}
#[test]
fn test_draw_blocks_logs_parsing_frame_one() {
let mut setup = test_setup(32, 6, true, true);
let uuid = Uuid::new_v4();
setup.gui_state.lock().next_loading(uuid);
let mut fd = FrameData::from((&setup.app_data, &setup.gui_state));
fd.status.insert(Status::Init);
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
AppColors::new(),
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
match (row_index, result_cell_index) {
(0, 0..=31) | (1..=4, 0) | (1..=5, 31) | (5, 0..=30) => {
assert_eq!(result_cell.bg, Color::Reset);
assert_eq!(result_cell.fg, Color::Gray);
}
_ => {
assert_eq!(result_cell.fg, Color::Reset);
assert_eq!(result_cell.bg, Color::Reset);
}
}
}
}
}
#[test]
fn test_draw_blocks_logs_parsing_frame_two() {
let mut setup = test_setup(32, 6, true, true);
let uuid = Uuid::new_v4();
setup.gui_state.lock().next_loading(uuid);
let mut fd = FrameData::from((&setup.app_data, &setup.gui_state));
fd.status.insert(Status::Init);
setup.gui_state.lock().next_loading(uuid);
let mut fd = FrameData::from((&setup.app_data, &setup.gui_state));
fd.status.insert(Status::Init);
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
AppColors::new(),
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
match (row_index, result_cell_index) {
(0, 0..=31) | (1..=4, 0) | (1..=5, 31) | (5, 0..=30) => {
assert_eq!(result_cell.bg, Color::Reset);
assert_eq!(result_cell.fg, Color::Gray);
}
_ => {
assert_eq!(result_cell.fg, Color::Reset);
assert_eq!(result_cell.bg, Color::Reset);
}
}
}
}
}
#[test]
fn test_draw_blocks_logs_some_line_three() {
let mut setup = test_setup(36, 6, true, true);
insert_logs(&setup);
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
AppColors::new(),
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Reset);
if let (1..=4, 1..=34) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Reset);
} else {
assert_eq!(result_cell.fg, Color::Gray);
}
if row_index == 3 && (1..=34).contains(&result_cell_index) {
assert_eq!(result_cell.modifier, Modifier::BOLD);
} else {
assert!(result_cell.modifier.is_empty());
}
}
}
}
#[test]
fn test_draw_blocks_logs_some_line_two() {
let mut setup = test_setup(36, 6, true, true);
insert_logs(&setup);
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
AppColors::new(),
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
setup.app_data.lock().log_scroll(&ScrollDirection::Up);
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
AppColors::new(),
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Reset);
if let (1..=4, 1..=34) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Reset);
} else {
assert_eq!(result_cell.fg, Color::Gray);
}
if row_index == 2 && (1..=34).contains(&result_cell_index) {
assert_eq!(result_cell.modifier, Modifier::BOLD);
} else {
assert!(result_cell.modifier.is_empty());
}
}
}
}
#[test]
fn test_draw_blocks_logs_long_name() {
let mut setup = test_setup(80, 6, true, true);
setup.app_data.lock().containers.items[0].name =
ContainerName::from("a_long_container_name_for_the_purposes_of_this_test");
setup.app_data.lock().containers.items[0].image =
ContainerImage::from("a_long_image_name_for_the_purposes_of_this_test");
insert_logs(&setup);
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
AppColors::new(),
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
}
#[test]
fn test_draw_blocks_logs_custom_colors_parsing() {
let mut setup = test_setup(32, 6, true, true);
let uuid = Uuid::new_v4();
setup.gui_state.lock().next_loading(uuid);
let mut fd = FrameData::from((&setup.app_data, &setup.gui_state));
fd.status.insert(Status::Init);
let mut colors = AppColors::new();
colors.logs.background = Color::Green;
colors.logs.text = Color::Black;
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Green);
if let (1..=4, 1..=29) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Black);
}
}
}
fd.color_logs = true;
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Reset);
if let (1..=4, 1..=29) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Reset);
}
}
}
}
#[test]
fn test_draw_blocks_logs_custom_colors_no_logs() {
let mut setup = test_setup(35, 6, true, true);
let mut colors = AppColors::new();
colors.logs.background = Color::Green;
colors.logs.text = Color::Black;
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&setup.fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Green);
if let (1..=4, 1..=29) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Black);
}
}
}
setup.fd.color_logs = true;
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&setup.fd,
&setup.gui_state,
);
})
.unwrap();
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Reset);
if let (1..=4, 1..=29) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Reset);
}
}
}
}
#[test]
fn test_draw_blocks_logs_custom_colors_logs() {
let mut setup = test_setup(36, 6, true, true);
insert_logs(&setup);
let mut colors = setup.app_data.lock().config.app_colors;
colors.logs.background = Color::Green;
colors.logs.text = Color::Black;
let mut fd = FrameData::from((&setup.app_data, &setup.gui_state));
fd.color_logs = true;
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
assert_snapshot!(setup.terminal.backend());
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Reset);
if let (1..=4, 1..=34) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Reset);
if row_index == 3 && (1..=34).contains(&result_cell_index) {
assert_eq!(result_cell.modifier, Modifier::BOLD);
} else {
assert!(result_cell.modifier.is_empty());
}
}
}
}
fd.color_logs = false;
setup
.terminal
.draw(|f| {
super::draw(
&setup.app_data,
setup.area,
colors,
f,
&fd,
&setup.gui_state,
);
})
.unwrap();
for (row_index, result_row) in get_result(&setup) {
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
assert_eq!(result_cell.bg, Color::Green);
if let (1..=4, 1..=34) = (row_index, result_cell_index) {
assert_eq!(result_cell.fg, Color::Black);
if row_index == 3 && (1..=34).contains(&result_cell_index) {
assert_eq!(result_cell.modifier, Modifier::BOLD);
} else {
assert!(result_cell.modifier.is_empty());
}
}
}
}
}
}