89 lines
5.0 KiB
JavaScript
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">×</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,'<')+'</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');
|
|
})();
|