diff --git a/src/widgets/DevicesTable/DeviceLogsModal.tsx b/src/widgets/DevicesTable/DeviceLogsModal.tsx index 02610da..68f4c09 100644 --- a/src/widgets/DevicesTable/DeviceLogsModal.tsx +++ b/src/widgets/DevicesTable/DeviceLogsModal.tsx @@ -1,5 +1,5 @@ import { API_URL, authInstance, Modal } from "@shared"; -import { CircularProgress, TextField } from "@mui/material"; +import { Button, CircularProgress, TextField } from "@mui/material"; import { useEffect, useState, useMemo } from "react"; import { toast } from "react-toastify"; @@ -82,6 +82,7 @@ const parseJsonLogLine = (line: string) => { return { ts, level, msg, extraStr }; } } catch { + return null; } return null; }; @@ -180,6 +181,49 @@ export const DeviceLogsModal = ({ return parsed; }, [chunks]); + const logsText = useMemo( + () => + logs + .map((log) => { + const level = log.level === "unknown" ? "LOG" : log.level.toUpperCase(); + const time = log.time ? `[${log.time}] ` : ""; + return `${time}${level}: ${log.text}`; + }) + .join("\n"), + [logs] + ); + + const handleDownloadLogs = () => { + if (!logsText) { + toast.info("Нет логов для сохранения"); + return; + } + + try { + const safeDeviceUuid = (deviceUuid ?? "device").replace( + /[^a-zA-Z0-9_-]/g, + "_" + ); + const fileName = `logs_${safeDeviceUuid}_${dateFrom}_${dateTo}.txt`; + const blob = new Blob([`\uFEFF${logsText}`], { + type: "text/plain;charset=utf-8", + }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + + link.href = url; + link.download = fileName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + + toast.success("Логи сохранены в .txt"); + } catch { + toast.error("Не удалось сохранить логи"); + } + }; + return (
@@ -188,7 +232,7 @@ export const DeviceLogsModal = ({
setDateFrom(e.target.value)} @@ -196,12 +240,20 @@ export const DeviceLogsModal = ({ /> setDateTo(e.target.value)} slotProps={{ inputLabel: { shrink: true } }} /> +