Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/buzz-help.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,13 @@ that agent in Buzz; they do not notify the external app through this connection.
- **Inbox** collects DMs, ordinary responses in Solo chats, mentions of you, and replies in threads you started,
replied in, or follow. Solo chats appear under All, not DMs; their nested threads stay separate. Agent-only
coordination stays out.
- **New messages** marks the first known unread incoming channel message when
you enter. Once established, the divider stays in place for that visit as you
read, reveal another message, or receive new messages. It is absent for a visit
that starts with incomplete or unverified history, even if older rows load
later. It may also be absent when unread evidence is incomplete, or when read
intent or the read evidence needed to locate the boundary changes before it is
established.
- **Communities** have their own channels, people, and agents. Switching
communities changes the available context. A channel reopens where you
stopped reading, or at the latest message once you had caught up. You and
Expand Down
11 changes: 6 additions & 5 deletions src/bundled/channels/ChannelsPage.solo.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,11 @@ function fixture({
coverage: "observed" as const,
freshness: "observed" as const,
};
const readSync = {
capability,
status: "reconciled" as const,
completeness: "snapshot" as const,
};
const session = {
...owner.session,
profiles: {
Expand Down Expand Up @@ -293,11 +298,7 @@ function fixture({
? owner.session.unread
: {
...owner.session.unread,
sync: () => ({
capability,
status: "reconciled" as const,
completeness: "snapshot" as const,
}),
sync: () => readSync,
snapshot: (
target: Parameters<typeof owner.session.unread.snapshot>[0],
) => {
Expand Down
70 changes: 59 additions & 11 deletions src/bundled/channels/ConversationTab.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ vi.mock("../../features/messages/MessageComposer", () => ({
</div>
),
}));
const unreadEvidence = {
revision: () => 0,
sync: () => ({ capability: "unsupported" }),
};
const owners: ReturnType<typeof createOutbox>[] = [];
afterEach(() => {
cleanup();
Expand Down Expand Up @@ -138,8 +142,13 @@ it.each(["thread", "conversation"] as const)(
// Only management consumes this session; independent child views above are
// stubbed. These writable tabs have static eligibility/profile evidence.
const session = {
unread: unreadEvidence,
outbox: owner.outbox,
channels: { list: () => channels, subscribeList: () => () => {} },
channels: {
window: () => ({ rows: [] }),
list: () => channels,
subscribeList: () => () => {},
},
profiles: { subscribe: () => () => {} },
messages: { canRetry: () => true },
} as unknown as RelaySession;
Expand Down Expand Up @@ -201,9 +210,13 @@ it.each(["thread", "conversation"] as const)(
const leaveChannel = vi.fn();
const session = {
viewer: "viewer",
channels: { list: () => snapshot, subscribeList: () => () => {} },
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: () => () => {},
},
profiles: {},
unread: { enterChannel, leaveChannel },
unread: { ...unreadEvidence, enterChannel, leaveChannel },
} as unknown as RelaySession;
const props = {
tab: {
Expand Down Expand Up @@ -253,9 +266,13 @@ it.each(["thread", "conversation"] as const)(
const enterChannel = vi.fn(async () => {});
const session = {
viewer: "viewer",
channels: { list: () => snapshot, subscribeList: () => () => {} },
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: () => () => {},
},
profiles: {},
unread: { enterChannel, leaveChannel: vi.fn() },
unread: { ...unreadEvidence, enterChannel, leaveChannel: vi.fn() },
} as unknown as RelaySession;
render(
<ConversationTab
Expand Down Expand Up @@ -294,7 +311,12 @@ it.each([false, true])(
const channel = { id: "beta", name: "Beta" };
const snapshot = { status: "ready", channels: [channel] };
const session = {
channels: { list: () => snapshot, subscribeList: () => () => {} },
unread: unreadEvidence,
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: () => () => {},
},
} as unknown as RelaySession;
const tab = {
id: "thread",
Expand Down Expand Up @@ -340,7 +362,12 @@ it("a tab mounted later in its visit treats the visit's requests as restored", (
const channel = { id: "beta", name: "Beta" };
const snapshot = { status: "ready", channels: [channel] };
const session = {
channels: { list: () => snapshot, subscribeList: () => () => {} },
unread: unreadEvidence,
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: () => () => {},
},
} as unknown as RelaySession;
const tab: Tab = {
id: "thread",
Expand Down Expand Up @@ -390,7 +417,12 @@ it.each([
const channel = { id: "beta", name: "Beta" };
const snapshot = { status: "ready", channels: [channel] };
const session = {
channels: { list: () => snapshot, subscribeList: () => () => {} },
unread: unreadEvidence,
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: () => () => {},
},
} as unknown as RelaySession;
const tab: Tab =
kind === "thread"
Expand Down Expand Up @@ -434,7 +466,12 @@ it.each(["pointerDown", "keyDown"] as const)(
const channel = { id: "beta", name: "Beta" };
const snapshot = { status: "ready", channels: [channel] };
const session = {
channels: { list: () => snapshot, subscribeList: () => () => {} },
unread: unreadEvidence,
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: () => () => {},
},
} as unknown as RelaySession;
const tab: Tab = {
id: "thread",
Expand Down Expand Up @@ -482,6 +519,7 @@ function openingAt(rows: { id: string; threadRootId?: string }[]) {
};
const listeners = new Set<() => void>();
const session = {
unread: unreadEvidence,
channels: {
list: () => snapshot,
subscribeList: () => () => {},
Expand Down Expand Up @@ -641,7 +679,12 @@ it("lets the tab supply Solo chat identity without repeating a visible heading",
const idle = () => () => {};
const profiles = new Map();
const session = {
channels: { list: () => snapshot, subscribeList: idle },
unread: unreadEvidence,
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: idle,
},
profiles: { snapshot: () => profiles, subscribe: idle },
agentChoices: { snapshot: () => undefined, subscribe: idle },
} as unknown as RelaySession;
Expand Down Expand Up @@ -675,7 +718,12 @@ it("tells the composer when its tab is shown, apart from whether showing visits"
const idle = () => () => {};
const profiles = new Map();
const session = {
channels: { list: () => snapshot, subscribeList: idle },
unread: unreadEvidence,
channels: {
window: () => ({ rows: [] }),
list: () => snapshot,
subscribeList: idle,
},
profiles: { snapshot: () => profiles, subscribe: idle },
agentChoices: { snapshot: () => undefined, subscribe: idle },
} as unknown as RelaySession;
Expand Down
1 change: 1 addition & 0 deletions src/bundled/channels/useConversationTabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,7 @@ it("a hidden retained thread tab's rows re-render for new panels, not channel-li
messages: { retry: () => {} },
media: () => undefined,
unread: {
revision: () => 0,
sync: () => sync,
snapshot: () => undefined,
subscribe: () => () => {},
Expand Down
7 changes: 6 additions & 1 deletion src/features/conversation/EmbeddedThread.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ function fixture(
],
};
const unread = {
revision: () => 0,
sync: () => ({ capability: "unsupported" }),
snapshot: () => undefined,
subscribe: () => () => {},
Expand All @@ -166,7 +167,11 @@ function fixture(
loadMore: async () => {},
dispose() {},
}),
channels: { subscribeList: () => () => {}, list: () => channels },
channels: {
subscribeList: () => () => {},
list: () => channels,
window: () => ({ rows: [] }),
},
profiles: {
ensure: async () => {},
snapshot: () => profiles,
Expand Down
Loading
Loading