Add tauri commands to create comments and reply

This commit is contained in:
Sebastian Martinez
2024-09-19 16:00:13 +02:00
parent 8731506b94
commit 9334ffb3c5
10 changed files with 231 additions and 1 deletions
+3
View File
@@ -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 CobOptions = { announce?: boolean };
+9
View File
@@ -0,0 +1,9 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { CodeRange } from "./CodeRange";
export type CodeLocation = {
commit: string;
path: string;
old: CodeRange | null;
new: CodeRange | null;
};
+5
View File
@@ -0,0 +1,5 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type CodeRange =
| { type: "lines"; range: { start: number; end: number } }
| { type: "chars"; line: number; range: { start: number; end: number } };
+8
View File
@@ -0,0 +1,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type NewIssueComment = {
id: string;
body: string;
replyTo?: string;
embeds: { name: string; content: string }[];
};
+11
View File
@@ -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 { CodeLocation } from "./CodeLocation";
export type NewPatchComment = {
id: string;
revision: string;
body: string;
replyTo?: string;
location: CodeLocation | null;
embeds: { name: string; content: string }[];
};
+1
View File
@@ -2,3 +2,4 @@ pub mod auth;
pub mod cobs;
pub mod profile;
pub mod repos;
pub mod thread;
+68
View File
@@ -0,0 +1,68 @@
use std::str::FromStr;
use radicle::cob::{EntryId, ObjectId};
use radicle::git::Oid;
use radicle::identity::RepoId;
use radicle::node::Handle;
use radicle::storage::ReadStorage;
use radicle::Node;
use crate::error::Error;
use crate::types::cobs::{CobOptions, NewIssueComment, NewPatchComment};
use crate::AppState;
#[tauri::command]
pub fn create_issue_comment(
ctx: tauri::State<AppState>,
rid: RepoId,
new: NewIssueComment,
opts: CobOptions,
) -> Result<Oid, Error> {
let mut node = Node::new(ctx.profile.socket());
let signer = ctx.profile.signer()?;
let issue_id = ObjectId::from_str(&new.id)?;
let repo = ctx.profile.storage.repository(rid)?;
let mut issues = ctx.profile.issues_mut(&repo)?;
let mut issue = issues.get_mut(&issue_id)?;
let id = new.reply_to.unwrap_or_else(|| {
let (root_id, _) = issue.root();
*root_id
});
let oid = issue.comment(new.body, id, new.embeds, &signer)?;
if opts.announce() {
node.announce_refs(rid)?;
}
Ok::<_, Error>(oid)
}
#[tauri::command]
pub fn create_patch_comment(
ctx: tauri::State<AppState>,
rid: RepoId,
new: NewPatchComment,
opts: CobOptions,
) -> Result<Oid, Error> {
let mut node = Node::new(ctx.profile.socket());
let signer = ctx.profile.signer()?;
let patch_id = ObjectId::from_str(&new.id)?;
let revision_id = EntryId::from_str(&new.revision)?;
let repo = ctx.profile.storage.repository(rid)?;
let mut patches = ctx.profile.patches_mut(&repo)?;
let mut patch = patches.get_mut(&patch_id)?;
let oid = patch.comment(
revision_id.into(),
new.body,
new.reply_to,
new.location.map(|l| l.into()),
new.embeds,
&signer,
)?;
if opts.announce() {
node.announce_refs(rid)?;
}
Ok::<_, Error>(oid)
}
+12
View File
@@ -54,6 +54,14 @@ pub enum Error {
#[error(transparent)]
Surf(#[from] radicle_surf::Error),
/// Issue error.
#[error(transparent)]
Issue(#[from] radicle::issue::Error),
/// Patch error.
#[error(transparent)]
Patch(#[from] radicle::patch::Error),
/// Crypto error.
#[error(transparent)]
Crypto(#[from] radicle::crypto::ssh::keystore::Error),
@@ -77,6 +85,10 @@ pub enum Error {
#[error(transparent)]
Tauri(#[from] tauri::Error),
/// Parse ObjectId error.
#[error(transparent)]
ParseObjectId(#[from] radicle::cob::object::ParseObjectId),
/// Storage error.
#[error(transparent)]
Storage(#[from] radicle::storage::Error),
+3 -1
View File
@@ -17,7 +17,7 @@ use radicle::storage::git::Repository;
use radicle::storage::{ReadRepository, ReadStorage};
use radicle::Node;
use commands::{auth, cobs, profile, repos};
use commands::{auth, cobs, profile, repos, thread};
use types::repo::SupportedPayloads;
struct AppState {
@@ -142,6 +142,8 @@ pub fn run() {
repos::repo_by_id,
cobs::list_issues,
cobs::list_patches,
thread::create_issue_comment,
thread::create_patch_comment,
profile::config,
])
.run(tauri::generate_context!())
+111
View File
@@ -1,8 +1,10 @@
use radicle::cob;
use radicle::git;
use radicle::identity;
use radicle::issue;
use radicle::node::{Alias, AliasStore};
use radicle::patch;
use serde::Deserialize;
use serde::Serialize;
use ts_rs::TS;
@@ -103,3 +105,112 @@ impl Patch {
}
}
}
#[derive(TS, Serialize, Deserialize)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct NewPatchComment {
pub id: String,
pub revision: String,
pub body: String,
#[ts(as = "Option<String>")]
#[ts(optional)]
pub reply_to: Option<cob::thread::CommentId>,
pub location: Option<CodeLocation>,
#[ts(type = "{ name: string, content: string }[]")]
pub embeds: Vec<cob::Embed>,
}
#[derive(TS, Serialize, Deserialize)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct NewIssueComment {
pub id: String,
pub body: String,
#[ts(as = "Option<String>")]
#[ts(optional)]
pub reply_to: Option<cob::thread::CommentId>,
#[ts(type = "{ name: string, content: string }[]")]
pub embeds: Vec<cob::Embed>,
}
#[derive(TS, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub struct CodeLocation {
#[ts(as = "String")]
commit: git::Oid,
path: std::path::PathBuf,
old: Option<CodeRange>,
new: Option<CodeRange>,
}
impl From<cob::CodeLocation> for CodeLocation {
fn from(val: cob::CodeLocation) -> Self {
Self {
commit: val.commit,
path: val.path,
old: val.old.map(|o| o.into()),
new: val.new.map(|o| o.into()),
}
}
}
impl From<CodeLocation> for cob::CodeLocation {
fn from(val: CodeLocation) -> Self {
Self {
commit: val.commit,
path: val.path,
old: val.old.map(|o| o.into()),
new: val.new.map(|o| o.into()),
}
}
}
#[derive(TS, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
#[ts(export)]
pub enum CodeRange {
Lines {
#[ts(type = "{ start: number, end: number }")]
range: std::ops::Range<usize>,
},
Chars {
line: usize,
#[ts(type = "{ start: number, end: number }")]
range: std::ops::Range<usize>,
},
}
impl From<cob::CodeRange> for CodeRange {
fn from(val: cob::CodeRange) -> Self {
match val {
cob::CodeRange::Chars { line, range } => Self::Chars { line, range },
cob::CodeRange::Lines { range } => Self::Lines { range },
}
}
}
impl From<CodeRange> for cob::CodeRange {
fn from(val: CodeRange) -> Self {
match val {
CodeRange::Chars { line, range } => Self::Chars { line, range },
CodeRange::Lines { range } => Self::Lines { range },
}
}
}
#[derive(TS, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[ts(export)]
pub struct CobOptions {
#[ts(as = "Option<bool>")]
#[ts(optional)]
announce: Option<bool>,
}
impl CobOptions {
pub fn announce(&self) -> bool {
self.announce.unwrap_or(true)
}
}