Allow milestones to be closed and reopened
This commit is contained in:
@@ -141,6 +141,7 @@ pub async fn save_milestone(
|
||||
title: draft.title,
|
||||
description: draft.description,
|
||||
due_on: draft.due_date.map(api_date),
|
||||
state: if draft.closed { "closed" } else { "open" }.into(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -138,6 +138,7 @@ pub struct MilestoneDraft {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub due_date: Option<i64>,
|
||||
pub closed: bool,
|
||||
}
|
||||
|
||||
pub fn open_status() -> String {
|
||||
|
||||
@@ -527,12 +527,10 @@ impl GotchaCore {
|
||||
owner: String,
|
||||
repository: String,
|
||||
id: Option<i64>,
|
||||
title: String,
|
||||
description: String,
|
||||
due_date: Option<i64>,
|
||||
draft: MilestoneEditorPage,
|
||||
) -> Result<i64, GotchaError> {
|
||||
let (owner, repository) = validate_repository(&owner, &repository)?;
|
||||
let title = title.trim();
|
||||
let title = draft.title.trim();
|
||||
if title.is_empty() {
|
||||
return Err("Enter a milestone title.".into());
|
||||
}
|
||||
@@ -546,8 +544,9 @@ impl GotchaCore {
|
||||
id,
|
||||
MilestoneDraft {
|
||||
title: title.into(),
|
||||
description,
|
||||
due_date,
|
||||
description: draft.description,
|
||||
due_date: draft.due_date,
|
||||
closed: draft.closed,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -148,6 +148,7 @@ pub struct MilestoneEditorPage {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub due_date: Option<i64>,
|
||||
pub closed: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Record)]
|
||||
@@ -424,6 +425,10 @@ pub fn milestone_editor_page(milestone: Option<models::Milestone>) -> MilestoneE
|
||||
.as_ref()
|
||||
.and_then(|milestone| milestone.due_on.as_deref())
|
||||
.and_then(parse_api_date),
|
||||
closed: milestone
|
||||
.as_ref()
|
||||
.and_then(|milestone| milestone.state.as_deref())
|
||||
== Some("closed"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1628,13 +1633,17 @@ mod tests {
|
||||
title: Some("Version 1".into()),
|
||||
description: Some("Ship it".into()),
|
||||
due_on: Some("2024-02-29T12:34:56Z".into()),
|
||||
state: Some("closed".into()),
|
||||
..Default::default()
|
||||
}));
|
||||
assert_eq!(page.title, "Version 1");
|
||||
assert_eq!(page.description, "Ship it");
|
||||
assert_eq!(page.due_date, Some(1_709_164_800));
|
||||
assert!(page.closed);
|
||||
|
||||
assert_eq!(milestone_editor_page(None).due_date, None);
|
||||
let new = milestone_editor_page(None);
|
||||
assert_eq!(new.due_date, None);
|
||||
assert!(!new.closed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -130,6 +130,7 @@ pub struct MilestoneDraft {
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub due_on: Option<String>,
|
||||
pub state: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -164,6 +164,11 @@ impl Client {
|
||||
"milestone title must not be empty".into(),
|
||||
));
|
||||
}
|
||||
if !matches!(draft.state.as_str(), "open" | "closed") {
|
||||
return Err(Error::InvalidInput(
|
||||
"milestone state must be open or closed".into(),
|
||||
));
|
||||
}
|
||||
let endpoint = match id {
|
||||
Some(id) if id > 0 => format!(
|
||||
"repos/{}/{}/milestones/{id}",
|
||||
@@ -194,6 +199,7 @@ impl Client {
|
||||
title: draft.title,
|
||||
description: draft.description,
|
||||
due_on: draft.due_on,
|
||||
state: draft.state,
|
||||
});
|
||||
self.execute(request)
|
||||
.await?
|
||||
@@ -219,6 +225,7 @@ struct MilestoneRequest {
|
||||
title: String,
|
||||
description: String,
|
||||
due_on: Option<String>,
|
||||
state: String,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -231,8 +238,10 @@ mod tests {
|
||||
title: "Release".into(),
|
||||
description: String::new(),
|
||||
due_on: None,
|
||||
state: "closed".into(),
|
||||
})
|
||||
.unwrap();
|
||||
assert!(value.get("due_on").unwrap().is_null());
|
||||
assert_eq!(value["state"], "closed");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user