diff --git a/packages/api/src/db/queries.ts b/packages/api/src/db/queries.ts
index 9f5fe89..4135625 100644
--- a/packages/api/src/db/queries.ts
+++ b/packages/api/src/db/queries.ts
@@ -283,7 +283,7 @@ export async function getTransceiverDocuments(transceiverI: string) {
export async function getCompatibleTransceivers(switchId: string) {
const result = await pool.query(
- `SELECT t.*, c.status, c.verified_by, c.notes as compat_notes,
+ `SELECT t.*, c.status, c.verified_by, c.verification_method, c.notes as compat_notes,
v.name AS vendor_name, v.type AS vendor_type, v.website AS vendor_website,
-- Latest verified price
COALESCE(t.price_verified_eur,
@@ -298,6 +298,9 @@ export async function getCompatibleTransceivers(switchId: string) {
WHERE c.switch_id = $1 AND c.status = 'compatible'
ORDER BY
CASE WHEN LOWER(v.name) = 'flexoptix' THEN 0 ELSE 1 END,
+ CASE WHEN c.verification_method = 'vendor_compat' THEN 0
+ WHEN c.verification_method = 'vendor_matrix' THEN 1
+ ELSE 2 END,
t.speed_gbps DESC`,
[switchId]
);
diff --git a/packages/dashboard/index.html b/packages/dashboard/index.html
index ba50c14..af701b0 100644
--- a/packages/dashboard/index.html
+++ b/packages/dashboard/index.html
@@ -4070,9 +4070,19 @@ async function openSwitchDetail(id) {
ch += '
Flexoptix Recommended ' + foList.length + '
';
ch += 'Directly available from Flexoptix — FlexBox coding supported
';
- // Group Flexoptix by speed class
+ // Split Flexoptix by verification method
+ var foVendorVerified = foList.filter(function(t) { return t.verification_method === 'vendor_compat' || t.verification_method === 'vendor_matrix'; });
+ var foSpecMatch = foList.filter(function(t) { return t.verification_method !== 'vendor_compat' && t.verification_method !== 'vendor_matrix'; });
+
+ // Show explicitly verified first
+ var foToShow = foVendorVerified.length > 0 ? foVendorVerified : foList;
+ if (foVendorVerified.length > 0 && foSpecMatch.length > 0) {
+ ch += '✓ Vendor-tested compatibility (' + foVendorVerified.length + ')
';
+ }
+
+ // Group by speed class
var foGroups = {};
- foList.forEach(function(t) {
+ foToShow.forEach(function(t) {
var key = (t.speed || '?') + ' ' + (t.form_factor || '?');
if (!foGroups[key]) foGroups[key] = [];
foGroups[key].push(t);
@@ -4107,28 +4117,74 @@ async function openSwitchDetail(id) {
if (items.length > 8) ch += '+' + (items.length - 8) + ' more Flexoptix options
';
ch += '';
});
+
+ // Form-factor matches (spec_match) — collapsed summary
+ if (foSpecMatch.length > 0) {
+ ch += ''
+ + '+ ' + foSpecMatch.length + ' more by form factor match
'
+ + ''
+ + foSpecMatch.slice(0, 20).map(function(t) {
+ return ''
+ + esc(t.standard_name || t.part_number) + '';
+ }).join('')
+ + (foSpecMatch.length > 20 ? '+' + (foSpecMatch.length - 20) + ' more' : '')
+ + '
';
+ }
}
// ── ALL COMPATIBLE (other vendors) ────────────────────────────────────
- ch += 'Compatible Transceivers ' + txList.length + '
';
- var groups = {};
- otherList.forEach(function(t) {
- var key = (t.form_factor || '?') + ' ' + (t.speed || '?');
- if (!groups[key]) groups[key] = [];
- groups[key].push(t);
- });
- Object.keys(groups).sort().forEach(function(key) {
- var items = groups[key];
- ch += '' + esc(key) + ' (' + items.length + ')
';
- ch += '';
- items.slice(0, 12).forEach(function(t) {
- var fullyBadge = (t.fully_verified === true) ? '★ ' : '';
- ch += ''
- + fullyBadge + esc(t.standard_name || t.slug || t.part_number) + '';
- });
- if (items.length > 12) ch += '+' + (items.length - 12) + ' more';
- ch += '
';
- });
+ if (otherList.length > 0) {
+ var verifiedOthers = otherList.filter(function(t) { return t.verification_method === 'vendor_matrix'; });
+ var specOthers = otherList.filter(function(t) { return t.verification_method !== 'vendor_matrix'; });
+
+ ch += 'Competitor Transceivers ' + otherList.length + ''
+ + (verifiedOthers.length > 0 ? '(' + verifiedOthers.length + ' vendor-tested)' : '') + '
';
+
+ // Show vendor-tested ones with price info
+ if (verifiedOthers.length > 0) {
+ var groups = {};
+ verifiedOthers.forEach(function(t) {
+ var key = (t.form_factor || '?') + ' ' + (t.speed || '?');
+ if (!groups[key]) groups[key] = [];
+ groups[key].push(t);
+ });
+ Object.keys(groups).sort().forEach(function(key) {
+ var items = groups[key];
+ ch += '' + esc(key) + ' (' + items.length + ')
';
+ ch += '';
+ items.slice(0, 6).forEach(function(t) {
+ var priceStr = '';
+ if (t.latest_price) {
+ var _pAmt = parseFloat(t.latest_price);
+ var _pCur = (t.latest_currency || 'USD').toUpperCase();
+ var _pUSD = toUSD(_pAmt, _pCur);
+ priceStr = _pUSD !== null ? fmtUSD(_pUSD) : _pCur + ' ' + _pAmt.toFixed(2);
+ }
+ ch += '
'
+ + '' + esc(t.part_number || t.standard_name) + ''
+ + '' + esc(t.vendor_name || '') + ''
+ + (priceStr ? '' + priceStr + '' : '')
+ + '
';
+ });
+ if (items.length > 6) ch += '
+' + (items.length - 6) + ' more
';
+ ch += '
';
+ });
+ }
+
+ // Show spec-match ones as compact chips
+ if (specOthers.length > 0) {
+ ch += '';
+ ch += '
Form factor compatible
';
+ ch += '
';
+ specOthers.slice(0, 20).forEach(function(t) {
+ var fullyBadge = (t.fully_verified === true) ? '★ ' : '';
+ ch += ''
+ + fullyBadge + esc(t.standard_name || t.slug || t.part_number) + '';
+ });
+ if (specOthers.length > 20) ch += '+' + (specOthers.length - 20) + ' more';
+ ch += '
';
+ }
+ }
el('panel-content').insertAdjacentHTML('beforeend', ch);
}).catch(function() {});