pinakes-ui: add SettingsSection widget target; align location strings with schema constants
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I9a5b91457136254fdf5fa582899079e46a6a6964
This commit is contained in:
parent
5d7076426c
commit
0baa57d48d
1 changed files with 64 additions and 13 deletions
|
|
@ -4,10 +4,15 @@
|
|||
//! predefined locations. Unlike full pages, widgets have no data sources of
|
||||
//! their own and render with empty data context.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use pinakes_plugin_api::UiWidget;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{data::PluginPageData, renderer::render_element};
|
||||
use dioxus::prelude::*;
|
||||
use pinakes_plugin_api::{ActionDefinition, UiWidget, widget_location};
|
||||
|
||||
use super::{
|
||||
data::PluginPageData,
|
||||
renderer::{RenderContext, render_element},
|
||||
};
|
||||
use crate::client::ApiClient;
|
||||
|
||||
/// Predefined injection points in the host UI.
|
||||
|
|
@ -21,6 +26,7 @@ pub enum WidgetLocation {
|
|||
LibrarySidebar,
|
||||
DetailPanel,
|
||||
SearchFilters,
|
||||
SettingsSection,
|
||||
}
|
||||
|
||||
impl WidgetLocation {
|
||||
|
|
@ -28,10 +34,11 @@ impl WidgetLocation {
|
|||
#[must_use]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::LibraryHeader => "library_header",
|
||||
Self::LibrarySidebar => "library_sidebar",
|
||||
Self::DetailPanel => "detail_panel",
|
||||
Self::SearchFilters => "search_filters",
|
||||
Self::LibraryHeader => widget_location::LIBRARY_HEADER,
|
||||
Self::LibrarySidebar => widget_location::LIBRARY_SIDEBAR,
|
||||
Self::DetailPanel => widget_location::DETAIL_PANEL,
|
||||
Self::SearchFilters => widget_location::SEARCH_FILTERS,
|
||||
Self::SettingsSection => widget_location::SETTINGS_SECTION,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,11 +48,13 @@ impl WidgetLocation {
|
|||
pub struct WidgetContainerProps {
|
||||
/// Injection point to render widgets for.
|
||||
pub location: WidgetLocation,
|
||||
/// All widgets from all plugins (plugin_id, widget) pairs.
|
||||
pub widgets: Vec<(String, UiWidget)>,
|
||||
/// API client (unused by widgets themselves but threaded through for
|
||||
/// consistency with the rest of the plugin UI system).
|
||||
pub client: Signal<ApiClient>,
|
||||
|
||||
/// All widgets from all plugins (`plugin_id`, widget) pairs.
|
||||
pub widgets: Vec<(String, UiWidget)>,
|
||||
|
||||
/// API client. It is actually unused by widgets themselves but threaded
|
||||
/// through for consistency with the rest of the plugin UI system.
|
||||
pub client: Signal<ApiClient>,
|
||||
}
|
||||
|
||||
/// Renders all widgets registered for a specific [`WidgetLocation`].
|
||||
|
|
@ -107,12 +116,54 @@ pub struct WidgetViewRendererProps {
|
|||
#[component]
|
||||
pub fn WidgetViewRenderer(props: WidgetViewRendererProps) -> Element {
|
||||
let empty_data = PluginPageData::default();
|
||||
let feedback = use_signal(|| None::<(String, bool)>);
|
||||
let navigate = use_signal(|| None::<String>);
|
||||
let refresh = use_signal(|| 0u32);
|
||||
let modal = use_signal(|| None::<pinakes_plugin_api::UiElement>);
|
||||
let local_state = use_signal(HashMap::<String, serde_json::Value>::new);
|
||||
let ctx = RenderContext {
|
||||
client: props.client,
|
||||
feedback,
|
||||
navigate,
|
||||
refresh,
|
||||
modal,
|
||||
local_state,
|
||||
};
|
||||
let empty_actions: HashMap<String, ActionDefinition> = HashMap::new();
|
||||
rsx! {
|
||||
div {
|
||||
class: "plugin-widget",
|
||||
"data-plugin-id": props.plugin_id.clone(),
|
||||
"data-widget-id": props.widget.id.clone(),
|
||||
{ render_element(&props.widget.content, &empty_data, props.client) }
|
||||
"data-widget-id": props.widget.id,
|
||||
{ render_element(&props.widget.content, &empty_data, &empty_actions, ctx) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_widget_location_settings_section_str() {
|
||||
assert_eq!(WidgetLocation::SettingsSection.as_str(), "settings_section");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_widget_location_all_variants_unique() {
|
||||
let locations = [
|
||||
WidgetLocation::LibraryHeader,
|
||||
WidgetLocation::LibrarySidebar,
|
||||
WidgetLocation::DetailPanel,
|
||||
WidgetLocation::SearchFilters,
|
||||
WidgetLocation::SettingsSection,
|
||||
];
|
||||
let strings: Vec<&str> = locations.iter().map(|l| l.as_str()).collect();
|
||||
let unique: std::collections::HashSet<_> = strings.iter().collect();
|
||||
assert_eq!(
|
||||
strings.len(),
|
||||
unique.len(),
|
||||
"all location strings must be unique"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue