mirror of
https://github.com/block/buzz.git
synced 2026-11-02 07:22:55 +00:00
feat(home): add activity and agent feed sections with deep-linking (#330)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,15 +2,56 @@ import { createFileRoute } from "@tanstack/react-router";
|
||||
|
||||
import { useAppNavigation } from "@/app/navigation/useAppNavigation";
|
||||
import { useChannelsQuery } from "@/features/channels/hooks";
|
||||
import type { FeedItem, SearchHit } from "@/shared/api/types";
|
||||
import { useIdentityQuery } from "@/shared/api/hooks";
|
||||
import { HomeScreen } from "@/features/home/ui/HomeScreen";
|
||||
import {
|
||||
KIND_FORUM_COMMENT,
|
||||
KIND_FORUM_POST,
|
||||
KIND_JOB_ACCEPTED,
|
||||
KIND_JOB_CANCEL,
|
||||
KIND_JOB_ERROR,
|
||||
KIND_JOB_PROGRESS,
|
||||
KIND_JOB_REQUEST,
|
||||
KIND_JOB_RESULT,
|
||||
KIND_STREAM_MESSAGE,
|
||||
KIND_STREAM_MESSAGE_V2,
|
||||
} from "@/shared/constants/kinds";
|
||||
|
||||
function canOpenFeedItemAsExactEvent(item: FeedItem) {
|
||||
return (
|
||||
item.kind === KIND_STREAM_MESSAGE ||
|
||||
item.kind === KIND_STREAM_MESSAGE_V2 ||
|
||||
item.kind === KIND_JOB_REQUEST ||
|
||||
item.kind === KIND_JOB_ACCEPTED ||
|
||||
item.kind === KIND_JOB_PROGRESS ||
|
||||
item.kind === KIND_JOB_RESULT ||
|
||||
item.kind === KIND_JOB_CANCEL ||
|
||||
item.kind === KIND_JOB_ERROR ||
|
||||
item.kind === KIND_FORUM_POST ||
|
||||
item.kind === KIND_FORUM_COMMENT
|
||||
);
|
||||
}
|
||||
|
||||
function toFeedItemSearchHit(item: FeedItem): SearchHit {
|
||||
return {
|
||||
channelId: item.channelId,
|
||||
channelName: item.channelName || null,
|
||||
content: item.content,
|
||||
createdAt: item.createdAt,
|
||||
eventId: item.id,
|
||||
kind: item.kind,
|
||||
pubkey: item.pubkey,
|
||||
score: 0,
|
||||
};
|
||||
}
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: HomeRouteComponent,
|
||||
});
|
||||
|
||||
function HomeRouteComponent() {
|
||||
const { goChannel, goPulse } = useAppNavigation();
|
||||
const { goChannel, goPulse, openSearchHit } = useAppNavigation();
|
||||
const channelsQuery = useChannelsQuery();
|
||||
const identityQuery = useIdentityQuery();
|
||||
const channels = channelsQuery.data ?? [];
|
||||
@@ -20,8 +61,17 @@ function HomeRouteComponent() {
|
||||
<HomeScreen
|
||||
availableChannelIds={availableChannelIds}
|
||||
currentPubkey={identityQuery.data?.pubkey}
|
||||
onOpenChannel={(channelId) => {
|
||||
void goChannel(channelId);
|
||||
onOpenFeedItem={(item) => {
|
||||
if (!item.channelId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (canOpenFeedItemAsExactEvent(item)) {
|
||||
void openSearchHit(toFeedItemSearchHit(item));
|
||||
return;
|
||||
}
|
||||
|
||||
void goChannel(item.channelId);
|
||||
}}
|
||||
onOpenPulse={() => {
|
||||
void goPulse();
|
||||
|
||||
@@ -5,7 +5,11 @@ import { getHomeFeed } from "@/shared/api/tauri";
|
||||
export function useHomeFeedQuery() {
|
||||
return useQuery({
|
||||
queryKey: ["home-feed"],
|
||||
queryFn: () => getHomeFeed({ limit: 12, types: "mentions,needs_action" }),
|
||||
queryFn: () =>
|
||||
getHomeFeed({
|
||||
limit: 12,
|
||||
types: "mentions,needs_action,activity,agent_activity",
|
||||
}),
|
||||
staleTime: 15_000,
|
||||
gcTime: 5 * 60 * 1_000,
|
||||
refetchInterval: 30_000,
|
||||
|
||||
@@ -5,6 +5,18 @@ import {
|
||||
type UserProfileLookup,
|
||||
} from "@/features/profile/lib/identity";
|
||||
import type { FeedItem } from "@/shared/api/types";
|
||||
import {
|
||||
KIND_APPROVAL_REQUEST,
|
||||
KIND_FORUM_COMMENT,
|
||||
KIND_FORUM_POST,
|
||||
KIND_JOB_ACCEPTED,
|
||||
KIND_JOB_CANCEL,
|
||||
KIND_JOB_ERROR,
|
||||
KIND_JOB_PROGRESS,
|
||||
KIND_JOB_REQUEST,
|
||||
KIND_JOB_RESULT,
|
||||
KIND_REMINDER,
|
||||
} from "@/shared/constants/kinds";
|
||||
import { resolveMentionNames } from "@/shared/lib/resolveMentionNames";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import { Markdown } from "@/shared/ui/markdown";
|
||||
@@ -46,25 +58,25 @@ function formatRelativeTime(unixSeconds: number) {
|
||||
|
||||
function feedHeadline(item: FeedItem) {
|
||||
switch (item.kind) {
|
||||
case 40007:
|
||||
case KIND_REMINDER:
|
||||
return "Reminder";
|
||||
case 43001:
|
||||
case KIND_JOB_REQUEST:
|
||||
return "Job requested";
|
||||
case 43002:
|
||||
case KIND_JOB_ACCEPTED:
|
||||
return "Job accepted";
|
||||
case 43003:
|
||||
case KIND_JOB_PROGRESS:
|
||||
return "Progress update";
|
||||
case 43004:
|
||||
case KIND_JOB_RESULT:
|
||||
return "Job result";
|
||||
case 43005:
|
||||
case KIND_JOB_CANCEL:
|
||||
return "Job cancelled";
|
||||
case 43006:
|
||||
case KIND_JOB_ERROR:
|
||||
return "Job failed";
|
||||
case 45001:
|
||||
case KIND_FORUM_POST:
|
||||
return "Forum post";
|
||||
case 45003:
|
||||
case KIND_FORUM_COMMENT:
|
||||
return "Forum reply";
|
||||
case 46010:
|
||||
case KIND_APPROVAL_REQUEST:
|
||||
return "Approval requested";
|
||||
default:
|
||||
if (item.category === "mention") {
|
||||
@@ -85,11 +97,11 @@ function feedContent(item: FeedItem) {
|
||||
return content;
|
||||
}
|
||||
|
||||
if (item.kind === 46010) {
|
||||
if (item.kind === KIND_APPROVAL_REQUEST) {
|
||||
return "A workflow is waiting for approval.";
|
||||
}
|
||||
|
||||
if (item.kind === 40007) {
|
||||
if (item.kind === KIND_REMINDER) {
|
||||
return "A reminder is waiting for you.";
|
||||
}
|
||||
|
||||
@@ -107,7 +119,7 @@ type FeedSectionProps = {
|
||||
availableChannelIds: ReadonlySet<string>;
|
||||
doneSet: ReadonlySet<string>;
|
||||
showDoneAction: boolean;
|
||||
onOpenChannel: (channelId: string) => void;
|
||||
onOpenItem: (item: FeedItem) => void;
|
||||
onMarkDone: (id: string) => void;
|
||||
onUndoDone: (id: string) => void;
|
||||
};
|
||||
@@ -123,7 +135,7 @@ export function FeedSection({
|
||||
availableChannelIds,
|
||||
doneSet,
|
||||
showDoneAction,
|
||||
onOpenChannel,
|
||||
onOpenItem,
|
||||
onMarkDone,
|
||||
onUndoDone,
|
||||
}: FeedSectionProps) {
|
||||
@@ -164,10 +176,9 @@ export function FeedSection({
|
||||
<button
|
||||
aria-label={`Open ${item.channelName || "channel"}`}
|
||||
className="absolute inset-0"
|
||||
data-testid={`home-feed-open-${item.id}`}
|
||||
onClick={() => {
|
||||
if (channelId) {
|
||||
onOpenChannel(channelId);
|
||||
}
|
||||
onOpenItem(item);
|
||||
}}
|
||||
type="button"
|
||||
/>
|
||||
@@ -197,12 +208,14 @@ export function FeedSection({
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<Markdown
|
||||
className="pointer-events-none relative mt-0.5 max-w-none text-[13px] leading-snug text-muted-foreground"
|
||||
compact
|
||||
content={feedContent(item)}
|
||||
mentionNames={mentionNames}
|
||||
/>
|
||||
<div className="pointer-events-none relative mt-0.5 line-clamp-2">
|
||||
<Markdown
|
||||
className="max-w-none text-[13px] leading-snug text-muted-foreground"
|
||||
compact
|
||||
content={feedContent(item)}
|
||||
mentionNames={mentionNames}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showDoneAction ? (
|
||||
<Button
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { FeedItem } from "@/shared/api/types";
|
||||
import { ChatHeader } from "@/features/chat/ui/ChatHeader";
|
||||
import { useHomeFeedQuery } from "@/features/home/hooks";
|
||||
import { HomeView } from "@/features/home/ui/HomeView";
|
||||
@@ -5,14 +6,14 @@ import { HomeView } from "@/features/home/ui/HomeView";
|
||||
type HomeScreenProps = {
|
||||
availableChannelIds: ReadonlySet<string>;
|
||||
currentPubkey?: string;
|
||||
onOpenChannel: (channelId: string) => void;
|
||||
onOpenFeedItem: (item: FeedItem) => void;
|
||||
onOpenPulse: () => void;
|
||||
};
|
||||
|
||||
export function HomeScreen({
|
||||
availableChannelIds,
|
||||
currentPubkey,
|
||||
onOpenChannel,
|
||||
onOpenFeedItem,
|
||||
onOpenPulse,
|
||||
}: HomeScreenProps) {
|
||||
const homeFeedQuery = useHomeFeedQuery();
|
||||
@@ -20,7 +21,7 @@ export function HomeScreen({
|
||||
return (
|
||||
<>
|
||||
<ChatHeader
|
||||
description="Personalized feed for mentions, reminders, channel activity, and agent work."
|
||||
description="Personalized activity feed for mentions, reminders, channel activity, and agent work."
|
||||
mode="home"
|
||||
title="Home"
|
||||
/>
|
||||
@@ -36,7 +37,7 @@ export function HomeScreen({
|
||||
}
|
||||
feed={homeFeedQuery.data}
|
||||
isLoading={homeFeedQuery.isLoading}
|
||||
onOpenChannel={onOpenChannel}
|
||||
onOpenFeedItem={onOpenFeedItem}
|
||||
onOpenPulse={onOpenPulse}
|
||||
onRefresh={() => {
|
||||
void homeFeedQuery.refetch();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as React from "react";
|
||||
import { AtSign, CircleAlert, RefreshCcw } from "lucide-react";
|
||||
import { Activity, AtSign, Bot, CircleAlert, RefreshCcw } from "lucide-react";
|
||||
|
||||
import { useRelayAgentsQuery } from "@/features/agents/hooks";
|
||||
import { useFeedItemState } from "@/features/home/useFeedItemState";
|
||||
import { useUsersBatchQuery } from "@/features/profile/hooks";
|
||||
import { useContactListQuery, useTimelineQuery } from "@/features/pulse/hooks";
|
||||
import type { HomeFeedResponse } from "@/shared/api/types";
|
||||
import type { FeedItem, HomeFeedResponse } from "@/shared/api/types";
|
||||
import { Button } from "@/shared/ui/button";
|
||||
import { Skeleton } from "@/shared/ui/skeleton";
|
||||
|
||||
@@ -19,7 +19,12 @@ const RecentNotesSection = React.lazy(async () => {
|
||||
return { default: module.RecentNotesSection };
|
||||
});
|
||||
|
||||
type FeedFilter = "all" | "mention" | "needs_action";
|
||||
type FeedFilter =
|
||||
| "all"
|
||||
| "mention"
|
||||
| "needs_action"
|
||||
| "activity"
|
||||
| "agent_activity";
|
||||
|
||||
function HomeLoadingState() {
|
||||
return (
|
||||
@@ -46,6 +51,8 @@ const FILTER_OPTIONS: { value: FeedFilter; label: string }[] = [
|
||||
{ value: "all", label: "All" },
|
||||
{ value: "mention", label: "Mentions" },
|
||||
{ value: "needs_action", label: "Needs Action" },
|
||||
{ value: "activity", label: "Activity" },
|
||||
{ value: "agent_activity", label: "Agent Updates" },
|
||||
];
|
||||
|
||||
type HomeViewProps = {
|
||||
@@ -54,7 +61,7 @@ type HomeViewProps = {
|
||||
errorMessage?: string;
|
||||
currentPubkey?: string;
|
||||
availableChannelIds: ReadonlySet<string>;
|
||||
onOpenChannel: (channelId: string) => void;
|
||||
onOpenFeedItem: (item: FeedItem) => void;
|
||||
onOpenPulse: () => void;
|
||||
onRefresh: () => void;
|
||||
};
|
||||
@@ -65,7 +72,7 @@ export function HomeView({
|
||||
errorMessage,
|
||||
currentPubkey,
|
||||
availableChannelIds,
|
||||
onOpenChannel,
|
||||
onOpenFeedItem,
|
||||
onOpenPulse,
|
||||
onRefresh,
|
||||
}: HomeViewProps) {
|
||||
@@ -105,7 +112,12 @@ export function HomeView({
|
||||
);
|
||||
|
||||
const feedItems = feed
|
||||
? [...feed.feed.mentions, ...feed.feed.needsAction]
|
||||
? [
|
||||
...feed.feed.mentions,
|
||||
...feed.feed.needsAction,
|
||||
...(feed.feed.activity ?? []),
|
||||
...(feed.feed.agentActivity ?? []),
|
||||
]
|
||||
: [];
|
||||
const feedProfilesQuery = useUsersBatchQuery(
|
||||
feedItems.map((item) => item.pubkey),
|
||||
@@ -142,6 +154,8 @@ export function HomeView({
|
||||
|
||||
const showMentions = filter === "all" || filter === "mention";
|
||||
const showNeedsAction = filter === "all" || filter === "needs_action";
|
||||
const showActivity = filter === "all" || filter === "activity";
|
||||
const showAgentActivity = filter === "all" || filter === "agent_activity";
|
||||
const singleColumn = filter !== "all";
|
||||
|
||||
return (
|
||||
@@ -186,7 +200,7 @@ export function HomeView({
|
||||
icon={AtSign}
|
||||
items={feed.feed.mentions}
|
||||
onMarkDone={markDone}
|
||||
onOpenChannel={onOpenChannel}
|
||||
onOpenItem={onOpenFeedItem}
|
||||
onUndoDone={undoDone}
|
||||
showDoneAction={false}
|
||||
title="Mentions"
|
||||
@@ -203,12 +217,46 @@ export function HomeView({
|
||||
icon={CircleAlert}
|
||||
items={feed.feed.needsAction}
|
||||
onMarkDone={markDone}
|
||||
onOpenChannel={onOpenChannel}
|
||||
onOpenItem={onOpenFeedItem}
|
||||
onUndoDone={undoDone}
|
||||
showDoneAction={true}
|
||||
title="Needs Action"
|
||||
/>
|
||||
) : null}
|
||||
{showActivity ? (
|
||||
<FeedSection
|
||||
availableChannelIds={availableChannelIds}
|
||||
currentPubkey={currentPubkey}
|
||||
profiles={feedProfiles}
|
||||
doneSet={doneSet}
|
||||
emptyDescription="Recent channel messages and forum posts will show up here."
|
||||
emptyTitle="No channel activity yet"
|
||||
icon={Activity}
|
||||
items={feed.feed.activity ?? []}
|
||||
onMarkDone={markDone}
|
||||
onOpenItem={onOpenFeedItem}
|
||||
onUndoDone={undoDone}
|
||||
showDoneAction={false}
|
||||
title="Channel Activity"
|
||||
/>
|
||||
) : null}
|
||||
{showAgentActivity ? (
|
||||
<FeedSection
|
||||
availableChannelIds={availableChannelIds}
|
||||
currentPubkey={currentPubkey}
|
||||
profiles={feedProfiles}
|
||||
doneSet={doneSet}
|
||||
emptyDescription="Agent job requests, progress, and results will appear here."
|
||||
emptyTitle="No agent updates yet"
|
||||
icon={Bot}
|
||||
items={feed.feed.agentActivity ?? []}
|
||||
onMarkDone={markDone}
|
||||
onOpenItem={onOpenFeedItem}
|
||||
onUndoDone={undoDone}
|
||||
showDoneAction={false}
|
||||
title="Agent Updates"
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</React.Suspense>
|
||||
</div>
|
||||
|
||||
@@ -10,9 +10,16 @@ import {
|
||||
type UserProfileLookup,
|
||||
} from "@/features/profile/lib/identity";
|
||||
import {
|
||||
KIND_JOB_ACCEPTED,
|
||||
KIND_JOB_CANCEL,
|
||||
KIND_JOB_ERROR,
|
||||
KIND_JOB_PROGRESS,
|
||||
KIND_JOB_REQUEST,
|
||||
KIND_JOB_RESULT,
|
||||
KIND_DELETION,
|
||||
KIND_REACTION,
|
||||
KIND_STREAM_MESSAGE,
|
||||
KIND_STREAM_MESSAGE_V2,
|
||||
KIND_STREAM_MESSAGE_EDIT,
|
||||
KIND_STREAM_MESSAGE_DIFF,
|
||||
KIND_SYSTEM_MESSAGE,
|
||||
@@ -25,8 +32,15 @@ const HEX_RE = /^[0-9a-f]+$/i;
|
||||
function isTimelineContentEvent(event: RelayEvent) {
|
||||
return (
|
||||
event.kind === KIND_STREAM_MESSAGE ||
|
||||
event.kind === KIND_STREAM_MESSAGE_V2 ||
|
||||
event.kind === KIND_STREAM_MESSAGE_DIFF ||
|
||||
event.kind === KIND_SYSTEM_MESSAGE
|
||||
event.kind === KIND_SYSTEM_MESSAGE ||
|
||||
event.kind === KIND_JOB_REQUEST ||
|
||||
event.kind === KIND_JOB_ACCEPTED ||
|
||||
event.kind === KIND_JOB_PROGRESS ||
|
||||
event.kind === KIND_JOB_RESULT ||
|
||||
event.kind === KIND_JOB_CANCEL ||
|
||||
event.kind === KIND_JOB_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,17 @@ export const KIND_STREAM_MESSAGE = 9;
|
||||
export const KIND_STREAM_MESSAGE_V2 = 40002;
|
||||
export const KIND_STREAM_MESSAGE_EDIT = 40003;
|
||||
export const KIND_STREAM_MESSAGE_DIFF = 40008;
|
||||
export const KIND_REMINDER = 40007;
|
||||
export const KIND_SYSTEM_MESSAGE = 40099;
|
||||
export const KIND_JOB_REQUEST = 43001;
|
||||
export const KIND_JOB_ACCEPTED = 43002;
|
||||
export const KIND_JOB_PROGRESS = 43003;
|
||||
export const KIND_JOB_RESULT = 43004;
|
||||
export const KIND_JOB_CANCEL = 43005;
|
||||
export const KIND_JOB_ERROR = 43006;
|
||||
export const KIND_FORUM_POST = 45001;
|
||||
export const KIND_FORUM_COMMENT = 45003;
|
||||
export const KIND_APPROVAL_REQUEST = 46010;
|
||||
export const KIND_TYPING_INDICATOR = 20002;
|
||||
|
||||
// Keep this in sync with the Home-feed mention query in sprout-db.
|
||||
|
||||
@@ -147,12 +147,94 @@ test("opens a mocked channel from the home feed", async ({ page }) => {
|
||||
|
||||
await mentionsSection.getByRole("button", { name: "Open general" }).click();
|
||||
|
||||
await expect(page).toHaveURL(
|
||||
/#\/channels\/9a1657ac-f7aa-5db0-b632-d8bbeb6dfb50\?messageId=mock-feed-mention$/,
|
||||
);
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
await expect(page.getByTestId("message-timeline")).toContainText(
|
||||
"Welcome to #general",
|
||||
"Please review the release checklist.",
|
||||
);
|
||||
});
|
||||
|
||||
test("home feed shows channel and agent activity sections", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "Channel Activity" }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "Agent Updates" }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("Engineering shipped the desktop build."),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("Agent progress: channel index complete."),
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByTestId("home-feed-open-mock-feed-agent").click();
|
||||
await expect(page).toHaveURL(
|
||||
/#\/channels\/94a444a4-c0a3-5966-ab05-530c6ddc2301\?messageId=mock-feed-agent$/,
|
||||
);
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("agents");
|
||||
await expect(page.getByTestId("message-timeline")).toContainText(
|
||||
"Agent progress: channel index complete.",
|
||||
);
|
||||
});
|
||||
|
||||
test("opens a mocked forum activity item from the home feed", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "Channel Activity" }),
|
||||
).toBeVisible();
|
||||
|
||||
await page.evaluate(() => {
|
||||
const win = window as Window & {
|
||||
__SPROUT_E2E_PUSH_MOCK_FEED_ITEM__?: (item: {
|
||||
category: "mention" | "needs_action" | "activity" | "agent_activity";
|
||||
channel_id: string | null;
|
||||
channel_name: string;
|
||||
content: string;
|
||||
created_at: number;
|
||||
id: string;
|
||||
kind: number;
|
||||
pubkey: string;
|
||||
tags: string[][];
|
||||
}) => unknown;
|
||||
};
|
||||
|
||||
win.__SPROUT_E2E_PUSH_MOCK_FEED_ITEM__?.({
|
||||
category: "activity",
|
||||
channel_id: "a27e1ee9-76a6-5bdf-a5d5-1d85610dad11",
|
||||
channel_name: "watercooler",
|
||||
content: "Release checklist: async feedback thread.",
|
||||
created_at: Math.floor(Date.now() / 1000) + 5,
|
||||
id: "mock-forum-release-thread",
|
||||
kind: 45001,
|
||||
pubkey:
|
||||
"953d3363262e86b770419834c53d2446409db6d918a57f8f339d495d54ab001f",
|
||||
tags: [["h", "a27e1ee9-76a6-5bdf-a5d5-1d85610dad11"]],
|
||||
});
|
||||
});
|
||||
|
||||
await expect(
|
||||
page.getByTestId("home-feed-open-mock-forum-release-thread"),
|
||||
).toBeVisible();
|
||||
await page.getByTestId("home-feed-open-mock-forum-release-thread").click();
|
||||
|
||||
await expect(page).toHaveURL(
|
||||
/#\/channels\/a27e1ee9-76a6-5bdf-a5d5-1d85610dad11\/posts\/mock-forum-release-thread$/,
|
||||
);
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("watercooler");
|
||||
await expect(
|
||||
page.getByText("Release checklist: async feedback thread."),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("home feed renders resolved author labels", async ({ page }) => {
|
||||
const mentionsSection = page.locator("section").filter({
|
||||
has: page.getByRole("heading", { name: "Mentions" }),
|
||||
|
||||
@@ -117,7 +117,10 @@ test("loads the home feed from the relay", async ({ page }) => {
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "Channel Activity" }),
|
||||
).toHaveCount(0);
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("heading", { name: "Agent Updates" }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("creates a relay-backed stream", async ({ page }) => {
|
||||
|
||||
Reference in New Issue
Block a user