use super::{parse_tag_args, Action, App};
impl App {
pub(crate) fn cmd_batch_action(&mut self, action: Action) {
if self.read_only {
self.error_message = Some("read-only mode — batch actions disabled".into());
return;
}
if self.multi_selected.is_empty() {
self.error_message = Some("no envs selected — press space to mark envs first".into());
return;
}
let names: Vec<String> = self.multi_selected.iter().cloned().collect();
let n = names.len();
for name in names {
self.spawn_batch_action(action, name);
}
self.status_message = Some(format!(
"dispatched {} to {n} env(s) — watch the events panel for outcomes",
action.label()
));
self.multi_selected.clear();
}
pub(crate) fn cmd_batch_deploy(&mut self, rest: &[&str]) {
if self.read_only {
self.error_message = Some("read-only mode — batch-deploy disabled".into());
return;
}
if self.multi_selected.is_empty() {
self.error_message = Some("no envs selected — press space to mark envs first".into());
return;
}
let Some(label) = rest.first().map(|s| s.to_string()) else {
self.error_message = Some("usage: :batch-deploy LABEL".into());
return;
};
let names: Vec<String> = self.multi_selected.iter().cloned().collect();
let apps: std::collections::BTreeSet<String> = names
.iter()
.filter_map(|n| {
self.environments
.iter()
.find(|e| &e.name == n)
.map(|e| e.application.clone())
})
.collect();
if apps.len() > 1 {
self.error_message = Some(format!(
"selected envs span {} applications ({}); :batch-deploy needs a single application",
apps.len(),
apps.iter().cloned().collect::<Vec<_>>().join(", ")
));
return;
}
let n = names.len();
for name in names {
self.spawn_batch_deploy(name, label.clone());
}
self.status_message = Some(format!(
"dispatched Deploy({label}) to {n} env(s) — outcomes via toasts",
));
self.multi_selected.clear();
}
pub(crate) fn cmd_batch_tag_or_untag(&mut self, is_tag: bool, rest: &[&str]) {
if self.read_only {
self.error_message = Some("read-only mode — batch tag/untag disabled".into());
return;
}
if self.multi_selected.is_empty() {
self.error_message = Some("no envs selected — press space to mark envs first".into());
return;
}
let (key, value) = if is_tag {
let Some((k, v)) = parse_tag_args(rest) else {
self.error_message = Some("usage: :batch-tag KEY VALUE".into());
return;
};
(k, Some(v))
} else {
let Some(k) = rest.first().map(|s| s.to_string()) else {
self.error_message = Some("usage: :batch-untag KEY".into());
return;
};
(k, None)
};
let names: Vec<String> = self.multi_selected.iter().cloned().collect();
let mut dispatched = 0usize;
let mut missing_arn: Vec<String> = Vec::new();
for name in &names {
let arn = self
.environments
.iter()
.find(|e| &e.name == name)
.and_then(|e| e.arn.clone());
match arn {
Some(arn) => {
self.spawn_batch_tag(name.clone(), arn, key.clone(), value.clone());
dispatched += 1;
}
None => missing_arn.push(name.clone()),
}
}
let op = if is_tag { "tag" } else { "untag" };
let mut msg = format!("dispatched {op} {key} to {dispatched} env(s)");
if !missing_arn.is_empty() {
msg.push_str(&format!(
" — skipped {} (no ARN): {}",
missing_arn.len(),
missing_arn.join(", ")
));
}
self.status_message = Some(msg);
self.multi_selected.clear();
}
pub(crate) fn cmd_batch_set_option(&mut self, rest: &[&str]) {
if self.read_only {
self.error_message = Some("read-only mode — batch-set-option disabled".into());
return;
}
if self.multi_selected.is_empty() {
self.error_message = Some("no envs selected — press space to mark envs first".into());
return;
}
if rest.len() < 3 {
self.error_message = Some("usage: :batch-set-option NAMESPACE NAME VALUE".into());
return;
}
let ns = rest[0].to_string();
let name = rest[1].to_string();
let value = rest[2..].join(" ");
let names: Vec<String> = self.multi_selected.iter().cloned().collect();
let n = names.len();
for env_name in names {
self.spawn_batch_set_option(env_name, ns.clone(), name.clone(), value.clone());
}
self.status_message = Some(format!(
"dispatched set-option {ns}.{name}={value} to {n} env(s)"
));
self.multi_selected.clear();
}
}