mirror of
https://seed.radicle.dev/rad:z39mP9rQAaGmERfUMPULfPUi473tY.git
synced 2026-11-02 09:50:33 +08:00
lib: Support notifications in flux apps
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
use anyhow::anyhow;
|
||||
|
||||
use ratatui::widgets::Cell;
|
||||
|
||||
use radicle::cob::{self, ObjectId, Timestamp};
|
||||
use radicle::issue::Issues;
|
||||
use radicle::node::notifications::{Notification, NotificationId, NotificationKind};
|
||||
use radicle::patch::Patches;
|
||||
use radicle::storage::git::Repository;
|
||||
use radicle::storage::{ReadRepository, RefUpdate};
|
||||
|
||||
use super::widget::ToRow;
|
||||
use super::{format, span};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum NotificationKindItem {
|
||||
Branch {
|
||||
name: String,
|
||||
summary: String,
|
||||
status: String,
|
||||
id: Option<ObjectId>,
|
||||
},
|
||||
Cob {
|
||||
type_name: String,
|
||||
summary: String,
|
||||
status: String,
|
||||
id: Option<ObjectId>,
|
||||
},
|
||||
}
|
||||
|
||||
impl TryFrom<(&Repository, &Notification)> for NotificationKindItem {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: (&Repository, &Notification)) -> Result<Self, Self::Error> {
|
||||
let (repo, notification) = value;
|
||||
// TODO: move out of here
|
||||
let issues = Issues::open(repo)?;
|
||||
let patches = Patches::open(repo)?;
|
||||
|
||||
match ¬ification.kind {
|
||||
NotificationKind::Branch { name } => {
|
||||
let (head, message) = if let Some(head) = notification.update.new() {
|
||||
let message = repo.commit(head)?.summary().unwrap_or_default().to_owned();
|
||||
(Some(head), message)
|
||||
} else {
|
||||
(None, String::new())
|
||||
};
|
||||
let status = match notification.update {
|
||||
RefUpdate::Updated { .. } => "updated",
|
||||
RefUpdate::Created { .. } => "created",
|
||||
RefUpdate::Deleted { .. } => "deleted",
|
||||
RefUpdate::Skipped { .. } => "skipped",
|
||||
};
|
||||
|
||||
Ok(NotificationKindItem::Branch {
|
||||
name: name.to_string(),
|
||||
summary: message,
|
||||
status: status.to_string(),
|
||||
id: head.map(ObjectId::from),
|
||||
})
|
||||
}
|
||||
NotificationKind::Cob { type_name, id } => {
|
||||
let (category, summary) = if *type_name == *cob::issue::TYPENAME {
|
||||
let issue = issues.get(id)?.ok_or(anyhow!("missing"))?;
|
||||
(String::from("issue"), issue.title().to_owned())
|
||||
} else if *type_name == *cob::patch::TYPENAME {
|
||||
let patch = patches.get(id)?.ok_or(anyhow!("missing"))?;
|
||||
(String::from("patch"), patch.title().to_owned())
|
||||
} else {
|
||||
(type_name.to_string(), "".to_owned())
|
||||
};
|
||||
let status = match notification.update {
|
||||
RefUpdate::Updated { .. } => "updated",
|
||||
RefUpdate::Created { .. } => "opened",
|
||||
RefUpdate::Deleted { .. } => "deleted",
|
||||
RefUpdate::Skipped { .. } => "skipped",
|
||||
};
|
||||
|
||||
Ok(NotificationKindItem::Cob {
|
||||
type_name: category.to_string(),
|
||||
summary: summary.to_string(),
|
||||
status: status.to_string(),
|
||||
id: Some(*id),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NotificationItem {
|
||||
/// Unique notification ID.
|
||||
pub id: NotificationId,
|
||||
/// Mark this notification as seen.
|
||||
pub seen: bool,
|
||||
/// Wrapped notification kind.
|
||||
pub kind: NotificationKindItem,
|
||||
/// Time the update has happened.
|
||||
timestamp: Timestamp,
|
||||
}
|
||||
|
||||
impl TryFrom<(&Repository, &Notification)> for NotificationItem {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: (&Repository, &Notification)) -> Result<Self, Self::Error> {
|
||||
let (repo, notification) = value;
|
||||
let kind = NotificationKindItem::try_from((repo, notification))?;
|
||||
|
||||
Ok(NotificationItem {
|
||||
id: notification.id,
|
||||
seen: notification.status.is_read(),
|
||||
kind,
|
||||
timestamp: notification.timestamp.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRow<7> for NotificationItem {
|
||||
fn to_row(&self) -> [Cell; 7] {
|
||||
let (type_name, summary, status, kind_id) = match &self.kind {
|
||||
NotificationKindItem::Branch {
|
||||
name,
|
||||
summary,
|
||||
status,
|
||||
id: _,
|
||||
} => ("branch".to_string(), summary, status, name.to_string()),
|
||||
NotificationKindItem::Cob {
|
||||
type_name,
|
||||
summary,
|
||||
status,
|
||||
id,
|
||||
} => {
|
||||
let id = id.map(|id| format::cob(&id)).unwrap_or_default();
|
||||
(type_name.to_string(), summary, status, id.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
let id = span::default(format!(" {}", &self.id));
|
||||
let seen = if self.seen {
|
||||
span::blank()
|
||||
} else {
|
||||
span::positive(" ● ".into())
|
||||
};
|
||||
let type_name = span::secondary(type_name);
|
||||
let summary = span::default(summary.to_string());
|
||||
let kind_id = span::primary(kind_id);
|
||||
let status = span::default(status.to_string());
|
||||
let timestamp = span::timestamp(format::timestamp(&self.timestamp));
|
||||
|
||||
[
|
||||
id.into(),
|
||||
seen.into(),
|
||||
type_name.into(),
|
||||
summary.into(),
|
||||
kind_id.into(),
|
||||
status.into(),
|
||||
timestamp.into(),
|
||||
]
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -3,16 +3,17 @@ use std::hash::Hash;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use radicle::node::notifications::NotificationId;
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
|
||||
use radicle::cob::ObjectId;
|
||||
use serde::ser::{Serialize, SerializeStruct, Serializer};
|
||||
|
||||
use tuirealm::terminal::TerminalBridge;
|
||||
use tuirealm::tui::layout::Rect;
|
||||
use tuirealm::Frame;
|
||||
use tuirealm::{Application, EventListenerCfg, NoUserEvent};
|
||||
|
||||
use radicle::cob::ObjectId;
|
||||
use radicle::node::notifications::NotificationId;
|
||||
|
||||
pub mod cob;
|
||||
pub mod context;
|
||||
pub mod log;
|
||||
@@ -175,8 +176,8 @@ impl Window {
|
||||
}
|
||||
update = tui.update(&mut app)?;
|
||||
|
||||
resize = size != self.terminal.raw().size()?;
|
||||
size = self.terminal.raw().size()?;
|
||||
resize = size != self.terminal.raw_mut().size()?;
|
||||
size = self.terminal.raw_mut().size()?;
|
||||
}
|
||||
|
||||
Ok(tui.exit().unwrap().value)
|
||||
|
||||
Reference in New Issue
Block a user