feat(ui): R3 S1 — honest error states across the pages

The error state didn't exist as a concept: a failed main query rendered as an "empty" list
("No channels" while the request actually died), so a backend restart read as "everything is
empty". Add the convention that an empty state may NEVER show while a query is erroring.

- New components/QueryState.tsx: shared StateMessage (loading / error+Retry, house style, with
  role=status/aria-live — the app had zero live regions).
- DataTable gains loading/error/onRetry props (suppresses empty-text on error).
- isError branch (before the empty branch) added across the false-empty pages: Feed (retry),
  Channels, ChannelDiscovery, AuditLog, NotificationsPanel, Messages (conversations + people),
  Scheduler, Stats, PlexBrowse grid, PlexPlaylistView. ChannelPage's main content is Feed, now
  covered. common.loadError/empty strings (en+hu).
This commit is contained in:
2026-07-22 03:58:51 +02:00
parent 2427de3bbc
commit d9a08892a5
14 changed files with 138 additions and 13 deletions
+6 -1
View File
@@ -15,6 +15,7 @@ import ChannelLink from "./ChannelLink";
import AboutCell from "./AboutCell";
import DataTable, { type Column } from "./DataTable";
import ChannelLayoutGrid from "./ChannelLayoutGrid";
import { StateMessage } from "./QueryState";
import ColumnSortControl from "./ColumnSortControl";
import Pager from "./Pager";
import { PageToolbar } from "./PageShell";
@@ -223,7 +224,11 @@ export default function ChannelDiscovery({
</div>
</PageToolbar>
<div className="px-4 pb-4 max-w-[96rem] mx-auto">
{query.isLoading ? (
{query.isError ? (
<StateMessage tone="error" onRetry={() => query.refetch()}>
{t("common.loadError")}
</StateMessage>
) : query.isLoading ? (
<div className="text-muted py-8">{t("channels.discovery.loading")}</div>
) : layout === "table" ? (
<DataTable