window system rewrite
This commit is contained in:
parent
62fa057daf
commit
de2504cdb1
6 changed files with 458 additions and 374 deletions
|
@ -1,9 +1,7 @@
|
|||
use super::csv_handler::{DataEntry, ImportedData};
|
||||
use super::database_handler::{DBLoginData, QueryResult, Table, TableField, Tables};
|
||||
use super::parser::parse;
|
||||
use sqlx::mysql::MySqlQueryResult;
|
||||
use sqlx::MySqlConnection;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
use tokio::sync::{oneshot, Mutex, MutexGuard};
|
||||
|
@ -43,12 +41,7 @@ impl BackendManger {
|
|||
}
|
||||
}
|
||||
}
|
||||
Communication::AreCreditentialsValidated(sender) => sender
|
||||
.send(self.db_login_data.is_verified)
|
||||
.unwrap_or_else(|e| {
|
||||
println!("Server - Failed answering if credit. validated");
|
||||
}),
|
||||
Communication::LoadImportFilePath(path, sender) => {
|
||||
Communication::LoadImportFilePath(path) => {
|
||||
self.imported_data.path = path;
|
||||
match self.imported_data.load_csv() {
|
||||
Ok(_) => {
|
||||
|
@ -57,21 +50,19 @@ impl BackendManger {
|
|||
data.are_headers = self.imported_data.are_headers.clone();
|
||||
data.data = self.imported_data.data.clone();
|
||||
data.path = self.imported_data.path.clone();
|
||||
|
||||
drop(data);
|
||||
sender.send(true).unwrap_or_else(|err| {
|
||||
println!("Server - failed to send loaded file callback, {}", err)
|
||||
})
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{}", e);
|
||||
sender.send(false).unwrap_or_else(|e| {
|
||||
println!("Server - Failed answering if imported{}", e)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
Communication::GetTableDescription(table_index, sender) => {
|
||||
Communication::ImportDBEntries(usize) => {
|
||||
todo!()
|
||||
}
|
||||
Communication::SaveCSV(path) => {
|
||||
todo!()
|
||||
}
|
||||
Communication::GetTableDescription(table_index) => {
|
||||
let mut db_table_data = self.db_table_data.lock().await;
|
||||
let mut csv_data = self.csv_data.lock().await;
|
||||
db_table_data
|
||||
|
@ -80,59 +71,53 @@ impl BackendManger {
|
|||
.unwrap()
|
||||
.describe_table(&mut self.db_connection.as_mut().unwrap())
|
||||
.await;
|
||||
if csv_data.are_headers {
|
||||
match try_match_headers_to_fields(
|
||||
&mut db_table_data,
|
||||
table_index,
|
||||
&csv_data.data.iter_row(0),
|
||||
) {
|
||||
Ok(_) => {
|
||||
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;
|
||||
|
||||
match try_match_headers_to_fields(
|
||||
&mut db_table_data,
|
||||
table_index,
|
||||
&csv_data.data.iter_row(0),
|
||||
) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
sender.send(true).unwrap_or_else(|e| {
|
||||
println!(
|
||||
"Server - failed to respond to getTableDescription, {}",
|
||||
e
|
||||
)
|
||||
});
|
||||
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(_) => sender.send(false).unwrap_or_else(|e| {
|
||||
println!("Server - failed to respond to getTableDescription, {}", e)
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
sender.send(false).unwrap_or_else(|e| {
|
||||
println!("Server - failed to respond to getTableDescription, {}", e)
|
||||
});
|
||||
Err(_) => (),
|
||||
}
|
||||
}
|
||||
Communication::RemoveRow(usize) => {
|
||||
todo!()
|
||||
}
|
||||
Communication::RemoveCol(usize) => {
|
||||
todo!()
|
||||
}
|
||||
Communication::TryParseCol(col_index) => {
|
||||
let mut csv_data = self.csv_data.lock().await;
|
||||
for cell in csv_data.data.iter_col_mut(col_index) {
|
||||
|
@ -261,9 +246,12 @@ pub enum Communication {
|
|||
DBLoginData,
|
||||
oneshot::Sender<Result<(), Box<dyn std::error::Error + Send>>>,
|
||||
),
|
||||
AreCreditentialsValidated(oneshot::Sender<bool>),
|
||||
LoadImportFilePath(String, oneshot::Sender<bool>),
|
||||
GetTableDescription(usize, oneshot::Sender<bool>),
|
||||
LoadImportFilePath(String),
|
||||
GetTableDescription(usize),
|
||||
ImportDBEntries(usize),
|
||||
RemoveCol(usize),
|
||||
RemoveRow(usize),
|
||||
SaveCSV(String),
|
||||
TryParseCol(usize),
|
||||
StartInserting(usize, Sender<QueryResult>, oneshot::Sender<bool>),
|
||||
TryCommit(oneshot::Sender<QueryResult>),
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use crate::backend::csv_handler::DataEntry;
|
||||
use core::num::ParseIntError;
|
||||
use eframe::glow::Query;
|
||||
use sqlx::mysql::MySqlQueryResult;
|
||||
use sqlx::{mysql::MySqlConnectOptions, ConnectOptions};
|
||||
use sqlx::{FromRow, MySqlConnection};
|
||||
use sqlx::{Executor, FromRow, MySqlConnection};
|
||||
use std::error::Error;
|
||||
use std::slice::Iter;
|
||||
#[derive(Default)]
|
||||
pub struct Tables {
|
||||
pub tables: Vec<Table>,
|
||||
pub current_working_table: Option<usize>,
|
||||
pub is_connection_verified: bool,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
|
@ -43,8 +43,10 @@ impl Tables {
|
|||
.fetch_all(connection)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut table_i = 0;
|
||||
for table in qr_tables {
|
||||
println!(" >Found table:{}. {}", &table_i, &table.tables_in_quotes);
|
||||
table_i += 1;
|
||||
self.tables.push({
|
||||
Table {
|
||||
name: table.tables_in_quotes,
|
||||
|
@ -59,23 +61,23 @@ impl Tables {
|
|||
|
||||
impl Table {
|
||||
pub async fn transaction_commit(connection: &mut MySqlConnection) -> QueryResult {
|
||||
match sqlx::query("COMMIT").execute(connection).await {
|
||||
match connection.execute("COMMIT").await {
|
||||
Ok(res) => {
|
||||
return QueryResult {
|
||||
query: "ROLLBACK".to_owned(),
|
||||
query: "COMMIT".to_owned(),
|
||||
result: Ok(res),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return QueryResult {
|
||||
query: "ROLLBACK".to_owned(),
|
||||
query: "COMMIT".to_owned(),
|
||||
result: Err(Box::new(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub async fn transaction_rollback(connection: &mut MySqlConnection) -> QueryResult {
|
||||
match sqlx::query("ROLLBACK").execute(connection).await {
|
||||
match connection.execute("ROLLBACK").await {
|
||||
Ok(res) => {
|
||||
return QueryResult {
|
||||
query: "ROLLBACK".to_owned(),
|
||||
|
@ -91,16 +93,24 @@ impl Table {
|
|||
}
|
||||
}
|
||||
pub async fn start_transaction(connection: &mut MySqlConnection) -> QueryResult {
|
||||
match sqlx::query("BEGIN").execute(connection).await {
|
||||
Ok(res) => {
|
||||
return QueryResult {
|
||||
query: "ROLLBACK".to_owned(),
|
||||
result: Ok(res),
|
||||
match connection.execute("SET autocommit = OFF").await {
|
||||
Ok(_) => match connection.execute("BEGIN").await {
|
||||
Ok(res) => {
|
||||
return QueryResult {
|
||||
query: "BEGIN".to_owned(),
|
||||
result: Ok(res),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return QueryResult {
|
||||
query: "BEGIN".to_owned(),
|
||||
result: Err(Box::new(e)),
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
return QueryResult {
|
||||
query: "ROLLBACK".to_owned(),
|
||||
query: "SET autocommit = OFF".to_owned(),
|
||||
result: Err(Box::new(e)),
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +137,7 @@ impl Table {
|
|||
row.1 + "\'" + next_row.data.as_str() + "\', ",
|
||||
)
|
||||
});
|
||||
/* remove last ", " from both */
|
||||
fields.0.pop();
|
||||
fields.0.pop();
|
||||
fields.1.pop();
|
||||
|
@ -187,7 +198,7 @@ pub struct QueryResult {
|
|||
pub result: Result<MySqlQueryResult, Box<dyn Error + Send>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct DBLoginData {
|
||||
pub user_name: String,
|
||||
pub database: String,
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use super::window_manager::{CSQLWindow, ExitStatus};
|
||||
use crate::backend::backend_manager::Communication;
|
||||
use crate::backend::database_handler::DBLoginData;
|
||||
use egui::{Context, Ui, Vec2};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
pub struct DBLoginWindow {
|
||||
db_login_data: DBLoginData,
|
||||
sender: Sender<Communication>,
|
||||
are_creditentials_verified_receiver:
|
||||
Option<oneshot::Receiver<Result<(), Box<dyn std::error::Error + Send>>>>,
|
||||
are_creditentials_verified_error: Option<Box<dyn std::error::Error + Send>>,
|
||||
are_creditentials_verified: Option<Result<(), Box<dyn std::error::Error + Send>>>,
|
||||
debug_autoconnect_sent: bool,
|
||||
}
|
||||
impl DBLoginWindow {
|
||||
pub fn default(sender: Sender<Communication>) -> DBLoginWindow {
|
||||
|
@ -25,23 +26,18 @@ impl DBLoginWindow {
|
|||
},
|
||||
sender,
|
||||
are_creditentials_verified_receiver: None,
|
||||
are_creditentials_verified_error: None,
|
||||
are_creditentials_verified: None,
|
||||
debug_autoconnect_sent: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DBLoginWindow {
|
||||
pub fn show(&mut self, ctx: &Context, ui: &mut Ui, is_db_connection_verified: bool) {
|
||||
let alignment: egui::Align2;
|
||||
|
||||
match is_db_connection_verified {
|
||||
true => {
|
||||
alignment = egui::Align2::CENTER_TOP;
|
||||
}
|
||||
false => {
|
||||
alignment = egui::Align2::CENTER_CENTER;
|
||||
}
|
||||
}
|
||||
|
||||
impl CSQLWindow for DBLoginWindow {
|
||||
fn refresh(
|
||||
&mut self,
|
||||
ctx: &egui::Context,
|
||||
_ui: &mut egui::Ui,
|
||||
_frame: &mut eframe::Frame,
|
||||
) -> Option<ExitStatus> {
|
||||
egui::Window::new("MySQL Login")
|
||||
.id(egui::Id::new("MySQL Login"))
|
||||
.resizable(false)
|
||||
|
@ -49,13 +45,27 @@ impl DBLoginWindow {
|
|||
.title_bar(true)
|
||||
.scroll2([false, false])
|
||||
.enabled(true)
|
||||
.default_open(!is_db_connection_verified)
|
||||
.anchor(alignment, Vec2::ZERO)
|
||||
.anchor(egui::Align2::CENTER_CENTER, Vec2::ZERO)
|
||||
.show(ctx, |ui| {
|
||||
self.ui(ctx, ui);
|
||||
});
|
||||
if let Some(result) = &self.are_creditentials_verified {
|
||||
match result {
|
||||
Ok(_) => return Some(ExitStatus::Ok),
|
||||
Err(e) => {
|
||||
return Some(ExitStatus::Err(Box::from(<String as Into<
|
||||
Box<dyn std::error::Error>,
|
||||
>>::into(
|
||||
e.to_string()
|
||||
))))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
impl DBLoginWindow {
|
||||
fn ui(&mut self, ctx: &Context, ui: &mut Ui) {
|
||||
ui.heading("Log into the database:");
|
||||
ui.group(|ui| {
|
||||
|
@ -92,6 +102,21 @@ impl DBLoginWindow {
|
|||
ui.horizontal(|ui| {
|
||||
ui.checkbox(&mut self.db_login_data.should_remember, "Remember");
|
||||
|
||||
/* Autoconnects in debug mode */
|
||||
if cfg!(debug_assertions) && !self.debug_autoconnect_sent {
|
||||
println!(" * pre-connecting to \"{:?}\"...", &self.db_login_data);
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.are_creditentials_verified_receiver = Some(receiver);
|
||||
self.sender
|
||||
.try_send(Communication::ValidateCreditentials(
|
||||
self.db_login_data.clone(),
|
||||
sender,
|
||||
))
|
||||
.unwrap_or_else(|e| {
|
||||
println!("Failed to send authenticator... {}", e);
|
||||
});
|
||||
self.debug_autoconnect_sent = true
|
||||
}
|
||||
if ui.button("Connect").clicked() {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.are_creditentials_verified_receiver = Some(receiver);
|
||||
|
@ -107,16 +132,19 @@ impl DBLoginWindow {
|
|||
});
|
||||
|
||||
/* If db login bad, return sqlx error to UI */
|
||||
if let Some(err) = &mut self.are_creditentials_verified_error {
|
||||
if let Some(Err(err)) = &mut self.are_creditentials_verified {
|
||||
ui.style_mut().visuals.override_text_color = Some(egui::Color32::RED);
|
||||
ui.label(format!("{}", err));
|
||||
} else if let Some(Ok(_)) = &self.are_creditentials_verified {
|
||||
ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN);
|
||||
ui.label("Connected");
|
||||
}
|
||||
|
||||
if let Some(receiver) = &mut self.are_creditentials_verified_receiver {
|
||||
if let Ok(response) = receiver.try_recv() {
|
||||
match response {
|
||||
Ok(_) => self.are_creditentials_verified_error = None,
|
||||
Err(err) => self.are_creditentials_verified_error = Some(err),
|
||||
Ok(_) => self.are_creditentials_verified = Some(Ok(())),
|
||||
Err(err) => self.are_creditentials_verified = Some(Err(err)),
|
||||
}
|
||||
self.are_creditentials_verified_receiver = None;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,15 @@ use tokio::sync::oneshot;
|
|||
use crate::backend::backend_manager::Communication;
|
||||
use crate::backend::database_handler::QueryResult;
|
||||
|
||||
use super::window_manager::{CSQLWindow, ExitStatus};
|
||||
|
||||
pub struct DBTransactionWindow {
|
||||
sender: Sender<Communication>,
|
||||
/* (Query, Result) */
|
||||
log_history: Vec<QueryResult>,
|
||||
logs_receiver: Option<Receiver<QueryResult>>,
|
||||
is_log_finished_receiver: Option<oneshot::Receiver<bool>>,
|
||||
result: Option<Vec<Result<MySqlQueryResult, Box<dyn Error>>>>,
|
||||
is_log_finished: bool,
|
||||
is_finished: bool,
|
||||
final_result_receiver: Option<oneshot::Receiver<QueryResult>>,
|
||||
working_table_index: usize,
|
||||
}
|
||||
|
@ -25,16 +27,22 @@ impl DBTransactionWindow {
|
|||
DBTransactionWindow {
|
||||
sender,
|
||||
log_history: vec![],
|
||||
result: None,
|
||||
is_finished: false,
|
||||
logs_receiver: None,
|
||||
final_result_receiver: None,
|
||||
is_log_finished_receiver: None,
|
||||
is_log_finished: false,
|
||||
working_table_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DBTransactionWindow {
|
||||
pub fn show(&mut self, ctx: &Context, ui: &mut Ui, frame: &mut eframe::Frame) {
|
||||
impl CSQLWindow for DBTransactionWindow {
|
||||
fn refresh(
|
||||
&mut self,
|
||||
ctx: &Context,
|
||||
ui: &mut Ui,
|
||||
frame: &mut eframe::Frame,
|
||||
) -> Option<ExitStatus> {
|
||||
egui::Window::new("Database Transactions")
|
||||
.id(egui::Id::new("Database Transactions"))
|
||||
.resizable(false)
|
||||
|
@ -50,10 +58,24 @@ impl DBTransactionWindow {
|
|||
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
|
||||
.show(ctx, |ui| {
|
||||
self.log();
|
||||
self.ui(ctx, ui);
|
||||
self.ui(ctx, ui, frame);
|
||||
});
|
||||
|
||||
if self.is_finished {
|
||||
return Some(ExitStatus::Ok);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
impl DBTransactionWindow {
|
||||
pub fn log(&mut self) {
|
||||
if let Some(finish_receiver) = self.final_result_receiver.as_mut() {
|
||||
if let Ok(result) = finish_receiver.try_recv() {
|
||||
if result.result.is_ok() {
|
||||
self.is_finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.logs_receiver.is_some() {
|
||||
if let Ok(log) = self.logs_receiver.as_mut().unwrap().try_recv() {
|
||||
self.log_history.push(log);
|
||||
|
@ -61,8 +83,8 @@ impl DBTransactionWindow {
|
|||
}
|
||||
if self.is_log_finished_receiver.is_some() {
|
||||
if let Ok(finished) = self.is_log_finished_receiver.as_mut().unwrap().try_recv() {
|
||||
self.result = Some(vec![]);
|
||||
println!("FINISHED THE QUERY!!!");
|
||||
self.is_log_finished = finished;
|
||||
println!("FINISHED QUERYING!!!");
|
||||
}
|
||||
}
|
||||
if self.is_log_finished_receiver.is_none() && self.logs_receiver.is_none() {
|
||||
|
@ -79,8 +101,8 @@ impl DBTransactionWindow {
|
|||
.unwrap_or_else(|_| println!("Failed to send startInserting"));
|
||||
}
|
||||
}
|
||||
pub fn ui(&mut self, ctx: &Context, ui: &mut Ui) {
|
||||
ui.add_enabled_ui(self.result.is_some(), |ui| {
|
||||
pub fn ui(&mut self, ctx: &Context, ui: &mut Ui, frame: &mut eframe::Frame) {
|
||||
ui.add_enabled_ui(self.is_log_finished, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Roll back").clicked() {
|
||||
if self.final_result_receiver.is_none() {
|
||||
|
@ -103,7 +125,7 @@ impl DBTransactionWindow {
|
|||
});
|
||||
});
|
||||
/* DB Output Stuff */
|
||||
egui::ScrollArea::both()
|
||||
egui::ScrollArea::vertical()
|
||||
.auto_shrink([false; 2])
|
||||
.stick_to_bottom(true)
|
||||
.show(ui, |ui| {
|
||||
|
@ -111,9 +133,17 @@ impl DBTransactionWindow {
|
|||
.striped(true)
|
||||
.resizable(true)
|
||||
.cell_layout(egui::Layout::left_to_right(egui::Align::LEFT))
|
||||
.column(egui_extras::Column::remainder().clip(true))
|
||||
.column(
|
||||
egui_extras::Column::remainder()
|
||||
.clip(true)
|
||||
.at_most(frame.info().window_info.size.x / 1.3 / 2.0),
|
||||
)
|
||||
.stick_to_bottom(true)
|
||||
.column(egui_extras::Column::remainder().clip(true))
|
||||
.column(
|
||||
egui_extras::Column::remainder()
|
||||
.clip(true)
|
||||
.at_most(frame.info().window_info.size.x / 1.3 / 2.0),
|
||||
)
|
||||
.stick_to_bottom(true);
|
||||
|
||||
table
|
||||
|
@ -155,3 +185,8 @@ impl DBTransactionWindow {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OptionsDBTransactionWindow {
|
||||
substitute_zero_dates_for_NULL: bool,
|
||||
remove_id_field_from_insert: bool,
|
||||
}
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
use super::window_manager::{CSQLWindow, ExitStatus};
|
||||
use crate::backend::backend_manager::Communication;
|
||||
use crate::backend::csv_handler::ImportedData;
|
||||
use crate::backend::database_handler::{TableField, Tables};
|
||||
use egui::{ComboBox, Context, Ui};
|
||||
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
|
||||
use egui_extras::{Column, TableBuilder};
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::{mpsc::Sender, oneshot};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::{Mutex, MutexGuard};
|
||||
pub struct SpreadSheetWindow {
|
||||
sender: Sender<Communication>,
|
||||
csv_data_handle: Arc<Mutex<ImportedData>>,
|
||||
db_table_data_handle: Arc<Mutex<Tables>>,
|
||||
is_file_loaded_receiver: Option<oneshot::Receiver<bool>>,
|
||||
is_file_loaded: bool,
|
||||
current_table: Option<usize>,
|
||||
is_table_described_receiver: Option<oneshot::Receiver<bool>>,
|
||||
is_table_described: bool,
|
||||
is_table_matched_with_headers: bool,
|
||||
commit_to_db_sender: Sender<usize>,
|
||||
should_export_to_db: bool,
|
||||
debug_autoload_file_sent: bool,
|
||||
}
|
||||
impl SpreadSheetWindow {
|
||||
pub fn default(
|
||||
|
@ -28,147 +25,121 @@ impl SpreadSheetWindow {
|
|||
) -> SpreadSheetWindow {
|
||||
SpreadSheetWindow {
|
||||
sender,
|
||||
is_file_loaded_receiver: None,
|
||||
is_file_loaded: false,
|
||||
is_table_described_receiver: None,
|
||||
is_table_described: false,
|
||||
is_table_matched_with_headers: false,
|
||||
csv_data_handle,
|
||||
db_table_data_handle,
|
||||
current_table: None,
|
||||
commit_to_db_sender,
|
||||
debug_autoload_file_sent: false,
|
||||
should_export_to_db: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl SpreadSheetWindow {
|
||||
pub fn show(&mut self, ctx: &Context, ui: &mut Ui, is_db_connection_verified: bool) {
|
||||
self.ui(ui, ctx, is_db_connection_verified);
|
||||
impl CSQLWindow for SpreadSheetWindow {
|
||||
fn refresh(
|
||||
&mut self,
|
||||
ctx: &egui::Context,
|
||||
ui: &mut egui::Ui,
|
||||
frame: &mut eframe::Frame,
|
||||
) -> Option<ExitStatus> {
|
||||
self.ui(ui, ctx);
|
||||
if self.should_export_to_db {
|
||||
self.should_export_to_db = false;
|
||||
return Some(ExitStatus::StartTransactionWindow);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn ui(&mut self, ui: &mut Ui, ctx: &Context, is_db_connection_verified: bool) {
|
||||
/* Program Menu */
|
||||
|
||||
ui.horizontal_top(|ui| {
|
||||
if ui.button("Open File").clicked() {
|
||||
if let Some(path) = rfd::FileDialog::new()
|
||||
.add_filter("Spreadsheets", &["csv"])
|
||||
.pick_file()
|
||||
{
|
||||
self.open_file(path.display().to_string());
|
||||
};
|
||||
}
|
||||
if ui.button("Save File").clicked() {
|
||||
println!("Saving file lol");
|
||||
}
|
||||
ui.add_space(ui.available_width() * 0.8);
|
||||
|
||||
let is_csv_parsed: bool;
|
||||
if let Ok(csv_data) = self.csv_data_handle.try_lock() {
|
||||
is_csv_parsed = csv_data.is_parsed.clone();
|
||||
} else {
|
||||
is_csv_parsed = false;
|
||||
}
|
||||
ui.add_enabled_ui(is_csv_parsed, |ui| {
|
||||
if ui.button("Commit to Database").clicked() {
|
||||
self.commit_to_db_sender
|
||||
.try_send(self.current_table.unwrap())
|
||||
.unwrap_or_else(|_| println!("failed to send committodb-UI"))
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* if db isn't connected, don't allow imports */
|
||||
|
||||
if !is_db_connection_verified {
|
||||
return;
|
||||
};
|
||||
|
||||
/* Handle file drops */
|
||||
|
||||
ctx.input(|i| {
|
||||
if !i.raw.dropped_files.is_empty() {
|
||||
self.open_file(
|
||||
i.raw
|
||||
.dropped_files
|
||||
.clone()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.path
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.display()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
});
|
||||
self.check_file();
|
||||
SpreadSheetWindow::preview_files_being_dropped(ctx);
|
||||
|
||||
if !self.is_file_loaded {
|
||||
ui.centered_and_justified(|ui| ui.heading("Drag and drop or Open a file..."));
|
||||
}
|
||||
impl SpreadSheetWindow {
|
||||
fn ui(&mut self, ui: &mut Ui, ctx: &Context) {
|
||||
/* if csv was auto mapped and parsed */
|
||||
let is_csv_parsed: bool;
|
||||
if let Ok(csv_data) = self.csv_data_handle.try_lock() {
|
||||
is_csv_parsed = csv_data.is_parsed.clone();
|
||||
} else {
|
||||
is_csv_parsed = false;
|
||||
}
|
||||
|
||||
if self.is_file_loaded {
|
||||
ui.group(|ui| {
|
||||
StripBuilder::new(ui) //So the window doesn't grow with the innerts
|
||||
.size(Size::remainder().at_least(100.0)) // for the table
|
||||
.vertical(|mut strip| {
|
||||
strip.cell(|ui| {
|
||||
egui::ScrollArea::horizontal().show(ui, |ui| self.table_options(ui));
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
fn table_options(&mut self, ui: &mut Ui) {
|
||||
/* Create table select option */
|
||||
|
||||
if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() {
|
||||
let mut select_table = ComboBox::from_label("Select Table");
|
||||
if let Some(table_index) = self.current_table {
|
||||
select_table = select_table
|
||||
.selected_text(&db_table_data.tables.get(table_index).unwrap().name);
|
||||
}
|
||||
ui.vertical(|ui| {
|
||||
select_table.show_ui(ui, |ui| {
|
||||
for (table_i, table) in db_table_data.tables.iter().enumerate() {
|
||||
ui.selectable_value(
|
||||
&mut self.current_table,
|
||||
Some(table_i.clone()),
|
||||
&table.name,
|
||||
);
|
||||
/* Program Menu */
|
||||
ui.horizontal(|ui| {
|
||||
ui.group(|ui| {});
|
||||
});
|
||||
/* CSV & DB menu */
|
||||
ui.horizontal(|ui| {
|
||||
ui.columns(2, |uis| {
|
||||
uis[0].group(|ui| {
|
||||
if ui.button("Import file").clicked() {
|
||||
self.open_file();
|
||||
}
|
||||
if ui.button("Save").clicked() {
|
||||
self.save_file();
|
||||
}
|
||||
if ui.button("Save as...").clicked() {
|
||||
self.save_file();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* If a table is selected, try if it's fields are discovered */
|
||||
if !self.is_table_described {
|
||||
if let Some(table_i) = self.current_table {
|
||||
if db_table_data.tables.get(table_i).unwrap().fields.is_some() {
|
||||
self.is_table_described = true;
|
||||
} else if self.is_table_described_receiver.is_some() {
|
||||
match self
|
||||
.is_table_described_receiver
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.try_recv()
|
||||
{
|
||||
Ok(res) => self.is_table_matched_with_headers = res,
|
||||
Err(e) => println!("Failed receiving is_table_described, {}", e),
|
||||
uis[1].group(|ui| {
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
self.table_options(ui);
|
||||
if ui.button("Import DB").clicked() {
|
||||
todo!();
|
||||
}
|
||||
} else {
|
||||
let (sender, receiver) = oneshot::channel();
|
||||
self.is_table_described_receiver = Some(receiver);
|
||||
self.sender
|
||||
.try_send(Communication::GetTableDescription(table_i, sender))
|
||||
.unwrap_or_else(|e| println!("Failed asking to describe table, {}", e));
|
||||
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() {
|
||||
todo!();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
/* Handle file drops */
|
||||
ctx.input(|i| {
|
||||
if !i.raw.dropped_files.is_empty() {
|
||||
self.open_dropped_file(i);
|
||||
}
|
||||
});
|
||||
SpreadSheetWindow::preview_files_being_dropped(ctx);
|
||||
|
||||
if self.current_table.is_none() {
|
||||
ui.group(|ui| {
|
||||
egui::ScrollArea::horizontal().show(ui, |ui| {
|
||||
self.table_builder(ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
fn table_options(&mut self, ui: &mut Ui) {
|
||||
/* Create table select option, only enable if the tables are discovered yet*/
|
||||
if let Ok(db_table_data) = &mut self.db_table_data_handle.try_lock() {
|
||||
ui.add_enabled_ui(db_table_data.tables.get(0).is_some(), |ui| {
|
||||
let mut select_table = ComboBox::from_label("Select Table").width(100.0);
|
||||
if let Some(table_index) = self.current_table {
|
||||
if let Some(current_table) = &db_table_data.tables.get(table_index) {
|
||||
select_table = select_table.selected_text(current_table.name.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_table_described {
|
||||
self.table_builder(ui);
|
||||
/* autoselect oc_product in debug mode */
|
||||
if cfg!(debug_assertions) && self.current_table.is_none() {
|
||||
self.current_table = Some(88);
|
||||
if let Some(table_88) = &db_table_data.tables.get(88) {
|
||||
select_table = select_table.selected_text(table_88.name.clone());
|
||||
}
|
||||
}
|
||||
ui.vertical(|ui| {
|
||||
select_table.show_ui(ui, |ui| {
|
||||
for (table_i, table) in db_table_data.tables.iter().enumerate() {
|
||||
ui.selectable_value(
|
||||
&mut self.current_table,
|
||||
Some(table_i.clone()),
|
||||
&table.name,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
fn table_builder(&mut self, ui: &mut Ui) {
|
||||
|
@ -186,7 +157,7 @@ impl SpreadSheetWindow {
|
|||
.striped(true)
|
||||
.cell_layout(egui::Layout::left_to_right(egui::Align::Center));
|
||||
|
||||
for _i in 0..csv_data.data.cols() {
|
||||
for _i in 0..csv_data.data.cols() + 1 {
|
||||
table = table.column(Column::auto().resizable(true).clip(false));
|
||||
}
|
||||
/* If cols got prematched by name */
|
||||
|
@ -195,62 +166,15 @@ impl SpreadSheetWindow {
|
|||
.column(Column::remainder())
|
||||
.min_scrolled_height(0.0)
|
||||
.header(20., |mut header| {
|
||||
/* First Col for row mutators */
|
||||
header.col(|ui|{
|
||||
ui.add_space(45.0);
|
||||
});
|
||||
|
||||
for i in 0..csv_data.data.cols() {
|
||||
header.col(|ui| {
|
||||
if csv_data.parsed_cols.contains(&i){
|
||||
/* If the whole col is parsed, change header bg to green, else normal */
|
||||
ui.style_mut().visuals.override_text_color= Some(egui::Color32::GREEN);
|
||||
} else {
|
||||
ui.style_mut().visuals.override_text_color= Some(egui::Color32::RED);
|
||||
}
|
||||
let mut combo_box: ComboBox;
|
||||
if csv_data.are_headers {
|
||||
combo_box = ComboBox::new(
|
||||
i,
|
||||
csv_data.data.get(0, i).unwrap().data.clone(),
|
||||
);
|
||||
} else {
|
||||
combo_box = ComboBox::new(i, "");
|
||||
}
|
||||
|
||||
//if any field is assinged to this combobox, show it's text, else "----"
|
||||
if let Some(selected_field) = curr_db_table_fields
|
||||
.iter()
|
||||
.find(|field| field.mapped_to_col == Some(i))
|
||||
{
|
||||
combo_box = combo_box
|
||||
.selected_text(selected_field.description.field.clone());
|
||||
} else{
|
||||
combo_box = combo_box.selected_text("-----");
|
||||
}
|
||||
|
||||
/* When a Field gets attached to Col, */
|
||||
combo_box.show_ui(ui, |ui| {
|
||||
for field in curr_db_table_fields.iter_mut()
|
||||
{
|
||||
if ui
|
||||
.selectable_value(
|
||||
&mut field.mapped_to_col,
|
||||
Some(i),
|
||||
field.description.field.clone(),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
self.is_table_described = false;
|
||||
match self.sender.try_send(Communication::TryParseCol(i)){
|
||||
Ok(_) => {
|
||||
for cel in csv_data.data.iter_col_mut(i) {
|
||||
cel.curr_field_description =
|
||||
Some(field.description.clone());
|
||||
}
|
||||
}
|
||||
Err(e) => println!("failed sending parsecol request, {}",e)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.reset_style();
|
||||
});
|
||||
SpreadSheetWindow::add_header_col(ui,i, csv_data,&mut curr_db_table_fields, &mut self.sender);
|
||||
});
|
||||
}
|
||||
})
|
||||
.body(|body| {
|
||||
|
@ -287,33 +211,125 @@ impl SpreadSheetWindow {
|
|||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
ui.centered_and_justified(|ui| ui.heading("Drag and drop or Open a file..."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpreadSheetWindow {
|
||||
pub fn check_file(&mut self) {
|
||||
if let Some(receiver) = &mut self.is_file_loaded_receiver {
|
||||
match receiver.try_recv() {
|
||||
Ok(boole) => {
|
||||
if boole {
|
||||
self.is_file_loaded_receiver = None;
|
||||
}
|
||||
self.is_file_loaded = boole;
|
||||
}
|
||||
Err(e) => println!("Failed receiving load file callback, {}", e),
|
||||
pub fn add_header_col(
|
||||
ui: &mut Ui,
|
||||
i: usize,
|
||||
csv_data: &mut MutexGuard<ImportedData>,
|
||||
curr_db_table_fields: &mut Vec<TableField>,
|
||||
sender: &mut Sender<Communication>,
|
||||
) {
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
if ui.button("x").clicked() {
|
||||
todo!()
|
||||
}
|
||||
if csv_data.parsed_cols.contains(&i) {
|
||||
/* If the whole col is parsed, change header bg to green, else normal */
|
||||
ui.style_mut().visuals.override_text_color = Some(egui::Color32::GREEN);
|
||||
} else {
|
||||
ui.style_mut().visuals.override_text_color = Some(egui::Color32::RED);
|
||||
}
|
||||
let mut combo_box: ComboBox;
|
||||
if csv_data.are_headers {
|
||||
combo_box = ComboBox::new(i, csv_data.data.get(0, i).unwrap().data.clone());
|
||||
} else {
|
||||
combo_box = ComboBox::new(i, "");
|
||||
}
|
||||
|
||||
//if any field is assinged to this combobox, show it's text, else "----"
|
||||
if let Some(selected_field) = curr_db_table_fields
|
||||
.iter()
|
||||
.find(|field| field.mapped_to_col == Some(i))
|
||||
{
|
||||
combo_box = combo_box.selected_text(selected_field.description.field.clone());
|
||||
} else {
|
||||
combo_box = combo_box.selected_text("-----");
|
||||
}
|
||||
|
||||
/* When a Field gets attached to Col, */
|
||||
combo_box.show_ui(ui, |ui| {
|
||||
for field in curr_db_table_fields.iter_mut() {
|
||||
if ui
|
||||
.selectable_value(
|
||||
&mut field.mapped_to_col,
|
||||
Some(i),
|
||||
field.description.field.clone(),
|
||||
)
|
||||
.clicked()
|
||||
{
|
||||
match sender.try_send(Communication::TryParseCol(i)) {
|
||||
Ok(_) => {
|
||||
for cel in csv_data.data.iter_col_mut(i) {
|
||||
cel.curr_field_description = Some(field.description.clone());
|
||||
}
|
||||
}
|
||||
Err(e) => println!("failed sending parsecol request, {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ui.reset_style();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn save_file(&mut self) {
|
||||
let mut save_name = "to-csv".to_owned();
|
||||
if let Some(table_i) = self.current_table {
|
||||
if let Ok(db_table_data) = self.db_table_data_handle.try_lock() {
|
||||
save_name = db_table_data.tables.get(table_i).unwrap().name.clone();
|
||||
}
|
||||
}
|
||||
if let Some(path) = rfd::FileDialog::new()
|
||||
.set_file_name(format!("db-{}-converted.csv", save_name).as_str())
|
||||
.save_file()
|
||||
{
|
||||
self.sender
|
||||
.try_send(Communication::SaveCSV(path.display().to_string()))
|
||||
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
|
||||
};
|
||||
}
|
||||
|
||||
pub fn open_file(&mut self) {
|
||||
/*preloads file in debug */
|
||||
if cfg!(debug_assertions) && !self.debug_autoload_file_sent {
|
||||
let path = std::path::PathBuf::from("/home/djkato/Dokumenty/csql/oc_product.csv");
|
||||
println!(" * Preloading \"{:?}\"...", path);
|
||||
self.debug_autoload_file_sent = true;
|
||||
}
|
||||
if let Some(path) = rfd::FileDialog::new()
|
||||
.add_filter("Spreadsheets", &["csv"])
|
||||
.pick_file()
|
||||
{
|
||||
self.sender
|
||||
.try_send(Communication::LoadImportFilePath(
|
||||
path.display().to_string(),
|
||||
))
|
||||
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_file(&mut self, path: String) {
|
||||
if !self.is_file_loaded_receiver.is_some() {
|
||||
let (sed, rec) = oneshot::channel();
|
||||
self.sender
|
||||
.try_send(Communication::LoadImportFilePath(path, sed))
|
||||
.unwrap_or_else(|err| println!("failed to send loadimportpath, {}", err));
|
||||
self.is_file_loaded_receiver = Some(rec);
|
||||
}
|
||||
pub fn open_dropped_file(&mut self, path: &egui::InputState) {
|
||||
let path = path
|
||||
.raw
|
||||
.dropped_files
|
||||
.clone()
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.path
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.display()
|
||||
.to_string();
|
||||
|
||||
self.sender
|
||||
.try_send(Communication::LoadImportFilePath(path))
|
||||
.unwrap_or_else(|err| println!("failed to send loadimportpathdropped, {}", err));
|
||||
}
|
||||
|
||||
pub fn preview_files_being_dropped(ctx: &egui::Context) {
|
||||
|
|
|
@ -10,6 +10,7 @@ use tokio::sync::oneshot;
|
|||
use tokio::sync::Mutex;
|
||||
|
||||
use super::db_transaction_window::DBTransactionWindow;
|
||||
use super::{db_login_window, db_transaction_window};
|
||||
|
||||
pub fn create_ui(
|
||||
sender: Sender<Communication>,
|
||||
|
@ -32,15 +33,13 @@ pub fn create_ui(
|
|||
csv_data_handle.clone(),
|
||||
db_table_data_handle.clone(),
|
||||
),
|
||||
db_login_window: DBLoginWindow::default(sender.clone()),
|
||||
db_login_window: None,
|
||||
db_transaction_window: None,
|
||||
is_db_connection_verified_receiver: None,
|
||||
sender,
|
||||
is_db_connection_verified: false,
|
||||
csv_data_handle,
|
||||
db_table_data_handle,
|
||||
open_db_transaction_window_receiver,
|
||||
should_open_db_transaction_window: None,
|
||||
should_open_transaction_window: false,
|
||||
should_open_login_window: true,
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
@ -48,60 +47,67 @@ pub fn create_ui(
|
|||
|
||||
struct CSQL {
|
||||
spreadsheet_window: SpreadSheetWindow,
|
||||
db_login_window: DBLoginWindow,
|
||||
db_login_window: Option<DBLoginWindow>,
|
||||
db_transaction_window: Option<DBTransactionWindow>,
|
||||
sender: Sender<Communication>,
|
||||
is_db_connection_verified_receiver: Option<oneshot::Receiver<bool>>,
|
||||
is_db_connection_verified: bool,
|
||||
csv_data_handle: Arc<Mutex<ImportedData>>,
|
||||
db_table_data_handle: Arc<Mutex<Tables>>,
|
||||
open_db_transaction_window_receiver: Receiver<usize>,
|
||||
should_open_db_transaction_window: Option<usize>,
|
||||
should_open_transaction_window: bool,
|
||||
should_open_login_window: bool,
|
||||
}
|
||||
|
||||
impl App for CSQL {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
self.db_login_window
|
||||
.show(ctx, ui, self.is_db_connection_verified);
|
||||
|
||||
self.spreadsheet_window
|
||||
.show(ctx, ui, self.is_db_connection_verified);
|
||||
|
||||
if let Ok(resp) = self.open_db_transaction_window_receiver.try_recv() {
|
||||
self.should_open_db_transaction_window = Some(resp);
|
||||
}
|
||||
if let Some(db_transaction_window) = self.db_transaction_window.as_mut() {
|
||||
db_transaction_window.show(ctx, ui, frame)
|
||||
}
|
||||
if let Some(working_table_index) = self.should_open_db_transaction_window {
|
||||
let db_transaction_window =
|
||||
DBTransactionWindow::default(self.sender.clone(), working_table_index);
|
||||
self.db_transaction_window = Some(db_transaction_window);
|
||||
self.db_transaction_window
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.show(ctx, ui, frame);
|
||||
self.should_open_db_transaction_window = None;
|
||||
}
|
||||
|
||||
/* Changes self if db connection is verified */
|
||||
if let Some(oneshot_receiver) = &mut self.is_db_connection_verified_receiver {
|
||||
if let Ok(boole) = oneshot_receiver.try_recv() {
|
||||
self.is_db_connection_verified = boole;
|
||||
self.is_db_connection_verified_receiver = None;
|
||||
if let Some(result) = self.spreadsheet_window.refresh(ctx, ui, frame) {
|
||||
match result {
|
||||
ExitStatus::StartLoginWindow => self.should_open_transaction_window = true,
|
||||
ExitStatus::StartTransactionWindow => self.should_open_login_window = true,
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
let (sed, rec) = oneshot::channel();
|
||||
self.is_db_connection_verified_receiver = Some(rec);
|
||||
match self
|
||||
.sender
|
||||
.try_send(Communication::AreCreditentialsValidated(sed))
|
||||
{
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("Failed to send-verify db conn oneshot, {}", e),
|
||||
};
|
||||
|
||||
if self.should_open_login_window {
|
||||
if let Some(db_login_window) = self.db_login_window.as_mut() {
|
||||
if let Some(result) = db_login_window.refresh(ctx, ui, frame) {
|
||||
match result {
|
||||
ExitStatus::Ok => {
|
||||
self.db_login_window = None;
|
||||
self.should_open_login_window = false;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.should_open_transaction_window {
|
||||
if let Some(db_transaction_window) = self.db_transaction_window.as_mut() {
|
||||
if let Some(result) = db_transaction_window.refresh(ctx, ui, frame) {
|
||||
match result {
|
||||
ExitStatus::Ok => {
|
||||
self.db_transaction_window = None;
|
||||
self.should_open_transaction_window = false;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CSQLWindow {
|
||||
fn refresh(
|
||||
&mut self,
|
||||
ctx: &egui::Context,
|
||||
ui: &mut egui::Ui,
|
||||
frame: &mut eframe::Frame,
|
||||
) -> Option<ExitStatus>;
|
||||
}
|
||||
pub enum ExitStatus {
|
||||
StartTransactionWindow,
|
||||
StartLoginWindow,
|
||||
Ok,
|
||||
Err(Box<dyn std::error::Error>),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue