use crate::actions::label::display_label;
use crate::actions::GeneralArgs;
use crate::render::color::mk_color_validator;
use crate::render::spinner::spin_until_ready;
use crate::render::ui::{fuzzy_select_with_key, multi_fuzzy_select_with_key};
use crate::types::context::BergContext;
use crate::types::git::OwnerRepo;
use anyhow::Context;
use forgejo_api::structs::{EditLabelOption, IssueListLabelsQuery, Label};
use strum::{Display, VariantArray};
use crate::actions::text_manipulation::{edit_prompt_for, input_prompt_for, select_prompt_for};
use clap::Parser;
#[derive(Parser, Debug)]
pub struct EditLabelArgs {}
#[derive(Display, PartialEq, Eq, VariantArray)]
enum EditableFields {
Name,
Description,
Color,
}
impl EditLabelArgs {
pub async fn run(self, general_args: GeneralArgs) -> anyhow::Result<()> {
let _ = general_args;
let ctx = BergContext::new(self).await?;
let OwnerRepo { repo, owner } = ctx.owner_repo()?;
let label = select_label(&ctx).await?;
let label_id = label.id.context("Selected label doesn't have an ID")?;
let options = create_options(&ctx, &label).await?;
let updated_label = ctx
.client
.issue_edit_label(owner.as_str(), repo.as_str(), label_id, options)
.await?;
tracing::debug!("{updated_label:?}");
Ok(())
}
}
async fn select_label(ctx: &BergContext<EditLabelArgs>) -> anyhow::Result<Label> {
let OwnerRepo { repo, owner } = ctx.owner_repo()?;
let labels_list = spin_until_ready(ctx.client.issue_list_labels(
owner.as_str(),
repo.as_str(),
IssueListLabelsQuery::default(),
))
.await?;
if labels_list.is_empty() {
anyhow::bail!("No labels found in this repository");
}
fuzzy_select_with_key(&labels_list, select_prompt_for("label"), display_label).cloned()
}
async fn create_options(
ctx: &BergContext<EditLabelArgs>,
label: &Label,
) -> anyhow::Result<EditLabelOption> {
let selected_update_fields = multi_fuzzy_select_with_key(
EditableFields::VARIANTS,
select_prompt_for("options"),
|_| false,
|f| f.to_string(),
)?;
let mut options = EditLabelOption {
color: None,
description: None,
exclusive: None,
is_archived: None,
name: None,
};
if selected_update_fields.contains(&&EditableFields::Name) {
let current_name = label.name.as_ref().cloned();
options.name.replace(label_name(ctx, current_name).await?);
}
if selected_update_fields.contains(&&EditableFields::Description) {
let current_description = label.description.as_ref().cloned();
options
.description
.replace(label_description(ctx, current_description).await?);
}
if selected_update_fields.contains(&&EditableFields::Color) {
let current_color = label.color.as_ref().cloned();
options
.color
.replace(label_color(ctx, current_color).await?);
}
Ok(options)
}
async fn label_name(
_ctx: &BergContext<EditLabelArgs>,
current_name: Option<String>,
) -> anyhow::Result<String> {
inquire::Text::new(input_prompt_for("Choose a new label name").as_str())
.with_default(current_name.as_deref().unwrap_or("Enter a label name"))
.prompt()
.map_err(anyhow::Error::from)
}
async fn label_description(
_ctx: &BergContext<EditLabelArgs>,
current_description: Option<String>,
) -> anyhow::Result<String> {
inquire::Editor::new(edit_prompt_for("a description").as_str())
.with_predefined_text(
current_description
.as_deref()
.unwrap_or("Enter a label description"),
)
.prompt()
.map_err(anyhow::Error::from)
}
async fn label_color(
_ctx: &BergContext<EditLabelArgs>,
current_color: Option<String>,
) -> anyhow::Result<String> {
mk_color_validator(
inquire::Text::new(input_prompt_for("Enter a color").as_str())
.with_default(current_color.as_deref().unwrap_or("Enter a label color")),
)
.prompt()
.map_err(anyhow::Error::from)
}