codeberg-cli 0.5.5

CLI Tool for codeberg similar to gh and glab
Documentation
use crate::render::json::JsonToStdout;
use crate::render::option::{option_debug_display, option_display};
use crate::render::ui::fuzzy_select_with_key;
use crate::types::context::BergContext;
use crate::types::output::OutputMode;
use crate::{actions::GlobalArgs, render::datetime::render_datetime_and_info};
use forgejo_api::structs::{NotificationThread, NotifyGetListQuery};
use miette::{Context, IntoDiagnostic};

use clap::Parser;
#[derive(Debug, Parser)]
pub struct ViewNotificationArgs {
    /// view specific notification if available
    pub id: Option<i64>,

    /// show everything about the notification if available
    #[arg(short, long)]
    pub all: bool,
}

impl ViewNotificationArgs {
    pub async fn run(self, global_args: GlobalArgs) -> miette::Result<()> {
        let ctx = BergContext::new(self, global_args).await?;

        let thread_id = if let Some(id) = ctx.args.id {
            id
        } else {
            let (_, notification_threads) = ctx
                .client
                .notify_get_list(NotifyGetListQuery {
                    ..Default::default()
                })
                .await
                .into_diagnostic()?;
            fuzzy_select_with_key(
                &notification_threads
                    .iter()
                    .filter(|thread| thread.id.is_some())
                    .collect::<Vec<_>>(),
                "notification thread",
                |thread| {
                    option_display(
                        &thread
                            .subject
                            .as_ref()
                            .and_then(|subject| subject.title.as_ref()),
                    )
                },
            )
            .and_then(|thread| thread.id.context("No ID on selected thread"))?
        };

        let selected_notification_thread = ctx
            .client
            .notify_get_thread(thread_id)
            .await
            .into_diagnostic()?;

        match ctx.global_args.output_mode {
            OutputMode::Pretty => {
                present_notification_thread_details(&ctx, selected_notification_thread);
            }
            OutputMode::Json => selected_notification_thread.print_json()?,
        }

        Ok(())
    }
}

fn present_notification_thread_details(
    ctx: &BergContext<ViewNotificationArgs>,
    notification_thread: NotificationThread,
) {
    let table = ctx
        .make_table()
        .add_row(vec![
            String::from("Title"),
            option_display(
                &notification_thread
                    .subject
                    .as_ref()
                    .and_then(|subject| subject.title.as_ref()),
            ),
        ])
        .add_row(vec![
            String::from("URL"),
            option_display(
                &notification_thread
                    .subject
                    .as_ref()
                    .and_then(|subject| subject.html_url.as_ref()),
            ),
        ])
        .add_row(vec![
            String::from("Type"),
            option_display(
                &notification_thread
                    .subject
                    .as_ref()
                    .and_then(|subject| subject.r#type)
                    .and_then(|subject| serde_json::to_string(&subject).ok()),
            ),
        ])
        .add_row(vec![
            String::from("State"),
            option_debug_display(
                &notification_thread
                    .subject
                    .as_ref()
                    .and_then(|subject| subject.state.as_ref()),
            ),
        ])
        .add_row(vec![
            "Unread",
            if notification_thread.unread.is_some_and(|is_true| is_true) {
                "Yes"
            } else {
                "No"
            },
        ])
        .add_row(vec![
            "Pinned",
            if notification_thread.pinned.is_some_and(|is_true| is_true) {
                "Yes"
            } else {
                "No"
            },
        ])
        .add_row(vec![
            String::from("Last updated"),
            option_display(
                &notification_thread
                    .updated_at
                    .as_ref()
                    .map(render_datetime_and_info),
            ),
        ]);

    println!("{table}", table = table.show());
}