Compare commits

1 Commits

Author SHA1 Message Date
ea04413e8a couple ui and data 2025-02-27 01:54:08 +08:00
9 changed files with 98 additions and 34 deletions

View File

@@ -1,18 +1,22 @@
use std::io; use std::{default, io};
use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind}; use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
use ratatui::{DefaultTerminal, Frame}; use ratatui::{DefaultTerminal, Frame};
use crate::{ use crate::{
session::{connection::ConnectionManager, credential::CredentialManager}, session::{connection::ConnectionManager, credential::CredentialManager, SessionManager},
view::{home::Home, View}, view::{home::Home, View},
}; };
pub struct App { pub struct App {
running: bool, running: bool,
view: Home, view: Home,
connection_manager: ConnectionManager, }
credential_manager: CredentialManager,
pub struct AppState {
pub connection_manager: ConnectionManager,
pub credential_manager: CredentialManager,
pub running: bool,
} }
impl Default for App { impl Default for App {
@@ -20,33 +24,45 @@ impl Default for App {
App { App {
running: true, running: true,
view: Home::default(), view: Home::default(),
connection_manager: ConnectionManager::default(), }
credential_manager: CredentialManager::default(), }
}
impl Default for AppState {
fn default() -> Self {
let mut sem = SessionManager::read_from_file();
let mut cnm = sem.connection_manager;
let mut crm = sem.credential_manager;
AppState {
connection_manager: cnm,
credential_manager: crm,
running: true,
} }
} }
} }
impl App { impl App {
pub fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> { pub fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> {
while self.running { let mut state = AppState::default();
terminal.draw(|frame| self.draw(frame))?; while state.running {
self.handle_event()?; terminal.draw(|frame| self.draw(frame, &state))?;
self.handle_event(&mut state)?;
} }
Ok(()) Ok(())
} }
fn draw(&self, frame: &mut Frame) { fn draw(&mut self, frame: &mut Frame, ctx: &AppState) {
self.view.draw(frame); self.view.draw(frame, ctx);
} }
fn handle_event(&mut self) -> io::Result<()> { fn handle_event(&mut self, ctx: &mut AppState) -> io::Result<()> {
match event::read()? { match event::read()? {
Event::Key(KeyEvent { Event::Key(KeyEvent {
kind: KeyEventKind::Press, kind: KeyEventKind::Press,
code: KeyCode::Esc, code: KeyCode::Esc,
.. ..
}) => self.running = false, }) => ctx.running = false,
event => self.view.handle_event(&event)?, event => self.view.handle_event(&event, ctx)?,
} }
Ok(()) Ok(())
} }

View File

@@ -22,6 +22,11 @@ fn main() -> io::Result<()> {
app_result app_result
} }
/* fn main() {
let mut conf = SessionManager::read_from_file();
println!("{:?}", conf.connection_manager.connections().len());
} */
// fn main() -> io::Result<()> { // fn main() -> io::Result<()> {
// // let sh = ShConnection::new("zsh".to_string(), "/usr/bin/nu".to_string(), None); // // let sh = ShConnection::new("zsh".to_string(), "/usr/bin/nu".to_string(), None);
// // let _ = sh.exec_cmd(); // // let _ = sh.exec_cmd();

View File

@@ -2,13 +2,16 @@ use connection::ConnectionManager;
use credential::CredentialManager; use credential::CredentialManager;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::global;
use crate::util::file;
pub mod connection; pub mod connection;
pub mod credential; pub mod credential;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct SessionManager { pub struct SessionManager {
connection_manager: ConnectionManager, pub connection_manager: ConnectionManager,
credential_manager: CredentialManager, pub credential_manager: CredentialManager,
} }
impl SessionManager { impl SessionManager {
@@ -18,4 +21,12 @@ impl SessionManager {
credential_manager: crm, credential_manager: crm,
} }
} }
pub fn read_from_file() -> SessionManager {
let conf = file::read_file(&global::CONFIG_DIR.join("tethers.toml"));
// println!("{}", conf);
let sem: SessionManager = toml::from_str(&conf).unwrap();
// let cnm: ConnectionManager = ConnectionManager { connections: vec![] };
sem
}
} }

View File

@@ -2,6 +2,7 @@ use std::{env, fs, io, path::Path, process::Command};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::global;
use crate::util::file; use crate::util::file;
use super::credential::{Credential, CredentialType}; use super::credential::{Credential, CredentialType};
@@ -12,7 +13,7 @@ pub trait Connection {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct ShConnection { pub struct ShConnection {
name: String, pub name: String,
path: String, path: String,
args: Vec<String>, args: Vec<String>,
} }
@@ -45,7 +46,7 @@ impl ShConnection {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct SshConnection { pub struct SshConnection {
name: String, pub name: String,
host: String, host: String,
port: u16, port: u16,
user: String, user: String,
@@ -113,4 +114,8 @@ impl ConnectionManager {
pub fn connections(&mut self) -> &mut Vec<Connections> { pub fn connections(&mut self) -> &mut Vec<Connections> {
&mut self.connections &mut self.connections
} }
pub fn connections_imut(&self) -> &Vec<Connections> {
&self.connections
}
} }

View File

@@ -5,7 +5,7 @@ use std::{
}; };
pub fn read_file(path: &Path) -> String { pub fn read_file(path: &Path) -> String {
let path = dirs::home_dir().unwrap().join(".ssh/Server"); // let path = dirs::home_dir().unwrap().join(".ssh/Server");
let mut file = File::open(path).unwrap(); let mut file = File::open(path).unwrap();
let mut content = String::new(); let mut content = String::new();
file.read_to_string(&mut content).unwrap(); file.read_to_string(&mut content).unwrap();

View File

@@ -6,13 +6,15 @@ use ratatui::{
Frame, Frame,
}; };
use crate::app::AppState;
pub mod component; pub mod component;
pub mod home; pub mod home;
pub mod setting; pub mod setting;
pub trait View { pub trait View {
fn draw(&self, frame: &mut Frame); fn draw(&mut self, frame: &mut Frame, ctx: &AppState);
fn handle_event(&mut self, event: &Event) -> io::Result<()>; fn handle_event(&mut self, event: &Event, ctx: &mut AppState) -> io::Result<()>;
} }
pub trait PopupView { pub trait PopupView {

View File

@@ -26,8 +26,8 @@ pub struct ListComponent {
} }
impl ListComponent { impl ListComponent {
pub fn add_item(&mut self, _item_keys: Vec<String>) { pub fn add_item(&mut self, item_keys: Vec<String>) {
self.item_keys.extend(vec!["S".to_string()]); self.item_keys = item_keys;
} }
pub fn name(mut self, name: String) -> Self { pub fn name(mut self, name: String) -> Self {
self.name = name; self.name = name;
@@ -43,7 +43,7 @@ impl Default for ListComponent {
fn default() -> Self { fn default() -> Self {
ListComponent { ListComponent {
name: String::default(), name: String::default(),
item_keys: vec!["1".to_string(), "2".to_string(), "3".to_string()], item_keys: vec![],
cursor: 0, cursor: 0,
selectable: false, selectable: false,
active_state: Default::default(), active_state: Default::default(),

View File

@@ -1,4 +1,4 @@
use std::io; use std::{io, string};
use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind};
use ratatui::{ use ratatui::{
@@ -7,6 +7,9 @@ use ratatui::{
widgets::{Block, BorderType, Borders}, widgets::{Block, BorderType, Borders},
Frame, Frame,
}; };
use serde::Serialize;
use crate::{app::AppState, session::connection::{Connection, Connections, ShConnection}};
use super::{ use super::{
component::{ component::{
@@ -44,7 +47,7 @@ impl Default for Home {
} }
impl View for Home { impl View for Home {
fn draw(&self, frame: &mut Frame) { fn draw(&mut self, frame: &mut Frame, ctx: &AppState) {
let layout = Layout::default() let layout = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.constraints(vec![ .constraints(vec![
@@ -54,26 +57,42 @@ impl View for Home {
]) ])
.split(frame.area()); .split(frame.area());
self.input.show_cursor(frame, layout[0]); self.input.show_cursor(frame, layout[0]);
let conn_names: Vec<_> = ctx
.connection_manager
.connections_imut()
.iter()
.map(|conn| match conn {
Connections::Sh(sh) => sh.name.clone(),
Connections::Ssh(ssh) => ssh.name.clone(),
})
.collect();
self.table.add_item(conn_names);
frame.render_widget(self.input.widget(), layout[0]); frame.render_widget(self.input.widget(), layout[0]);
frame.render_widget(self.table.widget(), layout[1]); frame.render_widget(self.table.widget(), layout[1]);
frame.render_widget(self.help.widget(), layout[2]); frame.render_widget(self.help.widget(), layout[2]);
self.setting.draw(frame); self.setting.draw(frame, ctx);
} }
fn handle_event(&mut self, event: &Event) -> io::Result<()> { fn handle_event(&mut self, event: &Event, ctx: &mut AppState) -> io::Result<()> {
match self.input.event_handler(event) { match self.input.event_handler(event) {
Ok(InputEvent::None) => {} Ok(InputEvent::None) => {}
_ => {} _ => {}
} }
match self.table.event_handler(event) { match self.table.event_handler(event) {
Ok(ListEvent::Select(i)) => { Ok(ListEvent::Select(i)) => {
let active_state = self.setting.active_state().is_active(); let conn = &ctx.connection_manager.connections()[i];
self.setting.active_state().set_active(active_state); match &conn {
println!("{}", i); &Connections::Sh(sh) => {
sh.exec_cmd();
},
&Connections::Ssh(ssh) => {
println!("{:?}", toml::to_string_pretty(&ctx.credential_manager));
},
};
} }
_ => {} _ => {}
} }
self.setting.handle_event(event)?; // self.setting.handle_event(event)?;
Ok(()) Ok(())
} }
} }

View File

@@ -5,6 +5,8 @@ use ratatui::{
widgets::{Block, Clear}, widgets::{Block, Clear},
}; };
use crate::app::AppState;
use super::{ use super::{
center_rect, center_rect,
component::{ component::{
@@ -36,7 +38,7 @@ impl Default for SettingView {
} }
impl View for SettingView { impl View for SettingView {
fn draw(&self, frame: &mut ratatui::Frame) { fn draw(&mut self, frame: &mut ratatui::Frame, ctx: &AppState) {
if !self.activate_state.is_active() { if !self.activate_state.is_active() {
return; return;
} }
@@ -47,7 +49,11 @@ impl View for SettingView {
frame.render_widget(self.menu.widget(), layout[0]); frame.render_widget(self.menu.widget(), layout[0]);
} }
fn handle_event(&mut self, event: &crossterm::event::Event) -> io::Result<()> { fn handle_event(
&mut self,
event: &crossterm::event::Event,
ctx: &mut AppState,
) -> io::Result<()> {
match self.menu.event_handler(event) { match self.menu.event_handler(event) {
Ok(ListEvent::Select(idx)) => { Ok(ListEvent::Select(idx)) => {
self.activate_state.set_active(false); self.activate_state.set_active(false);