From 6ddf48591b94345edb39aa554b993589c0f96c7c Mon Sep 17 00:00:00 2001 From: Willem Date: Thu, 17 Apr 2025 09:42:36 -0400 Subject: [PATCH] modified tui-example main --- Cargo.lock | 6 +- examples/tui/src/main.rs | 6 +- harmony_tui/Cargo.toml | 2 + harmony_tui/src/lib.rs | 18 ++++- harmony_tui/src/widget/score.rs | 127 +++++++++++++++++++++++++++++++- 5 files changed, 149 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9c279f..c571489 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1188,6 +1188,8 @@ dependencies = [ "log", "log-panics", "ratatui", + "serde-value", + "serde_json", "tokio", "tokio-stream", "tui-logger", @@ -3026,9 +3028,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", diff --git a/examples/tui/src/main.rs b/examples/tui/src/main.rs index 05a768b..d912844 100644 --- a/examples/tui/src/main.rs +++ b/examples/tui/src/main.rs @@ -1,7 +1,10 @@ use harmony::{ inventory::Inventory, maestro::Maestro, - modules::dummy::{ErrorScore, PanicScore, SuccessScore}, + modules::{ + dns::DnsScore, + dummy::{ErrorScore, PanicScore, SuccessScore}, + }, topology::HAClusterTopology, }; @@ -15,6 +18,7 @@ async fn main() { Box::new(SuccessScore {}), Box::new(ErrorScore {}), Box::new(PanicScore {}), + Box::new(DnsScore::new(vec![], None)), ]); harmony_tui::init(maestro).await.unwrap(); } diff --git a/harmony_tui/Cargo.toml b/harmony_tui/Cargo.toml index a12e534..6aacedd 100644 --- a/harmony_tui/Cargo.toml +++ b/harmony_tui/Cargo.toml @@ -16,3 +16,5 @@ color-eyre = "0.6.3" tokio-stream = "0.1.17" tui-logger = "0.14.1" log-panics = "2.1.0" +serde-value.workspace = true +serde_json = "1.0.140" diff --git a/harmony_tui/src/lib.rs b/harmony_tui/src/lib.rs index 11208f0..462591d 100644 --- a/harmony_tui/src/lib.rs +++ b/harmony_tui/src/lib.rs @@ -14,7 +14,7 @@ use ratatui::{ self, Frame, layout::{Constraint, Layout, Position}, style::{Color, Style}, - widgets::{Block, Borders}, + widgets::{Block, Borders, Paragraph, Wrap}, }; pub mod tui { @@ -159,12 +159,15 @@ impl HarmonyTUI { frame.render_widget(&help_block, help_area); frame.render_widget(HelpWidget::new(), help_block.inner(help_area)); - let [list_area, output_area] = + let [list_area, right_area] = Layout::horizontal([Constraint::Min(30), Constraint::Percentage(100)]).areas(app_area); let block = Block::default().borders(Borders::RIGHT); frame.render_widget(&block, list_area); self.score.render(list_area, frame); + + let [logger_area, info_area] = + Layout::vertical([Constraint::Min(30), Constraint::Percentage(100)]).areas(right_area); let tui_logger = tui_logger::TuiLoggerWidget::default() .style_error(Style::default().fg(Color::Red)) .style_warn(Style::default().fg(Color::LightRed)) @@ -172,7 +175,16 @@ impl HarmonyTUI { .style_debug(Style::default().fg(Color::Gray)) .style_trace(Style::default().fg(Color::Gray)) .state(&self.tui_state); - frame.render_widget(tui_logger, output_area) + + frame.render_widget(tui_logger, logger_area); + + let info = self.score.display_value(); + //let info = self.score.display_value(); + let info_block = Block::default().borders(Borders::ALL).title("Scores Info"); + let info_paragraph = Paragraph::new(info) + .block(info_block) + .wrap(Wrap { trim: true }); + frame.render_widget(info_paragraph, info_area); } fn scores_list(maestro: &Maestro) -> Vec>> { diff --git a/harmony_tui/src/widget/score.rs b/harmony_tui/src/widget/score.rs index b0d2c27..c4d3d63 100644 --- a/harmony_tui/src/widget/score.rs +++ b/harmony_tui/src/widget/score.rs @@ -1,18 +1,22 @@ +use ratatui::layout::Constraint; +use serde_value::Value; +use std::collections::BTreeMap; use std::sync::{Arc, RwLock}; +use crate::HarmonyTuiEvent; use crossterm::event::{Event, KeyCode, KeyEventKind}; use harmony::{score::Score, topology::Topology}; use log::{info, warn}; use ratatui::{ Frame, layout::Rect, - style::{Style, Stylize}, - widgets::{List, ListItem, ListState, StatefulWidget, Widget}, + style::{Modifier, Style, Stylize}, + widgets::{ + Block, Borders, Cell, List, ListItem, ListState, Row, StatefulWidget, Table, Widget, + }, }; use tokio::sync::mpsc; -use crate::HarmonyTuiEvent; - #[derive(Debug)] enum ExecutionState { INITIATED, @@ -64,11 +68,126 @@ impl ScoreListWidget { state: ExecutionState::INITIATED, score: score.clone_box(), }); + //TODO: need to format the output of the score.serialize() + //currently just dumps to MAP() and handle _ + //maybe columns + //https://arcnmx.github.io/serde-value/serde_value/enum.Value.html info!("{:#?}\n\nConfirm Execution (Press y/n)", score); } else { warn!("No Score selected, nothing to launch"); } } + //TODO working on match statement to output serialized value + //want to try and build a fn for a few types that are represtendd in DNSscore + //and output them by calling fn display_values in the about fn + // + //currently outputs info about all available scores, not quite + //looking to output info about the selected score and subscores + // + +fn print_value(&self, val: &Value, indent: usize) -> String { + let pad = " ".repeat(indent * 2); + let mut output = String::new(); + + match val { + Value::Bool(b) => output += &format!("{}{}\n", pad, b), + Value::U8(u) => output += &format!("{}{}\n", pad, u), + Value::U16(u) => output += &format!("{}{}\n", pad, u), + Value::U32(u) => output += &format!("{}{}\n", pad, u), + Value::U64(u) => output += &format!("{}{}\n", pad, u), + Value::I8(i) => output += &format!("{}{}\n", pad, i), + Value::I16(i) => output += &format!("{}{}\n", pad, i), + Value::I32(i) => output += &format!("{}{}\n", pad, i), + Value::I64(i) => output += &format!("{}{}\n", pad, i), + Value::F32(f) => output += &format!("{}{}\n", pad, f), + Value::F64(f) => output += &format!("{}{}\n", pad, f), + Value::Char(c) => output += &format!("{}{}\n", pad, c), + Value::String(s) => output += &format!("{}{}\n", pad, s), + Value::Unit => output += &format!("{}\n", pad), + Value::Bytes(bytes) => output += &format!("{}{:?}\n", pad, bytes), + + Value::Option(opt) => match opt { + Some(inner) => { + output += &format!("{}Option:\n", pad); + output += &self.print_value(inner, indent + 1); + } + None => output += &format!("{}None\n", pad), + }, + + Value::Newtype(inner) => { + output += &format!("{}Newtype:\n", pad); + output += &self.print_value(inner, indent + 1); + } + + Value::Seq(seq) => { + if seq.is_empty() { + output += &format!("{}[]\n", pad); + } else { + output += &format!("{}[\n", pad); + for item in seq { + output += &self.print_value(item, indent + 1); + } + output += &format!("{}]\n", pad); + } + } + + Value::Map(map) => { + if map.is_empty() { + output += &format!("{}\n", pad); + } else { + output += &format!( + "\n{}+--------------------------+----------------------------+\n", + pad + ); + output += &format!( + "{}| {:<24} | {:<26} |\n", + pad, "Key", "Value" + ); + output += &format!( + "{}+--------------------------+----------------------------+\n", + pad + ); + + for (k, v) in map { + let key_str = match k { + Value::String(s) => s.clone(), + other => format!("{:?}", other), + }; + let val_str = match v { + Value::String(s) => s.clone(), + Value::Bool(b) => b.to_string(), + Value::Option(Some(inner)) => format!("{:?}", inner), + Value::Option(None) => "None".to_string(), + Value::Seq(seq) => format!("{:?}", seq), + _ => format!("{:?}", v), + }; + + output += &format!( + "{}| {:<24} | {:<26} |\n", + pad, key_str, val_str + ); + } + + output += &format!( + "{}+--------------------------+----------------------------+\n\n", + pad + ); + } + } + } + + output +} + + pub(crate) fn display_value(&self) -> String { + let mut output = String::new(); + output += "SCORE DETAILS"; + for score in &self.scores { + let val = score.serialize(); + output += &self.print_value(&val, 0); + } + output + } pub(crate) fn scroll_down(&self) { self.list_state.write().unwrap().scroll_down_by(1);