From 4f0bf78a0b814bb88f1061cbb472c96f9d894789 Mon Sep 17 00:00:00 2001 From: Anthony Potappel Date: Thu, 26 Sep 2024 21:51:21 +0200 Subject: [PATCH] finalize ability to change provider for profile --- .../prompt/src/tui/modals/settings/list.rs | 25 ++++ .../prompt/src/tui/modals/settings/manager.rs | 47 ++++++- .../tui/modals/settings/profile/creator.rs | 117 +++++++++++++----- .../src/tui/modals/settings/profile/mod.rs | 2 +- 4 files changed, 151 insertions(+), 40 deletions(-) diff --git a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/list.rs b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/list.rs index 5ac4550..b3ad77e 100644 --- a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/list.rs +++ b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/list.rs @@ -32,6 +32,31 @@ impl SettingsList { list } + pub fn new_with_selected_item( + items: Vec, + default_item: Option, + item_type: String, + list_item_id: i64, + ) -> Self { + let selected_index = items + .iter() + .position(|item| item.id() == list_item_id) + .unwrap_or(0); + + let mut list = SettingsList { + items, + selected_index, + default_item: None, + item_type, + }; + + if let Some(default) = default_item { + list.mark_as_default(&default); + } + + list + } + pub fn get_selected_item(&self) -> Option<&T> { self.items.get(self.selected_index) } diff --git a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/manager.rs b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/manager.rs index 390c8ce..5b52b9e 100644 --- a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/manager.rs +++ b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/manager.rs @@ -2,6 +2,8 @@ use async_trait::async_trait; use ratatui::prelude::*; use serde_json::{json, Value as JsonValue}; +use super::list::ListItemTrait; +use super::profile::ProfileCreationStep; use super::provider::ProviderCreationStep; use super::*; @@ -316,7 +318,17 @@ impl ConfigItemManager { } }; - self.list = SettingsList::new(items, default_item, item_type); + self.list = if let Some(selected_item) = self.list.get_selected_item() { + let selected_item_id = selected_item.id(); + SettingsList::new_with_selected_item( + items, + default_item, + item_type, + selected_item_id, + ) + } else { + SettingsList::new(items, default_item, item_type) + }; self.load_selected_item_settings().await?; Ok(WindowMode::Modal(ModalEvent::UpdateUI)) } @@ -501,7 +513,10 @@ impl ConfigItemManager { { let mut creator = ProfileCreator::new(self.db_handler.clone()).await?; - creator.set_editing_mode(profile.clone()); + creator.set_editing_mode( + profile.clone(), + ProfileCreationStep::SelectProvider, + ); self.creator = Some(Box::new(creator)); *tab_focus = TabFocus::Creation; @@ -532,19 +547,18 @@ impl ConfigItemManager { Ok(WindowMode::Modal(ModalEvent::UpdateUI)) } CreatorAction::Finish(new_item) => { - self.list.add_item(new_item); self.creator = None; *tab_focus = TabFocus::List; + self.update_list_with_item(new_item).await?; Ok(WindowMode::Modal(ModalEvent::UpdateUI)) } CreatorAction::CreateItem => { let result = creator.create_item().await?; match result { CreatorAction::Finish(new_item) => { - self.list.add_item(new_item); self.creator = None; *tab_focus = TabFocus::List; - self.refresh_list(current_tab).await?; + self.update_list_with_item(new_item).await?; Ok(WindowMode::Modal(ModalEvent::UpdateUI)) } _ => Ok(WindowMode::Modal( @@ -561,6 +575,29 @@ impl ConfigItemManager { } } + async fn update_list_with_item( + &mut self, + item: ConfigItem, + ) -> Result<(), ApplicationError> { + // Check if the item already exists in the list + if let Some(index) = self + .list + .items + .iter() + .position(|existing| existing.id() == item.id()) + { + // Update existing item + self.list.items[index] = item; + self.list.selected_index = index; + } else { + // Add new item + self.list.add_item(item); + } + // Refresh the entire list to ensure consistency with the database + self.refresh_list(ConfigTab::Profiles).await?; + Ok(()) + } + async fn load_selected_item_settings( &mut self, ) -> Result<(), ApplicationError> { diff --git a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/creator.rs b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/creator.rs index 97ce22c..fe2acd2 100644 --- a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/creator.rs +++ b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/creator.rs @@ -59,10 +59,14 @@ impl ProfileCreator { }) } - pub fn set_editing_mode(&mut self, profile: UserProfile) { + pub fn set_editing_mode( + &mut self, + profile: UserProfile, + step: ProfileCreationStep, + ) { self.editing_profile = Some(profile.clone()); self.new_profile_name = profile.name.clone(); - self.creation_step = ProfileCreationStep::SelectProvider; + self.creation_step = step; } pub fn render_creator(&mut self, f: &mut Frame, area: Rect) { @@ -119,8 +123,7 @@ impl ProfileCreator { self.provider_configs[self.selected_provider_index] .clone(), ); - self.creation_step = ProfileCreationStep::ConfirmCreate; - self.initialize_confirm_create_state().await; + return self.go_to_next_step().await; } } KeyCode::Esc | KeyCode::Backspace => { @@ -361,7 +364,7 @@ impl ProfileCreator { match self.creation_step { ProfileCreationStep::EnterName => { - self.handle_enter_name(input) + self.handle_enter_name(input).await } ProfileCreationStep::SelectProvider => { self.handle_select_provider(input).await @@ -412,7 +415,7 @@ impl ProfileCreator { } } - fn handle_enter_name( + async fn handle_enter_name( &mut self, input: KeyEvent, ) -> Result, ApplicationError> { @@ -421,12 +424,7 @@ impl ProfileCreator { self.new_profile_name.push(c); Ok(CreatorAction::Continue) } - KeyCode::Enter => { - if !self.new_profile_name.is_empty() { - self.creation_step = ProfileCreationStep::SelectProvider; - } - Ok(CreatorAction::Continue) - } + KeyCode::Enter => self.go_to_next_step().await, _ => Ok(CreatorAction::Continue), } } @@ -446,8 +444,7 @@ impl ProfileCreator { if self.editing_profile.is_some() { self.update_profile().await } else { - self.creation_step = ProfileCreationStep::CreatingProfile; - Ok(CreatorAction::CreateItem) + self.go_to_next_step().await } } KeyCode::Esc => { @@ -549,32 +546,84 @@ impl ProfileCreator { .alignment(Alignment::Center); f.render_widget(back_button, button_chunks[0]); - let create_button = Paragraph::new("[ Create Profile ]") - .style( - Style::default() - .fg(Color::Green) - .add_modifier(Modifier::BOLD), - ) - .alignment(Alignment::Center); - f.render_widget(create_button, button_chunks[1]); + let action_button = if self.editing_profile.is_some() { + Paragraph::new("[ Update Profile ]") + .style( + Style::default() + .fg(Color::Green) + .add_modifier(Modifier::BOLD), + ) + .alignment(Alignment::Center) + } else { + Paragraph::new("[ Create Profile ]") + .style( + Style::default() + .fg(Color::Green) + .add_modifier(Modifier::BOLD), + ) + .alignment(Alignment::Center) + }; + f.render_widget(action_button, button_chunks[1]); } fn go_to_previous_step( &mut self, ) -> Result, ApplicationError> { - match self.creation_step { - ProfileCreationStep::EnterName => Ok(CreatorAction::Cancel), - ProfileCreationStep::SelectProvider => { - self.creation_step = ProfileCreationStep::EnterName; - Ok(CreatorAction::Continue) - } - ProfileCreationStep::ConfirmCreate => { - self.creation_step = ProfileCreationStep::SelectProvider; - Ok(CreatorAction::Continue) + if self.editing_profile.is_some() { + // If editing a profile, any "back" action should cancel the edit + self.editing_profile = None; + Ok(CreatorAction::Cancel) + } else { + // Normal behavior for non-editing mode + match self.creation_step { + ProfileCreationStep::EnterName => Ok(CreatorAction::Cancel), + ProfileCreationStep::SelectProvider => { + self.creation_step = ProfileCreationStep::EnterName; + Ok(CreatorAction::Continue) + } + ProfileCreationStep::ConfirmCreate => { + self.creation_step = ProfileCreationStep::SelectProvider; + Ok(CreatorAction::Continue) + } + ProfileCreationStep::CreatingProfile => { + self.creation_step = ProfileCreationStep::ConfirmCreate; + Ok(CreatorAction::Continue) + } } - ProfileCreationStep::CreatingProfile => { - self.creation_step = ProfileCreationStep::ConfirmCreate; - Ok(CreatorAction::Continue) + } + } + + async fn go_to_next_step( + &mut self, + ) -> Result, ApplicationError> { + if self.editing_profile.is_some() { + self.creation_step = ProfileCreationStep::ConfirmCreate; + self.initialize_confirm_create_state().await; + Ok(CreatorAction::Continue) + } else { + // Normal behavior for non-editing mode + match self.creation_step { + ProfileCreationStep::EnterName => { + if !self.new_profile_name.is_empty() { + self.creation_step = + ProfileCreationStep::SelectProvider; + } + Ok(CreatorAction::Continue) + } + ProfileCreationStep::SelectProvider => { + self.creation_step = ProfileCreationStep::ConfirmCreate; + self.initialize_confirm_create_state().await; + Ok(CreatorAction::Continue) + } + ProfileCreationStep::ConfirmCreate => { + self.creation_step = ProfileCreationStep::CreatingProfile; + Ok(CreatorAction::CreateItem) + } + ProfileCreationStep::CreatingProfile => { + unreachable!( + "Unexpected state: no next step after CreatingProfile" + ); + } } } } diff --git a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/mod.rs b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/mod.rs index 817e0b7..18fea16 100644 --- a/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/mod.rs +++ b/lumni/src/apps/builtin/llm/prompt/src/tui/modals/settings/profile/mod.rs @@ -1,5 +1,5 @@ mod creator; -pub use creator::ProfileCreator; +pub use creator::{ProfileCreationStep, ProfileCreator}; use super::*;