- {summary &&
{summary}
}
+ {summary && (
+
{summary}
+ )}
{change &&
{change}
}
+ {r.runs && r.runs.length > 1 && (
+
localDetails(t, run, lang)?.sub ?? run.summary}
+ />
+ )}
);
},
diff --git a/frontend/src/components/feedFiltersInit.ts b/frontend/src/components/feedFiltersInit.ts
index fe0f9594..d9eb0ccd 100644
--- a/frontend/src/components/feedFiltersInit.ts
+++ b/frontend/src/components/feedFiltersInit.ts
@@ -18,6 +18,9 @@ export const DEFAULT_FILTERS: FeedFilters = {
show: "unwatched",
};
+/** The watch-state choices, in the order the filter offers them. */
+export const SHOW_IDS = ["unwatched", "in_progress", "all", "watched", "hidden"];
+
export const FILTERS_KEY = LS.filters;
// This account's own persisted filters (per-account keys — never another account's). No account
diff --git a/frontend/src/components/ui/NavRail.dom.test.tsx b/frontend/src/components/ui/NavRail.dom.test.tsx
index cd0b9b70..0ed36d31 100644
--- a/frontend/src/components/ui/NavRail.dom.test.tsx
+++ b/frontend/src/components/ui/NavRail.dom.test.tsx
@@ -6,7 +6,7 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
-import { cleanup, render, screen } from "@testing-library/react";
+import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import { Bell } from "lucide-react";
import { NavRailAction, NavRailItem } from "./NavRail";
@@ -24,10 +24,11 @@ describe("NavRailItem", () => {
showLabel={false}
active
badge={3}
+ href="/?page=notifications"
onClick={() => {}}
/>,
);
- const row = screen.getByRole("button", { name: "Notifications (3)" });
+ const row = screen.getByRole("link", { name: "Notifications (3)" });
expect(row.getAttribute("aria-current")).toBe("page");
expect(row.className).toContain("bg-accent/15");
expect(row.textContent).not.toContain("Alerts");
@@ -40,10 +41,11 @@ describe("NavRailItem", () => {
label="Notifications"
shortLabel="Alerts"
showLabel
+ href="/?page=notifications"
onClick={() => {}}
/>,
);
- const row = screen.getByRole("button", { name: "Alerts" });
+ const row = screen.getByRole("link", { name: "Alerts" });
expect(row.getAttribute("aria-current")).toBeNull();
});
@@ -57,10 +59,51 @@ describe("NavRailItem", () => {
shortLabel="Alerts"
showLabel
badge={20}
+ href="/?page=notifications"
onClick={() => {}}
/>,
);
- expect(screen.getByRole("button", { name: "Alerts (20)" })).toBeTruthy();
+ expect(screen.getByRole("link", { name: "Alerts (20)" })).toBeTruthy();
+ });
+
+ // E31 (the owner): a middle-click on a rail row opens the page in a new tab. The row is a real link
+ // to the page, so the browser's own gestures work; only a plain left click navigates in-app.
+ it("is a link to its page, navigating in-app only on a plain left click", () => {
+ const onClick = vi.fn();
+ render(
+