mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 17:24:05 +00:00
fix(ui): clear chat composer after send (#89106)
This commit is contained in:
@@ -297,6 +297,11 @@ describeControlUiE2e("Control UI mocked Gateway E2E", () => {
|
||||
await page.getByRole("button", { name: "Send message" }).click();
|
||||
|
||||
const sendRequest = await gateway.waitForRequest("chat.send");
|
||||
await expect
|
||||
.poll(() => page.locator(".agent-chat__composer-combobox textarea").inputValue(), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBe("");
|
||||
const params = requireRecord(sendRequest.params);
|
||||
expect(params.message).toBe(prompt);
|
||||
expect(params.sessionKey).toBe("global");
|
||||
@@ -377,6 +382,11 @@ describeControlUiE2e("Control UI mocked Gateway E2E", () => {
|
||||
await page.getByRole("button", { name: "Send message" }).click();
|
||||
|
||||
const sendRequest = await gateway.waitForRequest("chat.send");
|
||||
await expect
|
||||
.poll(() => page.locator(".agent-chat__composer-combobox textarea").inputValue(), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBe("");
|
||||
const params = requireRecord(sendRequest.params);
|
||||
const runId = requireString(params.idempotencyKey, "chat send idempotency key");
|
||||
|
||||
|
||||
@@ -1144,6 +1144,31 @@ describe("chat slash menu accessibility", () => {
|
||||
expect(onSend).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("clears the visible local draft immediately when send clears the host draft", () => {
|
||||
let draft = "";
|
||||
const container = document.createElement("div");
|
||||
const onDraftChange = vi.fn((next: string) => {
|
||||
draft = next;
|
||||
});
|
||||
const onSend = vi.fn(() => {
|
||||
draft = "";
|
||||
});
|
||||
const renderWithDraft = () => {
|
||||
render(
|
||||
renderChat(createChatProps({ draft, getDraft: () => draft, onDraftChange, onSend })),
|
||||
container,
|
||||
);
|
||||
};
|
||||
|
||||
renderWithDraft();
|
||||
inputDraft(container, "submitted message");
|
||||
container.querySelector<HTMLButtonElement>(".chat-send-btn")!.click();
|
||||
|
||||
expect(onDraftChange).toHaveBeenCalledWith("submitted message");
|
||||
expect(onSend).toHaveBeenCalledTimes(1);
|
||||
expect(container.querySelector<HTMLTextAreaElement>("textarea")?.value).toBe("");
|
||||
});
|
||||
|
||||
it("commits local draft input before Enter sends", () => {
|
||||
const onDraftChange = vi.fn();
|
||||
const onSend = vi.fn();
|
||||
|
||||
@@ -1388,6 +1388,7 @@ export function renderChat(props: ChatProps) {
|
||||
};
|
||||
const draftMirror = getComposerDraftMirror(props);
|
||||
const visibleDraft = draftMirror.value;
|
||||
let composerTextarea: HTMLTextAreaElement | null = null;
|
||||
const pinned = getPinnedMessages(props.sessionKey);
|
||||
const deleted = getDeletedMessages(props.sessionKey);
|
||||
const hasAttachments = (props.attachments?.length ?? 0) > 0;
|
||||
@@ -1624,6 +1625,21 @@ export function renderChat(props: ChatProps) {
|
||||
</div>
|
||||
`;
|
||||
|
||||
const syncComposerDraftAfterSend = (target: HTMLTextAreaElement | null) => {
|
||||
const hostDraft = props.getDraft?.();
|
||||
if (typeof hostDraft !== "string") {
|
||||
return;
|
||||
}
|
||||
// Sends can clear the host draft synchronously before Lit rerenders; keep
|
||||
// the local mirror aligned so the submitted text does not stay editable.
|
||||
draftMirror.hostDraft = hostDraft;
|
||||
draftMirror.value = hostDraft;
|
||||
if (target && target.value !== hostDraft) {
|
||||
target.value = hostDraft;
|
||||
adjustTextareaHeight(target);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
// Slash menu navigation — arg mode
|
||||
if (vs.slashMenuOpen && vs.slashMenuMode === "args" && vs.slashMenuArgItems.length > 0) {
|
||||
@@ -1743,6 +1759,7 @@ export function renderChat(props: ChatProps) {
|
||||
const target = e.target as HTMLTextAreaElement;
|
||||
commitComposerDraft(props, target.value);
|
||||
props.onSend();
|
||||
syncComposerDraftAfterSend(target);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1764,6 +1781,7 @@ export function renderChat(props: ChatProps) {
|
||||
const handleSend = () => {
|
||||
commitComposerDraft(props, draftMirror.value);
|
||||
props.onSend();
|
||||
syncComposerDraftAfterSend(composerTextarea);
|
||||
};
|
||||
const slashMenuVisible = isSlashMenuVisible();
|
||||
const activeSlashMenuOptionId = getActiveSlashMenuOptionId();
|
||||
@@ -1899,7 +1917,12 @@ export function renderChat(props: ChatProps) {
|
||||
|
||||
<div class="agent-chat__composer-combobox">
|
||||
<textarea
|
||||
${ref((el) => el && adjustTextareaHeight(el as HTMLTextAreaElement))}
|
||||
${ref((el) => {
|
||||
composerTextarea = el instanceof HTMLTextAreaElement ? el : null;
|
||||
if (composerTextarea) {
|
||||
adjustTextareaHeight(composerTextarea);
|
||||
}
|
||||
})}
|
||||
.value=${visibleDraft}
|
||||
dir=${detectTextDirection(visibleDraft)}
|
||||
?disabled=${!props.connected}
|
||||
|
||||
Reference in New Issue
Block a user