From 928355b9bcc20cbabaaa4e69e1428e49943550f5 Mon Sep 17 00:00:00 2001 From: "andrew.ng" Date: Fri, 29 May 2026 09:57:53 +0700 Subject: [PATCH] update highlight list SN --- BACKEND/app/services/line_connection.ts | 52 +++++++++++++++++-------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/BACKEND/app/services/line_connection.ts b/BACKEND/app/services/line_connection.ts index 097df9c..6b027ed 100644 --- a/BACKEND/app/services/line_connection.ts +++ b/BACKEND/app/services/line_connection.ts @@ -2186,28 +2186,46 @@ Ports Missing/Down: ${missing.length}\n\n` // Helper function to highlight SNs from listInventory in outputTestLog const highlightSnInConsoleOutput = (text: string, listInventory: any[] | undefined) => { if (!text || !listInventory || listInventory.length === 0) { - return escapeHtml(text || 'No test log available') + return escapeHtml(text || 'No test log available'); } - let result = escapeHtml(text) - const snList = listInventory.map((item) => item.sn).filter((sn) => sn) + // 1. Extract, Deduplicate (Set), filter, and sort SNs + const uniqueSns = [...new Set(listInventory.map((item) => item.sn).filter(Boolean))]; + const snList = uniqueSns.sort((a, b) => b.length - a.length); - // Sort by length descending to match longest SNs first (avoid partial matches) - snList.sort((a, b) => b.length - a.length) + if (snList.length === 0) { + return escapeHtml(text); + } - snList.forEach((sn) => { - if (sn) { - // Create a regex that matches the SN as a whole word/token - const regex = new RegExp(`\\b${sn.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\$&')}\\b`, 'g') - result = result.replace( - regex, - `${escapeHtml(sn)}` - ) - } - }) + // 2. Escape regex special chars and combine into a single Regex OR statement + const escapedForRegex = snList.map((sn) => sn.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); + const combinedRegex = new RegExp(`\\b(${escapedForRegex.join('|')})\\b`, 'g'); - return result - } + let result = ''; + let lastIndex = 0; + let match; + + // 3. Single-pass execution over the raw text + while ((match = combinedRegex.exec(text)) !== null) { + const matchedSn = match[0]; + const startIndex = match.index; + + // Escape and append the text BEFORE the match + result += escapeHtml(text.substring(lastIndex, startIndex)); + + // Escape the SN and wrap it in the highlight span + const safeSn = escapeHtml(matchedSn); + result += `${safeSn}`; + + // Update the index to move forward + lastIndex = combinedRegex.lastIndex; + } + + // Append any remaining text after the final match + result += escapeHtml(text.substring(lastIndex)); + + return result; + }; // ---- Body: full template mirroring index.html, table-based + inline styles ---- const body = `