feat(client): unified EmptyState across all pages and table empties
- New EmptyState + EmptyStateIllustration components: stacked-cards SVG with grid background, theme-aware light/dark palette. - Variants: default (centered with title + description), compact (horizontal, in-section), fullscreen (vertically centers in viewport). - Wired into Checks, Incidents, Logs (Logs+Queue tabs), Notifications, Maintenance, Status pages, and Team tab — each with i18n title + description and a fullscreen layout when truly empty. - Table.EmptyView now wraps the EmptyState in a divider-bordered card so short messages no longer look orphaned. - Incidents Option-A short-circuit: when summary.total === 0, replace the whole page chrome with EmptyState; otherwise keep filters + cards. - Fallback.tsx (BaseFallback / EmptyFallback / EmptyMonitorFallback / ErrorFallback) refactored to delegate to EmptyState.
This commit is contained in:
1 parent
ff208710d7
commit
031a6fdf3c
12 files changed
+188
-145
No files matched your search
@@ -17,6 +17,7 @@ interface EmptyStateProps {
|
||||
secondaryText?: string;
|
||||
secondaryHref?: string;
|
||||
compact?: boolean;
|
||||
fullscreen?: boolean;
|
||||
alert?: ReactNode;
|
||||
children?: ReactNode;
|
||||
}
|
||||
@@ -30,6 +31,7 @@ export const EmptyState = ({
|
||||
secondaryText,
|
||||
secondaryHref,
|
||||
compact = false,
|
||||
fullscreen = false,
|
||||
alert,
|
||||
children,
|
||||
}: EmptyStateProps) => {
|
||||
@@ -78,6 +80,7 @@ export const EmptyState = ({
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
sx={{
|
||||
...(fullscreen && { minHeight: "65vh" }),
|
||||
py: theme.spacing(LAYOUT.XXL),
|
||||
px: theme.spacing(LAYOUT.MD),
|
||||
textAlign: "center",
|
||||
|
||||
@@ -1,12 +1,37 @@
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
interface EmptyStateIllustrationProps {
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
}
|
||||
|
||||
const PALETTE = {
|
||||
light: {
|
||||
grid: "#CBD5E1",
|
||||
backFill: "#F5F7FA",
|
||||
backStroke: "#D5DBE3",
|
||||
backInner: "#B6C2CF",
|
||||
frontFill: "#EEF4FE",
|
||||
frontStroke: "#7DA8E8",
|
||||
frontInner: "#7DA8E8",
|
||||
},
|
||||
dark: {
|
||||
grid: "#3A4452",
|
||||
backFill: "#475569",
|
||||
backStroke: "#64748B",
|
||||
backInner: "#CBD5E1",
|
||||
frontFill: "#1E40AF",
|
||||
frontStroke: "#60A5FA",
|
||||
frontInner: "#DBEAFE",
|
||||
},
|
||||
};
|
||||
|
||||
export const EmptyStateIllustration = ({
|
||||
width = 160,
|
||||
height = 120,
|
||||
}: EmptyStateIllustrationProps) => {
|
||||
const theme = useTheme();
|
||||
const p = theme.palette.mode === "dark" ? PALETTE.dark : PALETTE.light;
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 160 120"
|
||||
@@ -14,50 +39,8 @@ export const EmptyStateIllustration = ({
|
||||
height={height}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="emptyStateCardFade"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor="white"
|
||||
stopOpacity="1"
|
||||
/>
|
||||
<stop
|
||||
offset="65%"
|
||||
stopColor="white"
|
||||
stopOpacity="1"
|
||||
/>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor="white"
|
||||
stopOpacity="0.35"
|
||||
/>
|
||||
</linearGradient>
|
||||
<mask
|
||||
id="emptyStateCardMask"
|
||||
maskUnits="userSpaceOnUse"
|
||||
x="0"
|
||||
y="0"
|
||||
width="160"
|
||||
height="120"
|
||||
>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="160"
|
||||
height="120"
|
||||
fill="url(#emptyStateCardFade)"
|
||||
/>
|
||||
</mask>
|
||||
</defs>
|
||||
|
||||
<g
|
||||
stroke="#CBD5E1"
|
||||
stroke={p.grid}
|
||||
strokeWidth="0.75"
|
||||
>
|
||||
<line
|
||||
@@ -114,15 +97,15 @@ export const EmptyStateIllustration = ({
|
||||
/>
|
||||
</g>
|
||||
|
||||
<g mask="url(#emptyStateCardMask)">
|
||||
<g>
|
||||
<rect
|
||||
x="38"
|
||||
y="22"
|
||||
width="92"
|
||||
height="42"
|
||||
rx="6"
|
||||
fill="#F5F7FA"
|
||||
stroke="#D5DBE3"
|
||||
fill={p.backFill}
|
||||
stroke={p.backStroke}
|
||||
strokeWidth="0.5"
|
||||
/>
|
||||
<rect
|
||||
@@ -131,7 +114,7 @@ export const EmptyStateIllustration = ({
|
||||
width="14"
|
||||
height="22"
|
||||
rx="2"
|
||||
fill="#B6C2CF"
|
||||
fill={p.backInner}
|
||||
opacity="0.5"
|
||||
/>
|
||||
<rect
|
||||
@@ -140,7 +123,7 @@ export const EmptyStateIllustration = ({
|
||||
width="50"
|
||||
height="2.5"
|
||||
rx="1.25"
|
||||
fill="#B6C2CF"
|
||||
fill={p.backInner}
|
||||
opacity="0.7"
|
||||
/>
|
||||
<rect
|
||||
@@ -149,7 +132,7 @@ export const EmptyStateIllustration = ({
|
||||
width="38"
|
||||
height="2.5"
|
||||
rx="1.25"
|
||||
fill="#B6C2CF"
|
||||
fill={p.backInner}
|
||||
opacity="0.55"
|
||||
/>
|
||||
<rect
|
||||
@@ -158,7 +141,7 @@ export const EmptyStateIllustration = ({
|
||||
width="44"
|
||||
height="2.5"
|
||||
rx="1.25"
|
||||
fill="#B6C2CF"
|
||||
fill={p.backInner}
|
||||
opacity="0.55"
|
||||
/>
|
||||
<rect
|
||||
@@ -167,8 +150,8 @@ export const EmptyStateIllustration = ({
|
||||
width="92"
|
||||
height="42"
|
||||
rx="6"
|
||||
fill="#EEF4FE"
|
||||
stroke="#7DA8E8"
|
||||
fill={p.frontFill}
|
||||
stroke={p.frontStroke}
|
||||
strokeWidth="0.5"
|
||||
strokeOpacity="0.4"
|
||||
/>
|
||||
@@ -178,7 +161,7 @@ export const EmptyStateIllustration = ({
|
||||
width="14"
|
||||
height="22"
|
||||
rx="2"
|
||||
fill="#7DA8E8"
|
||||
fill={p.frontInner}
|
||||
opacity="0.35"
|
||||
/>
|
||||
<rect
|
||||
@@ -187,7 +170,7 @@ export const EmptyStateIllustration = ({
|
||||
width="50"
|
||||
height="2.5"
|
||||
rx="1.25"
|
||||
fill="#7DA8E8"
|
||||
fill={p.frontInner}
|
||||
opacity="0.55"
|
||||
/>
|
||||
<rect
|
||||
@@ -196,7 +179,7 @@ export const EmptyStateIllustration = ({
|
||||
width="38"
|
||||
height="2.5"
|
||||
rx="1.25"
|
||||
fill="#7DA8E8"
|
||||
fill={p.frontInner}
|
||||
opacity="0.4"
|
||||
/>
|
||||
<rect
|
||||
@@ -205,7 +188,7 @@ export const EmptyStateIllustration = ({
|
||||
width="44"
|
||||
height="2.5"
|
||||
rx="1.25"
|
||||
fill="#7DA8E8"
|
||||
fill={p.frontInner}
|
||||
opacity="0.4"
|
||||
/>
|
||||
</g>
|
||||
|
||||
@@ -32,32 +32,29 @@ export const ErrorFallback = ({
|
||||
}) => {
|
||||
return (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={title}
|
||||
description={subtitle}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const bulletsToDescription = (bullets: unknown): string | undefined => {
|
||||
if (!Array.isArray(bullets) || bullets.length === 0) return undefined;
|
||||
return bullets.join(" • ");
|
||||
};
|
||||
|
||||
export const EmptyFallback = ({
|
||||
title,
|
||||
bullets,
|
||||
description,
|
||||
actionButtonText,
|
||||
actionLink,
|
||||
}: {
|
||||
title: string;
|
||||
bullets: unknown;
|
||||
description?: string;
|
||||
actionButtonText: string;
|
||||
actionLink: string;
|
||||
}) => {
|
||||
return (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={title}
|
||||
description={bulletsToDescription(bullets)}
|
||||
description={description}
|
||||
actionText={actionButtonText}
|
||||
actionTo={actionLink}
|
||||
/>
|
||||
@@ -66,20 +63,21 @@ export const EmptyFallback = ({
|
||||
|
||||
export const EmptyMonitorFallback = ({
|
||||
title,
|
||||
bullets,
|
||||
description,
|
||||
actionButtonText,
|
||||
actionLink,
|
||||
}: {
|
||||
page: string;
|
||||
title: string;
|
||||
bullets: unknown;
|
||||
description?: string;
|
||||
actionButtonText: string;
|
||||
actionLink: string;
|
||||
}) => {
|
||||
return (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={title}
|
||||
description={bulletsToDescription(bullets)}
|
||||
description={description}
|
||||
actionText={actionButtonText}
|
||||
actionTo={actionLink}
|
||||
/>
|
||||
|
||||
@@ -18,10 +18,9 @@ import {
|
||||
ChevronsRight,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Coffee,
|
||||
Ellipsis,
|
||||
PartyPopper,
|
||||
} from "lucide-react";
|
||||
import { EmptyState } from "./EmptyState";
|
||||
|
||||
import TablePagination from "@mui/material/TablePagination";
|
||||
import type { TablePaginationOwnProps } from "@mui/material/TablePagination";
|
||||
@@ -548,49 +547,18 @@ export const Pagination = ({ ...props }: PaginationProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const EmptyView = ({ text, positive }: { text?: string; positive?: boolean }) => {
|
||||
const theme = useTheme();
|
||||
const EmptyView = ({ text }: { text?: string; positive?: boolean }) => {
|
||||
const { t } = useTranslation();
|
||||
const Icon = positive ? PartyPopper : Coffee;
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Stack
|
||||
alignItems={"center"}
|
||||
justifyContent={"center"}
|
||||
<Box
|
||||
sx={{
|
||||
py: theme.spacing(LAYOUT.XL),
|
||||
px: theme.spacing(LAYOUT.XS),
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.divider,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
textAlign: "center",
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
borderRadius: 1,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: 64,
|
||||
height: 64,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
mb: theme.spacing(SPACING.LG),
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
size={28}
|
||||
strokeWidth={1}
|
||||
color={theme.palette.text.secondary}
|
||||
/>
|
||||
</Box>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
color={theme.palette.text.primary}
|
||||
sx={{ fontWeight: 500 }}
|
||||
>
|
||||
{text ?? t("common.table.empty")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<EmptyState title={text ?? t("common.table.empty")} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -1,15 +1,18 @@
|
||||
import { Stack } from "@mui/material";
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useState, useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { HeaderTeamControls } from "./components/HeaderTeamControls";
|
||||
import { TeamTable } from "./components/TeamTable";
|
||||
import { InviteTeamMemberDialog } from "./components/InviteTeamMemberDialog";
|
||||
import { AddTeamMemberDialog } from "./components/AddTeamMemberDialog";
|
||||
import { EmptyState } from "@/Components/design-elements";
|
||||
import { useGet } from "@/Hooks/UseApi";
|
||||
import type { User, UserRole } from "@/Types/User";
|
||||
|
||||
export const TabTeam = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const [filter, setFilter] = useState<UserRole | "">("");
|
||||
const [inviteDialogOpen, setInviteDialogOpen] = useState(false);
|
||||
const [addMemberDialogOpen, setAddMemberDialogOpen] = useState(false);
|
||||
@@ -33,6 +36,9 @@ export const TabTeam = () => {
|
||||
refetch();
|
||||
};
|
||||
|
||||
const totalUsers = users?.length ?? 0;
|
||||
const noUsers = users !== undefined && totalUsers === 0;
|
||||
|
||||
return (
|
||||
<Stack gap={theme.spacing(8)}>
|
||||
<HeaderTeamControls
|
||||
@@ -41,7 +47,15 @@ export const TabTeam = () => {
|
||||
onInviteClick={handleOpenInviteDialog}
|
||||
onAddMemberClick={handleOpenAddMemberDialog}
|
||||
/>
|
||||
<TeamTable users={filteredUsers} />
|
||||
{noUsers ? (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={t("pages.account.team.fallback.title")}
|
||||
description={t("pages.account.team.fallback.description")}
|
||||
/>
|
||||
) : (
|
||||
<TeamTable users={filteredUsers} />
|
||||
)}
|
||||
<InviteTeamMemberDialog
|
||||
open={inviteDialogOpen}
|
||||
onClose={handleCloseInviteDialog}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import {
|
||||
BasePage,
|
||||
EmptyState,
|
||||
TotalChecksBox,
|
||||
UpChecksBox,
|
||||
DownChecksBox,
|
||||
@@ -102,8 +103,19 @@ const Checks = () => {
|
||||
const downChecks = summaryResponse?.downChecks || 0;
|
||||
const upChecks = totalChecks - (summaryResponse?.downChecks || 0);
|
||||
|
||||
const noMonitors = !isLoadingMonitors && (monitorsResponse?.length ?? 0) === 0;
|
||||
if (noMonitors) {
|
||||
return (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={t("pages.checks.fallback.title")}
|
||||
description={t("pages.checks.fallback.description")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BasePage>
|
||||
<BasePage headerKey="checks">
|
||||
<Stack
|
||||
direction={{ xs: "column", md: "row" }}
|
||||
gap={4}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BasePage } from "@/Components/design-elements";
|
||||
import { BasePage, EmptyState } from "@/Components/design-elements";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Divider from "@mui/material/Divider";
|
||||
@@ -153,8 +153,20 @@ const IncidentsPage = () => {
|
||||
refetchSummary();
|
||||
};
|
||||
|
||||
const trulyEmpty = summaryData !== undefined && (summaryData?.total ?? 0) === 0;
|
||||
|
||||
if (trulyEmpty) {
|
||||
return (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={t("pages.incidents.fallback.title")}
|
||||
description={t("pages.incidents.fallback.description")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BasePage>
|
||||
<BasePage headerKey="incidents">
|
||||
<Stack
|
||||
direction={{ xs: "column", md: "row" }}
|
||||
gap={theme.spacing(8)}
|
||||
@@ -171,7 +183,7 @@ const IncidentsPage = () => {
|
||||
setSelectedResolutionType={setFilter}
|
||||
onClearFilters={handleClearFilters}
|
||||
/>
|
||||
{activeIncidentsCount > 0 ? (
|
||||
{activeIncidentsCount > 0 && (
|
||||
<>
|
||||
<Typography
|
||||
variant="h6"
|
||||
@@ -193,13 +205,6 @@ const IncidentsPage = () => {
|
||||
/>
|
||||
<Divider />
|
||||
</>
|
||||
) : (
|
||||
<Typography
|
||||
variant="body1"
|
||||
sx={{ mb: theme.spacing(4), color: theme.palette.success.main }}
|
||||
>
|
||||
{t("pages.incidents.summaryCard.activeIncidents.active_zero")}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
<Typography
|
||||
|
||||
@@ -4,6 +4,7 @@ import Typography from "@mui/material/Typography";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Select } from "@/Components/inputs";
|
||||
import { TableLogs } from "@/Pages/Logs/components/TableLogs";
|
||||
import { EmptyState } from "@/Components/design-elements";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useGet } from "@/Hooks/UseApi";
|
||||
@@ -15,7 +16,7 @@ import type { RootState } from "@/Types/state";
|
||||
|
||||
export const TabLogs = () => {
|
||||
const theme = useTheme();
|
||||
const { data: logs } = useGet<Log[]>("/logs");
|
||||
const { data: logs, isLoading } = useGet<Log[]>("/logs");
|
||||
const [selectedLogLevel, setSelectedLogLevel] = useState<LogLevelOption>("all");
|
||||
const [page, setPage] = useState(0);
|
||||
const rowsPerPage = useSelector(
|
||||
@@ -33,6 +34,16 @@ export const TabLogs = () => {
|
||||
const paginatedLogs =
|
||||
filteredLogs?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) ?? [];
|
||||
|
||||
if (!isLoading && (logs?.length ?? 0) === 0) {
|
||||
return (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={t("pages.logs.fallback.title")}
|
||||
description={t("pages.logs.fallback.description")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack gap={theme.spacing(8)}>
|
||||
<Select
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
import { TableJobs, TableFailedJobs } from "./components/TableJobs";
|
||||
|
||||
import { useTheme } from "@mui/material";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTranslation, Trans } from "react-i18next";
|
||||
import { useGet, usePost } from "@/Hooks/UseApi";
|
||||
import type { QueueData } from "@/Types/Queue";
|
||||
import { Metrics } from "@/Pages/Logs/components/Metrics";
|
||||
import { Button } from "@/Components/inputs";
|
||||
import { EmptyState } from "@/Components/design-elements";
|
||||
|
||||
export const TabQueue = () => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
data: queueData,
|
||||
// isLoading,
|
||||
isLoading,
|
||||
// error,
|
||||
refetch,
|
||||
} = useGet<QueueData>("/queue/all-metrics", {}, { refreshInterval: 5000 });
|
||||
@@ -23,6 +25,17 @@ export const TabQueue = () => {
|
||||
|
||||
const jobs = queueData?.jobs ?? [];
|
||||
const metrics = queueData?.metrics ?? null;
|
||||
const hasNeverRun = !isLoading && metrics !== null && (metrics.totalRuns ?? 0) === 0;
|
||||
const noQueueData = !isLoading && metrics === null && jobs.length === 0;
|
||||
if (hasNeverRun || noQueueData) {
|
||||
return (
|
||||
<EmptyState
|
||||
fullscreen
|
||||
title={t("pages.logs.queueFallback.title")}
|
||||
description={t("pages.logs.queueFallback.description")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const handleFlushQueue = async () => {
|
||||
await post("/queue/flush", {});
|
||||
@@ -32,19 +45,58 @@ export const TabQueue = () => {
|
||||
return (
|
||||
<Stack gap={theme.spacing(8)}>
|
||||
<Metrics metrics={metrics} />
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{ textTransform: "uppercase" }}
|
||||
>
|
||||
{t("pages.logs.jobQueue")}
|
||||
</Typography>
|
||||
<Stack gap={theme.spacing(1)}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{ textTransform: "uppercase" }}
|
||||
>
|
||||
{t("pages.logs.jobQueue")}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: 13,
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
<Trans
|
||||
i18nKey="pages.logs.jobQueueExplainer"
|
||||
components={{
|
||||
highlight: (
|
||||
<Box
|
||||
component="span"
|
||||
sx={{
|
||||
backgroundColor:
|
||||
theme.palette.mode === "dark"
|
||||
? "rgba(19, 113, 91, 0.18)"
|
||||
: "#ECF7F2",
|
||||
color: theme.palette.text.primary,
|
||||
px: 1,
|
||||
py: 0.25,
|
||||
borderRadius: 0.5,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Typography>
|
||||
</Stack>
|
||||
<TableJobs jobs={jobs} />
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{ textTransform: "uppercase" }}
|
||||
>
|
||||
{t("pages.logs.failedJobs")}
|
||||
</Typography>
|
||||
<Stack gap={theme.spacing(1)}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{ textTransform: "uppercase" }}
|
||||
>
|
||||
{t("pages.logs.failedJobs")}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: 13,
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
{t("pages.logs.failedJobsExplainer")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<TableFailedJobs metrics={metrics} />
|
||||
<Stack alignItems={"flex-end"}>
|
||||
<Button
|
||||
|
||||
@@ -32,11 +32,10 @@ const MaintenanceWindowPage = () => {
|
||||
|
||||
return (
|
||||
<BasePageWithStates
|
||||
headerKey="maintenanceWindow"
|
||||
page={t("pages.maintenanceWindow.fallback.title")}
|
||||
totalCount={maintenanceWindowCount}
|
||||
bullets={
|
||||
t("pages.maintenanceWindow.fallback.checks", { returnObjects: true }) as string[]
|
||||
}
|
||||
description={t("pages.maintenanceWindow.fallback.description")}
|
||||
loading={isLoading}
|
||||
error={!!error}
|
||||
actionButtonText={t("pages.maintenanceWindow.fallback.actionButton")}
|
||||
|
||||
@@ -39,10 +39,9 @@ const NotificationsPage = () => {
|
||||
|
||||
return (
|
||||
<BasePageWithStates
|
||||
headerKey="notifications"
|
||||
page={t("pages.notifications.fallback.title")}
|
||||
bullets={
|
||||
t("pages.notifications.fallback.checks", { returnObjects: true }) as string[]
|
||||
}
|
||||
description={t("pages.notifications.fallback.description")}
|
||||
loading={isLoading || isValidating}
|
||||
error={!!error}
|
||||
totalCount={notifications?.length ?? 0}
|
||||
|
||||
@@ -37,11 +37,10 @@ const StatusPages = () => {
|
||||
|
||||
return (
|
||||
<BasePageWithStates
|
||||
page={t("pages.statusPages.title")}
|
||||
headerKey="statusPages"
|
||||
page={t("pages.statusPages.fallback.title")}
|
||||
loading={isLoading}
|
||||
bullets={
|
||||
t("pages.statusPages.fallback.checks", { returnObjects: true }) as string[]
|
||||
}
|
||||
description={t("pages.statusPages.fallback.description")}
|
||||
error={!!error}
|
||||
totalCount={statusPages?.length ?? 0}
|
||||
actionButtonText={t("pages.statusPages.fallback.actionButton")}
|
||||
|
||||
Reference in new issue
Block a user