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-z>": "Suspend",
},
"ExplorerActive": {
"<q>": "Quit",
"<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit",
"<Ctrl-z>": "Suspend",
},
"Empty": {
"<q>": "Quit",
"<Ctrl-d>": "Quit",
"<Ctrl-c>": "Quit",
"<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,
SetMode(crate::app::Mode),
//MenuItem(bool),
GetNodeName,
GetSyncState,

View File

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

View File

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

View File

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

View File

@ -34,15 +34,15 @@ pub struct ExplorerBlocks {
is_active: bool,
used_paragraph_index: usize,
used_block_index: Option<usize>,
used_block_index: Option<(usize, u32)>,
used_ext_index: Option<(String, usize, usize)>,
}
impl ExplorerBlocks {
const MAX_BLOCKS: usize = 50;
const LENGTH_OF_BLOCK_HASH: u16 = 66; // hash + 0x prefix
const LENGTH_OF_ADDRESS: u16 = 49;
const TOTAL_OFFSETS: u16 = 18;
const MAX_BLOCKS: usize = 50;
const LENGTH_OF_BLOCK_HASH: u16 = 66; // hash + 0x prefix
const LENGTH_OF_ADDRESS: u16 = 49;
const TOTAL_OFFSETS: u16 = 18;
fn update_validator_list(&mut self, validators: Vec<String>) -> Result<()> {
self.validators = validators;
@ -125,19 +125,14 @@ impl ExplorerBlocks {
let number_hex_str = number_hex_str.trim_start_matches("0x");
let block_number = u32::from_str_radix(&number_hex_str, 16)?;
if !self.blocks.is_empty() {
for current_block_info in self.blocks.iter_mut() {
if current_block_info.block_number <= block_number {
*current_block_info = BlockInfo {
block_number: current_block_info.block_number,
hash: hash.clone(),
finalized: true,
};
self.extrinsics.insert(hash.clone(), extrinsics.clone());
self.logs.insert(hash.clone(), logs.clone());
} else {
break;
}
for idx in 0..self.blocks.len() {
if self.blocks[idx].finalized { break; }
else if self.blocks[idx].block_number > block_number { continue; }
else {
self.blocks[idx].finalized = true;
self.blocks[idx].hash = hash.clone();
self.extrinsics.insert(hash.clone(), extrinsics.clone());
self.logs.insert(hash.clone(), logs.clone());
}
}
@ -145,74 +140,85 @@ impl ExplorerBlocks {
}
fn prepare_block_line_info(&self, current_block: &BlockInfo, width: u16) -> Line {
let block_number_length = self
.max_block_len
.max(current_block.block_number.checked_ilog10().unwrap_or(0) + 1) as usize;
let block_number_length = self
.max_block_len
.max(current_block.block_number.checked_ilog10().unwrap_or(0) + 1) as usize;
let free_space = width
.saturating_sub(block_number_length as u16)
.saturating_sub(Self::TOTAL_OFFSETS);
let free_space = width
.saturating_sub(block_number_length as u16)
.saturating_sub(Self::TOTAL_OFFSETS);
let author = self
.logs
.get(&current_block.hash)
.map_or(String::from("..."), |maybe_logs| {
self.get_author_from_digest(maybe_logs.to_vec())
.map_or(String::from("..."), |maybe_author| maybe_author)
let author = self
.logs
.get(&current_block.hash)
.map_or(String::from("..."), |maybe_logs| {
self.get_author_from_digest(maybe_logs.to_vec())
.map_or(String::from("..."), |maybe_author| maybe_author)
});
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_hash = (free_space - len_for_author) / 2;
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_hash = (free_space - len_for_author) / 2;
let hash_to_print = format!("{}...{}",
&current_block.hash[..len_for_hash as usize],
&current_block.hash[(Self::LENGTH_OF_BLOCK_HASH - len_for_hash) as usize..]);
let hash_to_print = format!("{}...{}",
&current_block.hash[..len_for_hash as usize],
&current_block.hash[(Self::LENGTH_OF_BLOCK_HASH - len_for_hash) as usize..]);
if &author == "..." {
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$}",
if &author == "..." {
Line::raw(format!("{:^left$}| {} | {:^right$}",
current_block.block_number,
current_block.hash,
author))
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.hash,
author))
}
}
fn prepare_block_lines(&mut self, rect: Rect) -> Vec<Line> {
let width = rect.as_size().width;
let total_length = rect.as_size().height - 2;
let mut total_index = 0;
let total_length = rect.as_size().height as usize - 2;
let mut items = Vec::new();
let active_style = self.palette.create_text_style(true);
let latest_style = self.palette.create_text_style(false);
let finalized_style = Style::new().fg(self.palette.foreground_hover());
for current_block_info in self.blocks.iter() {
if total_length == total_index { break; }
let start_index = match self.used_block_index {
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 {
if total_index as usize == used_block_index { active_style } else { latest_style }
} else {
if current_block_info.finalized { finalized_style } else { latest_style }
for (idx, current_block_info) in self.blocks.iter().skip(start_index).enumerate() {
if idx == total_length { break; }
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));
total_index += 1;
}
items
@ -229,17 +235,22 @@ impl ExplorerBlocks {
fn prepare_ext_lines(&mut self, rect: Rect) -> Vec<Line> {
let width = rect.as_size().width;
let total_length = rect.as_size().height - 2;
let mut total_index = 0;
let mut total_length = rect.as_size().height - 2;
let mut items = Vec::new();
let normal_style = self.palette.create_text_style(false);
let active_style = self.palette.create_text_style(true);
if let Some((used_block_hash, _, _)) = &self.used_ext_index {
if let Some(exts) = self.extrinsics.get(used_block_hash) {
if let Some((_, used_block_number)) = self.used_block_index {
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() {
if total_length == total_index { break; }
if total_length == 0 { break; }
let style = if let Some((_, _, used_ext_index)) = self.used_ext_index {
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));
total_index += 1;
total_length -= 1;
}
}
}
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) {
let new_index = self.used_paragraph_index + 1;
if new_index < 2 {
@ -264,8 +292,10 @@ impl ExplorerBlocks {
}
fn move_left(&mut self) {
self.used_paragraph_index = self.used_paragraph_index
self.used_paragraph_index = self
.used_paragraph_index
.saturating_sub(1);
self.used_ext_index = None;
}
fn move_down(&mut self) {
@ -285,54 +315,6 @@ impl ExplorerBlocks {
}
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 {
Some((header, block_index, used_index)) => {
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) {
self.used_block_index = match &self.used_block_index {
Some(used_index) => {
if *used_index == 0 { return }
let new_index = used_index - 1;
self.blocks.get(new_index).map(|_| new_index)
Some((used_index, used_block)) => {
Some(self.blocks
.iter()
.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(
&mut self,
_place: Rect,
place: Rect,
border_style: Color,
border_type: BorderType,
) -> Paragraph {
let title_style = self.palette.create_title_style();
Paragraph::new("")
Paragraph::new(self.prepare_event_lines(place))
.block(Block::bordered()
.border_style(border_style)
.border_type(border_type)
@ -441,16 +473,16 @@ impl ExplorerBlocks {
impl Component for ExplorerBlocks {
fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> {
match key.code {
KeyCode::Char('k') | KeyCode::Up => self.move_up(),
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('h') | KeyCode::Left if self.is_active => self.move_left(),
KeyCode::Esc => {
self.used_block_index = None;
self.used_ext_index = None;
self.used_paragraph_index = 0;
},
_ => {},
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('l') | KeyCode::Right if self.is_active => self.move_right(),
KeyCode::Char('h') | KeyCode::Left if self.is_active => self.move_left(),
KeyCode::Esc => {
self.used_block_index = None;
self.used_ext_index = None;
self.used_paragraph_index = 0;
},
_ => {},
};
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::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::SetMode(Mode::Explorer(true)) if !self.is_active => self.set_active()?,
Action::SetMode(Mode::Explorer(false)) if self.is_active => self.unset_active()?,
Action::SetMode(Mode::ExplorerActive) if !self.is_active => self.set_active()?,
Action::SetMode(_) if self.is_active => self.unset_active()?,
_ => {}
};
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_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);
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 crossterm::event::KeyEvent;
use ratatui::{
layout::{Constraint, Flex, Layout, Rect},
Frame,
@ -44,6 +45,13 @@ impl Default 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>> {
for component in self.components.iter_mut() {
component.update(action.clone())?;

View File

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