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 {
|
match view {
|
||||||
AppView::Intro => 1,
|
AppView::Intro => 1,
|
||||||
AppView::Login | AppView::Register | AppView::Admin | AppView::AddTable | AppView::AddLogic => 2,
|
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,
|
Admin,
|
||||||
AddTable,
|
AddTable,
|
||||||
AddLogic,
|
AddLogic,
|
||||||
Form,
|
Form(String),
|
||||||
Scratch,
|
Scratch,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ impl AppView {
|
|||||||
AppView::Admin => "Admin_Panel",
|
AppView::Admin => "Admin_Panel",
|
||||||
AppView::AddTable => "Add_Table",
|
AppView::AddTable => "Add_Table",
|
||||||
AppView::AddLogic => "Add_Logic",
|
AppView::AddLogic => "Add_Logic",
|
||||||
AppView::Form => "Form",
|
AppView::Form(_) => "Form",
|
||||||
AppView::Scratch => "*scratch*",
|
AppView::Scratch => "*scratch*",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ impl AppView {
|
|||||||
/// Returns the display name with dynamic context (for Form buffers)
|
/// Returns the display name with dynamic context (for Form buffers)
|
||||||
pub fn display_name_with_context(&self, current_table_name: Option<&str>) -> String {
|
pub fn display_name_with_context(&self, current_table_name: Option<&str>) -> String {
|
||||||
match self {
|
match self {
|
||||||
AppView::Form => {
|
AppView::Form(_) => {
|
||||||
current_table_name
|
current_table_name
|
||||||
.unwrap_or("Data Form")
|
.unwrap_or("Data Form")
|
||||||
.to_string()
|
.to_string()
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub async fn save(
|
|||||||
app_state: &mut AppState,
|
app_state: &mut AppState,
|
||||||
grpc_client: &mut GrpcClient,
|
grpc_client: &mut GrpcClient,
|
||||||
) -> Result<SaveOutcome> {
|
) -> 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 {
|
if !fs.has_unsaved_changes {
|
||||||
return Ok(SaveOutcome::NoChange);
|
return Ok(SaveOutcome::NoChange);
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ pub async fn save(
|
|||||||
.context("Failed to post new table data")?;
|
.context("Failed to post new table data")?;
|
||||||
|
|
||||||
if response.success {
|
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.id = response.inserted_id;
|
||||||
fs.total_count += 1;
|
fs.total_count += 1;
|
||||||
fs.current_position = fs.total_count;
|
fs.current_position = fs.total_count;
|
||||||
@@ -84,7 +84,7 @@ pub async fn save(
|
|||||||
.context("Failed to put (update) table data")?;
|
.context("Failed to put (update) table data")?;
|
||||||
|
|
||||||
if response.success {
|
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;
|
fs.has_unsaved_changes = false;
|
||||||
}
|
}
|
||||||
SaveOutcome::UpdatedExisting
|
SaveOutcome::UpdatedExisting
|
||||||
@@ -103,7 +103,7 @@ pub async fn revert(
|
|||||||
app_state: &mut AppState,
|
app_state: &mut AppState,
|
||||||
grpc_client: &mut GrpcClient,
|
grpc_client: &mut GrpcClient,
|
||||||
) -> Result<String> {
|
) -> 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
|
if fs.id == 0
|
||||||
|| (fs.total_count > 0 && fs.current_position > fs.total_count)
|
|| (fs.total_count > 0 && fs.current_position > fs.total_count)
|
||||||
|| (fs.total_count == 0 && fs.current_position == 1)
|
|| (fs.total_count == 0 && fs.current_position == 1)
|
||||||
|
|||||||
@@ -61,18 +61,18 @@ pub fn render_form_page(
|
|||||||
f.render_widget(count_para, main_layout[0]);
|
f.render_widget(count_para, main_layout[0]);
|
||||||
|
|
||||||
// --- FORM RENDERING (Using persistent FormEditor) ---
|
// --- FORM RENDERING (Using persistent FormEditor) ---
|
||||||
if let Some(editor) = &app_state.form_editor {
|
if let Some(AppView::Form(path)) = buffer_state.get_active_view() {
|
||||||
let active_field_rect = render_canvas(f, main_layout[1], editor, theme);
|
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 {
|
||||||
if let Some(active_rect) = active_field_rect {
|
render_suggestions_dropdown(
|
||||||
render_suggestions_dropdown(
|
f,
|
||||||
f,
|
main_layout[1],
|
||||||
main_layout[1],
|
active_rect,
|
||||||
active_rect,
|
&DefaultCanvasTheme,
|
||||||
&DefaultCanvasTheme,
|
editor,
|
||||||
editor,
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pub enum Page {
|
|||||||
Admin(AdminState),
|
Admin(AdminState),
|
||||||
AddLogic(AddLogicState),
|
AddLogic(AddLogicState),
|
||||||
AddTable(AddTableState),
|
AddTable(AddTableState),
|
||||||
Form(FormState),
|
Form(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Router {
|
pub struct Router {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ pub struct AppState {
|
|||||||
// UI preferences
|
// UI preferences
|
||||||
pub ui: UiState,
|
pub ui: UiState,
|
||||||
|
|
||||||
pub form_editor: Option<FormEditor<FormState>>,
|
pub form_editor: HashMap<String, FormEditor<FormState>>, // key = "profile/table"
|
||||||
|
|
||||||
#[cfg(feature = "ui-debug")]
|
#[cfg(feature = "ui-debug")]
|
||||||
pub debug_state: Option<DebugState>,
|
pub debug_state: Option<DebugState>,
|
||||||
@@ -81,7 +81,7 @@ impl AppState {
|
|||||||
pending_table_structure_fetch: None,
|
pending_table_structure_fetch: None,
|
||||||
search_state: None,
|
search_state: None,
|
||||||
ui: UiState::default(),
|
ui: UiState::default(),
|
||||||
form_editor: None,
|
form_editor: HashMap::new(),
|
||||||
|
|
||||||
#[cfg(feature = "ui-debug")]
|
#[cfg(feature = "ui-debug")]
|
||||||
debug_state: None,
|
debug_state: None,
|
||||||
@@ -99,32 +99,28 @@ impl AppState {
|
|||||||
self.current_view_table_name = Some(table_name);
|
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 {
|
pub fn is_canvas_edit_mode(&self) -> bool {
|
||||||
matches!(self.form_editor.as_ref().map(|e| e.mode()), Some(canvas::AppMode::Edit))
|
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 {
|
impl Default for UiState {
|
||||||
|
|||||||
@@ -113,13 +113,15 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Replace local form_state with app_state.form_editor
|
// Replace local form_state with app_state.form_editor
|
||||||
app_state.set_form_state(
|
let path = format!("{}/{}", initial_profile, initial_table);
|
||||||
FormState::new(initial_profile.clone(), initial_table.clone(), initial_field_defs),
|
app_state.ensure_form_editor(&path, &config, || {
|
||||||
&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
|
// 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)
|
UiService::fetch_and_set_table_count(&mut grpc_client, form_state)
|
||||||
.await
|
.await
|
||||||
.context(format!(
|
.context(format!(
|
||||||
@@ -137,7 +139,9 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if auto_logged_in {
|
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;
|
buffer_state.active_index = 0;
|
||||||
info!("Initial view set to Form due to auto-login.");
|
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;
|
let mut table_just_switched = false;
|
||||||
|
|
||||||
loop {
|
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)
|
.map(|fs| fs.current_position)
|
||||||
.unwrap_or(1);
|
.unwrap_or(1);
|
||||||
let mut event_processed = false;
|
let mut event_processed = false;
|
||||||
@@ -216,7 +220,7 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
if !overlay_active {
|
if !overlay_active {
|
||||||
if let Page::Form(_) = &router.current {
|
if let Page::Form(_) = &router.current {
|
||||||
if !app_state.ui.focus_outside_canvas {
|
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) {
|
match editor.handle_key_event(*key_event) {
|
||||||
KeyEventOutcome::Consumed(Some(msg)) => {
|
KeyEventOutcome::Consumed(Some(msg)) => {
|
||||||
event_handler.command_message = msg;
|
event_handler.command_message = msg;
|
||||||
@@ -725,11 +729,14 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
|
|
||||||
// Workaround for borrow checker
|
// Workaround for borrow checker
|
||||||
let current_dir = app_state.current_dir.clone();
|
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
|
if let Some(form_state_clone) = form_state_clone {
|
||||||
.draw(|f| {
|
terminal.draw(|f| {
|
||||||
let mut temp_form_state = form_state_clone.clone();
|
|
||||||
render_ui(
|
render_ui(
|
||||||
f,
|
f,
|
||||||
&mut router,
|
&mut router,
|
||||||
@@ -746,6 +753,7 @@ pub async fn run_ui() -> Result<()> {
|
|||||||
})
|
})
|
||||||
.context("Terminal draw call failed")?;
|
.context("Terminal draw call failed")?;
|
||||||
needs_redraw = false;
|
needs_redraw = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|||||||
Reference in New Issue
Block a user