diff --git a/crates/radicle-tauri/bindings/IssueAction.ts b/crates/radicle-tauri/bindings/IssueAction.ts new file mode 100644 index 000000000..d0a636cf6 --- /dev/null +++ b/crates/radicle-tauri/bindings/IssueAction.ts @@ -0,0 +1,46 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type IssueAction = + | { type: "assign"; assignees: Array } + | { type: "edit"; title: string } + | { + type: "lifecycle"; + state: + | { status: "closed"; reason: "other" | "solved" } + | { status: "open" }; + } + | { type: "label"; labels: Array } + | { + type: "comment"; + /** + * Comment body. + */ + body: string; + /** + * Comment this is a reply to. + * Should be [`None` | `null`] if it's the top-level comment. + * Should be the root [`CommentId`] if it's a top-level comment. + */ + replyTo: string | null; + /** + * Embeded content. + */ + embeds: Array; + } + | { + type: "comment.edit"; + /** + * Comment being edited. + */ + id: string; + /** + * New value for the comment body. + */ + body: string; + /** + * New value for the embeds list. + */ + embeds: Array; + } + | { type: "comment.redact"; id: string } + | { type: "comment.react"; id: string; reaction: string; active: boolean }; diff --git a/crates/radicle-tauri/src/commands/cob/issue.rs b/crates/radicle-tauri/src/commands/cob/issue.rs index 198ddb55c..e5fcd4374 100644 --- a/crates/radicle-tauri/src/commands/cob/issue.rs +++ b/crates/radicle-tauri/src/commands/cob/issue.rs @@ -38,6 +38,59 @@ pub fn create_issue( Ok::<_, Error>(cobs::Issue::new(issue.id(), &issue, &aliases)) } +#[tauri::command] +pub fn edit_issue( + ctx: tauri::State, + rid: RepoId, + cob_id: git::Oid, + action: cobs::IssueAction, + opts: cobs::CobOptions, +) -> Result { + let mut node = Node::new(ctx.profile.socket()); + let repo = ctx.profile.storage.repository(rid)?; + let signer = ctx.profile.signer()?; + let aliases = ctx.profile.aliases(); + let mut issues = ctx.profile.issues_mut(&repo)?; + let mut issue = issues.get_mut(&cob_id.into())?; + + match action { + cobs::IssueAction::Lifecycle { state } => { + issue.lifecycle(state, &signer)?; + } + cobs::IssueAction::Assign { assignees } => { + issue.assign(assignees, &signer)?; + } + cobs::IssueAction::Label { labels } => { + issue.label(labels, &signer)?; + } + cobs::IssueAction::CommentReact { + id, + reaction, + active, + } => { + issue.react(id, reaction, active, &signer)?; + } + cobs::IssueAction::CommentRedact { id } => { + issue.redact_comment(id, &signer)?; + } + cobs::IssueAction::Comment { .. } => { + unimplemented!("Create of issue comment not yet implemented") + } + cobs::IssueAction::CommentEdit { .. } => { + unimplemented!("Edit of issue comment not yet implemented") + } + cobs::IssueAction::Edit { title } => { + issue.edit(title, &signer)?; + } + } + + if opts.announce() { + node.announce_refs(rid)?; + } + + Ok::<_, Error>(cobs::Issue::new(issue.id(), &issue, &aliases)) +} + #[tauri::command] pub fn list_issues( ctx: tauri::State, diff --git a/crates/radicle-tauri/src/lib.rs b/crates/radicle-tauri/src/lib.rs index 248661f2c..bc5095e3e 100644 --- a/crates/radicle-tauri/src/lib.rs +++ b/crates/radicle-tauri/src/lib.rs @@ -80,6 +80,7 @@ pub fn run() { cob::issue::list_issues, cob::issue::issue_by_id, cob::issue::create_issue, + cob::issue::edit_issue, cob::patch::list_patches, cob::patch::patch_by_id, cob::patch::revisions_by_patch, diff --git a/crates/radicle-tauri/src/types/cobs.rs b/crates/radicle-tauri/src/types/cobs.rs index e5649af13..c935709ac 100644 --- a/crates/radicle-tauri/src/types/cobs.rs +++ b/crates/radicle-tauri/src/types/cobs.rs @@ -1,4 +1,5 @@ use std::collections::BTreeMap; +use std::collections::BTreeSet; use serde::{Deserialize, Serialize}; use ts_rs::TS; @@ -352,3 +353,81 @@ impl Stats { } } } + +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, TS)] +#[serde(tag = "type", rename_all = "camelCase")] +#[ts(export)] +pub enum IssueAction { + /// Assign issue to an actor. + #[serde(rename = "assign")] + Assign { + #[ts(as = "Vec")] + assignees: BTreeSet, + }, + + /// Edit issue title. + #[serde(rename = "edit")] + Edit { title: String }, + + /// Transition to a different state. + #[serde(rename = "lifecycle")] + Lifecycle { + #[ts(type = "{ status: 'closed', reason: 'other' | 'solved' } | { status: 'open' } ")] + state: issue::State, + }, + + /// Modify issue labels. + #[serde(rename = "label")] + Label { + #[ts(as = "Vec")] + labels: BTreeSet, + }, + + /// Comment on a thread. + #[serde(rename_all = "camelCase")] + #[serde(rename = "comment")] + Comment { + /// Comment body. + body: String, + /// Comment this is a reply to. + /// Should be [`None` | `null`] if it's the top-level comment. + /// Should be the root [`CommentId`] if it's a top-level comment. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(as = "Option")] + reply_to: Option, + /// Embeded content. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + #[ts(as = "Vec")] + embeds: Vec>, + }, + + /// Edit a comment. + #[serde(rename = "comment.edit")] + CommentEdit { + /// Comment being edited. + #[ts(as = "String")] + id: cob::thread::CommentId, + /// New value for the comment body. + body: String, + /// New value for the embeds list. + #[ts(as = "Vec")] + embeds: Vec>, + }, + + /// Redact a change. Not all changes can be redacted. + #[serde(rename = "comment.redact")] + CommentRedact { + #[ts(as = "String")] + id: cob::thread::CommentId, + }, + + /// React to a comment. + #[serde(rename = "comment.react")] + CommentReact { + #[ts(as = "String")] + id: cob::thread::CommentId, + #[ts(as = "String")] + reaction: cob::Reaction, + active: bool, + }, +}