feat(tui): hightlight status message in colour

This commit is contained in:
Paul Campbell 2024-08-31 09:28:20 +01:00
parent 4555b3ae09
commit f9e305afa4
7 changed files with 135 additions and 30 deletions

64
Cargo.lock generated
View file

@ -320,6 +320,28 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bon"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3b71187ef9d11cfa48c023d574a00ec5e4850dcb145ef51619d99cc119486cb"
dependencies = [
"bon-macros",
]
[[package]]
name = "bon-macros"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f8407447d440da7b3de982f286d15e30e7646bef4ebca994eebebaa1690fd9c"
dependencies = [
"darling",
"ident_case",
"proc-macro2",
"quote",
"syn 2.0.76",
]
[[package]]
name = "bstr"
version = "1.10.0"
@ -592,6 +614,41 @@ dependencies = [
"typenum",
]
[[package]]
name = "darling"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.76",
]
[[package]]
name = "darling_macro"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn 2.0.76",
]
[[package]]
name = "dashmap"
version = "6.0.1"
@ -1041,6 +1098,7 @@ dependencies = [
"actix-rt",
"anyhow",
"assert2",
"bon",
"bytes",
"clap",
"color-eyre",
@ -2350,6 +2408,12 @@ dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.5.0"

View file

@ -79,6 +79,7 @@ time = "0.3"
standardwebhooks = "1.0"
# boilerplate
bon = "2.0"
derive_more = { version = "1.0.0-beta", features = [
"as_ref",
"constructor",

View file

@ -52,6 +52,7 @@ actix = { workspace = true }
actix-rt = { workspace = true }
# boilerplate
bon = { workspace = true }
derive_more = { workspace = true }
derive-with = { workspace = true }
anyhow = { workspace = true }

View file

@ -1,11 +1,17 @@
//
use actix::Handler;
use ratatui::style::Color;
use crate::{
server::actor::messages::{RepoUpdate, ServerUpdate},
tui::{actor::ServerState, Tui},
};
static OKAY: Color = Color::Green;
static PREP: Color = Color::Gray;
static ACTING: Color = Color::Yellow;
static WARN: Color = Color::LightYellow;
impl Handler<ServerUpdate> for Tui {
type Result = ();
@ -35,50 +41,53 @@ impl Handler<ServerUpdate> for Tui {
RepoUpdate::Log { log } => {
repo_state.update_log(log);
}
RepoUpdate::ValidateRepo => repo_state.update_message("polling..."),
RepoUpdate::ValidateRepo => repo_state.update_message("polling...", ACTING),
RepoUpdate::Okay { main, next, dev } => {
repo_state.clear_alert();
repo_state.update_message("okay");
repo_state.update_message("okay", OKAY);
*repo_state = repo_state.clone().ready(main, next, dev);
}
RepoUpdate::Alert { alert } => {
repo_state.alert(alert);
}
RepoUpdate::CheckingCI => {
repo_state.update_message("Checking CI status");
repo_state.update_message("Checking CI status", ACTING);
}
RepoUpdate::AdvancingNext { commit, force: _ } => {
repo_state.update_message(format!("advancing next to {commit}"));
repo_state
.update_message(format!("advancing next to {commit}"), ACTING);
}
RepoUpdate::AdvancingMain { commit } => {
repo_state.update_message(format!("advancing main to {commit}"));
repo_state
.update_message(format!("advancing main to {commit}"), ACTING);
}
RepoUpdate::Opening => {
repo_state.update_message("opening...");
repo_state.update_message("opening...", PREP);
}
RepoUpdate::Opened => {
repo_state.update_message("opened");
repo_state.update_message("opened", PREP);
}
RepoUpdate::LoadingConfigFromRepo => {
repo_state.update_message("loading config from repo...");
repo_state.update_message("loading config from repo...", PREP);
}
RepoUpdate::ReceiveCIStatus { status } => {
repo_state.update_message(format!("ci status: {status:?}"));
repo_state.update_message(format!("ci status: {status:?}"), WARN);
}
RepoUpdate::ReceiveRepoConfig { repo_config: _ } => {
repo_state.update_message("loaded config from repo");
repo_state.update_message("loaded config from repo", PREP);
}
RepoUpdate::RegisteringWebhook => {
repo_state.update_message("registering webhook...");
repo_state.update_message("registering webhook...", PREP);
}
RepoUpdate::UnregisteringWebhook => {
repo_state.update_message("unregistering webhook...");
repo_state.update_message("unregistering webhook...", PREP);
}
RepoUpdate::WebhookReceived { branch, push: _ } => {
repo_state.update_message(format!("webhook update: {branch:?}"));
repo_state
.update_message(format!("webhook update: {branch:?}"), ACTING);
}
RepoUpdate::RegisteredWebhook => {
repo_state.update_message("registered webhook");
repo_state.update_message("registered webhook", PREP);
}
}
}

View file

@ -2,9 +2,9 @@
use ratatui::{
layout::Alignment,
prelude::{Buffer, Rect},
style::Stylize as _,
style::{Color, Style, Stylize as _},
symbols::border,
text::Line,
text::{Line, Span},
widgets::{block::Title, Block, Paragraph, StatefulWidget, Widget},
};
@ -127,7 +127,10 @@ impl From<ValidAppConfig> for ServerState {
repo_alias.clone(),
RepoState::Configured {
repo_alias,
message: "configured".into(),
message: RepoMessage::builder()
.text("configured".into())
.style(Style::default().fg(Color::LightGreen))
.build(),
alert: None,
branches: rc.branches().clone(),
log: git::graph::Log::default(),
@ -137,7 +140,10 @@ impl From<ValidAppConfig> for ServerState {
repo_alias.clone(),
RepoState::Identified {
repo_alias,
message: "identified".into(),
message: RepoMessage::builder()
.text("identified".into())
.style(Style::default().fg(Color::Gray))
.build(),
alert: None,
},
),
@ -182,23 +188,37 @@ pub struct ForgeState {
pub repos: BTreeMap<RepoAlias, RepoState>,
}
#[bon::builder]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RepoMessage {
text: String,
style: Style,
}
impl From<&RepoMessage> for Span<'_> {
fn from(value: &RepoMessage) -> Self {
Self::default()
.content(value.text.clone())
.style(value.style)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RepoState {
Identified {
repo_alias: RepoAlias,
message: String,
message: RepoMessage,
alert: Option<String>,
},
Configured {
repo_alias: RepoAlias,
message: String,
message: RepoMessage,
alert: Option<String>,
branches: RepoBranches,
log: Log,
},
Ready {
repo_alias: RepoAlias,
message: String,
message: RepoMessage,
alert: Option<String>,
branches: RepoBranches,
view_state: ViewState,
@ -241,14 +261,16 @@ impl RepoState {
}
#[tracing::instrument]
pub fn update_message(&mut self, msg: impl Into<String> + std::fmt::Debug) {
let msg: String = msg.into();
pub fn update_message(&mut self, msg: impl Into<String> + std::fmt::Debug, colour: Color) {
match self {
Self::Identified { message, .. }
| Self::Configured { message, .. }
| Self::Ready { message, .. } => {
info!(?msg, "updating ui");
*message = msg;
*message = RepoMessage::builder()
.text(msg.into())
.style(Style::default().fg(colour))
.build();
}
}
}
@ -265,7 +287,7 @@ impl RepoState {
pub fn alert(&mut self, msg: impl Into<String> + std::fmt::Debug) {
let msg: String = msg.into();
tracing::info!(%msg, "new tui alert");
self.update_message("ALERT");
self.update_message("ALERT", Color::Red);
match self {
Self::Identified { alert, .. }
| Self::Configured { alert, .. }

View file

@ -8,11 +8,13 @@ use ratatui::{
widgets::block::Title,
};
use crate::tui::actor::RepoMessage;
pub struct Identity<'a> {
pub label: &'a str,
pub repo_alias: &'a RepoAlias,
pub alert: Option<&'a str>,
pub message: &'a str,
pub message: &'a RepoMessage,
pub repo_branches: Option<&'a RepoBranches>,
}
impl<'a> Identity<'a> {
@ -20,7 +22,7 @@ impl<'a> Identity<'a> {
label: &'a str,
repo_alias: &'a RepoAlias,
alert: Option<&'a str>,
message: &'a str,
message: &'a RepoMessage,
repo_branches: Option<&'a RepoBranches>,
) -> Self {
Self {
@ -56,7 +58,10 @@ impl<'a> Identity<'a> {
vec![
Span::from(format!(" {repo_alias} ({label}) ")),
alert,
Span::from(format!("({main}/{next}/{dev}) [{message}] ")),
Span::from(format!("({main}/{next}/{dev}) [")),
message.into(),
// Span::from(message.},
Span::from("] "),
]
}
}

View file

@ -7,7 +7,10 @@ use git_next_core::{RepoAlias, RepoBranches};
use crate::{
git,
tui::{actor::RepoState, components::CommitLog},
tui::{
actor::{RepoMessage, RepoState},
components::CommitLog,
},
};
use identity::Identity;
@ -97,7 +100,7 @@ impl<'a> Widget for RepoWidget<'a> {
struct InnerRepoWidget<'a> {
pub label: &'a str,
pub repo_alias: &'a RepoAlias,
pub message: &'a str,
pub message: &'a RepoMessage,
pub alert: Option<&'a str>,
pub branches: Option<&'a RepoBranches>,
pub log: Option<&'a git::graph::Log>,