From ed44520e51bafbbff4cbddcde67e5113294a67fd Mon Sep 17 00:00:00 2001 From: yiliang114 <1204183885@qq.com> Date: Sat, 6 Dec 2025 21:46:31 +0800 Subject: [PATCH] fix(vscode-ide-companion): clean up deprecated permission drawer file Remove obsolete PermissionDrawer.tsx file that has been replaced by the new directory structure --- .../webview/components/PermissionDrawer.tsx | 313 ------------------ 1 file changed, 313 deletions(-) delete mode 100644 packages/vscode-ide-companion/src/webview/components/PermissionDrawer.tsx diff --git a/packages/vscode-ide-companion/src/webview/components/PermissionDrawer.tsx b/packages/vscode-ide-companion/src/webview/components/PermissionDrawer.tsx deleted file mode 100644 index 94ad29e1..00000000 --- a/packages/vscode-ide-companion/src/webview/components/PermissionDrawer.tsx +++ /dev/null @@ -1,313 +0,0 @@ -/** - * @license - * Copyright 2025 Qwen Team - * SPDX-License-Identifier: Apache-2.0 - */ - -import type React from 'react'; -import { useEffect, useState, useRef } from 'react'; -import type { PermissionOption, ToolCall } from './PermissionRequest.js'; - -interface PermissionDrawerProps { - isOpen: boolean; - options: PermissionOption[]; - toolCall: ToolCall; - onResponse: (optionId: string) => void; - onClose?: () => void; -} - -/** - * Permission drawer component - Claude Code style bottom sheet - */ -export const PermissionDrawer: React.FC = ({ - isOpen, - options, - toolCall, - onResponse, - onClose, -}) => { - const [focusedIndex, setFocusedIndex] = useState(0); - const [customMessage, setCustomMessage] = useState(''); - const containerRef = useRef(null); - // 将自定义输入的 ref 类型修正为 HTMLInputElement,避免后续强转 - const customInputRef = useRef(null); - - console.log('PermissionDrawer rendered with isOpen:', isOpen, toolCall); - // Prefer file name from locations, fall back to content[].path if present - const getAffectedFileName = (): string => { - const fromLocations = toolCall.locations?.[0]?.path; - if (fromLocations) { - return fromLocations.split('/').pop() || fromLocations; - } - // Some tool calls (e.g. write/edit with diff content) only include path in content - const fromContent = Array.isArray(toolCall.content) - ? ( - toolCall.content.find( - (c: unknown) => - typeof c === 'object' && - c !== null && - 'path' in (c as Record), - ) as { path?: unknown } | undefined - )?.path - : undefined; - if (typeof fromContent === 'string' && fromContent.length > 0) { - return fromContent.split('/').pop() || fromContent; - } - return 'file'; - }; - - // Get the title for the permission request - const getTitle = () => { - if (toolCall.kind === 'edit' || toolCall.kind === 'write') { - const fileName = getAffectedFileName(); - return ( - <> - Make this edit to{' '} - - {fileName} - - ? - - ); - } - if (toolCall.kind === 'execute' || toolCall.kind === 'bash') { - return 'Allow this bash command?'; - } - if (toolCall.kind === 'read') { - const fileName = getAffectedFileName(); - return ( - <> - Allow read from{' '} - - {fileName} - - ? - - ); - } - return toolCall.title || 'Permission Required'; - }; - - // Handle keyboard navigation - useEffect(() => { - const handleKeyDown = (e: KeyboardEvent) => { - if (!isOpen) { - return; - } - - // Number keys 1-9 for quick select - const numMatch = e.key.match(/^[1-9]$/); - if ( - numMatch && - !customInputRef.current?.contains(document.activeElement) - ) { - const index = parseInt(e.key, 10) - 1; - if (index < options.length) { - e.preventDefault(); - onResponse(options[index].optionId); - } - return; - } - - // Arrow keys for navigation - if (e.key === 'ArrowDown' || e.key === 'ArrowUp') { - e.preventDefault(); - const totalItems = options.length + 1; // +1 for custom input - if (e.key === 'ArrowDown') { - setFocusedIndex((prev) => (prev + 1) % totalItems); - } else { - setFocusedIndex((prev) => (prev - 1 + totalItems) % totalItems); - } - } - - // Enter to select - if ( - e.key === 'Enter' && - !customInputRef.current?.contains(document.activeElement) - ) { - e.preventDefault(); - if (focusedIndex < options.length) { - onResponse(options[focusedIndex].optionId); - } - } - - // Escape to cancel permission and close (align with CLI/Claude behavior) - if (e.key === 'Escape') { - e.preventDefault(); - const rejectOptionId = - options.find((o) => o.kind.includes('reject'))?.optionId || - options.find((o) => o.optionId === 'cancel')?.optionId || - 'cancel'; - onResponse(rejectOptionId); - if (onClose) onClose(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); - }, [isOpen, options, onResponse, onClose, focusedIndex]); - - // Focus container when opened - useEffect(() => { - if (isOpen && containerRef.current) { - containerRef.current.focus(); - } - }, [isOpen]); - - // Reset focus to the first option when the drawer opens or the options change - useEffect(() => { - if (isOpen) { - setFocusedIndex(0); - } - }, [isOpen, options.length]); - - if (!isOpen) { - return null; - } - - return ( -
- {/* Main container */} -
- {/* Background layer */} -
- - {/* Title + Description (from toolCall.title) */} -
-
- {getTitle()} -
- {(toolCall.kind === 'edit' || - toolCall.kind === 'write' || - toolCall.kind === 'read' || - toolCall.kind === 'execute' || - toolCall.kind === 'bash') && - toolCall.title && ( -
- {toolCall.title} -
- )} -
- - {/* Options */} -
- {options.map((option, index) => { - const isFocused = focusedIndex === index; - - return ( - - ); - })} - - {/* Custom message input (extracted component) */} - {(() => { - const isFocused = focusedIndex === options.length; - const rejectOptionId = options.find((o) => - o.kind.includes('reject'), - )?.optionId; - return ( - setFocusedIndex(options.length)} - onSubmitReject={() => { - if (rejectOptionId) onResponse(rejectOptionId); - }} - inputRef={customInputRef} - /> - ); - })()} -
-
- - {/* Moved slide-up keyframes to Tailwind theme (tailwind.config.js) */} -
- ); -}; - -/** - * CustomMessageInputRow: 复用的自定义输入行组件(无 hooks) - */ -interface CustomMessageInputRowProps { - isFocused: boolean; - customMessage: string; - setCustomMessage: (val: string) => void; - onFocusRow: () => void; // 鼠标移入或输入框 focus 时设置焦点 - onSubmitReject: () => void; // Enter 提交时触发(选择 reject 选项) - inputRef: React.RefObject; -} - -const CustomMessageInputRow: React.FC = ({ - isFocused, - customMessage, - setCustomMessage, - onFocusRow, - onSubmitReject, - inputRef, -}) => ( -
inputRef.current?.focus()} - > - {/* 输入行不显示序号徽标 */} - {/* Input field */} - setCustomMessage(e.target.value)} - onFocus={onFocusRow} - onKeyDown={(e) => { - if (e.key === 'Enter' && !e.shiftKey && customMessage.trim()) { - e.preventDefault(); - onSubmitReject(); - } - }} - /> -
-);