Skip to content

Commit 0f0ef07

Browse files
Merge pull request #457 from bvolpato-dd/bvolpato/dashboard-url-time-window
feat(dashboards): add time-scoped url command
2 parents 9166dee + 05d3951 commit 0f0ef07

4 files changed

Lines changed: 84 additions & 0 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,9 @@ pup dashboards list
334334
# Get dashboard details
335335
pup dashboards get abc-123-def
336336

337+
# Print a live 1 week dashboard URL
338+
pup dashboards url abc-123-def --from=now-1w --to=now --live=true
339+
337340
# Delete dashboard
338341
pup dashboards delete abc-123-def --yes
339342
```

docs/EXAMPLES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ pup dashboards get "abc-123-def"
170170

171171
# Get public URL for sharing
172172
pup dashboards url "abc-123-def"
173+
174+
# Open with a live 1 week time window
175+
pup dashboards url "abc-123-def" --from=now-1w --to=now --live=true
173176
```
174177

175178
### Delete Dashboard

src/commands/dashboards.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::Result;
22
use datadog_api_client::datadogV1::api_dashboards::{DashboardsAPI, ListDashboardsOptionalParams};
33
use datadog_api_client::datadogV1::model::Dashboard;
4+
use url::Url;
45

56
use crate::config::Config;
67
use crate::formatter;
@@ -53,6 +54,35 @@ pub async fn delete(cfg: &Config, id: &str) -> Result<()> {
5354
formatter::output(cfg, &resp)
5455
}
5556

57+
pub async fn url(cfg: &Config, id: &str, from: &str, to: &str, live: bool) -> Result<()> {
58+
let api = crate::make_api!(DashboardsAPI, cfg);
59+
let dashboard = api
60+
.get_dashboard(id.to_string())
61+
.await
62+
.map_err(|e| anyhow::anyhow!("failed to get dashboard: {e:?}"))?;
63+
let base_url = dashboard
64+
.url
65+
.ok_or_else(|| anyhow::anyhow!("dashboard response did not include url"))?;
66+
println!("{}", dashboard_url_with_time(&base_url, from, to, live)?);
67+
Ok(())
68+
}
69+
70+
fn dashboard_url_with_time(base_url: &str, from: &str, to: &str, live: bool) -> Result<String> {
71+
let mut url = Url::parse(base_url).map_err(|e| {
72+
anyhow::anyhow!("dashboard response included invalid url {base_url:?}: {e}")
73+
})?;
74+
let mut query_pairs: Vec<(String, String)> = url
75+
.query_pairs()
76+
.filter(|(key, _)| key != "from_ts" && key != "to_ts" && key != "live")
77+
.map(|(key, value)| (key.into_owned(), value.into_owned()))
78+
.collect();
79+
query_pairs.push(("from_ts".to_string(), from.to_string()));
80+
query_pairs.push(("to_ts".to_string(), to.to_string()));
81+
query_pairs.push(("live".to_string(), live.to_string()));
82+
url.query_pairs_mut().clear().extend_pairs(query_pairs);
83+
Ok(url.to_string())
84+
}
85+
5686
#[cfg(test)]
5787
mod tests {
5888

@@ -107,4 +137,36 @@ mod tests {
107137
);
108138
cleanup_env();
109139
}
140+
141+
#[test]
142+
fn test_dashboard_url_with_time_adds_live_window() {
143+
let url = super::dashboard_url_with_time(
144+
"https://app.datadoghq.com/dashboard/abc-123/test-dashboard?tpl_var_env=prod",
145+
"now-1w",
146+
"now",
147+
true,
148+
)
149+
.expect("dashboard URL should be valid");
150+
151+
assert_eq!(
152+
url,
153+
"https://app.datadoghq.com/dashboard/abc-123/test-dashboard?tpl_var_env=prod&from_ts=now-1w&to_ts=now&live=true"
154+
);
155+
}
156+
157+
#[test]
158+
fn test_dashboard_url_with_time_replaces_existing_time_params() {
159+
let url = super::dashboard_url_with_time(
160+
"https://app.datadoghq.com/dashboard/abc-123/test-dashboard?from_ts=old&to_ts=old&live=false",
161+
"now-1w",
162+
"now",
163+
true,
164+
)
165+
.expect("dashboard URL should be valid");
166+
167+
assert_eq!(
168+
url,
169+
"https://app.datadoghq.com/dashboard/abc-123/test-dashboard?from_ts=now-1w&to_ts=now&live=true"
170+
);
171+
}
110172
}

src/main.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3198,6 +3198,16 @@ enum DashboardActions {
31983198
List,
31993199
/// Get dashboard details
32003200
Get { id: String },
3201+
/// Print dashboard URL, optionally scoped to a live time window
3202+
Url {
3203+
id: String,
3204+
#[arg(long = "from", default_value = "now-1w")]
3205+
from_ts: String,
3206+
#[arg(long = "to", default_value = "now")]
3207+
to_ts: String,
3208+
#[arg(long, default_value_t = true, action = clap::ArgAction::Set)]
3209+
live: bool,
3210+
},
32013211
/// Create a dashboard from JSON file
32023212
Create {
32033213
#[arg(long)]
@@ -10370,6 +10380,12 @@ async fn main_inner() -> anyhow::Result<()> {
1037010380
match action {
1037110381
DashboardActions::List => commands::dashboards::list(&cfg).await?,
1037210382
DashboardActions::Get { id } => commands::dashboards::get(&cfg, &id).await?,
10383+
DashboardActions::Url {
10384+
id,
10385+
from_ts,
10386+
to_ts,
10387+
live,
10388+
} => commands::dashboards::url(&cfg, &id, &from_ts, &to_ts, live).await?,
1037310389
DashboardActions::Create { file } => {
1037410390
commands::dashboards::create(&cfg, &file).await?;
1037510391
}

0 commit comments

Comments
 (0)