Close, reopen, and delete issues on iPhone

This commit is contained in:
Georg Bauer
2026-08-01 15:48:14 +02:00
parent d0ec533da6
commit 5a48456333
11 changed files with 269 additions and 10 deletions

View File

@@ -304,6 +304,36 @@ pub async fn edit_issue(
.map_err(message)
}
pub async fn set_issue_closed(
server: &Server,
owner: &str,
repository: &str,
number: i64,
closed: bool,
) -> Result<(), String> {
client(server)?
.set_issue_state(
&scope(owner, repository)?,
&[number],
if closed { "closed" } else { "open" },
)
.await
.map(|_| ())
.map_err(message)
}
pub async fn delete_issue(
server: &Server,
owner: &str,
repository: &str,
number: i64,
) -> Result<(), String> {
client(server)?
.delete_issue(&scope(owner, repository)?, number)
.await
.map_err(message)
}
pub async fn load_pull(
server: &Server,
owner: &str,
@@ -382,6 +412,7 @@ fn shared_issue_draft(draft: IssueDraft) -> gotcha_gitea::IssueDraft {
label_ids: draft.label_ids,
milestone_id: draft.milestone_id,
due_date: draft.due_date.map(api_date),
closed: draft.closed,
}
}

View File

@@ -132,6 +132,7 @@ pub struct IssueDraft {
pub label_ids: Vec<i64>,
pub milestone_id: Option<i64>,
pub due_date: Option<i64>,
pub closed: bool,
}
pub struct MilestoneDraft {

View File

@@ -445,6 +445,7 @@ impl GotchaCore {
label_ids: Vec<i64>,
milestone_id: Option<i64>,
due_date: Option<i64>,
closed: bool,
) -> Result<i64, GotchaError> {
let (owner, repository) = validate_repository(&owner, &repository)?;
let title = title.trim();
@@ -468,6 +469,7 @@ impl GotchaCore {
label_ids,
milestone_id,
due_date,
closed,
};
let server = self.server()?;
let issue = match number {
@@ -479,6 +481,35 @@ impl GotchaCore {
.ok_or_else(|| "The saved issue has no number.".into())
}
pub async fn set_issue_closed(
&self,
owner: String,
repository: String,
number: i64,
closed: bool,
) -> Result<(), GotchaError> {
let (owner, repository) = validate_repository(&owner, &repository)?;
if number <= 0 {
return Err("Invalid issue number.".into());
}
set_issue_closed(&self.server()?, owner, repository, number, closed).await?;
Ok(())
}
pub async fn delete_issue(
&self,
owner: String,
repository: String,
number: i64,
) -> Result<(), GotchaError> {
let (owner, repository) = validate_repository(&owner, &repository)?;
if number <= 0 {
return Err("Invalid issue number.".into());
}
delete_issue(&self.server()?, owner, repository, number).await?;
Ok(())
}
pub async fn milestones(
&self,
owner: String,

View File

@@ -103,6 +103,7 @@ pub struct IssueEditorPage {
pub title: String,
pub body: String,
pub due_date: Option<i64>,
pub closed: bool,
pub labels: Vec<IssueEditorLabel>,
pub milestones: Vec<IssueEditorMilestone>,
}
@@ -666,6 +667,7 @@ pub fn issue_editor_page(data: IssueEditorData) -> IssueEditorPage {
.as_ref()
.and_then(|issue| issue.due_date.as_deref())
.and_then(parse_api_date),
closed: data.issue.as_ref().and_then(|issue| issue.state.as_deref()) == Some("closed"),
labels,
milestones,
}
@@ -1513,6 +1515,7 @@ mod tests {
title: Some("Title".into()),
body: Some("Body".into()),
due_date: Some("2024-02-29T18:00:00Z".into()),
state: Some("closed".into()),
labels: Some(vec![selected_label.clone()]),
milestone: Some(Box::new(models::Milestone {
id: Some(4),
@@ -1533,8 +1536,16 @@ mod tests {
assert_eq!((page.title.as_str(), page.body.as_str()), ("Title", "Body"));
assert_eq!(page.due_date, Some(1_709_164_800));
assert!(page.closed);
assert!(page.labels[0].selected);
assert!(page.milestones[0].selected);
let new = issue_editor_page(IssueEditorData {
issue: None,
labels: Vec::new(),
milestones: Vec::new(),
});
assert!(!new.closed);
}
#[test]

View File

@@ -108,6 +108,7 @@ pub struct IssueDraft {
pub label_ids: Vec<i64>,
pub milestone_id: Option<i64>,
pub due_date: Option<String>,
pub closed: bool,
}
#[derive(Clone, Debug)]

View File

@@ -463,6 +463,7 @@ pub fn comment_can_edit(comment: &models::Comment, viewer_id: Option<i64>) -> bo
fn create_issue_option(draft: IssueDraft) -> models::CreateIssueOption {
models::CreateIssueOption {
body: Some(draft.body),
closed: Some(draft.closed),
due_date: draft.due_date,
labels: Some(draft.label_ids),
milestone: draft.milestone_id,
@@ -476,6 +477,7 @@ fn edit_issue_draft(draft: IssueDraft) -> EditIssue {
body: Some(draft.body),
due_date: draft.due_date.clone(),
milestone: Some(draft.milestone_id.unwrap_or_default()),
state: Some(if draft.closed { "closed" } else { "open" }.into()),
title: Some(draft.title),
unset_due_date: draft.due_date.is_none().then_some(true),
..models::EditIssueOption::new()
@@ -552,13 +554,16 @@ mod tests {
label_ids: vec![2, 4],
milestone_id: None,
due_date: None,
closed: true,
};
let create = create_issue_option(draft.clone());
assert_eq!(create.title, "Title");
assert_eq!(create.body.as_deref(), Some("Body"));
assert_eq!(create.closed, Some(true));
assert_eq!(create.labels, Some(vec![2, 4]));
let edit = edit_issue_draft(draft);
assert_eq!(edit.option.milestone, Some(0));
assert_eq!(edit.option.state.as_deref(), Some("closed"));
assert_eq!(edit.option.unset_due_date, Some(true));
assert_eq!(edit.replace_labels, Some(vec![2, 4]));
}