- 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.
75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import Stack from "@mui/material/Stack";
|
|
import MenuItem from "@mui/material/MenuItem";
|
|
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";
|
|
import { useState } from "react";
|
|
import type { Log, LogLevelOption } from "@/Types/Log";
|
|
import { LOG_LEVEL_OPTIONS } from "@/Types/Log";
|
|
import { t } from "i18next";
|
|
import type { RootState } from "@/Types/state";
|
|
|
|
export const TabLogs = () => {
|
|
const theme = useTheme();
|
|
const { data: logs, isLoading } = useGet<Log[]>("/logs");
|
|
const [selectedLogLevel, setSelectedLogLevel] = useState<LogLevelOption>("all");
|
|
const [page, setPage] = useState(0);
|
|
const rowsPerPage = useSelector(
|
|
(state: RootState) => state?.ui?.logs?.rowsPerPage ?? 15
|
|
);
|
|
|
|
const filteredLogs = logs
|
|
?.filter((log) => {
|
|
if (selectedLogLevel === "all") return true;
|
|
return log.level === selectedLogLevel;
|
|
})
|
|
.reverse()
|
|
.map((log, idx) => ({ ...log, id: idx }));
|
|
|
|
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
|
|
sx={{ maxWidth: 200 }}
|
|
fieldLabel={t("pages.logs.logLevelSelect.label")}
|
|
value={selectedLogLevel}
|
|
onChange={(e) => setSelectedLogLevel(e.target.value)}
|
|
>
|
|
{LOG_LEVEL_OPTIONS.map((level) => {
|
|
return (
|
|
<MenuItem
|
|
key={level}
|
|
value={level}
|
|
>
|
|
<Typography textTransform={"capitalize"}>{level}</Typography>
|
|
</MenuItem>
|
|
);
|
|
})}
|
|
</Select>
|
|
<TableLogs
|
|
logs={paginatedLogs}
|
|
logCount={filteredLogs?.length ?? 0}
|
|
page={page}
|
|
setPage={setPage}
|
|
/>
|
|
</Stack>
|
|
);
|
|
};
|