From 17e5aad8d9cab91357e7be45041c5c9cb794f295 Mon Sep 17 00:00:00 2001 From: Truong Vo <41848815+vmtruong301296@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:59:44 +0700 Subject: [PATCH] Update input search list logs --- FRONTEND/src/components/DrawerLogs.tsx | 421 +++++++++++++------------ 1 file changed, 223 insertions(+), 198 deletions(-) diff --git a/FRONTEND/src/components/DrawerLogs.tsx b/FRONTEND/src/components/DrawerLogs.tsx index 1f64120..1ee0c1b 100644 --- a/FRONTEND/src/components/DrawerLogs.tsx +++ b/FRONTEND/src/components/DrawerLogs.tsx @@ -1,14 +1,6 @@ import { useDisclosure } from "@mantine/hooks"; -import { - Button, - Box, - Drawer, - Grid, - Table, - Text, - ScrollArea, - Tooltip, -} from "@mantine/core"; +import { Button, Box, Drawer, Grid, Table, Text, ScrollArea, Tooltip, TextInput } from "@mantine/core"; +import { DateInput } from "@mantine/dates"; import { useEffect, useState } from "react"; import type { ISystemLog } from "../untils/types"; import { IconDownload, IconEye, IconInfoCircle } from "@tabler/icons-react"; @@ -18,202 +10,235 @@ import type { Socket } from "socket.io-client"; import ModalLog from "./ModalLog"; function DrawerLogs({ - socket, - isLogModalOpen, - setIsLogModalOpen, - testLogContent, - setTestLogContent, + socket, + isLogModalOpen, + setIsLogModalOpen, + testLogContent, + setTestLogContent, }: { - socket: Socket | null; - isLogModalOpen: boolean; - setIsLogModalOpen: (value: React.SetStateAction) => void; - testLogContent: string; - setTestLogContent: (value: React.SetStateAction) => void; + socket: Socket | null; + isLogModalOpen: boolean; + setIsLogModalOpen: (value: React.SetStateAction) => void; + testLogContent: string; + setTestLogContent: (value: React.SetStateAction) => void; }) { - const [opened, { open, close }] = useDisclosure(false); - const [systemLogs, setSystemLogs] = useState([]); - const [isDownloadLog, setIsDownloadLog] = useState(false); - // const [testLogContent, setTestLogContent] = useState(""); - // const [isLogModalOpen, setIsLogModalOpen] = useState(false); - const [downloadName, setDownloadName] = useState(""); + const [opened, { open, close }] = useDisclosure(false); + const [systemLogs, setSystemLogs] = useState([]); + const [isDownloadLog, setIsDownloadLog] = useState(false); + // const [testLogContent, setTestLogContent] = useState(""); + // const [isLogModalOpen, setIsLogModalOpen] = useState(false); + const [downloadName, setDownloadName] = useState(""); + const [searchFileName, setSearchFileName] = useState(""); + const [fromDate, setFromDate] = useState(null); + const [toDate, setToDate] = useState(null); - useEffect(() => { - if (opened) { - socket?.emit("get_list_logs"); - } - }, [opened]); + const [filteredLogs, setFilteredLogs] = useState([]); - useEffect(() => { - socket?.on("list_logs", (files: string[]) => { - const list: ISystemLog[] = files.map((file) => { - const filename = file.replace(/^.*[\\/]/, ""); - const createAt = filename.match(/\d{8}/); - return { - fileName: - file.split("/")[3] || file.split("/")[2] || file.split("/")[1], - createdAt: createAt ? createAt[0] : "N/A", - path: file, - }; - }); - setSystemLogs( - list.sort( - (a: ISystemLog, b: ISystemLog) => - parseInt(b.createdAt) - parseInt(a.createdAt) - ) - ); - }); - }, [socket]); + useEffect(() => { + if (opened) { + socket?.emit("get_list_logs"); + } + }, [opened]); - useEffect(() => { - if (isDownloadLog && testLogContent && downloadName) { - const blob = new Blob([testLogContent], { type: "text/plain" }); - // Create a temporary link element - const link = document.createElement("a"); - link.href = URL.createObjectURL(blob); - link.download = downloadName; - // Trigger the download by clicking the link - link.click(); - // Clean up - URL.revokeObjectURL(link.href); - setIsDownloadLog(false); - setTestLogContent(""); - setDownloadName(""); - } - }, [testLogContent]); + useEffect(() => { + socket?.on("list_logs", (files: string[]) => { + const list: ISystemLog[] = files.map((file) => { + const filename = file.replace(/^.*[\\/]/, ""); + const createAt = filename.match(/\d{8}/); + return { + fileName: file.split("/")[3] || file.split("/")[2] || file.split("/")[1], + createdAt: createAt ? createAt[0] : "N/A", + path: file, + }; + }); + setSystemLogs(list.sort((a: ISystemLog, b: ISystemLog) => parseInt(b.createdAt) - parseInt(a.createdAt))); + }); + }, [socket]); - return ( - <> - - - Format: - - YYYYMMDD-AUTO-Session.{`{Station name}`}-{`{Station ID}`}- - {`{Station IP}`}-{`{Line number}`} - .log - - - } - position="right" - > - - List Logs - - - - } - > - - - - - - - File name - Created at - - - - - {systemLogs.map((element) => ( - - {element.fileName} - - - {moment(element.createdAt).format("DD/MM/YYYY")} - - - - - { - setTestLogContent(""); - socket?.emit("get_content_log", { - line: { systemLogUrl: element.path }, - }); - setIsLogModalOpen(true); - }} - width={20} - /> - { - socket?.emit("get_content_log", { - line: { systemLogUrl: element.path }, - }); - setIsDownloadLog(true); - setTestLogContent(""); - setDownloadName( - element.path.split("/")[3] || - element.path.split("/")[2] || - element.path.split("/")[1] - ); - }} - width={20} - /> - - - - ))} - -
-
-
-
+ useEffect(() => { + if (isDownloadLog && testLogContent && downloadName) { + const blob = new Blob([testLogContent], { type: "text/plain" }); + // Create a temporary link element + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = downloadName; + // Trigger the download by clicking the link + link.click(); + // Clean up + URL.revokeObjectURL(link.href); + setIsDownloadLog(false); + setTestLogContent(""); + setDownloadName(""); + } + }, [testLogContent]); - {isLogModalOpen && ( - { - setIsLogModalOpen(false); - }} - testLogContent={testLogContent} - /> - )} -
+ useEffect(() => { + // Chuẩn bị trước các giá trị search/date để tránh tính lại trong filter cho từng phần tử + const trimmedSearch = searchFileName.trim().toLowerCase(); + const hasSearch = trimmedSearch.length > 0; + const fromMoment = fromDate ? moment(fromDate, "DD/MM/YYYY").startOf("day") : null; + const toMoment = toDate ? moment(toDate, "DD/MM/YYYY").endOf("day") : null; - - - ); + const delayDebounceFn = setTimeout(() => { + // Nếu không có filter nào, tránh filter tốn công, gán thẳng + if (!hasSearch && !fromMoment && !toMoment) { + setFilteredLogs(systemLogs); + return; + } + + const next = systemLogs.filter((log) => { + if (hasSearch && !log.fileName.toLowerCase().includes(trimmedSearch)) { + return false; + } + + const logDate = moment(log.createdAt, "YYYYMMDD"); + if (fromMoment && !logDate.isSameOrAfter(fromMoment)) { + return false; + } + if (toMoment && !logDate.isSameOrBefore(toMoment)) { + return false; + } + + return true; + }); + + setFilteredLogs(next); + }, 500); + + return () => clearTimeout(delayDebounceFn); + }, [searchFileName, fromDate, toDate, systemLogs]); + + return ( + <> + + + Format: + + YYYYMMDD-AUTO-Session.{`{Station name}`}-{`{Station ID}`}-{`{Station IP}`}-{`{Line number}`} + .log + + + } + position="right"> + + List Logs + + + + }> + + + + + + setSearchFileName(event.currentTarget.value)} + size="xs" + /> + + + + + + + + + + + + + + File name + Created at + + + + + {filteredLogs.map((element) => ( + + {element.fileName} + + {moment(element.createdAt).format("DD/MM/YYYY")} + + + + { + setTestLogContent(""); + socket?.emit("get_content_log", { + line: { systemLogUrl: element.path }, + }); + setIsLogModalOpen(true); + }} + width={20} + /> + { + socket?.emit("get_content_log", { + line: { systemLogUrl: element.path }, + }); + setIsDownloadLog(true); + setTestLogContent(""); + setDownloadName(element.path.split("/")[3] || element.path.split("/")[2] || element.path.split("/")[1]); + }} + width={20} + /> + + + + ))} + +
+
+
+
+ + {isLogModalOpen && ( + { + setIsLogModalOpen(false); + }} + testLogContent={testLogContent} + /> + )} +
+ + + + ); } export default DrawerLogs;