Automatically hide columns if they do not fit
All checks were successful
Build and deploy / Build container and manifests (push) Successful in 6m4s
All checks were successful
Build and deploy / Build container and manifests (push) Successful in 6m4s
This commit is contained in:
parent
413d9f2157
commit
61d57d6de1
|
@ -1,4 +1,5 @@
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
#![feature(iter_intersperse)]
|
||||||
mod helper;
|
mod helper;
|
||||||
mod io;
|
mod io;
|
||||||
pub mod ldap;
|
pub mod ldap;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::cmp::{self, max};
|
use std::cmp::{self, max};
|
||||||
use std::io::Write as _;
|
use std::io::Write as _;
|
||||||
|
use std::iter::once;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
@ -37,6 +38,42 @@ struct RendererInner {
|
||||||
rx: UnboundedReceiver<Message>,
|
rx: UnboundedReceiver<Message>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_widths(rows: &Vec<Vec<Span<'static>>>) -> Vec<u16> {
|
||||||
|
let table_header = Tunnel::header();
|
||||||
|
std::iter::once(&table_header)
|
||||||
|
.chain(rows)
|
||||||
|
.map(|row| row.iter().map(|cell| cell.width() as u16))
|
||||||
|
.fold(vec![0; table_header.len()], |acc, row| {
|
||||||
|
acc.into_iter()
|
||||||
|
.zip(row)
|
||||||
|
.map(|v| cmp::max(v.0, v.1))
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_column_skip(
|
||||||
|
widths: &[u16],
|
||||||
|
column_spacing: u16,
|
||||||
|
highlight_symbol: usize,
|
||||||
|
max_width: u16,
|
||||||
|
) -> (usize, usize) {
|
||||||
|
for pattern in [(7, 0), (4, 0), (4, 1), (4, 2)] {
|
||||||
|
let width: u16 = widths
|
||||||
|
.iter()
|
||||||
|
.take(pattern.0)
|
||||||
|
.skip(pattern.1)
|
||||||
|
.intersperse(&column_spacing)
|
||||||
|
.chain(once(&(highlight_symbol as u16)))
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
if width <= max_width {
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(4, 3)
|
||||||
|
}
|
||||||
|
|
||||||
impl RendererInner {
|
impl RendererInner {
|
||||||
fn new(rx: UnboundedReceiver<Message>) -> Self {
|
fn new(rx: UnboundedReceiver<Message>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -109,22 +146,6 @@ impl RendererInner {
|
||||||
(height as u16, Paragraph::new(text).centered().block(block))
|
(height as u16, Paragraph::new(text).centered().block(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_widths(&mut self, rows: &Vec<Vec<Span<'static>>>) -> Vec<Constraint> {
|
|
||||||
let table_header = Tunnel::header();
|
|
||||||
std::iter::once(&table_header)
|
|
||||||
.chain(rows)
|
|
||||||
.map(|row| row.iter().map(|cell| cell.width() as u16))
|
|
||||||
.fold(vec![0; table_header.len()], |acc, row| {
|
|
||||||
acc.into_iter()
|
|
||||||
.zip(row)
|
|
||||||
.map(|v| cmp::max(v.0, v.1))
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.into_iter()
|
|
||||||
.map(|c| Constraint::Length(c + 1))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&mut self, frame: &mut Frame) {
|
fn render(&mut self, frame: &mut Frame) {
|
||||||
self.render_title(frame, frame.area());
|
self.render_title(frame, frame.area());
|
||||||
|
|
||||||
|
@ -153,15 +174,41 @@ impl RendererInner {
|
||||||
let highlight_style = Style::default().bold();
|
let highlight_style = Style::default().bold();
|
||||||
let header_style = Style::default().bold().reversed();
|
let header_style = Style::default().bold().reversed();
|
||||||
let row_style = Style::default();
|
let row_style = Style::default();
|
||||||
|
let highlight_symbol = Line::from("> ");
|
||||||
|
let column_spacing = 3;
|
||||||
|
|
||||||
let r = self
|
let rows = self
|
||||||
.rows
|
.rows
|
||||||
.iter()
|
.iter()
|
||||||
.map(From::from)
|
.map(From::from)
|
||||||
.collect::<Vec<Vec<Span<'static>>>>();
|
.collect::<Vec<Vec<Span<'static>>>>();
|
||||||
|
|
||||||
let rows = r.iter().map(|row| {
|
let widths = compute_widths(&rows);
|
||||||
|
let (take, skip) = compute_column_skip(
|
||||||
|
&widths,
|
||||||
|
column_spacing,
|
||||||
|
highlight_symbol.width(),
|
||||||
|
rect.width,
|
||||||
|
);
|
||||||
|
|
||||||
|
let constraints: Vec<_> = widths
|
||||||
|
.into_iter()
|
||||||
|
.take(take)
|
||||||
|
.enumerate()
|
||||||
|
.map(|(index, width)| {
|
||||||
|
if index == 3 {
|
||||||
|
Constraint::Min(width)
|
||||||
|
} else {
|
||||||
|
Constraint::Length(width)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.skip(skip)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let rows = rows.iter().map(|row| {
|
||||||
row.iter()
|
row.iter()
|
||||||
|
.take(take)
|
||||||
|
.skip(skip)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(Cell::from)
|
.map(Cell::from)
|
||||||
.collect::<Row>()
|
.collect::<Row>()
|
||||||
|
@ -171,6 +218,8 @@ impl RendererInner {
|
||||||
|
|
||||||
let header = Tunnel::header()
|
let header = Tunnel::header()
|
||||||
.iter()
|
.iter()
|
||||||
|
.take(take)
|
||||||
|
.skip(skip)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(Cell::from)
|
.map(Cell::from)
|
||||||
.collect::<Row>()
|
.collect::<Row>()
|
||||||
|
@ -181,10 +230,10 @@ impl RendererInner {
|
||||||
.header(header)
|
.header(header)
|
||||||
.rows(rows)
|
.rows(rows)
|
||||||
.flex(Flex::Start)
|
.flex(Flex::Start)
|
||||||
.column_spacing(3)
|
.column_spacing(column_spacing)
|
||||||
.widths(self.compute_widths(&r))
|
.widths(&constraints)
|
||||||
.row_highlight_style(highlight_style)
|
.row_highlight_style(highlight_style)
|
||||||
.highlight_symbol(Line::from("> "))
|
.highlight_symbol(highlight_symbol)
|
||||||
.highlight_spacing(HighlightSpacing::Always);
|
.highlight_spacing(HighlightSpacing::Always);
|
||||||
|
|
||||||
frame.render_stateful_widget(t, rect, &mut self.state);
|
frame.render_stateful_widget(t, rect, &mut self.state);
|
||||||
|
|
|
@ -9,8 +9,8 @@ use crate::io::Stats;
|
||||||
|
|
||||||
pub struct TunnelRow {
|
pub struct TunnelRow {
|
||||||
name: Span<'static>,
|
name: Span<'static>,
|
||||||
access: Span<'static>,
|
|
||||||
port: Span<'static>,
|
port: Span<'static>,
|
||||||
|
access: Span<'static>,
|
||||||
address: Span<'static>,
|
address: Span<'static>,
|
||||||
stats: Arc<Stats>,
|
stats: Arc<Stats>,
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ impl From<&TunnelRow> for Vec<Span<'static>> {
|
||||||
fn from(row: &TunnelRow) -> Self {
|
fn from(row: &TunnelRow) -> Self {
|
||||||
vec![
|
vec![
|
||||||
row.name.clone(),
|
row.name.clone(),
|
||||||
row.access.clone(),
|
|
||||||
row.port.clone(),
|
row.port.clone(),
|
||||||
|
row.access.clone(),
|
||||||
row.address.clone(),
|
row.address.clone(),
|
||||||
row.stats.connections().to_string().into(),
|
row.stats.connections().to_string().into(),
|
||||||
row.stats.rx().to_string().into(),
|
row.stats.rx().to_string().into(),
|
||||||
|
@ -33,8 +33,8 @@ impl Tunnel {
|
||||||
pub fn header() -> Vec<Span<'static>> {
|
pub fn header() -> Vec<Span<'static>> {
|
||||||
vec![
|
vec![
|
||||||
"Name".into(),
|
"Name".into(),
|
||||||
"Access".into(),
|
|
||||||
"Port".into(),
|
"Port".into(),
|
||||||
|
"Access".into(),
|
||||||
"Address".into(),
|
"Address".into(),
|
||||||
"Conn".into(),
|
"Conn".into(),
|
||||||
"Rx".into(),
|
"Rx".into(),
|
||||||
|
@ -56,8 +56,8 @@ impl Tunnel {
|
||||||
|
|
||||||
TunnelRow {
|
TunnelRow {
|
||||||
name: tunnel.registry_entry.get_name().to_string().into(),
|
name: tunnel.registry_entry.get_name().to_string().into(),
|
||||||
access,
|
|
||||||
port: tunnel.inner.port.to_string().into(),
|
port: tunnel.inner.port.to_string().into(),
|
||||||
|
access,
|
||||||
address,
|
address,
|
||||||
stats: tunnel.inner.stats.clone(),
|
stats: tunnel.inner.stats.clone(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user