displaying data properly, fixing hardcoded backend to firma part one
This commit is contained in:
@@ -17,28 +17,29 @@ pub fn render_form(
|
||||
fields: &[&str],
|
||||
current_field_idx: &usize,
|
||||
inputs: &[&String],
|
||||
table_name: &str, // This parameter receives the correct table name
|
||||
theme: &Theme,
|
||||
is_edit_mode: bool,
|
||||
highlight_state: &HighlightState,
|
||||
total_count: u64,
|
||||
current_position: u64,
|
||||
) {
|
||||
// Create Adresar card
|
||||
// Use the dynamic `table_name` parameter for the title instead of a hardcoded string.
|
||||
let card_title = format!(" {} ", table_name);
|
||||
|
||||
let adresar_card = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_style(Style::default().fg(theme.border))
|
||||
.title(" Adresar ")
|
||||
.title(card_title) // Use the dynamic title
|
||||
.style(Style::default().bg(theme.bg).fg(theme.fg));
|
||||
|
||||
f.render_widget(adresar_card, area);
|
||||
|
||||
// Define inner area
|
||||
let inner_area = area.inner(Margin {
|
||||
horizontal: 1,
|
||||
vertical: 1,
|
||||
});
|
||||
|
||||
// Create main layout
|
||||
let main_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
@@ -47,12 +48,11 @@ pub fn render_form(
|
||||
])
|
||||
.split(inner_area);
|
||||
|
||||
// Render count/position
|
||||
let count_position_text = if total_count == 0 && current_position == 1 {
|
||||
"Total: 0 | New Entry".to_string()
|
||||
} else if current_position > total_count && total_count > 0 {
|
||||
format!("Total: {} | New Entry ({})", total_count, current_position)
|
||||
} else if total_count == 0 && current_position > 1 { // Should not happen if logic is correct
|
||||
} else if total_count == 0 && current_position > 1 {
|
||||
format!("Total: 0 | New Entry ({})", current_position)
|
||||
}
|
||||
else {
|
||||
@@ -63,7 +63,6 @@ pub fn render_form(
|
||||
.alignment(Alignment::Left);
|
||||
f.render_widget(count_para, main_layout[0]);
|
||||
|
||||
// Delegate input handling to canvas
|
||||
render_canvas(
|
||||
f,
|
||||
main_layout[1],
|
||||
|
||||
@@ -23,8 +23,6 @@ pub async fn handle_read_only_event(
|
||||
add_table_state: &mut AddTableState,
|
||||
add_logic_state: &mut AddLogicState,
|
||||
key_sequence_tracker: &mut KeySequenceTracker,
|
||||
current_position: &mut u64,
|
||||
total_count: u64,
|
||||
grpc_client: &mut GrpcClient,
|
||||
command_message: &mut String,
|
||||
edit_mode_cooldown: &mut bool,
|
||||
@@ -74,12 +72,10 @@ pub async fn handle_read_only_event(
|
||||
action,
|
||||
form_state,
|
||||
grpc_client,
|
||||
current_position,
|
||||
total_count,
|
||||
ideal_cursor_column,
|
||||
)
|
||||
.await?
|
||||
} else if app_state.ui.show_login && CONTEXT_ACTIONS_LOGIN.contains(&action) { // Handle login context actions
|
||||
} else if app_state.ui.show_login && CONTEXT_ACTIONS_LOGIN.contains(&action) {
|
||||
crate::tui::functions::login::handle_action(action).await?
|
||||
} else if app_state.ui.show_add_table {
|
||||
add_table_ro::execute_action(
|
||||
@@ -143,12 +139,10 @@ pub async fn handle_read_only_event(
|
||||
action,
|
||||
form_state,
|
||||
grpc_client,
|
||||
current_position,
|
||||
total_count,
|
||||
ideal_cursor_column,
|
||||
)
|
||||
.await?
|
||||
} else if app_state.ui.show_login && CONTEXT_ACTIONS_LOGIN.contains(&action) { // Handle login context actions
|
||||
} else if app_state.ui.show_login && CONTEXT_ACTIONS_LOGIN.contains(&action) {
|
||||
crate::tui::functions::login::handle_action(action).await?
|
||||
} else if app_state.ui.show_add_table {
|
||||
add_table_ro::execute_action(
|
||||
@@ -177,7 +171,7 @@ pub async fn handle_read_only_event(
|
||||
key_sequence_tracker,
|
||||
command_message,
|
||||
).await?
|
||||
} else if app_state.ui.show_login { // Handle login general actions
|
||||
} else if app_state.ui.show_login {
|
||||
auth_ro::execute_action(
|
||||
action,
|
||||
app_state,
|
||||
@@ -211,8 +205,6 @@ pub async fn handle_read_only_event(
|
||||
action,
|
||||
form_state,
|
||||
grpc_client,
|
||||
current_position,
|
||||
total_count,
|
||||
ideal_cursor_column,
|
||||
)
|
||||
.await?
|
||||
@@ -245,7 +237,7 @@ pub async fn handle_read_only_event(
|
||||
key_sequence_tracker,
|
||||
command_message,
|
||||
).await?
|
||||
} else if app_state.ui.show_login { // Handle login general actions
|
||||
} else if app_state.ui.show_login {
|
||||
auth_ro::execute_action(
|
||||
action,
|
||||
app_state,
|
||||
|
||||
@@ -338,15 +338,23 @@ impl EventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_position = form_state.current_position;
|
||||
let total_count = form_state.total_count;
|
||||
let (_should_exit, message) = read_only::handle_read_only_event(
|
||||
app_state, key_event, config, form_state, login_state, register_state,
|
||||
&mut admin_state.add_table_state, &mut admin_state.add_logic_state,
|
||||
&mut self.key_sequence_tracker, &mut current_position, total_count,
|
||||
grpc_client, &mut self.command_message, &mut self.edit_mode_cooldown,
|
||||
app_state,
|
||||
key_event,
|
||||
config,
|
||||
form_state,
|
||||
login_state,
|
||||
register_state,
|
||||
&mut admin_state.add_table_state,
|
||||
&mut admin_state.add_logic_state,
|
||||
&mut self.key_sequence_tracker,
|
||||
// No more current_position or total_count arguments
|
||||
grpc_client,
|
||||
&mut self.command_message,
|
||||
&mut self.edit_mode_cooldown,
|
||||
&mut self.ideal_cursor_column,
|
||||
).await?;
|
||||
)
|
||||
.await?;
|
||||
return Ok(EventOutcome::Ok(message));
|
||||
}
|
||||
|
||||
@@ -365,15 +373,22 @@ impl EventHandler {
|
||||
return Ok(EventOutcome::Ok("".to_string()));
|
||||
}
|
||||
|
||||
let mut current_position = form_state.current_position;
|
||||
let total_count = form_state.total_count;
|
||||
let (_should_exit, message) = read_only::handle_read_only_event(
|
||||
app_state, key_event, config, form_state, login_state, register_state,
|
||||
&mut admin_state.add_table_state, &mut admin_state.add_logic_state,
|
||||
&mut self.key_sequence_tracker, &mut current_position, total_count,
|
||||
grpc_client, &mut self.command_message, &mut self.edit_mode_cooldown,
|
||||
app_state,
|
||||
key_event,
|
||||
config,
|
||||
form_state,
|
||||
login_state,
|
||||
register_state,
|
||||
&mut admin_state.add_table_state,
|
||||
&mut admin_state.add_logic_state,
|
||||
&mut self.key_sequence_tracker,
|
||||
grpc_client,
|
||||
&mut self.command_message,
|
||||
&mut self.edit_mode_cooldown,
|
||||
&mut self.ideal_cursor_column,
|
||||
).await?;
|
||||
)
|
||||
.await?;
|
||||
return Ok(EventOutcome::Ok(message));
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ pub async fn handle_highlight_event(
|
||||
&mut admin_state.add_table_state,
|
||||
&mut admin_state.add_logic_state,
|
||||
key_sequence_tracker,
|
||||
current_position,
|
||||
total_count,
|
||||
grpc_client,
|
||||
command_message, // Pass the message buffer
|
||||
edit_mode_cooldown,
|
||||
|
||||
@@ -161,7 +161,7 @@ impl UiService {
|
||||
form_state.total_count = total_count;
|
||||
|
||||
if total_count > 0 {
|
||||
form_state.current_position = 1;
|
||||
form_state.current_position = total_count;
|
||||
} else {
|
||||
form_state.current_position = 1;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ impl FormState {
|
||||
theme: &Theme,
|
||||
is_edit_mode: bool,
|
||||
highlight_state: &HighlightState,
|
||||
// total_count and current_position are now part of self
|
||||
) {
|
||||
let fields_str_slice: Vec<&str> =
|
||||
self.fields.iter().map(|s| s.as_str()).collect();
|
||||
@@ -64,6 +63,7 @@ impl FormState {
|
||||
&fields_str_slice,
|
||||
&self.current_field,
|
||||
&values_str_slice,
|
||||
&self.table_name,
|
||||
theme,
|
||||
is_edit_mode,
|
||||
highlight_state,
|
||||
@@ -107,33 +107,35 @@ impl FormState {
|
||||
&mut self,
|
||||
response_data: &HashMap<String, String>,
|
||||
) {
|
||||
self.values = self.fields.iter()
|
||||
.map(|field| response_data.get(field).cloned().unwrap_or_default())
|
||||
.collect();
|
||||
// Create a new vector for the values, ensuring they are in the correct order.
|
||||
self.values = self.fields.iter().map(|field_from_schema| {
|
||||
// For each field from our schema, find the corresponding key in the
|
||||
// response data by doing a case-insensitive comparison.
|
||||
response_data
|
||||
.iter()
|
||||
.find(|(key_from_data, _)| key_from_data.eq_ignore_ascii_case(field_from_schema))
|
||||
.map(|(_, value)| value.clone()) // If found, clone its value.
|
||||
.unwrap_or_default() // If not found, use an empty string.
|
||||
}).collect();
|
||||
|
||||
if let Some(id_str) = response_data.get("id") {
|
||||
match id_str.parse::<i64>() {
|
||||
Ok(parsed_id) => self.id = parsed_id,
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"Failed to parse 'id' field '{}' for table {}.{}: {}",
|
||||
id_str,
|
||||
self.profile_name,
|
||||
self.table_name,
|
||||
e
|
||||
);
|
||||
self.id = 0; // Default to 0 if parsing fails
|
||||
}
|
||||
// Now, do the same case-insensitive lookup for the 'id' field.
|
||||
let id_str_opt = response_data
|
||||
.iter()
|
||||
.find(|(k, _)| k.eq_ignore_ascii_case("id"))
|
||||
.map(|(_, v)| v);
|
||||
|
||||
if let Some(id_str) = id_str_opt {
|
||||
if let Ok(parsed_id) = id_str.parse::<i64>() {
|
||||
self.id = parsed_id;
|
||||
} else {
|
||||
tracing::error!( "Failed to parse 'id' field '{}' for table {}.{}", id_str, self.profile_name, self.table_name);
|
||||
self.id = 0;
|
||||
}
|
||||
} else {
|
||||
// If no ID is present, it might be a new record structure or an error
|
||||
// For now, assume it means the record doesn't have an ID from the server yet
|
||||
self.id = 0;
|
||||
}
|
||||
|
||||
self.has_unsaved_changes = false;
|
||||
// current_field and current_cursor_pos might need resetting or adjusting
|
||||
// depending on the desired behavior after loading data.
|
||||
// For now, let's reset current_field to 0.
|
||||
self.current_field = 0;
|
||||
self.current_cursor_pos = 0;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
// src/tui/functions/form.rs
|
||||
use crate::state::pages::canvas_state::CanvasState; // Import the trait
|
||||
use crate::state::pages::form::FormState;
|
||||
use crate::services::grpc_client::GrpcClient;
|
||||
use crate::state::pages::canvas_state::CanvasState;
|
||||
use crate::services::ui_service::UiService;
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
pub async fn handle_action(
|
||||
action: &str,
|
||||
form_state: &mut FormState,
|
||||
grpc_client: &mut GrpcClient,
|
||||
current_position: &mut u64,
|
||||
total_count: u64,
|
||||
_grpc_client: &mut GrpcClient,
|
||||
ideal_cursor_column: &mut usize,
|
||||
) -> Result<String> {
|
||||
// Check for unsaved changes in both cases
|
||||
// FIX: Call has_unsaved_changes() via the CanvasState trait.
|
||||
if form_state.has_unsaved_changes() {
|
||||
return Ok(
|
||||
"Unsaved changes. Save (Ctrl+S) or Revert (Ctrl+R) before navigating."
|
||||
@@ -21,56 +18,31 @@ pub async fn handle_action(
|
||||
);
|
||||
}
|
||||
|
||||
let total_count = form_state.total_count;
|
||||
|
||||
match action {
|
||||
"previous_entry" => {
|
||||
let new_position = form_state.current_position.saturating_sub(1);
|
||||
if new_position >= 1 {
|
||||
form_state.current_position = new_position;
|
||||
*current_position = new_position;
|
||||
|
||||
if new_position <= form_state.total_count {
|
||||
let load_message = UiService::load_table_data_by_position(grpc_client, form_state).await?;
|
||||
|
||||
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 = (*ideal_cursor_column).min(max_cursor_pos);
|
||||
|
||||
Ok(load_message)
|
||||
if total_count > 0 {
|
||||
if form_state.current_position > 1 {
|
||||
form_state.current_position -= 1;
|
||||
} else {
|
||||
Ok(format!("Moved to position {}", new_position))
|
||||
form_state.current_position = total_count;
|
||||
}
|
||||
} else {
|
||||
Ok("Already at first position".into())
|
||||
*ideal_cursor_column = 0;
|
||||
}
|
||||
}
|
||||
"next_entry" => {
|
||||
if form_state.current_position <= form_state.total_count {
|
||||
form_state.current_position += 1;
|
||||
*current_position = form_state.current_position;
|
||||
|
||||
if form_state.current_position <= form_state.total_count {
|
||||
let load_message = UiService::load_table_data_by_position(grpc_client, form_state).await?;
|
||||
|
||||
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 = (*ideal_cursor_column).min(max_cursor_pos);
|
||||
|
||||
Ok(load_message)
|
||||
if total_count > 0 {
|
||||
if form_state.current_position < total_count {
|
||||
form_state.current_position += 1;
|
||||
} else {
|
||||
form_state.reset_to_empty();
|
||||
form_state.current_field = 0;
|
||||
form_state.current_cursor_pos = 0;
|
||||
*ideal_cursor_column = 0;
|
||||
Ok("New form entry mode".into())
|
||||
form_state.current_position = 1;
|
||||
}
|
||||
} else {
|
||||
Ok("Already at last entry".into())
|
||||
*ideal_cursor_column = 0;
|
||||
}
|
||||
}
|
||||
_ => Err(anyhow!("Unknown form action: {}", action))
|
||||
_ => return Err(anyhow!("Unknown form action: {}", action)),
|
||||
}
|
||||
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ pub fn render_ui(
|
||||
f, app_state, auth_state, admin_state, main_content_area, theme,
|
||||
&app_state.profile_tree, &app_state.selected_profile,
|
||||
);
|
||||
|
||||
} else if app_state.ui.show_form {
|
||||
let (sidebar_area, form_actual_area) = calculate_sidebar_layout(
|
||||
app_state.ui.show_sidebar, main_content_area
|
||||
@@ -158,12 +159,24 @@ pub fn render_ui(
|
||||
};
|
||||
let fields_vec: Vec<&str> = form_state.fields.iter().map(AsRef::as_ref).collect();
|
||||
let values_vec: Vec<&String> = form_state.values.iter().collect();
|
||||
|
||||
// --- START FIX ---
|
||||
// Add the missing `&form_state.table_name` argument to this function call.
|
||||
render_form(
|
||||
f, form_render_area, form_state, &fields_vec, &form_state.current_field,
|
||||
&values_vec, theme, is_event_handler_edit_mode, highlight_state,
|
||||
f,
|
||||
form_render_area,
|
||||
form_state,
|
||||
&fields_vec,
|
||||
&form_state.current_field,
|
||||
&values_vec,
|
||||
&form_state.table_name, // <-- THIS ARGUMENT WAS MISSING
|
||||
theme,
|
||||
is_event_handler_edit_mode,
|
||||
highlight_state,
|
||||
form_state.total_count,
|
||||
form_state.current_position,
|
||||
);
|
||||
// --- END FIX ---
|
||||
}
|
||||
|
||||
if let Some(area) = buffer_list_area {
|
||||
|
||||
@@ -56,7 +56,6 @@ pub async fn get_table_data(
|
||||
let system_columns = vec![
|
||||
("id".to_string(), "BIGINT".to_string()),
|
||||
("deleted".to_string(), "BOOLEAN".to_string()),
|
||||
("firma".to_string(), "TEXT".to_string()),
|
||||
];
|
||||
let all_columns: Vec<(String, String)> = system_columns
|
||||
.into_iter()
|
||||
|
||||
@@ -19,19 +19,11 @@ pub async fn post_table_data(
|
||||
let table_name = request.table_name;
|
||||
let mut data = HashMap::new();
|
||||
|
||||
// Process and validate all data values
|
||||
// CORRECTED: Process and trim all incoming data values.
|
||||
// We remove the hardcoded validation. We will let the database's
|
||||
// NOT NULL constraints or Steel validation scripts handle required fields.
|
||||
for (key, value) in request.data {
|
||||
let trimmed = value.trim().to_string();
|
||||
|
||||
// Handle specially - it cannot be empty
|
||||
if trimmed.is_empty() {
|
||||
return Err(Status::invalid_argument("Firma cannot be empty"));
|
||||
}
|
||||
|
||||
// Add trimmed non-empty values to data map
|
||||
if !trimmed.is_empty() {
|
||||
data.insert(key, trimmed);
|
||||
}
|
||||
data.insert(key, value.trim().to_string());
|
||||
}
|
||||
|
||||
// Lookup profile
|
||||
|
||||
Reference in New Issue
Block a user