diff --git a/.generator/schemas/v1/openapi.yaml b/.generator/schemas/v1/openapi.yaml index 4fc8dbe37..afb32a4a8 100644 --- a/.generator/schemas/v1/openapi.yaml +++ b/.generator/schemas/v1/openapi.yaml @@ -2952,11 +2952,24 @@ components: description: Metrics query definition. example: avg:system.cpu.user{*} type: string + semantic_mode: + $ref: '#/components/schemas/FormulaAndFunctionMetricSemanticMode' required: - data_source - query - name type: object + FormulaAndFunctionMetricSemanticMode: + description: Semantic mode for metrics queries. This determines how metrics + from different sources are combined or displayed. + enum: + - combined + - native + example: combined + type: string + x-enum-varnames: + - COMBINED + - NATIVE FormulaAndFunctionProcessQueryDataSource: description: Data sources that rely on the process backend. enum: diff --git a/examples/v1_dashboards_CreateDashboard_3685886950.rs b/examples/v1_dashboards_CreateDashboard_3685886950.rs new file mode 100644 index 000000000..eaed04f55 --- /dev/null +++ b/examples/v1_dashboards_CreateDashboard_3685886950.rs @@ -0,0 +1,55 @@ +// Create a new dashboard with a timeseries widget using formulas and functions +// metrics query with native semantic_mode +use datadog_api_client::datadog; +use datadog_api_client::datadogV1::api_dashboards::DashboardsAPI; +use datadog_api_client::datadogV1::model::Dashboard; +use datadog_api_client::datadogV1::model::DashboardLayoutType; +use datadog_api_client::datadogV1::model::FormulaAndFunctionMetricDataSource; +use datadog_api_client::datadogV1::model::FormulaAndFunctionMetricQueryDefinition; +use datadog_api_client::datadogV1::model::FormulaAndFunctionMetricSemanticMode; +use datadog_api_client::datadogV1::model::FormulaAndFunctionQueryDefinition; +use datadog_api_client::datadogV1::model::FormulaAndFunctionResponseFormat; +use datadog_api_client::datadogV1::model::TimeseriesWidgetDefinition; +use datadog_api_client::datadogV1::model::TimeseriesWidgetDefinitionType; +use datadog_api_client::datadogV1::model::TimeseriesWidgetRequest; +use datadog_api_client::datadogV1::model::Widget; +use datadog_api_client::datadogV1::model::WidgetDefinition; +use datadog_api_client::datadogV1::model::WidgetDisplayType; +use datadog_api_client::datadogV1::model::WidgetFormula; + +#[tokio::main] +async fn main() { + let body = Dashboard::new( + DashboardLayoutType::ORDERED, + "Example-Dashboard with native semantic_mode".to_string(), + vec![Widget::new(WidgetDefinition::TimeseriesWidgetDefinition( + Box::new(TimeseriesWidgetDefinition::new( + vec![TimeseriesWidgetRequest::new() + .display_type(WidgetDisplayType::LINE) + .formulas(vec![WidgetFormula::new("query1".to_string())]) + .queries(vec![ + FormulaAndFunctionQueryDefinition::FormulaAndFunctionMetricQueryDefinition( + Box::new( + FormulaAndFunctionMetricQueryDefinition::new( + FormulaAndFunctionMetricDataSource::METRICS, + "query1".to_string(), + "avg:system.cpu.user{*}".to_string(), + ) + .semantic_mode(FormulaAndFunctionMetricSemanticMode::NATIVE), + ), + ), + ]) + .response_format(FormulaAndFunctionResponseFormat::TIMESERIES)], + TimeseriesWidgetDefinitionType::TIMESERIES, + )), + ))], + ); + let configuration = datadog::Configuration::new(); + let api = DashboardsAPI::with_config(configuration); + let resp = api.create_dashboard(body).await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/examples/v1_dashboards_CreateDashboard_865807520.rs b/examples/v1_dashboards_CreateDashboard_865807520.rs new file mode 100644 index 000000000..2cdbf9aab --- /dev/null +++ b/examples/v1_dashboards_CreateDashboard_865807520.rs @@ -0,0 +1,55 @@ +// Create a new dashboard with a timeseries widget using formulas and functions +// metrics query with combined semantic_mode +use datadog_api_client::datadog; +use datadog_api_client::datadogV1::api_dashboards::DashboardsAPI; +use datadog_api_client::datadogV1::model::Dashboard; +use datadog_api_client::datadogV1::model::DashboardLayoutType; +use datadog_api_client::datadogV1::model::FormulaAndFunctionMetricDataSource; +use datadog_api_client::datadogV1::model::FormulaAndFunctionMetricQueryDefinition; +use datadog_api_client::datadogV1::model::FormulaAndFunctionMetricSemanticMode; +use datadog_api_client::datadogV1::model::FormulaAndFunctionQueryDefinition; +use datadog_api_client::datadogV1::model::FormulaAndFunctionResponseFormat; +use datadog_api_client::datadogV1::model::TimeseriesWidgetDefinition; +use datadog_api_client::datadogV1::model::TimeseriesWidgetDefinitionType; +use datadog_api_client::datadogV1::model::TimeseriesWidgetRequest; +use datadog_api_client::datadogV1::model::Widget; +use datadog_api_client::datadogV1::model::WidgetDefinition; +use datadog_api_client::datadogV1::model::WidgetDisplayType; +use datadog_api_client::datadogV1::model::WidgetFormula; + +#[tokio::main] +async fn main() { + let body = Dashboard::new( + DashboardLayoutType::ORDERED, + "Example-Dashboard with combined semantic_mode".to_string(), + vec![Widget::new(WidgetDefinition::TimeseriesWidgetDefinition( + Box::new(TimeseriesWidgetDefinition::new( + vec![TimeseriesWidgetRequest::new() + .display_type(WidgetDisplayType::LINE) + .formulas(vec![WidgetFormula::new("query1".to_string())]) + .queries(vec![ + FormulaAndFunctionQueryDefinition::FormulaAndFunctionMetricQueryDefinition( + Box::new( + FormulaAndFunctionMetricQueryDefinition::new( + FormulaAndFunctionMetricDataSource::METRICS, + "query1".to_string(), + "avg:system.cpu.user{*}".to_string(), + ) + .semantic_mode(FormulaAndFunctionMetricSemanticMode::COMBINED), + ), + ), + ]) + .response_format(FormulaAndFunctionResponseFormat::TIMESERIES)], + TimeseriesWidgetDefinitionType::TIMESERIES, + )), + ))], + ); + let configuration = datadog::Configuration::new(); + let api = DashboardsAPI::with_config(configuration); + let resp = api.create_dashboard(body).await; + if let Ok(value) = resp { + println!("{:#?}", value); + } else { + println!("{:#?}", resp.unwrap_err()); + } +} diff --git a/src/datadogV1/model/mod.rs b/src/datadogV1/model/mod.rs index 417066ecb..10dc3359a 100644 --- a/src/datadogV1/model/mod.rs +++ b/src/datadogV1/model/mod.rs @@ -194,6 +194,8 @@ pub mod model_formula_and_function_metric_aggregation; pub use self::model_formula_and_function_metric_aggregation::FormulaAndFunctionMetricAggregation; pub mod model_formula_and_function_metric_data_source; pub use self::model_formula_and_function_metric_data_source::FormulaAndFunctionMetricDataSource; +pub mod model_formula_and_function_metric_semantic_mode; +pub use self::model_formula_and_function_metric_semantic_mode::FormulaAndFunctionMetricSemanticMode; pub mod model_formula_and_function_event_query_definition; pub use self::model_formula_and_function_event_query_definition::FormulaAndFunctionEventQueryDefinition; pub mod model_formula_and_function_event_query_definition_compute; diff --git a/src/datadogV1/model/model_formula_and_function_metric_query_definition.rs b/src/datadogV1/model/model_formula_and_function_metric_query_definition.rs index 597abe983..4e6816547 100644 --- a/src/datadogV1/model/model_formula_and_function_metric_query_definition.rs +++ b/src/datadogV1/model/model_formula_and_function_metric_query_definition.rs @@ -26,6 +26,9 @@ pub struct FormulaAndFunctionMetricQueryDefinition { /// Metrics query definition. #[serde(rename = "query")] pub query: String, + /// Semantic mode for metrics queries. This determines how metrics from different sources are combined or displayed. + #[serde(rename = "semantic_mode")] + pub semantic_mode: Option, #[serde(flatten)] pub additional_properties: std::collections::BTreeMap, #[serde(skip)] @@ -45,6 +48,7 @@ impl FormulaAndFunctionMetricQueryDefinition { data_source, name, query, + semantic_mode: None, additional_properties: std::collections::BTreeMap::new(), _unparsed: false, } @@ -63,6 +67,14 @@ impl FormulaAndFunctionMetricQueryDefinition { self } + pub fn semantic_mode( + mut self, + value: crate::datadogV1::model::FormulaAndFunctionMetricSemanticMode, + ) -> Self { + self.semantic_mode = Some(value); + self + } + pub fn additional_properties( mut self, value: std::collections::BTreeMap, @@ -98,6 +110,9 @@ impl<'de> Deserialize<'de> for FormulaAndFunctionMetricQueryDefinition { > = None; let mut name: Option = None; let mut query: Option = None; + let mut semantic_mode: Option< + crate::datadogV1::model::FormulaAndFunctionMetricSemanticMode, + > = None; let mut additional_properties: std::collections::BTreeMap< String, serde_json::Value, @@ -145,6 +160,21 @@ impl<'de> Deserialize<'de> for FormulaAndFunctionMetricQueryDefinition { "query" => { query = Some(serde_json::from_value(v).map_err(M::Error::custom)?); } + "semantic_mode" => { + if v.is_null() { + continue; + } + semantic_mode = + Some(serde_json::from_value(v).map_err(M::Error::custom)?); + if let Some(ref _semantic_mode) = semantic_mode { + match _semantic_mode { + crate::datadogV1::model::FormulaAndFunctionMetricSemanticMode::UnparsedObject(_semantic_mode) => { + _unparsed = true; + }, + _ => {} + } + } + } &_ => { if let Ok(value) = serde_json::from_value(v.clone()) { additional_properties.insert(k, value); @@ -163,6 +193,7 @@ impl<'de> Deserialize<'de> for FormulaAndFunctionMetricQueryDefinition { data_source, name, query, + semantic_mode, additional_properties, _unparsed, }; diff --git a/src/datadogV1/model/model_formula_and_function_metric_semantic_mode.rs b/src/datadogV1/model/model_formula_and_function_metric_semantic_mode.rs new file mode 100644 index 000000000..2909dc196 --- /dev/null +++ b/src/datadogV1/model/model_formula_and_function_metric_semantic_mode.rs @@ -0,0 +1,51 @@ +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2019-Present Datadog, Inc. + +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum FormulaAndFunctionMetricSemanticMode { + COMBINED, + NATIVE, + UnparsedObject(crate::datadog::UnparsedObject), +} + +impl ToString for FormulaAndFunctionMetricSemanticMode { + fn to_string(&self) -> String { + match self { + Self::COMBINED => String::from("combined"), + Self::NATIVE => String::from("native"), + Self::UnparsedObject(v) => v.value.to_string(), + } + } +} + +impl Serialize for FormulaAndFunctionMetricSemanticMode { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::UnparsedObject(v) => v.serialize(serializer), + _ => serializer.serialize_str(self.to_string().as_str()), + } + } +} + +impl<'de> Deserialize<'de> for FormulaAndFunctionMetricSemanticMode { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s: String = String::deserialize(deserializer)?; + Ok(match s.as_str() { + "combined" => Self::COMBINED, + "native" => Self::NATIVE, + _ => Self::UnparsedObject(crate::datadog::UnparsedObject { + value: serde_json::Value::String(s.into()), + }), + }) + } +} diff --git a/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-combined-semantic-mode.frozen b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-combined-semantic-mode.frozen new file mode 100644 index 000000000..0f7fd4489 --- /dev/null +++ b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-combined-semantic-mode.frozen @@ -0,0 +1 @@ +2025-12-08T18:40:10.047Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-combined-semantic-mode.json b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-combined-semantic-mode.json new file mode 100644 index 000000000..0854da94b --- /dev/null +++ b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-combined-semantic-mode.json @@ -0,0 +1,67 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"layout_type\":\"ordered\",\"title\":\"Test-Create_a_new_dashboard_with_a_timeseries_widget_using_formulas_and_functions_metrics_query_with_comb-1765219210 with combined semantic_mode\",\"widgets\":[{\"definition\":{\"requests\":[{\"display_type\":\"line\",\"formulas\":[{\"formula\":\"query1\"}],\"queries\":[{\"data_source\":\"metrics\",\"name\":\"query1\",\"query\":\"avg:system.cpu.user{*}\",\"semantic_mode\":\"combined\"}],\"response_format\":\"timeseries\"}],\"type\":\"timeseries\"}}]}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v1/dashboard" + }, + "response": { + "body": { + "string": "{\"id\":\"bpt-wdw-b9x\",\"title\":\"Test-Create_a_new_dashboard_with_a_timeseries_widget_using_formulas_and_functions_metrics_query_with_comb-1765219210 with combined semantic_mode\",\"description\":null,\"author_handle\":\"frog@datadoghq.com\",\"author_name\":\"frog\",\"layout_type\":\"ordered\",\"url\":\"/dashboard/bpt-wdw-b9x/test-createanewdashboardwithatimeserieswidgetusingformulasandfunctionsmetricsque\",\"template_variables\":null,\"widgets\":[{\"definition\":{\"requests\":[{\"display_type\":\"line\",\"formulas\":[{\"formula\":\"query1\"}],\"queries\":[{\"data_source\":\"metrics\",\"name\":\"query1\",\"query\":\"avg:system.cpu.user{*}\",\"semantic_mode\":\"combined\"}],\"response_format\":\"timeseries\"}],\"type\":\"timeseries\"},\"id\":7196642548461969}],\"notify_list\":null,\"created_at\":\"2025-12-08T18:40:10.214467+00:00\",\"modified_at\":\"2025-12-08T18:40:10.214467+00:00\",\"restricted_roles\":[]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Mon, 08 Dec 2025 18:40:10 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v1/dashboard/bpt-wdw-b9x" + }, + "response": { + "body": { + "string": "{\"deleted_dashboard_id\":\"bpt-wdw-b9x\"}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Mon, 08 Dec 2025 18:40:10 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-native-semantic-mode.frozen b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-native-semantic-mode.frozen new file mode 100644 index 000000000..1acb8f271 --- /dev/null +++ b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-native-semantic-mode.frozen @@ -0,0 +1 @@ +2025-12-08T18:32:38.191Z \ No newline at end of file diff --git a/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-native-semantic-mode.json b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-native-semantic-mode.json new file mode 100644 index 000000000..5e57d76a9 --- /dev/null +++ b/tests/scenarios/cassettes/v1/dashboards/Create-a-new-dashboard-with-a-timeseries-widget-using-formulas-and-functions-metrics-query-with-native-semantic-mode.json @@ -0,0 +1,67 @@ +{ + "http_interactions": [ + { + "request": { + "body": { + "string": "{\"layout_type\":\"ordered\",\"title\":\"Test-Create_a_new_dashboard_with_a_timeseries_widget_using_formulas_and_functions_metrics_query_with_nati-1765218758 with native semantic_mode\",\"widgets\":[{\"definition\":{\"requests\":[{\"display_type\":\"line\",\"formulas\":[{\"formula\":\"query1\"}],\"queries\":[{\"data_source\":\"metrics\",\"name\":\"query1\",\"query\":\"avg:system.cpu.user{*}\",\"semantic_mode\":\"native\"}],\"response_format\":\"timeseries\"}],\"type\":\"timeseries\"}}]}", + "encoding": null + }, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json" + ] + }, + "method": "post", + "uri": "https://api.datadoghq.com/api/v1/dashboard" + }, + "response": { + "body": { + "string": "{\"id\":\"ptr-h98-jx4\",\"title\":\"Test-Create_a_new_dashboard_with_a_timeseries_widget_using_formulas_and_functions_metrics_query_with_nati-1765218758 with native semantic_mode\",\"description\":null,\"author_handle\":\"frog@datadoghq.com\",\"author_name\":\"frog\",\"layout_type\":\"ordered\",\"url\":\"/dashboard/ptr-h98-jx4/test-createanewdashboardwithatimeserieswidgetusingformulasandfunctionsmetricsque\",\"template_variables\":null,\"widgets\":[{\"definition\":{\"requests\":[{\"display_type\":\"line\",\"formulas\":[{\"formula\":\"query1\"}],\"queries\":[{\"data_source\":\"metrics\",\"name\":\"query1\",\"query\":\"avg:system.cpu.user{*}\",\"semantic_mode\":\"native\"}],\"response_format\":\"timeseries\"}],\"type\":\"timeseries\"},\"id\":7543625669678795}],\"notify_list\":null,\"created_at\":\"2025-12-08T18:32:38.359385+00:00\",\"modified_at\":\"2025-12-08T18:32:38.359385+00:00\",\"restricted_roles\":[]}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Mon, 08 Dec 2025 18:32:38 GMT" + }, + { + "request": { + "body": "", + "headers": { + "Accept": [ + "application/json" + ] + }, + "method": "delete", + "uri": "https://api.datadoghq.com/api/v1/dashboard/ptr-h98-jx4" + }, + "response": { + "body": { + "string": "{\"deleted_dashboard_id\":\"ptr-h98-jx4\"}", + "encoding": null + }, + "headers": { + "Content-Type": [ + "application/json" + ] + }, + "status": { + "code": 200, + "message": "OK" + } + }, + "recorded_at": "Mon, 08 Dec 2025 18:32:38 GMT" + } + ], + "recorded_with": "VCR 6.0.0" +} \ No newline at end of file diff --git a/tests/scenarios/features/v1/dashboards.feature b/tests/scenarios/features/v1/dashboards.feature index 0d161522e..3eeebebdc 100644 --- a/tests/scenarios/features/v1/dashboards.feature +++ b/tests/scenarios/features/v1/dashboards.feature @@ -195,6 +195,30 @@ Feature: Dashboards And the response "widgets[0].definition.requests[0].formulas[0].formula" is equal to "query1" And the response "widgets[0].definition.time.live_span" is equal to "week_to_date" + @team:DataDog/dashboards-backend + Scenario: Create a new dashboard with a timeseries widget using formulas and functions metrics query with combined semantic_mode + Given new "CreateDashboard" request + And body with value {"layout_type": "ordered", "title": "{{ unique }} with combined semantic_mode", "widgets": [{"definition": {"type": "timeseries", "requests": [{"queries": [{"data_source": "metrics", "name": "query1", "query": "avg:system.cpu.user{*}", "semantic_mode": "combined"}], "response_format": "timeseries", "formulas": [{"formula": "query1"}], "display_type": "line"}]}}]} + When the request is sent + Then the response status is 200 OK + And the response "widgets[0].definition.requests[0].response_format" is equal to "timeseries" + And the response "widgets[0].definition.requests[0].queries[0].data_source" is equal to "metrics" + And the response "widgets[0].definition.requests[0].queries[0].name" is equal to "query1" + And the response "widgets[0].definition.requests[0].queries[0].query" is equal to "avg:system.cpu.user{*}" + And the response "widgets[0].definition.requests[0].queries[0].semantic_mode" is equal to "combined" + + @team:DataDog/dashboards-backend + Scenario: Create a new dashboard with a timeseries widget using formulas and functions metrics query with native semantic_mode + Given new "CreateDashboard" request + And body with value {"layout_type": "ordered", "title": "{{ unique }} with native semantic_mode", "widgets": [{"definition": {"type": "timeseries", "requests": [{"queries": [{"data_source": "metrics", "name": "query1", "query": "avg:system.cpu.user{*}", "semantic_mode": "native"}], "response_format": "timeseries", "formulas": [{"formula": "query1"}], "display_type": "line"}]}}]} + When the request is sent + Then the response status is 200 OK + And the response "widgets[0].definition.requests[0].response_format" is equal to "timeseries" + And the response "widgets[0].definition.requests[0].queries[0].data_source" is equal to "metrics" + And the response "widgets[0].definition.requests[0].queries[0].name" is equal to "query1" + And the response "widgets[0].definition.requests[0].queries[0].query" is equal to "avg:system.cpu.user{*}" + And the response "widgets[0].definition.requests[0].queries[0].semantic_mode" is equal to "native" + @team:DataDog/dashboards-backend Scenario: Create a new dashboard with a toplist widget sorted by group Given new "CreateDashboard" request