logs.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. sx={{ mr: 2 }}
  45. onClick={() => setEnableLog((e) => !e)}
  46. >
  47. {enableLog ? (
  48. <PauseCircleOutlineRounded />
  49. ) : (
  50. <PlayCircleOutlineRounded />
  51. )}
  52. </IconButton>
  53. <Button
  54. size="small"
  55. variant="contained"
  56. onClick={() => setLogData([])}
  57. >
  58. {t("Clear")}
  59. </Button>
  60. </Box>
  61. }
  62. >
  63. <Paper sx={{ boxSizing: "border-box", boxShadow: 2, height: "100%" }}>
  64. <Box
  65. sx={{
  66. pt: 1,
  67. mb: 0.5,
  68. mx: "12px",
  69. height: "36px",
  70. display: "flex",
  71. alignItems: "center",
  72. }}
  73. >
  74. <Select
  75. size="small"
  76. autoComplete="off"
  77. value={logState}
  78. onChange={(e) => setLogState(e.target.value)}
  79. sx={{ width: 120, mr: 1, '[role="button"]': { py: 0.65 } }}
  80. >
  81. <MenuItem value="all">ALL</MenuItem>
  82. <MenuItem value="info">INFO</MenuItem>
  83. <MenuItem value="warn">WARN</MenuItem>
  84. </Select>
  85. <TextField
  86. hiddenLabel
  87. fullWidth
  88. size="small"
  89. autoComplete="off"
  90. variant="outlined"
  91. placeholder={t("Filter conditions")}
  92. value={filterText}
  93. onChange={(e) => setFilterText(e.target.value)}
  94. sx={{ input: { py: 0.65, px: 1.25 } }}
  95. />
  96. </Box>
  97. <Box height="calc(100% - 50px)">
  98. {filterLogs.length > 0 ? (
  99. <Virtuoso
  100. initialTopMostItemIndex={999}
  101. data={filterLogs}
  102. itemContent={(index, item) => <LogItem value={item} />}
  103. followOutput={"smooth"}
  104. />
  105. ) : (
  106. <BaseEmpty text="No Logs" />
  107. )}
  108. </Box>
  109. </Paper>
  110. </BasePage>
  111. );
  112. };
  113. export default LogPage;