Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package erldash for openSUSE:Factory checked in at 2023-10-22 21:02:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/erldash (Old) and /work/SRC/openSUSE:Factory/.erldash.new.1945 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "erldash" Sun Oct 22 21:02:28 2023 rev:6 rq:1119420 version:0.2.0~0 Changes: -------- --- /work/SRC/openSUSE:Factory/erldash/erldash.changes 2023-10-19 22:52:02.232698607 +0200 +++ /work/SRC/openSUSE:Factory/.erldash.new.1945/erldash.changes 2023-10-22 21:02:52.179493312 +0200 @@ -1,0 +2,8 @@ +Sun Oct 22 10:17:39 UTC 2023 - Michael Vetter <mvet...@suse.com> + +- Update to 0.2.0: + * Display current time in the top-right corner of the dashboard #7 + * Add node name column to the header #8 + * Introduce run and replay subcommands (breaking change) #9 + +------------------------------------------------------------------- Old: ---- erldash-0.1.5~0.tar.xz New: ---- erldash-0.2.0~0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ erldash.spec ++++++ --- /var/tmp/diff_new_pack.iw9L4L/_old 2023-10-22 21:02:53.235531711 +0200 +++ /var/tmp/diff_new_pack.iw9L4L/_new 2023-10-22 21:02:53.239531857 +0200 @@ -17,7 +17,7 @@ Name: erldash -Version: 0.1.5~0 +Version: 0.2.0~0 Release: 0 Summary: A simple, terminal-based Erlang dashboard License: (Apache-2.0 OR MIT) AND MIT AND Apache-2.0 WITH LLVM-exception AND MPL-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.iw9L4L/_old 2023-10-22 21:02:53.267532875 +0200 +++ /var/tmp/diff_new_pack.iw9L4L/_new 2023-10-22 21:02:53.271533020 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/sile/erldash.git</param> <param name="versionformat">@PARENT_TAG@~@TAG_OFFSET@</param> <param name="scm">git</param> - <param name="revision">0.1.5</param> + <param name="revision">0.2.0</param> <param name="match-tag">*</param> <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param> <param name="versionrewrite-replacement">\1</param> ++++++ erldash-0.1.5~0.tar.xz -> erldash-0.2.0~0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/.github/workflows/release.yml new/erldash-0.2.0~0/.github/workflows/release.yml --- old/erldash-0.1.5~0/.github/workflows/release.yml 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/.github/workflows/release.yml 2023-10-21 03:49:17.000000000 +0200 @@ -25,7 +25,7 @@ draft: true linux-binary: - name: 'Uplaod Binary for Linux' + name: 'Upload Binary for Linux' runs-on: ubuntu-latest needs: github-release-draft steps: @@ -59,7 +59,7 @@ asset_content_type: application/octet-stream macos-binary: - name: 'Uplaod Binary for MacOS' + name: 'Upload Binary for MacOS' runs-on: macos-11 # TODO: Use `macos-latest` once it supports `aarch64-apple-darwin` needs: github-release-draft strategy: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/Cargo.lock new/erldash-0.2.0~0/Cargo.lock --- old/erldash-0.1.5~0/Cargo.lock 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/Cargo.lock 2023-10-21 03:49:17.000000000 +0200 @@ -9,6 +9,21 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] name = "anstream" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -221,6 +236,12 @@ ] [[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -233,12 +254,36 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] name = "clap" version = "4.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -294,6 +339,12 @@ ] [[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] name = "crc32fast" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -425,9 +476,10 @@ [[package]] name = "erldash" -version = "0.1.5" +version = "0.2.0" dependencies = [ "anyhow", + "chrono", "clap", "crossterm 0.27.0", "dirs", @@ -612,6 +664,29 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -638,6 +713,15 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] name = "libc" version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -801,6 +885,12 @@ ] [[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1274,6 +1364,60 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1305,6 +1449,15 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + +[[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/Cargo.toml new/erldash-0.2.0~0/Cargo.toml --- old/erldash-0.1.5~0/Cargo.toml 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/Cargo.toml 2023-10-21 03:49:17.000000000 +0200 @@ -1,6 +1,6 @@ [package] name = "erldash" -version = "0.1.5" +version = "0.2.0" edition = "2021" authors = ["Takeru Ohta <phjgt...@gmail.com>"] license = "MIT OR Apache-2.0" @@ -13,6 +13,7 @@ [dependencies] anyhow = "1" +chrono = { version = "0.4.31", features = ["serde"] } clap = { version = "4", features = ["derive"] } crossterm = "0.27" dirs = "5" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/README.md new/erldash-0.2.0~0/README.md --- old/erldash-0.1.5~0/README.md 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/README.md 2023-10-21 03:49:17.000000000 +0200 @@ -32,7 +32,7 @@ ```console // An example to download the binary for Linux. -$ VERSION=... # Set the target erldash version such as "0.1.2" +$ VERSION=... # Set the target erldash version such as "0.2.0" $ curl -L https://github.com/sile/erldash/releases/download/${VERSION}/erldash-${VERSION}.x86_64-unknown-linux-musl -o erldash $ chmod +x erldash $ ./erldash @@ -54,9 +54,11 @@ Just execute the following command: ```console -$ erldash $TARGET_ERLANG_NODE +$ erldash run $TARGET_ERLANG_NODE ``` If you need to specify a cookie value other than `$HOME/.erlang.cookie`, please specify that to `--cookie` option. `$ erldash --help` shows the detailed help message. + +You can record the collected metrics to a file via `--record <FILE>` option and replay the recorded run using `$ erldash replay <FILE>` command. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/src/lib.rs new/erldash-0.2.0~0/src/lib.rs --- old/erldash-0.1.5~0/src/lib.rs 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/src/lib.rs 2023-10-21 03:49:17.000000000 +0200 @@ -4,8 +4,17 @@ pub mod metrics; pub mod ui; -#[derive(Debug, Clone, clap::Parser)] -pub struct Options { +#[derive(Debug, Clone, clap::Subcommand)] +pub enum Command { + /// Run the dashboard. + Run(RunArgs), + + /// Replay a previously recorded dashboard session. + Replay(ReplayArgs), +} + +#[derive(Debug, Clone, clap::Args)] +pub struct RunArgs { /// Target Erlang node name. pub erlang_node: erl_dist::node::NodeName, @@ -22,13 +31,9 @@ /// If specified, the collected metrics will be recorded to the given file and can be replayed later. #[clap(long, value_name = "FILE")] pub record: Option<PathBuf>, - - /// If specified, the recorded metrics will be replayed. - #[clap(long, requires = "record")] - pub replay: bool, } -impl Options { +impl RunArgs { pub fn find_cookie(&self) -> anyhow::Result<String> { if let Some(cookie) = &self.cookie { Ok(cookie.clone()) @@ -37,3 +42,9 @@ } } } + +#[derive(Debug, Clone, clap::Args)] +pub struct ReplayArgs { + /// Path to a file containing recorded metrics. + pub file: PathBuf, +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/src/main.rs new/erldash-0.2.0~0/src/main.rs --- old/erldash-0.1.5~0/src/main.rs 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/src/main.rs 2023-10-21 03:49:17.000000000 +0200 @@ -6,8 +6,8 @@ #[derive(Debug, Parser)] #[clap(version)] struct Args { - #[clap(flatten)] - options: erldash::Options, + #[clap(subcommand)] + command: erldash::Command, #[clap(hide = true, long)] logfile: Option<std::path::PathBuf>, @@ -23,7 +23,7 @@ let args = Args::parse(); setup_logger(&args)?; - let poller = metrics::MetricsPoller::start_thread(args.options)?; + let poller = metrics::MetricsPoller::start_thread(args.command)?; let app = ui::App::new(poller)?; app.run()?; Ok(()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/src/metrics.rs new/erldash-0.2.0~0/src/metrics.rs --- old/erldash-0.1.5~0/src/metrics.rs 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/src/metrics.rs 2023-10-21 03:49:17.000000000 +0200 @@ -1,5 +1,5 @@ use crate::erlang::{MSAccThread, RpcClient, SystemVersion}; -use crate::Options; +use crate::{Command, ReplayArgs, RunArgs}; use anyhow::Context; use serde::{Deserialize, Serialize}; use smol::fs::File; @@ -241,11 +241,10 @@ } impl MetricsPoller { - pub fn start_thread(options: Options) -> anyhow::Result<Self> { - if options.replay { - ReplayMetricsPoller::new(options).map(Self::Replay) - } else { - RealtimeMetricsPoller::start_thread(options).map(Self::Realtime) + pub fn start_thread(command: Command) -> anyhow::Result<Self> { + match command { + Command::Run(args) => RealtimeMetricsPoller::start_thread(args).map(Self::Realtime), + Command::Replay(args) => ReplayMetricsPoller::new(args).map(Self::Replay), } } @@ -253,10 +252,10 @@ matches!(self, Self::Replay(_)) } - pub fn system_version(&self) -> &SystemVersion { + pub fn header(&self) -> &Header { match self { - Self::Realtime(poller) => &poller.system_version, - Self::Replay(poller) => &poller.system_version, + Self::Realtime(poller) => &poller.header, + Self::Replay(poller) => &poller.header, } } @@ -295,28 +294,33 @@ } } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Header { + pub system_version: SystemVersion, + pub node_name: String, + pub start_time: chrono::DateTime<chrono::Local>, +} + #[derive(Debug)] pub struct ReplayMetricsPoller { - system_version: SystemVersion, + header: Header, metrics_log: Vec<Metrics>, } impl ReplayMetricsPoller { - fn new(options: Options) -> anyhow::Result<Self> { - let Some(record_file_path) = options.record else { - anyhow::bail!("`--record` is required for replay mode"); - }; + fn new(args: ReplayArgs) -> anyhow::Result<Self> { + let record_file_path = args.file; let file = std::fs::File::open(&record_file_path).with_context(|| { format!("failed to open record file: {}", record_file_path.display()) })?; let reader = std::io::BufReader::new(file); - let mut system_version = None; + let mut header = None; let mut metrics_log = Vec::new(); for (i, line) in reader.lines().enumerate() { let line = line?; if i == 0 { - system_version = Some( + header = Some( serde_json::from_str(&line) .with_context(|| format!("failed to parse record file: line={}", i + 1))?, ); @@ -326,10 +330,9 @@ .with_context(|| format!("failed to parse record file: line={}", i + 1))?; metrics_log.push(metrics); } - let system_version = - system_version.ok_or_else(|| anyhow::anyhow!("record file is empty"))?; + let header = header.ok_or_else(|| anyhow::anyhow!("record file is empty"))?; Ok(Self { - system_version, + header, metrics_log, }) } @@ -338,14 +341,14 @@ #[derive(Debug)] pub struct RealtimeMetricsPoller { rx: MetricsReceiver, - system_version: SystemVersion, + header: Header, rpc_client: RpcClient, old_microstate_accounting_flag: bool, } impl RealtimeMetricsPoller { - fn start_thread(options: Options) -> anyhow::Result<Self> { - MetricsPollerThread::start_thread(options) + fn start_thread(args: RunArgs) -> anyhow::Result<Self> { + MetricsPollerThread::start_thread(args) } } @@ -366,22 +369,22 @@ #[derive(Debug)] struct MetricsPollerThread { - options: Options, + args: RunArgs, rpc_client: RpcClient, tx: MetricsSender, prev_metrics: Metrics, start: Instant, - system_version: SystemVersion, + header: Header, record_file: Option<File>, } impl MetricsPollerThread { - fn start_thread(options: Options) -> anyhow::Result<RealtimeMetricsPoller> { + fn start_thread(args: RunArgs) -> anyhow::Result<RealtimeMetricsPoller> { let (tx, rx) = mpsc::channel(); let rpc_client: RpcClient = smol::block_on(async { - let cookie = options.find_cookie()?; - let client = RpcClient::connect(&options.erlang_node, &cookie).await?; + let cookie = args.find_cookie()?; + let client = RpcClient::connect(&args.erlang_node, &cookie).await?; Ok(client) as anyhow::Result<_> })?; let system_version = smol::block_on(rpc_client.get_system_version())?; @@ -391,14 +394,19 @@ "enabled microstate accounting (old flag state is {old_microstate_accounting_flag})" ); + let header = Header { + system_version: system_version.clone(), + node_name: args.erlang_node.to_string(), + start_time: chrono::Local::now(), + }; let poller = RealtimeMetricsPoller { rx, - system_version: system_version.clone(), + header: header.clone(), rpc_client: rpc_client.clone(), old_microstate_accounting_flag, }; - let record_file = if let Some(path) = &options.record { + let record_file = if let Some(path) = &args.record { Some(File::from(std::fs::File::create(path).with_context( || format!("failed to record file {}", path.display()), )?)) @@ -409,12 +417,12 @@ std::thread::spawn(|| { let start = Instant::now(); Self { - options, + args, rpc_client, tx, prev_metrics: Metrics::new(start), start, - system_version, + header, record_file, } .run() @@ -433,10 +441,10 @@ } fn run(mut self) { - let interval = Duration::from_secs(self.options.polling_interval.get() as u64); + let interval = Duration::from_secs(self.args.polling_interval.get() as u64); let mut next_time = Duration::from_secs(0); smol::block_on(async { - if let Err(e) = self.write_json_line(&self.system_version.clone()).await { + if let Err(e) = self.write_json_line(&self.header.clone()).await { log::error!("faild to write record file: {e}"); return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/erldash-0.1.5~0/src/ui.rs new/erldash-0.2.0~0/src/ui.rs --- old/erldash-0.1.5~0/src/ui.rs 2023-10-19 04:24:59.000000000 +0200 +++ new/erldash-0.2.0~0/src/ui.rs 2023-10-21 03:49:17.000000000 +0200 @@ -1,5 +1,4 @@ -use crate::erlang::SystemVersion; -use crate::metrics::{format_u64, MetricValue, Metrics, MetricsPoller}; +use crate::metrics::{format_u64, Header, MetricValue, Metrics, MetricsPoller}; use crossterm::event::{KeyCode, KeyEvent}; use std::collections::{BTreeMap, VecDeque}; use std::sync::mpsc; @@ -32,11 +31,11 @@ log::debug!("setup terminal"); let replay_mode = poller.is_replay(); - let system_version = poller.system_version().clone(); + let header = poller.header().clone(); Ok(Self { terminal, poller, - ui: UiState::new(system_version, replay_mode), + ui: UiState::new(header, replay_mode), replay_cursor_time: Duration::default(), }) } @@ -92,6 +91,7 @@ } log::debug!("remove old metrics"); } + self.ui.elapsed = self.ui.start.elapsed(); self.render_ui()?; } } @@ -186,18 +186,13 @@ let time = self.replay_cursor_time; self.ui.history.clear(); + self.ui.averages.clear(); for metrics in self .poller .get_metrics_range(time, time + Duration::from_secs(CHART_DURATION))? { self.ui.history.push_back(metrics.clone()); - } - self.ui.averages.clear(); - for metrics in self.poller.get_metrics_range( - time.saturating_sub(Duration::from_secs(CHART_DURATION)), - time, - )? { for (name, item) in &metrics.items { if let Some(avg) = self.ui.averages.get_mut(name) { avg.add(item.clone()); @@ -209,6 +204,13 @@ } } + self.ui.elapsed = self + .ui + .history + .back() + .map(|x| x.timestamp) + .unwrap_or_default(); + self.render_ui()?; Ok(()) } @@ -246,7 +248,8 @@ #[derive(Debug)] struct UiState { start: Instant, - system_version: SystemVersion, + header: Header, + elapsed: Duration, pause: bool, history: VecDeque<Metrics>, averages: BTreeMap<String, AvgValue>, @@ -257,10 +260,11 @@ } impl UiState { - fn new(system_version: SystemVersion, replay_mode: bool) -> Self { + fn new(header: Header, replay_mode: bool) -> Self { Self { start: Instant::now(), - system_version, + header, + elapsed: Duration::default(), pause: false, history: VecDeque::new(), averages: BTreeMap::new(), @@ -282,10 +286,35 @@ } fn render_header(&mut self, f: &mut Frame, area: Rect) { - let paragraph = Paragraph::new(vec![Spans::from(self.system_version.get())]) + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints( + [ + Constraint::Percentage(20), + Constraint::Percentage(60), + Constraint::Percentage(20), + ] + .as_ref(), + ) + .split(area); + + let paragraph = Paragraph::new(vec![Spans::from(self.header.node_name.clone())]) + .block(self.make_block("Node")) + .alignment(Alignment::Left); + f.render_widget(paragraph, chunks[0]); + + let paragraph = Paragraph::new(vec![Spans::from(self.header.system_version.get())]) .block(self.make_block("System Version")) .alignment(Alignment::Left); - f.render_widget(paragraph, area); + f.render_widget(paragraph, chunks[1]); + + let now = self.header.start_time + self.elapsed; + let paragraph = Paragraph::new(vec![Spans::from( + now.to_rfc3339_opts(chrono::SecondsFormat::Secs, true), + )]) + .block(self.make_block("Time")) + .alignment(Alignment::Left); + f.render_widget(paragraph, chunks[2]); } fn render_body(&mut self, f: &mut Frame, area: Rect) { @@ -322,7 +351,7 @@ let header = Row::new(header_cells).bottom_margin(1); let items = self.latest_metrics().root_items().collect::<Vec<_>>(); - let is_avg_available = self.start.elapsed().as_secs() >= ONE_MINUTE; + let is_avg_available = self.elapsed.as_secs() >= (ONE_MINUTE - 1); let mut value_width = 0; let mut avg_width = 0; let mut row_items = Vec::with_capacity(items.len()); ++++++ vendor.tar.xz ++++++ /work/SRC/openSUSE:Factory/erldash/vendor.tar.xz /work/SRC/openSUSE:Factory/.erldash.new.1945/vendor.tar.xz differ: char 25, line 1