From 6fa8b0606366f95a62786165315f27a62a7d0b9c Mon Sep 17 00:00:00 2001 From: filipriec Date: Tue, 22 Apr 2025 23:22:59 +0200 Subject: [PATCH] grpc post request to the table definition from add table, not working, major bug, needs debugging to make it work --- .../modes/navigation/add_table_nav.rs | 31 ++++++- client/src/modes/handlers/event.rs | 9 ++ client/src/services/grpc_client.rs | 8 +- client/src/tui/functions/common/add_table.rs | 82 ++++++++++++++++++- client/src/ui/handlers/ui.rs | 31 +++++++ 5 files changed, 156 insertions(+), 5 deletions(-) diff --git a/client/src/functions/modes/navigation/add_table_nav.rs b/client/src/functions/modes/navigation/add_table_nav.rs index d0a5233..dd545a8 100644 --- a/client/src/functions/modes/navigation/add_table_nav.rs +++ b/client/src/functions/modes/navigation/add_table_nav.rs @@ -6,8 +6,14 @@ use crate::state::{ }; use crossterm::event::{KeyEvent}; use ratatui::widgets::TableState; -use crate::tui::functions::common::add_table::handle_add_column_action; +use crate::tui::functions::common::add_table::{handle_add_column_action, handle_save_table_action}; use crate::ui::handlers::context::DialogPurpose; +use crate::services::GrpcClient; +use tokio::sync::mpsc; +use anyhow::Result; + +// Define a type for the save result channel +pub type SaveTableResultSender = mpsc::Sender>; /// Handles navigation events specifically for the Add Table view. /// Returns true if the event was handled, false otherwise. @@ -16,6 +22,8 @@ pub fn handle_add_table_navigation( config: &Config, app_state: &mut AppState, add_table_state: &mut AddTableState, + grpc_client: GrpcClient, + save_result_sender: SaveTableResultSender, command_message: &mut String, ) -> bool { let action = config.get_general_action(key.code, key.modifiers); @@ -246,8 +254,25 @@ pub fn handle_add_table_navigation( } } AddTableFocus::SaveButton => { - *command_message = "Action: Save Table (Not Implemented)".to_string(); - // TODO: Implement logic + // --- Initiate Async Save --- + if add_table_state.table_name.is_empty() { + *command_message = "Cannot save: Table name is empty.".to_string(); + } else if add_table_state.columns.is_empty() { + *command_message = "Cannot save: No columns defined.".to_string(); + } else { + *command_message = "Saving table...".to_string(); + app_state.show_loading_dialog("Saving", "Please wait..."); + + let mut client_clone = grpc_client.clone(); + let state_clone = add_table_state.clone(); + let sender_clone = save_result_sender.clone(); + + tokio::spawn(async move { + let result = handle_save_table_action(&mut client_clone, &state_clone).await; + let _ = sender_clone.send(result).await; // Send result back + }); + } + // --- End Initiate Async Save --- } AddTableFocus::DeleteSelectedButton => { // --- Show Confirmation Dialog --- diff --git a/client/src/modes/handlers/event.rs b/client/src/modes/handlers/event.rs index 3e4f392..5f48d34 100644 --- a/client/src/modes/handlers/event.rs +++ b/client/src/modes/handlers/event.rs @@ -40,6 +40,7 @@ use crate::config::binds::key_sequences::KeySequenceTracker; use tokio::sync::mpsc; use crate::tui::functions::common::login::LoginResult; use crate::tui::functions::common::register::RegisterResult; +use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender; #[derive(Debug, Clone, PartialEq, Eq)] pub enum EventOutcome { @@ -61,12 +62,14 @@ pub struct EventHandler { pub auth_client: AuthClient, pub login_result_sender: mpsc::Sender, pub register_result_sender: mpsc::Sender, + pub save_table_result_sender: SaveTableResultSender, } impl EventHandler { pub async fn new( login_result_sender: mpsc::Sender, register_result_sender: mpsc::Sender, + save_table_result_sender: SaveTableResultSender, ) -> Result { Ok(EventHandler { command_mode: false, @@ -80,6 +83,7 @@ impl EventHandler { auth_client: AuthClient::new().await?, login_result_sender, register_result_sender, + save_table_result_sender, }) } @@ -189,11 +193,16 @@ impl EventHandler { } // --- Add Table Page Navigation --- if app_state.ui.show_add_table { + let client_clone = grpc_client.clone(); + let sender_clone = self.save_table_result_sender.clone(); + if add_table_nav::handle_add_table_navigation( key, config, app_state, &mut admin_state.add_table_state, + client_clone, + sender_clone, &mut self.command_message, ) { diff --git a/client/src/services/grpc_client.rs b/client/src/services/grpc_client.rs index 5bb994a..e56b8a2 100644 --- a/client/src/services/grpc_client.rs +++ b/client/src/services/grpc_client.rs @@ -8,7 +8,7 @@ use common::proto::multieko2::table_structure::table_structure_service_client::T use common::proto::multieko2::table_structure::TableStructureResponse; use common::proto::multieko2::table_definition::{ table_definition_client::TableDefinitionClient, - ProfileTreeResponse + ProfileTreeResponse, PostTableDefinitionRequest, TableDefinitionResponse, }; use anyhow::Result; @@ -67,4 +67,10 @@ impl GrpcClient { let response = self.table_definition_client.get_profile_tree(request).await?; Ok(response.into_inner()) } + + pub async fn post_table_definition(&mut self, request: PostTableDefinitionRequest) -> Result { + let tonic_request = tonic::Request::new(request); + let response = self.table_definition_client.post_table_definition(tonic_request).await?; + Ok(response.into_inner()) + } } diff --git a/client/src/tui/functions/common/add_table.rs b/client/src/tui/functions/common/add_table.rs index 69d1206..cc5ad41 100644 --- a/client/src/tui/functions/common/add_table.rs +++ b/client/src/tui/functions/common/add_table.rs @@ -1,6 +1,13 @@ // src/tui/functions/common/add_table.rs use crate::state::pages::add_table::{ - AddTableFocus, AddTableState, ColumnDefinition, IndexDefinition, + AddTableFocus, AddTableState, ColumnDefinition, IndexDefinition, LinkDefinition, +}; +use crate::services::GrpcClient; +use anyhow::{anyhow, Result}; +use common::proto::multieko2::table_definition::{ + PostTableDefinitionRequest, + ColumnDefinition as ProtoColumnDefinition, + TableLink as ProtoTableLink, }; /// Handles the logic for adding a column when the "Add" button is activated. @@ -113,3 +120,76 @@ pub fn handle_delete_selected_columns( } } +/// Prepares and sends the request to save the new table definition via gRPC. +pub async fn handle_save_table_action( + grpc_client: &mut GrpcClient, + add_table_state: &AddTableState, +) -> Result { + // --- Basic Validation --- + if add_table_state.table_name.is_empty() { + return Err(anyhow!("Table name cannot be empty.")); + } + if add_table_state.columns.is_empty() { + return Err(anyhow!("Table must have at least one column.")); + } + + // --- Prepare Proto Data --- + let proto_columns: Vec = add_table_state + .columns + .iter() + .map(|col| ProtoColumnDefinition { + name: col.name.clone(), + field_type: col.data_type.clone(), // Assuming data_type maps directly + }) + .collect(); + + let proto_indexes: Vec = add_table_state + .indexes + .iter() + .filter(|idx| idx.selected) // Only include selected indexes + .map(|idx| idx.name.clone()) + .collect(); + + let proto_links: Vec = add_table_state + .links + .iter() + .filter(|link| link.selected) // Only include selected links + .map(|link| ProtoTableLink { + linked_table_name: link.linked_table_name.clone(), + // Assuming 'required' maps directly, adjust if needed + // For now, the proto only seems to use linked_table_name based on example + // If your proto evolves, map link.is_required here. + required: false, // Set based on your proto definition/needs + }) + .collect(); + + // --- Create Request --- + let request = PostTableDefinitionRequest { + table_name: add_table_state.table_name.clone(), + columns: proto_columns, + indexes: proto_indexes, + links: proto_links, + profile_name: add_table_state.profile_name.clone(), + }; + + // --- Call gRPC Service --- + match grpc_client.post_table_definition(request).await { + Ok(response) => { + if response.success { + Ok(format!( + "Table '{}' saved successfully.", + add_table_state.table_name + )) + } else { + // Use the SQL message from the response if available, otherwise generic error + let error_message = if !response.sql.is_empty() { + format!("Server failed to save table: {}", response.sql) + } else { + "Server failed to save table (unknown reason).".to_string() + }; + Err(anyhow!(error_message)) + } + } + Err(e) => Err(anyhow!("gRPC call failed: {}", e)), + } +} diff --git a/client/src/ui/handlers/ui.rs b/client/src/ui/handlers/ui.rs index 2d96d94..7eb9602 100644 --- a/client/src/ui/handlers/ui.rs +++ b/client/src/ui/handlers/ui.rs @@ -21,6 +21,8 @@ use crate::tui::terminal::{EventReader, TerminalCore}; use crate::ui::handlers::render::render_ui; use crate::tui::functions::common::login::LoginResult; use crate::tui::functions::common::register::RegisterResult; +use crate::tui::functions::common::add_table::handle_save_table_action; +use crate::functions::modes::navigation::add_table_nav::SaveTableResultSender; use crate::tui::functions::common::login; use crate::tui::functions::common::register; use std::time::Instant; @@ -42,9 +44,13 @@ pub async fn run_ui() -> Result<()> { mpsc::channel::(1); let (register_result_sender, mut register_result_receiver) = mpsc::channel::(1); + let (save_table_result_sender, mut save_table_result_receiver) = + mpsc::channel::>(1); + let mut event_handler = EventHandler::new( login_result_sender.clone(), register_result_sender.clone(), + save_table_result_sender.clone(), ).await.context("Failed to create event handler")?; let event_reader = EventReader::new(); @@ -215,6 +221,31 @@ pub async fn run_ui() -> Result<()> { error!("Register result channel disconnected unexpectedly."); } } + // --- Check for Save Table Results --- + match save_table_result_receiver.try_recv() { + Ok(result) => { + app_state.hide_dialog(); // Hide loading indicator + match result { + Ok(success_message) => { + event_handler.command_message = success_message; + admin_state.add_table_state.has_unsaved_changes = false; + // Optionally refresh profile tree if needed + // let _ = UiService::initialize_app_state(&mut grpc_client, &mut app_state).await; + // Navigate back to Admin view + buffer_state.update_history(AppView::Admin); + } + Err(e) => { + event_handler.command_message = format!("Save failed: {}", e); + // Optionally show an error dialog instead of just command message + } + } + needs_redraw = true; + } + Err(mpsc::error::TryRecvError::Empty) => {} // No message + Err(mpsc::error::TryRecvError::Disconnected) => { + error!("Save table result channel disconnected unexpectedly."); + } + } // --- Centralized Consequence Handling --- let mut should_exit = false;