From 0c61ba5b8e6cba3a13f792dd248292387f1239e3 Mon Sep 17 00:00:00 2001 From: Fini Date: Mon, 1 Jun 2026 06:27:36 +0800 Subject: [PATCH] fix(settings): track image search test status --- crates/op-editor-core/src/agent_settings.rs | 10 ++ crates/op-editor-core/src/lib.rs | 3 +- .../src/tests_agent_settings.rs | 3 +- .../src/widgets/agent_settings_images.rs | 56 +++++- .../src/widgets/agent_settings_panel_tests.rs | 22 ++- .../src/widget_host/agent_settings_tests.rs | 18 +- .../src/widget_host/press_helpers.rs | 7 + crates/op-host-web/src/widget_host.rs | 2 + .../src/widget_host/agent_settings_press.rs | 166 +----------------- .../widget_host/agent_settings_press_tests.rs | 153 ++++++++++++++++ 10 files changed, 275 insertions(+), 165 deletions(-) create mode 100644 crates/op-host-web/src/widget_host/agent_settings_press_tests.rs diff --git a/crates/op-editor-core/src/agent_settings.rs b/crates/op-editor-core/src/agent_settings.rs index f7ba94fd2..69b3db9f6 100644 --- a/crates/op-editor-core/src/agent_settings.rs +++ b/crates/op-editor-core/src/agent_settings.rs @@ -135,6 +135,14 @@ pub enum ImageSearchField { ClientSecret, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ImageTestStatus { + Idle, + Testing, + Valid, + Invalid, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AcpAgentField { DisplayName, @@ -433,6 +441,7 @@ pub struct AgentSettings { pub mcp_cli_enabled: [bool; 6], pub images_advanced_open: bool, pub images_search_ready: bool, + pub images_search_test_status: ImageTestStatus, pub openverse_client_id: String, pub openverse_client_secret: String, pub image_gen_profiles: Vec, @@ -474,6 +483,7 @@ impl Default for AgentSettings { mcp_cli_enabled: [false; 6], images_advanced_open: false, images_search_ready: true, + images_search_test_status: ImageTestStatus::Idle, openverse_client_id: String::new(), openverse_client_secret: String::new(), image_gen_profiles: Vec::new(), diff --git a/crates/op-editor-core/src/lib.rs b/crates/op-editor-core/src/lib.rs index fe124c102..9294f0fec 100644 --- a/crates/op-editor-core/src/lib.rs +++ b/crates/op-editor-core/src/lib.rs @@ -76,7 +76,8 @@ mod tests_pages; pub use agent_settings::{ AcpAgentConfig, AcpAgentField, AcpConnectionType, AgentSettings, AgentSettingsDrag, AgentSettingsTab, BuiltinAgentConfig, BuiltinAgentField, BuiltinAgentKind, ImageGenField, - ImageGenProfile, ImageGenProvider, ImageSearchField, McpCli, McpServer, SettingsFocus, + ImageGenProfile, ImageGenProvider, ImageSearchField, ImageTestStatus, McpCli, McpServer, + SettingsFocus, }; pub use agent_settings_builtin_presets::{ builtin_agent_preset, infer_builtin_agent_preset, normalize_builtin_agent_preset, diff --git a/crates/op-editor-core/src/tests_agent_settings.rs b/crates/op-editor-core/src/tests_agent_settings.rs index c0a1f0474..df4f658ba 100644 --- a/crates/op-editor-core/src/tests_agent_settings.rs +++ b/crates/op-editor-core/src/tests_agent_settings.rs @@ -1,6 +1,6 @@ use crate::agent_settings::{ AcpConnectionType, AgentSettings, AgentSettingsTab, BuiltinAgentConfig, BuiltinAgentKind, - ImageGenProvider, McpCli, + ImageGenProvider, ImageTestStatus, McpCli, }; use crate::agent_settings_builtin_presets::BuiltinAgentPresetKey; @@ -18,6 +18,7 @@ fn default_settings_are_quiescent() { assert!(!s.images_advanced_open); assert!(s.openverse_client_id.is_empty()); assert!(s.openverse_client_secret.is_empty()); + assert_eq!(s.images_search_test_status, ImageTestStatus::Idle); assert_eq!(s.mcp_server.port, 3100); assert!(s.auto_update_enabled); assert!(s.focus.is_none()); diff --git a/crates/op-editor-ui/src/widgets/agent_settings_images.rs b/crates/op-editor-ui/src/widgets/agent_settings_images.rs index 4cd9ff214..4695d59c0 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_images.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_images.rs @@ -11,7 +11,7 @@ use crate::widgets::PaintCx; use crate::{Color, Point2D, Rect, TextLayout}; use op_editor_core::agent_settings::{ AgentSettings, ImageGenField, ImageGenProfile, ImageGenProvider, ImageSearchField, - SettingsFocus, + ImageTestStatus, SettingsFocus, }; use op_editor_core::editor_ui_state::EditorUiState; @@ -131,6 +131,11 @@ fn has_search_credentials(settings: &AgentSettings) -> bool { || !settings.openverse_client_secret.trim().is_empty() } +fn search_test_enabled(settings: &AgentSettings) -> bool { + has_search_credentials(settings) + && settings.images_search_test_status != ImageTestStatus::Testing +} + fn test_btn_rect(content: Rect, settings: &AgentSettings) -> Rect { if !settings.images_advanced_open { return Rect { @@ -273,7 +278,7 @@ pub fn hit_test(content: Rect, settings: &AgentSettings, scrolled: Point2D) -> I if rect_contains(search_field_rect(content, 1), scrolled) { return ImagesHit::FocusSearchField(ImageSearchField::ClientSecret); } - if has_search_credentials(settings) + if search_test_enabled(settings) && rect_contains(test_btn_rect(content, settings), scrolled) { return ImagesHit::TestSearch; @@ -476,6 +481,7 @@ pub(super) fn paint_images_tab( 1.6, ); let test_btn = test_btn_rect(content, settings); + paint_search_test_status(cx, theme, settings, test_btn); cx.backend.fill_round_rect(test_btn, 6.0, theme.muted); cx.backend .stroke_round_rect(test_btn, 6.0, theme.border, 1.0); @@ -485,7 +491,11 @@ pub(super) fn paint_images_tab( test_label, "system-ui", 13.0, - to_jian(theme.foreground), + to_jian(if search_test_enabled(settings) { + theme.foreground + } else { + theme.muted_foreground + }), Point2D::new(0.0, 0.0), ); cx.backend.draw_text( @@ -554,6 +564,46 @@ pub(super) fn paint_images_tab( } } +fn paint_search_test_status( + cx: &mut PaintCx<'_>, + theme: &Theme, + settings: &AgentSettings, + test_btn: Rect, +) { + match settings.images_search_test_status { + ImageTestStatus::Idle => {} + ImageTestStatus::Testing => draw_icon( + cx.backend, + Icon::Loader, + Point2D::new(test_btn.origin.x - 20.0, test_btn.origin.y + 8.5), + 11.0, + theme.muted_foreground, + 1.5, + ), + ImageTestStatus::Valid => draw_icon( + cx.backend, + Icon::Check, + Point2D::new(test_btn.origin.x - 20.0, test_btn.origin.y + 8.5), + 11.0, + theme.primary, + 1.8, + ), + ImageTestStatus::Invalid => { + let label = TextLayout::single_run( + "Invalid", + "system-ui", + 10.0, + to_jian(theme.destructive), + Point2D::new(0.0, 0.0), + ); + cx.backend.draw_text( + &label, + Point2D::new(test_btn.origin.x - 44.0, test_btn.origin.y + 17.0), + ); + } + } +} + #[allow(clippy::too_many_arguments)] fn paint_profile_row( cx: &mut PaintCx<'_>, diff --git a/crates/op-editor-ui/src/widgets/agent_settings_panel_tests.rs b/crates/op-editor-ui/src/widgets/agent_settings_panel_tests.rs index c6bfae0dd..21f7154b3 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_panel_tests.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_panel_tests.rs @@ -3,7 +3,7 @@ use crate::widgets::{PaintCx, Widget}; use crate::{Color, Point2D, Rect, RenderBackend, TextLayout}; use op_editor_core::agent_settings::{ AcpAgentField, AgentSettingsTab, BuiltinAgentField, ImageGenField, ImageSearchField, - SettingsFocus, + ImageTestStatus, SettingsFocus, }; use op_editor_core::EditorState; @@ -753,6 +753,26 @@ fn images_tab_test_search_requires_some_oauth_text() { ); } +#[test] +fn images_tab_test_search_is_disabled_while_testing_like_ts() { + let mut state = EditorState::default(); + state.editor_ui.agent_settings.tab = AgentSettingsTab::Images; + state.editor_ui.agent_settings.images_advanced_open = true; + state.editor_ui.agent_settings.openverse_client_id = "client".into(); + state.editor_ui.agent_settings.images_search_test_status = ImageTestStatus::Testing; + let panel = AgentSettingsPanel::for_editor(&state); + let rect = panel.rect(1200.0, 800.0); + let content_y = rect.origin.y + 24.0; + let content_w = rect.size.x - 200.0 - 48.0; + let button_x = rect.origin.x + 200.0 + 24.0 + content_w - 28.0; + let button_y = content_y + 36.0 + 24.0 + 22.0 + 36.0 + 10.0 + 36.0 + 14.0 + 18.0; + + assert_eq!( + panel.hit_test(rect, crate::Point2D::new(button_x, button_y)), + AgentSettingsHit::Inside + ); +} + #[test] fn images_tab_content_height_includes_profile_rows() { let mut empty = EditorState::default(); diff --git a/crates/op-host-native/src/widget_host/agent_settings_tests.rs b/crates/op-host-native/src/widget_host/agent_settings_tests.rs index 3a7dfb499..12ad7c538 100644 --- a/crates/op-host-native/src/widget_host/agent_settings_tests.rs +++ b/crates/op-host-native/src/widget_host/agent_settings_tests.rs @@ -1,7 +1,7 @@ use super::WidgetHostNative; use op_editor_core::agent_settings::{ AcpAgentField, AgentSettingsTab, BuiltinAgentField, ImageGenField, ImageGenProvider, - ImageSearchField, SettingsFocus, + ImageSearchField, ImageTestStatus, SettingsFocus, }; use op_editor_core::BuiltinAgentPresetKey; use op_editor_ui::widgets::agent_settings_panel::AgentSettingsPanel; @@ -743,7 +743,7 @@ fn image_search_oauth_focus_accepts_text_and_commits() { } #[test] -fn image_search_test_keeps_search_ready_when_oauth_is_incomplete() { +fn image_search_test_tracks_invalid_and_testing_status_like_ts() { let mut host = WidgetHostNative::new(); host.editor_state_mut().editor_ui.agent_settings.tab = AgentSettingsTab::Images; host.editor_state_mut() @@ -763,6 +763,13 @@ fn image_search_test_keeps_search_ready_when_oauth_is_incomplete() { let y = content_y + 36.0 + 24.0 + 22.0 + 36.0 + 10.0 + 36.0 + 14.0 + 18.0; assert!(host.dispatch_agent_settings_press(x, y, 1200.0, 800.0)); + assert_eq!( + host.editor_state() + .editor_ui + .agent_settings + .images_search_test_status, + ImageTestStatus::Invalid + ); assert!( host.editor_state() .editor_ui @@ -775,6 +782,13 @@ fn image_search_test_keeps_search_ready_when_oauth_is_incomplete() { .agent_settings .openverse_client_secret = "secret".into(); assert!(host.dispatch_agent_settings_press(x, y, 1200.0, 800.0)); + assert_eq!( + host.editor_state() + .editor_ui + .agent_settings + .images_search_test_status, + ImageTestStatus::Testing + ); assert!( host.editor_state() .editor_ui diff --git a/crates/op-host-native/src/widget_host/press_helpers.rs b/crates/op-host-native/src/widget_host/press_helpers.rs index 77d043f0b..dadd9ec9c 100644 --- a/crates/op-host-native/src/widget_host/press_helpers.rs +++ b/crates/op-host-native/src/widget_host/press_helpers.rs @@ -144,7 +144,14 @@ impl WidgetHostNative { AgentSettingsHit::TestImageSearch => { self.commit_settings_focus_if_any(); let settings = &mut self.editor_state.editor_ui.agent_settings; + let has_client_id = !settings.openverse_client_id.trim().is_empty(); + let has_client_secret = !settings.openverse_client_secret.trim().is_empty(); settings.images_search_ready = true; + settings.images_search_test_status = if has_client_id && has_client_secret { + op_editor_core::agent_settings::ImageTestStatus::Testing + } else { + op_editor_core::agent_settings::ImageTestStatus::Invalid + }; } AgentSettingsHit::SetActiveGenConfig(index) => { self.commit_settings_focus_if_any(); diff --git a/crates/op-host-web/src/widget_host.rs b/crates/op-host-web/src/widget_host.rs index ee67a3418..495db869f 100644 --- a/crates/op-host-web/src/widget_host.rs +++ b/crates/op-host-web/src/widget_host.rs @@ -44,6 +44,8 @@ use op_editor_ui::widgets::{ use op_editor_ui::{Point2D, Rect, Theme}; mod agent_settings_press; +#[cfg(test)] +mod agent_settings_press_tests; mod boolean_ops; #[cfg(test)] mod boolean_toolbar_tests; diff --git a/crates/op-host-web/src/widget_host/agent_settings_press.rs b/crates/op-host-web/src/widget_host/agent_settings_press.rs index 4612e2e21..34db00e8a 100644 --- a/crates/op-host-web/src/widget_host/agent_settings_press.rs +++ b/crates/op-host-web/src/widget_host/agent_settings_press.rs @@ -3,7 +3,7 @@ use super::WidgetHost; use op_editor_core::agent_settings::{ AcpAgentField, AcpConnectionType, AgentProvider, BuiltinAgentField, ImageGenField, - ImageSearchField, McpCli, SettingsFocus, + ImageSearchField, ImageTestStatus, McpCli, SettingsFocus, }; use op_editor_ui::widgets::agent_settings_panel::{AgentSettingsHit, AgentSettingsPanel}; use op_editor_ui::Point2D; @@ -99,8 +99,14 @@ impl WidgetHost { AgentSettingsHit::TestImageSearch => { self.commit_settings_focus(); let settings = &mut self.editor_state.editor_ui.agent_settings; - settings.images_search_ready = !settings.openverse_client_id.trim().is_empty() - && !settings.openverse_client_secret.trim().is_empty(); + let has_client_id = !settings.openverse_client_id.trim().is_empty(); + let has_client_secret = !settings.openverse_client_secret.trim().is_empty(); + settings.images_search_ready = true; + settings.images_search_test_status = if has_client_id && has_client_secret { + ImageTestStatus::Testing + } else { + ImageTestStatus::Invalid + }; } AgentSettingsHit::SetActiveGenConfig(index) => { self.commit_settings_focus(); @@ -669,157 +675,3 @@ impl WidgetHost { } } } - -#[cfg(test)] -mod tests { - use super::*; - use op_editor_core::agent_settings::AgentSettingsTab; - - #[test] - fn toggling_builtin_kind_commits_focused_api_key_draft() { - let mut host = WidgetHost::new(); - host.editor_state - .editor_ui - .agent_settings - .add_builtin_agent_with_defaults("MINIMAX", "", "MiniMax-M2.7"); - host.editor_state.editor_ui.agent_settings.focus = Some(SettingsFocus::BuiltinAgent { - index: 0, - field: BuiltinAgentField::ApiKey, - }); - host.editor_state.editor_ui.settings_input_draft = "sk-web".into(); - - let panel = AgentSettingsPanel::for_editor(&host.editor_state); - let rect = panel.rect(1200.0, 800.0); - let content_x = rect.origin.x + 200.0 + 24.0; - let content_y = rect.origin.y + 24.0; - let content_w = rect.size.x - 200.0 - 48.0; - let first_card_y = content_y + 12.0 + 28.0 + 28.0; - let kind_x = content_x + content_w - 172.0 + 120.0; - let kind_y = first_card_y + 22.0; - - assert!(host.dispatch_agent_settings_press(kind_x, kind_y, 1200.0, 800.0)); - - let agent = &host.editor_state.editor_ui.agent_settings.builtin_agents[0]; - assert_eq!(agent.api_key, "sk-web"); - assert_eq!( - agent.kind, - op_editor_core::agent_settings::BuiltinAgentKind::OpenAiCompat - ); - assert!(host.editor_state.editor_ui.agent_settings.focus.is_none()); - } - - #[test] - fn add_provider_opens_unsaved_builtin_agent_draft() { - let mut host = WidgetHost::new(); - host.set_now_ms(1234); - - let panel = AgentSettingsPanel::for_editor(&host.editor_state); - let rect = panel.rect(1200.0, 800.0); - let content_x = rect.origin.x + 200.0 + 24.0; - let content_y = rect.origin.y + 24.0; - let content_w = rect.size.x - 200.0 - 48.0; - let add_x = content_x + content_w - 48.0; - let add_y = content_y + 24.0; - - assert!(host.dispatch_agent_settings_press(add_x, add_y, 1200.0, 800.0)); - - let settings = &host.editor_state.editor_ui.agent_settings; - assert!(settings.builtin_agents.is_empty()); - assert!(settings.builtin_agent_draft.is_some()); - assert_eq!( - settings.focus, - Some(SettingsFocus::BuiltinAgentDraft(BuiltinAgentField::ApiKey)) - ); - assert_eq!(host.editor_state.editor_ui.settings_input_draft, ""); - assert_eq!( - host.editor_state.editor_ui.settings_input_caret_anchor_ms, - 1234 - ); - } - - #[test] - fn builtin_provider_menu_selects_ts_preset_for_draft() { - let mut host = WidgetHost::new(); - let panel = AgentSettingsPanel::for_editor(&host.editor_state); - let rect = panel.rect(1200.0, 800.0); - let content_x = rect.origin.x + 200.0 + 24.0; - let content_y = rect.origin.y + 24.0; - let content_w = rect.size.x - 200.0 - 48.0; - let add_x = content_x + content_w - 48.0; - let add_y = content_y + 24.0; - - assert!(host.dispatch_agent_settings_press(add_x, add_y, 1200.0, 800.0)); - let card_y = content_y + 12.0 + 28.0 + 28.0; - let provider_x = content_x + 68.0 + 24.0; - let provider_y = card_y + 60.0; - assert!(host.dispatch_agent_settings_press(provider_x, provider_y, 1200.0, 800.0)); - let minimax_y = card_y + 76.0 + 4.0 + 5.0 * 24.0 + 12.0; - assert!(host.dispatch_agent_settings_press(provider_x, minimax_y, 1200.0, 800.0)); - - let draft = host - .editor_state - .editor_ui - .agent_settings - .builtin_agent_draft - .as_ref() - .expect("draft remains open"); - assert_eq!(draft.preset, op_editor_core::BuiltinAgentPresetKey::MiniMax); - assert_eq!(draft.display_name, "MiniMax"); - assert_eq!(draft.model, "MiniMax-M2.7"); - assert_eq!(draft.base_url, "https://api.minimaxi.com/anthropic"); - } - - #[test] - fn save_builtin_agent_draft_persists_provider() { - let mut host = WidgetHost::new(); - let panel = AgentSettingsPanel::for_editor(&host.editor_state); - let rect = panel.rect(1200.0, 800.0); - let content_x = rect.origin.x + 200.0 + 24.0; - let content_y = rect.origin.y + 24.0; - let content_w = rect.size.x - 200.0 - 48.0; - let add_x = content_x + content_w - 48.0; - let add_y = content_y + 24.0; - - assert!(host.dispatch_agent_settings_press(add_x, add_y, 1200.0, 800.0)); - for c in "sk-web".chars() { - assert!(host.apply_text(c)); - } - let card_y = content_y + 12.0 + 28.0 + 28.0; - let save_x = content_x + content_w - 12.0 - 34.0; - let save_y = card_y + 196.0 + 18.0; - assert!(host.dispatch_agent_settings_press(save_x, save_y, 1200.0, 800.0)); - - let settings = &host.editor_state.editor_ui.agent_settings; - assert_eq!(settings.builtin_agents.len(), 1); - assert!(settings.builtin_agent_draft.is_none()); - assert_eq!(settings.builtin_agents[0].api_key, "sk-web"); - assert!(settings.focus.is_none()); - } - - #[test] - fn image_generation_profile_header_click_toggles_editor_closed() { - let mut host = WidgetHost::new(); - host.editor_state.editor_ui.agent_settings.tab = AgentSettingsTab::Images; - host.editor_state - .editor_ui - .agent_settings - .add_image_gen_profile(); - host.editor_state.editor_ui.agent_settings.focus = Some(SettingsFocus::ImageGenProfile { - index: 0, - field: ImageGenField::Name, - }); - host.editor_state.editor_ui.settings_input_draft = "Config 1".into(); - - let panel = AgentSettingsPanel::for_editor(&host.editor_state); - let rect = panel.rect(1200.0, 800.0); - let content_x = rect.origin.x + 200.0 + 24.0; - let content_y = rect.origin.y + 24.0; - let gen_top = content_y + 36.0 + 24.0 + 28.0; - let row_y = gen_top + 36.0; - - assert!(host.dispatch_agent_settings_press(content_x + 72.0, row_y + 16.0, 1200.0, 800.0)); - - assert_eq!(host.editor_state.editor_ui.agent_settings.focus, None); - assert!(host.editor_state.editor_ui.settings_input_draft.is_empty()); - } -} diff --git a/crates/op-host-web/src/widget_host/agent_settings_press_tests.rs b/crates/op-host-web/src/widget_host/agent_settings_press_tests.rs new file mode 100644 index 000000000..8ceb1b719 --- /dev/null +++ b/crates/op-host-web/src/widget_host/agent_settings_press_tests.rs @@ -0,0 +1,153 @@ +use super::WidgetHost; +use op_editor_core::agent_settings::{ + AgentSettingsTab, BuiltinAgentField, ImageGenField, SettingsFocus, +}; +use op_editor_ui::widgets::agent_settings_panel::AgentSettingsPanel; + +#[test] +fn toggling_builtin_kind_commits_focused_api_key_draft() { + let mut host = WidgetHost::new(); + host.editor_state + .editor_ui + .agent_settings + .add_builtin_agent_with_defaults("MINIMAX", "", "MiniMax-M2.7"); + host.editor_state.editor_ui.agent_settings.focus = Some(SettingsFocus::BuiltinAgent { + index: 0, + field: BuiltinAgentField::ApiKey, + }); + host.editor_state.editor_ui.settings_input_draft = "sk-web".into(); + + let panel = AgentSettingsPanel::for_editor(&host.editor_state); + let rect = panel.rect(1200.0, 800.0); + let content_x = rect.origin.x + 200.0 + 24.0; + let content_y = rect.origin.y + 24.0; + let content_w = rect.size.x - 200.0 - 48.0; + let first_card_y = content_y + 12.0 + 28.0 + 28.0; + let kind_x = content_x + content_w - 172.0 + 120.0; + let kind_y = first_card_y + 22.0; + + assert!(host.dispatch_agent_settings_press(kind_x, kind_y, 1200.0, 800.0)); + + let agent = &host.editor_state.editor_ui.agent_settings.builtin_agents[0]; + assert_eq!(agent.api_key, "sk-web"); + assert_eq!( + agent.kind, + op_editor_core::agent_settings::BuiltinAgentKind::OpenAiCompat + ); + assert!(host.editor_state.editor_ui.agent_settings.focus.is_none()); +} + +#[test] +fn add_provider_opens_unsaved_builtin_agent_draft() { + let mut host = WidgetHost::new(); + host.set_now_ms(1234); + + let panel = AgentSettingsPanel::for_editor(&host.editor_state); + let rect = panel.rect(1200.0, 800.0); + let content_x = rect.origin.x + 200.0 + 24.0; + let content_y = rect.origin.y + 24.0; + let content_w = rect.size.x - 200.0 - 48.0; + let add_x = content_x + content_w - 48.0; + let add_y = content_y + 24.0; + + assert!(host.dispatch_agent_settings_press(add_x, add_y, 1200.0, 800.0)); + + let settings = &host.editor_state.editor_ui.agent_settings; + assert!(settings.builtin_agents.is_empty()); + assert!(settings.builtin_agent_draft.is_some()); + assert_eq!( + settings.focus, + Some(SettingsFocus::BuiltinAgentDraft(BuiltinAgentField::ApiKey)) + ); + assert_eq!(host.editor_state.editor_ui.settings_input_draft, ""); + assert_eq!( + host.editor_state.editor_ui.settings_input_caret_anchor_ms, + 1234 + ); +} + +#[test] +fn builtin_provider_menu_selects_ts_preset_for_draft() { + let mut host = WidgetHost::new(); + let panel = AgentSettingsPanel::for_editor(&host.editor_state); + let rect = panel.rect(1200.0, 800.0); + let content_x = rect.origin.x + 200.0 + 24.0; + let content_y = rect.origin.y + 24.0; + let content_w = rect.size.x - 200.0 - 48.0; + let add_x = content_x + content_w - 48.0; + let add_y = content_y + 24.0; + + assert!(host.dispatch_agent_settings_press(add_x, add_y, 1200.0, 800.0)); + let card_y = content_y + 12.0 + 28.0 + 28.0; + let provider_x = content_x + 68.0 + 24.0; + let provider_y = card_y + 60.0; + assert!(host.dispatch_agent_settings_press(provider_x, provider_y, 1200.0, 800.0)); + let minimax_y = card_y + 76.0 + 4.0 + 5.0 * 24.0 + 12.0; + assert!(host.dispatch_agent_settings_press(provider_x, minimax_y, 1200.0, 800.0)); + + let draft = host + .editor_state + .editor_ui + .agent_settings + .builtin_agent_draft + .as_ref() + .expect("draft remains open"); + assert_eq!(draft.preset, op_editor_core::BuiltinAgentPresetKey::MiniMax); + assert_eq!(draft.display_name, "MiniMax"); + assert_eq!(draft.model, "MiniMax-M2.7"); + assert_eq!(draft.base_url, "https://api.minimaxi.com/anthropic"); +} + +#[test] +fn save_builtin_agent_draft_persists_provider() { + let mut host = WidgetHost::new(); + let panel = AgentSettingsPanel::for_editor(&host.editor_state); + let rect = panel.rect(1200.0, 800.0); + let content_x = rect.origin.x + 200.0 + 24.0; + let content_y = rect.origin.y + 24.0; + let content_w = rect.size.x - 200.0 - 48.0; + let add_x = content_x + content_w - 48.0; + let add_y = content_y + 24.0; + + assert!(host.dispatch_agent_settings_press(add_x, add_y, 1200.0, 800.0)); + for c in "sk-web".chars() { + assert!(host.apply_text(c)); + } + let card_y = content_y + 12.0 + 28.0 + 28.0; + let save_x = content_x + content_w - 12.0 - 34.0; + let save_y = card_y + 196.0 + 18.0; + assert!(host.dispatch_agent_settings_press(save_x, save_y, 1200.0, 800.0)); + + let settings = &host.editor_state.editor_ui.agent_settings; + assert_eq!(settings.builtin_agents.len(), 1); + assert!(settings.builtin_agent_draft.is_none()); + assert_eq!(settings.builtin_agents[0].api_key, "sk-web"); + assert!(settings.focus.is_none()); +} + +#[test] +fn image_generation_profile_header_click_toggles_editor_closed() { + let mut host = WidgetHost::new(); + host.editor_state.editor_ui.agent_settings.tab = AgentSettingsTab::Images; + host.editor_state + .editor_ui + .agent_settings + .add_image_gen_profile(); + host.editor_state.editor_ui.agent_settings.focus = Some(SettingsFocus::ImageGenProfile { + index: 0, + field: ImageGenField::Name, + }); + host.editor_state.editor_ui.settings_input_draft = "Config 1".into(); + + let panel = AgentSettingsPanel::for_editor(&host.editor_state); + let rect = panel.rect(1200.0, 800.0); + let content_x = rect.origin.x + 200.0 + 24.0; + let content_y = rect.origin.y + 24.0; + let gen_top = content_y + 36.0 + 24.0 + 28.0; + let row_y = gen_top + 36.0; + + assert!(host.dispatch_agent_settings_press(content_x + 72.0, row_y + 16.0, 1200.0, 800.0)); + + assert_eq!(host.editor_state.editor_ui.agent_settings.focus, None); + assert!(host.editor_state.editor_ui.settings_input_draft.is_empty()); +}