elasticctl_api/dashboards_ops/
delete.rs1use super::{
2 BTreeSet, DashboardSummary, DeleteOutcome, Error, ErrorKind, MutationPlan, Result, Transport,
3 dashboards, invalid_plan, resolve,
4};
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct DashboardDeletePlan {
8 pub preview: MutationPlan,
9 pub targets: Vec<DashboardSummary>,
10}
11pub async fn plan_delete(
12 transport: &Transport,
13 selectors: &[String],
14) -> Result<DashboardDeletePlan> {
15 if selectors.is_empty() {
16 return Err(Error::new(
17 ErrorKind::Error,
18 "dashboard delete needs at least one dashboard",
19 ));
20 }
21 let mut seen = BTreeSet::new();
22 let mut targets = Vec::new();
23 for selector in selectors {
24 let dashboard = resolve(transport, selector).await?;
25 if seen.insert(dashboard.id.clone()) {
26 targets.push(dashboard);
27 }
28 }
29 Ok(DashboardDeletePlan {
30 preview: delete_preview(&targets),
31 targets,
32 })
33}
34
35pub async fn apply_delete(
36 transport: &Transport,
37 plan: &DashboardDeletePlan,
38) -> Result<DeleteOutcome> {
39 validate_delete_plan(plan)?;
40 let mut deleted = Vec::new();
41 let mut failed = Vec::new();
42 for target in &plan.targets {
43 match dashboards::delete(transport, &target.id).await {
44 Ok(()) => deleted.push(serde_json::json!({"id": target.id})),
45 Err(error) => failed.push(serde_json::json!({
46 "id": target.id,
47 "error": error.message,
48 })),
49 }
50 }
51 Ok(DeleteOutcome {
52 applied: true,
53 deleted,
54 failed,
55 total: plan.targets.len(),
56 })
57}
58
59fn delete_preview(targets: &[DashboardSummary]) -> MutationPlan {
60 MutationPlan {
61 preview_action: format!("Delete {} dashboard(s)", targets.len()),
62 preview_details: targets
63 .iter()
64 .map(|dashboard| format!("{} {}", dashboard.id, dashboard.title))
65 .collect(),
66 targets: targets
67 .iter()
68 .map(|dashboard| dashboard.id.clone())
69 .collect(),
70 }
71}
72
73fn validate_delete_plan(plan: &DashboardDeletePlan) -> Result<()> {
74 if plan.targets.is_empty() {
75 return invalid_plan("dashboard delete plan needs at least one target");
76 }
77 let mut ids = BTreeSet::new();
78 for target in &plan.targets {
79 if target.id.trim().is_empty() || target.title.trim().is_empty() {
80 return invalid_plan("dashboard delete target identity must not be empty");
81 }
82 if !ids.insert(target.id.clone()) {
83 return invalid_plan("dashboard delete targets must be unique by id");
84 }
85 }
86 if plan.preview != delete_preview(&plan.targets) {
87 return invalid_plan("dashboard delete preview does not match guarded targets");
88 }
89 Ok(())
90}