From 0525ea6c608a501b54cf67b06d80e1476c33eb88 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Mon, 9 Mar 2026 19:59:21 +0300 Subject: [PATCH] pinakes-core: expose plugin UI pages via `PluginManager` Signed-off-by: NotAShelf Change-Id: Ic58a0174e6592303e863f51fb237220e6a6a6964 --- crates/pinakes-core/src/plugin/mod.rs | 30 +++++++++++++++++++++++ crates/pinakes-core/src/plugin/runtime.rs | 4 ++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/pinakes-core/src/plugin/mod.rs b/crates/pinakes-core/src/plugin/mod.rs index 8ad12cf..5d47ed3 100644 --- a/crates/pinakes-core/src/plugin/mod.rs +++ b/crates/pinakes-core/src/plugin/mod.rs @@ -599,6 +599,36 @@ impl PluginManager { &self.enforcer } + /// List all UI pages provided by loaded plugins. + /// + /// Returns a vector of `(plugin_id, page)` tuples for all enabled plugins + /// that have the `ui_page` kind and provide pages in their manifests. + pub async fn list_ui_pages( + &self, + ) -> Vec<(String, pinakes_plugin_api::UiPage)> { + let registry = self.registry.read().await; + let mut pages = Vec::new(); + for plugin in registry.list_all() { + if !plugin.enabled { + continue; + } + for entry in &plugin.manifest.ui.pages { + let page = match entry { + pinakes_plugin_api::manifest::UiPageEntry::Inline(page) => { + (**page).clone() + }, + pinakes_plugin_api::manifest::UiPageEntry::File { .. } => { + // File-referenced pages require a base path to resolve; + // skip them here as they should have been loaded at startup. + continue; + }, + }; + pages.push((plugin.id.clone(), page)); + } + } + pages + } + /// Check if a plugin is loaded and enabled pub async fn is_plugin_enabled(&self, plugin_id: &str) -> bool { let registry = self.registry.read().await; diff --git a/crates/pinakes-core/src/plugin/runtime.rs b/crates/pinakes-core/src/plugin/runtime.rs index cb93d73..14fe010 100644 --- a/crates/pinakes-core/src/plugin/runtime.rs +++ b/crates/pinakes-core/src/plugin/runtime.rs @@ -493,7 +493,9 @@ impl HostFunctions { if let Some(ref allowed) = caller.data().context.capabilities.network.allowed_domains { - let parsed = if let Ok(u) = url::Url::parse(&url_str) { u } else { + let parsed = if let Ok(u) = url::Url::parse(&url_str) { + u + } else { tracing::warn!(url = %url_str, "plugin provided invalid URL"); return -1; };