mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-11-12 14:00:35 +00:00
fix(frontend): open file chooser from attachment button (#8018)
This commit is contained in:
parent
0d04322d41
commit
97746ad725
@ -2649,6 +2649,8 @@ When the agent asks for clarification, the Web UI shows the structured response
|
||||
|
||||
Unsent Web UI composer drafts survive page reloads and switching between conversations within the same browser tab. Drafts are isolated by user, agent, and conversation, include the selected skill and explicit conversation references, and are cleared once a send is accepted. Project documents already attached to the thread also survive reloads; browser-local uploads and quoted message excerpts are not persisted.
|
||||
|
||||
The composer's paperclip button opens the local file chooser directly; the `@` button opens the reference picker for skills, project files, conversations, and plugins.
|
||||
|
||||
If an attachment upload reports `success: false`, the Web UI stops the send even when the HTTP response is 200. The upload error is shown and the composer keeps its draft and attachments for correction or retry. Files already accepted by a partially successful upload remain on the server; this does not roll them back.
|
||||
|
||||
Document conversion reads the live PDF-converter setting and parses documents in a background worker, keeping configuration-file checks off the Gateway event loop.
|
||||
|
||||
@ -3281,7 +3281,6 @@ export function InputBox({
|
||||
</PromptInputButton>
|
||||
</Tooltip>
|
||||
<AddAttachmentsButton
|
||||
onOpen={openMentions}
|
||||
className="px-2!"
|
||||
disabled={composerLocked}
|
||||
uploadLimits={uploadLimits}
|
||||
@ -3853,9 +3852,7 @@ function AddAttachmentsButton({
|
||||
className,
|
||||
disabled,
|
||||
uploadLimits,
|
||||
onOpen,
|
||||
}: {
|
||||
onOpen?: () => void;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
uploadLimits?: UploadLimits;
|
||||
@ -3876,7 +3873,7 @@ function AddAttachmentsButton({
|
||||
className={cn("px-2!", className)}
|
||||
data-testid="add-attachments-button"
|
||||
disabled={disabled}
|
||||
onClick={onOpen ?? (() => attachments.openFileDialog())}
|
||||
onClick={() => attachments.openFileDialog()}
|
||||
>
|
||||
<PaperclipIcon className="size-3" />
|
||||
</PromptInputButton>
|
||||
|
||||
@ -1210,6 +1210,37 @@ test.describe("Chat workspace", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("opens local files directly from the attachment button and keeps references under @", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/workspace/chats/new");
|
||||
const fileChooserPromise = page.waitForEvent("filechooser");
|
||||
await page.getByTestId("add-attachments-button").click();
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await expect(page.getByTestId("mention-picker")).toBeHidden();
|
||||
await fileChooser.setFiles({
|
||||
name: "local-report.txt",
|
||||
mimeType: "text/plain",
|
||||
buffer: Buffer.from("Local attachment"),
|
||||
});
|
||||
await expect(
|
||||
page.locator("form").getByText("local-report.txt"),
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByTestId("mention-button").click();
|
||||
const picker = page.getByTestId("mention-picker");
|
||||
await expect(picker).toBeVisible();
|
||||
await expect(
|
||||
picker.getByRole("option", { name: "Upload a file" }),
|
||||
).toBeAttached();
|
||||
await expect(
|
||||
picker.getByRole("group", { name: "Skills", exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.locator("form").getByText("local-report.txt"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("shows gateway upload limits on the attachment entry point", async ({
|
||||
page,
|
||||
}) => {
|
||||
|
||||
@ -333,7 +333,7 @@ describe("mention selection focus", () => {
|
||||
'[contenteditable="true"]',
|
||||
)!;
|
||||
act(() => focusReferenceAt(editor, 2));
|
||||
const picker = screen.getByTestId("add-attachments-button");
|
||||
const picker = screen.getByTestId("mention-button");
|
||||
act(() => picker.focus());
|
||||
holdAnimationFrames();
|
||||
fireEvent.click(picker);
|
||||
@ -630,11 +630,29 @@ describe("unified composer mentions", () => {
|
||||
enterMention(container, "@");
|
||||
expect(screen.queryByRole("option", { name: "Writer brief" })).toBeNull();
|
||||
});
|
||||
it("the attachment button opens the same picker", () => {
|
||||
renderComposer();
|
||||
it("the attachment button opens the file input directly", () => {
|
||||
const { container } = renderComposer();
|
||||
const fileInput =
|
||||
container.querySelector<HTMLInputElement>('input[type="file"]')!;
|
||||
const click = rs.spyOn(fileInput, "click");
|
||||
fireEvent.click(screen.getByTestId("add-attachments-button"));
|
||||
expect(click).toHaveBeenCalledTimes(1);
|
||||
expect(screen.queryByTestId("mention-picker")).toBeNull();
|
||||
});
|
||||
it("the mention button keeps the reference picker and its upload action", () => {
|
||||
const { container } = renderComposer();
|
||||
const fileInput =
|
||||
container.querySelector<HTMLInputElement>('input[type="file"]')!;
|
||||
const click = rs.spyOn(fileInput, "click");
|
||||
fireEvent.click(screen.getByTestId("mention-button"));
|
||||
expect(click).not.toHaveBeenCalled();
|
||||
expect(screen.getByTestId("mention-picker")).toBeTruthy();
|
||||
expect(
|
||||
screen.getByRole("option", { name: "research Research a topic" }),
|
||||
).toBeTruthy();
|
||||
expect(screen.getByRole("option", { name: "Upload a file" })).toBeTruthy();
|
||||
fireEvent.click(screen.getByRole("option", { name: "Upload a file" }));
|
||||
expect(click).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it("does not select upload automatically for an unknown query", () => {
|
||||
const { container } = renderComposer();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user