mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 11:20:36 +08:00
Add tauri commands for single repo and cobs
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Author = { did: string; alias?: string };
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
export type Config = {
|
||||
/**
|
||||
* Node alias.
|
||||
* Node Public Key in NID format.
|
||||
*/
|
||||
publicKey: string;
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Author } from "./Author";
|
||||
|
||||
export type Issue = {
|
||||
id: string;
|
||||
author: Author;
|
||||
title: string;
|
||||
state: { status: "closed"; reason: "other" | "solved" } | { status: "open" };
|
||||
assignees: Array<Author>;
|
||||
labels: Array<string>;
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Author } from "./Author";
|
||||
|
||||
export type Patch = {
|
||||
id: string;
|
||||
author: Author;
|
||||
title: string;
|
||||
state:
|
||||
| {
|
||||
status: "draft";
|
||||
}
|
||||
| {
|
||||
status: "open";
|
||||
conflicts: [string, string][];
|
||||
}
|
||||
| {
|
||||
status: "archived";
|
||||
}
|
||||
| {
|
||||
status: "merged";
|
||||
revision: string;
|
||||
commit: string;
|
||||
};
|
||||
assignees: Array<Author>;
|
||||
labels: Array<string>;
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod auth;
|
||||
pub mod cobs;
|
||||
pub mod profile;
|
||||
pub mod repos;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
use radicle::identity::RepoId;
|
||||
use radicle::issue::cache::Issues;
|
||||
use radicle::patch::cache::Patches;
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::types::cobs;
|
||||
use crate::AppState;
|
||||
|
||||
#[tauri::command]
|
||||
pub fn list_issues(
|
||||
ctx: tauri::State<AppState>,
|
||||
rid: RepoId,
|
||||
status: query::IssueStatus,
|
||||
) -> Result<Vec<cobs::Issue>, Error> {
|
||||
let (repo, _) = ctx.repo(rid)?;
|
||||
let issues = ctx.profile.issues(&repo)?;
|
||||
let mut issues: Vec<_> = issues
|
||||
.list()?
|
||||
.filter_map(|r| {
|
||||
let (id, issue) = r.ok()?;
|
||||
(status.matches(issue.state())).then_some((id, issue))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
issues.sort_by(|(_, a), (_, b)| b.timestamp().cmp(&a.timestamp()));
|
||||
let aliases = &ctx.profile.aliases();
|
||||
let issues = issues
|
||||
.into_iter()
|
||||
.map(|(id, issue)| cobs::Issue::new(id, issue, aliases))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok::<_, Error>(issues)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn list_patches(
|
||||
ctx: tauri::State<AppState>,
|
||||
rid: RepoId,
|
||||
status: query::PatchStatus,
|
||||
) -> Result<Vec<cobs::Patch>, Error> {
|
||||
let (repo, _) = ctx.repo(rid)?;
|
||||
let patches = ctx.profile.patches(&repo)?;
|
||||
let mut patches: Vec<_> = patches
|
||||
.list()?
|
||||
.filter_map(|r| {
|
||||
let (id, patch) = r.ok()?;
|
||||
(status.matches(patch.state())).then_some((id, patch))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
patches.sort_by(|(_, a), (_, b)| b.timestamp().cmp(&a.timestamp()));
|
||||
let aliases = &ctx.profile.aliases();
|
||||
let patches = patches
|
||||
.into_iter()
|
||||
.map(|(id, patch)| cobs::Patch::new(id, patch, aliases))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok::<_, Error>(patches)
|
||||
}
|
||||
|
||||
mod query {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use radicle::issue;
|
||||
use radicle::patch;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum IssueStatus {
|
||||
Closed,
|
||||
#[default]
|
||||
Open,
|
||||
All,
|
||||
}
|
||||
|
||||
impl IssueStatus {
|
||||
pub fn matches(&self, issue: &issue::State) -> bool {
|
||||
match self {
|
||||
Self::Open => matches!(issue, issue::State::Open),
|
||||
Self::Closed => matches!(issue, issue::State::Closed { .. }),
|
||||
Self::All => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum PatchStatus {
|
||||
#[default]
|
||||
Open,
|
||||
Draft,
|
||||
Archived,
|
||||
Merged,
|
||||
All,
|
||||
}
|
||||
|
||||
impl PatchStatus {
|
||||
pub fn matches(&self, patch: &patch::State) -> bool {
|
||||
match self {
|
||||
Self::Open => matches!(patch, patch::State::Open { .. }),
|
||||
Self::Draft => matches!(patch, patch::State::Draft),
|
||||
Self::Archived => matches!(patch, patch::State::Archived),
|
||||
Self::Merged => matches!(patch, patch::State::Merged { .. }),
|
||||
Self::All => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use radicle::identity::RepoId;
|
||||
use radicle::storage::ReadStorage;
|
||||
|
||||
use crate::error::Error;
|
||||
@@ -28,3 +29,14 @@ pub fn list_repos(ctx: tauri::State<AppState>) -> Result<Vec<types::repo::RepoIn
|
||||
|
||||
Ok::<_, Error>(infos)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn repo_by_id(
|
||||
ctx: tauri::State<AppState>,
|
||||
rid: RepoId,
|
||||
) -> Result<types::repo::RepoInfo, Error> {
|
||||
let (repo, doc) = ctx.repo(rid)?;
|
||||
let repo_info = ctx.repo_info(&repo, doc)?;
|
||||
|
||||
Ok::<_, Error>(repo_info)
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use radicle::identity;
|
||||
use radicle::node::AliasStore;
|
||||
|
||||
pub(crate) struct Author<'a>(&'a identity::Did);
|
||||
|
||||
impl<'a> Author<'a> {
|
||||
pub fn new(did: &'a identity::Did) -> Self {
|
||||
Self(did)
|
||||
}
|
||||
|
||||
pub fn as_json(&self, aliases: &impl AliasStore) -> Value {
|
||||
aliases.alias(self.0).map_or(
|
||||
json!({ "id": self.0 }),
|
||||
|alias| json!({ "id": self.0, "alias": alias, }),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
mod commands;
|
||||
mod error;
|
||||
mod json;
|
||||
mod types;
|
||||
|
||||
use serde_json::json;
|
||||
@@ -15,7 +14,7 @@ use radicle::patch::cache::Patches;
|
||||
use radicle::storage::git::Repository;
|
||||
use radicle::storage::{ReadRepository, ReadStorage};
|
||||
|
||||
use commands::{auth, profile, repos};
|
||||
use commands::{auth, cobs, profile, repos};
|
||||
use types::repo::SupportedPayloads;
|
||||
|
||||
struct AppState {
|
||||
@@ -35,7 +34,7 @@ impl AppState {
|
||||
let delegates = doc
|
||||
.delegates
|
||||
.into_iter()
|
||||
.map(|did| json::Author::new(&did).as_json(&aliases))
|
||||
.map(|did| types::cobs::Author::new(did, &aliases))
|
||||
.collect::<Vec<_>>();
|
||||
let db = &self.profile.database()?;
|
||||
let seeding = db.count(&rid).unwrap_or_default();
|
||||
@@ -107,6 +106,9 @@ pub fn run() {
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
auth::authenticate,
|
||||
repos::list_repos,
|
||||
repos::repo_by_id,
|
||||
cobs::list_issues,
|
||||
cobs::list_patches,
|
||||
profile::config,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
use radicle::cob::Label;
|
||||
use radicle::identity;
|
||||
use radicle::issue;
|
||||
use radicle::node::{Alias, AliasStore};
|
||||
use radicle::patch;
|
||||
use serde::Serialize;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Serialize, TS)]
|
||||
pub(crate) struct Author {
|
||||
#[ts(as = "String")]
|
||||
did: identity::Did,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[ts(as = "Option<String>")]
|
||||
#[ts(optional)]
|
||||
alias: Option<Alias>,
|
||||
}
|
||||
|
||||
impl Author {
|
||||
pub fn new(did: identity::Did, aliases: &impl AliasStore) -> Self {
|
||||
Self {
|
||||
did,
|
||||
alias: aliases.alias(&did),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(TS, Serialize)]
|
||||
#[ts(export)]
|
||||
pub struct Issue {
|
||||
#[ts(as = "String")]
|
||||
id: String,
|
||||
author: Author,
|
||||
title: String,
|
||||
#[ts(type = "{ status: 'closed', reason: 'other' | 'solved' } | { status: 'open' } ")]
|
||||
state: issue::State,
|
||||
assignees: Vec<Author>,
|
||||
#[ts(as = "Vec<String>")]
|
||||
labels: Vec<Label>,
|
||||
}
|
||||
|
||||
impl Issue {
|
||||
pub fn new(id: issue::IssueId, issue: issue::Issue, aliases: &impl AliasStore) -> Self {
|
||||
Self {
|
||||
id: id.to_string(),
|
||||
author: Author::new(*issue.author().id(), aliases),
|
||||
title: issue.title().to_string(),
|
||||
state: *issue.state(),
|
||||
assignees: issue
|
||||
.assignees()
|
||||
.map(|did| Author::new(*did, aliases))
|
||||
.collect::<Vec<_>>(),
|
||||
labels: issue.labels().cloned().collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(TS, Serialize)]
|
||||
#[ts(export)]
|
||||
pub struct Patch {
|
||||
#[ts(as = "String")]
|
||||
id: String,
|
||||
author: Author,
|
||||
title: String,
|
||||
#[ts(type = r#"{
|
||||
status: 'draft'
|
||||
} | {
|
||||
status: 'open',
|
||||
conflicts: [string, string][]
|
||||
} | {
|
||||
status: 'archived'
|
||||
} | {
|
||||
status: 'merged', revision: string, commit: string
|
||||
} "#)]
|
||||
state: patch::State,
|
||||
assignees: Vec<Author>,
|
||||
#[ts(as = "Vec<String>")]
|
||||
labels: Vec<Label>,
|
||||
}
|
||||
|
||||
impl Patch {
|
||||
pub fn new(id: patch::PatchId, patch: patch::Patch, aliases: &impl AliasStore) -> Self {
|
||||
Self {
|
||||
id: id.to_string(),
|
||||
author: Author::new(*patch.author().id(), aliases),
|
||||
title: patch.title().to_string(),
|
||||
state: patch.state().clone(),
|
||||
assignees: patch
|
||||
.assignees()
|
||||
.map(|did| Author::new(did, aliases))
|
||||
.collect::<Vec<_>>(),
|
||||
labels: patch.labels().cloned().collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ use radicle::node::config::DefaultSeedingPolicy;
|
||||
use radicle::node::Alias;
|
||||
|
||||
/// Service configuration.
|
||||
#[derive(Debug, Clone, TS, Serialize)]
|
||||
#[derive(TS, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct Config {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod cobs;
|
||||
pub mod config;
|
||||
pub mod repo;
|
||||
|
||||
@@ -4,13 +4,15 @@ use ts_rs::TS;
|
||||
|
||||
use radicle::identity::RepoId;
|
||||
|
||||
use super::cobs::Author;
|
||||
|
||||
/// Repos info.
|
||||
#[derive(Serialize, TS)]
|
||||
#[ts(export)]
|
||||
pub struct RepoInfo {
|
||||
pub payloads: SupportedPayloads,
|
||||
#[ts(type = "({ id: string } | { id: string, alias?: string })[]")]
|
||||
pub delegates: Vec<Value>,
|
||||
pub delegates: Vec<Author>,
|
||||
pub threshold: usize,
|
||||
#[ts(type = "{ type: 'public' } | { type: 'private', allow?: string[] }")]
|
||||
pub visibility: radicle::identity::Visibility,
|
||||
|
||||
@@ -4,9 +4,24 @@
|
||||
|
||||
import Header from "@app/components/Header.svelte";
|
||||
import RepoCard from "@app/components/RepoCard.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
export let repos: RepoInfo[];
|
||||
export let config: Config;
|
||||
|
||||
onMount(async () => {
|
||||
const patches = await invoke("list_patches", {
|
||||
rid: "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
|
||||
status: "open",
|
||||
});
|
||||
const issues = await invoke("list_issues", {
|
||||
rid: "rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5",
|
||||
status: "open",
|
||||
});
|
||||
|
||||
console.log(patches, issues);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user