diff --git a/src/app/dashboard/mod.rs b/src/app/dashboard/mod.rs index 7e5010e..f460f82 100644 --- a/src/app/dashboard/mod.rs +++ b/src/app/dashboard/mod.rs @@ -39,6 +39,8 @@ pub struct DashBoard<'a, CI: ChainInfo> { pub selected_pallet: Option<(u8, String)>, pub tab_titles: Vec, pub selected_tab: usize, + pub pallet_info_titles: Vec, + pub selected_pallet_info_tab: usize, } impl<'a, CI: ChainInfo> DashBoard<'a, CI> { @@ -61,6 +63,14 @@ impl<'a, CI: ChainInfo> DashBoard<'a, CI> { selected_pallet: None, tab_titles: vec![String::from("Blocks"), String::from("Events"), String::from("Pallets")], selected_tab: 0, + pallet_info_titles: vec![ + String::from("Constants"), + String::from("Events"), + String::from("Errors"), + String::from("Storages"), + String::from("Calls"), + ], + selected_pallet_info_tab: 0, } } @@ -186,6 +196,15 @@ where }, _ => {}, }, + KeyCode::Right => + if dash_board.selected_tab == 2 { + dash_board.selected_pallet_info_tab = + (dash_board.selected_pallet_info_tab + 1) % dash_board.pallet_info_titles.len(); + }, + KeyCode::Left => + if dash_board.selected_tab == 2 && dash_board.selected_pallet_info_tab > 0 { + dash_board.selected_pallet_info_tab -= 1; + }, _ => {}, } } diff --git a/src/app/dashboard/tab_pallets.rs b/src/app/dashboard/tab_pallets.rs index d7522f9..b6a8882 100644 --- a/src/app/dashboard/tab_pallets.rs +++ b/src/app/dashboard/tab_pallets.rs @@ -4,14 +4,15 @@ use ratatui::{ style::Stylize, widgets::*, }; +use scale_info::TypeDef; // this crate use super::DashBoard; -use crate::networks::ChainInfo; +use crate::{handler::print_storage_type, networks::ChainInfo}; pub fn draw_pallets_tab(f: &mut Frame, app: &mut DashBoard, area: Rect) { let chunks = Layout::default() .direction(Direction::Horizontal) - .constraints(vec![Constraint::Percentage(30), Constraint::Percentage(70)]) + .constraints(vec![Constraint::Percentage(20), Constraint::Percentage(80)]) .split(area); render_pallet_list(f, app, chunks[0]); @@ -29,7 +30,6 @@ fn render_pallet_list(f: &mut Frame, app: &mut DashBoard, are let l = List::new(pallets) .block( Block::default() - .title(" Pallets ") .title_style(Style::default().bold().italic()) .borders(Borders::ALL) .border_type(BorderType::Double) @@ -40,15 +40,229 @@ fn render_pallet_list(f: &mut Frame, app: &mut DashBoard, are .highlight_symbol("> "); f.render_stateful_widget(l, area, &mut app.pallets.state); } -fn render_pallet_info(f: &mut Frame, _app: &mut DashBoard, area: Rect) { - let block_style = Block::default() - .title(" Pallet Details ") +fn render_pallet_info(f: &mut Frame, dash_board: &mut DashBoard, area: Rect) { + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref()) + .split(area); + let titles = dash_board + .pallet_info_titles + .iter() + .map(|t| Line::from(Span::styled(t, Style::default().fg(Color::Yellow).bold()))) + .collect(); + let tabs = Tabs::new(titles) + .block( + Block::default() + .title(" Pallet Information ") + .title_style(Style::default().bold().italic()) + .border_type(BorderType::Double) + .borders(Borders::ALL), + ) + .select(dash_board.selected_pallet_info_tab) + .style(Style::default().fg(Color::Yellow)) + .highlight_style(Style::default().fg(Color::Cyan)); + f.render_widget(tabs, chunks[0]); + + match dash_board.selected_pallet_info_tab { + 0 => render_pallet_constants_page(f, dash_board, chunks[1]), + 1 => render_pallet_events_page(f, dash_board, chunks[1]), + 2 => render_pallet_errors_page(f, dash_board, chunks[1]), + 3 => render_pallet_storages_page(f, dash_board, chunks[1]), + 4 => render_pallet_calls_page(f, dash_board, chunks[1]), + _ => {}, + }; +} +fn render_pallet_constants_page(f: &mut Frame, dash_board: &mut DashBoard, area: Rect) { + let block_style = default_block_style(); + if let Some((id, name)) = dash_board.selected_pallet.clone() { + let pallet = dash_board.metadata.pallets().find(|p| p.name() == name && p.index() == id); + if let Some(pallet) = pallet { + let constants: Vec = pallet + .constants() + .map(|c| { + let ty_id = c.ty(); + let mut bytes = c.value(); + let value = scale_value::scale::decode_as_type(&mut bytes, ty_id, dash_board.metadata.types()).unwrap(); + ListItem::new(vec![Line::from(Span::styled(format!("> {} : {}", c.name(), value), Style::default().fg(Color::Yellow)))]) + }) + .collect(); + + if !constants.is_empty() { + let l = List::new(constants).block(block_style); + f.render_widget(l, area); + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area); + } + } + } +} +fn render_pallet_events_page(f: &mut Frame, dash_board: &mut DashBoard, area: Rect) { + let block_style = default_block_style(); + if let Some((id, name)) = dash_board.selected_pallet.clone() { + let pallet = dash_board.metadata.pallets().find(|p| p.name() == name && p.index() == id); + if let Some(pallet) = pallet { + let event_type = pallet.event_ty_id(); + if let Some(event_type) = event_type { + let events = dash_board.metadata.types().resolve(event_type); + if let Some(t) = events { + let enums: Vec = match &t.type_def { + TypeDef::Variant(def_variant) => def_variant + .variants + .iter() + .map(|v| { + ListItem::new(vec![Line::from(Span::styled( + format!("> {}", v.name.to_string()), + Style::default().fg(Color::Yellow), + ))]) + }) + .collect(), + _ => { + vec![] + }, + }; + + if !enums.is_empty() { + let l = List::new(enums).block(block_style); + f.render_widget(l, area); + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area); + } + } + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area) + } + } + } +} +fn render_pallet_errors_page(f: &mut Frame, dash_board: &mut DashBoard, area: Rect) { + let block_style = default_block_style(); + if let Some((id, name)) = dash_board.selected_pallet.clone() { + let pallet = dash_board.metadata.pallets().find(|p| p.name() == name && p.index() == id); + if let Some(pallet) = pallet { + let error_type = pallet.error_ty_id(); + if let Some(error_type) = error_type { + let errors = dash_board.metadata.types().resolve(error_type); + if let Some(t) = errors { + let enums: Vec = match &t.type_def { + TypeDef::Variant(def_variant) => def_variant + .variants + .iter() + .map(|v| { + ListItem::new(vec![Line::from(Span::styled( + format!("> {}", v.name.to_string()), + Style::default().fg(Color::Yellow), + ))]) + }) + .collect(), + _ => { + vec![] + }, + }; + + if !enums.is_empty() { + let l = List::new(enums).block(block_style); + f.render_widget(l, area); + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area); + } + } + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area) + } + } + } +} +fn render_pallet_storages_page(f: &mut Frame, dash_board: &mut DashBoard, area: Rect) { + let block_style = default_block_style(); + if let Some((id, name)) = dash_board.selected_pallet.clone() { + let pallet = dash_board.metadata.pallets().find(|p| p.name() == name && p.index() == id); + if let Some(pallet) = pallet { + if let Some(s) = pallet.storage() { + let storages: Vec = s + .entries() + .iter() + .map(|e| { + ListItem::new(vec![Line::from(Span::styled( + format!("> {} : {}", e.name(), &print_storage_type(e.entry_type().clone(), dash_board.metadata)), + Style::default().fg(Color::Yellow), + ))]) + }) + .collect(); + + if !storages.is_empty() { + let l = List::new(storages).block(block_style); + f.render_widget(l, area); + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area); + } + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area); + } + } + } +} +fn render_pallet_calls_page(f: &mut Frame, dash_board: &mut DashBoard, area: Rect) { + let block_style = default_block_style(); + if let Some((id, name)) = dash_board.selected_pallet.clone() { + let pallet = dash_board.metadata.pallets().find(|p| p.name() == name && p.index() == id); + if let Some(pallet) = pallet { + let call_type = pallet.call_ty_id(); + if let Some(call_type) = call_type { + let calls = dash_board.metadata.types().resolve(call_type); + if let Some(c) = calls { + let enums: Vec = match &c.type_def { + TypeDef::Variant(def_variant) => def_variant + .variants + .iter() + .map(|v| { + ListItem::new(vec![Line::from(Span::styled( + format!("> {}", v.name.to_string()), + Style::default().fg(Color::Yellow), + ))]) + }) + .collect(), + _ => { + vec![] + }, + }; + + if !enums.is_empty() { + let l = List::new(enums).block(block_style); + f.render_widget(l, area); + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area); + } + } + } else { + let text = "None".to_string(); + let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); + f.render_widget(paragraph, area) + } + } + } +} + +fn default_block_style<'a>() -> Block<'a> { + Block::default() .title_style(Style::default().bold().italic()) .borders(Borders::ALL) .border_type(BorderType::Double) - .style(Style::default().fg(Color::Yellow)); - - let text = "Pallets Details Page".to_string(); - let paragraph = Paragraph::new(text).block(block_style).wrap(Wrap { trim: true }); - f.render_widget(paragraph, area); + .padding(Padding::horizontal(2)) + .style(Style::default().fg(Color::Yellow)) } diff --git a/src/handler/mod.rs b/src/handler/mod.rs index a5e2cc6..20c94a9 100644 --- a/src/handler/mod.rs +++ b/src/handler/mod.rs @@ -1,5 +1,7 @@ mod printer; +pub use crate::handler::printer::print_storage_type; + // std use std::{ fs::File, @@ -30,7 +32,7 @@ use crate::{ RuntimeCommand, POLKADOT_CLI, }, errors::AppError, - handler::printer::{print_result, print_storage_type, print_usage}, + handler::printer::{print_result, print_usage}, networks::{ChainInfo, Network}, rpc::{single_map_storage_key, AccountBalances, AccountNonce, ChainApi, RpcClient, RpcError, StateApi, SubscribeApi, SystemApi}, };