Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ff9399b81 | ||
|
|
d18f7862ab | ||
|
|
dc6c1ce43c |
@@ -11,7 +11,7 @@ use anyhow::{Context, Result};
|
|||||||
use crate::tui::functions::common::{
|
use crate::tui::functions::common::{
|
||||||
form::{save as form_save, revert as form_revert},
|
form::{save as form_save, revert as form_revert},
|
||||||
login::{save as login_save, revert as login_revert},
|
login::{save as login_save, revert as login_revert},
|
||||||
register::{save as register_save, revert as register_revert},
|
register::{revert as register_revert},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn handle_core_action(
|
pub async fn handle_core_action(
|
||||||
@@ -32,9 +32,6 @@ pub async fn handle_core_action(
|
|||||||
if app_state.ui.show_login {
|
if app_state.ui.show_login {
|
||||||
let message = login_save(auth_state, login_state, auth_client, app_state).await.context("Login save action failed")?;
|
let message = login_save(auth_state, login_state, auth_client, app_state).await.context("Login save action failed")?;
|
||||||
Ok(EventOutcome::Ok(message))
|
Ok(EventOutcome::Ok(message))
|
||||||
} else if app_state.ui.show_register {
|
|
||||||
let message = register_save(register_state, auth_client, app_state).await.context("Register save_and_quit action failed")?;
|
|
||||||
Ok(EventOutcome::Ok(message))
|
|
||||||
} else {
|
} else {
|
||||||
let save_outcome = form_save(
|
let save_outcome = form_save(
|
||||||
form_state,
|
form_state,
|
||||||
@@ -57,8 +54,6 @@ pub async fn handle_core_action(
|
|||||||
"save_and_quit" => {
|
"save_and_quit" => {
|
||||||
let message = if app_state.ui.show_login {
|
let message = if app_state.ui.show_login {
|
||||||
login_save(auth_state, login_state, auth_client, app_state).await.context("Login save n quit action failed")?
|
login_save(auth_state, login_state, auth_client, app_state).await.context("Login save n quit action failed")?
|
||||||
} else if app_state.ui.show_register {
|
|
||||||
register_save(register_state, auth_client, app_state).await.context("Register save n quit action failed")?
|
|
||||||
} else {
|
} else {
|
||||||
let save_outcome = form_save(
|
let save_outcome = form_save(
|
||||||
form_state,
|
form_state,
|
||||||
|
|||||||
@@ -6,17 +6,12 @@ use crate::services::auth::AuthClient;
|
|||||||
use crate::config::binds::config::Config;
|
use crate::config::binds::config::Config;
|
||||||
use crate::ui::handlers::rat_state::UiStateHandler;
|
use crate::ui::handlers::rat_state::UiStateHandler;
|
||||||
use crate::ui::handlers::context::UiContext;
|
use crate::ui::handlers::context::UiContext;
|
||||||
use crate::ui::handlers::context::DialogPurpose;
|
|
||||||
use crate::functions::common::buffer;
|
use crate::functions::common::buffer;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use crate::tui::{
|
use crate::tui::{
|
||||||
terminal::core::TerminalCore,
|
terminal::core::TerminalCore,
|
||||||
functions::{
|
functions::{
|
||||||
common::{
|
common::{form::SaveOutcome, login, register},
|
||||||
form::SaveOutcome,
|
|
||||||
login,
|
|
||||||
register,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{intro, admin},
|
{intro, admin},
|
||||||
};
|
};
|
||||||
@@ -42,7 +37,6 @@ use crate::modes::{
|
|||||||
};
|
};
|
||||||
use crate::functions::modes::navigation::{admin_nav, add_table_nav};
|
use crate::functions::modes::navigation::{admin_nav, add_table_nav};
|
||||||
use crate::config::binds::key_sequences::KeySequenceTracker;
|
use crate::config::binds::key_sequences::KeySequenceTracker;
|
||||||
use tokio::spawn;
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use crate::tui::functions::common::login::LoginResult;
|
use crate::tui::functions::common::login::LoginResult;
|
||||||
use crate::tui::functions::common::register::RegisterResult;
|
use crate::tui::functions::common::register::RegisterResult;
|
||||||
@@ -234,50 +228,8 @@ impl EventHandler {
|
|||||||
}
|
}
|
||||||
UiContext::Login => {
|
UiContext::Login => {
|
||||||
let login_action_message = match index {
|
let login_action_message = match index {
|
||||||
0 => { // "Login" button pressed
|
0 => {
|
||||||
let username = login_state.username.clone();
|
login::initiate_login(login_state, app_state, self.login_result_sender.clone())
|
||||||
let password = login_state.password.clone();
|
|
||||||
|
|
||||||
// 1. Client-side validation
|
|
||||||
if username.trim().is_empty() {
|
|
||||||
app_state.show_dialog(
|
|
||||||
"Login Failed",
|
|
||||||
"Username/Email cannot be empty.",
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::LoginFailed,
|
|
||||||
);
|
|
||||||
// Return a message, no need to modify login_state here
|
|
||||||
// as it will be cleared when result is processed
|
|
||||||
"Username cannot be empty.".to_string()
|
|
||||||
} else {
|
|
||||||
// 2. Show Loading Dialog
|
|
||||||
app_state.show_loading_dialog("Logging In", "Please wait...");
|
|
||||||
|
|
||||||
// 3. Clone sender for the task (needs sender from ui.rs)
|
|
||||||
// NOTE: We need access to login_result_sender here.
|
|
||||||
// This requires passing it into EventHandler or handle_event.
|
|
||||||
// Let's assume it's added to EventHandler state for now.
|
|
||||||
let sender = self.login_result_sender.clone(); // Assumes sender is part of EventHandler state
|
|
||||||
|
|
||||||
// 4. Spawn the login task
|
|
||||||
spawn(async move {
|
|
||||||
let login_outcome = match AuthClient::new().await {
|
|
||||||
Ok(mut auth_client) => {
|
|
||||||
match auth_client.login(username.clone(), password).await
|
|
||||||
.with_context(|| format!("Spawned login task failed for identifier: {}", username))
|
|
||||||
{
|
|
||||||
Ok(response) => login::LoginResult::Success(response),
|
|
||||||
Err(e) => login::LoginResult::Failure(format!("{}", e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => login::LoginResult::ConnectionError(format!("Failed to create AuthClient: {}", e)),
|
|
||||||
};
|
|
||||||
let _ = sender.send(login_outcome).await; // Handle error?
|
|
||||||
});
|
|
||||||
|
|
||||||
// 5. Return immediately
|
|
||||||
"Login initiated.".to_string()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
1 => login::back_to_main(login_state, app_state, buffer_state).await,
|
1 => login::back_to_main(login_state, app_state, buffer_state).await,
|
||||||
_ => "Invalid Login Option".to_string(),
|
_ => "Invalid Login Option".to_string(),
|
||||||
@@ -286,50 +238,8 @@ impl EventHandler {
|
|||||||
}
|
}
|
||||||
UiContext::Register => {
|
UiContext::Register => {
|
||||||
let register_action_message = match index {
|
let register_action_message = match index {
|
||||||
0 => { // "Register" button pressed
|
0 => {
|
||||||
// Clone necessary data
|
register::initiate_registration(register_state, app_state, self.register_result_sender.clone())
|
||||||
let username = register_state.username.clone();
|
|
||||||
let email = register_state.email.clone();
|
|
||||||
let password = register_state.password.clone();
|
|
||||||
let password_confirmation = register_state.password_confirmation.clone();
|
|
||||||
let role = register_state.role.clone();
|
|
||||||
|
|
||||||
// 1. Client-side validation (similar to register::save)
|
|
||||||
if username.trim().is_empty() {
|
|
||||||
app_state.show_dialog("Registration Failed", "Username cannot be empty.", vec!["OK".to_string()], DialogPurpose::RegisterFailed);
|
|
||||||
"Username cannot be empty.".to_string()
|
|
||||||
} else if !password.is_empty() && password != password_confirmation {
|
|
||||||
app_state.show_dialog("Registration Failed", "Passwords do not match.", vec!["OK".to_string()], DialogPurpose::RegisterFailed);
|
|
||||||
"Passwords do not match.".to_string()
|
|
||||||
} else {
|
|
||||||
// 2. Show Loading Dialog
|
|
||||||
app_state.show_loading_dialog("Registering", "Please wait...");
|
|
||||||
|
|
||||||
// 3. Clone sender for the task
|
|
||||||
let sender = self.register_result_sender.clone();
|
|
||||||
|
|
||||||
// 4. Spawn the registration task
|
|
||||||
spawn(async move {
|
|
||||||
let register_outcome = match AuthClient::new().await {
|
|
||||||
Ok(mut auth_client) => {
|
|
||||||
// Handle optional fields correctly for the gRPC call
|
|
||||||
let password_opt = if password.is_empty() { None } else { Some(password) };
|
|
||||||
let password_conf_opt = if password_confirmation.is_empty() { None } else { Some(password_confirmation) };
|
|
||||||
let role_opt = if role.is_empty() { None } else { Some(role) };
|
|
||||||
|
|
||||||
match auth_client.register(username.clone(), email, password_opt, password_conf_opt, role_opt).await {
|
|
||||||
Ok(response) => register::RegisterResult::Success(response),
|
|
||||||
Err(e) => register::RegisterResult::Failure(format!("{}", e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => register::RegisterResult::ConnectionError(format!("Failed to create AuthClient: {}", e)),
|
|
||||||
};
|
|
||||||
let _ = sender.send(register_outcome).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 5. Return immediately
|
|
||||||
"Registration initiated.".to_string()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
1 => register::back_to_login(register_state, app_state, buffer_state).await,
|
1 => register::back_to_login(register_state, app_state, buffer_state).await,
|
||||||
_ => "Invalid Login Option".to_string(),
|
_ => "Invalid Login Option".to_string(),
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ use crate::state::pages::canvas_state::CanvasState;
|
|||||||
use crate::ui::handlers::context::DialogPurpose;
|
use crate::ui::handlers::context::DialogPurpose;
|
||||||
use common::proto::multieko2::auth::LoginResponse;
|
use common::proto::multieko2::auth::LoginResponse;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use tokio::spawn;
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use tracing::{info, error};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LoginResult {
|
pub enum LoginResult {
|
||||||
@@ -139,3 +142,87 @@ pub async fn back_to_main(
|
|||||||
"Returned to main menu".to_string()
|
"Returned to main menu".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Validates input, shows loading, and spawns the login task.
|
||||||
|
pub fn initiate_login(
|
||||||
|
login_state: &LoginState,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
sender: mpsc::Sender<LoginResult>,
|
||||||
|
) -> String {
|
||||||
|
let username = login_state.username.clone();
|
||||||
|
let password = login_state.password.clone();
|
||||||
|
|
||||||
|
// 1. Client-side validation
|
||||||
|
if username.trim().is_empty() {
|
||||||
|
app_state.show_dialog(
|
||||||
|
"Login Failed",
|
||||||
|
"Username/Email cannot be empty.",
|
||||||
|
vec!["OK".to_string()],
|
||||||
|
DialogPurpose::LoginFailed,
|
||||||
|
);
|
||||||
|
"Username cannot be empty.".to_string()
|
||||||
|
} else {
|
||||||
|
// 2. Show Loading Dialog
|
||||||
|
app_state.show_loading_dialog("Logging In", "Please wait...");
|
||||||
|
|
||||||
|
// 3. Spawn the login task
|
||||||
|
spawn(async move {
|
||||||
|
let login_outcome = match AuthClient::new().await {
|
||||||
|
Ok(mut auth_client) => {
|
||||||
|
match auth_client.login(username.clone(), password).await
|
||||||
|
.with_context(|| format!("Spawned login task failed for identifier: {}", username))
|
||||||
|
{
|
||||||
|
Ok(response) => LoginResult::Success(response),
|
||||||
|
Err(e) => LoginResult::Failure(format!("{}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => LoginResult::ConnectionError(format!("Failed to create AuthClient: {}", e)),
|
||||||
|
};
|
||||||
|
// Send result back to the main UI thread
|
||||||
|
if let Err(e) = sender.send(login_outcome).await {
|
||||||
|
error!("Failed to send login result: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Return immediately
|
||||||
|
"Login initiated.".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles the result received from the login task.
|
||||||
|
/// Returns true if a redraw is needed.
|
||||||
|
pub fn handle_login_result(
|
||||||
|
result: LoginResult,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
auth_state: &mut AuthState,
|
||||||
|
login_state: &mut LoginState,
|
||||||
|
) -> bool {
|
||||||
|
match result {
|
||||||
|
LoginResult::Success(response) => {
|
||||||
|
auth_state.auth_token = Some(response.access_token.clone());
|
||||||
|
auth_state.user_id = Some(response.user_id.clone());
|
||||||
|
auth_state.role = Some(response.role.clone());
|
||||||
|
auth_state.decoded_username = Some(response.username.clone());
|
||||||
|
|
||||||
|
let success_message = format!(
|
||||||
|
"Login Successful!\n\nUsername: {}\nUser ID: {}\nRole: {}",
|
||||||
|
response.username, response.user_id, response.role
|
||||||
|
);
|
||||||
|
app_state.update_dialog_content(
|
||||||
|
&success_message,
|
||||||
|
vec!["Menu".to_string(), "Exit".to_string()],
|
||||||
|
DialogPurpose::LoginSuccess,
|
||||||
|
);
|
||||||
|
info!(message = %success_message, "Login successful");
|
||||||
|
}
|
||||||
|
LoginResult::Failure(err_msg) | LoginResult::ConnectionError(err_msg) => {
|
||||||
|
app_state.update_dialog_content(&err_msg, vec!["OK".to_string()], DialogPurpose::LoginFailed);
|
||||||
|
login_state.error_message = Some(err_msg.clone());
|
||||||
|
error!(error = %err_msg, "Login failed/connection error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
login_state.username.clear();
|
||||||
|
login_state.password.clear();
|
||||||
|
login_state.set_has_unsaved_changes(false);
|
||||||
|
login_state.current_cursor_pos = 0;
|
||||||
|
true // Request redraw as dialog content changed
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ use crate::state::{
|
|||||||
use crate::ui::handlers::context::DialogPurpose;
|
use crate::ui::handlers::context::DialogPurpose;
|
||||||
use crate::state::app::buffer::{AppView, BufferState};
|
use crate::state::app::buffer::{AppView, BufferState};
|
||||||
use common::proto::multieko2::auth::AuthResponse;
|
use common::proto::multieko2::auth::AuthResponse;
|
||||||
use anyhow::Result;
|
use anyhow::Context;
|
||||||
|
use tokio::spawn;
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
use tracing::{info, error};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RegisterResult {
|
pub enum RegisterResult {
|
||||||
@@ -18,109 +21,6 @@ pub enum RegisterResult {
|
|||||||
ConnectionError(String),
|
ConnectionError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to register the user using the provided details via gRPC.
|
|
||||||
/// Updates RegisterState and AppState on success or failure.
|
|
||||||
pub async fn save(
|
|
||||||
register_state: &mut RegisterState,
|
|
||||||
auth_client: &mut AuthClient,
|
|
||||||
app_state: &mut AppState,
|
|
||||||
) -> Result<String> {
|
|
||||||
let username = register_state.username.clone();
|
|
||||||
let email = register_state.email.clone();
|
|
||||||
// Handle optional passwords: send None if empty, Some(value) otherwise
|
|
||||||
let password = if register_state.password.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(register_state.password.clone())
|
|
||||||
};
|
|
||||||
let password_confirmation = if register_state.password_confirmation.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(register_state.password_confirmation.clone())
|
|
||||||
};
|
|
||||||
let role = if register_state.role.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(register_state.role.clone())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Basic client-side validation (example)
|
|
||||||
if username.is_empty() {
|
|
||||||
app_state.show_dialog(
|
|
||||||
"Registration Failed",
|
|
||||||
"Username cannot be empty.",
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::RegisterFailed,
|
|
||||||
);
|
|
||||||
register_state.error_message = Some("Username cannot be empty.".to_string());
|
|
||||||
return Ok("Registration failed: Username cannot be empty.".to_string());
|
|
||||||
}
|
|
||||||
if password.is_some() && password != password_confirmation {
|
|
||||||
app_state.show_dialog(
|
|
||||||
"Registration Failed",
|
|
||||||
"Passwords do not match.",
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::RegisterFailed,
|
|
||||||
);
|
|
||||||
register_state.error_message = Some("Passwords do not match.".to_string());
|
|
||||||
return Ok("Registration failed: Passwords do not match.".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Clear previous error/dialog state before attempting
|
|
||||||
register_state.error_message = None;
|
|
||||||
app_state.hide_dialog();
|
|
||||||
|
|
||||||
// Call the gRPC register method
|
|
||||||
match auth_client.register(username, email, password, password_confirmation, role).await {
|
|
||||||
Ok(response) => {
|
|
||||||
// Clear fields on success? Optional, maybe wait for dialog confirmation.
|
|
||||||
// register_state.username.clear();
|
|
||||||
// register_state.email.clear();
|
|
||||||
// register_state.password.clear();
|
|
||||||
// register_state.password_confirmation.clear();
|
|
||||||
register_state.set_has_unsaved_changes(false);
|
|
||||||
|
|
||||||
let success_message = format!(
|
|
||||||
"Registration Successful!\n\n\
|
|
||||||
User ID: {}\n\
|
|
||||||
Username: {}\n\
|
|
||||||
Email: {}\n\
|
|
||||||
Role: {}",
|
|
||||||
response.id,
|
|
||||||
response.username,
|
|
||||||
response.email,
|
|
||||||
response.role
|
|
||||||
);
|
|
||||||
|
|
||||||
// Show success dialog
|
|
||||||
app_state.show_dialog(
|
|
||||||
"Registration Success",
|
|
||||||
&success_message,
|
|
||||||
vec!["OK".to_string()], // Simple OK for now
|
|
||||||
DialogPurpose::RegisterSuccess,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok("Registration successful, details shown in dialog.".to_string())
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
let error_message = format!("{}", e);
|
|
||||||
register_state.error_message = Some(error_message.clone());
|
|
||||||
register_state.set_has_unsaved_changes(true); // Keep changes on error
|
|
||||||
|
|
||||||
// Show error dialog
|
|
||||||
app_state.show_dialog(
|
|
||||||
"Registration Failed",
|
|
||||||
&error_message,
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::RegisterFailed,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(format!("Registration failed: {}", error_message))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clears the registration form fields.
|
/// Clears the registration form fields.
|
||||||
pub async fn revert(
|
pub async fn revert(
|
||||||
register_state: &mut RegisterState,
|
register_state: &mut RegisterState,
|
||||||
@@ -161,3 +61,89 @@ pub async fn back_to_login(
|
|||||||
"Returned to main menu".to_string()
|
"Returned to main menu".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Validates input, shows loading, and spawns the registration task.
|
||||||
|
pub fn initiate_registration(
|
||||||
|
register_state: &RegisterState,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
sender: mpsc::Sender<RegisterResult>,
|
||||||
|
) -> String {
|
||||||
|
// Clone necessary data
|
||||||
|
let username = register_state.username.clone();
|
||||||
|
let email = register_state.email.clone();
|
||||||
|
let password = register_state.password.clone();
|
||||||
|
let password_confirmation = register_state.password_confirmation.clone();
|
||||||
|
let role = register_state.role.clone();
|
||||||
|
|
||||||
|
// 1. Client-side validation
|
||||||
|
if username.trim().is_empty() {
|
||||||
|
app_state.show_dialog("Registration Failed", "Username cannot be empty.", vec!["OK".to_string()], DialogPurpose::RegisterFailed);
|
||||||
|
"Username cannot be empty.".to_string()
|
||||||
|
} else if !password.is_empty() && password != password_confirmation {
|
||||||
|
app_state.show_dialog("Registration Failed", "Passwords do not match.", vec!["OK".to_string()], DialogPurpose::RegisterFailed);
|
||||||
|
"Passwords do not match.".to_string()
|
||||||
|
} else {
|
||||||
|
// 2. Show Loading Dialog
|
||||||
|
app_state.show_loading_dialog("Registering", "Please wait...");
|
||||||
|
|
||||||
|
// 3. Spawn the registration task
|
||||||
|
spawn(async move {
|
||||||
|
let register_outcome = match AuthClient::new().await {
|
||||||
|
Ok(mut auth_client) => {
|
||||||
|
// Handle optional fields correctly for the gRPC call
|
||||||
|
let password_opt = if password.is_empty() { None } else { Some(password) };
|
||||||
|
let password_conf_opt = if password_confirmation.is_empty() { None } else { Some(password_confirmation) };
|
||||||
|
let role_opt = if role.is_empty() { None } else { Some(role) };
|
||||||
|
|
||||||
|
match auth_client.register(username.clone(), email, password_opt, password_conf_opt, role_opt).await
|
||||||
|
.with_context(|| format!("Spawned register task failed for username: {}", username))
|
||||||
|
{
|
||||||
|
Ok(response) => RegisterResult::Success(response),
|
||||||
|
Err(e) => RegisterResult::Failure(format!("{}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => RegisterResult::ConnectionError(format!("Failed to create AuthClient: {}", e)),
|
||||||
|
};
|
||||||
|
// Send result back to the main UI thread
|
||||||
|
if let Err(e) = sender.send(register_outcome).await {
|
||||||
|
error!("Failed to send registration result: {}", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Return immediately
|
||||||
|
"Registration initiated.".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles the result received from the registration task.
|
||||||
|
/// Returns true if a redraw is needed.
|
||||||
|
pub fn handle_registration_result(
|
||||||
|
result: RegisterResult,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
register_state: &mut RegisterState,
|
||||||
|
) -> bool {
|
||||||
|
match result {
|
||||||
|
RegisterResult::Success(response) => {
|
||||||
|
let success_message = format!(
|
||||||
|
"Registration Successful!\n\nUser ID: {}\nUsername: {}\nEmail: {}\nRole: {}",
|
||||||
|
response.id, response.username, response.email, response.role
|
||||||
|
);
|
||||||
|
app_state.update_dialog_content(
|
||||||
|
&success_message,
|
||||||
|
vec!["OK".to_string()],
|
||||||
|
DialogPurpose::RegisterSuccess,
|
||||||
|
);
|
||||||
|
info!(message = %success_message, "Registration successful");
|
||||||
|
}
|
||||||
|
RegisterResult::Failure(err_msg) | RegisterResult::ConnectionError(err_msg) => {
|
||||||
|
app_state.update_dialog_content(
|
||||||
|
&err_msg,
|
||||||
|
vec!["OK".to_string()],
|
||||||
|
DialogPurpose::RegisterFailed,
|
||||||
|
);
|
||||||
|
register_state.error_message = Some(err_msg.clone());
|
||||||
|
error!(error = %err_msg, "Registration failed/connection error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
register_state.set_has_unsaved_changes(false); // Clear flag after processing
|
||||||
|
true // Request redraw as dialog content changed
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
use crate::config::binds::config::Config;
|
use crate::config::binds::config::Config;
|
||||||
use crate::config::colors::themes::Theme;
|
use crate::config::colors::themes::Theme;
|
||||||
use crate::services::grpc_client::GrpcClient;
|
use crate::services::grpc_client::GrpcClient;
|
||||||
// <-- Add AuthClient import
|
|
||||||
use crate::services::ui_service::UiService;
|
use crate::services::ui_service::UiService;
|
||||||
use crate::modes::common::commands::CommandHandler;
|
use crate::modes::common::commands::CommandHandler;
|
||||||
use crate::modes::handlers::event::{EventHandler, EventOutcome};
|
use crate::modes::handlers::event::{EventHandler, EventOutcome};
|
||||||
@@ -18,16 +17,17 @@ use crate::state::pages::intro::IntroState;
|
|||||||
use crate::state::app::buffer::BufferState;
|
use crate::state::app::buffer::BufferState;
|
||||||
use crate::state::app::buffer::AppView;
|
use crate::state::app::buffer::AppView;
|
||||||
use crate::state::app::state::AppState;
|
use crate::state::app::state::AppState;
|
||||||
use crate::ui::handlers::context::DialogPurpose;
|
|
||||||
use crate::tui::terminal::{EventReader, TerminalCore};
|
use crate::tui::terminal::{EventReader, TerminalCore};
|
||||||
use crate::ui::handlers::render::render_ui;
|
use crate::ui::handlers::render::render_ui;
|
||||||
use crate::tui::functions::common::login::LoginResult;
|
use crate::tui::functions::common::login::LoginResult;
|
||||||
use crate::tui::functions::common::register::RegisterResult;
|
use crate::tui::functions::common::register::RegisterResult;
|
||||||
|
use crate::tui::functions::common::login;
|
||||||
|
use crate::tui::functions::common::register;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use crossterm::cursor::SetCursorStyle;
|
use crossterm::cursor::SetCursorStyle;
|
||||||
use crossterm::event as crossterm_event;
|
use crossterm::event as crossterm_event;
|
||||||
use tracing::{info, error};
|
use tracing::error;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
pub async fn run_ui() -> Result<()> {
|
pub async fn run_ui() -> Result<()> {
|
||||||
@@ -191,54 +191,10 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
|
|
||||||
// --- Check for Login Results from Channel ---
|
// --- Check for Login Results from Channel ---
|
||||||
match login_result_receiver.try_recv() {
|
match login_result_receiver.try_recv() {
|
||||||
Ok(login_result) => {
|
Ok(result) => {
|
||||||
// A result arrived from the login task!
|
if login::handle_login_result(result, &mut app_state, &mut auth_state, &mut login_state) {
|
||||||
match login_result {
|
needs_redraw = true;
|
||||||
LoginResult::Success(response) => {
|
|
||||||
// Update AuthState
|
|
||||||
auth_state.auth_token = Some(response.access_token.clone());
|
|
||||||
auth_state.user_id = Some(response.user_id.clone());
|
|
||||||
auth_state.role = Some(response.role.clone());
|
|
||||||
auth_state.decoded_username = Some(response.username.clone());
|
|
||||||
|
|
||||||
// Update Dialog
|
|
||||||
let success_message = format!(
|
|
||||||
"Login Successful!\n\nUsername: {}\nUser ID: {}\nRole: {}",
|
|
||||||
response.username, response.user_id, response.role
|
|
||||||
);
|
|
||||||
// Use update_dialog_content if loading dialog is shown, otherwise show_dialog
|
|
||||||
app_state.update_dialog_content( // Assuming loading dialog was shown
|
|
||||||
&success_message,
|
|
||||||
vec!["Menu".to_string(), "Exit".to_string()],
|
|
||||||
DialogPurpose::LoginSuccess,
|
|
||||||
);
|
|
||||||
info!(message = %success_message, "Login successful");
|
|
||||||
}
|
|
||||||
LoginResult::Failure(err_msg) => {
|
|
||||||
app_state.update_dialog_content( // Update loading dialog
|
|
||||||
&err_msg,
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::LoginFailed,
|
|
||||||
);
|
|
||||||
login_state.error_message = Some(err_msg.clone()); // Keep error message
|
|
||||||
error!(error = %err_msg, "Login failed");
|
|
||||||
}
|
|
||||||
LoginResult::ConnectionError(err_msg) => {
|
|
||||||
app_state.update_dialog_content( // Update loading dialog
|
|
||||||
&err_msg, // Show connection error
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::LoginFailed,
|
|
||||||
);
|
|
||||||
login_state.error_message = Some(err_msg.clone());
|
|
||||||
error!(error = %err_msg, "Login connection error");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Clear login form state regardless of outcome now that it's processed
|
|
||||||
login_state.username.clear();
|
|
||||||
login_state.password.clear();
|
|
||||||
login_state.set_has_unsaved_changes(false);
|
|
||||||
login_state.current_cursor_pos = 0;
|
|
||||||
needs_redraw = true;
|
|
||||||
}
|
}
|
||||||
Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ }
|
Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ }
|
||||||
Err(mpsc::error::TryRecvError::Disconnected) => {
|
Err(mpsc::error::TryRecvError::Disconnected) => {
|
||||||
@@ -249,43 +205,10 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
|
|
||||||
// --- Check for Register Results from Channel ---
|
// --- Check for Register Results from Channel ---
|
||||||
match register_result_receiver.try_recv() {
|
match register_result_receiver.try_recv() {
|
||||||
Ok(register_result) => {
|
Ok(result) => {
|
||||||
// A result arrived from the register task!
|
if register::handle_registration_result(result, &mut app_state, &mut register_state) {
|
||||||
match register_result {
|
needs_redraw = true;
|
||||||
RegisterResult::Success(response) => {
|
|
||||||
// Update Dialog
|
|
||||||
let success_message = format!(
|
|
||||||
"Registration Successful!\n\nUser ID: {}\nUsername: {}\nEmail: {}\nRole: {}",
|
|
||||||
response.id, response.username, response.email, response.role
|
|
||||||
);
|
|
||||||
app_state.update_dialog_content( // Update loading dialog
|
|
||||||
&success_message,
|
|
||||||
vec!["OK".to_string()], // Simple OK for now
|
|
||||||
DialogPurpose::RegisterSuccess,
|
|
||||||
);
|
|
||||||
info!(message = %success_message, "Registration successful");
|
|
||||||
}
|
|
||||||
RegisterResult::Failure(err_msg) => {
|
|
||||||
app_state.update_dialog_content( // Update loading dialog
|
|
||||||
&err_msg,
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::RegisterFailed,
|
|
||||||
);
|
|
||||||
register_state.error_message = Some(err_msg.clone()); // Keep error message
|
|
||||||
error!(error = %err_msg, "Registration failed");
|
|
||||||
}
|
|
||||||
RegisterResult::ConnectionError(err_msg) => {
|
|
||||||
app_state.update_dialog_content( // Update loading dialog
|
|
||||||
&err_msg, // Show connection error
|
|
||||||
vec!["OK".to_string()],
|
|
||||||
DialogPurpose::RegisterFailed, // Still a failure from user perspective
|
|
||||||
);
|
|
||||||
register_state.error_message = Some(err_msg.clone());
|
|
||||||
error!(error = %err_msg, "Registration connection error");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
register_state.set_has_unsaved_changes(false); // Clear unsaved changes flag after processing
|
|
||||||
needs_redraw = true; // Set flag: Register result processed, UI state (dialog) changed
|
|
||||||
}
|
}
|
||||||
Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ }
|
Err(mpsc::error::TryRecvError::Empty) => { /* No message waiting */ }
|
||||||
Err(mpsc::error::TryRecvError::Disconnected) => {
|
Err(mpsc::error::TryRecvError::Disconnected) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user