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
|
//! predefined locations. Unlike full pages, widgets have no data sources of
|
||||||
//! their own and render with empty data context.
|
//! their own and render with empty data context.
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use std::collections::HashMap;
|
||||||
use pinakes_plugin_api::UiWidget;
|
|
||||||
|
|
||||||
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;
|
use crate::client::ApiClient;
|
||||||
|
|
||||||
/// Predefined injection points in the host UI.
|
/// Predefined injection points in the host UI.
|
||||||
|
|
@ -21,6 +26,7 @@ pub enum WidgetLocation {
|
||||||
LibrarySidebar,
|
LibrarySidebar,
|
||||||
DetailPanel,
|
DetailPanel,
|
||||||
SearchFilters,
|
SearchFilters,
|
||||||
|
SettingsSection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetLocation {
|
impl WidgetLocation {
|
||||||
|
|
@ -28,10 +34,11 @@ impl WidgetLocation {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn as_str(self) -> &'static str {
|
pub const fn as_str(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::LibraryHeader => "library_header",
|
Self::LibraryHeader => widget_location::LIBRARY_HEADER,
|
||||||
Self::LibrarySidebar => "library_sidebar",
|
Self::LibrarySidebar => widget_location::LIBRARY_SIDEBAR,
|
||||||
Self::DetailPanel => "detail_panel",
|
Self::DetailPanel => widget_location::DETAIL_PANEL,
|
||||||
Self::SearchFilters => "search_filters",
|
Self::SearchFilters => widget_location::SEARCH_FILTERS,
|
||||||
|
Self::SettingsSection => widget_location::SETTINGS_SECTION,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,11 +48,13 @@ impl WidgetLocation {
|
||||||
pub struct WidgetContainerProps {
|
pub struct WidgetContainerProps {
|
||||||
/// Injection point to render widgets for.
|
/// Injection point to render widgets for.
|
||||||
pub location: WidgetLocation,
|
pub location: WidgetLocation,
|
||||||
/// All widgets from all plugins (plugin_id, widget) pairs.
|
|
||||||
pub widgets: Vec<(String, UiWidget)>,
|
/// All widgets from all plugins (`plugin_id`, widget) pairs.
|
||||||
/// API client (unused by widgets themselves but threaded through for
|
pub widgets: Vec<(String, UiWidget)>,
|
||||||
/// consistency with the rest of the plugin UI system).
|
|
||||||
pub client: Signal<ApiClient>,
|
/// 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`].
|
/// Renders all widgets registered for a specific [`WidgetLocation`].
|
||||||
|
|
@ -107,12 +116,54 @@ pub struct WidgetViewRendererProps {
|
||||||
#[component]
|
#[component]
|
||||||
pub fn WidgetViewRenderer(props: WidgetViewRendererProps) -> Element {
|
pub fn WidgetViewRenderer(props: WidgetViewRendererProps) -> Element {
|
||||||
let empty_data = PluginPageData::default();
|
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! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
class: "plugin-widget",
|
class: "plugin-widget",
|
||||||
"data-plugin-id": props.plugin_id.clone(),
|
"data-plugin-id": props.plugin_id.clone(),
|
||||||
"data-widget-id": props.widget.id.clone(),
|
"data-widget-id": props.widget.id,
|
||||||
{ render_element(&props.widget.content, &empty_data, props.client) }
|
{ 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