use topcoat::icon::IconData;
use super::register::{CustomizePage, PageRegistration, Registration, ResourceRegistration};
use crate::{Page, PageDef, Resource, ResourceDef};
pub struct Area {
pub(super) slug: String,
pub(super) label: Option<crate::Text>,
pub(super) icon: Option<IconData>,
pub(super) navigation_order: i32,
pub(super) navigation_group: Option<crate::Text>,
pub(super) navigation_hidden: bool,
pub(super) groups: Vec<(AreaGroupLabel, AreaGroup)>,
}
impl Area {
pub fn new(slug: impl Into<String>) -> Self {
Self {
slug: slug.into(),
label: None,
icon: None,
navigation_order: 0,
navigation_group: None,
navigation_hidden: false,
groups: Vec::new(),
}
}
#[must_use]
pub fn label(mut self, label: impl Into<crate::Text>) -> Self {
self.label = Some(label.into());
self
}
#[must_use]
pub fn icon(mut self, icon: IconData) -> Self {
self.icon = Some(icon);
self
}
#[must_use]
pub fn navigation_order(mut self, order: i32) -> Self {
self.navigation_order = order;
self
}
#[must_use]
pub fn navigation_group(mut self, group: impl Into<crate::Text>) -> Self {
self.navigation_group = Some(group.into());
self
}
#[must_use]
pub fn without_navigation(mut self) -> Self {
self.navigation_hidden = true;
self
}
#[must_use]
pub fn group(
mut self,
label: impl Into<crate::Text>,
build: impl FnOnce(AreaGroup) -> AreaGroup,
) -> Self {
self.groups.push((
AreaGroupLabel::Text(label.into()),
build(AreaGroup::default()),
));
self
}
#[must_use]
pub fn tenant_group(mut self, build: impl FnOnce(AreaGroup) -> AreaGroup) -> Self {
self.groups
.push((AreaGroupLabel::Tenant, build(AreaGroup::default())));
self
}
}
impl std::fmt::Debug for Area {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Area")
.field("slug", &self.slug)
.field("label", &self.label)
.field("navigation_order", &self.navigation_order)
.field("navigation_group", &self.navigation_group)
.field("navigation_hidden", &self.navigation_hidden)
.field("groups", &self.groups.len())
.finish_non_exhaustive()
}
}
pub(super) enum AreaGroupLabel {
Text(crate::Text),
Tenant,
}
#[derive(Default)]
pub struct AreaGroup {
pub(super) entries: Vec<AreaEntry>,
}
pub(super) enum AreaEntry {
Registration(Box<dyn Registration>),
Auth(AuthPage, CustomizePage),
AuditLog,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum AuthPage {
Profile,
TwoFactor,
TenantProfile,
}
impl AreaGroup {
#[must_use]
pub fn resource<R: Resource>(self) -> Self {
self.resource_with::<R>(|def| def)
}
#[must_use]
pub fn resource_with<R: Resource>(
mut self,
customize: impl FnOnce(ResourceDef<R>) -> ResourceDef<R> + Send + 'static,
) -> Self {
self.entries.push(AreaEntry::Registration(Box::new(
ResourceRegistration::<R>(Box::new(customize)),
)));
self
}
#[must_use]
pub fn page<P: Page>(self) -> Self {
self.page_with::<P>(|def| def)
}
#[must_use]
pub fn page_with<P: Page>(
mut self,
customize: impl FnOnce(PageDef) -> PageDef + Send + 'static,
) -> Self {
self.entries
.push(AreaEntry::Registration(Box::new(PageRegistration::<P> {
home: false,
customize: Box::new(customize),
_page: std::marker::PhantomData,
})));
self
}
#[must_use]
pub fn profile(self) -> Self {
self.profile_with(|def| def)
}
#[must_use]
pub fn profile_with(self, customize: impl FnOnce(PageDef) -> PageDef + Send + 'static) -> Self {
self.auth_page(AuthPage::Profile, customize)
}
#[must_use]
pub fn two_factor(self) -> Self {
self.two_factor_with(|def| def)
}
#[must_use]
pub fn two_factor_with(
self,
customize: impl FnOnce(PageDef) -> PageDef + Send + 'static,
) -> Self {
self.auth_page(AuthPage::TwoFactor, customize)
}
#[must_use]
pub fn tenant_profile(self) -> Self {
self.tenant_profile_with(|def| def)
}
#[must_use]
pub fn tenant_profile_with(
self,
customize: impl FnOnce(PageDef) -> PageDef + Send + 'static,
) -> Self {
self.auth_page(AuthPage::TenantProfile, customize)
}
#[must_use]
pub fn audit_log(mut self) -> Self {
self.entries.push(AreaEntry::AuditLog);
self
}
fn auth_page(
mut self,
page: AuthPage,
customize: impl FnOnce(PageDef) -> PageDef + Send + 'static,
) -> Self {
self.entries
.push(AreaEntry::Auth(page, Box::new(customize)));
self
}
}
impl std::fmt::Debug for AreaGroup {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AreaGroup")
.field("entries", &self.entries.len())
.finish()
}
}
pub(super) fn settings_paths(
prefix: &str,
placed: &[(AuthPage, String)],
) -> crate::auth::SettingsPaths {
let mut paths = crate::auth::SettingsPaths::under(prefix);
for (page, url) in placed {
let path = match page {
AuthPage::Profile => &mut paths.profile,
AuthPage::TwoFactor => &mut paths.two_factor,
AuthPage::TenantProfile => &mut paths.tenant_profile,
};
path.clone_from(url);
}
paths
}