Add issue creation and editing

This commit is contained in:
Georg Bauer
2026-07-31 14:39:17 +02:00
parent 86200b4668
commit 228879da15
11 changed files with 1175 additions and 40 deletions

View File

@@ -9,8 +9,8 @@ use tokio::task::JoinSet;
use crate::{
diff,
domain::{
HistoryCommit, HomeData, IssueDetails, MilestoneDetails, PullDetails, RepositoryData,
Server,
HistoryCommit, HomeData, IssueDetails, IssueDraft, IssueEditorData, MilestoneDetails,
PullDetails, RepositoryData, Server, api_date,
},
presentation::compact_date,
};
@@ -430,6 +430,115 @@ pub async fn load_issue(
})
}
pub async fn load_issue_editor(
server: &Server,
owner: &str,
repository: &str,
number: Option<i64>,
) -> Result<IssueEditorData, String> {
let issue = async {
match number {
Some(number) => {
let client = Client::new(&server.url, Some(&server.token))
.map_err(|error| error.to_string())?;
apis::issue_api::issue_get_issue(&client.configuration(), owner, repository, number)
.await
.map(Some)
.map_err(|error| error.to_string())
}
None => Ok(None),
}
};
let (issue, labels, milestones) = tokio::try_join!(
issue,
load_labels(server, owner, repository),
load_milestones(server, owner, repository)
)?;
Ok(IssueEditorData {
issue,
labels,
milestones,
})
}
fn create_issue_option(draft: IssueDraft) -> models::CreateIssueOption {
models::CreateIssueOption {
body: Some(draft.body),
due_date: draft.due_date.map(api_date),
labels: Some(draft.label_ids),
milestone: draft.milestone_id,
..models::CreateIssueOption::new(draft.title)
}
}
fn edit_issue_option(draft: &IssueDraft) -> models::EditIssueOption {
models::EditIssueOption {
body: Some(draft.body.clone()),
due_date: draft.due_date.map(api_date),
milestone: Some(draft.milestone_id.unwrap_or_default()),
title: Some(draft.title.clone()),
unset_due_date: draft.due_date.is_none().then_some(true),
..models::EditIssueOption::new()
}
}
pub async fn create_issue(
server: &Server,
owner: &str,
repository: &str,
draft: IssueDraft,
) -> Result<models::Issue, String> {
let client =
Client::new(&server.url, Some(&server.token)).map_err(|error| error.to_string())?;
apis::issue_api::issue_create_issue(
&client.configuration(),
owner,
repository,
Some(create_issue_option(draft)),
)
.await
.map_err(|error| error.to_string())
}
pub async fn edit_issue(
server: &Server,
owner: &str,
repository: &str,
number: i64,
draft: IssueDraft,
) -> Result<models::Issue, String> {
let client =
Client::new(&server.url, Some(&server.token)).map_err(|error| error.to_string())?;
let configuration = client.configuration();
let issue = apis::issue_api::issue_edit_issue(
&configuration,
owner,
repository,
number,
Some(edit_issue_option(&draft)),
)
.await
.map_err(|error| error.to_string())?;
apis::issue_api::issue_replace_labels(
&configuration,
owner,
repository,
number,
Some(models::IssueLabelsOption {
labels: Some(
draft
.label_ids
.into_iter()
.map(serde_json::Value::from)
.collect(),
),
}),
)
.await
.map_err(|error| error.to_string())?;
Ok(issue)
}
pub async fn load_pull(
server: &Server,
owner: &str,
@@ -845,4 +954,32 @@ mod tests {
assert!(commits[4].bottom_lanes.is_empty());
assert_eq!(commits[4].node_lane, Some(0));
}
#[test]
fn builds_complete_create_and_edit_issue_requests() {
let create = create_issue_option(IssueDraft {
title: "Title".into(),
body: "**Body**".into(),
label_ids: vec![2, 3],
milestone_id: Some(5),
due_date: Some(1_709_164_800),
});
assert_eq!(create.title, "Title");
assert_eq!(create.body.as_deref(), Some("**Body**"));
assert_eq!(create.labels, Some(vec![2, 3]));
assert_eq!(create.milestone, Some(5));
assert_eq!(create.due_date.as_deref(), Some("2024-02-29T00:00:00Z"));
let edit = edit_issue_option(&IssueDraft {
title: "New".into(),
body: String::new(),
label_ids: Vec::new(),
milestone_id: None,
due_date: None,
});
assert_eq!(edit.title.as_deref(), Some("New"));
assert_eq!(edit.body.as_deref(), Some(""));
assert_eq!(edit.milestone, Some(0));
assert_eq!(edit.unset_due_date, Some(true));
}
}