ghtui 0.2.6

A keyboard-driven terminal client for GitHub, with a pull request diff viewer that goes further than GitHub's
//! A repository's Settings tab, at one of its pages ([`crate::settings`]),
//! and the two pages kept as settings are outside it: Actions' caches and
//! the custom properties.

use super::{Family, Route, Target, Url};
use crate::api::model::RepoId;
use crate::api::settings::SettingsPage;
use crate::browse::Build;
use crate::chrome::Section;
use crate::data::DataKey;
use crate::state::State;
use crate::ui::pages::url as links;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Page {
    pub repo: RepoId,
    pub page: SettingsPage,
}

impl Family for Page {
    fn url(&self) -> String {
        format!("{}{}", links::repo(&self.repo), self.page.slug())
    }

    fn title(&self) -> String {
        let repo = &self.repo;
        match self.page {
            SettingsPage::Hook(id) => format!("{repo} · Webhook {id}"),
            SettingsPage::Caches => format!("{repo} · Actions · Caches"),
            SettingsPage::Properties => format!("{repo} · Custom properties"),
            page => format!("{repo} · Settings · {}", page.name()),
        }
    }

    fn repo(&self) -> Option<&RepoId> {
        Some(&self.repo)
    }

    fn up(&self, _: &State) -> Option<Route> {
        let repo = self.repo.clone();
        Some(match self.page {
            SettingsPage::Hook(_) => Route::Settings(Page {
                repo,
                page: SettingsPage::Hooks,
            }),
            SettingsPage::Caches => Route::Runs(super::runs::Page::Actions {
                repo,
                query: String::new(),
            }),
            _ => Route::code(repo),
        })
    }

    fn needs(&self) -> Vec<DataKey> {
        let repo = self.repo.clone();
        vec![
            DataKey::Repo(repo.clone()),
            DataKey::Settings(repo, self.page),
        ]
    }

    fn section(&self) -> Section {
        match self.page {
            SettingsPage::Caches => Section::Actions,
            SettingsPage::Properties => Section::Code,
            _ => Section::Settings,
        }
    }

    fn build(&self, b: Build<'_>, page: &mut crate::ui::page::Page) {
        let settings = b.get(&DataKey::Settings(self.repo.clone(), self.page));
        crate::settings::build(b.state, page, &self.repo, self.page, settings, b.cx.now);
    }
}

/// The Settings tab's pages ghtui has (the rest are on GitHub), and
/// Actions' caches and the custom properties.
pub(super) fn parse_repo(repo: &RepoId, rest: &[&str], _: &Url<'_>) -> Option<Target> {
    use SettingsPage as P;
    let page = match rest {
        ["actions", "caches"] => P::Caches,
        ["custom-properties"] => P::Properties,
        ["settings", rest @ ..] => match rest {
            [] => P::General,
            ["branches" | "branch_protection_rules" | "rules", ..] => P::Branches,
            ["access" | "collaboration"] => P::Access,
            ["hooks"] | ["hooks", "new"] => P::Hooks,
            ["hooks", id] => P::Hook(id.parse().ok().filter(|&n| n > 0)?),
            ["keys", ..] => P::Keys,
            ["secrets", "actions", ..] => P::Secrets,
            ["variables", "actions", ..] => P::Variables,
            ["pages"] => P::Pages,
            _ => return None,
        },
        _ => return None,
    };
    let repo = repo.clone();
    Some(Target::Page(Route::Settings(Page { repo, page })))
}

#[cfg(test)]
pub(crate) fn arb() -> impl proptest::strategy::Strategy<Value = Route> {
    use crate::route::arb::repo;
    use proptest::prelude::*;
    let page = prop_oneof![
        Just(SettingsPage::General),
        Just(SettingsPage::Branches),
        Just(SettingsPage::Access),
        Just(SettingsPage::Hooks),
        Just(SettingsPage::Keys),
        Just(SettingsPage::Secrets),
        Just(SettingsPage::Variables),
        Just(SettingsPage::Pages),
        Just(SettingsPage::Caches),
        Just(SettingsPage::Properties),
        (1..u64::MAX).prop_map(SettingsPage::Hook),
    ];
    (repo(), page).prop_map(|(repo, page)| Route::Settings(Page { repo, page }))
}