Files
Checkmate/client/src/Pages/Logs/TabLogs.tsx
T
gorkem-bwl 031a6fdf3c 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.
2026-04-25 23:26:34 -04:00

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>
);
};