1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use cod_cli::issue::edit::EditIssueArgs;
use cod_client::CodebergClient;
use cod_endpoints::endpoint_generator::EndpointGenerator;
use cod_render::spinner::spin_until_ready;
use cod_render::ui::{fuzzy_select_with_key, multi_fuzzy_select_with_key};
use cod_types::api::edit_options::edit_issue_option::EditIssueOption;
use cod_types::api::issue::Issue;
use cod_types::api::state_type::StateType;
use strum::{Display, EnumIter, IntoEnumIterator};
use crate::text_manipulation::{edit_prompt_for, select_prompt_for};
#[derive(Display, EnumIter, PartialEq, Eq)]
enum EditableFields {
Assignees,
Description,
State,
Title,
}
pub async fn edit_issue(_args: EditIssueArgs, client: &CodebergClient) -> anyhow::Result<()> {
let issues_list = spin_until_ready(client.get_repo_issues(None, None)).await?;
if issues_list.is_empty() {
println!("No issues found in this repository");
}
let selected_issue =
fuzzy_select_with_key(issues_list, select_prompt_for("issue")).and_then(|maybe_issue| {
maybe_issue.ok_or_else(|| anyhow::anyhow!("Nothing selected. Aborting."))
})?;
let selected_update_fields = multi_fuzzy_select_with_key(
EditableFields::iter().collect::<Vec<_>>(),
select_prompt_for("options"),
|_| false,
)?;
let edit_issue_options =
create_update_data(client, selected_update_fields, &selected_issue).await?;
tracing::debug!("{edit_issue_options:?}");
let api_endpoint = EndpointGenerator::repo_update_issue(selected_issue.number)?;
let updated_issue: Issue = client.patch_body(api_endpoint, edit_issue_options).await?;
tracing::debug!("{updated_issue:?}");
Ok(())
}
async fn create_update_data(
client: &CodebergClient,
selected_update_fields: Vec<EditableFields>,
selected_issue: &Issue,
) -> anyhow::Result<EditIssueOption> {
use EditableFields::*;
let mut edit_issue_options = EditIssueOption::from_issue(selected_issue);
if selected_update_fields.contains(&Assignees) {
let assignees_list = client.get_repo_assignees().await?;
let selected_assignees = multi_fuzzy_select_with_key(
assignees_list,
select_prompt_for("assignees"),
|assignee| {
selected_issue
.assignees
.as_ref()
.map_or(false, |assignees| assignees.contains(assignee))
},
)?;
edit_issue_options.assignees.replace(
selected_assignees
.into_iter()
.map(|assignee| assignee.username)
.collect::<Vec<_>>(),
);
}
if selected_update_fields.contains(&Description) {
let new_description =
inquire::Editor::new(edit_prompt_for("the new issue description").as_str())
.with_predefined_text(selected_issue.body.as_str())
.prompt()?;
edit_issue_options.body.replace(new_description);
}
if selected_update_fields.contains(&State) {
let new_state = fuzzy_select_with_key(
StateType::available_for_choosing().to_vec(),
select_prompt_for("state"),
)?;
edit_issue_options
.state
.replace(new_state.unwrap_or(selected_issue.state));
}
if selected_update_fields.contains(&Title) {
let new_title = inquire::Text::new("Choose a new issue title")
.with_default(selected_issue.title.as_str())
.prompt()?;
edit_issue_options.title.replace(new_title);
}
Ok(edit_issue_options)
}