Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Seek N mins backward/forward" has been changed to "Set time interval" #42

Merged
merged 1 commit into from
Jan 28, 2024
Merged
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
147 changes: 98 additions & 49 deletions src/view/processes_view.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::{Error, Result};
use chrono::{DateTime, Duration, Utc};
use chrono::{DateTime, Duration, Utc, NaiveDateTime, TimeZone};
use chrono_tz::{Tz, UTC};
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
Expand All @@ -11,7 +11,7 @@ use cursive::{
event::{Callback, Event, EventResult},
inner_getters,
view::ViewWrapper,
views::{self, Dialog, EditView, OnEventView},
views::{self, Dialog, EditView, OnEventView, LinearLayout, DummyView, TextView},
Cursive,
};
use size::{Base, SizeFormatter, Style};
Expand Down Expand Up @@ -190,6 +190,7 @@ pub struct ProcessesView {
filter: Arc<Mutex<String>>,
// Used as a condition for event_time/event_date in system.query_log
// (for navigating through system.query_log historically)
start_time: Arc<Mutex<Option<DateTime<Tz>>>>,
end_time: Arc<Mutex<Option<DateTime<Tz>>>>,
// Number of queries to render
limit: Arc<Mutex<u64>>,
Expand Down Expand Up @@ -402,31 +403,59 @@ impl ProcessesView {
return Ok((query_ids, min_query_start_microseconds));
}

pub fn update_end_time(&mut self, is_sub: bool, minutes: i64) {
pub fn shift_time_interval(&mut self, is_sub: bool, minutes: i64) {
let start_time_bind = self.start_time.clone();
let start_time_guard = start_time_bind.lock();

let end_time_bind = self.end_time.clone();
let end_time_guard = end_time_bind.lock();

let mut new_start_time = start_time_guard
.as_ref()
.unwrap()
.unwrap_or_else(|| Utc::now().with_timezone(&UTC) - Duration::hours(1));

let mut new_end_time = end_time_guard
.as_ref()
.unwrap()
.unwrap_or_else(|| Utc::now().with_timezone(&UTC));

if is_sub {
new_start_time -= Duration::minutes(minutes);
new_end_time -= Duration::minutes(minutes);
log::debug!(
"Set end_time to {} (seeked to {} minutes backward)",
"Set start_time to {}, end_time to {} (seeked to {} minutes backward)",
new_start_time,
new_end_time,
minutes
);
} else {
new_start_time += Duration::minutes(minutes);
new_end_time += Duration::minutes(minutes);
log::debug!(
"Set end_time to {} (seeked to {} minutes forward)",
"Set start_time to {}, end_time to {} (seeked to {} minutes backward)",
new_start_time,
new_end_time,
minutes
);
}
*start_time_guard.unwrap() = Some(new_start_time);
*end_time_guard.unwrap() = Some(new_end_time);
}

pub fn update_time_interval(&mut self, start: DateTime<Tz>, end: DateTime<Tz>) {
let start_time_bind = self.start_time.clone();
let start_time_guard = start_time_bind.lock();

let end_time_bind = self.end_time.clone();
let end_time_guard = end_time_bind.lock();

log::debug!("Set start_time to {}, end_time to {}", start, end);

*start_time_guard.unwrap() = Some(start);
*end_time_guard.unwrap() = Some(end);
}

pub fn update_limit(&mut self, is_sub: bool) {
let new_limit = if is_sub {
self.limit.clone().lock().unwrap().saturating_sub(20)
Expand All @@ -446,6 +475,7 @@ impl ProcessesView {

let is_system_processes = matches!(processes_type, Type::ProcessList);
let filter = Arc::new(Mutex::new(String::new()));
let start_time = Arc::new(Mutex::new(Option::<DateTime<Tz>>::None));
let end_time = Arc::new(Mutex::new(Option::<DateTime<Tz>>::None));
let limit = Arc::new(Mutex::new(if matches!(processes_type, Type::ProcessList) {
10000
Expand All @@ -455,16 +485,18 @@ impl ProcessesView {

let update_callback_context = context.clone();
let update_callback_filter = filter.clone();
let update_callback_start_time = start_time.clone();
let update_callback_end_time = end_time.clone();
let update_callback_limit = limit.clone();
let update_callback = move || {
let mut context = update_callback_context.lock().unwrap();
let filter = update_callback_filter.lock().unwrap().clone();
let limit = *update_callback_limit.lock().unwrap();
let start_time = &*update_callback_start_time.lock().unwrap();
let end_time = &*update_callback_end_time.lock().unwrap();

let end_time = end_time.unwrap_or_else(|| Utc::now().with_timezone(&UTC));
let start_time = end_time - Duration::hours(1);
let start_time = start_time.unwrap_or_else(|| end_time - Duration::hours(1));

match processes_type {
// TODO: in case of end_time is set, render LastQueryLog automatically
Expand Down Expand Up @@ -524,6 +556,7 @@ impl ProcessesView {
options: view_options,
is_system_processes,
filter,
start_time,
end_time,
limit,
bg_runner,
Expand All @@ -550,28 +583,6 @@ impl ProcessesView {
}
return Some(EventResult::Ignored);
});

fn create_update_end_time_cb(
view_name: &'static str,
is_sub: bool,
) -> impl Fn(&mut Cursive, &str) {
move |siv: &mut Cursive, text: &str| {
siv.pop_layer();
match text.parse::<i64>() {
Ok(num_mins) => {
siv.call_on_name(view_name, |v: &mut OnEventView<ProcessesView>| {
let v = v.get_inner_mut();
v.update_end_time(is_sub, num_mins);
v.bg_runner.schedule();
});
}
Err(_) => {
siv.add_layer(Dialog::info("The number of minutes must be an integer"));
}
}
}
}

log::debug!("Adding views actions");
let mut context = context.lock().unwrap();
context.add_view_action(&mut event_view, "Select", ' ', |v| {
Expand Down Expand Up @@ -988,42 +999,80 @@ impl ProcessesView {
// Bindings T/t inspiried by atop(1) (so as this functionality)
context.add_view_action(&mut event_view, "Seek 10 mins backward", 'T', |v| {
let v = v.downcast_mut::<ProcessesView>().unwrap();
v.update_end_time(true, 10);
v.shift_time_interval(true, 10);
v.bg_runner.schedule();
return Ok(Some(EventResult::consumed()));
});
context.add_view_action(&mut event_view, "Seek 10 mins forward", 't', |v| {
let v = v.downcast_mut::<ProcessesView>().unwrap();
v.update_end_time(false, 10);
v.shift_time_interval(false, 10);
v.bg_runner.schedule();
return Ok(Some(EventResult::consumed()));
});
context.add_view_action(
&mut event_view,
"Seek N mins backward",
Event::AltChar('T'),
move |_v| {
return Ok(Some(EventResult::Consumed(Some(Callback::from_fn(
move |siv: &mut Cursive| {
let update_end_time_cb = create_update_end_time_cb(view_name, true);
let view = OnEventView::new(
EditView::new().on_submit(update_end_time_cb).min_width(10),
);
siv.add_layer(view);
},
)))));
},
);
context.add_view_action(
&mut event_view,
"Seek N mins forward",
"Set time interval",
Event::AltChar('t'),
move |_v| {
return Ok(Some(EventResult::Consumed(Some(Callback::from_fn(
move |siv: &mut Cursive| {
let update_end_time_cb = create_update_end_time_cb(view_name, false);
let on_submit = move |siv: &mut Cursive| {
let begin = siv
.call_on_name("begin", |view: &mut EditView| view.get_content())
.unwrap();
let end = siv
.call_on_name("end", |view: &mut EditView| view.get_content())
.unwrap();

siv.pop_layer();

let begin_str = begin.as_str();
let end_str = end.as_str();

let mut new_start_time = Utc::now().with_timezone(&UTC) - Duration::hours(1);
let mut new_end_time = Utc::now().with_timezone(&UTC);

if !(begin_str.is_empty() && end_str.is_empty()) {
let format_datetime = "%Y-%m-%d %H:%M:%S";

match NaiveDateTime::parse_from_str(begin_str, format_datetime) {
Ok(begin_native) => new_start_time = Utc.from_utc_datetime(&begin_native).with_timezone(&UTC),
Err(_) => {
siv.add_layer(Dialog::info("Error when parsing datetime \"begin\", datetime format should be YYYY-MM-DD hh:mm:ss. You can leave these fields blank to reset to \"default\""));
return;
},
}

match NaiveDateTime::parse_from_str(end_str, format_datetime) {
Ok(end_native) => new_end_time = Utc.from_utc_datetime(&end_native).with_timezone(&UTC),
Err(_) => {
siv.add_layer(Dialog::info("Error when parsing datetime \"end\", datetime format should be YYYY-MM-DD hh:mm:ss. You can leave these fields blank to reset to \"default\""));
return;
},
}
}

siv.call_on_name(view_name, |v: &mut OnEventView<ProcessesView>| {
let v = v.get_inner_mut();
v.update_time_interval(new_start_time, new_end_time);
v.bg_runner.schedule();
});
};

let view = OnEventView::new(
EditView::new().on_submit(update_end_time_cb).min_width(10),
Dialog::new()
.title("Set the time interval")
.content(
LinearLayout::vertical()
.child(TextView::new("format: YYYY-MM-DD hh:mm:ss"))
.child(DummyView)
.child(TextView::new("begin:"))
.child(EditView::new().with_name("begin"))
.child(DummyView)
.child(TextView::new("end:"))
.child(EditView::new().with_name("end")),
)
.button("Submit", on_submit)
);
siv.add_layer(view);
},
Expand Down
Loading