UI update - almost working

This commit is contained in:
djkato 2023-04-16 00:37:26 +02:00
parent de2504cdb1
commit f028064630
6 changed files with 225 additions and 177 deletions

View file

@ -1,5 +1,5 @@
use super::csv_handler::{DataEntry, ImportedData}; use super::csv_handler::{DataEntry, ImportedData};
use super::database_handler::{DBLoginData, QueryResult, Table, TableField, Tables}; use super::database_handler::{DBLoginData, QueryResult, Table, Tables};
use super::parser::parse; use super::parser::parse;
use sqlx::MySqlConnection; use sqlx::MySqlConnection;
use std::sync::Arc; use std::sync::Arc;
@ -55,6 +55,9 @@ impl BackendManger {
println!("{}", e); println!("{}", e);
} }
} }
let mut db_table_data = self.db_table_data.lock().await;
let mut csv_data = self.csv_data.lock().await;
try_match_headers_to_fields(&mut db_table_data, None, &mut csv_data)
} }
Communication::ImportDBEntries(usize) => { Communication::ImportDBEntries(usize) => {
todo!() todo!()
@ -72,45 +75,11 @@ impl BackendManger {
.describe_table(&mut self.db_connection.as_mut().unwrap()) .describe_table(&mut self.db_connection.as_mut().unwrap())
.await; .await;
match try_match_headers_to_fields( try_match_headers_to_fields(
&mut db_table_data, &mut db_table_data,
table_index, Some(table_index),
&csv_data.data.iter_row(0), &mut csv_data,
) {
Ok(_) => {
/* If some got automapped, try to parse them all */
for (col_index, field) in db_table_data
.tables
.get_mut(table_index)
.unwrap()
.fields
.as_mut()
.unwrap()
.iter_mut()
.enumerate()
{
println!(
" > automapping field \"{}\" to col \"{:?}\"",
&field.description.field, field.mapped_to_col
); );
if let Some(col_index) = field.mapped_to_col {
for cell in csv_data.data.iter_col_mut(col_index) {
cell.curr_field_description =
Some(field.description.clone());
parse(cell);
}
}
if is_whole_col_parsed(&mut csv_data, col_index) {
println!("col \"{}\" is parsed whole!", &col_index);
csv_data.parsed_cols.push(col_index);
}
if is_whole_table_parsed(&csv_data) {
csv_data.is_parsed = true;
}
}
}
Err(_) => (),
}
} }
Communication::RemoveRow(usize) => { Communication::RemoveRow(usize) => {
todo!() todo!()
@ -127,7 +96,7 @@ impl BackendManger {
} }
if is_whole_col_parsed(&mut csv_data, col_index) { if is_whole_col_parsed(&mut csv_data, col_index) {
println!("col \"{}\" is parsed whole!", &col_index); println!("col \"{}\" is parsed whole!", &col_index);
csv_data.parsed_cols.push(col_index - 1); csv_data.parsed_cols.push(col_index);
} }
if is_whole_table_parsed(&csv_data) { if is_whole_table_parsed(&csv_data) {
csv_data.is_parsed = true; csv_data.is_parsed = true;
@ -198,27 +167,32 @@ pub fn is_whole_col_parsed(csv_data: &mut MutexGuard<ImportedData>, col_index: u
match parse { match parse {
Ok(_) => return true, Ok(_) => return true,
Err(_) => { Err(_) => {
println!(
"Cel \"{}\" in Col \"{}\" isnt parsed :(",
cel.data, col_index
);
return false; return false;
} }
} }
} else { } else {
println!(
"Cel \"{}\" in Col \"{}\" isnt parsed :(",
cel.data, col_index
);
false false
} }
}) })
} }
pub fn try_match_headers_to_fields( pub fn try_match_headers_to_fields(
tables: &mut MutexGuard<Tables>, tables: &mut MutexGuard<Tables>,
table_index: usize, table_index: Option<usize>,
csv_headers: &std::slice::Iter<'_, DataEntry>, csv_data: &mut MutexGuard<ImportedData>,
) -> Result<(), ()> { ) {
if !csv_data.are_headers || csv_data.data.is_empty() {
return;
}
let final_table_index: usize;
if let Some(i) = table_index {
final_table_index = i;
} else if let Some(cw_table_i) = tables.current_working_table {
final_table_index = cw_table_i;
} else {
return;
}
let table_index = final_table_index;
let db_fields = tables let db_fields = tables
.tables .tables
.get_mut(table_index) .get_mut(table_index)
@ -228,19 +202,49 @@ pub fn try_match_headers_to_fields(
.unwrap(); .unwrap();
let mut has_matched_some = false; let mut has_matched_some = false;
for field in db_fields { for field in db_fields {
for (i, header) in csv_headers.clone().enumerate() { for (i, header) in csv_data.data.iter_row(0).into_iter().enumerate() {
if &field.description.field == &header.data { if &field.description.field == &header.data {
field.mapped_to_col = Some(i); field.mapped_to_col = Some(i);
has_matched_some = true; has_matched_some = true;
} }
} }
} }
match has_matched_some {
true => return Ok(()), if has_matched_some == false
false => return Err(()), || tables.current_working_table.is_none()
|| tables.tables.is_empty()
{
return;
}
/* If some got automapped, try to parse them all */
if let Some(table_i) = tables.current_working_table {
if let Some(table) = tables.tables.get_mut(table_i) {
if let Some(fields) = table.fields.as_mut() {
for (col_index, field) in fields.iter().enumerate() {
println!(
" > automapping field \"{}\" to col \"{:?}\"",
&field.description.field, field.mapped_to_col
);
if let Some(col_index) = field.mapped_to_col {
for cell in csv_data.data.iter_mut() {
cell.curr_field_description = Some(field.description.clone());
parse(cell);
}
}
if is_whole_col_parsed(csv_data, col_index) {
println!("col \"{}\" is parsed whole!", &col_index);
csv_data.parsed_cols.push(col_index);
}
if is_whole_table_parsed(&csv_data) {
csv_data.is_parsed = true;
}
}
}
}
} }
} }
#[derive(Debug)]
pub enum Communication { pub enum Communication {
ValidateCreditentials( ValidateCreditentials(
DBLoginData, DBLoginData,

View file

@ -1,3 +1,5 @@
#![cfg_attr(not(debug_assertions), deny(dead_code), deny(unused_variables))]
#![cfg_attr(debug_assertions, allow(dead_code), allow(unused_variables))]
mod backend; mod backend;
mod ui; mod ui;
use backend::backend_manager::BackendManger; use backend::backend_manager::BackendManger;

View file

@ -37,7 +37,7 @@ impl CSQLWindow for DBLoginWindow {
ctx: &egui::Context, ctx: &egui::Context,
_ui: &mut egui::Ui, _ui: &mut egui::Ui,
_frame: &mut eframe::Frame, _frame: &mut eframe::Frame,
) -> Option<ExitStatus> { ) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>> {
egui::Window::new("MySQL Login") egui::Window::new("MySQL Login")
.id(egui::Id::new("MySQL Login")) .id(egui::Id::new("MySQL Login"))
.resizable(false) .resizable(false)
@ -51,13 +51,11 @@ impl CSQLWindow for DBLoginWindow {
}); });
if let Some(result) = &self.are_creditentials_verified { if let Some(result) = &self.are_creditentials_verified {
match result { match result {
Ok(_) => return Some(ExitStatus::Ok), Ok(_) => return Some(Ok(ExitStatus::Ok)),
Err(e) => { Err(e) => {
return Some(ExitStatus::Err(Box::from(<String as Into< return Some(Err(Box::from(<String as Into<
Box<dyn std::error::Error>, Box<dyn std::error::Error>,
>>::into( >>::into(e.to_string()))))
e.to_string()
))))
} }
} }
} else { } else {

View file

@ -1,6 +1,4 @@
use egui::{Context, Ui}; use egui::{Context, Ui};
use sqlx::mysql::MySqlQueryResult;
use std::error::Error;
use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::sync::oneshot; use tokio::sync::oneshot;
@ -42,7 +40,7 @@ impl CSQLWindow for DBTransactionWindow {
ctx: &Context, ctx: &Context,
ui: &mut Ui, ui: &mut Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
) -> Option<ExitStatus> { ) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>> {
egui::Window::new("Database Transactions") egui::Window::new("Database Transactions")
.id(egui::Id::new("Database Transactions")) .id(egui::Id::new("Database Transactions"))
.resizable(false) .resizable(false)
@ -62,7 +60,7 @@ impl CSQLWindow for DBTransactionWindow {
}); });
if self.is_finished { if self.is_finished {
return Some(ExitStatus::Ok); return Some(Ok(ExitStatus::Ok));
} }
None None
} }
@ -129,7 +127,7 @@ impl DBTransactionWindow {
.auto_shrink([false; 2]) .auto_shrink([false; 2])
.stick_to_bottom(true) .stick_to_bottom(true)
.show(ui, |ui| { .show(ui, |ui| {
let mut table = egui_extras::TableBuilder::new(ui) let table = egui_extras::TableBuilder::new(ui)
.striped(true) .striped(true)
.resizable(true) .resizable(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::LEFT)) .cell_layout(egui::Layout::left_to_right(egui::Align::LEFT))
@ -155,7 +153,7 @@ impl DBTransactionWindow {
ui.strong("Result"); ui.strong("Result");
}); });
}) })
.body(|mut body| { .body(|body| {
body.rows(15.0, self.log_history.len(), |row_index, mut row| { body.rows(15.0, self.log_history.len(), |row_index, mut row| {
let log = self.log_history.get(row_index).unwrap(); let log = self.log_history.get(row_index).unwrap();
row.col(|ui| { row.col(|ui| {
@ -187,6 +185,6 @@ impl DBTransactionWindow {
} }
pub struct OptionsDBTransactionWindow { pub struct OptionsDBTransactionWindow {
substitute_zero_dates_for_NULL: bool, substitute_zero_dates_for_null: bool,
remove_id_field_from_insert: bool, remove_id_field_from_insert: bool,
} }

View file

@ -13,8 +13,9 @@ pub struct SpreadSheetWindow {
csv_data_handle: Arc<Mutex<ImportedData>>, csv_data_handle: Arc<Mutex<ImportedData>>,
db_table_data_handle: Arc<Mutex<Tables>>, db_table_data_handle: Arc<Mutex<Tables>>,
current_table: Option<usize>, current_table: Option<usize>,
should_export_to_db: bool, return_status: Option<ExitStatus>,
debug_autoload_file_sent: bool, debug_autoload_file_sent: bool,
is_table_description_request_sent: bool,
} }
impl SpreadSheetWindow { impl SpreadSheetWindow {
pub fn default( pub fn default(
@ -29,7 +30,8 @@ impl SpreadSheetWindow {
db_table_data_handle, db_table_data_handle,
current_table: None, current_table: None,
debug_autoload_file_sent: false, debug_autoload_file_sent: false,
should_export_to_db: false, is_table_description_request_sent: false,
return_status: None,
} }
} }
} }
@ -39,11 +41,11 @@ impl CSQLWindow for SpreadSheetWindow {
ctx: &egui::Context, ctx: &egui::Context,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
) -> Option<ExitStatus> { ) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>> {
self.ui(ui, ctx); self.ui(ui, ctx);
if self.should_export_to_db { if let Some(return_status) = self.return_status {
self.should_export_to_db = false; self.return_status = None;
return Some(ExitStatus::StartTransactionWindow); return Some(Ok(return_status));
} }
None None
} }
@ -57,15 +59,18 @@ impl SpreadSheetWindow {
} else { } else {
is_csv_parsed = false; is_csv_parsed = false;
} }
/* Program Menu */ /* Program Menu */
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.group(|ui| {}); if ui.button("Log into DB").clicked() {
self.return_status = Some(ExitStatus::StartLoginWindow);
}
ui.add_space(ui.available_width());
}); });
ui.separator();
/* CSV & DB menu */ /* CSV & DB menu */
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.columns(2, |uis| { ui.columns(2, |uis| {
uis[0].group(|ui| { uis[0].horizontal(|ui| {
if ui.button("Import file").clicked() { if ui.button("Import file").clicked() {
self.open_file(); self.open_file();
} }
@ -75,22 +80,24 @@ impl SpreadSheetWindow {
if ui.button("Save as...").clicked() { if ui.button("Save as...").clicked() {
self.save_file(); self.save_file();
} }
ui.add_space(ui.available_width());
ui.separator();
}); });
uis[1].group(|ui| { uis[1].with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
self.table_options(ui);
if ui.button("Import DB").clicked() {
todo!();
}
ui.add_enabled_ui(is_csv_parsed, |ui| { ui.add_enabled_ui(is_csv_parsed, |ui| {
if ui.button("Save to DB").clicked() {
self.should_export_to_db = true;
}
if ui.button("Append to DB").clicked() { if ui.button("Append to DB").clicked() {
todo!(); todo!();
} }
if ui.button("Save to DB").clicked() {
self.return_status = Some(ExitStatus::StartTransactionWindow);
}
}); });
}); if ui.button("Import DB").clicked() {
todo!();
}
self.table_options(ui);
ui.add_space(ui.available_width());
}); });
}) })
}); });
@ -103,10 +110,11 @@ impl SpreadSheetWindow {
}); });
SpreadSheetWindow::preview_files_being_dropped(ctx); SpreadSheetWindow::preview_files_being_dropped(ctx);
if self.current_table.is_none() { if self.current_table.is_some() {
ui.group(|ui| { ui.group(|ui| {
egui::ScrollArea::horizontal().show(ui, |ui| { egui::ScrollArea::horizontal().show(ui, |ui| {
self.table_builder(ui); self.table_builder(ui)
.unwrap_or_else(|e| println!("Table un-intd, {:?}", e));
}); });
}); });
} }
@ -142,45 +150,62 @@ impl SpreadSheetWindow {
}); });
} }
} }
fn table_builder(&mut self, ui: &mut Ui) { fn table_builder(&mut self, ui: &mut Ui) -> Result<(), Box<dyn std::error::Error>> {
if let Ok(csv_data) = &mut self.csv_data_handle.try_lock() { if let Ok(csv_data) = &mut self.csv_data_handle.try_lock() {
if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() { if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() {
//ref to all fields in curr db table //ref to all fields in curr db table
let mut curr_db_table_fields: &mut Vec<TableField> = db_table_data let mut curr_db_table_fields: &mut Vec<TableField> = match db_table_data
.tables .tables
.get_mut(self.current_table.unwrap()) .get_mut(self.current_table.unwrap())
.unwrap() .ok_or("no current table")?
.fields .fields
.as_mut() .as_mut()
.unwrap(); .ok_or("no fields yet")
let mut table = TableBuilder::new(ui) {
.striped(true) Ok(val) => val,
.cell_layout(egui::Layout::left_to_right(egui::Align::Center)); Err(e) => {
if !self.is_table_description_request_sent {
for _i in 0..csv_data.data.cols() + 1 { self.sender.try_send(Communication::GetTableDescription(
table = table.column(Column::auto().resizable(true).clip(false)); self.current_table.unwrap(),
))?;
self.is_table_description_request_sent = true;
} }
/* If cols got prematched by name */ return Err(Box::from(
<String as Into<Box<dyn std::error::Error>>>::into(e.to_string()),
));
}
};
if csv_data.data.is_empty() {
return Err(<String as Into<Box<dyn std::error::Error>>>::into(
"no rows yet".to_string(),
));
}
let table = TableBuilder::new(ui)
.striped(true)
.cell_layout(egui::Layout::left_to_right(egui::Align::Center))
/*First collumn for row actions */
.column(Column::auto().at_most(30.0).resizable(false).clip(false));
table table
.column(Column::remainder()) .columns(
Column::auto().resizable(true).clip(false),
csv_data.data.cols(),
)
.min_scrolled_height(0.0) .min_scrolled_height(0.0)
.header(20., |mut header| { .header(20., |mut header| {
/* First Col for row mutators */ /* First Col for row mutators */
header.col(|ui|{ header.col(|ui|{
ui.add_space(45.0);
}); });
SpreadSheetWindow::add_header_cols(&mut header, csv_data,&mut curr_db_table_fields, &mut self.sender);
for i in 0..csv_data.data.cols() {
header.col(|ui| {
SpreadSheetWindow::add_header_col(ui,i, csv_data,&mut curr_db_table_fields, &mut self.sender);
});
}
}) })
.body(|body| { .body(|body| {
body.rows(15., csv_data.data.rows() -1, |row_index, mut row| { body.rows(15., csv_data.data.rows() - csv_data.are_headers as usize, |row_index, mut row| {
let headers_i_offset = csv_data.are_headers as usize;
row.col(|ui|{
if ui.button("x").clicked(){}
});
for curr_cell in for curr_cell in
csv_data.data.iter_row_mut(row_index+1) csv_data.data.iter_row_mut(row_index + headers_i_offset)
{ {
/* If cell is bound to a field, color it's bg according to is_parsed */ /* If cell is bound to a field, color it's bg according to is_parsed */
row.col(|ui| { row.col(|ui| {
@ -214,21 +239,21 @@ impl SpreadSheetWindow {
} else { } else {
ui.centered_and_justified(|ui| ui.heading("Drag and drop or Open a file...")); ui.centered_and_justified(|ui| ui.heading("Drag and drop or Open a file..."));
} }
Ok(())
} }
} }
impl SpreadSheetWindow { impl SpreadSheetWindow {
pub fn add_header_col( pub fn add_header_cols(
ui: &mut Ui, header: &mut egui_extras::TableRow,
i: usize,
csv_data: &mut MutexGuard<ImportedData>, csv_data: &mut MutexGuard<ImportedData>,
curr_db_table_fields: &mut Vec<TableField>, curr_db_table_fields: &mut Vec<TableField>,
sender: &mut Sender<Communication>, sender: &mut Sender<Communication>,
) { ) {
for i in 0..csv_data.data.cols() {
header.col(|ui| {
ui.vertical_centered_justified(|ui| { ui.vertical_centered_justified(|ui| {
if ui.button("x").clicked() { if ui.button("x").clicked() {}
todo!()
}
if csv_data.parsed_cols.contains(&i) { if csv_data.parsed_cols.contains(&i) {
/* If the whole col is parsed, change header bg to green, else normal */ /* If the whole col is parsed, change header bg to green, else normal */
ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN); ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN);
@ -247,7 +272,8 @@ impl SpreadSheetWindow {
.iter() .iter()
.find(|field| field.mapped_to_col == Some(i)) .find(|field| field.mapped_to_col == Some(i))
{ {
combo_box = combo_box.selected_text(selected_field.description.field.clone()); combo_box =
combo_box.selected_text(selected_field.description.field.clone());
} else { } else {
combo_box = combo_box.selected_text("-----"); combo_box = combo_box.selected_text("-----");
} }
@ -266,7 +292,8 @@ impl SpreadSheetWindow {
match sender.try_send(Communication::TryParseCol(i)) { match sender.try_send(Communication::TryParseCol(i)) {
Ok(_) => { Ok(_) => {
for cel in csv_data.data.iter_col_mut(i) { for cel in csv_data.data.iter_col_mut(i) {
cel.curr_field_description = Some(field.description.clone()); cel.curr_field_description =
Some(field.description.clone());
} }
} }
Err(e) => println!("failed sending parsecol request, {}", e), Err(e) => println!("failed sending parsecol request, {}", e),
@ -276,6 +303,8 @@ impl SpreadSheetWindow {
}); });
ui.reset_style(); ui.reset_style();
}); });
});
}
} }
pub fn save_file(&mut self) { pub fn save_file(&mut self) {
@ -296,19 +325,24 @@ impl SpreadSheetWindow {
} }
pub fn open_file(&mut self) { pub fn open_file(&mut self) {
let final_path;
/*preloads file in debug */ /*preloads file in debug */
if cfg!(debug_assertions) && !self.debug_autoload_file_sent { if cfg!(debug_assertions) && !self.debug_autoload_file_sent {
let path = std::path::PathBuf::from("/home/djkato/Dokumenty/csql/oc_product.csv"); final_path = std::path::PathBuf::from("/home/djkato/Dokumenty/csql/oc_product.csv");
println!(" * Preloading \"{:?}\"...", path); println!(" * Preloading \"{:?}\"...", final_path);
self.debug_autoload_file_sent = true; self.debug_autoload_file_sent = true;
} } else {
if let Some(path) = rfd::FileDialog::new() if let Some(path) = rfd::FileDialog::new()
.add_filter("Spreadsheets", &["csv"]) .add_filter("Spreadsheets", &["csv"])
.pick_file() .pick_file()
{ {
final_path = path;
} else {
return;
}
self.sender self.sender
.try_send(Communication::LoadImportFilePath( .try_send(Communication::LoadImportFilePath(
path.display().to_string(), final_path.display().to_string(),
)) ))
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err)); .unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
} }

View file

@ -5,12 +5,10 @@ use crate::ui::db_login_window::DBLoginWindow;
use crate::ui::table_window::SpreadSheetWindow; use crate::ui::table_window::SpreadSheetWindow;
use eframe::{run_native, App, NativeOptions}; use eframe::{run_native, App, NativeOptions};
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::mpsc::{channel, Sender};
use tokio::sync::oneshot;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use super::db_transaction_window::DBTransactionWindow; use super::db_transaction_window::DBTransactionWindow;
use super::{db_login_window, db_transaction_window};
pub fn create_ui( pub fn create_ui(
sender: Sender<Communication>, sender: Sender<Communication>,
@ -61,8 +59,11 @@ impl App for CSQL {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
if let Some(result) = self.spreadsheet_window.refresh(ctx, ui, frame) { if let Some(result) = self.spreadsheet_window.refresh(ctx, ui, frame) {
match result { match result {
Ok(status) => match status {
ExitStatus::StartLoginWindow => self.should_open_transaction_window = true, ExitStatus::StartLoginWindow => self.should_open_transaction_window = true,
ExitStatus::StartTransactionWindow => self.should_open_login_window = true, ExitStatus::StartTransactionWindow => self.should_open_login_window = true,
_ => {}
},
_ => (), _ => (),
} }
}; };
@ -71,26 +72,37 @@ impl App for CSQL {
if let Some(db_login_window) = self.db_login_window.as_mut() { if let Some(db_login_window) = self.db_login_window.as_mut() {
if let Some(result) = db_login_window.refresh(ctx, ui, frame) { if let Some(result) = db_login_window.refresh(ctx, ui, frame) {
match result { match result {
ExitStatus::Ok => { Ok(status) => {
self.db_login_window = None; self.db_login_window = None;
self.should_open_login_window = false; self.should_open_login_window = false;
} }
_ => (), _ => (),
} }
} }
} else {
self.db_login_window = Some(DBLoginWindow::default(self.sender.clone()));
} }
} }
if self.should_open_transaction_window { if self.should_open_transaction_window {
if let Some(db_transaction_window) = self.db_transaction_window.as_mut() { if let Some(db_transaction_window) = self.db_transaction_window.as_mut() {
if let Some(result) = db_transaction_window.refresh(ctx, ui, frame) { if let Some(result) = db_transaction_window.refresh(ctx, ui, frame) {
match result { match result {
ExitStatus::Ok => { Ok(status) => {
self.db_transaction_window = None; self.db_transaction_window = None;
self.should_open_transaction_window = false; self.should_open_transaction_window = false;
} }
_ => (), _ => (),
} }
} }
} else {
if let Ok(db_table_data) = self.db_table_data_handle.try_lock() {
if let Some(cw_table_i) = db_table_data.current_working_table {
self.db_transaction_window = Some(DBTransactionWindow::default(
self.sender.clone(),
cw_table_i,
))
}
}
} }
} }
}); });
@ -103,11 +115,11 @@ pub trait CSQLWindow {
ctx: &egui::Context, ctx: &egui::Context,
ui: &mut egui::Ui, ui: &mut egui::Ui,
frame: &mut eframe::Frame, frame: &mut eframe::Frame,
) -> Option<ExitStatus>; ) -> Option<Result<ExitStatus, Box<dyn std::error::Error>>>;
} }
#[derive(Clone, Copy)]
pub enum ExitStatus { pub enum ExitStatus {
StartTransactionWindow, StartTransactionWindow,
StartLoginWindow, StartLoginWindow,
Ok, Ok,
Err(Box<dyn std::error::Error>),
} }