Unverified 提交 e99cf759 authored 作者: Mohamed Aziz Mejri's avatar Mohamed Aziz Mejri 提交者: GitHub

Fixing regression and adding plus button to HomeChatInput (#2135)

closes #2127 This PR includes - Fixing the regression introduced in the beta release - Adding the plus button to HomeChatInput I will create a follow-up PR that makes the e2e test more realistic <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a plus actions menu to HomeChatInput for attachments and fixes the beta regression that prevented attaching files in home chat. - **New Features** - Added AuxiliaryActionsMenu to HomeChatInput with an “Attach files” submenu; hides context picker and token toggle when not needed. - Made menu props optional (showTokenBar/toggle) and added hideContextFilesPicker, improving reuse across inputs. - **Bug Fixes** - Restored file upload by handling menu item onSelect and closing the submenu after selection; inputs reset to allow re-uploading the same file. - Updated the e2e test to open the menu, hover “Attach files,” upload via the file input, and close with Escape. <sup>Written for commit 3db5abc98c9f968cb04eb355a586209e4725be30. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces a consolidated plus “AuxiliaryActionsMenu” for file/context actions in both chat inputs and fixes attachment menu interactions. > > - Adds `AuxiliaryActionsMenu` with optional `showTokenBar/toggle`, `showContextFilesPicker`, and `isStreaming`; disables attach submenu while streaming and conditionally shows context picker and token toggle > - Refactors `FileAttachmentDropdown` to render only menu items + hidden inputs, use `onSelect` to trigger file pickers, clear input values, and close parent via `onMenuClose` > - Integrates the new menu into `HomeChatInput` and `ChatInput`; keeps `ChatInputControls` and hides context picker where not needed > - Updates e2e tests to interact with the new menu, including attach-as-context, upload-to-codebase, and drag-and-drop flows; standardizes snapshots and closes menus via Escape > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 6b0d1f24b069a9e9b066f8dba59a8f43af318a08. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
上级 dce37cd6
......@@ -15,10 +15,23 @@ const SNAPSHOT_NAME = "attach-image";
test("attach image - home chat", async ({ po }) => {
await po.setUp();
// Open auxiliary actions menu
await po
.getHomeChatInputContainer()
.getByTestId("auxiliary-actions-menu")
.click();
// Hover over "Attach files" to open submenu
await po.page.getByRole("menuitem", { name: "Attach files" }).hover();
// attach via file input (click-to-upload)
await po.page
.getByTestId("chat-context-file-input")
.setInputFiles("e2e-tests/fixtures/images/logo.png");
// Close the menu by pressing Escape
await po.page.keyboard.press("Escape");
await po.sendPrompt("[dump]");
await po.snapshotServerDump("last-message", { name: SNAPSHOT_NAME });
await po.snapshotMessages({ replaceDumpPath: true });
......
......@@ -19,14 +19,16 @@ interface AuxiliaryActionsMenuProps {
files: FileList,
type: "chat-context" | "upload-to-codebase",
) => void;
showTokenBar: boolean;
toggleShowTokenBar: () => void;
showTokenBar?: boolean;
toggleShowTokenBar?: () => void;
hideContextFilesPicker?: boolean;
}
export function AuxiliaryActionsMenu({
onFileSelect,
showTokenBar,
toggleShowTokenBar,
hideContextFilesPicker,
}: AuxiliaryActionsMenuProps) {
const [isOpen, setIsOpen] = useState(false);
......@@ -47,7 +49,7 @@ export function AuxiliaryActionsMenu({
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{/* Codebase Context */}
<ContextFilesPicker />
{!hideContextFilesPicker && <ContextFilesPicker />}
{/* Attach Files Submenu */}
<DropdownMenuSub>
......@@ -58,14 +60,15 @@ export function AuxiliaryActionsMenu({
<DropdownMenuSubContent>
<FileAttachmentDropdown
onFileSelect={onFileSelect}
renderAsMenuItems={true}
closeMenu={() => setIsOpen(false)}
/>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
{/* Toggle Token Usage */}
{toggleShowTokenBar && (
<>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={toggleShowTokenBar}
className={`py-2 px-3 group ${showTokenBar ? "bg-primary/10 text-primary" : ""}`}
......@@ -83,6 +86,8 @@ export function AuxiliaryActionsMenu({
{showTokenBar ? "Hide" : "Show"} token usage
</span>
</DropdownMenuItem>
</>
)}
</DropdownMenuContent>
</DropdownMenu>
);
......
import { Paperclip, MessageSquare, Upload } from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { MessageSquare, Upload } from "lucide-react";
import { DropdownMenuItem } from "@/components/ui/dropdown-menu";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { useRef } from "react";
interface FileAttachmentDropdownProps {
......@@ -19,16 +13,12 @@ interface FileAttachmentDropdownProps {
files: FileList,
type: "chat-context" | "upload-to-codebase",
) => void;
disabled?: boolean;
className?: string;
renderAsMenuItems?: boolean;
closeMenu?: () => void;
}
export function FileAttachmentDropdown({
onFileSelect,
disabled,
className,
renderAsMenuItems = false,
closeMenu,
}: FileAttachmentDropdownProps) {
const chatContextFileInputRef = useRef<HTMLInputElement>(null);
const uploadToCodebaseFileInputRef = useRef<HTMLInputElement>(null);
......@@ -49,6 +39,8 @@ export function FileAttachmentDropdown({
onFileSelect(e.target.files, type);
// Clear the input value so the same file can be selected again
e.target.value = "";
// Close the parent menu after file selection
closeMenu?.();
}
};
......@@ -58,7 +50,12 @@ export function FileAttachmentDropdown({
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuItem
onClick={handleChatContextClick}
onSelect={(e) => {
// Prevent default so menu doesn't close in order to keep the hidden inputs in the DOM
// Manually close menu after file selection
e.preventDefault();
handleChatContextClick();
}}
className="py-3 px-4"
>
<MessageSquare size={16} className="mr-2" />
......@@ -75,7 +72,12 @@ export function FileAttachmentDropdown({
<Tooltip>
<TooltipTrigger asChild>
<DropdownMenuItem
onClick={handleUploadToCodebaseClick}
onSelect={(e) => {
// Prevent default so menu doesn't close in order to keep the hidden inputs in the DOM
// Manually close menu after file selection
e.preventDefault();
handleUploadToCodebaseClick();
}}
className="py-3 px-4"
>
<Upload size={16} className="mr-2" />
......@@ -113,41 +115,9 @@ export function FileAttachmentDropdown({
</>
);
// If rendering as menu items only, return just the items and hidden inputs
if (renderAsMenuItems) {
return (
<>
{menuItems}
{hiddenInputs}
</>
);
}
// Otherwise, render the full dropdown with button trigger
return (
<>
<TooltipProvider>
<Tooltip>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
disabled={disabled}
title="Attach files"
className={className}
>
<Paperclip size={20} />
</Button>
</TooltipTrigger>
</DropdownMenuTrigger>
<DropdownMenuContent align="start">{menuItems}</DropdownMenuContent>
</DropdownMenu>
<TooltipContent>Attach files</TooltipContent>
</Tooltip>
</TooltipProvider>
{hiddenInputs}
</>
);
......
......@@ -7,13 +7,14 @@ import { useStreamChat } from "@/hooks/useStreamChat";
import { useAttachments } from "@/hooks/useAttachments";
import { AttachmentsList } from "./AttachmentsList";
import { DragDropOverlay } from "./DragDropOverlay";
import { FileAttachmentDropdown } from "./FileAttachmentDropdown";
import { usePostHog } from "posthog-js/react";
import { HomeSubmitOptions } from "@/pages/home";
import { ChatInputControls } from "../ChatInputControls";
import { LexicalChatInput } from "./LexicalChatInput";
import { useChatModeToggle } from "@/hooks/useChatModeToggle";
import { useTypingPlaceholder } from "@/hooks/useTypingPlaceholder";
import { AuxiliaryActionsMenu } from "./AuxiliaryActionsMenu";
export function HomeChatInput({
onSubmit,
}: {
......@@ -97,16 +98,9 @@ export function HomeChatInput({
disableSendButton={false}
/>
{/* File attachment dropdown */}
<FileAttachmentDropdown
className="mt-1 mr-1"
onFileSelect={handleFileSelect}
disabled={isStreaming}
/>
{isStreaming ? (
<button
className="px-2 py-2 mt-1 mr-2 text-(--sidebar-accent-fg) rounded-lg opacity-50 cursor-not-allowed" // Indicate disabled state
className="px-2 py-2 mt-1 mr-1 text-(--sidebar-accent-fg) rounded-lg opacity-50 cursor-not-allowed" // Indicate disabled state
title="Cancel generation (unavailable here)"
>
<StopCircleIcon size={20} />
......@@ -115,15 +109,22 @@ export function HomeChatInput({
<button
onClick={handleCustomSubmit}
disabled={!inputValue.trim() && attachments.length === 0}
className="px-2 py-2 mt-1 mr-2 hover:bg-(--background-darkest) text-(--sidebar-accent-fg) rounded-lg disabled:opacity-50"
className="px-2 py-2 mt-1 mr-1 hover:bg-(--background-darkest) text-(--sidebar-accent-fg) rounded-lg disabled:opacity-50"
title="Send message"
>
<SendIcon size={20} />
</button>
)}
</div>
<div className="px-2 pb-2">
<ChatInputControls />
<div className="pl-2 pr-1 flex items-center justify-between pb-2">
<div className="flex items-center">
<ChatInputControls showContextFilesPicker={false} />
</div>
<AuxiliaryActionsMenu
onFileSelect={handleFileSelect}
hideContextFilesPicker
/>
</div>
</div>
</div>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论