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