hardcoded adresar to general form
This commit is contained in:
@@ -47,8 +47,6 @@ pub fn render_ui(
|
||||
event_handler_command_mode_active: bool,
|
||||
event_handler_command_message: &str,
|
||||
navigation_state: &NavigationState,
|
||||
total_count: u64,
|
||||
current_position: u64,
|
||||
current_dir: &str,
|
||||
current_fps: f64,
|
||||
app_state: &AppState,
|
||||
@@ -163,7 +161,6 @@ pub fn render_ui(
|
||||
render_form(
|
||||
f, form_render_area, form_state, &fields_vec, &form_state.current_field,
|
||||
&values_vec, theme, is_event_handler_edit_mode, highlight_state,
|
||||
total_count, current_position,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// client/src/ui/handlers/ui.rs
|
||||
// src/ui/handlers/ui.rs
|
||||
|
||||
use crate::config::binds::config::Config;
|
||||
use crate::config::colors::themes::Theme;
|
||||
@@ -27,36 +27,32 @@ use crate::ui::handlers::context::DialogPurpose;
|
||||
use crate::tui::functions::common::login;
|
||||
use crate::tui::functions::common::register;
|
||||
use std::time::Instant;
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use crossterm::cursor::SetCursorStyle;
|
||||
use crossterm::event as crossterm_event;
|
||||
use tracing::{error, info, warn};
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
|
||||
pub async fn run_ui() -> Result<()> {
|
||||
let config = Config::load().context("Failed to load configuration")?;
|
||||
let theme = Theme::from_str(&config.colors.theme);
|
||||
let mut terminal = TerminalCore::new().context("Failed to initialize terminal")?;
|
||||
let mut grpc_client = GrpcClient::new().await?;
|
||||
let mut grpc_client = GrpcClient::new().await.context("Failed to create GrpcClient")?;
|
||||
let mut command_handler = CommandHandler::new();
|
||||
|
||||
|
||||
let (login_result_sender, mut login_result_receiver) =
|
||||
mpsc::channel::<LoginResult>(1);
|
||||
let (register_result_sender, mut register_result_receiver) =
|
||||
mpsc::channel::<RegisterResult>(1);
|
||||
let (save_table_result_sender, mut save_table_result_receiver) =
|
||||
mpsc::channel::<Result<String>>(1);
|
||||
let (save_logic_result_sender, _save_logic_result_receiver) =
|
||||
mpsc::channel::<Result<String>>(1);
|
||||
let (login_result_sender, mut login_result_receiver) = mpsc::channel::<LoginResult>(1);
|
||||
let (register_result_sender, mut register_result_receiver) = mpsc::channel::<RegisterResult>(1);
|
||||
let (save_table_result_sender, mut save_table_result_receiver) = mpsc::channel::<Result<String>>(1);
|
||||
let (save_logic_result_sender, _save_logic_result_receiver) = mpsc::channel::<Result<String>>(1);
|
||||
|
||||
let mut event_handler = EventHandler::new(
|
||||
login_result_sender.clone(),
|
||||
register_result_sender.clone(),
|
||||
save_table_result_sender.clone(),
|
||||
save_logic_result_sender.clone(),
|
||||
).await.context("Failed to create event handler")?;
|
||||
)
|
||||
.await
|
||||
.context("Failed to create event handler")?;
|
||||
let event_reader = EventReader::new();
|
||||
|
||||
let mut auth_state = AuthState::default();
|
||||
@@ -67,7 +63,6 @@ pub async fn run_ui() -> Result<()> {
|
||||
let mut buffer_state = BufferState::default();
|
||||
let mut app_state = AppState::new().context("Failed to create initial app state")?;
|
||||
|
||||
|
||||
let mut auto_logged_in = false;
|
||||
match load_auth_data() {
|
||||
Ok(Some(stored_data)) => {
|
||||
@@ -86,14 +81,33 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize AppState and FormState with table data
|
||||
let (initial_profile, initial_table, initial_columns) =
|
||||
UiService::initialize_app_state_and_form(&mut grpc_client, &mut app_state)
|
||||
.await
|
||||
.context("Failed to initialize app state and form")?;
|
||||
|
||||
let column_names =
|
||||
UiService::initialize_app_state(&mut grpc_client, &mut app_state)
|
||||
.await.context("Failed to initialize app state from UI service")?;
|
||||
let mut form_state = FormState::new(column_names);
|
||||
let mut form_state = FormState::new(
|
||||
initial_profile.clone(),
|
||||
initial_table.clone(),
|
||||
initial_columns,
|
||||
);
|
||||
|
||||
UiService::initialize_adresar_count(&mut grpc_client, &mut app_state).await?;
|
||||
form_state.reset_to_empty();
|
||||
UiService::fetch_and_set_table_count(&mut grpc_client, &mut form_state)
|
||||
.await
|
||||
.context(format!(
|
||||
"Failed to fetch initial count for table {}.{}",
|
||||
initial_profile, initial_table
|
||||
))?;
|
||||
|
||||
// Load initial data for the form
|
||||
if form_state.total_count > 0 {
|
||||
if let Err(e) = UiService::load_table_data_by_position(&mut grpc_client, &mut form_state).await {
|
||||
event_handler.command_message = format!("Error loading initial data: {}", e);
|
||||
}
|
||||
} else {
|
||||
form_state.reset_to_empty();
|
||||
}
|
||||
|
||||
if auto_logged_in {
|
||||
buffer_state.history = vec![AppView::Form];
|
||||
@@ -104,9 +118,10 @@ pub async fn run_ui() -> Result<()> {
|
||||
let mut last_frame_time = Instant::now();
|
||||
let mut current_fps = 0.0;
|
||||
let mut needs_redraw = true;
|
||||
let mut prev_view_profile_name = app_state.current_view_profile_name.clone();
|
||||
let mut prev_view_table_name = app_state.current_view_table_name.clone();
|
||||
|
||||
loop {
|
||||
|
||||
if let Some(active_view) = buffer_state.get_active_view() {
|
||||
app_state.ui.show_intro = false;
|
||||
app_state.ui.show_login = false;
|
||||
@@ -154,14 +169,53 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle table change for FormView
|
||||
if app_state.ui.show_form {
|
||||
let current_view_profile = app_state.current_view_profile_name.clone();
|
||||
let current_view_table = app_state.current_view_table_name.clone();
|
||||
|
||||
if prev_view_profile_name != current_view_profile || prev_view_table_name != current_view_table {
|
||||
if let (Some(prof_name), Some(tbl_name)) = (current_view_profile.as_ref(), current_view_table.as_ref()) {
|
||||
app_state.show_loading_dialog("Loading Table", &format!("Fetching data for {}.{}...", prof_name, tbl_name));
|
||||
needs_redraw = true;
|
||||
|
||||
match grpc_client.get_table_structure(prof_name.clone(), tbl_name.clone()).await {
|
||||
Ok(structure_response) => {
|
||||
let new_columns: Vec<String> = structure_response.columns.iter().map(|c| c.name.clone()).collect();
|
||||
form_state = FormState::new(prof_name.clone(), tbl_name.clone(), new_columns);
|
||||
|
||||
if let Err(e) = UiService::fetch_and_set_table_count(&mut grpc_client, &mut form_state).await {
|
||||
app_state.update_dialog_content(&format!("Error fetching count: {}", e), vec!["OK".to_string()], DialogPurpose::LoginFailed);
|
||||
} else {
|
||||
if form_state.total_count > 0 {
|
||||
if let Err(e) = UiService::load_table_data_by_position(&mut grpc_client, &mut form_state).await {
|
||||
app_state.update_dialog_content(&format!("Error loading data: {}", e), vec!["OK".to_string()], DialogPurpose::LoginFailed);
|
||||
} else {
|
||||
app_state.hide_dialog();
|
||||
}
|
||||
} else {
|
||||
form_state.reset_to_empty();
|
||||
app_state.hide_dialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
app_state.update_dialog_content(&format!("Error fetching table structure: {}", e), vec!["OK".to_string()], DialogPurpose::LoginFailed);
|
||||
app_state.current_view_profile_name = prev_view_profile_name.clone();
|
||||
app_state.current_view_table_name = prev_view_table_name.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_view_profile_name = current_view_profile;
|
||||
prev_view_table_name = current_view_table;
|
||||
needs_redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((profile_name, table_name)) = app_state.pending_table_structure_fetch.take() {
|
||||
if app_state.ui.show_add_logic {
|
||||
|
||||
if admin_state.add_logic_state.profile_name == profile_name &&
|
||||
admin_state.add_logic_state.selected_table_name.as_deref() == Some(table_name.as_str()) {
|
||||
|
||||
info!("Fetching table structure for {}.{}", profile_name, table_name);
|
||||
let fetch_message = UiService::initialize_add_logic_table_data(
|
||||
&mut grpc_client,
|
||||
@@ -194,7 +248,6 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if needs_redraw {
|
||||
terminal.draw(|f| {
|
||||
render_ui(
|
||||
@@ -213,9 +266,6 @@ pub async fn run_ui() -> Result<()> {
|
||||
event_handler.command_mode,
|
||||
&event_handler.command_message,
|
||||
&event_handler.navigation_state,
|
||||
|
||||
app_state.total_count,
|
||||
app_state.current_position,
|
||||
&app_state.current_dir,
|
||||
current_fps,
|
||||
&app_state,
|
||||
@@ -224,11 +274,10 @@ pub async fn run_ui() -> Result<()> {
|
||||
needs_redraw = false;
|
||||
}
|
||||
|
||||
|
||||
if let Some(table_name) = admin_state.add_logic_state.script_editor_awaiting_column_autocomplete.clone() {
|
||||
if app_state.ui.show_add_logic {
|
||||
let profile_name = admin_state.add_logic_state.profile_name.clone();
|
||||
|
||||
|
||||
info!("Fetching columns for table selection: {}.{}", profile_name, table_name);
|
||||
match UiService::fetch_columns_for_table(&mut grpc_client, &profile_name, &table_name).await {
|
||||
Ok(columns) => {
|
||||
@@ -247,7 +296,6 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let current_mode = ModeManager::derive_mode(&app_state, &event_handler, &admin_state);
|
||||
match current_mode {
|
||||
AppMode::Edit => { terminal.show_cursor()?; }
|
||||
@@ -264,15 +312,12 @@ pub async fn run_ui() -> Result<()> {
|
||||
AppMode::Command => { terminal.set_cursor_style(SetCursorStyle::SteadyUnderScore)?; terminal.show_cursor().context("Failed to show cursor in Command mode")?; }
|
||||
}
|
||||
|
||||
let position_before_event = form_state.current_position;
|
||||
|
||||
let total_count = app_state.total_count;
|
||||
let mut current_position = app_state.current_position;
|
||||
let position_before_event = current_position;
|
||||
if app_state.ui.dialog.is_loading {
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
|
||||
let mut event_outcome_result = Ok(EventOutcome::Ok(String::new()));
|
||||
let mut event_processed = false;
|
||||
if crossterm_event::poll(std::time::Duration::from_millis(1))? {
|
||||
@@ -292,16 +337,12 @@ pub async fn run_ui() -> Result<()> {
|
||||
&mut admin_state,
|
||||
&mut buffer_state,
|
||||
&mut app_state,
|
||||
total_count,
|
||||
&mut current_position,
|
||||
).await;
|
||||
}
|
||||
|
||||
if event_processed {
|
||||
needs_redraw = true;
|
||||
}
|
||||
app_state.current_position = current_position;
|
||||
|
||||
|
||||
match login_result_receiver.try_recv() {
|
||||
Ok(result) => {
|
||||
@@ -315,7 +356,6 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
match register_result_receiver.try_recv() {
|
||||
Ok(result) => {
|
||||
if register::handle_registration_result(result, &mut app_state, &mut register_state) {
|
||||
@@ -353,7 +393,6 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let mut should_exit = false;
|
||||
match event_outcome_result {
|
||||
Ok(outcome) => match outcome {
|
||||
@@ -383,68 +422,86 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let position_changed = app_state.current_position != position_before_event;
|
||||
let current_total_count = app_state.total_count;
|
||||
// --- MODIFIED: Position Change Handling (operates on form_state) ---
|
||||
let position_changed = form_state.current_position != position_before_event;
|
||||
let mut position_logic_needs_redraw = false;
|
||||
|
||||
if app_state.ui.show_form {
|
||||
if app_state.ui.show_form { // Only if the form is active
|
||||
if position_changed && !event_handler.is_edit_mode {
|
||||
let current_input = form_state.get_current_input();
|
||||
let max_cursor_pos = if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
// This part is okay: update cursor for the current field BEFORE loading new data
|
||||
let current_input_before_load = form_state.get_current_input();
|
||||
let max_cursor_pos_before_load = if !current_input_before_load.is_empty() { current_input_before_load.chars().count() } else { 0 };
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos_before_load);
|
||||
position_logic_needs_redraw = true;
|
||||
|
||||
if app_state.current_position > current_total_count + 1 {
|
||||
app_state.current_position = current_total_count + 1;
|
||||
// Validate new form_state.current_position
|
||||
if form_state.total_count > 0 && form_state.current_position > form_state.total_count + 1 {
|
||||
form_state.current_position = form_state.total_count + 1; // Cap at new entry
|
||||
} else if form_state.total_count == 0 && form_state.current_position > 1 {
|
||||
form_state.current_position = 1; // Cap at new entry for empty table
|
||||
}
|
||||
if form_state.current_position == 0 && form_state.total_count > 0 {
|
||||
form_state.current_position = 1; // Don't allow 0 if there are records
|
||||
}
|
||||
|
||||
if app_state.current_position > current_total_count {
|
||||
form_state.reset_to_empty();
|
||||
form_state.current_field = 0;
|
||||
} else if app_state.current_position >= 1 && app_state.current_position <= current_total_count {
|
||||
let current_position_to_load = app_state.current_position;
|
||||
let load_message = UiService::load_adresar_by_position(
|
||||
&mut grpc_client,
|
||||
&mut app_state,
|
||||
&mut form_state,
|
||||
current_position_to_load,
|
||||
)
|
||||
.await.with_context(|| format!("Failed to load adresar by position: {}", current_position_to_load))?;
|
||||
|
||||
let current_input_after_load = form_state.get_current_input();
|
||||
let max_cursor_pos_after_load = if !event_handler.is_edit_mode && !current_input_after_load.is_empty() {
|
||||
current_input_after_load.len() - 1
|
||||
} else {
|
||||
current_input_after_load.len()
|
||||
};
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos_after_load);
|
||||
|
||||
if !load_message.starts_with("Loaded entry") || event_handler.command_message.is_empty() {
|
||||
event_handler.command_message = load_message;
|
||||
// Load data for the new position OR reset for new entry
|
||||
if (form_state.total_count > 0 && form_state.current_position <= form_state.total_count && form_state.current_position > 0)
|
||||
{
|
||||
// It's an existing record position
|
||||
match UiService::load_table_data_by_position(&mut grpc_client, &mut form_state).await {
|
||||
Ok(load_message) => {
|
||||
if event_handler.command_message.is_empty() || !load_message.starts_with("Error") {
|
||||
event_handler.command_message = load_message;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
event_handler.command_message = format!("Error loading data: {}", e);
|
||||
// Consider what to do with form_state here - maybe revert position or clear form
|
||||
}
|
||||
}
|
||||
} else {
|
||||
app_state.current_position = 1.min(current_total_count + 1);
|
||||
if app_state.current_position > current_total_count {
|
||||
form_state.reset_to_empty();
|
||||
form_state.current_field = 0;
|
||||
}
|
||||
|
||||
// Position indicates a new entry (or table is empty and position is 1)
|
||||
form_state.reset_to_empty(); // This sets id=0, clears values, and sets current_position correctly
|
||||
event_handler.command_message = format!("New entry for {}.{}", form_state.profile_name, form_state.table_name);
|
||||
}
|
||||
} else if !position_changed && !event_handler.is_edit_mode {
|
||||
let current_input = form_state.get_current_input();
|
||||
let max_cursor_pos = if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
|
||||
// NOW, after data is loaded or form is reset, get the current input string and its length
|
||||
let current_input_after_load_str = form_state.get_current_input();
|
||||
let current_input_len_after_load = current_input_after_load_str.chars().count();
|
||||
|
||||
let max_cursor_pos_for_readonly_after_load = if current_input_len_after_load > 0 {
|
||||
current_input_len_after_load.saturating_sub(1)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if event_handler.is_edit_mode {
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(current_input_len_after_load);
|
||||
} else {
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos_for_readonly_after_load);
|
||||
// The check for empty string is implicitly handled by max_cursor_pos_for_readonly_after_load being 0
|
||||
}
|
||||
|
||||
} else if !position_changed && !event_handler.is_edit_mode && app_state.ui.show_form {
|
||||
// Update cursor if not editing and position didn't change (e.g. arrow keys within field)
|
||||
let current_input_str = form_state.get_current_input();
|
||||
let current_input_len = current_input_str.chars().count();
|
||||
let max_cursor_pos = if current_input_len > 0 {
|
||||
current_input_len.saturating_sub(1)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
form_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
}
|
||||
} else if app_state.ui.show_register {
|
||||
if !event_handler.is_edit_mode {
|
||||
if !event_handler.is_edit_mode {
|
||||
let current_input = register_state.get_current_input();
|
||||
let max_cursor_pos = if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
register_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
}
|
||||
} else if app_state.ui.show_login {
|
||||
if !event_handler.is_edit_mode {
|
||||
if !event_handler.is_edit_mode {
|
||||
let current_input = login_state.get_current_input();
|
||||
let max_cursor_pos = if !current_input.is_empty() { current_input.len() - 1 } else { 0 };
|
||||
login_state.current_cursor_pos = event_handler.ideal_cursor_column.min(max_cursor_pos);
|
||||
@@ -455,12 +512,10 @@ pub async fn run_ui() -> Result<()> {
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
|
||||
if should_exit {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
let now = Instant::now();
|
||||
let frame_duration = now.duration_since(last_frame_time);
|
||||
last_frame_time = now;
|
||||
|
||||
Reference in New Issue
Block a user