fix(desktop): polish live Bestie feed cards

Co-authored-by: Arjun Mahanti <arjun@squareup.com>
Signed-off-by: Arjun Mahanti <arjun@squareup.com>
This commit is contained in:
Arjun Mahanti
2026-08-25 12:52:03 -04:00
parent b9333de45d
commit f28780abac
4 changed files with 143 additions and 64 deletions

View File

@@ -3,6 +3,7 @@ import test from "node:test";
import {
bestieItemSourceLabel,
bestieItemSummary,
filterBestieFeedItems,
getVisibleBestieFeedItems,
reduceBestiePanelState,
@@ -96,6 +97,35 @@ test("bestieItemSourceLabel uses only source metadata with a neutral fallback",
);
});
test("bestieItemSummary extracts a concise headline from actual Buzz text", () => {
const actualContent =
"Reminder: Review the launch plan before lunch. This second sentence contains implementation details that do not belong in the card headline.";
assert.equal(
bestieItemSummary(
item({
groupItems: [{ ...item().item, content: actualContent }],
preview: actualContent,
subject: "Mention",
}),
),
"Review the launch plan before lunch.",
);
});
test("bestieItemSummary strips media and bounds long source text", () => {
const summary = bestieItemSummary(
item({
preview:
"@arjun Here is the important source update with enough additional context to exceed the compact Bestie headline limit by a wide margin ![proof](https://example.com/proof.png)",
subject: "Mention",
}),
);
assert.ok(summary.startsWith("Here is the important source update"));
assert.ok(summary.endsWith("…"));
assert.ok(Array.from(summary).length <= 96);
assert.doesNotMatch(summary, /proof|https/);
});
test("reduceBestiePanelState keeps only one floating panel open", () => {
const reply = reduceBestiePanelState(
{ mode: "closed" },

View File

@@ -1,5 +1,6 @@
import { isProjectInboxItem } from "@/features/home/lib/projectInbox";
import type { InboxItem } from "@/features/home/lib/inbox";
import { summarizeMessageLinkContent } from "@/features/messages/lib/messageLinkMetadata";
export type BestieFeedFilter = "all" | "messages" | "tasks";
@@ -60,6 +61,41 @@ export function bestieItemSourceLabel(item: InboxItem) {
return item.channelLabel ?? (item.item.channelName.trim() || "Buzz");
}
const BESTIE_SUMMARY_MAX_LENGTH = 96;
function truncateBestieSummary(value: string) {
const characters = Array.from(value);
if (characters.length <= BESTIE_SUMMARY_MAX_LENGTH) return value;
const clipped = characters.slice(0, BESTIE_SUMMARY_MAX_LENGTH - 1).join("");
const lastSpace = clipped.lastIndexOf(" ");
const summary = lastSpace > 56 ? clipped.slice(0, lastSpace) : clipped;
return `${summary.trimEnd()}…`;
}
/** Builds a concise extractive headline using only text from the Buzz item. */
export function bestieItemSummary(item: InboxItem) {
if (isProjectInboxItem(item.item)) return item.subject;
const latestContent = [...item.groupItems]
.sort((left, right) => right.createdAt - left.createdAt)
.find((event) => event.content.trim().length > 0)?.content;
const normalized = summarizeMessageLinkContent(latestContent ?? item.preview)
.replace(/^(?:agent progress|mention|reminder)\s*:\s*/i, "")
.replace(/^@[\p{L}\p{N}._-]+[:,]?\s*/u, "")
.trim();
if (!normalized || normalized === "No message text") return item.subject;
const sentenceEnd = normalized.search(/[.!?](?:\s|$)/);
const firstSentence =
sentenceEnd >= 0 ? normalized.slice(0, sentenceEnd + 1).trim() : normalized;
const [firstCharacter = "", ...remainingCharacters] =
Array.from(firstSentence);
return truncateBestieSummary(
`${firstCharacter.toLocaleUpperCase()}${remainingCharacters.join("")}`,
);
}
export function reduceBestiePanelState(
_state: BestiePanelState,
action: BestiePanelAction,

View File

@@ -1,17 +1,13 @@
import {
Bot,
Clock3,
GitPullRequest,
MessageSquareReply,
Sparkles,
} from "lucide-react";
import { Clock3, MessageSquareReply, Sparkles } from "lucide-react";
import { bestieItemSourceLabel } from "@/features/bestie/lib/bestieFeed";
import { bestieItemSummary } from "@/features/bestie/lib/bestieFeed";
import type { InboxItem } from "@/features/home/lib/inbox";
import { isProjectInboxItem } from "@/features/home/lib/projectInbox";
import { Badge } from "@/shared/ui/badge";
import { Button } from "@/shared/ui/button";
import { parseImetaTags } from "@/shared/ui/markdown/parseImeta";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip";
import { UserAvatar } from "@/shared/ui/UserAvatar";
import { VideoReviewCommentMarkdown } from "@/shared/ui/VideoReviewCommentMarkdown";
type BestieFeedCardProps = {
item: InboxItem;
@@ -20,12 +16,12 @@ type BestieFeedCardProps = {
onSnooze: () => void;
};
function actualSupportingContent(item: InboxItem) {
function actualSupportingItems(item: InboxItem) {
const seen = new Set<string>();
return [...item.groupItems]
.sort((left, right) => left.createdAt - right.createdAt)
.map((event) => event.content.trim())
.filter((content) => {
.filter((event) => {
const content = event.content.trim();
if (!content || seen.has(content)) return false;
seen.add(content);
return true;
@@ -34,42 +30,31 @@ function actualSupportingContent(item: InboxItem) {
}
function SupportingVisual({ item }: { item: InboxItem }) {
const content = actualSupportingContent(item);
const projectItem = isProjectInboxItem(item.item);
const sourceItems = actualSupportingItems(item);
return (
<div
className="rounded-2xl border border-border/60 bg-muted/25 p-4"
data-testid="bestie-source-visual"
>
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
{projectItem ? (
<GitPullRequest className="h-4 w-4 text-violet-500" />
) : item.categories.includes("agent_activity") ? (
<Bot className="h-4 w-4" />
) : (
<MessageSquareReply className="h-4 w-4" />
)}
<span className="font-medium text-foreground">
{bestieItemSourceLabel(item)}
</span>
<span>·</span>
<span>{item.categoryLabel}</span>
{item.unreadCount > 0 ? <span>· {item.unreadCount} unread</span> : null}
</div>
{content.length > 0 ? (
<div className="mt-3 flex flex-col items-start gap-1.5">
{content.map((message) => (
{sourceItems.length > 0 ? (
<div className="flex flex-col items-start gap-1.5">
{sourceItems.map((sourceItem) => (
<div
className="max-w-full rounded-2xl bg-muted/70 px-4 py-2.5 text-sm leading-relaxed text-foreground"
key={message}
className="max-w-full overflow-hidden rounded-2xl bg-muted/70 px-4 py-2.5"
key={sourceItem.id}
>
{message}
<VideoReviewCommentMarkdown
className="max-w-full text-sm leading-relaxed text-foreground [&_p]:line-clamp-4"
content={sourceItem.content}
imetaByUrl={parseImetaTags(sourceItem.tags)}
messageId={sourceItem.id}
/>
</div>
))}
</div>
) : (
<p className="mt-3 text-sm text-muted-foreground">
<p className="text-sm text-muted-foreground">
This Buzz event has no text content.
</p>
)}
@@ -115,6 +100,7 @@ export function BestieFeedCard({
onSnooze,
}: BestieFeedCardProps) {
const headingId = `bestie-card-heading-${item.id}`;
const summary = bestieItemSummary(item);
return (
<article
@@ -147,37 +133,21 @@ export function BestieFeedCard({
</div>
<div className="mt-6 flex items-center gap-3">
{item.avatarUrl ? (
<img
alt=""
className="h-11 w-11 shrink-0 rounded-2xl object-cover"
src={item.avatarUrl}
/>
) : (
<div
aria-hidden="true"
className="flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-foreground text-xs font-semibold text-background"
>
{item.senderLabel.slice(0, 2).toUpperCase()}
</div>
)}
<div className="min-w-0">
<p className="truncate text-sm font-medium">{item.senderLabel}</p>
<p className="truncate text-xs text-muted-foreground">
{bestieItemSourceLabel(item)}
</p>
</div>
<UserAvatar
avatarUrl={item.avatarUrl}
className="h-11 w-11 shrink-0"
displayName={item.senderLabel}
fallbackDelayMs={0}
testId={`bestie-avatar-${item.id}`}
/>
</div>
<h2
className="mt-5 text-balance text-xl font-semibold leading-tight tracking-tight sm:text-2xl"
id={headingId}
>
{item.subject}
{summary}
</h2>
<p className="mt-2 max-w-2xl whitespace-pre-wrap text-sm leading-relaxed text-muted-foreground">
{item.preview}
</p>
<div className="mt-5">
<SupportingVisual item={item} />
@@ -186,14 +156,14 @@ export function BestieFeedCard({
<div className="mt-6 flex flex-wrap items-center justify-between gap-3">
<div className="flex items-center gap-2">
<IconAction
label={`Snooze ${item.subject}`}
label={`Snooze ${summary}`}
onClick={onSnooze}
testId={`bestie-snooze-${item.id}`}
>
<Clock3 />
</IconAction>
<IconAction
label={`Reply about ${item.subject}`}
label={`Reply about ${summary}`}
onClick={onReply}
testId={`bestie-reply-${item.id}`}
>

View File

@@ -5,12 +5,34 @@ import { installMockBridge } from "../helpers/bridge";
const LIVE_MENTION = "Please review the release checklist.";
const LIVE_REMINDER = "Reminder: update the launch plan before lunch.";
const MEDIA_SUMMARY = "The design reference is ready for review.";
test("Bestie Feed projects only events returned by the Home feed", async ({
page,
}) => {
await installMockBridge(page);
await page.goto("/");
await page.waitForFunction(
() => typeof window.__BUZZ_E2E_PUSH_MOCK_FEED_ITEM__ === "function",
);
await page.evaluate(() => {
window.__BUZZ_E2E_PUSH_MOCK_FEED_ITEM__?.({
id: "bestie-media-evidence",
kind: 9,
pubkey: "a".repeat(64),
content:
"The design reference is ready for review. This additional implementation detail should remain supporting evidence rather than becoming the headline.\n\n![Reference image](/app-icon@2x.png)",
created_at: Math.floor(Date.now() / 1_000) + 1,
channel_id: "9a1657ac-f7aa-5db0-b632-d8bbeb6dfb50",
channel_name: "general",
channel_type: "stream",
tags: [
["h", "9a1657ac-f7aa-5db0-b632-d8bbeb6dfb50"],
["p", "deadbeef".repeat(8)],
],
category: "mention",
});
});
await page.getByTestId("open-bestie-feed").click();
await expect(page).toHaveURL(/#\/\?view=bestie$/);
@@ -24,6 +46,15 @@ test("Bestie Feed projects only events returned by the Home feed", async ({
await expect(
page.getByText(LIVE_REMINDER, { exact: true }).first(),
).toBeVisible();
const mediaCard = page
.getByRole("heading", { name: MEDIA_SUMMARY, exact: true })
.locator("xpath=ancestor::article");
await expect(mediaCard).toBeVisible();
await expect(
mediaCard.getByRole("button", {
name: "Zoom image: Reference image",
}),
).toBeVisible();
await expect(page.getByText(/Simon asked for the latest/)).toHaveCount(0);
await expect(page.getByText(/Cmd\+K is ready/)).toHaveCount(0);
@@ -38,8 +69,20 @@ test("Bestie Feed projects only events returned by the Home feed", async ({
.getByText(LIVE_MENTION, { exact: true })
.first()
.locator("xpath=ancestor::article");
await expect(
mentionCard.getByRole("heading", { name: LIVE_MENTION, exact: true }),
).toBeVisible();
await expect(mentionCard.getByText("Alice", { exact: true })).toHaveCount(0);
await expect(mentionCard.getByText("general", { exact: true })).toHaveCount(
0,
);
await expect(
mentionCard.locator(
'[data-testid^="bestie-avatar-"][data-testid$="-fallback"]',
),
).toBeVisible();
const snoozeTrigger = mentionCard.getByRole("button", {
name: /Snooze Mention/,
name: `Snooze ${LIVE_MENTION}`,
});
await snoozeTrigger.click();
await expect(page.getByText(LIVE_MENTION, { exact: true })).toHaveCount(0);
@@ -52,7 +95,7 @@ test("Bestie Feed projects only events returned by the Home feed", async ({
.getByText(LIVE_MENTION, { exact: true })
.first()
.locator("xpath=ancestor::article")
.getByRole("button", { name: /Reply about Mention/ });
.getByRole("button", { name: `Reply about ${LIVE_MENTION}` });
await replyTrigger.click();
const replyPanel = page.getByTestId("bestie-reply-panel");
await expect(replyPanel).toContainText(LIVE_MENTION);