fix: Finder 404 shows helpful message + fuzzy switch name matching
- api() helper now parses JSON body on non-2xx responses so error.suggestion is available in catch blocks - runFinder() catch shows 'Switch not found' + suggestion instead of 'Error: HTTP 404' - finder.ts: normalized search (removes hyphens/spaces) + token-based fallback so 'sg350-28' → 'SG350-28', 'N9K-C93180' → Nexus 93180, etc.
This commit is contained in:
parent
dad4750a86
commit
4b1734379a
@ -23,7 +23,11 @@ finderRouter.get("/", async (req, res) => {
|
||||
return res.status(400).json({ error: "Parameter 'switch' is required" });
|
||||
}
|
||||
|
||||
// Step 1: Find the switch
|
||||
// Step 1: Find the switch — try multiple search strategies
|
||||
const q = String(switchQuery);
|
||||
// Normalized form: remove hyphens/spaces for fuzzy match (sg350-28 → sg35028)
|
||||
const qNorm = q.replace(/[\s\-_]/g, "");
|
||||
|
||||
const switchResult = await pool.query(
|
||||
`SELECT sw.id, sw.model, sw.series, sw.ports_config, sw.max_speed_gbps,
|
||||
v.name AS vendor_name, sw.image_url, sw.datasheet_r2_key
|
||||
@ -31,21 +35,39 @@ finderRouter.get("/", async (req, res) => {
|
||||
JOIN vendors v ON sw.vendor_id = v.id
|
||||
WHERE sw.model ILIKE $1
|
||||
OR sw.model ILIKE '%' || $1 || '%'
|
||||
OR sw.search_vector @@ plainto_tsquery('english', $1)
|
||||
OR REPLACE(REPLACE(sw.model, '-', ''), ' ', '') ILIKE '%' || $2 || '%'
|
||||
OR sw.search_vector @@ plainto_tsquery('english', $3)
|
||||
ORDER BY
|
||||
CASE WHEN sw.model ILIKE $1 THEN 0
|
||||
WHEN sw.model ILIKE $1 || '%' THEN 1
|
||||
ELSE 2 END
|
||||
WHEN REPLACE(REPLACE(sw.model, '-', ''), ' ', '') ILIKE $2 || '%' THEN 2
|
||||
ELSE 3 END
|
||||
LIMIT 5`,
|
||||
[switchQuery]
|
||||
[q, qNorm, q.replace(/[^\w\s]/g, " ")]
|
||||
);
|
||||
|
||||
if (switchResult.rows.length === 0) {
|
||||
// Try one more time with individual tokens
|
||||
const tokens = q.split(/[\s\-_]+/).filter((t) => t.length >= 3);
|
||||
let fallbackResult = { rows: [] as any[] };
|
||||
if (tokens.length > 0) {
|
||||
fallbackResult = await pool.query(
|
||||
`SELECT sw.id, sw.model, sw.series, sw.ports_config, sw.max_speed_gbps,
|
||||
v.name AS vendor_name, sw.image_url, sw.datasheet_r2_key
|
||||
FROM switches sw JOIN vendors v ON sw.vendor_id = v.id
|
||||
WHERE ${tokens.map((_, i) => `sw.model ILIKE '%' || $${i + 1} || '%'`).join(" AND ")}
|
||||
LIMIT 5`,
|
||||
tokens
|
||||
);
|
||||
}
|
||||
if (fallbackResult.rows.length === 0) {
|
||||
return res.status(404).json({
|
||||
error: "Switch not found",
|
||||
suggestion: "Try a partial model name like 'N9K-C93180' or 'QFX5120'"
|
||||
error: `Switch "${q}" not found in the database`,
|
||||
suggestion: `Try a partial model name, e.g. "${tokens[0] || q.substring(0, 6)}" — or check spelling. Available: Cisco Nexus, Arista, Juniper QFX, Edgecore, Mellanox.`
|
||||
});
|
||||
}
|
||||
switchResult.rows.push(...fallbackResult.rows);
|
||||
}
|
||||
|
||||
const sw = switchResult.rows[0];
|
||||
|
||||
|
||||
@ -1083,9 +1083,19 @@ function el(id) { return document.getElementById(id); }
|
||||
function api(path) {
|
||||
return fetch(API + path).then(function(r) {
|
||||
var ct = r.headers.get('content-type') || '';
|
||||
if (ct.indexOf('application/json') === -1) {
|
||||
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||
if (ct.indexOf('application/json') === -1) throw new Error('Server returned non-JSON response');
|
||||
return r.json();
|
||||
throw new Error('Server returned non-JSON response');
|
||||
}
|
||||
// Parse JSON even on error so callers can read error.message / error.suggestion
|
||||
return r.json().then(function(body) {
|
||||
if (!r.ok) {
|
||||
var err = new Error(body.error || ('HTTP ' + r.status));
|
||||
err.body = body;
|
||||
throw err;
|
||||
}
|
||||
return body;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -2836,7 +2846,14 @@ async function runFinder() {
|
||||
tcvrHtml;
|
||||
|
||||
} catch(e) {
|
||||
results.innerHTML = '<div class="card" style="border-left:3px solid #c1121f">Error: ' + e.message + '</div>';
|
||||
var body = e.body || {};
|
||||
var msg = body.error || e.message || 'Unknown error';
|
||||
var suggestion = body.suggestion || '';
|
||||
results.innerHTML = '<div class="card" style="border-left:3px solid #c1121f;padding:1rem">'
|
||||
+ '<div style="font-weight:700;margin-bottom:0.3rem">Switch not found</div>'
|
||||
+ '<div style="color:var(--text-dim);font-size:0.85rem">' + esc(msg) + '</div>'
|
||||
+ (suggestion ? '<div style="color:var(--text-dim);font-size:0.8rem;margin-top:0.4rem">💡 ' + esc(suggestion) + '</div>' : '')
|
||||
+ '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user