Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Add more options to `list_repos` command
Open did:key:z6MkkfM3...sVz5 opened 1 year ago

Add filter for repos to list_repos command

Instead of only returning seeded repos, this repo adds 3 new filter options to the list_repos command, under the show field

  • all - All repos that a user has initialized or forked (own namespace)
  • seeded - Repos that are beeing seeded by the user
  • delegate - Repos that the current user is a delegate of.

checkcheck-e2e

👉 Workflow runs 👉 Branch on GitHub

4 files changed +81 -50 c35ab783 06437656
modified crates/radicle-tauri/src/commands/repo.rs
@@ -3,13 +3,16 @@ use radicle::identity::RepoId;

use radicle_types as types;
use radicle_types::error::Error;
-
use radicle_types::traits::repo::Repo;
+
use radicle_types::traits::repo::{Repo, Show};

use crate::AppState;

#[tauri::command]
-
pub fn list_repos(ctx: tauri::State<AppState>) -> Result<Vec<types::repo::RepoInfo>, Error> {
-
    ctx.list_repos()
+
pub fn list_repos(
+
    ctx: tauri::State<AppState>,
+
    show: Show,
+
) -> Result<Vec<types::repo::RepoInfo>, Error> {
+
    ctx.list_repos(show)
}

#[tauri::command]
modified crates/radicle-types/src/traits/repo.rs
@@ -1,45 +1,58 @@
+
use radicle_surf as surf;
+
use serde::{Deserialize, Serialize};
+

use radicle::crypto::Verified;
-
use radicle::identity::doc::PayloadId;
-
use radicle::identity::DocAt;
+
use radicle::identity::{doc, Doc, DocAt};
use radicle::issue::cache::Issues as _;
use radicle::node::routing::Store;
use radicle::patch::cache::Patches as _;
-
use radicle::prelude::Doc;
use radicle::storage;
-
use radicle::storage::ReadRepository;
-
use radicle::storage::ReadStorage;
+
use radicle::storage::{ReadRepository, ReadStorage, RepositoryInfo};
use radicle::{git, identity};
-
use radicle_surf as surf;

use crate::cobs;
-
use crate::cobs::diff::Options;
use crate::error::Error;
use crate::repo;
use crate::traits::Profile;

+
#[derive(Serialize, Deserialize, PartialEq)]
+
#[serde(rename_all = "camelCase")]
+
pub enum Show {
+
    Delegate,
+
    All,
+
    Seeded,
+
}
+

pub trait Repo: Profile {
-
    fn list_repos(&self) -> Result<Vec<repo::RepoInfo>, Error> {
+
    fn list_repos(&self, show: Show) -> Result<Vec<repo::RepoInfo>, Error> {
        let profile = self.profile();
        let storage = &profile.storage;
        let policies = profile.policies()?;
-
        let mut repos = storage.repositories()?.into_iter().collect::<Vec<_>>();
-
        repos.sort_by_key(|p| p.rid);
+
        let repos = storage.repositories()?;
+
        let mut entries = Vec::new();

-
        let infos = repos
-
            .into_iter()
-
            .filter_map(|info| {
-
                if !policies.is_seeding(&info.rid).unwrap_or_default() {
-
                    return None;
-
                }
-
                let repo = profile.storage.repository(info.rid).ok()?;
-
                let DocAt { doc, .. } = repo.identity_doc().ok()?;
-
                let repo_info = self.repo_info(&repo, &doc).ok()?;
-

-
                Some(repo_info)
-
            })
-
            .collect::<Vec<_>>();
+
        for RepositoryInfo { rid, doc, refs, .. } in repos {
+
            if refs.is_none() && show == Show::All {
+
                continue;
+
            }

-
        Ok::<_, Error>(infos)
+
            if !policies.is_seeding(&rid)? && show == Show::Seeded {
+
                continue;
+
            }
+

+
            if !doc.delegates.contains(&profile.public_key.into()) && show == Show::Delegate {
+
                continue;
+
            }
+

+
            let repo = profile.storage.repository(rid)?;
+
            let repo_info = self.repo_info(&repo, &doc)?;
+

+
            entries.push(repo_info)
+
        }
+

+
        entries.sort_by_key(|repo::RepoInfo { rid, .. }| *rid);
+

+
        Ok::<_, Error>(entries)
    }

    fn repo_by_id(&self, rid: identity::RepoId) -> Result<repo::RepoInfo, Error> {
@@ -86,24 +99,27 @@ pub trait Repo: Profile {
            .collect::<Vec<_>>();
        let db = profile.database()?;
        let seeding = db.count(&repo.id).unwrap_or_default();
-
        let project = doc.payload.get(&PayloadId::project()).and_then(|payload| {
-
            let (_, head) = repo.head().ok()?;
-
            let commit = repo.commit(head).ok()?;
-
            let patches = profile.patches(repo).ok()?;
-
            let patches = patches.counts().ok()?;
-
            let issues = profile.issues(repo).ok()?;
-
            let issues = issues.counts().ok()?;
-

-
            let data: repo::ProjectPayloadData = (*payload).clone().try_into().ok()?;
-
            let meta = repo::ProjectPayloadMeta {
-
                issues,
-
                patches,
-
                head,
-
                last_commit_timestamp: commit.time().seconds() * 1000,
-
            };
-

-
            Some(repo::ProjectPayload::new(data, meta))
-
        });
+
        let project = doc
+
            .payload
+
            .get(&doc::PayloadId::project())
+
            .and_then(|payload| {
+
                let (_, head) = repo.head().ok()?;
+
                let commit = repo.commit(head).ok()?;
+
                let patches = profile.patches(repo).ok()?;
+
                let patches = patches.counts().ok()?;
+
                let issues = profile.issues(repo).ok()?;
+
                let issues = issues.counts().ok()?;
+

+
                let data: repo::ProjectPayloadData = (*payload).clone().try_into().ok()?;
+
                let meta = repo::ProjectPayloadMeta {
+
                    issues,
+
                    patches,
+
                    head,
+
                    last_commit_timestamp: commit.time().seconds() * 1000,
+
                };
+

+
                Some(repo::ProjectPayload::new(data, meta))
+
            });

        Ok::<_, Error>(repo::RepoInfo {
            payloads: repo::SupportedPayloads { project },
@@ -115,7 +131,11 @@ pub trait Repo: Profile {
        })
    }

-
    fn get_diff(&self, rid: identity::RepoId, options: Options) -> Result<surf::diff::Diff, Error> {
+
    fn get_diff(
+
        &self,
+
        rid: identity::RepoId,
+
        options: cobs::diff::Options,
+
    ) -> Result<surf::diff::Diff, Error> {
        let profile = self.profile();
        let repo = profile.storage.repository(rid)?.backend;
        let base = repo.find_commit(*options.base)?;
modified crates/test-http-api/src/api.rs
@@ -20,7 +20,7 @@ use radicle_types::traits::auth::Auth;
use radicle_types::traits::cobs::Cobs;
use radicle_types::traits::issue::{Issues, IssuesMut};
use radicle_types::traits::patch::{Patches, PatchesMut};
-
use radicle_types::traits::repo::Repo;
+
use radicle_types::traits::repo::{Repo, Show};
use radicle_types::traits::thread::Thread;
use radicle_types::traits::Profile;

@@ -90,8 +90,16 @@ async fn auth_handler(State(ctx): State<Context>) -> impl IntoResponse {
    Ok::<_, Error>(Json(()))
}

-
async fn repo_root_handler(State(ctx): State<Context>) -> impl IntoResponse {
-
    let repos = ctx.list_repos()?;
+
#[derive(Serialize, Deserialize)]
+
pub struct Options {
+
    show: Show,
+
}
+

+
async fn repo_root_handler(
+
    State(ctx): State<Context>,
+
    Json(Options { show }): Json<Options>,
+
) -> impl IntoResponse {
+
    let repos = ctx.list_repos(show)?;

    Ok::<_, Error>(Json(repos))
}
modified src/lib/router/definitions.ts
@@ -52,7 +52,7 @@ export async function loadRoute(
  if (route.resource === "home") {
    const [config, repos] = await Promise.all([
      invoke<Config>("config"),
-
      invoke<RepoInfo[]>("list_repos"),
+
      invoke<RepoInfo[]>("list_repos", { show: "all" }),
    ]);
    return { resource: "home", params: { repos, config } };
  } else if (route.resource === "repo.issue") {