feat(ui): R3 S2 — loading rows for blank-flash pages, error paths for forever-loading ones
- Blank-flash (showed an empty state on first load before data): DownloadCenter (queue + library tabs), AdminUsers (roles + invites), ChatThread, PlaylistsRail now show a loading indicator (and an error+retry) instead of a false-empty flash — guarded on `&& !data` so live data isn't disturbed on refetch. - Forever-loading (`isLoading || !data` loops forever on a failed fetch): ConfigPanel, the three PlexBrowse subviews (playlist/show/season), and Stats' admin dashboard get an `isError && !data` error+retry path before the loading branch. - Playlists' detail pane already had an error path (isError+retry); its list lives in PlaylistsRail (now covered), so no change needed there.
This commit is contained in:
@@ -7,6 +7,7 @@ import { notify } from "../lib/notifications";
|
||||
import { ADMIN_USERS_TAB_KEY } from "../lib/adminUsersTab";
|
||||
import Tooltip from "./Tooltip";
|
||||
import { Section } from "./ui/form";
|
||||
import { StateMessage } from "./QueryState";
|
||||
import { useConfirm } from "./ConfirmProvider";
|
||||
import Tabs, { usePersistedTab } from "./Tabs";
|
||||
import { PageToolbar } from "./PageShell";
|
||||
@@ -159,7 +160,13 @@ function UsersRoles({ me }: { me: Me }) {
|
||||
return (
|
||||
<Section card title={t("users.roles.title")}>
|
||||
<p className="text-xs text-muted leading-relaxed mb-3">{t("users.roles.intro")}</p>
|
||||
{rows.length === 0 ? (
|
||||
{q.isError && !q.data ? (
|
||||
<StateMessage tone="error" onRetry={() => q.refetch()}>
|
||||
{t("common.loadError")}
|
||||
</StateMessage>
|
||||
) : q.isLoading && !q.data ? (
|
||||
<p className="text-sm text-muted">{t("common.loading")}</p>
|
||||
) : rows.length === 0 ? (
|
||||
<p className="text-sm text-muted">{t("users.roles.empty")}</p>
|
||||
) : (
|
||||
<div className="space-y-1.5">
|
||||
@@ -307,7 +314,13 @@ function AdminInvites() {
|
||||
|
||||
return (
|
||||
<Section card title={t("settings.invites.title")}>
|
||||
{pending.length === 0 ? (
|
||||
{invites.isError && !invites.data ? (
|
||||
<StateMessage tone="error" onRetry={() => invites.refetch()}>
|
||||
{t("common.loadError")}
|
||||
</StateMessage>
|
||||
) : invites.isLoading && !invites.data ? (
|
||||
<p className="text-sm text-muted">{t("common.loading")}</p>
|
||||
) : pending.length === 0 ? (
|
||||
<p className="text-sm text-muted">{t("settings.invites.noPending")}</p>
|
||||
) : (
|
||||
<div className="space-y-1.5">
|
||||
|
||||
Reference in New Issue
Block a user