logs.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { useMemo, useState } from "react";
  2. import { useRecoilState } from "recoil";
  3. import {
  4. Box,
  5. Button,
  6. IconButton,
  7. MenuItem,
  8. Paper,
  9. Select,
  10. TextField,
  11. } from "@mui/material";
  12. import { Virtuoso } from "react-virtuoso";
  13. import { useTranslation } from "react-i18next";
  14. import {
  15. PlayCircleOutlineRounded,
  16. PauseCircleOutlineRounded,
  17. } from "@mui/icons-material";
  18. import { atomEnableLog, atomLogData } from "@/services/states";
  19. import BasePage from "@/components/base/base-page";
  20. import BaseEmpty from "@/components/base/base-empty";
  21. import LogItem from "@/components/log/log-item";
  22. const LogPage = () => {
  23. const { t } = useTranslation();
  24. const [logData, setLogData] = useRecoilState(atomLogData);
  25. const [enableLog, setEnableLog] = useRecoilState(atomEnableLog);
  26. const [logState, setLogState] = useState("all");
  27. const [filterText, setFilterText] = useState("");
  28. const filterLogs = useMemo(() => {
  29. return logData.filter((data) => {
  30. return (
  31. data.payload.includes(filterText) &&
  32. (logState === "all" ? true : data.type.includes(logState))
  33. );
  34. });
  35. }, [logData, logState, filterText]);
  36. return (
  37. <BasePage
  38. title={t("Logs")}
  39. contentStyle={{ height: "100%" }}
  40. header={
  41. <Box sx={{ mt: 1, display: "flex", alignItems: "center" }}>
  42. <IconButton
  43. size="small"
  44. color="inherit"
  45. sx={{ mr: 2 }}
  46. onClick={() => setEnableLog((e) => !e)}
  47. >
  48. {enableLog ? (
  49. <PauseCircleOutlineRounded />
  50. ) : (
  51. <PlayCircleOutlineRounded />
  52. )}
  53. </IconButton>
  54. <Button
  55. size="small"
  56. variant="contained"
  57. onClick={() => setLogData([])}
  58. >
  59. {t("Clear")}
  60. </Button>
  61. </Box>
  62. }
  63. >
  64. <Paper sx={{ boxSizing: "border-box", boxShadow: 2, height: "100%" }}>
  65. <Box
  66. sx={{
  67. pt: 1,
  68. mb: 0.5,
  69. mx: "12px",
  70. height: "36px",
  71. display: "flex",
  72. alignItems: "center",
  73. }}
  74. >
  75. <Select
  76. size="small"
  77. autoComplete="off"
  78. value={logState}
  79. onChange={(e) => setLogState(e.target.value)}
  80. sx={{ width: 120, mr: 1, '[role="button"]': { py: 0.65 } }}
  81. >
  82. <MenuItem value="all">ALL</MenuItem>
  83. <MenuItem value="info">INFO</MenuItem>
  84. <MenuItem value="warn">WARN</MenuItem>
  85. </Select>
  86. <TextField
  87. hiddenLabel
  88. fullWidth
  89. size="small"
  90. autoComplete="off"
  91. spellCheck="false"
  92. variant="outlined"
  93. placeholder={t("Filter conditions")}
  94. value={filterText}
  95. onChange={(e) => setFilterText(e.target.value)}
  96. sx={{ input: { py: 0.65, px: 1.25 } }}
  97. />
  98. </Box>
  99. <Box height="calc(100% - 50px)">
  100. {filterLogs.length > 0 ? (
  101. <Virtuoso
  102. initialTopMostItemIndex={999}
  103. data={filterLogs}
  104. itemContent={(index, item) => <LogItem value={item} />}
  105. followOutput={"smooth"}
  106. />
  107. ) : (
  108. <BaseEmpty text="No Logs" />
  109. )}
  110. </Box>
  111. </Paper>
  112. </BasePage>
  113. );
  114. };
  115. export default LogPage;