pub mod bulk;
pub mod compare;
pub mod diff;
pub mod dns;
pub mod follow;
pub mod tld;
pub use bulk::BulkState;
pub use compare::CompareState;
pub use diff::DiffState;
pub use dns::DnsState;
pub use follow::FollowState;
pub use tld::TldState;
use crossterm::event::KeyEvent;
use crate::tui::action::{Action, EditTarget, FetchReq};
#[derive(Debug)]
pub enum PaneOutcome {
None,
Fetch(FetchReq),
Action(Action),
EditField(EditTarget),
Toast {
tone: &'static str,
msg: &'static str,
},
}
#[derive(Default)]
pub struct Panes {
pub tld: TldState,
pub dns: DnsState,
pub compare: CompareState,
pub diff: DiffState,
pub follow: FollowState,
pub bulk: BulkState,
}
impl Panes {
pub fn handle_key(
&mut self,
lens_key: &str,
tab: usize,
key: KeyEvent,
domain: Option<&str>,
) -> Option<PaneOutcome> {
match lens_key {
"tld" => self.tld.handle_key(key),
"dns" => match tab {
0 => self.dns.handle_key(key, domain),
2 => self.compare.handle_key(key, domain),
_ => None,
},
"diff" => self.diff.handle_key(key, domain),
"follow" => self.follow.handle_key(key, domain),
"bulk" => self.bulk.handle_key(key),
_ => None,
}
}
pub fn apply_field(
&mut self,
t: EditTarget,
v: String,
_domain: Option<String>,
) -> Vec<Action> {
match t {
EditTarget::FollowInterval => {
if let Ok(val) = v.parse::<u64>() {
self.follow.interval_secs = val.clamp(1, seer_core::MAX_FOLLOW_INTERVAL_SECS);
}
vec![]
}
EditTarget::FollowCount => {
if let Ok(val) = v.parse::<usize>() {
self.follow.count = val.clamp(1, seer_core::MAX_FOLLOW_ITERATIONS);
}
vec![]
}
EditTarget::BulkPath => {
self.bulk.running = true;
self.bulk.rows.clear();
self.bulk.note = None;
self.bulk.gen += 1;
self.bulk.selected = None;
self.bulk.detail = false;
self.bulk.total = 0;
vec![Action::StartBulkFromFile {
op: self.bulk.op().to_string(),
path: v,
gen: self.bulk.gen,
}]
}
EditTarget::BulkDomains => {
self.bulk.domains = v;
vec![]
}
_ => vec![],
}
}
pub fn field_value(&self, t: EditTarget) -> String {
match t {
EditTarget::DiffB => self.diff.b.clone(),
EditTarget::FollowInterval => self.follow.interval_secs.to_string(),
EditTarget::FollowCount => self.follow.count.to_string(),
EditTarget::BulkPath => String::new(),
EditTarget::BulkDomains => self.bulk.domains.clone(),
EditTarget::TldFilter => self.tld.filter.clone(),
_ => String::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn follow_interval_is_clamped_to_core_max() {
let mut panes = Panes::default();
panes.apply_field(EditTarget::FollowInterval, "3601".to_string(), None);
assert_eq!(
panes.follow.interval_secs,
seer_core::MAX_FOLLOW_INTERVAL_SECS,
"over-range interval must be clamped to the core maximum"
);
}
#[test]
fn follow_count_is_clamped_to_core_max() {
let mut panes = Panes::default();
panes.apply_field(EditTarget::FollowCount, "10001".to_string(), None);
assert_eq!(
panes.follow.count,
seer_core::MAX_FOLLOW_ITERATIONS,
"over-range count must be clamped to the core maximum"
);
}
#[test]
fn follow_fields_keep_lower_bound_of_one() {
let mut panes = Panes::default();
panes.apply_field(EditTarget::FollowInterval, "0".to_string(), None);
panes.apply_field(EditTarget::FollowCount, "0".to_string(), None);
assert_eq!(panes.follow.interval_secs, 1);
assert_eq!(panes.follow.count, 1);
}
}