fixed bug with screen actions and added the ability to move though table rows

Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
Uncle Stretch 2024-11-19 18:36:43 +03:00
parent b1d7add8a3
commit 1508ed818f
Signed by: str3tch
GPG Key ID: 84F3190747EE79AA
8 changed files with 207 additions and 154 deletions

View File

@ -6,11 +6,23 @@
"<Ctrl-c>": "Quit", "<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend", "<Ctrl-z>": "Suspend",
}, },
"ExplorerActive": {
"<q>": "Quit",
"<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend",
},
"Empty": { "Empty": {
"<q>": "Quit", "<q>": "Quit",
"<Ctrl-d>": "Quit", "<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit", "<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend", "<Ctrl-z>": "Suspend",
},
"EmptyActive": {
"<q>": "Quit",
"<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend",
} }
} }
} }

View File

@ -19,7 +19,6 @@ pub enum Action {
Help, Help,
SetMode(crate::app::Mode), SetMode(crate::app::Mode),
//MenuItem(bool),
GetNodeName, GetNodeName,
GetSyncState, GetSyncState,

View File

@ -17,13 +17,15 @@ use crate::{
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Mode { pub enum Mode {
Explorer(#[serde(skip)] bool), Explorer,
Empty(#[serde(skip)] bool), ExplorerActive,
Empty,
EmptyActive,
} }
impl Default for Mode { impl Default for Mode {
fn default() -> Self { fn default() -> Self {
Self::Explorer(false) Self::Explorer
} }
} }
@ -233,7 +235,7 @@ impl App {
} }
match self.mode { match self.mode {
Mode::Explorer(_) => { Mode::Explorer | Mode::ExplorerActive => {
if let Some(component) = self.components.get_mut(4) { if let Some(component) = self.components.get_mut(4) {
if let Err(err) = component.draw(frame, frame.area()) { if let Err(err) = component.draw(frame, frame.area()) {
let _ = self let _ = self

View File

@ -98,8 +98,8 @@ impl Empty {
impl Component for Empty { impl Component for Empty {
fn update(&mut self, action: Action) -> Result<Option<Action>> { fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action { match action {
Action::SetMode(Mode::Empty(true)) if !self.is_active => self.set_active()?, Action::SetMode(Mode::EmptyActive) if !self.is_active => self.set_active()?,
Action::SetMode(Mode::Empty(false)) if self.is_active => self.unset_active()?, Action::SetMode(_) if self.is_active => self.unset_active()?,
_ => {} _ => {}
}; };
Ok(None) Ok(None)

View File

@ -1,5 +1,4 @@
use color_eyre::Result; use color_eyre::Result;
use std::time::Instant;
use ratatui::{ use ratatui::{
layout::{Alignment, Rect}, layout::{Alignment, Rect},
text::Line, text::Line,

View File

@ -34,15 +34,15 @@ pub struct ExplorerBlocks {
is_active: bool, is_active: bool,
used_paragraph_index: usize, used_paragraph_index: usize,
used_block_index: Option<usize>, used_block_index: Option<(usize, u32)>,
used_ext_index: Option<(String, usize, usize)>, used_ext_index: Option<(String, usize, usize)>,
} }
impl ExplorerBlocks { impl ExplorerBlocks {
const MAX_BLOCKS: usize = 50; const MAX_BLOCKS: usize = 50;
const LENGTH_OF_BLOCK_HASH: u16 = 66; // hash + 0x prefix const LENGTH_OF_BLOCK_HASH: u16 = 66; // hash + 0x prefix
const LENGTH_OF_ADDRESS: u16 = 49; const LENGTH_OF_ADDRESS: u16 = 49;
const TOTAL_OFFSETS: u16 = 18; const TOTAL_OFFSETS: u16 = 18;
fn update_validator_list(&mut self, validators: Vec<String>) -> Result<()> { fn update_validator_list(&mut self, validators: Vec<String>) -> Result<()> {
self.validators = validators; self.validators = validators;
@ -125,19 +125,14 @@ impl ExplorerBlocks {
let number_hex_str = number_hex_str.trim_start_matches("0x"); let number_hex_str = number_hex_str.trim_start_matches("0x");
let block_number = u32::from_str_radix(&number_hex_str, 16)?; let block_number = u32::from_str_radix(&number_hex_str, 16)?;
if !self.blocks.is_empty() { for idx in 0..self.blocks.len() {
for current_block_info in self.blocks.iter_mut() { if self.blocks[idx].finalized { break; }
if current_block_info.block_number <= block_number { else if self.blocks[idx].block_number > block_number { continue; }
*current_block_info = BlockInfo { else {
block_number: current_block_info.block_number, self.blocks[idx].finalized = true;
hash: hash.clone(), self.blocks[idx].hash = hash.clone();
finalized: true, self.extrinsics.insert(hash.clone(), extrinsics.clone());
}; self.logs.insert(hash.clone(), logs.clone());
self.extrinsics.insert(hash.clone(), extrinsics.clone());
self.logs.insert(hash.clone(), logs.clone());
} else {
break;
}
} }
} }
@ -145,74 +140,85 @@ impl ExplorerBlocks {
} }
fn prepare_block_line_info(&self, current_block: &BlockInfo, width: u16) -> Line { fn prepare_block_line_info(&self, current_block: &BlockInfo, width: u16) -> Line {
let block_number_length = self let block_number_length = self
.max_block_len .max_block_len
.max(current_block.block_number.checked_ilog10().unwrap_or(0) + 1) as usize; .max(current_block.block_number.checked_ilog10().unwrap_or(0) + 1) as usize;
let free_space = width let free_space = width
.saturating_sub(block_number_length as u16) .saturating_sub(block_number_length as u16)
.saturating_sub(Self::TOTAL_OFFSETS); .saturating_sub(Self::TOTAL_OFFSETS);
let author = self let author = self
.logs .logs
.get(&current_block.hash) .get(&current_block.hash)
.map_or(String::from("..."), |maybe_logs| { .map_or(String::from("..."), |maybe_logs| {
self.get_author_from_digest(maybe_logs.to_vec()) self.get_author_from_digest(maybe_logs.to_vec())
.map_or(String::from("..."), |maybe_author| maybe_author) .map_or(String::from("..."), |maybe_author| maybe_author)
}); });
if free_space < Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS { if free_space < Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS {
let len_for_author = free_space * Self::LENGTH_OF_ADDRESS / (Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS); let len_for_author = free_space * Self::LENGTH_OF_ADDRESS / (Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS);
let len_for_hash = (free_space - len_for_author) / 2; let len_for_hash = (free_space - len_for_author) / 2;
let hash_to_print = format!("{}...{}", let hash_to_print = format!("{}...{}",
&current_block.hash[..len_for_hash as usize], &current_block.hash[..len_for_hash as usize],
&current_block.hash[(Self::LENGTH_OF_BLOCK_HASH - len_for_hash) as usize..]); &current_block.hash[(Self::LENGTH_OF_BLOCK_HASH - len_for_hash) as usize..]);
if &author == "..." { if &author == "..." {
Line::raw(format!("{:^left$}| {} | {:^right$}", Line::raw(format!("{:^left$}| {} | {:^right$}",
current_block.block_number,
hash_to_print,
author,
left=block_number_length,
right=(len_for_author + 2) as usize))
} else {
Line::raw(format!("{} | {} | {}",
current_block.block_number,
hash_to_print,
format!("{}...", &author[..(len_for_author) as usize])))
}
} else {
let total_space_used = block_number_length as u16 + Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS;
let margin = (width - total_space_used) as usize / 3;
Line::raw(format!("{:^margin$}|{:^margin$}|{:^margin$}",
current_block.block_number, current_block.block_number,
current_block.hash, hash_to_print,
author)) author,
left=block_number_length,
right=(len_for_author + 2) as usize))
} else {
Line::raw(format!("{} | {} | {}",
current_block.block_number,
hash_to_print,
format!("{}...", &author[..(len_for_author) as usize])))
} }
} else {
let total_space_used = block_number_length as u16 + Self::LENGTH_OF_BLOCK_HASH + Self::LENGTH_OF_ADDRESS;
let margin = (width - total_space_used) as usize / 3;
Line::raw(format!("{:^margin$}|{:^margin$}|{:^margin$}",
current_block.block_number,
current_block.hash,
author))
}
} }
fn prepare_block_lines(&mut self, rect: Rect) -> Vec<Line> { fn prepare_block_lines(&mut self, rect: Rect) -> Vec<Line> {
let width = rect.as_size().width; let width = rect.as_size().width;
let total_length = rect.as_size().height - 2; let total_length = rect.as_size().height as usize - 2;
let mut total_index = 0;
let mut items = Vec::new(); let mut items = Vec::new();
let active_style = self.palette.create_text_style(true); let active_style = self.palette.create_text_style(true);
let latest_style = self.palette.create_text_style(false); let latest_style = self.palette.create_text_style(false);
let finalized_style = Style::new().fg(self.palette.foreground_hover()); let finalized_style = Style::new().fg(self.palette.foreground_hover());
for current_block_info in self.blocks.iter() { let start_index = match self.used_block_index {
if total_length == total_index { break; } Some((_, used_block)) if total_length < self.blocks.len() => {
self.blocks
.iter()
.position(|b| b.block_number == used_block)
.unwrap_or_default()
.saturating_add(1)
.saturating_sub(total_length)
},
_ => 0,
};
let style = if let Some(used_block_index) = self.used_block_index { for (idx, current_block_info) in self.blocks.iter().skip(start_index).enumerate() {
if total_index as usize == used_block_index { active_style } else { latest_style } if idx == total_length { break; }
} else {
if current_block_info.finalized { finalized_style } else { latest_style } let style = match self.used_block_index {
Some((_, used_block)) if current_block_info.block_number == used_block => active_style,
_ => {
if current_block_info.finalized { finalized_style } else { latest_style }
}
}; };
items.push(self.prepare_block_line_info(&current_block_info, width).style(style)); items.push(self.prepare_block_line_info(&current_block_info, width).style(style));
total_index += 1;
} }
items items
@ -229,17 +235,22 @@ impl ExplorerBlocks {
fn prepare_ext_lines(&mut self, rect: Rect) -> Vec<Line> { fn prepare_ext_lines(&mut self, rect: Rect) -> Vec<Line> {
let width = rect.as_size().width; let width = rect.as_size().width;
let total_length = rect.as_size().height - 2; let mut total_length = rect.as_size().height - 2;
let mut total_index = 0;
let mut items = Vec::new(); let mut items = Vec::new();
let normal_style = self.palette.create_text_style(false); let normal_style = self.palette.create_text_style(false);
let active_style = self.palette.create_text_style(true); let active_style = self.palette.create_text_style(true);
if let Some((used_block_hash, _, _)) = &self.used_ext_index { if let Some((_, used_block_number)) = self.used_block_index {
if let Some(exts) = self.extrinsics.get(used_block_hash) { let hash = self.blocks
.iter()
.find(|b| b.block_number == used_block_number)
.map(|b| b.hash.clone())
.unwrap_or_default();
if let Some(exts) = self.extrinsics.get(&hash) {
for (index, ext) in exts.iter().enumerate() { for (index, ext) in exts.iter().enumerate() {
if total_length == total_index { break; } if total_length == 0 { break; }
let style = if let Some((_, _, used_ext_index)) = self.used_ext_index { let style = if let Some((_, _, used_ext_index)) = self.used_ext_index {
if index == used_ext_index { active_style } else { normal_style } if index == used_ext_index { active_style } else { normal_style }
@ -248,14 +259,31 @@ impl ExplorerBlocks {
}; };
items.push(self.prepare_ext_line_info(0, ext.to_string(), width).style(style)); items.push(self.prepare_ext_line_info(0, ext.to_string(), width).style(style));
total_index += 1; total_length -= 1;
} }
} }
} }
items items
} }
fn prepare_event_lines(&mut self, rect: Rect) -> Line {
let _width = rect.as_size().width;
let style = self.palette.create_text_style(false);
if let Some((hash, _, ext_index)) = &self.used_ext_index {
if let Some(exts) = &self.extrinsics.get(&hash.clone()) {
Line::from(format!("{}", exts.get(*ext_index).unwrap_or(&String::from("nothing here")))).style(style)
} else {
Line::from("nothing here")
}
} else {
Line::from("nothing here")
}
}
fn move_right(&mut self) { fn move_right(&mut self) {
let new_index = self.used_paragraph_index + 1; let new_index = self.used_paragraph_index + 1;
if new_index < 2 { if new_index < 2 {
@ -264,8 +292,10 @@ impl ExplorerBlocks {
} }
fn move_left(&mut self) { fn move_left(&mut self) {
self.used_paragraph_index = self.used_paragraph_index self.used_paragraph_index = self
.used_paragraph_index
.saturating_sub(1); .saturating_sub(1);
self.used_ext_index = None;
} }
fn move_down(&mut self) { fn move_down(&mut self) {
@ -285,54 +315,6 @@ impl ExplorerBlocks {
} }
fn move_up_extrinsics(&mut self) { fn move_up_extrinsics(&mut self) {
match &self.used_ext_index {
Some((header, block_index, used_index)) => {
let new_index = used_index + 1;
let maybe_exts = self.extrinsics.get(&*header);
if maybe_exts.is_none() { return }
let exts = maybe_exts.unwrap();
let found = exts
.get(new_index)
.is_some();
if found && new_index < exts.len() {
self.used_ext_index =
Some(((&*header).clone(), *block_index, new_index));
}
},
None => {
self.used_ext_index = self.blocks
.front()
.map(|block| {
self.extrinsics
.get(&block.hash)
.map(|_| (block.hash.clone(), 0, 0))
})
.flatten()
}
}
}
fn move_up_blocks(&mut self) {
match &self.used_block_index {
Some(used_index) => {
let new_index = used_index + 1;
let maybe_new_extrinsic = self.blocks.get(new_index);
if new_index < self.blocks.len() && maybe_new_extrinsic.is_some() {
self.used_block_index = maybe_new_extrinsic.map(|_| new_index);
}
},
None => {
self.used_block_index = self.blocks
.front()
.map(|_| 0);
}
}
}
fn move_down_extrinsics(&mut self) {
match &self.used_ext_index { match &self.used_ext_index {
Some((header, block_index, used_index)) => { Some((header, block_index, used_index)) => {
if *used_index == 0 { return } if *used_index == 0 { return }
@ -365,14 +347,64 @@ impl ExplorerBlocks {
} }
} }
fn move_up_blocks(&mut self) {
self.used_block_index = match &self.used_block_index {
Some((used_index, used_block)) => {
Some(self.blocks
.iter()
.enumerate()
.find(|(_, b)| b.block_number == used_block + 1)
.map(|(idx, b)| (idx, b.block_number))
.unwrap_or((*used_index, *used_block)))
},
None => self.blocks.front().map(|b| (0usize, b.block_number)),
}
}
fn move_down_extrinsics(&mut self) {
match &self.used_ext_index {
Some((header, block_index, used_index)) => {
let new_index = used_index + 1;
let maybe_exts = self.extrinsics.get(&*header);
if maybe_exts.is_none() { return }
let exts = maybe_exts.unwrap();
let found = exts
.get(new_index)
.is_some();
if found && new_index < exts.len() {
self.used_ext_index =
Some(((&*header).clone(), *block_index, new_index));
}
},
None => {
self.used_ext_index = self.blocks
.front()
.map(|block| {
self.extrinsics
.get(&block.hash)
.map(|_| (block.hash.clone(), 0, 0))
})
.flatten()
}
}
}
fn move_down_blocks(&mut self) { fn move_down_blocks(&mut self) {
self.used_block_index = match &self.used_block_index { self.used_block_index = match &self.used_block_index {
Some(used_index) => { Some((used_index, used_block)) => {
if *used_index == 0 { return } Some(self.blocks
let new_index = used_index - 1; .iter()
self.blocks.get(new_index).map(|_| new_index) .enumerate()
.find(|(_, b)| b.block_number == used_block.saturating_sub(1))
.map(|(idx, b)| (idx, b.block_number))
.unwrap_or((*used_index, *used_block)))
}, },
None => self.blocks.front().map(|_| 0), None => {
self.blocks.front().map(|b| (0usize, b.block_number))
}
} }
} }
@ -422,12 +454,12 @@ impl ExplorerBlocks {
fn prepare_event_paragraph( fn prepare_event_paragraph(
&mut self, &mut self,
_place: Rect, place: Rect,
border_style: Color, border_style: Color,
border_type: BorderType, border_type: BorderType,
) -> Paragraph { ) -> Paragraph {
let title_style = self.palette.create_title_style(); let title_style = self.palette.create_title_style();
Paragraph::new("") Paragraph::new(self.prepare_event_lines(place))
.block(Block::bordered() .block(Block::bordered()
.border_style(border_style) .border_style(border_style)
.border_type(border_type) .border_type(border_type)
@ -441,16 +473,16 @@ impl ExplorerBlocks {
impl Component for ExplorerBlocks { impl Component for ExplorerBlocks {
fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> { fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> {
match key.code { match key.code {
KeyCode::Char('k') | KeyCode::Up => self.move_up(), KeyCode::Char('k') | KeyCode::Up if self.is_active => self.move_up(),
KeyCode::Char('j') | KeyCode::Down if self.is_active => self.move_down(), KeyCode::Char('j') | KeyCode::Down if self.is_active => self.move_down(),
KeyCode::Char('l') | KeyCode::Right if self.is_active => self.move_right(), KeyCode::Char('l') | KeyCode::Right if self.is_active => self.move_right(),
KeyCode::Char('h') | KeyCode::Left if self.is_active => self.move_left(), KeyCode::Char('h') | KeyCode::Left if self.is_active => self.move_left(),
KeyCode::Esc => { KeyCode::Esc => {
self.used_block_index = None; self.used_block_index = None;
self.used_ext_index = None; self.used_ext_index = None;
self.used_paragraph_index = 0; self.used_paragraph_index = 0;
}, },
_ => {}, _ => {},
}; };
Ok(None) Ok(None)
@ -461,8 +493,8 @@ impl Component for ExplorerBlocks {
Action::SetLatestBlock(hash, block) => self.update_latest_block_info(hash, block.header.number, block.header.digest.logs, block.extrinsics)?, Action::SetLatestBlock(hash, block) => self.update_latest_block_info(hash, block.header.number, block.header.digest.logs, block.extrinsics)?,
Action::SetFinalizedBlock(hash, block) => self.update_finalized_block_info(hash, block.header.number, block.header.digest.logs, block.extrinsics)?, Action::SetFinalizedBlock(hash, block) => self.update_finalized_block_info(hash, block.header.number, block.header.digest.logs, block.extrinsics)?,
Action::SetValidators(validators) => self.update_validator_list(validators)?, Action::SetValidators(validators) => self.update_validator_list(validators)?,
Action::SetMode(Mode::Explorer(true)) if !self.is_active => self.set_active()?, Action::SetMode(Mode::ExplorerActive) if !self.is_active => self.set_active()?,
Action::SetMode(Mode::Explorer(false)) if self.is_active => self.unset_active()?, Action::SetMode(_) if self.is_active => self.unset_active()?,
_ => {} _ => {}
}; };
Ok(None) Ok(None)
@ -474,6 +506,7 @@ impl Component for ExplorerBlocks {
let (border_style_block, border_type_block) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 0); let (border_style_block, border_type_block) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 0);
let (border_style_extrinsics, border_type_extrinsics) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 1); let (border_style_extrinsics, border_type_extrinsics) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 1);
// TODO: never used, revisit
let (border_style_event, border_type_event) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 2); let (border_style_event, border_type_event) = self.palette.create_border_style(self.is_active && self.used_paragraph_index == 2);
frame.render_widget(self.prepare_blocks_paragraph(blocks_place, border_style_block, border_type_block), blocks_place); frame.render_widget(self.prepare_blocks_paragraph(blocks_place, border_style_block, border_type_block), blocks_place);

View File

@ -1,4 +1,5 @@
use color_eyre::Result; use color_eyre::Result;
use crossterm::event::KeyEvent;
use ratatui::{ use ratatui::{
layout::{Constraint, Flex, Layout, Rect}, layout::{Constraint, Flex, Layout, Rect},
Frame, Frame,
@ -44,6 +45,13 @@ impl Default for Explorer {
} }
impl Component for Explorer { impl Component for Explorer {
fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> {
for component in self.components.iter_mut() {
component.handle_key_event(key)?;
}
Ok(None)
}
fn update(&mut self, action: Action) -> Result<Option<Action>> { fn update(&mut self, action: Action) -> Result<Option<Action>> {
for component in self.components.iter_mut() { for component in self.components.iter_mut() {
component.update(action.clone())?; component.update(action.clone())?;

View File

@ -47,8 +47,8 @@ impl Menu {
if let Some(command_tx) = &self.command_tx { if let Some(command_tx) = &self.command_tx {
match self.current_item_index { match self.current_item_index {
0 => command_tx.send(Action::SetMode(Mode::Explorer(false)))?, 0 => command_tx.send(Action::SetMode(Mode::Explorer))?,
_ => command_tx.send(Action::SetMode(Mode::Empty(false)))?, _ => command_tx.send(Action::SetMode(Mode::Empty))?,
} }
}; };
Ok(()) Ok(())
@ -62,8 +62,8 @@ impl Menu {
if let Some(command_tx) = &self.command_tx { if let Some(command_tx) = &self.command_tx {
match self.current_item_index { match self.current_item_index {
0 => command_tx.send(Action::SetMode(Mode::Explorer(false)))?, 0 => command_tx.send(Action::SetMode(Mode::Explorer))?,
_ => command_tx.send(Action::SetMode(Mode::Empty(false)))?, _ => command_tx.send(Action::SetMode(Mode::Empty))?,
} }
}; };
Ok(()) Ok(())
@ -73,8 +73,8 @@ impl Menu {
self.is_active = true; self.is_active = true;
if let Some(command_tx) = &self.command_tx { if let Some(command_tx) = &self.command_tx {
match self.current_item_index { match self.current_item_index {
0 => command_tx.send(Action::SetMode(Mode::Explorer(false)))?, 0 => command_tx.send(Action::SetMode(Mode::Explorer))?,
_ => command_tx.send(Action::SetMode(Mode::Empty(false)))?, _ => command_tx.send(Action::SetMode(Mode::Empty))?,
} }
}; };
Ok(()) Ok(())
@ -84,8 +84,8 @@ impl Menu {
self.is_active = false; self.is_active = false;
if let Some(command_tx) = &self.command_tx { if let Some(command_tx) = &self.command_tx {
match self.current_item_index { match self.current_item_index {
0 => command_tx.send(Action::SetMode(Mode::Explorer(true)))?, 0 => command_tx.send(Action::SetMode(Mode::ExplorerActive))?,
_ => command_tx.send(Action::SetMode(Mode::Empty(true)))?, _ => command_tx.send(Action::SetMode(Mode::EmptyActive))?,
} }
}; };
Ok(()) Ok(())