From e15dd2f5c944aa3905c73119d64252c8f4dfd7ea Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Sun, 23 Nov 2025 18:09:43 +0800 Subject: [PATCH] refactor(vscode-ide-companion): extract InfoBanner as standalone component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move info banner UI from App.tsx to dedicated component with open settings functionality. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../vscode-ide-companion/src/webview/App.scss | 70 --------- .../vscode-ide-companion/src/webview/App.tsx | 56 ++------ .../src/webview/MessageHandler.ts | 24 ++++ .../src/webview/components/InfoBanner.tsx | 135 ++++++++++++++++++ 4 files changed, 168 insertions(+), 117 deletions(-) create mode 100644 packages/vscode-ide-companion/src/webview/components/InfoBanner.tsx diff --git a/packages/vscode-ide-companion/src/webview/App.scss b/packages/vscode-ide-companion/src/webview/App.scss index 64abceed..d4f0cde1 100644 --- a/packages/vscode-ide-companion/src/webview/App.scss +++ b/packages/vscode-ide-companion/src/webview/App.scss @@ -532,76 +532,6 @@ button { flex: 1; } -/* =========================== - Info Banner (at bottom) - =========================== */ -.info-banner { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 12px 16px; - background-color: var(--app-input-secondary-background); - border-top: 1px solid var(--app-primary-border-color); -} - -.banner-content { - display: flex; - align-items: center; - gap: 12px; - flex: 1; - min-width: 0; -} - -.banner-icon { - flex-shrink: 0; - width: 16px; - height: 16px; - fill: var(--app-primary-foreground); -} - -.banner-content label { - font-size: 13px; - color: var(--app-primary-foreground); - margin: 0; - line-height: 1.4; -} - -.banner-link { - color: var(--app-qwen-orange); - text-decoration: none; - cursor: pointer; -} - -.banner-link:hover { - text-decoration: underline; -} - -.banner-close { - flex-shrink: 0; - width: 20px; - height: 20px; - padding: 0; - background: transparent; - border: none; - border-radius: var(--corner-radius-small); - color: var(--app-primary-foreground); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: background-color 0.2s; -} - -.banner-close:hover { - background-color: var(--app-ghost-button-hover-background); -} - -.banner-close svg { - width: 10px; - height: 10px; -} - /* =========================== Claude Code Style Input Form (.Me > .u) =========================== */ diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index 506a6f16..92e7ee76 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -23,6 +23,7 @@ import { } from './components/CompletionMenu.js'; import { useCompletionTrigger } from './hooks/useCompletionTrigger.js'; import { SaveSessionDialog } from './components/SaveSessionDialog.js'; +import { InfoBanner } from './components/InfoBanner.js'; interface ToolCallUpdate { type: 'tool_call' | 'tool_call_update'; @@ -1402,53 +1403,14 @@ export const App: React.FC = () => { {/* Info Banner */} - {showBanner && ( -
-
- - - - - - -
- -
- )} + setShowBanner(false)} + onLinkClick={(e) => { + e.preventDefault(); + vscode.postMessage({ type: 'openSettings', data: {} }); + }} + />
diff --git a/packages/vscode-ide-companion/src/webview/MessageHandler.ts b/packages/vscode-ide-companion/src/webview/MessageHandler.ts index 5c2e39f2..8bb937a1 100644 --- a/packages/vscode-ide-companion/src/webview/MessageHandler.ts +++ b/packages/vscode-ide-companion/src/webview/MessageHandler.ts @@ -207,6 +207,10 @@ export class MessageHandler { await this.handleResumeSession(data?.sessionId as string); break; + case 'openSettings': + await this.handleOpenSettings(); + break; + default: console.warn('[MessageHandler] Unknown message type:', message.type); break; @@ -922,4 +926,24 @@ export class MessageHandler { }); } } + + /** + * 处理打开设置请求 + * 打开 VSCode 设置页面并定位到扩展配置 + */ + private async handleOpenSettings(): Promise { + try { + console.log('[MessageHandler] Opening settings'); + await vscode.commands.executeCommand( + 'workbench.action.openSettings', + 'qwenCode', + ); + } catch (error) { + console.error('[MessageHandler] Failed to open settings:', error); + this.sendToWebView({ + type: 'error', + data: { message: `Failed to open settings: ${error}` }, + }); + } + } } diff --git a/packages/vscode-ide-companion/src/webview/components/InfoBanner.tsx b/packages/vscode-ide-companion/src/webview/components/InfoBanner.tsx new file mode 100644 index 00000000..c51377b0 --- /dev/null +++ b/packages/vscode-ide-companion/src/webview/components/InfoBanner.tsx @@ -0,0 +1,135 @@ +/** + * @license + * Copyright 2025 Qwen Team + * SPDX-License-Identifier: Apache-2.0 + */ + +import type React from 'react'; + +interface InfoBannerProps { + /** + * Whether the banner is visible + */ + visible: boolean; + + /** + * Callback when the banner is dismissed + */ + onDismiss: () => void; + + /** + * Optional: Custom message content (if not provided, uses default) + */ + message?: React.ReactNode; + + /** + * Optional: Custom link text + */ + linkText?: string; + + /** + * Optional: Callback when the link is clicked + */ + onLinkClick?: (e: React.MouseEvent) => void; +} + +export const InfoBanner: React.FC = ({ + visible, + onDismiss, + message, + linkText = 'Switch back in Settings.', + onLinkClick, +}) => { + if (!visible) { + return null; + } + + return ( +
+
+ {/* Icon */} + + + + + + + {/* Message */} + +
+ + {/* Close button */} + +
+ ); +};