[Fix] Connection Management
This commit is contained in:
parent
9e9e3597da
commit
3f2ac18333
122 changed files with 19970 additions and 5263 deletions
|
|
@ -13,11 +13,11 @@ use std::{
|
|||
};
|
||||
use tokio::time::Instant;
|
||||
|
||||
use crate::theme::ResolvedTheme;
|
||||
use crate::{
|
||||
elements::elements::{Element, InteractableElement, JoinableElement},
|
||||
interaction_result::InteractionResult,
|
||||
ipc_client::IpcClient,
|
||||
render_context::RenderContext,
|
||||
screens::screens::IotaInteraction,
|
||||
util::borders::draw_block_joins,
|
||||
};
|
||||
|
||||
|
|
@ -300,18 +300,13 @@ impl Element for ConsoleCard {
|
|||
self
|
||||
}
|
||||
|
||||
fn render(&self, f: &mut Frame, r: Rect, context: &RenderContext<'_>) {
|
||||
if matches!(context.theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
let inner = crate::controls::panel::render_panel(
|
||||
f,
|
||||
r,
|
||||
&self.title,
|
||||
self.focused,
|
||||
context.theme,
|
||||
);
|
||||
fn render(&self, f: &mut Frame, r: Rect, theme: &ResolvedTheme) {
|
||||
if matches!(theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
let inner =
|
||||
crate::controls::panel::render_panel(f, r, &self.title, self.focused, theme);
|
||||
f.render_widget(
|
||||
Paragraph::new(Line::from(self.render_cursor_spans(context.theme)))
|
||||
.style(context.theme.console.text),
|
||||
Paragraph::new(Line::from(self.render_cursor_spans(theme)))
|
||||
.style(theme.console.text),
|
||||
inner,
|
||||
);
|
||||
return;
|
||||
|
|
@ -319,15 +314,15 @@ impl Element for ConsoleCard {
|
|||
let block = Block::default()
|
||||
.borders(self.borders)
|
||||
.title(self.title.clone())
|
||||
.title_style(context.theme.console.title)
|
||||
.title_style(theme.console.title)
|
||||
.border_style(if self.focused {
|
||||
context.theme.console.focused_border
|
||||
theme.console.focused_border
|
||||
} else {
|
||||
context.theme.console.border
|
||||
theme.console.border
|
||||
})
|
||||
.style(context.theme.console.text);
|
||||
.style(theme.console.text);
|
||||
|
||||
let spans = self.render_cursor_spans(context.theme);
|
||||
let spans = self.render_cursor_spans(theme);
|
||||
let par = Paragraph::new(Line::from(spans))
|
||||
.block(block)
|
||||
.scroll((0, 0));
|
||||
|
|
@ -338,9 +333,9 @@ impl Element for ConsoleCard {
|
|||
self.borders,
|
||||
self.joins,
|
||||
if self.focused {
|
||||
context.theme.borders.focused
|
||||
theme.borders.focused
|
||||
} else {
|
||||
context.theme.borders.normal
|
||||
theme.borders.normal
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -389,7 +384,7 @@ impl InteractableElement for ConsoleCard {
|
|||
self
|
||||
}
|
||||
|
||||
fn interact(&mut self, key: KeyEvent) -> InteractionResult {
|
||||
fn interact(&mut self, key: KeyEvent) -> IotaInteraction {
|
||||
// Check if a previously failed command should be restored.
|
||||
if let Some(restored) = self.pending_restore.lock().unwrap().take() {
|
||||
self.content = restored;
|
||||
|
|
@ -401,26 +396,26 @@ impl InteractableElement for ConsoleCard {
|
|||
if matches!(key.code, KeyCode::Char('y') | KeyCode::Char('Y')) {
|
||||
self.dispatch_command(command);
|
||||
}
|
||||
return InteractionResult::Handled;
|
||||
return IotaInteraction::Changed;
|
||||
}
|
||||
|
||||
match key.code {
|
||||
KeyCode::Enter => {
|
||||
if self.content.is_empty() {
|
||||
return InteractionResult::Handled;
|
||||
return IotaInteraction::Changed;
|
||||
}
|
||||
|
||||
let command = self.content.clone();
|
||||
if let Some(error) = iota_ipc::text_commands::validation_error(&command) {
|
||||
self.message = Some(error);
|
||||
return InteractionResult::Handled;
|
||||
return IotaInteraction::Changed;
|
||||
}
|
||||
if command.trim_start_matches('/').trim() == "help" {
|
||||
self.message = Some(format!(
|
||||
"Commands: {}",
|
||||
iota_ipc::text_commands::COMMANDS.join(", ")
|
||||
));
|
||||
return InteractionResult::Handled;
|
||||
return IotaInteraction::Changed;
|
||||
}
|
||||
if self.history.last() != Some(&command) {
|
||||
self.history.push(command.clone());
|
||||
|
|
@ -434,12 +429,12 @@ impl InteractableElement for ConsoleCard {
|
|||
} else {
|
||||
self.dispatch_command(command);
|
||||
}
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
self.message = None;
|
||||
self.delete_at_cursor();
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Delete => {
|
||||
self.message = None;
|
||||
|
|
@ -454,41 +449,41 @@ impl InteractableElement for ConsoleCard {
|
|||
.unwrap_or(self.content.len());
|
||||
self.content.replace_range(start..end, "");
|
||||
}
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Left => {
|
||||
self.move_cursor_left();
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Right => {
|
||||
self.move_cursor_right();
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Home => {
|
||||
self.cursor_position = 0;
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::End => {
|
||||
self.cursor_position = self.content.chars().count();
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Up => {
|
||||
self.history_previous();
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Down => {
|
||||
self.history_next();
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Tab if !self.content.is_empty() => {
|
||||
if self.complete() {
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
} else {
|
||||
self.message = Some("No command completion.".into());
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
}
|
||||
KeyCode::Tab | KeyCode::BackTab => InteractionResult::Unhandled,
|
||||
KeyCode::Tab | KeyCode::BackTab => IotaInteraction::Unhandled,
|
||||
_ => {
|
||||
if !key
|
||||
.modifiers
|
||||
|
|
@ -497,10 +492,10 @@ impl InteractableElement for ConsoleCard {
|
|||
if let Some(c) = key.code.as_char() {
|
||||
self.insert_at_cursor(c);
|
||||
self.message = None;
|
||||
return InteractionResult::Handled;
|
||||
return IotaInteraction::Changed;
|
||||
}
|
||||
}
|
||||
InteractionResult::Unhandled
|
||||
IotaInteraction::Unhandled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,15 @@ use std::any::Any;
|
|||
use crossterm::event::KeyEvent;
|
||||
use ratatui::{Frame, layout::Rect, widgets::Borders};
|
||||
|
||||
use crate::{
|
||||
interaction_result::InteractionResult, render_context::RenderContext, screens::screens::Screen,
|
||||
};
|
||||
use crate::screens::screens::{IotaInteraction, IotaScreen};
|
||||
use crate::theme::ResolvedTheme;
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait Element: Send + Sync + Any {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
fn render(&self, f: &mut Frame, r: Rect, context: &RenderContext<'_>);
|
||||
fn render(&self, f: &mut Frame, r: Rect, theme: &ResolvedTheme);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
|
@ -33,7 +32,7 @@ pub trait InfoElement: Send + Sync + Any {
|
|||
fn as_element(&self) -> &dyn Element;
|
||||
fn as_element_mut(&mut self) -> &mut dyn Element;
|
||||
|
||||
fn get_info_screen(&self) -> Box<dyn Screen>;
|
||||
fn get_info_screen(&self) -> Box<dyn IotaScreen>;
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
|
@ -43,7 +42,7 @@ pub trait InteractableElement: Send + Sync + Any {
|
|||
fn as_element(&self) -> &dyn Element;
|
||||
fn as_element_mut(&mut self) -> &mut dyn Element;
|
||||
|
||||
fn interact(&mut self, key: KeyEvent) -> InteractionResult;
|
||||
fn interact(&mut self, key: KeyEvent) -> IotaInteraction;
|
||||
|
||||
fn can_focus(&self) -> bool;
|
||||
fn is_focused(&self) -> bool;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{any::Any, sync::Arc};
|
||||
use std::any::Any;
|
||||
|
||||
use crossterm::event::KeyEvent;
|
||||
use iota_state::ClientState;
|
||||
|
|
@ -11,11 +11,10 @@ use ratatui::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::theme::ResolvedTheme;
|
||||
use crate::{
|
||||
elements::elements::{Element, InteractableElement, JoinableElement},
|
||||
interaction_result::InteractionResult,
|
||||
render_context::RenderContext,
|
||||
ui::UI,
|
||||
screens::screens::IotaInteraction,
|
||||
util::borders::draw_block_joins,
|
||||
};
|
||||
|
||||
|
|
@ -67,7 +66,6 @@ impl GRAPHS {
|
|||
|
||||
#[allow(unused)]
|
||||
pub struct GraphCard {
|
||||
ui: Arc<UI>,
|
||||
state: ClientState,
|
||||
graph_type: GRAPHS,
|
||||
|
||||
|
|
@ -82,9 +80,8 @@ pub struct GraphCard {
|
|||
}
|
||||
|
||||
impl GraphCard {
|
||||
pub fn new(ui: Arc<UI>, state: ClientState, graph_type: GRAPHS, title: String) -> Self {
|
||||
pub fn new(state: ClientState, graph_type: GRAPHS, title: String) -> Self {
|
||||
Self {
|
||||
ui,
|
||||
state,
|
||||
graph_type,
|
||||
focused: false,
|
||||
|
|
@ -113,7 +110,7 @@ impl Element for GraphCard {
|
|||
self
|
||||
}
|
||||
|
||||
fn render(&self, f: &mut Frame, r: Rect, context: &RenderContext<'_>) {
|
||||
fn render(&self, f: &mut Frame, r: Rect, theme: &ResolvedTheme) {
|
||||
if self.open {
|
||||
let graph = self.graph_type.get_graph(&self.state, self.sample_width);
|
||||
if graph.is_empty() {
|
||||
|
|
@ -121,13 +118,13 @@ impl Element for GraphCard {
|
|||
.title(format!(" {} ", self.title))
|
||||
.borders(self.borders)
|
||||
.border_style(if self.focused {
|
||||
context.theme.graphs.focused_border
|
||||
theme.graphs.focused_border
|
||||
} else {
|
||||
context.theme.graphs.border
|
||||
theme.graphs.border
|
||||
});
|
||||
f.render_widget(
|
||||
ratatui::widgets::Paragraph::new("No metric samples yet.")
|
||||
.style(context.theme.text.muted)
|
||||
.style(theme.text.muted)
|
||||
.block(block),
|
||||
r,
|
||||
);
|
||||
|
|
@ -149,7 +146,7 @@ impl Element for GraphCard {
|
|||
GRAPHS::Ping => (max_y * 1.2).max(10.0),
|
||||
};
|
||||
|
||||
let surface = matches!(context.theme.chrome, crate::theme::ChromeMode::Surfaces);
|
||||
let surface = matches!(theme.chrome, crate::theme::ChromeMode::Surfaces);
|
||||
let title = format!(
|
||||
"{}: {}{} {}min/{}max",
|
||||
self.title,
|
||||
|
|
@ -159,7 +156,7 @@ impl Element for GraphCard {
|
|||
max_y as i64
|
||||
);
|
||||
let plot_area = if surface {
|
||||
crate::controls::panel::render_panel(f, r, &title, self.focused, context.theme)
|
||||
crate::controls::panel::render_panel(f, r, &title, self.focused, theme)
|
||||
} else {
|
||||
r
|
||||
};
|
||||
|
|
@ -178,9 +175,9 @@ impl Element for GraphCard {
|
|||
})
|
||||
.borders(if surface { Borders::NONE } else { self.borders })
|
||||
.border_style(if self.focused {
|
||||
context.theme.graphs.focused_border
|
||||
theme.graphs.focused_border
|
||||
} else {
|
||||
context.theme.graphs.border
|
||||
theme.graphs.border
|
||||
});
|
||||
|
||||
let canvas = Canvas::default()
|
||||
|
|
@ -194,7 +191,7 @@ impl Element for GraphCard {
|
|||
y1: 0.0,
|
||||
x2: *x,
|
||||
y2: *y,
|
||||
color: self.graph_type.get_color(context.theme),
|
||||
color: self.graph_type.get_color(theme),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -204,22 +201,22 @@ impl Element for GraphCard {
|
|||
.title("")
|
||||
.borders(self.borders)
|
||||
.border_style(if self.focused {
|
||||
context.theme.graphs.focused_border
|
||||
theme.graphs.focused_border
|
||||
} else {
|
||||
context.theme.graphs.border
|
||||
theme.graphs.border
|
||||
});
|
||||
f.render_widget(block, r);
|
||||
}
|
||||
if !matches!(context.theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
if !matches!(theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
draw_block_joins(
|
||||
f,
|
||||
r,
|
||||
self.borders,
|
||||
self.joins,
|
||||
if self.focused {
|
||||
context.theme.borders.focused
|
||||
theme.borders.focused
|
||||
} else {
|
||||
context.theme.borders.normal
|
||||
theme.borders.normal
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -269,8 +266,8 @@ impl InteractableElement for GraphCard {
|
|||
self
|
||||
}
|
||||
|
||||
fn interact(&mut self, _key: KeyEvent) -> InteractionResult {
|
||||
InteractionResult::Handled
|
||||
fn interact(&mut self, _key: KeyEvent) -> IotaInteraction {
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
|
||||
fn can_focus(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::elements::elements::{Element, InteractableElement, JoinableElement};
|
||||
use crate::util::borders::draw_block_joins;
|
||||
use crate::{interaction_result::InteractionResult, render_context::RenderContext};
|
||||
use crate::{screens::screens::IotaInteraction, theme::ResolvedTheme};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use iota_state::{ClientState, UiLogEntry};
|
||||
use ratatui::{
|
||||
|
|
@ -270,7 +270,7 @@ impl LogCard {
|
|||
}
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self) {
|
||||
pub fn scroll_older(&mut self) {
|
||||
let max_offset = self
|
||||
.last_total_lines
|
||||
.load(Ordering::Relaxed)
|
||||
|
|
@ -278,7 +278,7 @@ impl LogCard {
|
|||
self.scroll_offset = (self.scroll_offset + 1).min(max_offset);
|
||||
}
|
||||
|
||||
fn scroll_down(&mut self) {
|
||||
pub fn scroll_newer(&mut self) {
|
||||
self.scroll_offset = self.scroll_offset.saturating_sub(1);
|
||||
}
|
||||
|
||||
|
|
@ -318,25 +318,19 @@ impl Element for LogCard {
|
|||
self
|
||||
}
|
||||
|
||||
fn render(&self, f: &mut Frame, area: Rect, context: &RenderContext<'_>) {
|
||||
fn render(&self, f: &mut Frame, area: Rect, theme: &ResolvedTheme) {
|
||||
let entries = self.get_logs();
|
||||
|
||||
let inner_area = if matches!(context.theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
crate::controls::panel::render_panel(
|
||||
f,
|
||||
area,
|
||||
&self.build_title(),
|
||||
self.focused,
|
||||
context.theme,
|
||||
)
|
||||
let inner_area = if matches!(theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
crate::controls::panel::render_panel(f, area, &self.build_title(), self.focused, theme)
|
||||
} else {
|
||||
let block = Block::default()
|
||||
.title(self.build_title())
|
||||
.borders(self.borders)
|
||||
.border_style(if self.focused {
|
||||
context.theme.logs.focused_border
|
||||
theme.logs.focused_border
|
||||
} else {
|
||||
context.theme.logs.border
|
||||
theme.logs.border
|
||||
});
|
||||
let inner = block.inner(area);
|
||||
f.render_widget(block, area);
|
||||
|
|
@ -350,9 +344,9 @@ impl Element for LogCard {
|
|||
self.borders,
|
||||
self.joins,
|
||||
if self.focused {
|
||||
context.theme.borders.focused
|
||||
theme.borders.focused
|
||||
} else {
|
||||
context.theme.borders.normal
|
||||
theme.borders.normal
|
||||
},
|
||||
);
|
||||
return;
|
||||
|
|
@ -376,24 +370,21 @@ impl Element for LogCard {
|
|||
let mut spans = Vec::new();
|
||||
|
||||
let (prefix, rest) = Self::split_line_prefix(line);
|
||||
let prefix = if matches!(context.theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
let prefix = if matches!(theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
""
|
||||
} else {
|
||||
prefix
|
||||
};
|
||||
|
||||
if !prefix.is_empty() {
|
||||
spans.push(Span::styled(
|
||||
prefix.to_string(),
|
||||
source.style(context.theme),
|
||||
));
|
||||
spans.push(Span::styled(prefix.to_string(), source.style(theme)));
|
||||
}
|
||||
|
||||
let (content, timestamp) = Self::split_timestamp_suffix(rest);
|
||||
let text_style = if *is_error {
|
||||
context.theme.logs.error
|
||||
theme.logs.error
|
||||
} else {
|
||||
context.theme.logs.text
|
||||
theme.logs.text
|
||||
};
|
||||
|
||||
if !content.is_empty() {
|
||||
|
|
@ -401,10 +392,7 @@ impl Element for LogCard {
|
|||
}
|
||||
|
||||
if !timestamp.is_empty() {
|
||||
spans.push(Span::styled(
|
||||
timestamp.to_string(),
|
||||
context.theme.logs.timestamp,
|
||||
));
|
||||
spans.push(Span::styled(timestamp.to_string(), theme.logs.timestamp));
|
||||
}
|
||||
|
||||
Line::from(spans)
|
||||
|
|
@ -421,16 +409,16 @@ impl Element for LogCard {
|
|||
f.render_widget(Paragraph::new(line.clone()), line_area);
|
||||
}
|
||||
|
||||
if !matches!(context.theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
if !matches!(theme.chrome, crate::theme::ChromeMode::Surfaces) {
|
||||
draw_block_joins(
|
||||
f,
|
||||
area,
|
||||
self.borders,
|
||||
self.joins,
|
||||
if self.focused {
|
||||
context.theme.borders.focused
|
||||
theme.borders.focused
|
||||
} else {
|
||||
context.theme.borders.normal
|
||||
theme.borders.normal
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -480,7 +468,7 @@ impl InteractableElement for LogCard {
|
|||
&mut *self
|
||||
}
|
||||
|
||||
fn interact(&mut self, key: KeyEvent) -> InteractionResult {
|
||||
fn interact(&mut self, key: KeyEvent) -> IotaInteraction {
|
||||
if self.filtering {
|
||||
match key.code {
|
||||
KeyCode::Esc => {
|
||||
|
|
@ -501,7 +489,7 @@ impl InteractableElement for LogCard {
|
|||
_ => {}
|
||||
}
|
||||
self.scroll_offset = 0;
|
||||
return InteractionResult::Handled;
|
||||
return IotaInteraction::Changed;
|
||||
}
|
||||
let entries = self.get_logs();
|
||||
let width = self.last_width.load(Ordering::Relaxed).max(1);
|
||||
|
|
@ -517,51 +505,51 @@ impl InteractableElement for LogCard {
|
|||
self.filtering = true;
|
||||
self.filter.clear();
|
||||
self.scroll_offset = 0;
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Enter | KeyCode::Char(' ') => {
|
||||
self.selected = !self.selected;
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Char('j') | KeyCode::Char('J') => {
|
||||
let (can_up, _) = self.get_title_hints();
|
||||
if can_up {
|
||||
self.scroll_up();
|
||||
self.scroll_older();
|
||||
}
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Char('k') | KeyCode::Char('K') => {
|
||||
let (_, can_down) = self.get_title_hints();
|
||||
if can_down {
|
||||
self.scroll_down();
|
||||
self.scroll_newer();
|
||||
}
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Up if self.selected => {
|
||||
let (can_up, _) = self.get_title_hints();
|
||||
if can_up {
|
||||
self.scroll_up();
|
||||
self.scroll_older();
|
||||
}
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Down if self.selected => {
|
||||
let (_, can_down) = self.get_title_hints();
|
||||
if can_down {
|
||||
self.scroll_down();
|
||||
self.scroll_newer();
|
||||
}
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::Home => {
|
||||
if total_lines > visible_height {
|
||||
self.scroll_offset = total_lines - visible_height;
|
||||
}
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
KeyCode::End => {
|
||||
self.scroll_offset = 0;
|
||||
InteractionResult::Handled
|
||||
IotaInteraction::Changed
|
||||
}
|
||||
_ => InteractionResult::Unhandled,
|
||||
_ => IotaInteraction::Unhandled,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue