use crossterm::event::{MouseEvent, MouseEventKind};
use super::app::{
key_binding::DEFAULT_KEYBINDING,
metrics::GroupBy,
models::{ScrollableTxt, StatefulTable},
ActiveBlock, App, RouteId,
};
use super::cmd::IoCmdEvent;
use super::event::Key;
pub async fn handle_key_events(key: Key, app: &mut App) {
match key {
_ if key == DEFAULT_KEYBINDING.esc.key => {
handle_escape(app);
}
_ if key == DEFAULT_KEYBINDING.quit.key => {
app.should_quit = true;
}
_ if key == DEFAULT_KEYBINDING.down.key => {
handle_scroll(app, true, false).await;
}
_ if key == DEFAULT_KEYBINDING.up.key => {
handle_scroll(app, false, false).await;
}
_ if key == DEFAULT_KEYBINDING.toggle_theme.key => {
app.light_theme = !app.light_theme;
}
_ if key == DEFAULT_KEYBINDING.refresh.key => {
app.refresh = true;
}
_ if key == DEFAULT_KEYBINDING.help.key => {
app.push_navigation_stack(RouteId::HelpMenu, ActiveBlock::Empty)
}
_ if key == DEFAULT_KEYBINDING.jump_to_all_context.key => {
app.route_contexts();
}
_ if key == DEFAULT_KEYBINDING.jump_to_current_context.key => {
app.route_home();
}
_ if key == DEFAULT_KEYBINDING.jump_to_utilization.key => {
app.route_utilization();
}
_ => handle_route_events(key, app).await,
}
}
pub async fn handle_mouse_events(mouse: MouseEvent, app: &mut App) {
match mouse.kind {
MouseEventKind::ScrollDown => handle_scroll(app, true, true).await,
MouseEventKind::ScrollUp => handle_scroll(app, false, true).await,
_ => {}
}
}
fn handle_escape(app: &mut App) {
match app.get_current_route().id {
RouteId::HelpMenu | RouteId::Contexts | RouteId::Error => {
app.pop_navigation_stack();
}
_ => match app.get_current_route().active_block {
ActiveBlock::Namespaces
| ActiveBlock::Logs
| ActiveBlock::Containers
| ActiveBlock::Describe => {
app.pop_navigation_stack();
}
_ => {}
},
}
}
async fn handle_route_events(key: Key, app: &mut App) {
match app.get_current_route().id {
RouteId::Home => {
match key {
_ if key == DEFAULT_KEYBINDING.right.key => {
app.context_tabs.next();
app.push_navigation_stack(
RouteId::Home,
app.context_tabs.active_block.unwrap_or(ActiveBlock::Empty),
);
}
_ if key == DEFAULT_KEYBINDING.left.key => {
app.context_tabs.previous();
app.push_navigation_stack(
RouteId::Home,
app.context_tabs.active_block.unwrap_or(ActiveBlock::Empty),
);
}
_ if key == DEFAULT_KEYBINDING.toggle_info.key => {
app.show_info_bar = !app.show_info_bar;
}
_ if key == DEFAULT_KEYBINDING.select_all_namespace.key => app.data.selected_ns = None,
_ if key == DEFAULT_KEYBINDING.jump_to_namespace.key => {
app.push_navigation_stack(RouteId::Home, ActiveBlock::Namespaces);
}
_ if key == DEFAULT_KEYBINDING.jump_to_pods.key => {
app.context_tabs.set_index(0);
app.push_navigation_stack(RouteId::Home, ActiveBlock::Pods);
}
_ if key == DEFAULT_KEYBINDING.jump_to_services.key => {
app.context_tabs.set_index(1);
app.push_navigation_stack(RouteId::Home, ActiveBlock::Services);
}
_ if key == DEFAULT_KEYBINDING.jump_to_nodes.key => {
app.context_tabs.set_index(2);
app.push_navigation_stack(RouteId::Home, ActiveBlock::Nodes);
}
_ if key == DEFAULT_KEYBINDING.jump_to_configmaps.key => {
app.context_tabs.set_index(3);
app.push_navigation_stack(RouteId::Home, ActiveBlock::ConfigMaps);
}
_ if key == DEFAULT_KEYBINDING.jump_to_statefulsets.key => {
app.context_tabs.set_index(4);
app.push_navigation_stack(RouteId::Home, ActiveBlock::StatefulSets);
}
_ if key == DEFAULT_KEYBINDING.jump_to_replicasets.key => {
app.context_tabs.set_index(5);
app.push_navigation_stack(RouteId::Home, ActiveBlock::ReplicaSets);
}
_ if key == DEFAULT_KEYBINDING.jump_to_deployments.key => {
app.context_tabs.set_index(6);
app.push_navigation_stack(RouteId::Home, ActiveBlock::Deployments);
}
_ => {}
};
match app.get_current_route().active_block {
ActiveBlock::Pods => {
if key == DEFAULT_KEYBINDING.describe_resource.key {
app.data.describe_out = ScrollableTxt::new();
let pod = app.data.pods.get_selected_item();
if let Some(p) = pod {
app.push_navigation_stack(RouteId::Home, ActiveBlock::Describe);
app
.dispatch_cmd(IoCmdEvent::GetDescribe {
kind: "pod".to_owned(),
value: p.name,
ns: Some(p.namespace),
})
.await;
}
} else {
let pod = handle_table_action(key, &mut app.data.pods);
if pod.is_some() {
app.push_navigation_stack(RouteId::Home, ActiveBlock::Containers);
}
}
}
ActiveBlock::Containers => {
let cont = handle_table_action(
key,
&mut app
.data
.pods
.get_selected_item()
.map_or(StatefulTable::new(), |c| c.containers),
);
if let Some(c) = cont {
app.dispatch_container_logs(c.name).await;
}
}
ActiveBlock::Services => {
let _svc = handle_table_action(key, &mut app.data.services);
}
ActiveBlock::Nodes => {
if key == DEFAULT_KEYBINDING.describe_resource.key {
app.data.describe_out = ScrollableTxt::new();
let node = app.data.nodes.get_selected_item();
if let Some(n) = node {
app.push_navigation_stack(RouteId::Home, ActiveBlock::Describe);
app
.dispatch_cmd(IoCmdEvent::GetDescribe {
kind: "node".to_owned(),
value: n.name,
ns: None,
})
.await;
}
} else {
let _node = handle_table_action(key, &mut app.data.nodes);
}
}
ActiveBlock::Namespaces => {
let ns = handle_table_action(key, &mut app.data.namespaces);
if let Some(v) = ns {
app.data.selected_ns = Some(v.name);
app.pop_navigation_stack();
}
}
ActiveBlock::Logs => {
if key == DEFAULT_KEYBINDING.log_auto_scroll.key {
app.log_auto_scroll = !app.log_auto_scroll;
} else if key == DEFAULT_KEYBINDING.copy_to_clipboard.key {
copy_to_clipboard(app.data.logs.get_plain_text());
}
}
ActiveBlock::Describe => {
if key == DEFAULT_KEYBINDING.copy_to_clipboard.key {
copy_to_clipboard(app.data.describe_out.get_txt());
}
}
_ => {
}
}
}
RouteId::Contexts => {
let _ctx = handle_table_action(key, &mut app.data.contexts);
}
RouteId::Utilization => {
if key == DEFAULT_KEYBINDING.cycle_group_by.key {
if app.utilization_group_by.len() == 1 {
app.utilization_group_by = vec![
GroupBy::Resource,
GroupBy::Node,
GroupBy::Namespace,
GroupBy::Pod,
];
} else {
app.utilization_group_by.pop();
}
app.tick_count = 0; }
}
_ => {}
}
if key == DEFAULT_KEYBINDING.submit.key {
app.tick_count = 0;
}
}
fn handle_table_action<T: Clone>(key: Key, item: &mut StatefulTable<T>) -> Option<T> {
match key {
_ if key == DEFAULT_KEYBINDING.submit.key
|| key == DEFAULT_KEYBINDING.describe_resource.key =>
{
item.get_selected_item()
}
_ => None,
}
}
fn handle_table_scroll<T: Clone>(item: &mut StatefulTable<T>, down: bool) {
if down {
item.previous();
} else {
item.next();
}
}
fn inverse_dir(down: bool, is_mouse: bool) -> bool {
if is_mouse {
down
} else {
!down
}
}
async fn handle_scroll(app: &mut App, down: bool, is_mouse: bool) {
match app.get_current_route().active_block {
ActiveBlock::Pods => handle_table_scroll(&mut app.data.pods, down),
ActiveBlock::Containers => handle_table_scroll(
&mut app
.data
.pods
.get_selected_item()
.map_or(StatefulTable::new(), |c| c.containers),
down,
),
ActiveBlock::Services => handle_table_scroll(&mut app.data.services, down),
ActiveBlock::Nodes => handle_table_scroll(&mut app.data.nodes, down),
ActiveBlock::Namespaces => handle_table_scroll(&mut app.data.namespaces, down),
ActiveBlock::Contexts => handle_table_scroll(&mut app.data.contexts, down),
ActiveBlock::Utilization => handle_table_scroll(&mut app.data.metrics, down),
ActiveBlock::Logs => {
app.log_auto_scroll = false;
if inverse_dir(down, is_mouse) {
app.data.logs.scroll_down();
} else {
app.data.logs.scroll_up();
}
}
ActiveBlock::Describe => {
if inverse_dir(down, is_mouse) {
app.data.describe_out.scroll_down();
} else {
app.data.describe_out.scroll_up();
}
}
_ => {}
}
}
fn copy_to_clipboard(content: String) {
use clipboard::ClipboardContext;
use clipboard::ClipboardProvider;
let mut ctx: ClipboardContext = ClipboardProvider::new().expect("Unable to obtain clipboard");
ctx
.set_contents(content)
.expect("Unable to set content to clipboard");
}