diff --git a/BACKEND/app/services/line_connection.ts b/BACKEND/app/services/line_connection.ts index 5674302..48fb527 100644 --- a/BACKEND/app/services/line_connection.ts +++ b/BACKEND/app/services/line_connection.ts @@ -134,6 +134,9 @@ export default class LineConnection { private outputPhysicalTest: string private outputLoadIosLicense: string | boolean private listDeviceIos: string[] + private debounceTimer: NodeJS.Timeout | null = null + private testingPortPoE: boolean + private outputTestingPortPoE: string constructor(config: LineConfig, socketIO: any, handleClearLine: () => void) { this.config = config @@ -163,6 +166,9 @@ export default class LineConnection { this.outputPhysicalTest = '' this.outputLoadIosLicense = '' this.listDeviceIos = [] + this.debounceTimer = null + this.testingPortPoE = false + this.outputTestingPortPoE = '' } /** * Connect to line with socket @@ -215,6 +221,13 @@ export default class LineConnection { } if (this.config.runningPhysical) { this.outputPhysicalTest += message + this.outputTestingPortPoE += message + if (this.debounceTimer) clearTimeout(this.debounceTimer) + + if (this.testingPortPoE) + this.debounceTimer = setTimeout(() => { + this.flushLogBuffer() + }, 1000) // 1s debounce } if (data.toString().includes('More') || data.toString().includes('MORE')) this.writeCommand(' ') @@ -1089,6 +1102,8 @@ export default class LineConnection { } this.config.runningPhysical = true this.config.runningScenario = 'Physical Test' + this.testingPortPoE = true + this.outputTestingPortPoE = '' const listPorts = await this.getPorts() this.socketIO.emit('running_scenario', { stationId: this.config.stationId, @@ -1111,12 +1126,12 @@ export default class LineConnection { if (!this.config.runningPhysical || this.config.status !== 'connected') { clearInterval(interval) } else { - this.flushLogBuffer() + this.checkingPhysicalPort() } }, 5000) } - async flushLogBuffer() { + async checkingPhysicalPort() { try { this.writeCommand('show power inline | include on\r\n') this.writeCommand('\r\n') @@ -1134,6 +1149,29 @@ export default class LineConnection { data: ports, }) } + } catch (error) { + console.log('checkingPhysicalPort', error) + } + } + + async flushLogBuffer() { + try { + const lines = this.outputTestingPortPoE.split(/\r?\n/) + + // giữ lại dòng cuối nếu chưa kết thúc hoàn chỉnh + this.outputTestingPortPoE = lines.pop() || '' + + const completeLines = lines.join('\n') + + if (completeLines.trim()) { + const ports = this.physicalTest.handleLog(completeLines) + if (ports?.length) + this.socketIO.emit('test_port_physical', { + stationId: this.config.stationId, + lineId: this.config.id, + data: ports, + }) + } } catch (error) { console.log('flushLogBuffer', error) } @@ -1147,6 +1185,8 @@ export default class LineConnection { this.physicalTest.resetTestedPorts() this.config.runningPhysical = false this.config.runningScenario = '' + this.testingPortPoE = false + this.outputTestingPortPoE = '' this.outputBuffer = '' this.outputScenario = '' this.outputPhysicalTest = '' diff --git a/BACKEND/app/services/physical_test_service.ts b/BACKEND/app/services/physical_test_service.ts index c609d54..ac351d0 100644 --- a/BACKEND/app/services/physical_test_service.ts +++ b/BACKEND/app/services/physical_test_service.ts @@ -157,6 +157,10 @@ export class PhysicalPortTest { generateEmailReport(report: PhysicalTestReport): string { const tested = report.ports.filter((p) => p.tested) const missing = report.ports.filter((p) => !p.tested) + const testedPoE = tested.filter((p) => !p.name.includes('SFP')) + const testedSFP = tested.filter((p) => p.name.includes('SFP')) + const missingPoE = missing.filter((p) => !p.name.includes('SFP')) + const missingSFP = missing.filter((p) => p.name.includes('SFP')) const status = missing.length === 0 ? 'PASS' : 'WARNING' @@ -177,23 +181,58 @@ export class PhysicalPortTest {
- ────────────────────────────────
- Passed Ports
- ${ - tested.length - ? `
${tested.map((p) => this.normalizePortName(p.name)).join('
')}

- ` - : '' - } ${ missing.length ? ` ────────────────────────────────
Missing Ports
-
${missing.map((p) => this.normalizePortName(p.name)).join('
')}

+ + + ${ + missingPoE?.length + ? `` + : '' + } + ${ + missingSFP?.length + ? `` + : '' + } + +
+
${missingPoE.map((p) => this.normalizePortName(p.name)).join('
')}
+
+
${missingSFP.map((p) => this.normalizePortName(p.name)).join('
')}
+
` : '' - }
+ } +
+ ────────────────────────────────
+ Passed Ports
+ ${ + tested.length + ? ` + + ${ + testedPoE?.length + ? `` + : '' + } + ${ + testedSFP?.length + ? `` + : '' + } + +
+
${testedPoE.map((p) => this.normalizePortName(p.name)).join('
')}
+
+
${testedSFP.map((p) => this.normalizePortName(p.name)).join('
')}
+

+ ` + : '' + }
`.trim() } diff --git a/BACKEND/app/ultils/helper.ts b/BACKEND/app/ultils/helper.ts index 6d27c65..a8e3dc7 100644 --- a/BACKEND/app/ultils/helper.ts +++ b/BACKEND/app/ultils/helper.ts @@ -578,7 +578,9 @@ export class TestSession { const fingerprint = `${err.ruleId}|${this.normalize(err.evidence.raw)}` const existing = this.errors.find( - (e) => `${e.ruleId}|${this.normalize(e.evidence.raw)}` === fingerprint + (e) => + `${e.ruleId}|${this.normalize(e.evidence.raw)}` === fingerprint || + (err.ruleId === e.ruleId && err.category === 'SPECIAL_KEYWORD') ) if (existing) { @@ -1508,7 +1510,7 @@ function keywordToRule(keyword: Keyword): KeywordRule { category: 'SPECIAL_KEYWORD', match, level: 'WARN', - message: `Keyword detected: ${keyword.name}`, + message: `Type: ${keyword.type}`, } } diff --git a/FRONTEND/src/components/Modal/ModalTerminal.tsx b/FRONTEND/src/components/Modal/ModalTerminal.tsx index cd2a75f..4c80252 100644 --- a/FRONTEND/src/components/Modal/ModalTerminal.tsx +++ b/FRONTEND/src/components/Modal/ModalTerminal.tsx @@ -947,11 +947,12 @@ const ModalTerminal = ({ - Mem: + Memory: - {findDataShowVersion() - ? findDataShowVersion()?.MEMORY || "" + {findDataShowVersion() && + findDataShowVersion()?.MEMORY + ? findDataShowVersion()?.MEMORY + " bytes" : ""} @@ -960,8 +961,9 @@ const ModalTerminal = ({ Flash: - {findDataShowVersion() - ? findDataShowVersion()?.USB_FLASH + {findDataShowVersion() && + findDataShowVersion()?.USB_FLASH + ? findDataShowVersion()?.USB_FLASH + " bytes" : ""}