working ratatui frontend

This commit is contained in:
filipriec
2025-02-16 20:35:57 +01:00
parent 598db07f16
commit ffa8931f62
18 changed files with 871 additions and 42 deletions

4
src/adresar/handlers.rs Normal file
View File

@@ -0,0 +1,4 @@
// src/adresar/handlers.rs
pub mod create_adresar;
pub use create_adresar::create_adresar;

View File

@@ -0,0 +1,57 @@
// src/adresar/handlers/create_adresar.rs
use tonic::{Request, Response, Status};
use sqlx::PgPool;
use crate::adresar::models::Adresar;
use crate::proto::multieko2::{AdresarRequest, AdresarResponse};
pub async fn create_adresar(
db_pool: &PgPool,
request: AdresarRequest,
) -> Result<AdresarResponse, Status> {
let adresar = sqlx::query_as!(
Adresar,
r#"
INSERT INTO adresar (
firma, kz, drc, ulica, psc, mesto, stat, banka, ucet, skladm, ico, kontakt, telefon, skladu, fax
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
RETURNING id, firma, kz, drc, ulica, psc, mesto, stat, banka, ucet, skladm, ico, kontakt, telefon, skladu, fax
"#,
request.firma,
request.kz,
request.drc,
request.ulica,
request.psc,
request.mesto,
request.stat,
request.banka,
request.ucet,
request.skladm,
request.ico,
request.kontakt,
request.telefon,
request.skladu,
request.fax
)
.fetch_one(db_pool)
.await
.map_err(|e| Status::internal(e.to_string()))?;
Ok(AdresarResponse {
id: adresar.id,
firma: adresar.firma,
kz: adresar.kz.unwrap_or_default(),
drc: adresar.drc.unwrap_or_default(),
ulica: adresar.ulica.unwrap_or_default(),
psc: adresar.psc.unwrap_or_default(),
mesto: adresar.mesto.unwrap_or_default(),
stat: adresar.stat.unwrap_or_default(),
banka: adresar.banka.unwrap_or_default(),
ucet: adresar.ucet.unwrap_or_default(),
skladm: adresar.skladm.unwrap_or_default(),
ico: adresar.ico.unwrap_or_default(),
kontakt: adresar.kontakt.unwrap_or_default(),
telefon: adresar.telefon.unwrap_or_default(),
skladu: adresar.skladu.unwrap_or_default(),
fax: adresar.fax.unwrap_or_default(),
})
}

4
src/adresar/mod.rs Normal file
View File

@@ -0,0 +1,4 @@
// src/adresar/mod.rs
pub mod models;
pub mod handlers;

22
src/adresar/models.rs Normal file
View File

@@ -0,0 +1,22 @@
// src/adresar/models.rs
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Adresar {
pub id: i64,
pub firma: String,
pub kz: Option<String>,
pub drc: Option<String>,
pub ulica: Option<String>,
pub psc: Option<String>,
pub mesto: Option<String>,
pub stat: Option<String>,
pub banka: Option<String>,
pub ucet: Option<String>,
pub skladm: Option<String>,
pub ico: Option<String>,
pub kontakt: Option<String>,
pub telefon: Option<String>,
pub skladu: Option<String>,
pub fax: Option<String>,
}

View File

@@ -1,18 +1,177 @@
// src/client/mod.rs
use tonic::transport::Channel;
use crate::proto::multieko2::data_processor_client::DataProcessorClient;
use crate::proto::multieko2::DataRequest;
use ratatui::{
backend::CrosstermBackend,
widgets::{Block, Borders, Paragraph},
layout::{Layout, Constraint, Direction},
Terminal,
style::{Style, Color},
Frame,
};
use crossterm::{
event::{self, Event, KeyCode},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::io;
use crate::proto::multieko2::{
AdresarRequest,
adresar_client::AdresarClient,
};
pub async fn run_client() -> Result<(), Box<dyn std::error::Error>> {
let mut client = DataProcessorClient::connect("http://[::1]:50051").await?;
// Setup terminal
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let request = tonic::Request::new(DataRequest {
data: "hello world".to_string(),
let mut client = AdresarClient::connect("http://[::1]:50051").await?;
let mut firma = String::new();
let mut kz = String::new();
let mut drc = String::new();
let mut ulica = String::new();
let mut psc = String::new();
let mut mesto = String::new();
let mut stat = String::new();
let mut banka = String::new();
let mut ucet = String::new();
let mut skladm = String::new();
let mut ico = String::new();
let mut kontakt = String::new();
let mut telefon = String::new();
let mut skladu = String::new();
let mut fax = String::new();
let mut current_field = 0;
let fields = vec!["Firma", "KZ", "DRC", "Ulica", "PSC", "Mesto", "Stat", "Banka", "Ucet", "Skladm", "ICO", "Kontakt", "Telefon", "Skladu", "Fax"];
loop {
terminal.draw(|f| {
ui(f, &fields, &mut current_field, &[
&firma, &kz, &drc, &ulica, &psc, &mesto, &stat, &banka, &ucet, &skladm, &ico, &kontakt, &telefon, &skladu, &fax,
]);
})?;
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char(c) => {
match current_field {
0 => firma.push(c),
1 => kz.push(c),
2 => drc.push(c),
3 => ulica.push(c),
4 => psc.push(c),
5 => mesto.push(c),
6 => stat.push(c),
7 => banka.push(c),
8 => ucet.push(c),
9 => skladm.push(c),
10 => ico.push(c),
11 => kontakt.push(c),
12 => telefon.push(c),
13 => skladu.push(c),
14 => fax.push(c),
_ => (),
}
}
KeyCode::Backspace => {
match current_field {
0 => firma.pop(),
1 => kz.pop(),
2 => drc.pop(),
3 => ulica.pop(),
4 => psc.pop(),
5 => mesto.pop(),
6 => stat.pop(),
7 => banka.pop(),
8 => ucet.pop(),
9 => skladm.pop(),
10 => ico.pop(),
11 => kontakt.pop(),
12 => telefon.pop(),
13 => skladu.pop(),
14 => fax.pop(),
_ => None,
};
}
KeyCode::Down => {
if current_field < fields.len() - 1 {
current_field += 1;
}
}
KeyCode::Up => {
if current_field > 0 {
current_field -= 1;
}
}
KeyCode::Enter => {
if current_field == fields.len() - 1 {
break;
} else {
current_field += 1;
}
}
_ => {}
}
}
}
// Cleanup terminal
disable_raw_mode()?;
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
let request = tonic::Request::new(AdresarRequest {
firma,
kz,
drc,
ulica,
psc,
mesto,
stat,
banka,
ucet,
skladm,
ico,
kontakt,
telefon,
skladu,
fax,
});
let response = client.process_data(request).await?;
println!("RESPONSE={:?}", response.into_inner().processed_data);
let response = client.create_adresar(request).await?;
println!("Adresar created: {:?}", response.into_inner());
Ok(())
}
fn ui(
f: &mut Frame,
fields: &[&str],
current_field: &mut usize,
inputs: &[&String],
) {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints::<&[Constraint]>(
&fields
.iter()
.map(|_| Constraint::Length(3))
.collect::<Vec<Constraint>>(),
)
.split(f.area());
for (i, field) in fields.iter().enumerate() {
let input = inputs[i].clone();
let paragraph = Paragraph::new(input)
.block(Block::default().borders(Borders::ALL).title(*field))
.style(if i == *current_field {
Style::default().fg(Color::Yellow)
} else {
Style::default()
});
f.render_widget(paragraph, chunks[i]);
}
}

View File

@@ -3,3 +3,4 @@ pub mod db;
pub mod client;
pub mod server;
pub mod proto;
pub mod adresar;

View File

@@ -1,49 +1,35 @@
// src/server/mod.rs
use tonic::{Request, Response, Status};
use crate::db;
use crate::adresar::handlers::create_adresar;
use crate::proto::multieko2::{
data_processor_server::{DataProcessor, DataProcessorServer},
DataRequest, DataResponse
AdresarRequest, AdresarResponse,
adresar_server::{Adresar, AdresarServer},
};
pub struct DataProcessorService {
pub struct AdresarService {
db_pool: sqlx::PgPool,
}
#[tonic::async_trait]
impl DataProcessor for DataProcessorService {
async fn process_data(
impl Adresar for AdresarService {
async fn create_adresar(
&self,
request: Request<DataRequest>,
) -> Result<Response<DataResponse>, Status> {
let data = request.into_inner().data;
// Store data in database
let stored_data = sqlx::query!(
"INSERT INTO processed_data (content) VALUES ($1) RETURNING id",
data
)
.fetch_one(&self.db_pool)
.await
.map_err(|e| Status::internal(e.to_string()))?;
// Simple processing: convert to uppercase
let processed_data = data.to_uppercase();
Ok(Response::new(DataResponse {
processed_data: format!("Processed data with ID: {}", stored_data.id)
}))
request: Request<AdresarRequest>,
) -> Result<Response<AdresarResponse>, Status> {
let response = create_adresar(&self.db_pool, request.into_inner()).await?;
Ok(Response::new(response))
}
}
pub async fn run_server(db_pool: sqlx::PgPool) -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse()?;
let service = DataProcessorService { db_pool };
let adresar_service = AdresarService { db_pool: db_pool.clone() };
println!("Server listening on {}", addr);
tonic::transport::Server::builder()
.add_service(DataProcessorServer::new(service))
.add_service(AdresarServer::new(adresar_service))
.serve(addr)
.await?;