Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions apps/service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub enum Error {
}

/// Location privacy setting
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
pub enum LocationPrivacy {
/// Disable location tracking completely
#[serde(rename = "disabled")]
Expand All @@ -21,15 +21,10 @@ pub enum LocationPrivacy {
CountryOnly,
/// Full location details (city, country, region)
#[serde(rename = "full")]
#[default]
Full,
}

impl Default for LocationPrivacy {
fn default() -> Self {
LocationPrivacy::Full
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
pub zeromq: ZeroMQ,
Expand Down
16 changes: 6 additions & 10 deletions apps/service/src/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,7 @@ async fn fetch_location_from_ip() -> Result<Location> {
let country =
if !response.country_code.is_empty() { Some(response.country_code.clone()) } else { None };

let region = if let Some(ref cc) = country {
Some(Location::region_from_country(cc).to_string())
} else {
None
};
let region = country.as_ref().map(|cc| Location::region_from_country(cc).to_string());

Ok(Location::new(city, country, region))
}
Expand All @@ -154,11 +150,11 @@ pub fn init_location_cache(update_interval_secs: u64, privacy_level: LocationPri
/// Initialize location from static config (for backwards compatibility)
pub fn init_location(location: Location) {
init_location_cache(0, LocationPrivacy::Full); // 0 = never auto-update
if let Some(cache) = LOCATION_CACHE.get() {
if let Ok(mut cache) = cache.write() {
cache.location = location;
cache.last_update = Instant::now();
}
if let Some(cache) = LOCATION_CACHE.get()
&& let Ok(mut cache) = cache.write()
{
cache.location = location;
cache.last_update = Instant::now();
}
}

Expand Down
8 changes: 4 additions & 4 deletions apps/service/src/orchestrator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ impl Orchestrator {
}

// Share with P2P network if enabled
if self.p2p_network.is_enabled() {
if let Err(e) = self.p2p_network.share_result(&signed_result).await {
error!("Failed to share result with P2P network: {}", e);
}
if self.p2p_network.is_enabled()
&& let Err(e) = self.p2p_network.share_result(&signed_result).await
{
error!("Failed to share result with P2P network: {}", e);
}

// Log the result
Expand Down
68 changes: 34 additions & 34 deletions apps/service/src/tui/events/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ pub async fn handle_edit_popup(
}

KeyCode::End => {
if state.edit_field_index < 2 {
if let Some(text) = state.get_current_field_text() {
state.text_cursor = text.len();
}
if state.edit_field_index < 2
&& let Some(text) = state.get_current_field_text()
{
state.text_cursor = text.len();
}
}

Expand Down Expand Up @@ -105,12 +105,12 @@ pub async fn handle_edit_popup(
}
} else {
// Validate before saving
if state.validate_current_monitor() {
if let Some(m) = state.edit_monitor.take() {
db.save_monitor(&m).await?;
state.close_edit();
state.refresh_monitors_and_results(db).await?;
}
if state.validate_current_monitor()
&& let Some(m) = state.edit_monitor.take()
{
db.save_monitor(&m).await?;
state.close_edit();
state.refresh_monitors_and_results(db).await?;
}
}
}
Expand All @@ -120,10 +120,10 @@ pub async fn handle_edit_popup(
KeyCode::Right => {
if state.edit_field_index < 2 {
// Move cursor right in text field
if let Some(text) = state.get_current_field_text() {
if state.text_cursor < text.len() {
state.text_cursor += 1;
}
if let Some(text) = state.get_current_field_text()
&& state.text_cursor < text.len()
{
state.text_cursor += 1;
}
} else {
// Adjust values in other fields
Expand Down Expand Up @@ -260,38 +260,38 @@ pub async fn handle_edit_popup(
}
}
'+' => {
if let Some(m) = state.edit_monitor.as_mut() {
if state.edit_field_index == 3 {
m.interval_seconds = m.interval_seconds.saturating_add(5);
}
if let Some(m) = state.edit_monitor.as_mut()
&& state.edit_field_index == 3
{
m.interval_seconds = m.interval_seconds.saturating_add(5);
}
}
'-' => {
if let Some(m) = state.edit_monitor.as_mut() {
if state.edit_field_index == 3 {
m.interval_seconds = m.interval_seconds.saturating_sub(5).max(1);
}
if let Some(m) = state.edit_monitor.as_mut()
&& state.edit_field_index == 3
{
m.interval_seconds = m.interval_seconds.saturating_sub(5).max(1);
}
}
'[' => {
if let Some(m) = state.edit_monitor.as_mut() {
if state.edit_field_index == 4 {
m.timeout_seconds = m.timeout_seconds.saturating_sub(1).max(1);
}
if let Some(m) = state.edit_monitor.as_mut()
&& state.edit_field_index == 4
{
m.timeout_seconds = m.timeout_seconds.saturating_sub(1).max(1);
}
}
']' => {
if let Some(m) = state.edit_monitor.as_mut() {
if state.edit_field_index == 4 {
m.timeout_seconds = m.timeout_seconds.saturating_add(1);
}
if let Some(m) = state.edit_monitor.as_mut()
&& state.edit_field_index == 4
{
m.timeout_seconds = m.timeout_seconds.saturating_add(1);
}
}
' ' => {
if let Some(m) = state.edit_monitor.as_mut() {
if state.edit_field_index == 5 {
m.enabled = !m.enabled;
}
if let Some(m) = state.edit_monitor.as_mut()
&& state.edit_field_index == 5
{
m.enabled = !m.enabled;
}
}
_ => {}
Expand Down
16 changes: 8 additions & 8 deletions apps/service/src/tui/events/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ pub async fn handle_main_view(

// Toggle enabled status
KeyCode::Char(' ') | KeyCode::Char('t') if key.modifiers.is_empty() => {
if state.focus == Focus::Monitors {
if let Some(mo) = state.monitors.get(state.selected).cloned() {
let mut nm = mo;
nm.enabled = !nm.enabled;
db.save_monitor(&nm).await?;
state.refresh_monitors_and_results(db).await?;
state.last_refresh = std::time::Instant::now();
}
if state.focus == Focus::Monitors
&& let Some(mo) = state.monitors.get(state.selected).cloned()
{
let mut nm = mo;
nm.enabled = !nm.enabled;
db.save_monitor(&nm).await?;
state.refresh_monitors_and_results(db).await?;
state.last_refresh = std::time::Instant::now();
}
}

Expand Down
141 changes: 69 additions & 72 deletions apps/service/src/tui/events/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,90 +12,87 @@ pub async fn handle_mouse(
mouse: MouseEvent,
db: &DatabaseImpl,
) -> Result<bool> {
if let Some(areas) = &state.areas {
match mouse.kind {
MouseEventKind::Down(MouseButton::Left) => {
let x = mouse.column;
let y = mouse.row;
if let Some(areas) = &state.areas
&& let MouseEventKind::Down(MouseButton::Left) = mouse.kind
{
let x = mouse.column;
let y = mouse.row;

// Footer action buttons
for (label, rect) in &areas.action_buttons {
if is_in_rect(x, y, rect) {
match label.as_str() {
"Add" => {
let mut m = Monitor::new("".into(), "".into(), "http".into());
m.interval_seconds = 30;
m.timeout_seconds = 10;
state.edit_monitor = Some(m);
state.show_edit = true;
state.is_add_form = true;
state.edit_field_index = 0;
state.text_cursor = 0;
}
"Edit" => {
if let Some(mo) = state.monitors.get(state.selected).cloned() {
state.edit_monitor = Some(mo);
state.show_edit = true;
state.is_add_form = false;
state.edit_field_index = 0;
state.text_cursor = 0;
}
}
"Delete" => {
if state.monitors.get(state.selected).is_some() {
state.show_delete_confirm = true;
}
}
"Refresh" => {
state.monitors = db.get_enabled_monitors().await?;
if let Some(mo) = state.monitors.get(state.selected) {
state.results = db.get_recent_results(mo.uuid, 50).await?;
} else {
state.results.clear();
}
}
"Help" => {
state.show_help = true;
}
"Quit" => {
return Ok(true); // Signal to quit
}
_ => {}
// Footer action buttons
for (label, rect) in &areas.action_buttons {
if is_in_rect(x, y, rect) {
match label.as_str() {
"Add" => {
let mut m = Monitor::new("".into(), "".into(), "http".into());
m.interval_seconds = 30;
m.timeout_seconds = 10;
state.edit_monitor = Some(m);
state.show_edit = true;
state.is_add_form = true;
state.edit_field_index = 0;
state.text_cursor = 0;
}
"Edit" => {
if let Some(mo) = state.monitors.get(state.selected).cloned() {
state.edit_monitor = Some(mo);
state.show_edit = true;
state.is_add_form = false;
state.edit_field_index = 0;
state.text_cursor = 0;
}
}
}

// Monitors area
let mrect = areas.monitors;
if is_in_rect(x, y, &mrect) {
state.focus = Focus::Monitors;
// Approximate row idx: account for border and title
let inner_y = y.saturating_sub(mrect.y + 1);
if inner_y < mrect.height.saturating_sub(2) {
let idx = inner_y as usize;
if idx < state.monitors.len() {
state.selected = idx;
"Delete" => {
if state.monitors.get(state.selected).is_some() {
state.show_delete_confirm = true;
}
}
"Refresh" => {
state.monitors = db.get_enabled_monitors().await?;
if let Some(mo) = state.monitors.get(state.selected) {
state.results = db.get_recent_results(mo.uuid, 50).await?;
} else {
state.results.clear();
}
}
"Help" => {
state.show_help = true;
}
"Quit" => {
return Ok(true); // Signal to quit
}
_ => {}
}
}
}

// Results area
let rrect = areas.results;
if is_in_rect(x, y, &rrect) {
state.focus = Focus::Results;
let inner_y = y.saturating_sub(rrect.y + 2); // header row
if inner_y < rrect.height.saturating_sub(3) {
let idx = inner_y as usize;
if idx < state.results.len() {
state.selected_result = idx;
}
}
// Monitors area
let mrect = areas.monitors;
if is_in_rect(x, y, &mrect) {
state.focus = Focus::Monitors;
// Approximate row idx: account for border and title
let inner_y = y.saturating_sub(mrect.y + 1);
if inner_y < mrect.height.saturating_sub(2) {
let idx = inner_y as usize;
if idx < state.monitors.len() {
state.selected = idx;
}
if let Some(mo) = state.monitors.get(state.selected) {
state.results = db.get_recent_results(mo.uuid, 50).await?;
}
}
}

// Results area
let rrect = areas.results;
if is_in_rect(x, y, &rrect) {
state.focus = Focus::Results;
let inner_y = y.saturating_sub(rrect.y + 2); // header row
if inner_y < rrect.height.saturating_sub(3) {
let idx = inner_y as usize;
if idx < state.results.len() {
state.selected_result = idx;
}
}
_ => {}
}
}

Expand Down
2 changes: 1 addition & 1 deletion apps/service/src/tui/ui/footer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn render(f: &mut Frame, area: Rect, show_help: bool) -> Vec<(String, Rect)>
let keys = ["A", "E", "D", "R", "H/?", "Q/Esc"];

for (i, (label, key)) in labels.iter().zip(keys.iter()).enumerate() {
let text = format!("{}: {}", key, label);
let text = format!("{key}: {label}");
let btn = Paragraph::new(Line::from(Span::styled(
text,
Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD),
Expand Down
2 changes: 1 addition & 1 deletion apps/service/src/tui/ui/monitors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn render(f: &mut Frame, area: Rect, state: &AppState) {
};

ListItem::new(Line::from(vec![
Span::styled(format!("{}", m.name), style),
Span::styled(m.name.to_string(), style),
Span::styled(
if m.enabled { " ✓ " } else { " ✗ " },
Style::default().fg(if m.enabled { Color::Green } else { Color::Red }),
Expand Down
Loading