logs.tsx 3.4 KB

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