adding to have multiple forms pages
This commit is contained in:
@@ -7,7 +7,7 @@ pub fn get_view_layer(view: &AppView) -> u8 {
|
||||
match view {
|
||||
AppView::Intro => 1,
|
||||
AppView::Login | AppView::Register | AppView::Admin | AppView::AddTable | AppView::AddLogic => 2,
|
||||
AppView::Form | AppView::Scratch => 3,
|
||||
AppView::Form(_) | AppView::Scratch => 3,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ pub enum AppView {
|
||||
Admin,
|
||||
AddTable,
|
||||
AddLogic,
|
||||
Form,
|
||||
Form(String),
|
||||
Scratch,
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ impl AppView {
|
||||
AppView::Admin => "Admin_Panel",
|
||||
AppView::AddTable => "Add_Table",
|
||||
AppView::AddLogic => "Add_Logic",
|
||||
AppView::Form => "Form",
|
||||
AppView::Form(_) => "Form",
|
||||
AppView::Scratch => "*scratch*",
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ impl AppView {
|
||||
/// Returns the display name with dynamic context (for Form buffers)
|
||||
pub fn display_name_with_context(&self, current_table_name: Option<&str>) -> String {
|
||||
match self {
|
||||
AppView::Form => {
|
||||
AppView::Form(_) => {
|
||||
current_table_name
|
||||
.unwrap_or("Data Form")
|
||||
.to_string()
|
||||
|
||||
@@ -17,7 +17,7 @@ pub async fn save(
|
||||
app_state: &mut AppState,
|
||||
grpc_client: &mut GrpcClient,
|
||||
) -> Result<SaveOutcome> {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if let Some(fs) = app_state.active_form_state_mut(buffer_state) {
|
||||
if !fs.has_unsaved_changes {
|
||||
return Ok(SaveOutcome::NoChange);
|
||||
}
|
||||
@@ -62,7 +62,7 @@ pub async fn save(
|
||||
.context("Failed to post new table data")?;
|
||||
|
||||
if response.success {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if let Some(fs) = app_state.active_form_state_mut(buffer_state) {
|
||||
fs.id = response.inserted_id;
|
||||
fs.total_count += 1;
|
||||
fs.current_position = fs.total_count;
|
||||
@@ -84,7 +84,7 @@ pub async fn save(
|
||||
.context("Failed to put (update) table data")?;
|
||||
|
||||
if response.success {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if let Some(fs) = app_state.active_form_state_mut(buffer_state) {
|
||||
fs.has_unsaved_changes = false;
|
||||
}
|
||||
SaveOutcome::UpdatedExisting
|
||||
@@ -103,7 +103,7 @@ pub async fn revert(
|
||||
app_state: &mut AppState,
|
||||
grpc_client: &mut GrpcClient,
|
||||
) -> Result<String> {
|
||||
if let Some(fs) = app_state.form_state_mut() {
|
||||
if let Some(fs) = app_state.active_form_state_mut(buffer_state) {
|
||||
if fs.id == 0
|
||||
|| (fs.total_count > 0 && fs.current_position > fs.total_count)
|
||||
|| (fs.total_count == 0 && fs.current_position == 1)
|
||||
|
||||
@@ -61,10 +61,9 @@ pub fn render_form_page(
|
||||
f.render_widget(count_para, main_layout[0]);
|
||||
|
||||
// --- FORM RENDERING (Using persistent FormEditor) ---
|
||||
if let Some(editor) = &app_state.form_editor {
|
||||
if let Some(AppView::Form(path)) = buffer_state.get_active_view() {
|
||||
if let Some(editor) = app_state.form_editor.get(path) {
|
||||
let active_field_rect = render_canvas(f, main_layout[1], editor, theme);
|
||||
|
||||
// --- SUGGESTIONS DROPDOWN ---
|
||||
if let Some(active_rect) = active_field_rect {
|
||||
render_suggestions_dropdown(
|
||||
f,
|
||||
@@ -75,4 +74,5 @@ pub fn render_form_page(
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ pub enum Page {
|
||||
Admin(AdminState),
|
||||
AddLogic(AddLogicState),
|
||||
AddTable(AddTableState),
|
||||
Form(FormState),
|
||||
Form(String),
|
||||
}
|
||||
|
||||
pub struct Router {
|
||||
|
||||
@@ -60,7 +60,7 @@ pub struct AppState {
|
||||
// UI preferences
|
||||
pub ui: UiState,
|
||||
|
||||
pub form_editor: Option<FormEditor<FormState>>,
|
||||
pub form_editor: HashMap<String, FormEditor<FormState>>, // key = "profile/table"
|
||||
|
||||
#[cfg(feature = "ui-debug")]
|
||||
pub debug_state: Option<DebugState>,
|
||||
@@ -81,7 +81,7 @@ impl AppState {
|
||||
pending_table_structure_fetch: None,
|
||||
search_state: None,
|
||||
ui: UiState::default(),
|
||||
form_editor: None,
|
||||
form_editor: HashMap::new(),
|
||||
|
||||
#[cfg(feature = "ui-debug")]
|
||||
debug_state: None,
|
||||
@@ -99,32 +99,28 @@ impl AppState {
|
||||
self.current_view_table_name = Some(table_name);
|
||||
}
|
||||
|
||||
pub fn init_form_editor(&mut self, form_state: FormState, config: &Config) {
|
||||
let mut editor = FormEditor::new(form_state);
|
||||
editor.set_keymap(config.build_canvas_keymap()); // inject keymap
|
||||
self.form_editor = Some(editor);
|
||||
}
|
||||
|
||||
/// Replace the current form state and wrap it in a FormEditor with keymap
|
||||
pub fn set_form_state(&mut self, form_state: FormState, config: &Config) {
|
||||
let mut editor = FormEditor::new(form_state);
|
||||
editor.set_keymap(config.build_canvas_keymap());
|
||||
self.form_editor = Some(editor);
|
||||
}
|
||||
|
||||
/// Immutable access to the underlying FormState
|
||||
pub fn form_state(&self) -> Option<&FormState> {
|
||||
self.form_editor.as_ref().map(|e| e.data_provider())
|
||||
}
|
||||
|
||||
/// Mutable access to the underlying FormState
|
||||
pub fn form_state_mut(&mut self) -> Option<&mut FormState> {
|
||||
self.form_editor.as_mut().map(|e| e.data_provider_mut())
|
||||
}
|
||||
|
||||
pub fn is_canvas_edit_mode(&self) -> bool {
|
||||
matches!(self.form_editor.as_ref().map(|e| e.mode()), Some(canvas::AppMode::Edit))
|
||||
}
|
||||
|
||||
pub fn editor_for_path(&mut self, path: &str) -> Option<&mut FormEditor<FormState>> {
|
||||
self.form_editor.get_mut(path)
|
||||
}
|
||||
|
||||
pub fn form_state_for_path(&mut self, path: &str) -> Option<&mut FormState> {
|
||||
self.form_editor.get_mut(path).map(|e| e.data_provider_mut())
|
||||
}
|
||||
|
||||
pub fn ensure_form_editor<F>(&mut self, path: &str, config: &Config, loader: F)
|
||||
where
|
||||
F: FnOnce() -> FormState,
|
||||
{
|
||||
if !self.form_editor.contains_key(path) {
|
||||
let mut editor = FormEditor::new(loader());
|
||||
editor.set_keymap(config.build_canvas_keymap());
|
||||
self.form_editor.insert(path.to_string(), editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UiState {
|
||||
|
||||
@@ -113,13 +113,15 @@ pub async fn run_ui() -> Result<()> {
|
||||
.collect();
|
||||
|
||||
// Replace local form_state with app_state.form_editor
|
||||
app_state.set_form_state(
|
||||
FormState::new(initial_profile.clone(), initial_table.clone(), initial_field_defs),
|
||||
&config,
|
||||
);
|
||||
let path = format!("{}/{}", initial_profile, initial_table);
|
||||
app_state.ensure_form_editor(&path, &config, || {
|
||||
FormState::new(initial_profile.clone(), initial_table.clone(), initial_field_defs)
|
||||
});
|
||||
buffer_state.update_history(AppView::Form(path.clone()));
|
||||
router.navigate(Page::Form(path));
|
||||
|
||||
// Fetch initial count using app_state accessor
|
||||
if let Some(form_state) = app_state.form_state_mut() {
|
||||
if let Some(form_state) = app_state.active_form_state_mut(&buffer_state) {
|
||||
UiService::fetch_and_set_table_count(&mut grpc_client, form_state)
|
||||
.await
|
||||
.context(format!(
|
||||
@@ -137,7 +139,9 @@ pub async fn run_ui() -> Result<()> {
|
||||
}
|
||||
|
||||
if auto_logged_in {
|
||||
buffer_state.history = vec![AppView::Form];
|
||||
let path = format!("{}/{}", initial_profile, initial_table);
|
||||
buffer_state.history = vec![AppView::Form(path.clone())];
|
||||
router.navigate(Page::Form(path));
|
||||
buffer_state.active_index = 0;
|
||||
info!("Initial view set to Form due to auto-login.");
|
||||
}
|
||||
@@ -150,7 +154,7 @@ pub async fn run_ui() -> Result<()> {
|
||||
let mut table_just_switched = false;
|
||||
|
||||
loop {
|
||||
let position_before_event = app_state.form_state()
|
||||
let position_before_event = app_state.active_form_state_mut(&buffer_state)
|
||||
.map(|fs| fs.current_position)
|
||||
.unwrap_or(1);
|
||||
let mut event_processed = false;
|
||||
@@ -216,7 +220,7 @@ pub async fn run_ui() -> Result<()> {
|
||||
if !overlay_active {
|
||||
if let Page::Form(_) = &router.current {
|
||||
if !app_state.ui.focus_outside_canvas {
|
||||
if let Some(editor) = app_state.form_editor.as_mut() {
|
||||
if let Some(editor) = app_state.active_form_editor_mut(&buffer_state) {
|
||||
match editor.handle_key_event(*key_event) {
|
||||
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||
event_handler.command_message = msg;
|
||||
@@ -725,11 +729,14 @@ pub async fn run_ui() -> Result<()> {
|
||||
|
||||
// Workaround for borrow checker
|
||||
let current_dir = app_state.current_dir.clone();
|
||||
let form_state_clone = app_state.form_state().unwrap().clone();
|
||||
let form_state_clone = if let Page::Form(path) = &router.current {
|
||||
app_state.form_state_for_path(path).cloned()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
terminal
|
||||
.draw(|f| {
|
||||
let mut temp_form_state = form_state_clone.clone();
|
||||
if let Some(form_state_clone) = form_state_clone {
|
||||
terminal.draw(|f| {
|
||||
render_ui(
|
||||
f,
|
||||
&mut router,
|
||||
@@ -747,6 +754,7 @@ pub async fn run_ui() -> Result<()> {
|
||||
.context("Terminal draw call failed")?;
|
||||
needs_redraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
let now = Instant::now();
|
||||
let frame_duration = now.duration_since(last_frame_time);
|
||||
|
||||
Reference in New Issue
Block a user