use std::{any::TypeId, collections::HashMap, sync::Arc};
use topcoat::context::{Cx, try_app_context, try_request_context};
use super::{
relations::Child,
search::{RelationSearchFn, SearchFn},
shell::{Brand, ShellAssets},
};
use crate::{auth::Auth, navigation::NavigationItem, resource::Mounts, upload::InstalledUploader};
pub(crate) struct PanelState {
pub(crate) prefix: String,
pub(crate) nav_items: Vec<NavigationItem>,
pub(crate) brand: Option<Brand>,
pub(crate) dark_mode: bool,
pub(crate) shell_assets: Option<ShellAssets>,
pub(crate) search: HashMap<String, SearchFn>,
pub(crate) relations: HashMap<(String, String), RelationSearchFn>,
pub(crate) children: HashMap<TypeId, Child>,
pub(crate) mounts: Arc<Mounts>,
pub(crate) root_redirect: Option<String>,
pub(crate) auth: Auth,
pub(crate) login_hint: Option<String>,
pub(crate) uploads: Option<InstalledUploader>,
pub(crate) served_paths: Vec<String>,
pub(crate) urls: HashMap<TypeId, String>,
}
impl PanelState {
pub(crate) fn gates(&self) -> bool {
!self.auth.is_disabled()
}
pub(crate) fn serves(&self, path: &str) -> bool {
under_prefix(&self.prefix, path)
}
}
pub(crate) fn under_prefix(prefix: &str, path: &str) -> bool {
path.strip_prefix(prefix)
.is_some_and(|rest| rest.is_empty() || rest.starts_with(['/', '?']))
}
#[derive(Default)]
pub(crate) struct Panels(pub(crate) Vec<Arc<PanelState>>);
impl Panels {
pub(crate) fn by_prefix(&self, prefix: &str) -> Option<&Arc<PanelState>> {
self.0.iter().find(|panel| panel.prefix == prefix)
}
pub(crate) fn by_path(&self, path: &str) -> Option<&Arc<PanelState>> {
self.0.iter().find(|panel| panel.serves(path))
}
pub(crate) fn all_gate(&self) -> bool {
self.0.iter().all(|panel| panel.gates())
}
pub(crate) fn any_gates(&self) -> bool {
self.0.iter().any(|panel| panel.gates())
}
}
#[derive(Clone)]
pub(crate) struct CurrentPanel(pub(crate) Arc<PanelState>);
pub(crate) fn current(cx: &Cx) -> Option<&Arc<PanelState>> {
if let Some(CurrentPanel(panel)) = try_request_context::<CurrentPanel>(cx) {
return Some(panel);
}
match try_app_context::<Panels>(cx).map(|panels| panels.0.as_slice()) {
Some([only]) => Some(only),
_ => None,
}
}
pub(crate) fn panels(cx: &Cx) -> Option<&Panels> {
try_app_context::<Panels>(cx)
}