pinakes-ui: fix plugin page data loading; add as_json helper
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I6d80eff06e9ca46f916e643d5d8bb6c86a6a6964
This commit is contained in:
parent
1acff0227c
commit
e55fd5cc98
1 changed files with 142 additions and 2 deletions
|
|
@ -10,7 +10,7 @@ use pinakes_plugin_api::{DataSource, HttpMethod};
|
||||||
use crate::client::ApiClient;
|
use crate::client::ApiClient;
|
||||||
|
|
||||||
/// Cached data for a plugin page
|
/// Cached data for a plugin page
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default, PartialEq)]
|
||||||
pub struct PluginPageData {
|
pub struct PluginPageData {
|
||||||
data: HashMap<String, serde_json::Value>,
|
data: HashMap<String, serde_json::Value>,
|
||||||
loading: HashMap<String, bool>,
|
loading: HashMap<String, bool>,
|
||||||
|
|
@ -62,6 +62,19 @@ impl PluginPageData {
|
||||||
self.errors.insert(source, error);
|
self.errors.insert(source, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert all resolved data to a single JSON object for expression
|
||||||
|
/// evaluation
|
||||||
|
#[must_use]
|
||||||
|
pub fn as_json(&self) -> serde_json::Value {
|
||||||
|
serde_json::Value::Object(
|
||||||
|
self
|
||||||
|
.data
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.clone()))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear all data
|
/// Clear all data
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.data.clear();
|
self.data.clear();
|
||||||
|
|
@ -114,7 +127,18 @@ pub async fn fetch_page_data(
|
||||||
) -> Result<HashMap<String, serde_json::Value>, String> {
|
) -> Result<HashMap<String, serde_json::Value>, String> {
|
||||||
let mut results = HashMap::new();
|
let mut results = HashMap::new();
|
||||||
|
|
||||||
for (name, source) in data_sources {
|
// Process non-Transform sources first so Transform sources can reference them
|
||||||
|
let mut ordered: Vec<(&String, &DataSource)> = data_sources
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, s)| !matches!(s, DataSource::Transform { .. }))
|
||||||
|
.collect();
|
||||||
|
ordered.extend(
|
||||||
|
data_sources
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, s)| matches!(s, DataSource::Transform { .. })),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (name, source) in ordered {
|
||||||
let value = match source {
|
let value = match source {
|
||||||
DataSource::Endpoint { path, method, .. } => {
|
DataSource::Endpoint { path, method, .. } => {
|
||||||
// Fetch from endpoint (ignoring params, poll_interval, transform for
|
// Fetch from endpoint (ignoring params, poll_interval, transform for
|
||||||
|
|
@ -168,11 +192,13 @@ pub fn use_plugin_data(
|
||||||
match fetch_page_data(&client.read(), &sources).await {
|
match fetch_page_data(&client.read(), &sources).await {
|
||||||
Ok(results) => {
|
Ok(results) => {
|
||||||
for (name, value) in results {
|
for (name, value) in results {
|
||||||
|
data.write().set_loading(&name, false);
|
||||||
data.write().set_data(name, value);
|
data.write().set_data(name, value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
for name in sources.keys() {
|
for name in sources.keys() {
|
||||||
|
data.write().set_loading(name, false);
|
||||||
data.write().set_error(name.clone(), e.clone());
|
data.write().set_error(name.clone(), e.clone());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -270,4 +296,118 @@ mod tests {
|
||||||
let data = serde_json::json!({"foo": "bar"});
|
let data = serde_json::json!({"foo": "bar"});
|
||||||
assert!(get_json_path(&data, "nonexistent").is_none());
|
assert!(get_json_path(&data, "nonexistent").is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_json_path_array_out_of_bounds() {
|
||||||
|
let data = serde_json::json!({"items": ["a"]});
|
||||||
|
assert!(get_json_path(&data, "items.5").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_json_path_non_array_index() {
|
||||||
|
let data = serde_json::json!({"foo": "bar"});
|
||||||
|
assert!(get_json_path(&data, "foo.0").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_as_json_empty() {
|
||||||
|
let data = PluginPageData::default();
|
||||||
|
assert_eq!(data.as_json(), serde_json::json!({}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_as_json_with_data() {
|
||||||
|
let mut data = PluginPageData::default();
|
||||||
|
data.set_data("users".to_string(), serde_json::json!([{"id": 1}]));
|
||||||
|
data.set_data("count".to_string(), serde_json::json!(42));
|
||||||
|
let json = data.as_json();
|
||||||
|
assert_eq!(json["users"], serde_json::json!([{"id": 1}]));
|
||||||
|
assert_eq!(json["count"], serde_json::json!(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_loading_true_clears_error() {
|
||||||
|
let mut data = PluginPageData::default();
|
||||||
|
data.set_error("src".to_string(), "oops".to_string());
|
||||||
|
assert!(data.error("src").is_some());
|
||||||
|
data.set_loading("src", true);
|
||||||
|
assert!(data.error("src").is_none());
|
||||||
|
assert!(data.is_loading("src"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_loading_false_removes_flag() {
|
||||||
|
let mut data = PluginPageData::default();
|
||||||
|
data.set_loading("src", true);
|
||||||
|
assert!(data.is_loading("src"));
|
||||||
|
data.set_loading("src", false);
|
||||||
|
assert!(!data.is_loading("src"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clear_resets_all_state() {
|
||||||
|
let mut data = PluginPageData::default();
|
||||||
|
data.set_data("x".to_string(), serde_json::json!(1));
|
||||||
|
data.set_loading("x", true);
|
||||||
|
data.set_error("y".to_string(), "err".to_string());
|
||||||
|
data.clear();
|
||||||
|
assert!(!data.has_data("x"));
|
||||||
|
assert!(!data.is_loading("x"));
|
||||||
|
assert!(data.error("y").is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_partial_eq() {
|
||||||
|
let mut a = PluginPageData::default();
|
||||||
|
let mut b = PluginPageData::default();
|
||||||
|
assert_eq!(a, b);
|
||||||
|
a.set_data("k".to_string(), serde_json::json!(1));
|
||||||
|
assert_ne!(a, b);
|
||||||
|
b.set_data("k".to_string(), serde_json::json!(1));
|
||||||
|
assert_eq!(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_fetch_page_data_static_only() {
|
||||||
|
use pinakes_plugin_api::DataSource;
|
||||||
|
|
||||||
|
use crate::client::ApiClient;
|
||||||
|
|
||||||
|
let client = ApiClient::default();
|
||||||
|
let mut sources = HashMap::new();
|
||||||
|
sources.insert("nums".to_string(), DataSource::Static {
|
||||||
|
value: serde_json::json!([1, 2, 3]),
|
||||||
|
});
|
||||||
|
sources.insert("flag".to_string(), DataSource::Static {
|
||||||
|
value: serde_json::json!(true),
|
||||||
|
});
|
||||||
|
|
||||||
|
let results = super::fetch_page_data(&client, &sources).await.unwrap();
|
||||||
|
assert_eq!(results["nums"], serde_json::json!([1, 2, 3]));
|
||||||
|
assert_eq!(results["flag"], serde_json::json!(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_fetch_page_data_transform_after_static() {
|
||||||
|
use pinakes_plugin_api::{DataSource, Expression};
|
||||||
|
|
||||||
|
use crate::client::ApiClient;
|
||||||
|
|
||||||
|
let client = ApiClient::default();
|
||||||
|
let mut sources = HashMap::new();
|
||||||
|
// Insert Transform before Static in the map to test ordering
|
||||||
|
sources.insert("derived".to_string(), DataSource::Transform {
|
||||||
|
source_name: "raw".to_string(),
|
||||||
|
expression: Expression::Literal(serde_json::Value::Null),
|
||||||
|
});
|
||||||
|
sources.insert("raw".to_string(), DataSource::Static {
|
||||||
|
value: serde_json::json!({"ok": true}),
|
||||||
|
});
|
||||||
|
|
||||||
|
let results = super::fetch_page_data(&client, &sources).await.unwrap();
|
||||||
|
// raw must have been processed before derived
|
||||||
|
assert_eq!(results["raw"], serde_json::json!({"ok": true}));
|
||||||
|
// derived gets source_data from raw (transform is identity for now)
|
||||||
|
assert_eq!(results["derived"], serde_json::json!({"ok": true}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue