From 8f1be67ab4ac512336603dd855d4bb178789b04e Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Fri, 3 Jul 2026 00:08:22 +0800 Subject: [PATCH] feat(web): hide desktop-only entry points on the web host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The image Search/Generate buttons, the six MCP CLI-integration toggles, and the auto-update card all painted on web with no executor behind them — clicking did nothing (silent dead UI, worse than a missing feature). Gate each behind a cfg const following the existing GIT_BUTTON_AVAILABLE pattern, with paint, hit-test, and layout heights kept in sync; the experimental-features card moves up into the hidden auto-update slot. --- .../src/widgets/agent_settings_mcp.rs | 20 +++- .../src/widgets/agent_settings_system.rs | 34 ++++-- .../src/widgets/property_panel_image_node.rs | 102 ++++++++++-------- 3 files changed, 101 insertions(+), 55 deletions(-) diff --git a/crates/op-editor-ui/src/widgets/agent_settings_mcp.rs b/crates/op-editor-ui/src/widgets/agent_settings_mcp.rs index 59e5510f6..5f363ab37 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_mcp.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_mcp.rs @@ -147,6 +147,13 @@ fn client_config_copy_button_rect(content: Rect) -> Rect { } } +/// Host capability: the CLI-integration toggles write MCP endpoints +/// into external CLI config files (`~/.claude.json` etc.) via the +/// desktop MCP runtime (`mcp_integrations.rs`). The web host has no +/// consumer — hide the grid there instead of painting toggles that +/// silently do nothing (same pattern as `GIT_BUTTON_AVAILABLE`). +pub(super) const CLI_INTEGRATIONS_AVAILABLE: bool = !cfg!(target_arch = "wasm32"); + pub fn hit_test(content: Rect, settings: &AgentSettings, scrolled: Point2D) -> McpHit { if (server_button_rect(content)).contains(scrolled) { return McpHit::ToggleServer; @@ -157,9 +164,11 @@ pub fn hit_test(content: Rect, settings: &AgentSettings, scrolled: Point2D) -> M if !settings.mcp_server.running && (port_field_rect(content)).contains(scrolled) { return McpHit::FocusPort; } - for (i, cli) in McpCli::ALL.iter().enumerate() { - if (cli_cell_rect(content, settings, i)).contains(scrolled) { - return McpHit::ToggleCli(*cli); + if CLI_INTEGRATIONS_AVAILABLE { + for (i, cli) in McpCli::ALL.iter().enumerate() { + if (cli_cell_rect(content, settings, i)).contains(scrolled) { + return McpHit::ToggleCli(*cli); + } } } McpHit::None @@ -187,6 +196,11 @@ pub(super) fn paint_mcp_tab( paint_server_card(cx, theme, settings, ui, content, now_ms); paint_client_config(cx, theme, settings, ui, content, now_ms); + // Terminal-integrations section — desktop-only (see + // `CLI_INTEGRATIONS_AVAILABLE`). + if !CLI_INTEGRATIONS_AVAILABLE { + return; + } let mut y = server_card_top(content) + SERVER_CARD_H + client_config_block_h(settings) + SECTION_GAP; let section_title = TextLayout::single_run( diff --git a/crates/op-editor-ui/src/widgets/agent_settings_system.rs b/crates/op-editor-ui/src/widgets/agent_settings_system.rs index 4028922c5..7b5396b51 100644 --- a/crates/op-editor-ui/src/widgets/agent_settings_system.rs +++ b/crates/op-editor-ui/src/widgets/agent_settings_system.rs @@ -37,7 +37,18 @@ fn auto_update_card_rect(content: Rect) -> Rect { } } +/// Host capability: the auto-update toggle drives the desktop +/// updater (`op-host-desktop/src/update_check.rs`). The web host has +/// no updater — hide the card there instead of painting a switch that +/// silently does nothing (same pattern as `GIT_BUTTON_AVAILABLE`). +pub(super) const AUTO_UPDATE_AVAILABLE: bool = !cfg!(target_arch = "wasm32"); + fn experimental_card_rect(content: Rect) -> Rect { + if !AUTO_UPDATE_AVAILABLE { + // The auto-update card is hidden — the experimental card + // moves up into its slot. + return auto_update_card_rect(content); + } Rect { origin: Point2D::new( content.origin.x, @@ -60,7 +71,7 @@ fn switch_rect_for(card: Rect) -> Rect { } pub fn hit_test(content: Rect, scrolled: Point2D) -> SystemHit { - if switch_rect_for(auto_update_card_rect(content)).contains(scrolled) { + if AUTO_UPDATE_AVAILABLE && switch_rect_for(auto_update_card_rect(content)).contains(scrolled) { return SystemHit::ToggleAutoUpdate; } if switch_rect_for(experimental_card_rect(content)).contains(scrolled) { @@ -88,15 +99,18 @@ pub(super) fn paint_system_tab( Point2D::new(content.origin.x, content.origin.y + 20.0), ); - paint_toggle_card( - cx, - theme, - ui, - auto_update_card_rect(content), - "agents.autoUpdate", - "settings.autoUpdateDesc", - settings.auto_update_enabled, - ); + // Auto-update card — desktop-only (see `AUTO_UPDATE_AVAILABLE`). + if AUTO_UPDATE_AVAILABLE { + paint_toggle_card( + cx, + theme, + ui, + auto_update_card_rect(content), + "agents.autoUpdate", + "settings.autoUpdateDesc", + settings.auto_update_enabled, + ); + } paint_toggle_card( cx, theme, diff --git a/crates/op-editor-ui/src/widgets/property_panel_image_node.rs b/crates/op-editor-ui/src/widgets/property_panel_image_node.rs index d48c4b3e5..c13b1988e 100644 --- a/crates/op-editor-ui/src/widgets/property_panel_image_node.rs +++ b/crates/op-editor-ui/src/widgets/property_panel_image_node.rs @@ -19,6 +19,13 @@ use crate::widgets::property_panel_inputs::{ use crate::widgets::PaintCx; use crate::{Point2D, Rect, TextLayout}; +/// Host capability: the Search / Generate buttons drive the image +/// search + generation sessions that only the desktop host executes +/// (`image_search_session.rs` / `image_generate_host.rs`). The web +/// host has no drain for them — hide the buttons there instead of +/// painting dead UI (same pattern as `GIT_BUTTON_AVAILABLE`). +pub(super) const IMAGE_REMOTE_ACTIONS_AVAILABLE: bool = !cfg!(target_arch = "wasm32"); + /// Total height the image section consumes BEFORE the trailing /// `SECTION_GAP` the walkers add — header + thumb row + optional /// warning + buttons row + the legacy 34 px divider tail. @@ -28,11 +35,15 @@ pub fn image_section_height(has_warning: bool) -> f32 { } else { 0.0 }; + let buttons = if IMAGE_REMOTE_ACTIONS_AVAILABLE { + IMAGE_ROW_GAP + IMAGE_BUTTON_H + } else { + 0.0 + }; crate::widgets::property_panel_inputs::SECTION_HEADER_HEIGHT + INPUT_HEIGHT + warning - + IMAGE_ROW_GAP - + IMAGE_BUTTON_H + + buttons + 34.0 } @@ -70,22 +81,24 @@ pub fn push_image_action_rects( )); y += IMAGE_WARNING_H; } - y += IMAGE_ROW_GAP; - let half_w = (usable_w - 4.0) / 2.0; - out.push(( - PropertyPanelAction::ToggleImageSearchPopover, - Rect { - origin: Point2D::new(x0 + PAD_X, y), - size: Point2D::new(half_w, IMAGE_BUTTON_H), - }, - )); - out.push(( - PropertyPanelAction::ToggleImageGeneratePopover, - Rect { - origin: Point2D::new(x0 + PAD_X + half_w + 4.0, y), - size: Point2D::new(half_w, IMAGE_BUTTON_H), - }, - )); + if IMAGE_REMOTE_ACTIONS_AVAILABLE { + y += IMAGE_ROW_GAP; + let half_w = (usable_w - 4.0) / 2.0; + out.push(( + PropertyPanelAction::ToggleImageSearchPopover, + Rect { + origin: Point2D::new(x0 + PAD_X, y), + size: Point2D::new(half_w, IMAGE_BUTTON_H), + }, + )); + out.push(( + PropertyPanelAction::ToggleImageGeneratePopover, + Rect { + origin: Point2D::new(x0 + PAD_X + half_w + 4.0, y), + size: Point2D::new(half_w, IMAGE_BUTTON_H), + }, + )); + } } #[allow(clippy::too_many_arguments)] @@ -160,30 +173,35 @@ pub fn paint_image_node_section( y = paint_warning_row(cx, theme, warning, x, y, width); } - // Search / Generate buttons (TS outline buttons, flex-1 h-7). - y += IMAGE_ROW_GAP; - let half_w = (usable_w - 4.0) / 2.0; - paint_outline_button( - cx, - theme, - Rect { - origin: Point2D::new(x + PAD_X, y), - size: Point2D::new(half_w, IMAGE_BUTTON_H), - }, - Icon::Search, - "Search", - ); - paint_outline_button( - cx, - theme, - Rect { - origin: Point2D::new(x + PAD_X + half_w + 4.0, y), - size: Point2D::new(half_w, IMAGE_BUTTON_H), - }, - Icon::Sparkles, - "Generate", - ); - y += IMAGE_BUTTON_H + 34.0; + // Search / Generate buttons (TS outline buttons, flex-1 h-7) — + // desktop-only, mirrored by `image_section_height` / + // `push_image_action_rects` so paint + hit-test stay in sync. + if IMAGE_REMOTE_ACTIONS_AVAILABLE { + y += IMAGE_ROW_GAP; + let half_w = (usable_w - 4.0) / 2.0; + paint_outline_button( + cx, + theme, + Rect { + origin: Point2D::new(x + PAD_X, y), + size: Point2D::new(half_w, IMAGE_BUTTON_H), + }, + Icon::Search, + "Search", + ); + paint_outline_button( + cx, + theme, + Rect { + origin: Point2D::new(x + PAD_X + half_w + 4.0, y), + size: Point2D::new(half_w, IMAGE_BUTTON_H), + }, + Icon::Sparkles, + "Generate", + ); + y += IMAGE_BUTTON_H; + } + y += 34.0; paint_section_divider(cx, theme, x, y, width); y + SECTION_GAP }