Update form summary
This commit is contained in:
parent
7ea6af3c28
commit
36a67c5b2d
|
|
@ -146,6 +146,10 @@ export default class LineConnection {
|
|||
private isPingToServer: boolean
|
||||
private outputPingToServer: string
|
||||
private outputTestLog: string
|
||||
private userTest: {
|
||||
dpelp: { name: string; time: number }
|
||||
physical: { name: string; time: number }
|
||||
}
|
||||
|
||||
constructor(config: LineConfig, socketIO: any, handleClearLine: () => void) {
|
||||
this.config = config
|
||||
|
|
@ -182,6 +186,7 @@ export default class LineConnection {
|
|||
this.isPingToServer = false
|
||||
this.outputPingToServer = ''
|
||||
this.outputTestLog = ''
|
||||
this.userTest = { dpelp: { name: '', time: 0 }, physical: { name: '', time: 0 } }
|
||||
}
|
||||
/**
|
||||
* Connect to line with socket
|
||||
|
|
@ -227,7 +232,7 @@ export default class LineConnection {
|
|||
this.waitingScenario = true
|
||||
this.outputBuffer += message
|
||||
this.outputScenario += message
|
||||
this.outputTestLog += message
|
||||
this.outputTestLog += cleanData(data.toString())
|
||||
if (!this.config.inventory)
|
||||
this.outputInventory = this.outputInventory.slice(-3000) + message
|
||||
}
|
||||
|
|
@ -442,6 +447,10 @@ export default class LineConnection {
|
|||
})
|
||||
if (script?.send_result || script?.sendResult) {
|
||||
this.dataDPELP = ''
|
||||
this.userTest = {
|
||||
...this.userTest,
|
||||
dpelp: { name: userName || '', time: Date.now() },
|
||||
}
|
||||
// this.config.inventory = ''
|
||||
}
|
||||
|
||||
|
|
@ -1178,6 +1187,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
this.config.reasonSkipPhysical = ''
|
||||
this.testingPortPoE = true
|
||||
this.outputTestingPortPoE = ''
|
||||
this.userTest = { ...this.userTest, physical: { name: userName || '', time: Date.now() } }
|
||||
const listPorts = await this.getPorts()
|
||||
this.socketIO.emit('running_scenario', {
|
||||
stationId: this.config.stationId,
|
||||
|
|
@ -1909,9 +1919,13 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
snapPhysical: PhysicalPortTest
|
||||
reason: string
|
||||
outputTestLog: string
|
||||
userTest: {
|
||||
dpelp: { name: string; time: number }
|
||||
physical: { name: string; time: number }
|
||||
}
|
||||
}) => {
|
||||
if (this.debounceSendSummaryReport) clearTimeout(this.debounceSendSummaryReport)
|
||||
|
||||
const timeZone = process.env.TIME_ZONE || 'Australia/Sydney'
|
||||
const physicalTest = snapshot?.snapPhysical ? snapshot?.snapPhysical : this.physicalTest
|
||||
const config = snapshot?.snapConfig ? snapshot?.snapConfig : this.config
|
||||
const portPhysical = Array.from(physicalTest.ports.values())
|
||||
|
|
@ -1944,7 +1958,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
const skipReason = this.config.reasonSkipPhysical || snapshot?.reason || ''
|
||||
const isSkipped = typeof skipReason === 'string' && skipReason.trim().length > 0
|
||||
|
||||
const verdictPass = missing.length === 0 && issues.length === 0 && !isSkipped
|
||||
const verdictPass = missing.length === 0 && !isSkipped
|
||||
const verdictLabel = verdictPass ? 'PASSED' : 'NEEDS REVIEW'
|
||||
const verdictMsg = verdictPass
|
||||
? 'All tests passed — Ready for deployment'
|
||||
|
|
@ -1953,10 +1967,8 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
const verdictBd = verdictPass ? '#a7f3d0' : '#fecaca'
|
||||
const verdictTx = verdictPass ? '#065f46' : '#991b1b'
|
||||
|
||||
const reportId = `RPT-${config.stationId}-L${config.lineNumber}-${Date.now().toString().slice(-6)}`
|
||||
const reportDate = momentTZ()
|
||||
.tz(process.env.TIME_ZONE || 'UTC')
|
||||
.format('DD MMM YYYY HH:mm')
|
||||
const reportId = `RPT-${momentTZ().tz(timeZone).format('YYYY-MMDD')}`
|
||||
const reportDate = momentTZ().tz(timeZone).format('DD MMM YYYY')
|
||||
|
||||
const memText = dataShowVersion?.MEMORY
|
||||
? convertFromKilobytesString(dataShowVersion.MEMORY)
|
||||
|
|
@ -1971,8 +1983,10 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
const productSN = escapeHtml(String(config?.inventory?.sn || ''))
|
||||
const productVid = escapeHtml(String(config?.inventory?.vid || ''))
|
||||
const iosVersion = escapeHtml(String(dataShowVersion?.VERSION || ''))
|
||||
const memDisplay = escapeHtml(memText !== '—' ? memText : '')
|
||||
const flashDisplay = escapeHtml(flashText !== '—' ? flashText : '')
|
||||
const macAddress = escapeHtml(String(dataShowVersion?.MAC_ADDRESS || ''))
|
||||
const memDisplay = escapeHtml(memText !== '—' ? memText : '-')
|
||||
const flashDisplay = escapeHtml(flashText !== '—' ? flashText : '-')
|
||||
const configRam = await detectConfigRamByModel(config?.inventory?.pid)
|
||||
|
||||
// AI issue rows (one per real AI issue, fall back to file's hardcoded row when none)
|
||||
const aiIssueRowsHtml =
|
||||
|
|
@ -1996,7 +2010,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
`<div style="background:#f9fafb;border:1px solid #f0f1f3;border-radius:6px;padding:8px 12px;margin-bottom:6px;"><div style="font-weight:700;color:#3b82f6;font-size:13px;">${escapeHtml(String(l.FEATURE || ''))}</div><div style="font-size:10px;color:#9ca3af;">${escapeHtml(String(l.LICENSE_TYPE || ''))}${l.STATUS ? ' · ' + escapeHtml(String(l.STATUS)) : ''}</div></div>`
|
||||
)
|
||||
.join('')
|
||||
: `<div style="background:#f9fafb;border:1px solid #f0f1f3;border-radius:6px;padding:8px 12px;margin-bottom:6px;"><div style="font-weight:700;color:#3b82f6;font-size:13px;">Network Advantage</div><div style="font-size:10px;color:#9ca3af;">Permanent · Smart License: Active</div></div><div style="background:#f9fafb;border:1px solid #f0f1f3;border-radius:6px;padding:8px 12px;"><div style="font-weight:700;color:#3b82f6;font-size:13px;">DNA Premier</div><div style="font-size:10px;color:#9ca3af;">Evaluation · 85 days remaining</div></div>`
|
||||
: ``
|
||||
|
||||
// Port stat values (real numbers if any port data, else file's defaults)
|
||||
const hasPortData = portPhysical.length > 0
|
||||
|
|
@ -2111,13 +2125,14 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
<tr><td style="padding:16px 20px;">
|
||||
<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.8px;color:#9ca3af;padding-bottom:7px;border-bottom:1px solid #f0f1f3;margin-bottom:8px;">Product Info</div>
|
||||
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;width:68px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Name</td><td style="padding:3px 0;font-weight:500;vertical-align:top;"><strong>${productName}</strong></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">P/N</td><td style="padding:3px 0;font-weight:500;vertical-align:top;">${productPN}</td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">S/N</td><td style="padding:3px 0;font-weight:500;vertical-align:top;">${productSN}</td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Type</td><td style="padding:3px 0;vertical-align:top;"><span style="display:inline-block;padding:1px 7px;border-radius:50px;font-size:11px;font-weight:600;background:#eff6ff;color:#1d4ed8;border:1px solid #bfdbfe;">Switch — Layer 3</span></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Cond.</td><td style="padding:3px 0;vertical-align:top;"><span style="display:inline-block;padding:1px 7px;border-radius:50px;font-size:11px;font-weight:600;background:#ecfdf5;color:#065f46;border:1px solid #a7f3d0;">Refurb — Grade A</span></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Supplier</td><td style="padding:3px 0;vertical-align:top;font-weight:500;">TechData AU — PO #TD-88432</td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Warranty</td><td style="padding:3px 0;vertical-align:top;font-weight:500;">12 Months (→ May 2027)</td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;width:68px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Name</td><td style="padding:3px 0;font-weight:500;vertical-align:top;font-size:14px;"><strong>${productName}</strong></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">P/N</td><td style="padding:3px 0;font-weight:500;vertical-align:top;font-size:12px;"><strong>${productPN}</strong></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">S/N</td><td style="padding:3px 0;font-weight:500;vertical-align:top;font-size:12px;"><strong>${productSN}</strong></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">MAC</td><td style="padding:3px 0;font-weight:500;vertical-align:top;font-size:12px;">${macAddress}</td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Type</td><td style="padding:3px 0;vertical-align:top;font-weight:500;font-size:12px;">-<span style="display:none;padding:1px 7px;border-radius:50px;font-size:11px;font-weight:600;background:#eff6ff;color:#1d4ed8;border:1px solid #bfdbfe;">-</span></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Cond.</td><td style="padding:3px 0;vertical-align:top;font-weight:500;font-size:12px;">-<span style="display:none;padding:1px 7px;border-radius:50px;font-size:11px;font-weight:600;background:#ecfdf5;color:#065f46;border:1px solid #a7f3d0;">-</span></td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Supplier</td><td style="padding:3px 0;vertical-align:top;font-weight:500;font-size:12px;">-</td></tr>
|
||||
<tr><td style="font-size:10px;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:.4px;padding:3px 8px 3px 0;white-space:nowrap;vertical-align:top;">Warranty</td><td style="padding:3px 0;vertical-align:top;font-weight:500;font-size:12px;">-</td></tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
|
@ -2135,32 +2150,32 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
<tr>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:600;color:#5f6978;">IOS-XE Version</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:700;font-family:Consolas,monospace;">${iosVersion}</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">17.06.01</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:600;color:#5f6978;">System RAM</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:700;font-family:Consolas,monospace;">${memDisplay}</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">8 GB</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">${configRam?.ram || '-'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:600;color:#5f6978;">Flash Storage</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:700;font-family:Consolas,monospace;">${flashDisplay}</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">16 GB</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">${configRam?.flash || '-'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:600;color:#5f6978;">Uplink Module</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:700;font-family:Consolas,monospace;">C9300-NM-4G</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-style:italic;color:#cbd5e1;font-family:Consolas,monospace;">N/A</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:700;font-family:Consolas,monospace;">-</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-style:italic;color:#cbd5e1;font-family:Consolas,monospace;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:600;color:#5f6978;">PSU Model</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:700;font-family:Consolas,monospace;">715W AC</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">715W AC</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:700;font-family:Consolas,monospace;">-</td>
|
||||
<td style="padding:6px 0;border-bottom:1px dashed #f0f1f3;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:6px 0;font-weight:600;color:#5f6978;">PoE Budget</td>
|
||||
<td style="padding:6px 0;font-weight:700;font-family:Consolas,monospace;">437 Watts</td>
|
||||
<td style="padding:6px 0;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">437 Watts</td>
|
||||
<td style="padding:6px 0;font-weight:700;font-family:Consolas,monospace;">-</td>
|
||||
<td style="padding:6px 0;font-weight:500;color:#9ca3af;font-family:Consolas,monospace;">-</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
|
|
@ -2227,7 +2242,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
<tbody style="position:relative; z-index:0;">
|
||||
<tr>
|
||||
<td colspan="3" style="padding:0 55px;">
|
||||
<div style="height:2px;background:#e2e8f0;font-size:0;line-height:0; position:absolute; z-index:-1; width: 90%; top: 12px;">
|
||||
<div style="height:2px;background:#e2e8f0;font-size:0;line-height:0; position:absolute; z-index:-1; width: 90%; top: 10px;">
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -2243,13 +2258,28 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
Received
|
||||
</div>
|
||||
<div style="font-size:11px;font-weight:600;color:#1a1d23;">
|
||||
Trung Nguyen
|
||||
Unknown
|
||||
</div>
|
||||
<div style="font-size:10px;color:#9ca3af;">
|
||||
06 May 10:30
|
||||
<div style="margin-top:4px;font-size:10px;color:#9ca3af;">
|
||||
${momentTZ().tz(timeZone).format('DD MMM')}
|
||||
</div>
|
||||
</td>
|
||||
<!-- Step 2 -->
|
||||
<td width="34%" align="center" valign="top" style="padding:0 4px 4px 4px;">
|
||||
<div style="display:inline-block;width:26px;height:26px;background:#fff;border:2px solid #10b981;border-radius:50%;color:#10b981;font-size:14px;font-weight:800;line-height:22px;text-align:center;margin-top:-14px;margin-bottom:8px;">
|
||||
✓
|
||||
</div>
|
||||
<div style="font-size:10px;font-weight:700;text-transform:uppercase;color:#5f6978;margin-bottom:2px;">
|
||||
Software Test
|
||||
</div>
|
||||
<div style="font-size:11px;font-weight:600;color:#1a1d23;">
|
||||
${snapshot?.userTest?.dpelp?.name || ''}
|
||||
</div>
|
||||
<div style="margin-top:4px;font-size:10px;color:#9ca3af;">
|
||||
${momentTZ(snapshot?.userTest?.dpelp?.time).tz(timeZone).format('DD MMM, HH:mm')}
|
||||
</div>
|
||||
</td>
|
||||
<!-- Step 3 -->
|
||||
<td width="33%" align="center" valign="top" style="padding:0 4px 4px 4px;">
|
||||
<div style="display:inline-block;width:26px;height:26px;background:#fff;border:2px solid #10b981;border-radius:50%;color:#10b981;font-size:14px;font-weight:800;line-height:22px;text-align:center;margin-top:-14px;margin-bottom:8px;">
|
||||
✓
|
||||
|
|
@ -2259,25 +2289,10 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
Physical Check
|
||||
</div>
|
||||
<div style="font-size:11px;font-weight:600;color:#1a1d23;">
|
||||
Khanh Le
|
||||
${snapshot?.userTest?.physical?.name || ''}
|
||||
</div>
|
||||
<div style="font-size:10px;color:#9ca3af;">
|
||||
06 May 11:15
|
||||
</div>
|
||||
</td>
|
||||
<!-- Step 3 -->
|
||||
<td width="34%" align="center" valign="top" style="padding:0 4px 4px 4px;">
|
||||
<div style="display:inline-block;width:26px;height:26px;background:#fff;border:2px solid #10b981;border-radius:50%;color:#10b981;font-size:14px;font-weight:800;line-height:22px;text-align:center;margin-top:-14px;margin-bottom:8px;">
|
||||
✓
|
||||
</div>
|
||||
<div style="font-size:10px;font-weight:700;text-transform:uppercase;color:#5f6978;margin-bottom:2px;">
|
||||
Software Test
|
||||
</div>
|
||||
<div style="font-size:11px;font-weight:600;color:#1a1d23;">
|
||||
Duy Pham (remote)
|
||||
</div>
|
||||
<div style="font-size:10px;color:#9ca3af;">
|
||||
06 May 14:00
|
||||
<div style="margin-top:4px;font-size:10px;color:#9ca3af;">
|
||||
${momentTZ(snapshot?.userTest?.physical?.time).tz(timeZone).format('DD MMM, HH:mm')}
|
||||
</div>
|
||||
</td>
|
||||
</tr></tbody>
|
||||
|
|
@ -2307,7 +2322,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
<svg viewBox="0 0 20 20" width="17" height="17" fill="none" style="vertical-align:middle;color:#166534;"><rect x="2" y="2" width="16" height="16" rx="3" stroke="currentColor" stroke-width="1.5"/><path d="M7 10h6M10 7v6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
<span style="vertical-align:middle;margin-left:8px;">Physical Check</span>
|
||||
</td>
|
||||
<td align="right" style="padding:7px 12px;color:#166534;font-size:11px;font-weight:500;opacity:.65;">Khanh Le · 06 May 11:15</td>
|
||||
<td align="right" style="padding:7px 12px;color:#166534;font-size:11px;font-weight:500;opacity:.65;">${snapshot?.userTest?.physical?.name || ''} · ${momentTZ(snapshot?.userTest?.physical?.time).tz(timeZone).format('DD MMM, HH:mm')}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
||||
|
|
@ -2343,7 +2358,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
<svg viewBox="0 0 20 20" width="17" height="17" fill="none" style="vertical-align:middle;color:#1e40af;"><rect x="2" y="3" width="16" height="11" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M7 17h6M10 14v3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
<span style="vertical-align:middle;margin-left:8px;">Software Check</span>
|
||||
</td>
|
||||
<td align="right" style="padding:7px 12px;color:#1e40af;font-size:11px;font-weight:500;opacity:.65;">Duy Pham (remote) · 06 May 14:00–17:45</td>
|
||||
<td align="right" style="padding:7px 12px;color:#1e40af;font-size:11px;font-weight:500;opacity:.65;">${snapshot?.userTest?.dpelp?.name || ''} · ${momentTZ(snapshot?.userTest?.dpelp?.time).tz(timeZone).format('DD MMM, HH:mm')}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table cellpadding="0" cellspacing="0" border="0" width="100%">
|
||||
|
|
@ -2373,8 +2388,8 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
<td width="50%" style="padding:0 0 6px 3px;"><table cellpadding="0" cellspacing="0" border="0" width="100%" style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;border-collapse:separate;"><tr><td align="center" style="padding:6px;"><div style="font-weight:800;font-size:14px;color:${sfpColor};">${escapeHtml(sfpText)}</div><div style="font-size:9px;font-weight:600;color:#9ca3af;text-transform:uppercase;">SFP+ UP</div></td></tr></table></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" style="padding:0 3px 0 0;"><table cellpadding="0" cellspacing="0" border="0" width="100%" style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;border-collapse:separate;"><tr><td align="center" style="padding:6px;"><div style="font-weight:800;font-size:14px;color: ${missingSFP.length > 0 || missingPoE.length > 0 ? '#dc2626' : '#10b981'};">${missingSFP.length > 0 || missingPoE.length > 0 ? 'FAIL' : 'PASS'}</div><div style="font-size:9px;font-weight:600;color:#9ca3af;text-transform:uppercase;">PoE+ Test</div></td></tr></table></td>
|
||||
<td width="50%" style="padding:0 0 0 3px;"><table cellpadding="0" cellspacing="0" border="0" width="100%" style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;border-collapse:separate;"><tr><td align="center" style="padding:6px;"><div style="font-weight:800;font-size:14px;color: ${missingSFP.length > 0 || missingPoE.length > 0 ? '#dc2626' : '#10b981'};">${totalPoE + totalSFP === 0 ? 100 : Math.round(((totalPoE + totalSFP - (missingPoE.length + missingSFP.length)) / (totalPoE + totalSFP)) * 100)}%</div><div style="font-size:9px;font-weight:600;color:#9ca3af;text-transform:uppercase;">Throughput</div></td></tr></table></td>
|
||||
<td width="50%" style="padding:0 3px 0 0;"><table cellpadding="0" cellspacing="0" border="0" width="100%" style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;border-collapse:separate;"><tr><td align="center" style="padding:6px;"><div style="font-weight:800;font-size:14px;color: ${missingSFP.length > 0 || missingPoE.length > 0 ? '#f59e0b' : '#10b981'};">${missingSFP.length > 0 || missingPoE.length > 0 ? 'WARN' : 'PASS'}</div><div style="font-size:9px;font-weight:600;color:#9ca3af;text-transform:uppercase;">PoE+ Test</div></td></tr></table></td>
|
||||
<td width="50%" style="padding:0 0 0 3px;"><table cellpadding="0" cellspacing="0" border="0" width="100%" style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:6px;border-collapse:separate;"><tr><td align="center" style="padding:6px;"><div style="font-weight:800;font-size:14px;color: ${missingSFP.length > 0 || missingPoE.length > 0 ? '#f59e0b' : '#10b981'};">${totalPoE + totalSFP === 0 ? 100 : Math.round(((totalPoE + totalSFP - (missingPoE.length + missingSFP.length)) / (totalPoE + totalSFP)) * 100)}%</div><div style="font-size:9px;font-weight:600;color:#9ca3af;text-transform:uppercase;">Throughput</div></td></tr></table></td>
|
||||
</tr>
|
||||
</table>
|
||||
${missingDetailsHtml}
|
||||
|
|
@ -2398,7 +2413,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
</body>
|
||||
</html>`
|
||||
|
||||
// this.updateNote(config?.inventory?.sn, this.dataDPELP as DataDPELP)
|
||||
this.updateNote(config?.inventory?.sn, this.dataDPELP as DataDPELP)
|
||||
await sendMessageToMail(
|
||||
`[ATC] - [${config.stationName} - Line: ${config.lineNumber}] - [${this.config.inventory?.pid}] - [${this.config.inventory?.sn}] - Summary of Testing Results`,
|
||||
body
|
||||
|
|
@ -2450,6 +2465,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
snapPhysical: this.physicalTest,
|
||||
reason: '',
|
||||
outputTestLog: this.outputTestLog,
|
||||
userTest: this.userTest,
|
||||
}
|
||||
this.debounceSendSummaryReport = setTimeout(() => {
|
||||
if (!this.config.listFeatureTested?.includes('PHYSICAL')) {
|
||||
|
|
@ -2461,6 +2477,7 @@ Ports Missing/Down: ${missing.length}\n\n`
|
|||
this.sendFeatureTested()
|
||||
this.sendReportSummaryV2(snapshot)
|
||||
this.outputTestLog = ''
|
||||
this.userTest = { dpelp: { name: '', time: 0 }, physical: { name: '', time: 0 } }
|
||||
}, timeout)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ import ConfigRam from '#models/config_ram'
|
|||
import Keyword from '#models/keywords'
|
||||
|
||||
const mailTo = 'andrew.ng@apactech.io'
|
||||
// const mailCC = [
|
||||
// 'ips@ipsupply.com.au',
|
||||
// 'kay@ipsupply.com.au',
|
||||
// 'joseph@apactech.io',
|
||||
// 'kiet.phan@apactech.io',
|
||||
// ]
|
||||
const mailCC = ''
|
||||
const mailCC = [
|
||||
'ips@ipsupply.com.au',
|
||||
'kay@ipsupply.com.au',
|
||||
'joseph@apactech.io',
|
||||
'kiet.phan@apactech.io',
|
||||
]
|
||||
// const mailCC = ''
|
||||
|
||||
type DetectAI = {
|
||||
status: string[]
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ import XRegExp from 'xregexp'
|
|||
// Parser function
|
||||
const parseLog = (data: string) => {
|
||||
const patterns = [
|
||||
XRegExp('^.*Software.*\\((?<SOFTWARE_IMAGE>\\S+)\\),\\s+Version\\s+(?<VERSION>[\\w\\.-]+)'),
|
||||
XRegExp(
|
||||
'^\\*?\\s*\\d+\\s+\\d+\\s+[\\w-]+\\s+(?<VERSION>\\d[\\w\\.-]+)\\s+(?<SOFTWARE_IMAGE>[\\w-]+)\\s+(?:BUNDLE|INSTALL)'
|
||||
'^.*Software.*\\((?<SOFTWARE_IMAGE>\\S+)\\),\\s+Version\\s+(?<VERSION>[\\w\\.\\(\\)\\-]+)'
|
||||
),
|
||||
XRegExp(
|
||||
'^\\*?\\s*\\d+\\s+\\d+\\s+[\\w-]+\\s+(?<VERSION>\\d[\\w\\.\\(\\)\\-]+)\\s+(?<SOFTWARE_IMAGE>[\\w-]+)\\s+(?:BUNDLE|INSTALL)'
|
||||
),
|
||||
XRegExp('System\\s+image\\s+file\\s+is\\s+"(?:[^:]*:)?(?<SOFTWARE_IMAGE>[^"]+)"'),
|
||||
XRegExp('Active-image:\\s+(?<SOFTWARE_IMAGE>\\S+)'),
|
||||
|
|
|
|||
|
|
@ -203,6 +203,7 @@ export class WebSocketIo {
|
|||
socket.on('run_scenario', async (data) => {
|
||||
const lineId = data.id
|
||||
const scenario = data.scenario
|
||||
const name = data.userName || userName
|
||||
// Check station is active
|
||||
const activeStation = await checkStationActive(data.stationId)
|
||||
if (!activeStation) return
|
||||
|
|
@ -211,7 +212,7 @@ export class WebSocketIo {
|
|||
io,
|
||||
data.stationId,
|
||||
[lineId],
|
||||
async (line) => line.runScript(scenario, userName),
|
||||
async (line) => line.runScript(scenario, name),
|
||||
{
|
||||
scenario,
|
||||
}
|
||||
|
|
@ -678,10 +679,10 @@ export class WebSocketIo {
|
|||
const linkWiki =
|
||||
process.env.LINK_WIKI || 'https://logs.danielvu.com/api/wiki/page/insert?title=Dev_test'
|
||||
try {
|
||||
// await axios.post(linkWiki, {
|
||||
// data: tableHTML,
|
||||
// titleAuto: `[${scenarioName || 'DPELP'}] - ${stationName} - ` + dataFormat,
|
||||
// })
|
||||
await axios.post(linkWiki, {
|
||||
data: tableHTML,
|
||||
titleAuto: `[${scenarioName || 'DPELP'}] - ${stationName} - ` + dataFormat,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error sending wiki message:', error)
|
||||
}
|
||||
|
|
@ -697,13 +698,13 @@ export class WebSocketIo {
|
|||
const contentZulip =
|
||||
`\n\n---\n**[${scenarioName || 'DPELP'}] - ${stationName} - ${dataFormat}**\n\n` +
|
||||
zulipMess
|
||||
// await sendMessageToZulip(
|
||||
// 'stream',
|
||||
// streamZulip || 'ATC_Report',
|
||||
// topicZulip,
|
||||
// contentZulip
|
||||
// )
|
||||
// await sendMessageToZulip('stream', 'ATC_Report', station.name, contentZulip)
|
||||
await sendMessageToZulip(
|
||||
'stream',
|
||||
streamZulip || 'ATC_Report',
|
||||
topicZulip,
|
||||
contentZulip
|
||||
)
|
||||
await sendMessageToZulip('stream', 'ATC_Report', station.name, contentZulip)
|
||||
} catch (error) {
|
||||
console.error('Error sending zulip message:', error)
|
||||
}
|
||||
|
|
@ -737,7 +738,7 @@ export class WebSocketIo {
|
|||
io,
|
||||
stationId,
|
||||
[lineId],
|
||||
async (lineCon) => lineCon.runPhysicalTest(name),
|
||||
async (lineCon) => lineCon.runPhysicalTest(name || userName),
|
||||
{}
|
||||
)
|
||||
})
|
||||
|
|
@ -907,7 +908,7 @@ export class WebSocketIo {
|
|||
stationId,
|
||||
[lineId],
|
||||
async (lineCon) => {
|
||||
lineCon.sendReportSummary()
|
||||
lineCon.sendReportSummaryV2()
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -223,8 +223,8 @@ const BottomToolBar = ({
|
|||
onClick={() => {
|
||||
setSelectedLines(
|
||||
selectedLines.filter(
|
||||
(line) => line.id !== el.id
|
||||
)
|
||||
(line) => line.id !== el.id,
|
||||
),
|
||||
);
|
||||
socket?.emit("close_cli", {
|
||||
lineId: el?.id,
|
||||
|
|
@ -288,7 +288,7 @@ const BottomToolBar = ({
|
|||
const lines = station.lines.filter(
|
||||
(line) =>
|
||||
!line?.userOpenCLI ||
|
||||
line?.userOpenCLI === user?.userName
|
||||
line?.userOpenCLI === user?.userName,
|
||||
);
|
||||
if (selectedLines.length !== lines.length) {
|
||||
setSelectedLines(lines);
|
||||
|
|
@ -365,7 +365,7 @@ const BottomToolBar = ({
|
|||
selectedLines={selectedLines}
|
||||
isDisable={isDisable || selectedLines.length === 0}
|
||||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP"
|
||||
(el) => el.title.toUpperCase() === "DPELP",
|
||||
)}
|
||||
onClick={() => {
|
||||
if (selectedLines.length > 0) {
|
||||
|
|
@ -380,6 +380,11 @@ const BottomToolBar = ({
|
|||
setIsDisable(false);
|
||||
}, 5000);
|
||||
}}
|
||||
userName={
|
||||
user?.firstName
|
||||
? `${user.firstName} ${user.lastName || ""}`
|
||||
: user?.userName || "Unknown User"
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
fw={400}
|
||||
|
|
@ -400,7 +405,7 @@ const BottomToolBar = ({
|
|||
onClick={() => {
|
||||
if (
|
||||
selectedLines?.filter(
|
||||
(line) => line?.runningPhysical
|
||||
(line) => line?.runningPhysical,
|
||||
)?.length > 0
|
||||
) {
|
||||
selectedLines
|
||||
|
|
@ -430,7 +435,7 @@ const BottomToolBar = ({
|
|||
}}
|
||||
>
|
||||
{selectedLines?.filter(
|
||||
(line) => line?.runningPhysical
|
||||
(line) => line?.runningPhysical,
|
||||
)?.length > 0
|
||||
? "Done/End"
|
||||
: "Physical"}
|
||||
|
|
@ -545,8 +550,8 @@ const BottomToolBar = ({
|
|||
onClick={() => {
|
||||
setSelectedLines(
|
||||
selectedLines.filter(
|
||||
(line) => line.id !== el.id
|
||||
)
|
||||
(line) => line.id !== el.id,
|
||||
),
|
||||
);
|
||||
socket?.emit("close_cli", {
|
||||
lineId: el?.id,
|
||||
|
|
@ -645,7 +650,7 @@ const BottomToolBar = ({
|
|||
const lines = station.lines.filter(
|
||||
(line) =>
|
||||
!line?.userOpenCLI ||
|
||||
line?.userOpenCLI === user?.userName
|
||||
line?.userOpenCLI === user?.userName,
|
||||
);
|
||||
if (selectedLines.length !== lines.length) {
|
||||
setSelectedLines(lines);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export const ButtonDPELP = ({
|
|||
dataDPELP,
|
||||
text = "DPELP",
|
||||
color = "#00a164",
|
||||
userName = "Unknown User",
|
||||
}: {
|
||||
socket: Socket | null;
|
||||
isDisable: boolean;
|
||||
|
|
@ -27,6 +28,7 @@ export const ButtonDPELP = ({
|
|||
dataDPELP?: IScenario;
|
||||
text?: string;
|
||||
color?: string;
|
||||
userName?: string;
|
||||
}) => {
|
||||
return (
|
||||
<Button
|
||||
|
|
@ -161,7 +163,8 @@ export const ButtonDPELP = ({
|
|||
timeout: 360000,
|
||||
body: JSON.stringify(body),
|
||||
},
|
||||
})
|
||||
userName: userName,
|
||||
}),
|
||||
);
|
||||
});
|
||||
}}
|
||||
|
|
@ -179,6 +182,7 @@ export const ButtonScenario = ({
|
|||
scenario,
|
||||
fontSize = "12px",
|
||||
station,
|
||||
userName,
|
||||
}: {
|
||||
socket: Socket | null;
|
||||
isDisable: boolean;
|
||||
|
|
@ -187,6 +191,7 @@ export const ButtonScenario = ({
|
|||
scenario: IScenario;
|
||||
fontSize?: string;
|
||||
station: TStation | undefined;
|
||||
userName?: string;
|
||||
}) => {
|
||||
return (
|
||||
<Button
|
||||
|
|
@ -206,7 +211,7 @@ export const ButtonScenario = ({
|
|||
(el) =>
|
||||
el.outlet &&
|
||||
Number(el.outlet) > 0 &&
|
||||
(el.apcName === "apc_1" || el.apc_name === "apc_1")
|
||||
(el.apcName === "apc_1" || el.apc_name === "apc_1"),
|
||||
)
|
||||
?.map((el) => el.outlet);
|
||||
const lineApc2 = selectedLines
|
||||
|
|
@ -214,7 +219,7 @@ export const ButtonScenario = ({
|
|||
(el) =>
|
||||
el.outlet &&
|
||||
Number(el.outlet) > 0 &&
|
||||
(el.apcName === "apc_2" || el.apc_name === "apc_2")
|
||||
(el.apcName === "apc_2" || el.apc_name === "apc_2"),
|
||||
)
|
||||
?.map((el) => el.outlet);
|
||||
if (lineApc1.length > 0)
|
||||
|
|
@ -250,7 +255,8 @@ export const ButtonScenario = ({
|
|||
? scenario?.isReboot
|
||||
: scenario?.is_reboot,
|
||||
},
|
||||
})
|
||||
userName: userName,
|
||||
}),
|
||||
);
|
||||
});
|
||||
}}
|
||||
|
|
@ -278,7 +284,7 @@ export const ButtonCopy = ({
|
|||
?.map((el) => {
|
||||
// Get data platform
|
||||
const dataPlatform = el.data?.find(
|
||||
(comm: TextFSM) => comm.command?.trim() === "show platform"
|
||||
(comm: TextFSM) => comm.command?.trim() === "show platform",
|
||||
);
|
||||
const DPELP =
|
||||
dataPlatform && !dataPlatform?.output?.includes("Incomplete")
|
||||
|
|
@ -289,7 +295,7 @@ export const ButtonCopy = ({
|
|||
const dataLicense = el.data?.find(
|
||||
(comm: TextFSM) =>
|
||||
comm.command?.trim() === "show license" ||
|
||||
comm.command?.trim() === "sh license"
|
||||
comm.command?.trim() === "sh license",
|
||||
);
|
||||
const listLicense =
|
||||
dataLicense?.textfsm && Array.isArray(dataLicense?.textfsm)
|
||||
|
|
@ -341,7 +347,7 @@ export const ButtonSelect = ({
|
|||
>
|
||||
{selectedLines.length !==
|
||||
station.lines.filter(
|
||||
(line) => !line?.userOpenCLI || line?.userOpenCLI === userName
|
||||
(line) => !line?.userOpenCLI || line?.userOpenCLI === userName,
|
||||
).length
|
||||
? "Select All"
|
||||
: "Deselect"}
|
||||
|
|
|
|||
|
|
@ -596,6 +596,11 @@ const CardLine = ({
|
|||
setIsDisabled(false);
|
||||
}, 5000);
|
||||
}}
|
||||
userName={
|
||||
user?.firstName
|
||||
? `${user.firstName} ${user.lastName || ""}`
|
||||
: user?.userName || "Unknown User"
|
||||
}
|
||||
/>
|
||||
<Menu
|
||||
closeOnItemClick={false}
|
||||
|
|
@ -639,6 +644,11 @@ const CardLine = ({
|
|||
}}
|
||||
scenario={el}
|
||||
fontSize="11px"
|
||||
userName={
|
||||
user?.firstName
|
||||
? `${user.firstName} ${user.lastName || ""}`
|
||||
: user?.userName || "Unknown User"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
|
|
|
|||
|
|
@ -664,6 +664,9 @@ const ModalTerminal = ({
|
|||
timeout: 360000,
|
||||
body: JSON.stringify(bodyDPELP),
|
||||
},
|
||||
userName: user?.firstName
|
||||
? `${user.firstName} ${user.lastName || ""}`
|
||||
: user?.userName || "Unknown User",
|
||||
}),
|
||||
);
|
||||
socket?.emit("run_all_dpelp", {
|
||||
|
|
@ -687,17 +690,17 @@ const ModalTerminal = ({
|
|||
setIsDisable(false);
|
||||
}, 15000);
|
||||
}
|
||||
if (activeStep >= 2 && !isDisable) {
|
||||
setActiveStep(3);
|
||||
setIsDisable(true);
|
||||
setTimeout(() => {
|
||||
setIsDisable(false);
|
||||
}, 5000);
|
||||
socket?.emit("send_summary_report", {
|
||||
lineId: line?.id,
|
||||
stationId: line?.station_id || line?.stationId,
|
||||
});
|
||||
}
|
||||
// if (activeStep >= 2 && !isDisable) {
|
||||
// setActiveStep(3);
|
||||
// setIsDisable(true);
|
||||
// setTimeout(() => {
|
||||
// setIsDisable(false);
|
||||
// }, 5000);
|
||||
// socket?.emit("send_summary_report", {
|
||||
// lineId: line?.id,
|
||||
// stationId: line?.station_id || line?.stationId,
|
||||
// });
|
||||
// }
|
||||
}}
|
||||
>
|
||||
<Stepper.Step
|
||||
|
|
@ -737,11 +740,7 @@ const ModalTerminal = ({
|
|||
<Stepper.Step
|
||||
disabled={isDisable}
|
||||
label="Completed"
|
||||
description={
|
||||
activeStep < 2
|
||||
? "Complete all to send report"
|
||||
: "Click to send report"
|
||||
}
|
||||
description={"Complete all to send report"}
|
||||
></Stepper.Step>
|
||||
</Stepper>
|
||||
<Flex></Flex>
|
||||
|
|
@ -1492,6 +1491,11 @@ const ModalTerminal = ({
|
|||
dataDPELP={scenarios?.find(
|
||||
(el) => el.title.toUpperCase() === "DPELP",
|
||||
)}
|
||||
userName={
|
||||
user?.firstName
|
||||
? `${user.firstName} ${user.lastName || ""}`
|
||||
: user?.userName || "Unknown User"
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
fw={400}
|
||||
|
|
|
|||
Loading…
Reference in New Issue