update sidebar

This commit is contained in:
2026-09-14 08:56:32 +07:00
parent 1a13d4e0d7
commit c6ada10afa
5 changed files with 267 additions and 74 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ use git_store::set_git_cache;
pub use git_store::{ensure_repo_mirror, open_repo_mirror, repo_mirror_path};
use gpui::{App, AppContext};
pub use inbox::{Inbox, query_inbox};
pub use local_repos::{LocalReposStore, local_repo_addr};
pub use local_repos::{LocalReposStore, ResolvedLocalRepo, local_repo_addr, resolve_local_repos};
pub use nostr_sdk::prelude::Timestamp;
pub use profile::{Profile, ProfileStore};
pub use refresh::{RefreshGate, RefreshRequest};
+142 -2
View File
@@ -1,10 +1,11 @@
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use anyhow::Error;
use gpui::{App, AppContext, Context, Entity, Global, Task};
use signed_core::{RepoAddr, repo_addr};
use signed_git::{LocalRepo, find_git_repos};
use signed_core::{Announcement, RepoAddr, repo_addr};
use signed_git::{LocalRepo, Nip34Binding, find_git_repos};
struct GlobalLocalReposStore(Entity<LocalReposStore>);
@@ -114,3 +115,142 @@ pub fn local_repo_addr(repo: &LocalRepo) -> Option<RepoAddr> {
Some(repo_addr(owner, identifier))
}
/// A scanned repository resolved against the known announcements.
#[derive(Debug, Clone, PartialEq)]
pub struct ResolvedLocalRepo {
pub path: PathBuf,
/// `None` for a plain repository.
pub nip34: Option<Nip34Binding>,
/// The known announcement this repository is bound to, when one matched.
pub announcement: Option<Announcement>,
}
/// Resolve the scanned repositories against the known announcements.
pub fn resolve_local_repos(
repos: &[LocalRepo],
known: &[Announcement],
own: &[Announcement],
) -> Vec<ResolvedLocalRepo> {
let shown: HashSet<RepoAddr> = own.iter().map(Announcement::addr).collect();
repos
.iter()
.filter_map(|repo| {
let addr = local_repo_addr(repo);
if let Some(addr) = &addr
&& shown.contains(addr)
{
return None;
}
let announcement = addr
.as_ref()
.and_then(|addr| {
known
.iter()
.find(|announcement| announcement.addr() == *addr)
})
.cloned();
Some(ResolvedLocalRepo {
path: repo.path.clone(),
nip34: repo.nip34.clone(),
announcement,
})
})
.collect()
}
#[cfg(test)]
mod tests {
use nostr::prelude::*;
use signed_git::{GraspSignals, Nip34Kind};
use super::*;
const KEY: &str = "0000000000000000000000000000000000000000000000000000000000000001";
const OTHER_KEY: &str = "0000000000000000000000000000000000000000000000000000000000000002";
fn announcement(secret: &str, id: &str) -> Announcement {
let keys = Keys::new(SecretKey::from_hex(secret).expect("secret"));
let tag = Tag::parse(vec!["d", id]).expect("tag");
let event = EventBuilder::new(Kind::GitRepoAnnouncement, "")
.tags(vec![tag])
.finalize(&keys)
.expect("signed");
Announcement::from_event(&event).expect("parsed")
}
fn owner(secret: &str) -> PublicKey {
Keys::new(SecretKey::from_hex(secret).expect("secret")).public_key()
}
fn bound(secret: &str, id: &str) -> LocalRepo {
let binding = Nip34Binding {
kind: Nip34Kind::Initialized,
signals: GraspSignals {
nip34_json: true,
..Default::default()
},
owner: Some(owner(secret)),
identifier: Some(id.to_owned()),
grasp_urls: Vec::new(),
};
LocalRepo {
path: PathBuf::from(id),
nip34: Some(binding),
}
}
#[test]
fn the_users_own_announcement_is_dropped() {
let own = announcement(KEY, "mine");
let repo = bound(KEY, "mine");
let own = std::slice::from_ref(&own);
assert!(resolve_local_repos(&[repo], own, own).is_empty());
}
#[test]
fn another_owners_announcement_is_linked_and_kept() {
let known = announcement(OTHER_KEY, "theirs");
let repo = bound(OTHER_KEY, "theirs");
let resolved = resolve_local_repos(&[repo], std::slice::from_ref(&known), &[]);
assert_eq!(resolved.len(), 1);
assert_eq!(resolved[0].announcement.as_ref(), Some(&known));
}
#[test]
fn an_unmatched_repository_keeps_its_binding() {
let repo = bound(KEY, "unlisted");
let resolved = resolve_local_repos(&[repo], &[], &[]);
assert_eq!(resolved.len(), 1);
assert!(resolved[0].announcement.is_none());
assert_eq!(
resolved[0].nip34.as_ref().map(|binding| binding.kind),
Some(Nip34Kind::Initialized)
);
}
#[test]
fn a_plain_repository_is_kept_without_a_binding() {
let repo = LocalRepo {
path: PathBuf::from("plain"),
nip34: None,
};
let resolved = resolve_local_repos(&[repo], &[], &[]);
assert_eq!(resolved.len(), 1);
assert!(resolved[0].nip34.is_none());
assert!(resolved[0].announcement.is_none());
}
}