diff --git a/BACKEND/app/services/line_connection.ts b/BACKEND/app/services/line_connection.ts index 032f9d1..13b8de3 100644 --- a/BACKEND/app/services/line_connection.ts +++ b/BACKEND/app/services/line_connection.ts @@ -286,6 +286,11 @@ export default class LineConnection { if (!this.client || this.client.destroyed) { console.log('Not connected') this.isRunningScript = false + this.socketIO.emit('running_scenario', { + stationId: this.config.stationId, + lineId: this.config.id, + title: '', + }) this.outputBuffer = '' return } @@ -299,6 +304,11 @@ export default class LineConnection { ) if (script?.title === 'DPELP') this.dataDPELP = '' this.isRunningScript = true + this.socketIO.emit('running_scenario', { + stationId: this.config.stationId, + lineId: this.config.id, + title: script?.title, + }) const now = Date.now() this.outputScenario += `\n\n---start-scenarios---${now}---${userName}---${script?.title}---\n---scenario---${script?.title}---${now}---\n` appendLog( @@ -318,6 +328,11 @@ export default class LineConnection { return new Promise((resolve, reject) => { const timeoutTimer = setTimeout(() => { this.isRunningScript = false + this.socketIO.emit('running_scenario', { + stationId: this.config.stationId, + lineId: this.config.id, + title: '', + }) this.outputBuffer = '' this.outputScenario = '' this.config.output += 'Timeout run scenario' @@ -347,6 +362,11 @@ export default class LineConnection { return } else clearTimeout(timeoutTimer) this.isRunningScript = false + this.socketIO.emit('running_scenario', { + stationId: this.config.stationId, + lineId: this.config.id, + title: '', + }) this.outputBuffer = '' this.outputScenario += `\n---end-scenarios---${now}---${userName}---\n` appendLog( @@ -676,7 +696,7 @@ export default class LineConnection { (Tóm tắt trạng thái tổng thể của hệ thống trong 2–4 ý) issue: - (Tóm tắt cực ngắn gọn các lỗi/dấu hiệu bất thường, mỗi vấn đề 1 dòng) + (Tóm tắt cực ngắn gọn các lỗi/dấu hiệu bất thường, mỗi vấn đề 1 dòng, bỏ qua các vấn đề không quan trọng như về port up/down hay Invalid input, Incomplete command) Quy tắc: Không giải thích dài dòng. diff --git a/BACKEND/app/services/switch_connection.ts b/BACKEND/app/services/switch_connection.ts index a136145..7c8fde0 100644 --- a/BACKEND/app/services/switch_connection.ts +++ b/BACKEND/app/services/switch_connection.ts @@ -281,7 +281,7 @@ export default class SwitchController { public async getPorts(): Promise { this._send(' terminal length 0') - this._send('show interface status') + this._send('show interface') this._send(' ') await this.sleep(2000) const statusOutput = this.buffer @@ -289,17 +289,25 @@ export default class SwitchController { const lines = statusOutput.split('\n') const ports = this.ports?.length > 0 ? [...this.ports] : [] - for (const line of lines) { - const match = line.match(/^(\S+)\s+(connected|notconnect|disabled|inactive)/i) + // Match: "Gi0/1 is up, line protocol is up" + const match = line.match( + /^(TenGigabitEthernet|GigabitEthernet|FastEthernet|Ethernet)\S*\s+is\s+(\S+),\s+line protocol is\s+(\S+)/i + ) if (match) { - const name = match[1] - const rawStatus = match[2].toLowerCase() - const status = rawStatus === 'connected' ? 'ON' : 'OFF' + const name = match[1] + line.split(' ')[0].replace(match[1], '') + const status1 = match[2].toLowerCase() // up / down / administratively + const status2 = match[3].toLowerCase() // up / down + + // Rule: interface is considered ON only when both are "up" + const status = status1 === 'up' && status2 === 'up' ? 'ON' : 'OFF' + const port = ports.find((p) => p.name === name) if (port) { port.status = status - } else ports.push({ name, status, poe: 'UNKNOWN' }) + } else { + ports.push({ name, status, poe: 'UNKNOWN' }) + } } } diff --git a/FRONTEND/src/App.tsx b/FRONTEND/src/App.tsx index 1257b6b..44a421f 100644 --- a/FRONTEND/src/App.tsx +++ b/FRONTEND/src/App.tsx @@ -346,6 +346,16 @@ function App() { }, 100); }); + socket?.on("running_scenario", (data) => { + setTimeout(() => { + updateValueLineStation( + data?.lineId, + { runningScenario: data?.title || "" }, + data?.stationId + ); + }, 100); + }); + // ✅ cleanup on unmount or when socket changes return () => { socket.off("init"); @@ -359,6 +369,9 @@ function App() { socket.off("response_content_log"); socket.off("data_textfsm"); socket.off("update_ticket"); + socket.off("update_baud"); + socket.off("line_connecting"); + socket.off("running_scenario"); }; }, [socket, stations, selectedLine]); diff --git a/FRONTEND/src/components/CardLine.tsx b/FRONTEND/src/components/CardLine.tsx index 37d7ef9..bc6ff2a 100644 --- a/FRONTEND/src/components/CardLine.tsx +++ b/FRONTEND/src/components/CardLine.tsx @@ -284,6 +284,19 @@ const CardLine = ({ connecting... )} + {line?.runningScenario && ( + + Running {line?.runningScenario} + + )} diff --git a/FRONTEND/src/components/ModalTerminal.tsx b/FRONTEND/src/components/ModalTerminal.tsx index 16b525c..9294af3 100644 --- a/FRONTEND/src/components/ModalTerminal.tsx +++ b/FRONTEND/src/components/ModalTerminal.tsx @@ -33,6 +33,7 @@ import axios from "axios"; import { notifications } from "@mantine/notifications"; import classes from "./Component.module.css"; import { listBaudDefault } from "../untils/constanst"; +import { motion } from "motion/react"; const apiUrl = import.meta.env.VITE_BACKEND_URL; const INIT_TICKET = { @@ -427,6 +428,34 @@ const ModalTerminal = ({ > + + {line?.connecting && ( + + connecting... + + )} + {line?.runningScenario && ( + + Running {line?.runningScenario} + + )} + diff --git a/FRONTEND/src/components/TerminalXTerm.tsx b/FRONTEND/src/components/TerminalXTerm.tsx index fd2b6c8..b86353c 100644 --- a/FRONTEND/src/components/TerminalXTerm.tsx +++ b/FRONTEND/src/components/TerminalXTerm.tsx @@ -134,7 +134,10 @@ const TerminalCLI: React.FC = ({ useEffect(() => { if (cliOpened && isInit) { if (terminal.current) - setTimeout(() => terminal.current?.write(content), 200); + setTimeout(() => { + terminal.current?.write(content); + terminal.current?.scrollToBottom(); + }, 200); if (fitRef.current) setTimeout(() => fitRef.current?.fit(), 500); } diff --git a/FRONTEND/src/untils/types.ts b/FRONTEND/src/untils/types.ts index 58885b0..5cbb387 100644 --- a/FRONTEND/src/untils/types.ts +++ b/FRONTEND/src/untils/types.ts @@ -101,6 +101,7 @@ export type TLine = { baud?: number; tickets?: TDataTicket[]; connecting?: boolean; + runningScenario?: string; }; export type TUser = {