Give each user message its own copy, reply and time

Two prompts sent close together (as while a bot is still answering)
shared one row under their group: every copy button bunched beside the
last message's time. Each user message now has its own row, with its
copy button, a new Reply button (once it is saved) and its own time.
copyableMessages is gone with the shared row.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-27 07:40:22 +01:00
co-authored by Claude Opus 5.5
parent c75d3fe62c
commit 51fd4d5538
6 changed files with 47 additions and 61 deletions
@@ -1,27 +0,0 @@
import { describe, expect, test } from "bun:test";
import type { BotMessageWithAttachments } from "@/src/types";
import copyableMessages from "./copyable-messages";
function message(text?: string): BotMessageWithAttachments {
return { id: 1, author: "user", text } as BotMessageWithAttachments;
}
describe("copyableMessages", () => {
test("keeps the messages that have text", () => {
const kept = copyableMessages({
messages: [message("hello"), message(undefined), message("hi")],
});
expect(kept.map((one) => one.text)).toEqual(["hello", "hi"]);
});
test("drops text that is only whitespace", () => {
expect(copyableMessages({ messages: [message(" ")] })).toEqual([]);
});
test("a group with no text has nothing to copy", () => {
expect(copyableMessages({ messages: [message(), message()] })).toEqual(
[],
);
});
});
@@ -1,14 +0,0 @@
import type { BotMessageWithAttachments } from "@/src/types";
/**
* The messages of a group that can be copied: a file-only message has no
* text, and its copy button renders nothing, so it would only leave a
* gap in the row.
*/
export default function copyableMessages({
messages,
}: {
messages: BotMessageWithAttachments[];
}): BotMessageWithAttachments[] {
return messages.filter((message) => Boolean(message.text?.trim()));
}