feat(FN-3379): refine heartbeat timestamps and dashboard mobile UI polish

- Remove seconds from heartbeat timestamp display and update architecture docs accordingly
- Align quick chat FAB and related component styles with shared theme tokens
- Adjust ConfirmDialog and file mention popup styling for mobile fullscreen behavior
- Update dashboard tests for AgentsView, ChatView, ConfirmDialog, and mobile CSS assertions

Fusion-Task-Id: FN-3379
This commit is contained in:
Fusion
2026-05-04 09:48:08 -07:00
committed by gsxdsm
parent a6fdf3703c
commit 2a4fba505e
2 changed files with 29 additions and 2 deletions

View File

@@ -1233,11 +1233,11 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin
return (
<>
<span className="agent-heartbeat-last text-secondary" title={lastAt.toLocaleString()}>
Last: {lastAt.toLocaleTimeString()}
Last: {lastAt.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })}
</span>
{isTicking && (
<span className="agent-heartbeat-next text-secondary" title={nextAt.toLocaleString()}>
Next: {nextAt.toLocaleTimeString()}
Next: {nextAt.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })}
</span>
)}
</>

View File

@@ -772,6 +772,33 @@ describe("AgentsView", () => {
expect(options).not.toContain("1m");
});
it("renders Last/Next heartbeat timestamps without seconds", async () => {
const lastHeartbeatAt = "2026-05-04T14:23:45.000Z";
mockFetchAgents.mockResolvedValueOnce([
{
...mockAgents[1],
lastHeartbeatAt,
runtimeConfig: { heartbeatIntervalMs: 300000 },
},
]);
mockFetchAgentStats.mockResolvedValueOnce({ total: 1, byState: { active: 1 }, byRole: { triage: 1 } });
render(<AgentsView addToast={mockAddToast} />);
const lastAt = new Date(lastHeartbeatAt);
const nextAt = new Date(lastAt.getTime() + 300000);
const expectedLast = `Last: ${lastAt.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })}`;
const expectedNext = `Next: ${nextAt.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" })}`;
await waitFor(() => {
expect(screen.getByText(expectedLast)).toBeTruthy();
expect(screen.getByText(expectedNext)).toBeTruthy();
});
expect(screen.queryByText(/Last: .*:\d{2}:\d{2}/)).toBeNull();
expect(screen.queryByText(/Next: .*:\d{2}:\d{2}/)).toBeNull();
});
it("uses the system default heartbeat interval when runtime config is unset", async () => {
mockFetchAgents.mockResolvedValue([
{