Update physical test, report

This commit is contained in:
nguyentrungthat 2026-02-05 09:14:45 +07:00
parent 4369d722ef
commit c24febf32a
4 changed files with 102 additions and 19 deletions

View File

@ -134,6 +134,9 @@ export default class LineConnection {
private outputPhysicalTest: string private outputPhysicalTest: string
private outputLoadIosLicense: string | boolean private outputLoadIosLicense: string | boolean
private listDeviceIos: string[] private listDeviceIos: string[]
private debounceTimer: NodeJS.Timeout | null = null
private testingPortPoE: boolean
private outputTestingPortPoE: string
constructor(config: LineConfig, socketIO: any, handleClearLine: () => void) { constructor(config: LineConfig, socketIO: any, handleClearLine: () => void) {
this.config = config this.config = config
@ -163,6 +166,9 @@ export default class LineConnection {
this.outputPhysicalTest = '' this.outputPhysicalTest = ''
this.outputLoadIosLicense = '' this.outputLoadIosLicense = ''
this.listDeviceIos = [] this.listDeviceIos = []
this.debounceTimer = null
this.testingPortPoE = false
this.outputTestingPortPoE = ''
} }
/** /**
* Connect to line with socket * Connect to line with socket
@ -215,6 +221,13 @@ export default class LineConnection {
} }
if (this.config.runningPhysical) { if (this.config.runningPhysical) {
this.outputPhysicalTest += message 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')) if (data.toString().includes('More') || data.toString().includes('MORE'))
this.writeCommand(' ') this.writeCommand(' ')
@ -1089,6 +1102,8 @@ export default class LineConnection {
} }
this.config.runningPhysical = true this.config.runningPhysical = true
this.config.runningScenario = 'Physical Test' this.config.runningScenario = 'Physical Test'
this.testingPortPoE = true
this.outputTestingPortPoE = ''
const listPorts = await this.getPorts() const listPorts = await this.getPorts()
this.socketIO.emit('running_scenario', { this.socketIO.emit('running_scenario', {
stationId: this.config.stationId, stationId: this.config.stationId,
@ -1111,12 +1126,12 @@ export default class LineConnection {
if (!this.config.runningPhysical || this.config.status !== 'connected') { if (!this.config.runningPhysical || this.config.status !== 'connected') {
clearInterval(interval) clearInterval(interval)
} else { } else {
this.flushLogBuffer() this.checkingPhysicalPort()
} }
}, 5000) }, 5000)
} }
async flushLogBuffer() { async checkingPhysicalPort() {
try { try {
this.writeCommand('show power inline | include on\r\n') this.writeCommand('show power inline | include on\r\n')
this.writeCommand('\r\n') this.writeCommand('\r\n')
@ -1134,6 +1149,29 @@ export default class LineConnection {
data: ports, 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) { } catch (error) {
console.log('flushLogBuffer', error) console.log('flushLogBuffer', error)
} }
@ -1147,6 +1185,8 @@ export default class LineConnection {
this.physicalTest.resetTestedPorts() this.physicalTest.resetTestedPorts()
this.config.runningPhysical = false this.config.runningPhysical = false
this.config.runningScenario = '' this.config.runningScenario = ''
this.testingPortPoE = false
this.outputTestingPortPoE = ''
this.outputBuffer = '' this.outputBuffer = ''
this.outputScenario = '' this.outputScenario = ''
this.outputPhysicalTest = '' this.outputPhysicalTest = ''

View File

@ -157,6 +157,10 @@ export class PhysicalPortTest {
generateEmailReport(report: PhysicalTestReport): string { generateEmailReport(report: PhysicalTestReport): string {
const tested = report.ports.filter((p) => p.tested) const tested = report.ports.filter((p) => p.tested)
const missing = 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' const status = missing.length === 0 ? 'PASS' : 'WARNING'
@ -177,23 +181,58 @@ export class PhysicalPortTest {
</tr> </tr>
</table> </table>
<br/> <br/>
<br/>
<b style="color: #008000;">Passed Ports</b><br/>
${
tested.length
? `<div style="margin-top: 10px; border: 1px solid #ccc; padding: 5px; column-count: 12;">${tested.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div><br/>
`
: ''
}
${ ${
missing.length missing.length
? ` ? `
<br/> <br/>
<b style="color: #ff0000;">Missing Ports</b><br/> <b style="color: #ff0000;">Missing Ports</b><br/>
<div style="margin-top: 10px; border: 1px solid #ccc; padding: 5px; column-count: 12;">${missing.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div><br/> <table cellpadding="6" cellspacing="0" border="1" style="margin-top: 10px; border-collapse: collapse; width: 100%">
<tr>
${
missingPoE?.length
? `<td>
<div style="column-count: 12;">${missingPoE.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div>
</td>`
: ''
}
${
missingSFP?.length
? `<td>
<div style="column-count: 4;">${missingSFP.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div>
</td>`
: ''
}
</tr>
</table>
` `
: '' : ''
}<br/> }
<br/>
<br/>
<b style="color: #008000;">Passed Ports</b><br/>
${
tested.length
? `<table cellpadding="6" cellspacing="0" border="1" style="margin-top: 10px; border-collapse: collapse; width: 100%">
<tr>
${
testedPoE?.length
? `<td>
<div style="column-count: 12;">${testedPoE.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div>
</td>`
: ''
}
${
testedSFP?.length
? `<td>
<div style="column-count: 4;">${testedSFP.map((p) => this.normalizePortName(p.name)).join('<br/>')}</div>
</td>`
: ''
}
</tr>
</table><br/>
`
: ''
}
<br/> <br/>
`.trim() `.trim()
} }

View File

@ -578,7 +578,9 @@ export class TestSession {
const fingerprint = `${err.ruleId}|${this.normalize(err.evidence.raw)}` const fingerprint = `${err.ruleId}|${this.normalize(err.evidence.raw)}`
const existing = this.errors.find( 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) { if (existing) {
@ -1508,7 +1510,7 @@ function keywordToRule(keyword: Keyword): KeywordRule {
category: 'SPECIAL_KEYWORD', category: 'SPECIAL_KEYWORD',
match, match,
level: 'WARN', level: 'WARN',
message: `Keyword detected: ${keyword.name}`, message: `Type: ${keyword.type}`,
} }
} }

View File

@ -947,11 +947,12 @@ const ModalTerminal = ({
<Flex direction={"column"}> <Flex direction={"column"}>
<Flex> <Flex>
<Text size="md" mr={"sm"} fw={"bold"}> <Text size="md" mr={"sm"} fw={"bold"}>
Mem: Memory:
</Text> </Text>
<Text size="md"> <Text size="md">
{findDataShowVersion() {findDataShowVersion() &&
? findDataShowVersion()?.MEMORY || "" findDataShowVersion()?.MEMORY
? findDataShowVersion()?.MEMORY + " bytes"
: ""} : ""}
</Text> </Text>
</Flex> </Flex>
@ -960,8 +961,9 @@ const ModalTerminal = ({
Flash: Flash:
</Text> </Text>
<Text size="md"> <Text size="md">
{findDataShowVersion() {findDataShowVersion() &&
? findDataShowVersion()?.USB_FLASH findDataShowVersion()?.USB_FLASH
? findDataShowVersion()?.USB_FLASH + " bytes"
: ""} : ""}
</Text> </Text>
</Flex> </Flex>