mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-07-26 19:42:43 +02:00
feat(pathanalyzer): repeater filter matches by name as well as hash
The repeater filter input now accepts either form: pure-hex input still prefix-matches hop hash tokens, and any input also matches the names of contacts each token resolves to (pubkey-prefix candidates, memoized per token). With 1-byte hashes a name can match via a colliding candidate, so the filter is intentionally inclusive: it keeps messages where the named repeater could be on the path. Verified live via Playwright: hex prefix regression OK, name search returns only messages with a token resolving to the named contact, memoized pass over 606 messages takes <1 ms. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,7 +93,10 @@ async function paLoadContacts() {
|
||||
const resp = await fetch('/api/contacts/cached?format=full');
|
||||
if (resp.ok) {
|
||||
const data = await resp.json();
|
||||
if (data.success) paContacts = data.contacts || [];
|
||||
if (data.success) {
|
||||
paContacts = data.contacts || [];
|
||||
paTokenNameCache = new Map();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load contacts:', e);
|
||||
@@ -107,6 +110,19 @@ function paMatchContacts(token) {
|
||||
return paContacts.filter(c => (c.public_key || '').toLowerCase().startsWith(prefix));
|
||||
}
|
||||
|
||||
// token -> lowercase candidate contact names, memoized (contacts are
|
||||
// static per page load; cache is rebuilt when they arrive)
|
||||
let paTokenNameCache = new Map();
|
||||
|
||||
function paTokenNames(token) {
|
||||
let names = paTokenNameCache.get(token);
|
||||
if (!names) {
|
||||
names = paMatchContacts(token).map(c => (c.name || '').toLowerCase());
|
||||
paTokenNameCache.set(token, names);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// Split an echo's path hex into per-hop tokens using that echo's own
|
||||
// hash_size (same logic as showPathsPopup in app.js; trailing partial kept)
|
||||
function paDecodeEcho(echo) {
|
||||
@@ -133,8 +149,15 @@ function paMessageMatchesFilters(msg) {
|
||||
if (!ok) return false;
|
||||
}
|
||||
if (paFilters.token) {
|
||||
const t = paFilters.token;
|
||||
const ok = msg.echoView.some(e => e.tokens.some(tok => tok.startsWith(t)));
|
||||
const raw = paFilters.token; // lowercase
|
||||
const isHex = /^[0-9a-f]+$/.test(raw);
|
||||
const hexPrefix = raw.toUpperCase();
|
||||
// Hex input matches hash tokens by prefix; any input also matches
|
||||
// the names of contacts the token resolves to
|
||||
const ok = msg.echoView.some(e => e.tokens.some(tok =>
|
||||
(isHex && tok.startsWith(hexPrefix)) ||
|
||||
paTokenNames(tok).some(n => n.includes(raw))
|
||||
));
|
||||
if (!ok) return false;
|
||||
}
|
||||
if (paFilters.sender) {
|
||||
@@ -754,9 +777,7 @@ async function paLoadMessages() {
|
||||
function paReadFilters() {
|
||||
paFilters.hops = document.getElementById('paHopsFilter').value;
|
||||
paFilters.hashSize = document.getElementById('paHashSizeFilter').value;
|
||||
// Normalize token input to hex characters only (matches chip display casing)
|
||||
paFilters.token = document.getElementById('paTokenFilter').value
|
||||
.replace(/[^0-9a-fA-F]/g, '').toUpperCase();
|
||||
paFilters.token = document.getElementById('paTokenFilter').value.trim().toLowerCase();
|
||||
paFilters.sender = document.getElementById('paSenderFilter').value.trim().toLowerCase();
|
||||
paFilters.content = document.getElementById('paContentFilter').value.trim().toLowerCase();
|
||||
document.getElementById('paClearFiltersBtn').classList.toggle('d-none', !paFiltersActive());
|
||||
|
||||
@@ -367,8 +367,9 @@
|
||||
<option value="2">2-byte</option>
|
||||
<option value="3">3-byte</option>
|
||||
</select>
|
||||
<input id="paTokenFilter" type="text" class="form-control form-control-sm" style="width: 9.5rem;"
|
||||
placeholder="Repeater hash (3B)" title="Match a repeater hash anywhere in a path (prefix match)">
|
||||
<input id="paTokenFilter" type="text" class="form-control form-control-sm" style="width: 10.5rem;"
|
||||
placeholder="Repeater (3B or name)"
|
||||
title="Match a repeater anywhere in a path: hash prefix (hex) or contact name">
|
||||
<input id="paSenderFilter" type="text" class="form-control form-control-sm" style="width: 9.5rem;"
|
||||
placeholder="Sender" title="Filter by sender name">
|
||||
<input id="paContentFilter" type="text" class="form-control form-control-sm" style="width: 11rem;"
|
||||
|
||||
Reference in New Issue
Block a user