Added a third panel to display current projecct information and tool

information.
This commit is contained in:
2026-05-21 17:04:37 -05:00
parent 95b86f80aa
commit 283a336643
2 changed files with 269 additions and 5 deletions
+114 -5
View File
@@ -5,6 +5,7 @@ use crossterm::{
execute,
terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
};
use iced::alignment::Vertical::Bottom;
use ratatui::{
prelude::*,
widgets::{Block, Borders, List, ListItem, ListState, Paragraph},
@@ -82,7 +83,11 @@ pub fn run_tui(
.split(f.area());
let top_chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(30), Constraint::Percentage(70)])
.constraints([
Constraint::Percentage(20),
Constraint::Percentage(45),
Constraint::Percentage(35),
])
.split(main_chunks[0]);
let projects: Vec<ListItem> = state
.projects
@@ -103,6 +108,86 @@ pub fn run_tui(
)
.highlight_symbol(">> ");
f.render_stateful_widget(projects_list, top_chunks[0], &mut project_list_state);
let mut info_lines: Vec<Line> = Vec::new();
let project = state.projects[state.selected_project].clone();
info_lines.push(Line::from(Span::styled(
"--- PROJECT INFORMATION ---",
Style::default().fg(Color::Green),
)));
info_lines.push(Line::from(format!("ORG: {}", project.org_name)));
info_lines.push(Line::from(format!("NAME: {}", project.name)));
info_lines.push(Line::from(format!("NOTES: {}", project.notes.display())));
info_lines.push(Line::from(format!("Files: {}", project.files.display())));
if let Some(db) = project.db {
info_lines.push(Line::from(format!("DISTROBOX: {}", db.name)));
}
if project.current {
info_lines.push(Line::from("STATUS: CURRENT"));
} else {
info_lines.push(Line::from("STATUS: UPCOMING"));
}
if !project.hosts.is_empty() {
info_lines.push(Line::from(Span::styled(
"--- PROJECT HOST INFORMATION ---",
Style::default().fg(Color::Green),
)));
for host in &project.hosts {
info_lines.push(Line::from(format!("- {}:{}", host.hostname, host.ip)));
info_lines.push(Line::from(format!(" - PWNED: {}", host.pwned)));
info_lines.push(Line::from(format!(
" - CONTROL PORT: {}",
host.control_port
)));
if !host.open_ports.is_empty() {
info_lines.push(Line::from(format!(" - PORTS:")));
for port in &host.open_ports {
info_lines.push(Line::from(format!(" - {}", port)));
}
}
if !host.users.is_empty() {
info_lines.push(Line::from(format!(" - USERS:")));
for user in &host.users {
info_lines.push(Line::from(format!(
" - {} - PWNED: {}",
user.name, user.compromised
)));
}
}
}
}
let spacer = format!("{}", "+".repeat(top_chunks[2].width as usize - 2));
info_lines.push(Line::from(Span::styled(
&spacer,
Style::default().fg(Color::Green),
)));
info_lines.push(Line::from(Span::styled(
"--- Tool Information ---",
Style::default().fg(Color::Green),
)));
info_lines.push(Line::from(format!(
"CONFIG FILE: {}",
state.config_file.display()
)));
for setting in state.config.keys() {
info_lines.push(Line::from(format!(
"{}: {}",
setting.to_uppercase(),
state.config.get(setting).unwrap()
)));
}
let info_area_height = top_chunks[1].height.saturating_sub(2) as usize;
if state.info_scroll as usize > info_lines.len().saturating_sub(info_area_height) {
state.info_scroll = info_lines.len().saturating_sub(info_area_height) as u16;
}
let info_paragraph = Paragraph::new(info_lines)
.block(
Block::default()
.borders(Borders::ALL)
.title("Selected Project Information"),
)
.scroll((state.info_scroll, 0))
.wrap(ratatui::widgets::Wrap { trim: false });
f.render_widget(info_paragraph, top_chunks[2]);
let output_lines: Vec<Line> = state
.output
.iter()
@@ -341,10 +426,34 @@ pub fn run_tui(
}
}
AppEvent::Mouse(mouse) => {
if mouse.kind == crossterm::event::MouseEventKind::ScrollUp {
state.output_scroll = state.output_scroll.saturating_sub(1);
} else if mouse.kind == crossterm::event::MouseEventKind::ScrollDown {
state.output_scroll = state.output_scroll.saturating_add(1);
if let Ok(size) = terminal.size() {
let main_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(0), Constraint::Max(3)])
.split(ratatui::layout::Rect::from(size));
let top_chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(20),
Constraint::Percentage(45),
Constraint::Percentage(35),
])
.split(main_chunks[0]);
let left_side_cutoff = top_chunks[0].width + top_chunks[1].width;
if mouse.column < left_side_cutoff {
if mouse.kind == crossterm::event::MouseEventKind::ScrollUp {
state.output_scroll = state.output_scroll.saturating_sub(1);
} else if mouse.kind == crossterm::event::MouseEventKind::ScrollDown {
state.output_scroll = state.output_scroll.saturating_add(1);
}
} else {
if mouse.kind == crossterm::event::MouseEventKind::ScrollUp {
state.info_scroll = state.info_scroll.saturating_sub(1);
} else if mouse.kind == crossterm::event::MouseEventKind::ScrollDown {
state.info_scroll = state.info_scroll.saturating_add(1);
}
}
}
}
}