Update short log, print log
This commit is contained in:
parent
d4ea801bef
commit
e9c99814b2
|
|
@ -2183,7 +2183,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
const regex = new RegExp(`\\b${sn.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\$&')}\\b`, 'g')
|
||||
result = result.replace(
|
||||
regex,
|
||||
`<span id="${escapeHtml(sn)}" style="background-color:#fbbf24;color:#78350f;font-weight:600;padding:2px 6px;border-radius:3px;cursor:pointer;" title="Click Hardware Inventory link to scroll">${escapeHtml(sn)}</span>`
|
||||
`<span id="${sn}" style="background-color:#fbbf24;color:#78350f;font-weight:600;padding:2px 6px;border-radius:3px;cursor:pointer;" title="Click Hardware Inventory link to scroll">${escapeHtml(sn)}</span>`
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ const ModalLineHistory = ({
|
|||
setOpenLog(false);
|
||||
}}
|
||||
testLogContent={selectedHistory?.output || ""}
|
||||
isShowShortLog={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,29 @@
|
|||
import { Modal, Text } from "@mantine/core";
|
||||
import { Button, Flex, Modal, Text } from "@mantine/core";
|
||||
import classes from "../Component.module.css";
|
||||
import { convertTimestampToDate } from "../../untils/helper";
|
||||
import {
|
||||
convertTimestampToDate,
|
||||
createShortLog,
|
||||
printLogWeb,
|
||||
} from "../../untils/helper";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const ModalLog = ({
|
||||
opened,
|
||||
onClose,
|
||||
testLogContent,
|
||||
isShowShortLog = false,
|
||||
}: {
|
||||
opened: boolean;
|
||||
onClose: () => void;
|
||||
testLogContent: string;
|
||||
isShowShortLog?: boolean;
|
||||
}) => {
|
||||
const [valueLog, setValueLog] = useState(testLogContent);
|
||||
const [isShort, setIsShort] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setValueLog(testLogContent);
|
||||
}, [testLogContent]);
|
||||
const addTooltipsToHighlights = () => {
|
||||
const highlights = document.querySelectorAll(".highlight");
|
||||
highlights.forEach((highlight) => {
|
||||
|
|
@ -60,7 +73,7 @@ const ModalLog = ({
|
|||
size="90%"
|
||||
styles={{
|
||||
content: {
|
||||
height: "85vh",
|
||||
height: isShowShortLog ? "90vh" : "85vh",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
},
|
||||
|
|
@ -72,13 +85,50 @@ const ModalLog = ({
|
|||
>
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: highlightSystemLog(testLogContent),
|
||||
__html: highlightSystemLog(valueLog),
|
||||
}}
|
||||
className={`${classes.viewLog} ${classes.logLight}`}
|
||||
ref={(el) => {
|
||||
if (el) addTooltipsToHighlights();
|
||||
}}
|
||||
></div>
|
||||
|
||||
{isShowShortLog ? (
|
||||
<Flex justify="flex-end" mt="md" gap={"md"}>
|
||||
{!isShort ? (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
setValueLog(createShortLog(testLogContent));
|
||||
setIsShort(true);
|
||||
}}
|
||||
color="green"
|
||||
>
|
||||
Short
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
setValueLog(testLogContent);
|
||||
setIsShort(false);
|
||||
}}
|
||||
color="green"
|
||||
>
|
||||
Original
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => printLogWeb(valueLog)}
|
||||
color="blue"
|
||||
>
|
||||
Print
|
||||
</Button>
|
||||
</Flex>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -543,6 +543,7 @@ const ModalTerminal = ({
|
|||
<Modal
|
||||
zIndex={95}
|
||||
opened={opened}
|
||||
closeOnEscape={false}
|
||||
onClose={() => {
|
||||
if (openDrawerScenario) {
|
||||
setOpenDrawerScenario(false);
|
||||
|
|
@ -642,7 +643,7 @@ const ModalTerminal = ({
|
|||
</Flex>
|
||||
</Flex>
|
||||
<Stepper
|
||||
w={600}
|
||||
w={"35vw"}
|
||||
size="xs"
|
||||
color={isDisable ? "gray" : "cyan"}
|
||||
active={activeStep}
|
||||
|
|
@ -743,7 +744,20 @@ const ModalTerminal = ({
|
|||
description={"Complete all to send report"}
|
||||
></Stepper.Step>
|
||||
</Stepper>
|
||||
<Flex></Flex>
|
||||
<Flex justify={"flex-end"} w={"15vw"}>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
variant="outline"
|
||||
color="cyan"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
setOpenLineHistory(true);
|
||||
}}
|
||||
>
|
||||
View History
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
}
|
||||
>
|
||||
|
|
@ -1570,18 +1584,6 @@ const ModalTerminal = ({
|
|||
>
|
||||
Send Break
|
||||
</Button>
|
||||
<Button
|
||||
fw={400}
|
||||
disabled={isDisable}
|
||||
variant="outline"
|
||||
color="cyan"
|
||||
size="xs"
|
||||
onClick={() => {
|
||||
setOpenLineHistory(true);
|
||||
}}
|
||||
>
|
||||
View History
|
||||
</Button>
|
||||
<Menu trigger="hover" withArrow shadow="md" position="top">
|
||||
<Menu.Target>
|
||||
<Button
|
||||
|
|
|
|||
|
|
@ -113,11 +113,11 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
|||
// Handle Ctrl+V (Paste)
|
||||
if (e.ctrlKey && e.key.toLowerCase() === "v") return false;
|
||||
// Handle Esc
|
||||
if (e.key === "Escape") return false;
|
||||
// if (e.key === "Escape") return false;
|
||||
// Handle Enter
|
||||
// if (e.key === "ArrowUp") handleArrowUp();
|
||||
return true; // allow all other keys through
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const handleContextMenu = async (e: MouseEvent) => {
|
||||
|
|
@ -147,11 +147,11 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
|||
"[CLEAR_TERMINAL_SCROLL_BACK]",
|
||||
Array(miniSize ? 20 : 70)
|
||||
.fill("\r\n")
|
||||
.join("")
|
||||
.join(""),
|
||||
)
|
||||
.replaceAll(
|
||||
"[CONNECT_TO_SERVER_TFTP_FAIL]",
|
||||
"\x1b[41;37m CONNECT TO SERVER TFTP FAIL \x1b[0m\n"
|
||||
"\x1b[41;37m CONNECT TO SERVER TFTP FAIL \x1b[0m\n",
|
||||
);
|
||||
terminal.current?.write(valueContent);
|
||||
terminal.current?.scrollToBottom();
|
||||
|
|
@ -182,11 +182,11 @@ const TerminalCLI: React.FC<TerminalCLIProps> = ({
|
|||
"[CLEAR_TERMINAL_SCROLL_BACK]",
|
||||
Array(miniSize ? 20 : 70)
|
||||
.fill("\r\n")
|
||||
.join("")
|
||||
.join(""),
|
||||
)
|
||||
.replaceAll(
|
||||
"[CONNECT_TO_SERVER_TFTP_FAIL]",
|
||||
"\x1b[41;37m CONNECT TO SERVER TFTP FAIL \x1b[0m\n"
|
||||
"\x1b[41;37m CONNECT TO SERVER TFTP FAIL \x1b[0m\n",
|
||||
);
|
||||
terminal.current?.write(valueContent);
|
||||
setIsInit(true);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export const convertTimestampToDate = (timestamp: number) => {
|
|||
*/
|
||||
export const useDebounce = <T extends (...args: any[]) => void>(
|
||||
callback: T,
|
||||
delay: number
|
||||
delay: number,
|
||||
) => {
|
||||
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ export const useDebounce = <T extends (...args: any[]) => void>(
|
|||
callback(...args);
|
||||
}, delay);
|
||||
},
|
||||
[callback, delay]
|
||||
[callback, delay],
|
||||
);
|
||||
|
||||
return debouncedFn;
|
||||
|
|
@ -199,7 +199,7 @@ export const bodyDPELP = [
|
|||
|
||||
export function convertFromKilobytesString(
|
||||
input: string,
|
||||
decimals = 0
|
||||
decimals = 0,
|
||||
): string {
|
||||
if (!input) return "0 KB";
|
||||
|
||||
|
|
@ -242,3 +242,92 @@ export function convertFromKilobytesString(
|
|||
|
||||
return `${displayValue.toFixed(decimals)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hàm tách và rút gọn log Cisco (show inv, show version, show license)
|
||||
* @param {string} rawLog - Chuỗi log thô ban đầu (chứa toàn bộ kết quả terminal)
|
||||
* @returns {string} Chuỗi log đã được rút gọn theo định dạng yêu cầu
|
||||
*/
|
||||
export function createShortLog(rawLog: string): string {
|
||||
const shortLog = [];
|
||||
|
||||
// 1. Tách show inventory
|
||||
const invRegex =
|
||||
/(NAME:\s*"[^"]*",\s*DESCR:\s*"[^"]*"\r?\nPID:\s*[^,]+,\s*VID:\s*[^,]+,\s*SN:\s*\S+)/i;
|
||||
const invMatch = rawLog.match(invRegex);
|
||||
if (invMatch) {
|
||||
shortLog.push(invMatch[1].trim());
|
||||
}
|
||||
|
||||
// 2. Tách show version (Đã fix vụ bỏ phần thừa ở giữa)
|
||||
const verRegex =
|
||||
/(System image file is[^\r\n]+)[\s\S]*?(cisco\s+[a-zA-Z0-9\-]+\s+\([^)]+\)\s+processor[\s\S]*?Configuration register is 0x[0-9a-fA-F]+)/i;
|
||||
const verMatch = rawLog.match(verRegex);
|
||||
if (verMatch) {
|
||||
shortLog.push(`${verMatch[1].trim()}\n${verMatch[2].trim()}`);
|
||||
}
|
||||
|
||||
// 3. Tách show license
|
||||
const licRegex =
|
||||
/(Index\s+1\s+Feature:[\s\S]*?)(?=\r?\n[a-zA-Z0-9\-\_]+[#>]|$)/i;
|
||||
const licMatch = rawLog.match(licRegex);
|
||||
if (licMatch) {
|
||||
shortLog.push("\n" + licMatch[1].trim());
|
||||
}
|
||||
|
||||
return shortLog.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Hàm in log ra máy in vật lý trong môi trường Web (React/Vue/Vanilla)
|
||||
* @param shortLog - Chuỗi log đã được rút gọn
|
||||
*/
|
||||
export function printLogWeb(shortLog: string): void {
|
||||
if (!shortLog.trim()) {
|
||||
console.warn("Không có dữ liệu để in.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Mở một cửa sổ ẩn để in
|
||||
const printWindow = window.open("", "_blank", "width=800,height=600");
|
||||
if (!printWindow) {
|
||||
console.error("Trình duyệt đã chặn popup. Vui lòng cho phép popup để in.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ghi nội dung HTML với font monospace (giống terminal)
|
||||
printWindow.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Cisco Short Log</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 12px;
|
||||
padding: 20px;
|
||||
color: #000;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap; /* Tự động xuống dòng nếu quá dài */
|
||||
word-wrap: break-word;
|
||||
}
|
||||
@media print {
|
||||
@page { margin: 1cm; }
|
||||
body { padding: 0; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre>${shortLog}</pre>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
printWindow.document.close();
|
||||
printWindow.focus();
|
||||
|
||||
// Gọi lệnh in và đóng cửa sổ sau khi in xong (hoặc hủy)
|
||||
printWindow.print();
|
||||
printWindow.onafterprint = () => printWindow.close();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue