CC1 R3B-Mreža M1+M2+M3 — autocomplete + 3D centar + forensic enrich
M1 (default centar): - Augment /api/v1/presenter/graph-real with synthetic 'pgz-savez-nogometni' anchor (PGŽ gold, size 40), connected to top 3 person + top 3 entity nodes - centerMrezaOnAnchor() called 1.5s after render and via "🎯 Centar (PGŽ)" button M2 (autocomplete): - Backend GET /api/v2/search/suggest?q=&type=person|club|company Searches pgz_sport.klubovi, pgz_sport.savezi, pgz_sport.clanovi, civic.persons, civic.entities; returns 20 results max - Frontend: 3 inputs get keydown+input handlers, dropdown UI under each Enter → first suggestion, click → suggestion, blur → close - centerMrezaOnSuggestion: finds existing node by label, or injects new node + edge from anchor and re-renders M3 (forensic enrich): - Backend POST /api/v2/forensic/findings/{id}/enrich Extract person name from entities_involved or title regex, hit hr.wikipedia.org REST summary, persist into raw_data.enrichment - Frontend: forensicEnrichBlock + customFindingEnrichBlock added to alert panel and custom-finding panel (Liverić). Custom uses direct Wikipedia fetch since they're not in DB. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2417,10 +2417,54 @@ function renderCustomFindingPanel(c){
|
|||||||
<div class="card-h"><div class="card-t">📄 Dokumenti / dokazi</div></div>
|
<div class="card-h"><div class="card-t">📄 Dokumenti / dokazi</div></div>
|
||||||
<div class="empty" style="padding:14px">Za ovaj manualni nalaz nisu priloženi PDF dokazi. Pokreni "Obogati podatke" za prikupljanje izvora.</div>
|
<div class="empty" style="padding:14px">Za ovaj manualni nalaz nisu priloženi PDF dokazi. Pokreni "Obogati podatke" za prikupljanje izvora.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
${customFindingEnrichBlock(c.id, c.osoba || c.naslov)}
|
||||||
`;
|
`;
|
||||||
openPanel('Forenzika · '+c.naslov, html);
|
openPanel('Forenzika · '+c.naslov, html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function customFindingEnrichBlock(customId, queryName){
|
||||||
|
const safeId = String(customId).replace(/[^a-z0-9_-]/gi,'_');
|
||||||
|
return `
|
||||||
|
<div class="card" id="fenrich-card-${safeId}">
|
||||||
|
<div class="card-h">
|
||||||
|
<div class="card-t">✨ Obogati podatke (Wikipedia)</div>
|
||||||
|
<button class="btn primary" onclick="enrichCustomFinding('${safeId}', '${esc(queryName).replace(/'/g,'\\\\'')}')">▶ Pokreni</button>
|
||||||
|
</div>
|
||||||
|
<div id="fenrich-out-${safeId}">
|
||||||
|
<div class="empty" style="padding:14px">Lookup Wikipedia HR za "${esc(queryName)}" i prikaži dopune.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function enrichCustomFinding(safeId, queryName){
|
||||||
|
const out = document.getElementById('fenrich-out-'+safeId);
|
||||||
|
if(out) out.innerHTML = '<div class="loading">Lookup Wikipedia HR…</div>';
|
||||||
|
// Custom findings aren't in DB — call wiki lookup via a synthesised forensic_findings.id of -1 won't work.
|
||||||
|
// Instead, use the existing /v2/enrich/sportas pattern to query Wikipedia by name.
|
||||||
|
// We re-use the wiki summary via a mini fetch helper.
|
||||||
|
try{
|
||||||
|
const wiki = await fetch('https://hr.wikipedia.org/api/rest_v1/page/summary/'+encodeURIComponent(queryName.replace(/ /g,'_')))
|
||||||
|
.then(r => r.ok ? r.json() : null).catch(()=>null);
|
||||||
|
if(!wiki || wiki.type==='disambiguation' || !wiki.extract){
|
||||||
|
if(out) out.innerHTML = '<div class="empty" style="padding:14px">Nije pronađen Wikipedia HR članak za <b>'+esc(queryName)+'</b>.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const w = {title: wiki.title, extract: wiki.extract, description: wiki.description, url: (wiki.content_urls||{}).desktop?.page};
|
||||||
|
if(out) out.innerHTML = `
|
||||||
|
<div style="margin-bottom:8px"><span class="tag gr">🟢 Wikipedia HR</span></div>
|
||||||
|
<div style="padding:10px;background:var(--bg3);border-left:3px solid var(--pgz-gold);border-radius:5px">
|
||||||
|
<div style="font-weight:700;color:var(--t0);font-size:14px;margin-bottom:6px">${esc(w.title||'')}</div>
|
||||||
|
${w.description?'<div style="font-size:11px;color:var(--t2);margin-bottom:6px;font-style:italic">'+esc(w.description)+'</div>':''}
|
||||||
|
${w.extract?'<div style="font-size:12px;line-height:1.6;color:var(--t1)">'+esc(w.extract)+'</div>':''}
|
||||||
|
${w.url?'<div style="margin-top:8px"><a href="'+esc(w.url)+'" target="_blank">↗ Otvori članak</a></div>':''}
|
||||||
|
</div>`;
|
||||||
|
}catch(e){
|
||||||
|
if(out) out.innerHTML = '<div class="empty" style="color:var(--red);padding:14px">Greška: '+esc(String(e))+'</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function renderAlertPanel(a){
|
function renderAlertPanel(a){
|
||||||
const sevColor = a.razina==='CRITICAL'?'rd':(a.razina==='HIGH'?'am':'b');
|
const sevColor = a.razina==='CRITICAL'?'rd':(a.razina==='HIGH'?'am':'b');
|
||||||
const html = `
|
const html = `
|
||||||
|
|||||||
Reference in New Issue
Block a user