From 04746248a7dfd81b0eed58b381f4241ac53f315d Mon Sep 17 00:00:00 2001 From: Fini Date: Sat, 30 May 2026 06:37:17 +0800 Subject: [PATCH] fix(ai): edit openverse image search credentials --- crates/op-editor-core/src/agent_settings.rs | 13 +++ crates/op-editor-core/src/lib.rs | 4 +- .../src/widgets/agent_settings_images.rs | 88 ++++++++++++++++--- .../src/widgets/agent_settings_panel.rs | 8 +- .../src/widgets/agent_settings_panel_tests.rs | 52 ++++++++++- crates/op-host-desktop/src/settings_io.rs | 53 +++++++++++ .../src/widget_host/agent_settings_tests.rs | 82 ++++++++++++++++- .../src/widget_host/keyboard.rs | 3 + .../src/widget_host/press_helpers.rs | 30 ++++++- .../src/widget_host/settings_dispatch.rs | 14 +++ .../op-host-web/src/widget_host/keyboard.rs | 31 ++++++- crates/op-host-web/src/widget_host/press.rs | 2 +- 12 files changed, 356 insertions(+), 24 deletions(-) diff --git a/crates/op-editor-core/src/agent_settings.rs b/crates/op-editor-core/src/agent_settings.rs index ad4cf0401..fbf1f926e 100644 --- a/crates/op-editor-core/src/agent_settings.rs +++ b/crates/op-editor-core/src/agent_settings.rs @@ -108,9 +108,16 @@ pub enum ImageGenField { BaseUrl, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ImageSearchField { + ClientId, + ClientSecret, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SettingsFocus { McpPort, + ImageSearch(ImageSearchField), BuiltinAgent { index: usize, field: BuiltinAgentField, @@ -216,6 +223,8 @@ pub struct AgentSettings { pub mcp_cli_enabled: [bool; 6], pub images_advanced_open: bool, pub images_search_ready: bool, + pub openverse_client_id: String, + pub openverse_client_secret: String, pub image_gen_profiles: Vec, pub active_image_gen_profile_id: Option, pub next_image_gen_profile_id: u64, @@ -245,6 +254,8 @@ impl Default for AgentSettings { mcp_cli_enabled: [false; 6], images_advanced_open: false, images_search_ready: true, + openverse_client_id: String::new(), + openverse_client_secret: String::new(), image_gen_profiles: Vec::new(), active_image_gen_profile_id: None, next_image_gen_profile_id: 1, @@ -345,6 +356,8 @@ mod tests { assert!(s.image_gen_profiles.is_empty()); assert!(s.active_image_gen_profile_id.is_none()); assert!(!s.images_advanced_open); + assert!(s.openverse_client_id.is_empty()); + assert!(s.openverse_client_secret.is_empty()); assert_eq!(s.mcp_server.port, 3100); assert!(s.auto_update_enabled); assert!(s.focus.is_none()); diff --git a/crates/op-editor-core/src/lib.rs b/crates/op-editor-core/src/lib.rs index 191a2dd33..adfa02b16 100644 --- a/crates/op-editor-core/src/lib.rs +++ b/crates/op-editor-core/src/lib.rs @@ -70,8 +70,8 @@ mod tests_pages; pub use agent_settings::{ AgentSettings, AgentSettingsDrag, AgentSettingsTab, BuiltinAgentConfig, BuiltinAgentField, - BuiltinAgentKind, ImageGenField, ImageGenProfile, ImageGenProvider, McpCli, McpServer, - SettingsFocus, + BuiltinAgentKind, ImageGenField, ImageGenProfile, ImageGenProvider, ImageSearchField, McpCli, + McpServer, SettingsFocus, }; pub use align::AlignAction; pub use chat::{ 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 8aea3f10f..8ad4a3668 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_images.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_images.rs @@ -6,7 +6,7 @@ use crate::widgets::icons::{draw_icon, Icon}; use crate::widgets::PaintCx; use crate::{Color, Point2D, Rect, TextLayout}; use op_editor_core::agent_settings::{ - AgentSettings, ImageGenField, ImageGenProfile, SettingsFocus, + AgentSettings, ImageGenField, ImageGenProfile, ImageSearchField, SettingsFocus, }; use op_editor_core::editor_ui_state::EditorUiState; @@ -33,6 +33,7 @@ const PROFILE_FIELD_H: f32 = 24.0; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ImagesHit { ToggleAdvanced, + FocusSearchField(ImageSearchField), TestSearch, AddGenConfig, SetActiveGenConfig(usize), @@ -94,6 +95,23 @@ fn register_link_y(content: Rect) -> f32 { content.origin.y + TITLE_H + ADVANCED_ROW_H + SUBTITLE_H + ROW_H + ROW_VGAP + ROW_H + BODY_GAP } +fn search_field_rect(content: Rect, index: usize) -> Rect { + let y = content.origin.y + + TITLE_H + + ADVANCED_ROW_H + + SUBTITLE_H + + if index == 0 { 0.0 } else { ROW_H + ROW_VGAP }; + Rect { + origin: Point2D::new(content.origin.x + LABEL_W, y), + size: Point2D::new(content.size.x - LABEL_W, ROW_H), + } +} + +fn has_search_credentials(settings: &AgentSettings) -> bool { + !settings.openverse_client_id.trim().is_empty() + || !settings.openverse_client_secret.trim().is_empty() +} + fn test_btn_rect(content: Rect, settings: &AgentSettings) -> Rect { if !settings.images_advanced_open { return Rect { @@ -169,8 +187,18 @@ pub fn hit_test(content: Rect, settings: &AgentSettings, scrolled: Point2D) -> I if rect_contains(advanced_toggle_rect(content), scrolled) { return ImagesHit::ToggleAdvanced; } - if settings.images_advanced_open && rect_contains(test_btn_rect(content, settings), scrolled) { - return ImagesHit::TestSearch; + if settings.images_advanced_open { + if rect_contains(search_field_rect(content, 0), scrolled) { + return ImagesHit::FocusSearchField(ImageSearchField::ClientId); + } + if rect_contains(search_field_rect(content, 1), scrolled) { + return ImagesHit::FocusSearchField(ImageSearchField::ClientSecret); + } + if has_search_credentials(settings) + && rect_contains(test_btn_rect(content, settings), scrolled) + { + return ImagesHit::TestSearch; + } } if rect_contains(add_btn_rect(content, settings), scrolled) { return ImagesHit::AddGenConfig; @@ -298,9 +326,12 @@ pub(super) fn paint_images_tab( cx.backend .draw_text(&sub, Point2D::new(content.origin.x, y + 14.0)); y += SUBTITLE_H; - paint_input_row( + paint_search_input_row( cx, theme, + settings, + ui, + ImageSearchField::ClientId, t_settings(ui, "settings.images.clientId"), t_settings(ui, "settings.images.clientIdPlaceholder"), content.origin.x, @@ -308,9 +339,12 @@ pub(super) fn paint_images_tab( content.size.x, ); y += ROW_H + ROW_VGAP; - paint_input_row( + paint_search_input_row( cx, theme, + settings, + ui, + ImageSearchField::ClientSecret, t_settings(ui, "settings.images.clientSecret"), t_settings(ui, "settings.images.clientSecretPlaceholder"), content.origin.x, @@ -588,9 +622,13 @@ fn paint_profile_field( ); } -fn paint_input_row( +#[allow(clippy::too_many_arguments)] +fn paint_search_input_row( cx: &mut PaintCx<'_>, theme: &Theme, + settings: &AgentSettings, + ui: &EditorUiState, + field_kind: ImageSearchField, label: &str, placeholder: &str, x: f32, @@ -611,16 +649,44 @@ fn paint_input_row( size: Point2D::new(w - LABEL_W, ROW_H), }; cx.backend.fill_round_rect(field, 6.0, theme.background); - cx.backend.stroke_round_rect(field, 6.0, theme.border, 1.0); - let ph = TextLayout::single_run( - placeholder, + let focused = settings.focus == Some(SettingsFocus::ImageSearch(field_kind)); + cx.backend.stroke_round_rect( + field, + 6.0, + if focused { theme.primary } else { theme.border }, + 1.0, + ); + let stored = match field_kind { + ImageSearchField::ClientId => settings.openverse_client_id.as_str(), + ImageSearchField::ClientSecret => settings.openverse_client_secret.as_str(), + }; + let text = if focused { + ui.settings_input_draft.as_str() + } else if matches!(field_kind, ImageSearchField::ClientSecret) && !stored.is_empty() { + "********" + } else { + stored + }; + let showing_placeholder = text.is_empty(); + let value = if showing_placeholder { + placeholder + } else { + text + }; + let value = ellipsize(cx, value, field.size.x - 24.0, 13.0); + let lay = TextLayout::single_run( + &value, "system-ui", 13.0, - to_jian(theme.muted_foreground), + to_jian(if showing_placeholder { + theme.muted_foreground + } else { + theme.foreground + }), Point2D::new(0.0, 0.0), ); cx.backend.draw_text( - &ph, + &lay, Point2D::new(field.origin.x + 12.0, field.origin.y + ROW_H / 2.0 + 5.0), ); } diff --git a/crates/op-editor-ui/src/widgets/agent_settings_panel.rs b/crates/op-editor-ui/src/widgets/agent_settings_panel.rs index b2c21d9bd..aa07f65b2 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_panel.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_panel.rs @@ -1,6 +1,5 @@ //! Multi-tab settings modal opened via `Cmd+,`. Left sidebar //! nav (Agents / MCP / Images / System) + scrollable right pane. -//! Visual parity with the TS app's settings panel. use crate::theme::Theme; use crate::widgets::agent_settings_builtin::{self, BuiltinHit}; @@ -14,7 +13,8 @@ use crate::widgets::icons::{draw_icon, Icon}; use crate::widgets::{PaintCx, Widget, WidgetId}; use crate::{Color, Point2D, Rect, TextLayout}; use op_editor_core::agent_settings::{ - AgentProvider, AgentSettings, AgentSettingsTab, BuiltinAgentField, ImageGenField, McpCli, + AgentProvider, AgentSettings, AgentSettingsTab, BuiltinAgentField, ImageGenField, + ImageSearchField, McpCli, }; use op_editor_core::editor_ui_state::EditorUiState; use op_editor_core::EditorState; @@ -54,6 +54,7 @@ pub enum AgentSettingsHit { ToggleMcpServer, ToggleMcpCli(McpCli), ToggleImagesAdvanced, + FocusSearchField(ImageSearchField), TestImageSearch, AddGenConfig, SetActiveGenConfig(usize), @@ -166,6 +167,9 @@ impl<'a> AgentSettingsPanel<'a> { match agent_settings_images::hit_test(content_rect(panel), &self.settings, scrolled) { ImagesHit::ToggleAdvanced => return AgentSettingsHit::ToggleImagesAdvanced, + ImagesHit::FocusSearchField(field) => { + return AgentSettingsHit::FocusSearchField(field); + } ImagesHit::TestSearch => return AgentSettingsHit::TestImageSearch, ImagesHit::AddGenConfig => return AgentSettingsHit::AddGenConfig, ImagesHit::SetActiveGenConfig(index) => { 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 3eb66f32d..1aef825f1 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 @@ -1,6 +1,6 @@ use crate::widgets::agent_settings_panel::{AgentSettingsHit, AgentSettingsPanel}; use op_editor_core::agent_settings::{ - AgentSettingsTab, BuiltinAgentField, ImageGenField, SettingsFocus, + AgentSettingsTab, BuiltinAgentField, ImageGenField, ImageSearchField, SettingsFocus, }; use op_editor_core::EditorState; @@ -197,6 +197,56 @@ fn images_tab_profile_rows_expose_active_and_remove_targets() { ); } +#[test] +fn images_tab_advanced_search_fields_are_focusable() { + let mut state = EditorState::default(); + state.editor_ui.agent_settings.tab = AgentSettingsTab::Images; + state.editor_ui.agent_settings.images_advanced_open = true; + let panel = AgentSettingsPanel::for_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 field_x = content_x + 110.0 + 16.0; + let first_field_y = content_y + 36.0 + 24.0 + 22.0; + + assert_eq!( + panel.hit_test(rect, crate::Point2D::new(field_x, first_field_y + 18.0)), + AgentSettingsHit::FocusSearchField(ImageSearchField::ClientId) + ); + assert_eq!( + panel.hit_test( + rect, + crate::Point2D::new(field_x, first_field_y + 36.0 + 10.0 + 18.0) + ), + AgentSettingsHit::FocusSearchField(ImageSearchField::ClientSecret) + ); +} + +#[test] +fn images_tab_test_search_requires_some_oauth_text() { + let mut state = EditorState::default(); + state.editor_ui.agent_settings.tab = AgentSettingsTab::Images; + state.editor_ui.agent_settings.images_advanced_open = true; + 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 + ); + + state.editor_ui.agent_settings.openverse_client_id = "client".into(); + let panel = AgentSettingsPanel::for_editor(&state); + assert_eq!( + panel.hit_test(rect, crate::Point2D::new(button_x, button_y)), + AgentSettingsHit::TestImageSearch + ); +} + #[test] fn images_tab_content_height_includes_profile_rows() { let mut empty = EditorState::default(); diff --git a/crates/op-host-desktop/src/settings_io.rs b/crates/op-host-desktop/src/settings_io.rs index 006615b4a..b0efdacb2 100644 --- a/crates/op-host-desktop/src/settings_io.rs +++ b/crates/op-host-desktop/src/settings_io.rs @@ -51,6 +51,12 @@ struct ImageGenProfilePayload { base_url: Option, } +#[derive(Debug, Serialize, Deserialize, Clone)] +struct OpenverseOAuthPayload { + client_id: String, + client_secret: String, +} + /// Cheap snapshot of every persisted field. Captured before each /// dispatch; if it differs after, save the file. #[derive(Debug, Clone, PartialEq, Eq)] @@ -60,6 +66,8 @@ pub struct Fingerprint { port: u16, cli: [bool; 6], images_adv: bool, + openverse_client_id: String, + openverse_client_secret: String, auto_update_enabled: bool, connected: [bool; 5], builtin_agents: Vec, @@ -75,6 +83,8 @@ pub fn fingerprint(state: &EditorState) -> Fingerprint { port: eui.agent_settings.mcp_server.port, cli: eui.agent_settings.mcp_cli_enabled, images_adv: eui.agent_settings.images_advanced_open, + openverse_client_id: eui.agent_settings.openverse_client_id.clone(), + openverse_client_secret: eui.agent_settings.openverse_client_secret.clone(), auto_update_enabled: eui.agent_settings.auto_update_enabled, connected: eui.agent_settings.connected, builtin_agents: eui.agent_settings.builtin_agents.clone(), @@ -107,6 +117,8 @@ struct SettingsPayload { #[serde(default)] images_advanced_open: Option, #[serde(default)] + openverse_oauth: Option, + #[serde(default)] auto_update_enabled: Option, /// Per-provider connect state, indexed by `AgentProvider::ALL` /// (Claude / Codex / OpenCode / Copilot / Gemini). Restored on @@ -141,6 +153,7 @@ fn to_payload(state: &EditorState) -> SettingsPayload { mcp_port: Some(eui.agent_settings.mcp_server.port), mcp_cli_enabled: Some(eui.agent_settings.mcp_cli_enabled), images_advanced_open: Some(eui.agent_settings.images_advanced_open), + openverse_oauth: openverse_oauth_to_payload(&eui.agent_settings), auto_update_enabled: Some(eui.agent_settings.auto_update_enabled), connected: Some(eui.agent_settings.connected), builtin_agents: Some( @@ -201,6 +214,10 @@ fn apply_payload(state: &mut EditorState, payload: SettingsPayload) { if let Some(b) = payload.images_advanced_open { eui.agent_settings.images_advanced_open = b; } + if let Some(oauth) = payload.openverse_oauth { + eui.agent_settings.openverse_client_id = oauth.client_id; + eui.agent_settings.openverse_client_secret = oauth.client_secret; + } if let Some(b) = payload.auto_update_enabled { eui.agent_settings.auto_update_enabled = b; } @@ -296,6 +313,21 @@ fn builtin_agent_from_payload(payload: BuiltinAgentPayload) -> Option Option { + let client_id = settings.openverse_client_id.trim(); + let client_secret = settings.openverse_client_secret.trim(); + if client_id.is_empty() && client_secret.is_empty() { + None + } else { + Some(OpenverseOAuthPayload { + client_id: client_id.to_string(), + client_secret: client_secret.to_string(), + }) + } +} + fn image_gen_profile_to_payload(profile: &ImageGenProfile) -> ImageGenProfilePayload { ImageGenProfilePayload { id: profile.id.clone(), @@ -597,6 +629,27 @@ mod tests { ); } + #[test] + fn openverse_oauth_round_trips_through_payload() { + let mut src = EditorState::new(); + src.editor_ui.agent_settings.openverse_client_id = "client-id".into(); + src.editor_ui.agent_settings.openverse_client_secret = "client-secret".into(); + + let json = serde_json::to_string(&to_payload(&src)).unwrap(); + let payload: SettingsPayload = serde_json::from_str(&json).unwrap(); + let mut dst = EditorState::new(); + apply_payload(&mut dst, payload); + + assert_eq!( + dst.editor_ui.agent_settings.openverse_client_id, + "client-id" + ); + assert_eq!( + dst.editor_ui.agent_settings.openverse_client_secret, + "client-secret" + ); + } + #[test] fn auto_update_preference_round_trips_through_payload() { let mut src = EditorState::new(); 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 de3abb0cf..d496f12d3 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,6 +1,6 @@ use super::WidgetHostNative; use op_editor_core::agent_settings::{ - AgentSettingsTab, BuiltinAgentField, ImageGenField, SettingsFocus, + AgentSettingsTab, BuiltinAgentField, ImageGenField, ImageSearchField, SettingsFocus, }; use op_editor_ui::widgets::agent_settings_panel::AgentSettingsPanel; @@ -282,3 +282,83 @@ fn image_generation_profile_focus_accepts_text_and_commits() { .settings_input_draft .is_empty()); } + +#[test] +fn image_search_oauth_focus_accepts_text_and_commits() { + let mut host = WidgetHostNative::new(); + host.editor_state_mut().editor_ui.agent_settings.tab = AgentSettingsTab::Images; + host.editor_state_mut().editor_ui.agent_settings.focus = + Some(SettingsFocus::ImageSearch(ImageSearchField::ClientId)); + host.editor_state_mut() + .editor_ui + .settings_input_draft + .clear(); + + for c in "openverse-client".chars() { + assert!(host.apply_text(c)); + } + assert!(host.apply_send()); + + host.editor_state_mut().editor_ui.agent_settings.focus = + Some(SettingsFocus::ImageSearch(ImageSearchField::ClientSecret)); + host.editor_state_mut() + .editor_ui + .settings_input_draft + .clear(); + for c in "openverse-secret".chars() { + assert!(host.apply_text(c)); + } + assert!(host.apply_send()); + + let settings = &host.editor_state().editor_ui.agent_settings; + assert_eq!(settings.openverse_client_id, "openverse-client"); + assert_eq!(settings.openverse_client_secret, "openverse-secret"); + assert!(settings.focus.is_none()); + assert!(host + .editor_state() + .editor_ui + .settings_input_draft + .is_empty()); +} + +#[test] +fn image_search_test_updates_ready_status_from_oauth_completeness() { + let mut host = WidgetHostNative::new(); + host.editor_state_mut().editor_ui.agent_settings.tab = AgentSettingsTab::Images; + host.editor_state_mut() + .editor_ui + .agent_settings + .images_advanced_open = true; + host.editor_state_mut() + .editor_ui + .agent_settings + .openverse_client_id = "client".into(); + + let panel = AgentSettingsPanel::for_editor(host.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 x = rect.origin.x + 200.0 + 24.0 + content_w - 28.0; + 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!( + !host + .editor_state() + .editor_ui + .agent_settings + .images_search_ready + ); + + host.editor_state_mut() + .editor_ui + .agent_settings + .openverse_client_secret = "secret".into(); + assert!(host.dispatch_agent_settings_press(x, y, 1200.0, 800.0)); + assert!( + host.editor_state() + .editor_ui + .agent_settings + .images_search_ready + ); +} diff --git a/crates/op-host-native/src/widget_host/keyboard.rs b/crates/op-host-native/src/widget_host/keyboard.rs index 78352b87c..8274f036f 100644 --- a/crates/op-host-native/src/widget_host/keyboard.rs +++ b/crates/op-host-native/src/widget_host/keyboard.rs @@ -20,6 +20,9 @@ impl WidgetHostNative { op_editor_core::agent_settings::SettingsFocus::McpPort => { c.is_ascii_digit() && draft.len() < 5 } + op_editor_core::agent_settings::SettingsFocus::ImageSearch(_) => { + !c.is_control() && draft.len() < 512 + } op_editor_core::agent_settings::SettingsFocus::BuiltinAgent { .. } => { !c.is_control() && draft.len() < 512 } 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 c1e4367b9..555286abc 100644 --- a/crates/op-host-native/src/widget_host/press_helpers.rs +++ b/crates/op-host-native/src/widget_host/press_helpers.rs @@ -103,6 +103,32 @@ impl WidgetHostNative { .images_advanced_open; *v = !*v; } + AgentSettingsHit::FocusSearchField(field) => { + self.commit_settings_focus_if_any(); + self.editor_state.editor_ui.settings_input_draft = match field { + op_editor_core::agent_settings::ImageSearchField::ClientId => self + .editor_state + .editor_ui + .agent_settings + .openverse_client_id + .clone(), + op_editor_core::agent_settings::ImageSearchField::ClientSecret => self + .editor_state + .editor_ui + .agent_settings + .openverse_client_secret + .clone(), + }; + self.editor_state.editor_ui.agent_settings.focus = Some( + op_editor_core::agent_settings::SettingsFocus::ImageSearch(field), + ); + } + AgentSettingsHit::TestImageSearch => { + self.commit_settings_focus_if_any(); + 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(); + } AgentSettingsHit::SetActiveGenConfig(index) => { self.commit_settings_focus_if_any(); if let Some(id) = self @@ -306,9 +332,7 @@ impl WidgetHostNative { self.editor_state.editor_ui.settings_input_draft.clear(); self.editor_state.rebuild_chat_models(); } - AgentSettingsHit::AddAcpAgent - | AgentSettingsHit::TestImageSearch - | AgentSettingsHit::Inside => {} + AgentSettingsHit::AddAcpAgent | AgentSettingsHit::Inside => {} AgentSettingsHit::AddGenConfig => { self.commit_settings_focus_if_any(); let id = self diff --git a/crates/op-host-native/src/widget_host/settings_dispatch.rs b/crates/op-host-native/src/widget_host/settings_dispatch.rs index 752ef4f3d..9291b8a73 100644 --- a/crates/op-host-native/src/widget_host/settings_dispatch.rs +++ b/crates/op-host-native/src/widget_host/settings_dispatch.rs @@ -16,6 +16,20 @@ impl WidgetHostNative { self.editor_state.editor_ui.agent_settings.mcp_server.port = port.max(1024); } } + SettingsFocus::ImageSearch(field) => match field { + op_editor_core::agent_settings::ImageSearchField::ClientId => { + self.editor_state + .editor_ui + .agent_settings + .openverse_client_id = draft.trim().to_string(); + } + op_editor_core::agent_settings::ImageSearchField::ClientSecret => { + self.editor_state + .editor_ui + .agent_settings + .openverse_client_secret = draft.trim().to_string(); + } + }, SettingsFocus::BuiltinAgent { index, field } => { if let Some(agent) = self .editor_state diff --git a/crates/op-host-web/src/widget_host/keyboard.rs b/crates/op-host-web/src/widget_host/keyboard.rs index d5aca7677..534a39404 100644 --- a/crates/op-host-web/src/widget_host/keyboard.rs +++ b/crates/op-host-web/src/widget_host/keyboard.rs @@ -13,9 +13,20 @@ impl WidgetHost { /// Push a typed character into the focused chat / settings input. /// Returns true if anything changed. pub fn apply_text(&mut self, c: char) -> bool { - if self.editor_state.editor_ui.agent_settings.focus.is_some() { - if c.is_ascii_digit() && self.editor_state.editor_ui.settings_input_draft.len() < 5 { - self.editor_state.editor_ui.settings_input_draft.push(c); + if let Some(focus) = self.editor_state.editor_ui.agent_settings.focus { + let draft = &mut self.editor_state.editor_ui.settings_input_draft; + let accepts = match focus { + op_editor_core::agent_settings::SettingsFocus::McpPort => { + c.is_ascii_digit() && draft.len() < 5 + } + op_editor_core::agent_settings::SettingsFocus::ImageSearch(_) + | op_editor_core::agent_settings::SettingsFocus::BuiltinAgent { .. } + | op_editor_core::agent_settings::SettingsFocus::ImageGenProfile { .. } => { + !c.is_control() && draft.len() < 512 + } + }; + if accepts { + draft.push(c); self.mark_dirty(); return true; } @@ -404,6 +415,20 @@ impl WidgetHost { self.editor_state.editor_ui.agent_settings.mcp_server.port = port.max(1024); } } + SettingsFocus::ImageSearch(field) => match field { + op_editor_core::agent_settings::ImageSearchField::ClientId => { + self.editor_state + .editor_ui + .agent_settings + .openverse_client_id = draft.trim().to_string(); + } + op_editor_core::agent_settings::ImageSearchField::ClientSecret => { + self.editor_state + .editor_ui + .agent_settings + .openverse_client_secret = draft.trim().to_string(); + } + }, SettingsFocus::BuiltinAgent { .. } | SettingsFocus::ImageGenProfile { .. } => {} } self.mark_dirty(); diff --git a/crates/op-host-web/src/widget_host/press.rs b/crates/op-host-web/src/widget_host/press.rs index 1f3b4a818..c1ee2450f 100644 --- a/crates/op-host-web/src/widget_host/press.rs +++ b/crates/op-host-web/src/widget_host/press.rs @@ -718,7 +718,6 @@ impl WidgetHost { was_focused } - /// Cmd+, settings modal — dispatch hit-tests on the modal. /// Returns true once the modal swallowed the press. fn dispatch_agent_settings_press(&mut self, x: f32, y: f32, vw: f32, vh: f32) -> bool { use op_editor_ui::widgets::agent_settings_panel::{AgentSettingsHit, AgentSettingsPanel}; @@ -791,6 +790,7 @@ impl WidgetHost { | AgentSettingsHit::AddGenConfig | AgentSettingsHit::SetActiveGenConfig(_) | AgentSettingsHit::RemoveGenConfig(_) + | AgentSettingsHit::FocusSearchField(_) | AgentSettingsHit::FocusGenConfig { .. } | AgentSettingsHit::Inside => {} }