mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
refactor(ui): move 62 hand-written empty states onto EmptyState
The admin sections, the cycle, illness, medication, mood, records and settings cards, the pickers and dialogs said nothing-here-yet in a hand-written muted paragraph in five sizes and three alignments. List and section states now render through EmptyState (plain, compact; the three with a next step carry it as the action), and the six chart bodies through ChartEmptyState at their former height. The thirteen that stay are a field without a value or a hint inside an editor, not a list state. The ratchet ceiling drops from 75 to 13.
This commit is contained in:
1 parent
fe021c0ffd
commit
e7ee416e19
56 files changed
+353
-224
No files matched your search
@@ -28,6 +28,7 @@ import { useTranslations, useFormatters } from "@/lib/i18n/context";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
import { helpfulRateColour } from "./_shared";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
interface FeedbackBucket {
|
||||
severity: string;
|
||||
@@ -110,9 +111,11 @@ export function AiQualitySection() {
|
||||
onRetry={() => void query.refetch()}
|
||||
/>
|
||||
) : !hasData ? (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("admin.aiQuality.empty")}
|
||||
</p>
|
||||
<EmptyState
|
||||
variant="plain"
|
||||
size="compact"
|
||||
title={t("admin.aiQuality.empty")}
|
||||
/>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm" data-slot="ai-quality-table">
|
||||
|
||||
@@ -28,6 +28,7 @@ import { useTranslations, useFormatters } from "@/lib/i18n/context";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
import { helpfulRateColour } from "./_shared";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
interface CoachFeedbackBucket {
|
||||
promptVersion: string;
|
||||
@@ -105,9 +106,11 @@ export function CoachFeedbackSection() {
|
||||
onRetry={() => void query.refetch()}
|
||||
/>
|
||||
) : !hasData ? (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("admin.coachFeedback.empty")}
|
||||
</p>
|
||||
<EmptyState
|
||||
variant="plain"
|
||||
size="compact"
|
||||
title={t("admin.coachFeedback.empty")}
|
||||
/>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm" data-slot="coach-feedback-table">
|
||||
|
||||
@@ -53,6 +53,7 @@ import {
|
||||
import { KeyBackupCard } from "./key-backup-card";
|
||||
import { useKeyBackupStatus } from "./use-key-backup-status";
|
||||
import { QueryErrorRow } from "@/components/ui/query-error-row";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
interface ColumnScan {
|
||||
model: string;
|
||||
@@ -446,9 +447,11 @@ export function ColumnCoverage({
|
||||
{open ? (
|
||||
<>
|
||||
{shown.length === 0 ? (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("admin.section.encryption.columnsNoneWithRows")}
|
||||
</p>
|
||||
<EmptyState
|
||||
variant="plain"
|
||||
size="compact"
|
||||
title={t("admin.section.encryption.columnsNoneWithRows")}
|
||||
/>
|
||||
) : (
|
||||
/* Focusable, named scroll region: on a phone the table scrolls
|
||||
sideways, and a keyboard user has to be able to reach it
|
||||
|
||||
@@ -48,6 +48,7 @@ import { SettingsCardHeader } from "@/components/settings/_card-header";
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
import { readStoredTimezone } from "@/lib/timezone-mirror";
|
||||
import { resolveIntlLocale } from "@/lib/format-locale";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
interface HostMetricsApiSample {
|
||||
capturedAt: string;
|
||||
@@ -227,9 +228,11 @@ export function HostMetricsChart() {
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t("admin.hostMetrics.empty")}
|
||||
</p>
|
||||
<EmptyState
|
||||
variant="plain"
|
||||
size="compact"
|
||||
title={t("admin.hostMetrics.empty")}
|
||||
/>
|
||||
</SettingsCard>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { queryKeys } from "@/lib/query-keys";
|
||||
import { apiGet } from "@/lib/api/api-fetch";
|
||||
import { formatDateTime } from "@/lib/format";
|
||||
import { QueryErrorRow } from "@/components/ui/query-error-row";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
/**
|
||||
* v1.37.31 — the delivery-health readout the `provider_health` ledger never
|
||||
@@ -143,9 +144,11 @@ export function ProviderHealthSection() {
|
||||
onRetry={() => void refetch()}
|
||||
/>
|
||||
) : providers.length === 0 ? (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("admin.providerHealth.empty")}
|
||||
</p>
|
||||
<EmptyState
|
||||
variant="plain"
|
||||
size="compact"
|
||||
title={t("admin.providerHealth.empty")}
|
||||
/>
|
||||
) : (
|
||||
<ul className="flex flex-col gap-3" data-testid="provider-health-list">
|
||||
{providers.map((p) => (
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
describeChannelTestFailures,
|
||||
type ChannelTestResult,
|
||||
} from "./notification-test-failures";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
interface NotificationHealth {
|
||||
windowHours: number;
|
||||
@@ -73,9 +74,11 @@ function NotificationHealthPanel() {
|
||||
)}
|
||||
|
||||
{data && data.channels.length === 0 && (
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{t("admin.notificationHealth.empty")}
|
||||
</p>
|
||||
<EmptyState
|
||||
variant="plain"
|
||||
size="compact"
|
||||
title={t("admin.notificationHealth.empty")}
|
||||
/>
|
||||
)}
|
||||
|
||||
{data && data.channels.length > 0 && (
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
useSystemStatus,
|
||||
type FailingQueue,
|
||||
} from "./_shared";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
|
||||
// v1.4.16: Recharts is ~108 KiB Brotli — defer-load the host
|
||||
// metrics chart so the system-status page only ships it when an admin
|
||||
@@ -89,12 +90,14 @@ export function FailingJobsCard({
|
||||
description={t("admin.failingJobs.description")}
|
||||
/>
|
||||
{failingJobs.queues.length === 0 ? (
|
||||
<p
|
||||
<EmptyState
|
||||
variant="plain"
|
||||
size="compact"
|
||||
title={t("admin.failingJobs.none", {
|
||||
hours: failingJobs.windowHours,
|
||||
})}
|
||||
data-testid="failing-jobs-none"
|
||||
className="text-muted-foreground text-sm"
|
||||
>
|
||||
{t("admin.failingJobs.none", { hours: failingJobs.windowHours })}
|
||||
</p>
|
||||
/>
|
||||
) : (
|
||||
<ul data-testid="failing-jobs-list" className="space-y-3">
|
||||
{failingJobs.queues.map((queue) => (
|
||||
|
||||
Reference in new issue
Block a user