mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 04:04:25 +00:00
* feat(ai): support editing sent user messages Adds inline edit support for user messages in the AI chat panel. Hover over a user message to reveal the edit button; confirming the edit truncates all subsequent history and re-sends with the new content. * fix(ai): fix IME composition and ref-focus regression in message edit - Handle IME composition events in onEditKeydown to prevent accidental submission on Enter during CJK candidate selection - Replace per-render :ref focus callback with nextTick + data attribute to avoid cursor jumping on every keystroke - Extract visibleToActualIndex into aiMessageEdit.ts for testability - Add 8 unit tests covering index mapping with contextSummary messages * fix(ai): prevent data loss and mention pollution in message edit - Guard connection/config before truncating messages to prevent silent data loss when send() bails early - Clear selectedMentions before resend to prevent stale chips from polluting edited message content
49 lines
2.0 KiB
TypeScript
49 lines
2.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { visibleToActualIndex } from "@/lib/aiMessageEdit";
|
|
|
|
describe("visibleToActualIndex", () => {
|
|
it("maps visible index 0 to first non-summary message", () => {
|
|
const messages = [{ kind: undefined }, { kind: undefined }, { kind: undefined }];
|
|
expect(visibleToActualIndex(messages, 0)).toBe(0);
|
|
});
|
|
|
|
it("maps visible index 1 correctly with no summaries", () => {
|
|
const messages = [{ kind: undefined }, { kind: undefined }, { kind: undefined }];
|
|
expect(visibleToActualIndex(messages, 1)).toBe(1);
|
|
});
|
|
|
|
it("skips contextSummary messages when computing visible index", () => {
|
|
const messages = [{ kind: undefined }, { kind: "contextSummary" }, { kind: undefined }, { kind: undefined }];
|
|
// visible[0] → actual[0], visible[1] → actual[2], visible[2] → actual[3]
|
|
expect(visibleToActualIndex(messages, 0)).toBe(0);
|
|
expect(visibleToActualIndex(messages, 1)).toBe(2);
|
|
expect(visibleToActualIndex(messages, 2)).toBe(3);
|
|
});
|
|
|
|
it("skips multiple consecutive contextSummary messages", () => {
|
|
const messages = [{ kind: "contextSummary" }, { kind: "contextSummary" }, { kind: undefined }, { kind: undefined }];
|
|
expect(visibleToActualIndex(messages, 0)).toBe(2);
|
|
expect(visibleToActualIndex(messages, 1)).toBe(3);
|
|
});
|
|
|
|
it("returns -1 when visibleIndex is out of range", () => {
|
|
const messages = [{ kind: undefined }, { kind: undefined }];
|
|
expect(visibleToActualIndex(messages, 5)).toBe(-1);
|
|
});
|
|
|
|
it("returns -1 for empty messages array", () => {
|
|
expect(visibleToActualIndex([], 0)).toBe(-1);
|
|
});
|
|
|
|
it("returns -1 when all messages are contextSummary", () => {
|
|
const messages = [{ kind: "contextSummary" }, { kind: "contextSummary" }];
|
|
expect(visibleToActualIndex(messages, 0)).toBe(-1);
|
|
});
|
|
|
|
it("handles last visible message correctly", () => {
|
|
const messages = [{ kind: undefined }, { kind: "contextSummary" }, { kind: undefined }];
|
|
expect(visibleToActualIndex(messages, 1)).toBe(2);
|
|
expect(visibleToActualIndex(messages, 2)).toBe(-1);
|
|
});
|
|
});
|