diff --git a/src/api/edge_app/setting.rs b/src/api/edge_app/setting.rs index b51ef38..f60c73c 100644 --- a/src/api/edge_app/setting.rs +++ b/src/api/edge_app/setting.rs @@ -222,11 +222,39 @@ fn is_structured_help_text(help_text: &str) -> bool { serde_json::from_str::(help_text).is_ok_and(|value| value.is_object()) } +fn properties_are_malformed(object: &serde_json::Map) -> bool { + matches!(object.get("properties"), Some(value) if !value.is_object()) +} + +pub(crate) fn extract_display_help_text(help_text: &Value) -> String { + match help_text { + Value::Object(object) if !properties_are_malformed(object) => object + .get("properties") + .and_then(|properties| properties.get("help_text")) + .and_then(|value| value.as_str()) + .unwrap_or_default() + .to_string(), + Value::String(raw) if raw.trim_start().starts_with('{') => { + match serde_json::from_str::(raw) { + Ok(Value::Object(object)) if !properties_are_malformed(&object) => object + .get("properties") + .and_then(|properties| properties.get("help_text")) + .and_then(|value| value.as_str()) + .unwrap_or_default() + .to_string(), + _ => raw.clone(), + } + } + Value::String(raw) => raw.clone(), + _ => String::new(), + } +} + fn has_malformed_properties(help_text: &str) -> bool { let Ok(Value::Object(object)) = serde_json::from_str::(help_text) else { return false; }; - matches!(object.get("properties"), Some(value) if !value.is_object()) + properties_are_malformed(&object) } pub fn help_text_with_display_order(name: &str, help_text: &str, display_order: usize) -> String { @@ -594,6 +622,50 @@ mod display_order_tests { assert_eq!(value["properties"]["display_order"], json!(1)); } + #[test] + fn extract_display_help_text_returns_the_nested_help_text() { + let structured = json!({ + "schema_version": 1, + "properties": { "help_text": "Say hello", "display_order": 0 } + }) + .to_string(); + + assert_eq!(extract_display_help_text(&json!(structured)), "Say hello"); + } + + #[test] + fn extract_display_help_text_returns_empty_when_properties_help_text_is_missing() { + let structured = json!({ + "schema_version": 1, + "properties": { "type": "number", "display_order": 0 } + }) + .to_string(); + + assert_eq!(extract_display_help_text(&json!(structured)), ""); + } + + #[test] + fn extract_display_help_text_returns_raw_json_for_malformed_properties() { + let malformed = json!({ "schema_version": 1, "properties": "nope" }).to_string(); + + assert_eq!(extract_display_help_text(&json!(malformed)), malformed); + } + + #[test] + fn extract_display_help_text_accepts_a_nested_object_value() { + let structured = json!({ + "schema_version": 1, + "properties": { "help_text": "Say hello", "display_order": 0 } + }); + + assert_eq!(extract_display_help_text(&structured), "Say hello"); + } + + #[test] + fn extract_display_help_text_returns_plain_string_verbatim() { + assert_eq!(extract_display_help_text(&json!("Say hello")), "Say hello"); + } + #[test] fn overridden_names_are_left_untouched() { assert_eq!( diff --git a/src/commands/mod.rs b/src/commands/mod.rs index b2e59f2..4856598 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -425,6 +425,11 @@ impl Formatter for EdgeAppSettings { } return Cell::new(""); } + if field_name.eq("help_text") { + let help_text = + crate::api::edge_app::setting::extract_display_help_text(field_value); + return Cell::new(&help_text); + } debug!("field_name: {field_name}, field_value: {field_value:?}"); Cell::new(field_value.as_str().unwrap_or_default()) }, @@ -687,6 +692,44 @@ mod tests { assert!(!EdgeAppSettings::supports_csv()); } + #[test] + fn test_edge_app_settings_formatter_extracts_structured_help_text() { + let data = r#"[ + { + "name": "enable_analytics", + "title": "Enable Analytics", + "edge_app_setting_values": [], + "default_value": "true", + "optional": true, + "type": "string", + "help_text": "{\"properties\":{\"display_order\":0,\"help_text\":\"Enable or disable Sentry and Google Analytics integrations.\"},\"schema_version\":1}" + }, + { + "name": "override_locale", + "title": "Override Locale", + "edge_app_setting_values": [], + "default_value": "en", + "optional": true, + "type": "string", + "help_text": "Override the default locale with a supported language code." + } + ]"#; + let settings = EdgeAppSettings::new(serde_json::from_str(data).unwrap()); + + let output = settings.format(OutputType::HumanReadable); + assert_eq!( + output, + r#"+------------------+------------------+-------+---------------+----------+--------+-------------------------------------------------------------+ +| Name | Title | Value | Default value | Optional | Type | Help text | ++------------------+------------------+-------+---------------+----------+--------+-------------------------------------------------------------+ +| enable_analytics | Enable Analytics | | true | Yes | string | Enable or disable Sentry and Google Analytics integrations. | ++------------------+------------------+-------+---------------+----------+--------+-------------------------------------------------------------+ +| override_locale | Override Locale | | en | Yes | string | Override the default locale with a supported language code. | ++------------------+------------------+-------+---------------+----------+--------+-------------------------------------------------------------+ +"# + ); + } + #[test] fn test_edge_app_instance_formatter_format_output_properly() { let data = r#"[{