web: professional UI overhaul — ink/slate design system, archive+active sections, skeletons, error boundary, conn banner, usage chip, message copy, spawn progress steps; 162 tests ≥95% coverage

This commit is contained in:
Raphael Westphal
2026-08-18 18:19:25 +02:00
parent 42fcaa1fe3
commit e626b9cc6e
12 changed files with 1583 additions and 552 deletions
+18 -4
View File
@@ -1,4 +1,4 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { act, fireEvent, render, screen } from "@testing-library/react";
import { MemoryRouter, Route, Routes, useParams } from "react-router-dom";
import { describe, expect, it, vi } from "vitest";
import type { SessionListItem } from "./protocol";
@@ -43,7 +43,7 @@ function Probe({ onVisit }: { onVisit: (path: string) => void }): null {
}
describe("SessionsView", () => {
it("offline sessions are hidden (active only)", () => {
it("offline sessions appear under the Archive section, not in active", () => {
renderView({
sessions: [
session({ id: "on", name: "live" }),
@@ -53,14 +53,28 @@ describe("SessionsView", () => {
const cards = screen.getAllByRole("button", { name: /^Open session/ });
expect(cards.map((c) => c.getAttribute("aria-label"))).toEqual([
"Open session live",
"Open session dead",
]);
expect(screen.getByText("Archive")).toBeInTheDocument();
});
it("empty state message", () => {
renderView();
it("empty state message (after load window)", () => {
vi.useFakeTimers();
renderView({ sessions: [] });
act(() => { vi.advanceTimersByTime(700); });
expect(screen.getByText(/No active sessions/i)).toBeInTheDocument();
vi.useRealTimers();
});
it("skeleton while first load pending", () => {
renderView({ sessions: [] });
expect(screen.getByRole("heading", { name: "Active sessions" })).toBeInTheDocument();
const skel = document.querySelector(".skeleton");
expect(skel).not.toBeNull();
});
it("renders cards sorted by last activity with fallbacks", () => {
renderView({
sessions: [