WIP: Add UI to application #1
15
src/app.rs
15
src/app.rs
@ -1,8 +1,17 @@
|
||||
use ratatui::widgets::ListState;
|
||||
|
||||
use crate::config::*;
|
||||
|
||||
pub enum AppRenderDir {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
pub enum MenuState {
|
||||
Main,
|
||||
List,
|
||||
}
|
||||
|
||||
pub enum CurrentState {
|
||||
Lookup,
|
||||
Menu,
|
||||
@ -14,6 +23,9 @@ pub struct App {
|
||||
pub dns_info: Vec<String>,
|
||||
pub render_direction: AppRenderDir,
|
||||
pub current_state: CurrentState,
|
||||
pub menu_state: MenuState,
|
||||
pub config: Config,
|
||||
pub state: ListState,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@ -24,6 +36,9 @@ impl App {
|
||||
dns_info: vec![],
|
||||
render_direction: AppRenderDir::Vertical,
|
||||
current_state: CurrentState::Lookup,
|
||||
menu_state: MenuState::Main,
|
||||
config: Config::from_file("test.ini".to_string()),
|
||||
state: ListState::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,12 @@ use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use ratatui::{
|
||||
style::{Modifier, Style},
|
||||
text::{Line, Span},
|
||||
widgets::ListItem,
|
||||
};
|
||||
|
||||
use crate::config::Config;
|
||||
|
||||
#[derive(Serialize)]
|
||||
@ -43,4 +49,17 @@ impl DomainData {
|
||||
Ok(())
|
||||
// println!("{}", output);
|
||||
}
|
||||
|
||||
pub fn list_lookups(config: &Config) -> Vec<ListItem> {
|
||||
let mut items: Vec<ListItem> = vec![];
|
||||
for item in fs::read_dir(format!("{}/lookups", config.data_dir)).unwrap() {
|
||||
let item_name = item.unwrap();
|
||||
items.push(ListItem::new(Line::from(Span::styled(
|
||||
String::from(item_name.path().to_string_lossy().clone()),
|
||||
Style::default(),
|
||||
))));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
55
src/main.rs
55
src/main.rs
@ -13,8 +13,8 @@ use crate::app::*;
|
||||
mod ui;
|
||||
use crate::ui::*;
|
||||
|
||||
mod fs;
|
||||
use crate::fs::*;
|
||||
mod fsutil;
|
||||
use crate::fsutil::*;
|
||||
|
||||
use crossterm::event::{
|
||||
self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind,
|
||||
@ -41,7 +41,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
let config = Config::from_file("test.ini".to_string());
|
||||
|
||||
// Run the app
|
||||
let _res = run_app(&mut terminal, &mut app, &config);
|
||||
let _res = run_app(&mut terminal, &mut app);
|
||||
|
||||
disable_raw_mode()?;
|
||||
execute!(
|
||||
@ -53,11 +53,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_app<B: Backend>(
|
||||
terminal: &mut Terminal<B>,
|
||||
app: &mut App,
|
||||
config: &Config,
|
||||
) -> io::Result<bool> {
|
||||
fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> io::Result<bool> {
|
||||
loop {
|
||||
terminal.draw(|f| ui(f, app))?;
|
||||
|
||||
@ -83,7 +79,7 @@ fn run_app<B: Backend>(
|
||||
continue;
|
||||
}
|
||||
let mut domain = Domain::new(app.domain_input.clone());
|
||||
domain.apply_config(&config);
|
||||
domain.apply_config(&app.config);
|
||||
domain.lookup_all_records();
|
||||
app.dns_info = domain.to_vec();
|
||||
let whois = WhoisData::new(app.domain_input.clone());
|
||||
@ -94,21 +90,32 @@ fn run_app<B: Backend>(
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
CurrentState::Menu => match key.code {
|
||||
KeyCode::Esc => {
|
||||
app.current_state = CurrentState::Lookup;
|
||||
}
|
||||
KeyCode::Char('s') => {
|
||||
let domain_data = DomainData::new(
|
||||
app.domain_input.clone(),
|
||||
app.dns_info.clone(),
|
||||
app.whois_info.clone(),
|
||||
);
|
||||
domain_data.save_lookup(&config).unwrap();
|
||||
app.current_state = CurrentState::Lookup;
|
||||
}
|
||||
KeyCode::Char('q') => return Ok(false),
|
||||
_ => {}
|
||||
CurrentState::Menu => match app.menu_state {
|
||||
MenuState::Main => match key.code {
|
||||
KeyCode::Esc => {
|
||||
app.current_state = CurrentState::Lookup;
|
||||
}
|
||||
KeyCode::Char('s') => {
|
||||
let domain_data = DomainData::new(
|
||||
app.domain_input.clone(),
|
||||
app.dns_info.clone(),
|
||||
app.whois_info.clone(),
|
||||
);
|
||||
domain_data.save_lookup(&app.config).unwrap();
|
||||
app.current_state = CurrentState::Lookup;
|
||||
}
|
||||
KeyCode::Char('l') => {
|
||||
app.menu_state = MenuState::List;
|
||||
}
|
||||
KeyCode::Char('q') => return Ok(false),
|
||||
_ => {}
|
||||
},
|
||||
MenuState::List => match key.code {
|
||||
KeyCode::Esc => {
|
||||
app.menu_state = MenuState::Main;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
142
src/ui.rs
142
src/ui.rs
@ -1,14 +1,17 @@
|
||||
use ratatui::{
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Style, Styled},
|
||||
style::{Color, Modifier, Style, Styled},
|
||||
text::{Line, Span, Text},
|
||||
widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Wrap},
|
||||
widgets::{
|
||||
Block, Borders, Clear, HighlightSpacing, List, ListDirection, ListItem, ListState,
|
||||
Paragraph, Wrap,
|
||||
},
|
||||
Frame,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app::{App, AppRenderDir},
|
||||
CurrentState,
|
||||
CurrentState, DomainData, MenuState,
|
||||
};
|
||||
|
||||
pub fn ui(f: &mut Frame, app: &mut App) {
|
||||
@ -188,61 +191,104 @@ pub fn ui(f: &mut Frame, app: &mut App) {
|
||||
}
|
||||
}
|
||||
CurrentState::Menu => {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(3),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(3),
|
||||
])
|
||||
.split(f.size());
|
||||
match app.menu_state {
|
||||
MenuState::Main => {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(3),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(3),
|
||||
])
|
||||
.split(f.size());
|
||||
|
||||
let title_block = Block::new().borders(Borders::ALL).style(Style::default());
|
||||
let title_block = Block::new().borders(Borders::ALL).style(Style::default());
|
||||
|
||||
let title = Paragraph::new(Text::styled(
|
||||
"**** Menu ****",
|
||||
Style::default().fg(Color::Cyan),
|
||||
))
|
||||
.block(title_block);
|
||||
f.render_widget(title, chunks[0]);
|
||||
let title = Paragraph::new(Text::styled(
|
||||
"**** Menu ****",
|
||||
Style::default().fg(Color::Cyan),
|
||||
))
|
||||
.block(title_block);
|
||||
f.render_widget(title, chunks[0]);
|
||||
|
||||
let mut options_list = Vec::<ListItem>::new();
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"ESC) Return to lookup",
|
||||
Style::default(),
|
||||
))));
|
||||
let mut options_list = Vec::<ListItem>::new();
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"ESC) Return to lookup",
|
||||
Style::default(),
|
||||
))));
|
||||
|
||||
// TODO: Add code to save lookup
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"S) Save lookup",
|
||||
Style::default(),
|
||||
))));
|
||||
// TODO: Add code to save lookup
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"S) Save lookup",
|
||||
Style::default(),
|
||||
))));
|
||||
|
||||
// TODO: Add code to load and UI to list saved lookups
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"L) List previous lookups",
|
||||
Style::default(),
|
||||
))));
|
||||
// TODO: Add code to load and UI to list saved lookups
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"L) List previous lookups",
|
||||
Style::default(),
|
||||
))));
|
||||
|
||||
// TODO: Add code to read lookup and display
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"V) View previous lookup",
|
||||
Style::default(),
|
||||
))));
|
||||
// TODO: Add code to read lookup and display
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"V) View previous lookup",
|
||||
Style::default(),
|
||||
))));
|
||||
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"Q) Quit",
|
||||
Style::default(),
|
||||
))));
|
||||
options_list.push(ListItem::new(Line::from(Span::styled(
|
||||
"Q) Quit",
|
||||
Style::default(),
|
||||
))));
|
||||
|
||||
let options = List::new(options_list);
|
||||
f.render_widget(options, chunks[1]);
|
||||
let options = List::new(options_list);
|
||||
f.render_widget(options, chunks[1]);
|
||||
|
||||
let footer_block = Block::new().borders(Borders::ALL).style(Style::default());
|
||||
let footer_block = Block::new().borders(Borders::ALL).style(Style::default());
|
||||
|
||||
let footer = Paragraph::new(Text::styled("[q] Quit", Style::default().fg(Color::Red)))
|
||||
.block(footer_block);
|
||||
f.render_widget(footer, chunks[2]);
|
||||
let footer =
|
||||
Paragraph::new(Text::styled("[q] Quit", Style::default().fg(Color::Red)))
|
||||
.block(footer_block);
|
||||
f.render_widget(footer, chunks[2]);
|
||||
}
|
||||
MenuState::List => {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(3),
|
||||
Constraint::Min(1),
|
||||
Constraint::Length(3),
|
||||
])
|
||||
.split(f.size());
|
||||
|
||||
let title_block = Block::new().borders(Borders::ALL).style(Style::default());
|
||||
|
||||
let title = Paragraph::new(Text::styled(
|
||||
"**** List ****",
|
||||
Style::default().fg(Color::Cyan),
|
||||
))
|
||||
.block(title_block);
|
||||
f.render_widget(title, chunks[0]);
|
||||
|
||||
let item_list = DomainData::list_lookups(&app.config);
|
||||
let items = List::new(item_list)
|
||||
.block(Block::default().title("Lookups").borders(Borders::ALL))
|
||||
.style(Style::default())
|
||||
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.highlight_symbol(">>")
|
||||
.highlight_spacing(HighlightSpacing::Always)
|
||||
.repeat_highlight_symbol(true);
|
||||
f.render_stateful_widget(items, chunks[1], &mut app.state);
|
||||
|
||||
let footer_block = Block::new().borders(Borders::ALL).style(Style::default());
|
||||
|
||||
let footer = Paragraph::new(Text::styled(
|
||||
"[ESC] Return to menu",
|
||||
Style::default().fg(Color::Red),
|
||||
))
|
||||
.block(footer_block);
|
||||
f.render_widget(footer, chunks[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user