diff --git a/crates/pinakes-server/src/app.rs b/crates/pinakes-server/src/app.rs index 39a2509..fddc235 100644 --- a/crates/pinakes-server/src/app.rs +++ b/crates/pinakes-server/src/app.rs @@ -480,6 +480,7 @@ pub fn create_router_with_tls( .route("/database/backup", post(routes::backup::create_backup)) // Plugin management .route("/plugins", get(routes::plugins::list_plugins)) + .route("/plugins/ui-pages", get(routes::plugins::list_plugin_ui_pages)) .route("/plugins/{id}", get(routes::plugins::get_plugin)) .route("/plugins/install", post(routes::plugins::install_plugin)) .route("/plugins/{id}", delete(routes::plugins::uninstall_plugin)) diff --git a/crates/pinakes-server/src/dto/plugins.rs b/crates/pinakes-server/src/dto/plugins.rs index 7872217..4ec883d 100644 --- a/crates/pinakes-server/src/dto/plugins.rs +++ b/crates/pinakes-server/src/dto/plugins.rs @@ -1,3 +1,4 @@ +use pinakes_plugin_api::UiPage; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize)] @@ -21,6 +22,15 @@ pub struct TogglePluginRequest { pub enabled: bool, } +/// A single plugin UI page entry in the list response +#[derive(Debug, Serialize)] +pub struct PluginUiPageEntry { + /// Plugin ID that provides this page + pub plugin_id: String, + /// Full page definition + pub page: UiPage, +} + impl PluginResponse { #[must_use] pub fn new(meta: pinakes_plugin_api::PluginMetadata, enabled: bool) -> Self { diff --git a/crates/pinakes-server/src/routes/plugins.rs b/crates/pinakes-server/src/routes/plugins.rs index 00b77f1..429fb87 100644 --- a/crates/pinakes-server/src/routes/plugins.rs +++ b/crates/pinakes-server/src/routes/plugins.rs @@ -4,7 +4,12 @@ use axum::{ }; use crate::{ - dto::{InstallPluginRequest, PluginResponse, TogglePluginRequest}, + dto::{ + InstallPluginRequest, + PluginResponse, + PluginUiPageEntry, + TogglePluginRequest, + }, error::ApiError, state::AppState, }; @@ -144,6 +149,24 @@ pub async fn toggle_plugin( }))) } +/// List all UI pages provided by loaded plugins +pub async fn list_plugin_ui_pages( + State(state): State, +) -> Result>, ApiError> { + let plugin_manager = state.plugin_manager.as_ref().ok_or_else(|| { + ApiError(pinakes_core::error::PinakesError::InvalidOperation( + "Plugin system is not enabled".to_string(), + )) + })?; + + let pages = plugin_manager.list_ui_pages().await; + let entries = pages + .into_iter() + .map(|(plugin_id, page)| PluginUiPageEntry { plugin_id, page }) + .collect(); + Ok(Json(entries)) +} + /// Reload a plugin (for development) pub async fn reload_plugin( State(state): State,