dropdown is being triggered
This commit is contained in:
@@ -1,30 +1,44 @@
|
||||
// src/state/pages/form.rs
|
||||
|
||||
use std::collections::HashMap;
|
||||
use crate::config::colors::themes::Theme;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::Frame;
|
||||
use crate::state::app::highlight::HighlightState;
|
||||
use crate::state::pages::canvas_state::CanvasState;
|
||||
use ratatui::layout::Rect;
|
||||
use ratatui::Frame;
|
||||
use std::collections::HashMap;
|
||||
|
||||
// A struct to bridge the display name (label) to the data key from the server.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FieldDefinition {
|
||||
pub display_name: String,
|
||||
pub data_key: String,
|
||||
pub is_link: bool, // --- NEW --- To identify FK fields
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FormState {
|
||||
pub id: i64,
|
||||
pub profile_name: String,
|
||||
pub table_name: String,
|
||||
pub total_count: u64,
|
||||
pub current_position: u64,
|
||||
pub fields: Vec<String>,
|
||||
pub fields: Vec<FieldDefinition>,
|
||||
pub values: Vec<String>,
|
||||
pub current_field: usize,
|
||||
pub has_unsaved_changes: bool,
|
||||
pub current_cursor_pos: usize,
|
||||
|
||||
// --- NEW AUTOCOMPLETE STATE ---
|
||||
pub autocomplete_active: bool,
|
||||
pub autocomplete_suggestions: Vec<String>,
|
||||
pub selected_suggestion_index: Option<usize>,
|
||||
}
|
||||
|
||||
impl FormState {
|
||||
pub fn new(
|
||||
profile_name: String,
|
||||
table_name: String,
|
||||
fields: Vec<String>,
|
||||
fields: Vec<FieldDefinition>,
|
||||
) -> Self {
|
||||
let values = vec![String::new(); fields.len()];
|
||||
FormState {
|
||||
@@ -38,10 +52,13 @@ impl FormState {
|
||||
current_field: 0,
|
||||
has_unsaved_changes: false,
|
||||
current_cursor_pos: 0,
|
||||
// --- INITIALIZE NEW STATE ---
|
||||
autocomplete_active: false,
|
||||
autocomplete_suggestions: Vec::new(),
|
||||
selected_suggestion_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
// This signature is now correct and only deals with form-related state.
|
||||
pub fn render(
|
||||
&self,
|
||||
f: &mut Frame,
|
||||
@@ -51,13 +68,13 @@ impl FormState {
|
||||
highlight_state: &HighlightState,
|
||||
) {
|
||||
let fields_str_slice: Vec<&str> =
|
||||
self.fields.iter().map(|s| s.as_str()).collect();
|
||||
self.fields().iter().map(|s| *s).collect();
|
||||
let values_str_slice: Vec<&String> = self.values.iter().collect();
|
||||
|
||||
crate::components::form::form::render_form(
|
||||
f,
|
||||
area,
|
||||
self,
|
||||
self, // <--- This now correctly passes the concrete &FormState
|
||||
&fields_str_slice,
|
||||
&self.current_field,
|
||||
&values_str_slice,
|
||||
@@ -70,7 +87,6 @@ impl FormState {
|
||||
);
|
||||
}
|
||||
|
||||
// ... other methods are unchanged ...
|
||||
pub fn reset_to_empty(&mut self) {
|
||||
self.id = 0;
|
||||
self.values.iter_mut().for_each(|v| v.clear());
|
||||
@@ -82,6 +98,7 @@ impl FormState {
|
||||
} else {
|
||||
self.current_position = 1;
|
||||
}
|
||||
self.deactivate_autocomplete(); // Deactivate on reset
|
||||
}
|
||||
|
||||
pub fn get_current_input(&self) -> &str {
|
||||
@@ -102,13 +119,16 @@ impl FormState {
|
||||
response_data: &HashMap<String, String>,
|
||||
new_position: u64,
|
||||
) {
|
||||
self.values = self.fields.iter().map(|field_from_schema| {
|
||||
response_data
|
||||
.iter()
|
||||
.find(|(key_from_data, _)| key_from_data.eq_ignore_ascii_case(field_from_schema))
|
||||
.map(|(_, value)| value.clone())
|
||||
.unwrap_or_default()
|
||||
}).collect();
|
||||
self.values = self
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field_def| {
|
||||
response_data
|
||||
.get(&field_def.data_key)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let id_str_opt = response_data
|
||||
.iter()
|
||||
@@ -119,7 +139,12 @@ impl FormState {
|
||||
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);
|
||||
tracing::error!(
|
||||
"Failed to parse 'id' field '{}' for table {}.{}",
|
||||
id_str,
|
||||
self.profile_name,
|
||||
self.table_name
|
||||
);
|
||||
self.id = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -130,6 +155,15 @@ impl FormState {
|
||||
self.has_unsaved_changes = false;
|
||||
self.current_field = 0;
|
||||
self.current_cursor_pos = 0;
|
||||
self.deactivate_autocomplete(); // Deactivate on update
|
||||
}
|
||||
|
||||
// --- NEW HELPER METHOD ---
|
||||
/// Deactivates autocomplete and clears its state.
|
||||
pub fn deactivate_autocomplete(&mut self) {
|
||||
self.autocomplete_active = false;
|
||||
self.autocomplete_suggestions.clear();
|
||||
self.selected_suggestion_index = None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,13 +193,18 @@ impl CanvasState for FormState {
|
||||
}
|
||||
|
||||
fn fields(&self) -> Vec<&str> {
|
||||
self.fields.iter().map(|s| s.as_str()).collect()
|
||||
self.fields
|
||||
.iter()
|
||||
.map(|f| f.display_name.as_str())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn set_current_field(&mut self, index: usize) {
|
||||
if index < self.fields.len() {
|
||||
self.current_field = index;
|
||||
}
|
||||
// Deactivate autocomplete when changing fields
|
||||
self.deactivate_autocomplete();
|
||||
}
|
||||
|
||||
fn set_current_cursor_pos(&mut self, pos: usize) {
|
||||
@@ -176,11 +215,20 @@ impl CanvasState for FormState {
|
||||
self.has_unsaved_changes = changed;
|
||||
}
|
||||
|
||||
// --- MODIFIED: Implement autocomplete trait methods ---
|
||||
fn get_suggestions(&self) -> Option<&[String]> {
|
||||
None
|
||||
if self.autocomplete_active {
|
||||
Some(&self.autocomplete_suggestions)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_selected_suggestion_index(&self) -> Option<usize> {
|
||||
None
|
||||
if self.autocomplete_active {
|
||||
self.selected_suggestion_index
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user