Files
html/js/v94-drill-universal.js

89 lines
5.0 KiB
JavaScript

// V94 Universal drill-down module
(function(){
if (window.__V94_DRILL_LOADED__) return;
window.__V94_DRILL_LOADED__ = true;
const SEL = '.stat, .kpi, .card, .metric, .mc, .ctr, .tile';
const MODAL_ID = 'v94-universal-modal';
function buildModal(){
if (document.getElementById(MODAL_ID)) return;
const d = document.createElement('div');
d.id = MODAL_ID;
d.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,.85);backdrop-filter:blur(4px);z-index:999999;display:none;align-items:center;justify-content:center;padding:20px;font-family:system-ui,sans-serif';
d.innerHTML = '<div style="background:#0e1530;border:1px solid #263161;border-radius:12px;padding:24px;max-width:720px;width:100%;max-height:85vh;overflow-y:auto;box-shadow:0 24px 60px rgba(0,0,0,.6)"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px"><div id="v94-title" style="font-size:18px;font-weight:700;color:#e4e8f7">Drill-down</div><button id="v94-close" style="background:none;border:0;color:#9ca8d3;font-size:28px;cursor:pointer;line-height:1">&times;</button></div><div style="margin-bottom:10px;font-size:11px;color:#9ca8d3" id="v94-sub">via WEVIA Master</div><div id="v94-content" style="color:#e4e8f7;font-size:12px;line-height:1.7">Loading...</div></div>';
document.body.appendChild(d);
document.getElementById('v94-close').onclick = closeModal;
d.onclick = e => { if (e.target === d) closeModal(); };
const style = document.createElement('style');
style.textContent = '.v94-drillable{cursor:pointer;transition:transform .15s ease,box-shadow .15s ease,filter .15s ease}.v94-drillable:hover{transform:translateY(-2px);box-shadow:0 4px 12px rgba(245,158,11,.25);filter:brightness(1.08)}';
document.head.appendChild(style);
}
function closeModal(){ const m=document.getElementById(MODAL_ID); if(m) m.style.display='none'; }
function getLabel(el){
if (el.dataset.k) return el.dataset.k;
const labelEl = el.querySelector('.label, .st-l, .mc-l, .kpi-label');
if (labelEl) return (labelEl.textContent||'').trim().slice(0,60);
return (el.textContent||'').trim().split('\n')[0].slice(0,60) || 'kpi';
}
function getIntent(label){
const m = label.toLowerCase().replace(/[^a-z0-9 ]/g,'').trim();
const map = {
'hcps ethica':'ethica live','ethica':'ethica live',
'docker':'v82 unified status','containers':'v82 unified status',
'crons':'cron failed','cron':'cron failed',
'ia cascade':'sovereign status','providers':'sovereign status',
'tools':'v77 oss discovery enriched',
'pages':'drill hub','apis':'drill hub',
'contacts':'crm stats','deals':'crm stats',
'nr':'nonreg last fails','nonreg':'nonreg last fails',
'linkedin':'linkedin score live','score':'linkedin score live',
'services':'realtime status'
};
for (const [k,v] of Object.entries(map)) if (m.includes(k)) return v;
return 'drill '+m.split(' ').slice(0,3).join(' ');
}
async function drill(el, e){
if (e) e.stopPropagation();
buildModal();
const label = getLabel(el);
const intent = el.dataset.intent || getIntent(label);
const m = document.getElementById(MODAL_ID);
document.getElementById('v94-title').textContent = label;
document.getElementById('v94-sub').innerHTML = 'via WEVIA intent: <code style="color:#10b981">'+intent+'</code>';
const c = document.getElementById('v94-content');
m.style.display = 'flex';
c.innerHTML = '<span style="opacity:.6">Querying WEVIA Master...</span>';
try {
const r = await fetch('/api/wevia-autonomous.php', {method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({message:intent,session:'v94-universal-drill'})});
const raw = await r.text();
let answer = '';
raw.split('\n').forEach(l => { if (l.startsWith('data: ')) { try { const j=JSON.parse(l.slice(6)); if(j.text||j.content) answer+=(j.text||j.content); } catch(e){} } });
if (!answer) answer = raw.slice(0, 3000);
let pretty = answer;
try { const j=JSON.parse(answer); pretty = '<pre style="background:#0a0e27;padding:14px;border-radius:6px;overflow-x:auto;font-size:11px;color:#6ba3ff;border:1px solid #263161">'+JSON.stringify(j,null,2)+'</pre>'; } catch(e) { pretty = '<div style="white-space:pre-wrap;word-break:break-word">'+answer.replace(/</g,'&lt;')+'</div>'; }
c.innerHTML = pretty;
} catch(err) { c.innerHTML = '<div style="color:#ef4444">Error: '+err.message+'</div>'; }
}
function attachAll(){
document.querySelectorAll(SEL).forEach(el => {
if (el.__v94Bound) return;
el.__v94Bound = true;
el.classList.add('v94-drillable');
el.addEventListener('click', e => drill(el, e));
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', attachAll);
else attachAll();
new MutationObserver(()=>attachAll()).observe(document.body || document.documentElement, {childList:true,subtree:true});
document.addEventListener('keydown', e => { if (e.key==='Escape') closeModal(); });
window.v94 = { drill, attachAll, close: closeModal };
console.log('[V94] universal drill-down loaded');
})();