feat: add event fetching strategy #24

Merged
reya merged 10 commits from optimize into master 2026-09-27 02:50:12 +00:00
5 changed files with 9 additions and 45 deletions
Showing only changes of commit e1a6f0a669 - Show all commits
-7
View File
@@ -1,7 +0,0 @@
use nostr::prelude::*;
/// GitWorkshop and `ngit` cover-note extension, kind 1624.
///
/// A markdown note attached to an issue, patch or PR by its author or a maintainer,
/// not part of the NIP-34 draft, read support for interop.
pub const COVER_NOTE_KIND: Kind = Kind::Custom(1624);
+6 -26
View File
@@ -2,7 +2,7 @@ use std::time::Duration;
use nostr::prelude::*; use nostr::prelude::*;
use crate::{COVER_NOTE_KIND, RepoAddr}; use crate::RepoAddr;
/// Kinds that make up the activity of a repository. /// Kinds that make up the activity of a repository.
pub const ACTIVITY_KINDS: [Kind; 9] = [ pub const ACTIVITY_KINDS: [Kind; 9] = [
@@ -18,19 +18,18 @@ pub const ACTIVITY_KINDS: [Kind; 9] = [
]; ];
/// Kinds that notify a user when they tag them via their `p` tag. /// Kinds that notify a user when they tag them via their `p` tag.
pub const NOTIFICATION_KINDS: [Kind; 9] = [ pub const NOTIFICATION_KINDS: [Kind; 8] = [
Kind::GitIssue, Kind::GitIssue,
Kind::GitPullRequest, Kind::GitPullRequest,
Kind::GitPatch, Kind::GitPatch,
Kind::GitPullRequestUpdate, Kind::GitPullRequestUpdate,
COVER_NOTE_KIND,
Kind::GitStatusOpen, Kind::GitStatusOpen,
Kind::GitStatusApplied, Kind::GitStatusApplied,
Kind::GitStatusClosed, Kind::GitStatusClosed,
Kind::GitStatusDraft, Kind::GitStatusDraft,
]; ];
/// Git root kinds that make a comment or cover note count as git activity. /// Git root kinds that make a comment count as git activity.
const GIT_ROOT_KINDS: [Kind; 4] = [ const GIT_ROOT_KINDS: [Kind; 4] = [
Kind::GitIssue, Kind::GitIssue,
Kind::GitPatch, Kind::GitPatch,
@@ -44,7 +43,6 @@ pub fn is_repo_kind(kind: Kind) -> bool {
|| kind == Kind::RepoState || kind == Kind::RepoState
|| kind == Kind::EventDeletion || kind == Kind::EventDeletion
|| kind == Kind::RequestToVanish || kind == Kind::RequestToVanish
|| kind == COVER_NOTE_KIND
|| ACTIVITY_KINDS.contains(&kind) || ACTIVITY_KINDS.contains(&kind)
} }
@@ -150,13 +148,7 @@ pub fn notifications(me: PublicKey) -> Vec<Filter> {
/// A comment on an unrelated kind is matched too, so results must be filtered /// A comment on an unrelated kind is matched too, so results must be filtered
/// through [`is_git_activity`] before display. /// through [`is_git_activity`] before display.
pub fn authored_activity(me: PublicKey) -> Filter { pub fn authored_activity(me: PublicKey) -> Filter {
Filter::new() Filter::new().kinds(ACTIVITY_KINDS).author(me)
.kinds(
ACTIVITY_KINDS
.into_iter()
.chain(std::iter::once(COVER_NOTE_KIND)),
)
.author(me)
} }
/// Whether a kind-1111 comment targets a git root, checked via its `K` tag. /// Whether a kind-1111 comment targets a git root, checked via its `K` tag.
@@ -165,12 +157,6 @@ fn is_git_comment(event: &Event) -> bool {
&& tag_kind(event, "K").is_some_and(|kind| GIT_ROOT_KINDS.contains(&kind)) && tag_kind(event, "K").is_some_and(|kind| GIT_ROOT_KINDS.contains(&kind))
} }
/// Whether a kind-1624 cover note targets a git root, checked via its `k` tag.
fn is_git_cover_note(event: &Event) -> bool {
event.kind == COVER_NOTE_KIND
&& tag_kind(event, "k").is_some_and(|kind| GIT_ROOT_KINDS.contains(&kind))
}
/// Whether a status event references a git root, checked via its `k` tag. /// Whether a status event references a git root, checked via its `k` tag.
fn is_git_status(event: &Event) -> bool { fn is_git_status(event: &Event) -> bool {
tag_kind(event, "k").is_some_and(|kind| GIT_ROOT_KINDS.contains(&kind)) tag_kind(event, "k").is_some_and(|kind| GIT_ROOT_KINDS.contains(&kind))
@@ -185,7 +171,7 @@ pub fn is_git_activity(event: &Event) -> bool {
| Kind::GitStatusApplied | Kind::GitStatusApplied
| Kind::GitStatusClosed | Kind::GitStatusClosed
| Kind::GitStatusDraft => is_git_status(event), | Kind::GitStatusDraft => is_git_status(event),
kind => kind == COVER_NOTE_KIND && is_git_cover_note(event), _ => false,
} }
} }
@@ -277,17 +263,12 @@ mod tests {
} }
#[test] #[test]
fn status_and_cover_note_activity_depend_on_the_lowercase_k_tag() { fn status_activity_depends_on_the_lowercase_k_tag() {
let status = signed( let status = signed(
&keys(1), &keys(1),
Kind::GitStatusClosed, Kind::GitStatusClosed,
vec![kind_tag("k", Kind::GitPullRequest)], vec![kind_tag("k", Kind::GitPullRequest)],
); );
let cover = signed(
&keys(1),
COVER_NOTE_KIND,
vec![kind_tag("k", Kind::GitPatch)],
);
let unrelated = signed( let unrelated = signed(
&keys(1), &keys(1),
Kind::GitStatusClosed, Kind::GitStatusClosed,
@@ -295,7 +276,6 @@ mod tests {
); );
assert!(is_git_activity(&status)); assert!(is_git_activity(&status));
assert!(is_git_activity(&cover));
assert!(!is_git_activity(&unrelated)); assert!(!is_git_activity(&unrelated));
assert!(!is_git_activity(&signed( assert!(!is_git_activity(&signed(
&keys(1), &keys(1),
+2 -5
View File
@@ -4,7 +4,7 @@ use std::time::Duration;
use nostr::prelude::*; use nostr::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{COVER_NOTE_KIND, RepoAddr, activity_subject}; use crate::{RepoAddr, activity_subject};
/// Window before `now` that an advanced cutoff retreats to. /// Window before `now` that an advanced cutoff retreats to.
const ADVANCE_WINDOW: Duration = Duration::from_secs(3 * 24 * 60 * 60); const ADVANCE_WINDOW: Duration = Duration::from_secs(3 * 24 * 60 * 60);
@@ -121,14 +121,11 @@ impl InboxItem {
/// - patch (1617): its `e` parent patch, else itself /// - patch (1617): its `e` parent patch, else itself
/// - NIP-22 comment (1111): uppercase `E` root pointer /// - NIP-22 comment (1111): uppercase `E` root pointer
/// - PR update (1619): uppercase `E` /// - PR update (1619): uppercase `E`
/// - statuses (1630-1633) / cover note (1624): NIP-10 root `e` /// - statuses (1630-1633): NIP-10 root `e`
pub fn notification_root<L>(event: &Event, lookup: &L) -> Option<EventId> pub fn notification_root<L>(event: &Event, lookup: &L) -> Option<EventId>
where where
L: Fn(EventId) -> Option<Event>, L: Fn(EventId) -> Option<Event>,
{ {
if event.kind == COVER_NOTE_KIND {
return nip10_root_id(event).map(|root| resolve_thread_root(root, lookup));
}
match event.kind { match event.kind {
Kind::GitIssue | Kind::GitPullRequest => Some(event.id), Kind::GitIssue | Kind::GitPullRequest => Some(event.id),
Kind::GitPatch => Some(match first_e_id(event) { Kind::GitPatch => Some(match first_e_id(event) {
-2
View File
@@ -1,5 +1,4 @@
pub mod addr; pub mod addr;
pub mod annotations;
pub mod deletions; pub mod deletions;
pub mod filters; pub mod filters;
pub mod inbox; pub mod inbox;
@@ -8,7 +7,6 @@ pub mod state;
pub mod status; pub mod status;
pub use addr::{RepoAddr, identifier_from_name, repo_addr}; pub use addr::{RepoAddr, identifier_from_name, repo_addr};
pub use annotations::COVER_NOTE_KIND;
pub use deletions::Deletions; pub use deletions::Deletions;
pub use filters::{ pub use filters::{
NOTIFICATION_KINDS, authored_activity, is_git_activity, notification_comments, notifications, NOTIFICATION_KINDS, authored_activity, is_git_activity, notification_comments, notifications,
+1 -5
View File
@@ -11,7 +11,7 @@ use gpui::{
use gpui_component::button::{Button, ButtonVariants}; use gpui_component::button::{Button, ButtonVariants};
use gpui_component::{ActiveTheme, Icon, IconName, IconNamed, Sizable, StyledExt, h_flex, v_flex}; use gpui_component::{ActiveTheme, Icon, IconName, IconNamed, Sizable, StyledExt, h_flex, v_flex};
use nostr::prelude::{Event, EventId, Kind, PublicKey, Timestamp}; use nostr::prelude::{Event, EventId, Kind, PublicKey, Timestamp};
use signed_core::{COVER_NOTE_KIND, InboxItem, InboxReadState, RepoAddr}; use signed_core::{InboxItem, InboxReadState, RepoAddr};
use signed_state::{ use signed_state::{
Backend, BackendEvent, ProfileStore, RefreshGate, RefreshRequest, RepoListStore, query_inbox, Backend, BackendEvent, ProfileStore, RefreshGate, RefreshRequest, RepoListStore, query_inbox,
}; };
@@ -557,10 +557,6 @@ fn sub_activity(event: &Event, me: Option<PublicKey>, cx: &App) -> AnyElement {
} }
fn activity_phrase(kind: Kind) -> &'static str { fn activity_phrase(kind: Kind) -> &'static str {
if kind == COVER_NOTE_KIND {
return "added a note";
}
match kind { match kind {
Kind::GitIssue => "opened an issue", Kind::GitIssue => "opened an issue",
Kind::GitPullRequest => "opened a PR", Kind::GitPullRequest => "opened a PR",