feat(FN-3800): add session switcher to chat header and mobile switcher

This merge delivers five features: a session switcher for the chat header with mobile-aware dropdown styling and proper ARIA state, mailbox notification events with deep-link highlighting to the unread task, a fix for org chart connector endpoints in wide subtrees, a correction to merge finalize so

Fusion-Task-Id: FN-3800
This commit is contained in:
Fusion
2026-05-08 22:08:31 -07:00
committed by gsxdsm
parent 42357c1649
commit fdf387b220
22 changed files with 608 additions and 22 deletions

View File

@@ -65,15 +65,27 @@ describe("WebhookNotificationProvider", () => {
it("sendNotification formats Generic correctly", async () => {
fetchMock.mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
await provider.initialize({ webhookUrl: "https://example.com/hook", webhookFormat: "generic" });
await provider.initialize({
webhookUrl: "https://example.com/hook",
webhookFormat: "generic",
dashboardHost: "http://dash",
projectId: "p1",
});
await provider.sendNotification("in-review", { taskId: "FN-1", taskTitle: "My Task", event: "in-review" });
await provider.sendNotification("message:agent-to-user", {
taskId: "FN-1",
taskTitle: "My Task",
event: "message:agent-to-user",
metadata: { messageId: "msg-1", fromId: "agent-1", toId: "user:dashboard", preview: "hello" },
});
const [, requestInit] = fetchMock.mock.calls[0] as [string, RequestInit];
const payload = JSON.parse(String(requestInit.body));
expect(payload.event).toBe("in-review");
expect(payload.event).toBe("message:agent-to-user");
expect(payload.timestamp).toEqual(expect.any(String));
expect(payload.task).toEqual({ id: "FN-1", title: "My Task" });
expect(payload.metadata).toEqual(expect.objectContaining({ messageId: "msg-1" }));
expect(payload.clickUrl).toBe("http://dash/?project=p1&task=FN-1#message-msg-1");
});
it("sendNotification returns success on HTTP 200", async () => {
@@ -138,6 +150,8 @@ describe("WebhookNotificationProvider", () => {
["planning-awaiting-input", "is awaiting your input during planning"],
["gridlock", "Pipeline gridlocked"],
["fallback-used", "Fusion recovered by switching from"],
["message:agent-to-user", 'Event "message:agent-to-user" for task My Task'],
["message:agent-to-agent", 'Event "message:agent-to-agent" for task My Task'],
["unknown-event", 'Event "unknown-event" for task My Task'],
])("message formatting for %s", async (event, expectedPart) => {
fetchMock.mockResolvedValue({ ok: true, status: 200, statusText: "OK" });