fix: load live dashboard data and add terminal actions
This commit is contained in:
@@ -83,6 +83,13 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s
|
||||
.sensor-actions{display:flex;gap:6px;align-items:center}
|
||||
.mini-btn{border:1px solid rgba(100,240,200,0.18);background:rgba(100,240,200,0.04);color:var(--dim);font-family:var(--mono);font-size:9px;padding:3px 6px;cursor:pointer}
|
||||
.mini-btn:hover{color:var(--accent);border-color:rgba(100,240,200,0.4)}
|
||||
.action-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:10px}
|
||||
.action-btn{border:1px solid rgba(68,204,255,0.24);background:rgba(68,204,255,0.06);color:var(--text);font-family:var(--mono);font-size:9px;padding:7px 6px;cursor:pointer;text-transform:uppercase;letter-spacing:.08em}
|
||||
.action-btn:hover{border-color:rgba(68,204,255,0.55);color:var(--accent2);background:rgba(68,204,255,0.12)}
|
||||
.action-btn[disabled]{opacity:.45;cursor:wait}
|
||||
.terminal-output{min-height:58px;max-height:180px;overflow:auto;border:1px solid rgba(255,255,255,0.05);background:rgba(0,0,0,0.22);padding:8px;font-family:var(--mono);font-size:10px;line-height:1.45;color:var(--dim);white-space:pre-wrap}
|
||||
.terminal-output strong{color:var(--accent)}
|
||||
.terminal-output .err{color:var(--danger)}
|
||||
.layer-left{display:flex;align-items:center;gap:8px}
|
||||
.ldot{width:10px;height:10px;border-radius:50%;flex-shrink:0}
|
||||
.ldot.air{background:var(--accent);box-shadow:0 0 6px rgba(100,240,200,0.4)}
|
||||
@@ -404,6 +411,8 @@ let lowPerfMode = localStorage.getItem('crucix_low_perf') === 'true';
|
||||
let isFlat = shouldStartFlat();
|
||||
let layerModes = JSON.parse(localStorage.getItem('crucix_layer_modes') || '{}');
|
||||
let spaceDisplayMode = localStorage.getItem('crucix_space_display') || 'icons';
|
||||
let terminalOutput = 'Ready. Live data is loaded from /api/data in server mode.';
|
||||
let terminalBusy = false;
|
||||
let currentRegion = 'world';
|
||||
let flatSvg, flatProjection, flatPath, flatG, flatZoom, flatW, flatH;
|
||||
|
||||
@@ -1564,6 +1573,46 @@ function renderLower(){
|
||||
document.getElementById('lowerGrid').innerHTML=`${tickerPanel}${osintPanel}${macroPanel}${ideasPanel}`;
|
||||
}
|
||||
|
||||
async function runTerminalAction(action){
|
||||
if(terminalBusy) return;
|
||||
terminalBusy = true;
|
||||
terminalOutput = `> ${action}\nRunning...`;
|
||||
renderRight();
|
||||
try{
|
||||
const res = await fetch('/api/action', {
|
||||
method:'POST',
|
||||
headers:{
|
||||
'Content-Type':'application/json',
|
||||
...(localStorage.getItem('crucix_sweep_token') ? {'x-crucix-token': localStorage.getItem('crucix_sweep_token')} : {})
|
||||
},
|
||||
body:JSON.stringify({action})
|
||||
});
|
||||
const payload = await res.json().catch(()=>({error:'Invalid server response'}));
|
||||
if(!res.ok) throw new Error(payload.error || `HTTP ${res.status}`);
|
||||
if(action === 'status'){
|
||||
const h = payload.health || {};
|
||||
terminalOutput = [
|
||||
'> status',
|
||||
`State: ${h.status || '--'}`,
|
||||
`Last sweep: ${h.lastSuccessfulSweep || h.lastSweep || '--'}`,
|
||||
`Data age: ${h.dataAgeSeconds != null ? h.dataAgeSeconds + 's' : '--'}`,
|
||||
`Sources: ${h.sourcesOk || 0} ok / ${h.sourcesDegraded || 0} degraded / ${h.sourcesFailed || 0} failed`,
|
||||
`LLM: ${h.llm?.state || '--'}`,
|
||||
`Sweep active: ${h.sweepInProgress ? 'yes' : 'no'}`
|
||||
].join('\n');
|
||||
}else if(action === 'brief'){
|
||||
terminalOutput = `> brief\n${payload.text || 'No briefing text returned.'}`;
|
||||
}else if(action === 'sweep'){
|
||||
terminalOutput = `> sweep\n${payload.status === 'already_running' ? 'Sweep already running.' : 'Sweep accepted. The dashboard will update when the sweep finishes.'}`;
|
||||
}
|
||||
}catch(err){
|
||||
terminalOutput = `> ${action}\nERROR: ${err.message}`;
|
||||
}finally{
|
||||
terminalBusy = false;
|
||||
renderRight();
|
||||
}
|
||||
}
|
||||
|
||||
// === RIGHT RAIL ===
|
||||
function renderRight(){
|
||||
const mobile = isMobileLayout();
|
||||
@@ -1605,6 +1654,15 @@ function renderRight(){
|
||||
const deltaHtml = hasDelta ? deltaRows.join('') : `<div style="padding:12px;text-align:center;color:var(--dim);font-family:var(--mono);font-size:10px">${t('delta.noChanges','No changes since last sweep')}</div>`;
|
||||
|
||||
document.getElementById('rightRail').innerHTML=`
|
||||
<div class="g-panel right-actions">
|
||||
<div class="sec-head"><h3>Terminal Actions</h3><span class="badge">${terminalBusy?'RUNNING':'READY'}</span></div>
|
||||
<div class="action-grid">
|
||||
<button class="action-btn" ${terminalBusy?'disabled':''} onclick="runTerminalAction('status')">Status</button>
|
||||
<button class="action-btn" ${terminalBusy?'disabled':''} onclick="runTerminalAction('sweep')">Sweep</button>
|
||||
<button class="action-btn" ${terminalBusy?'disabled':''} onclick="runTerminalAction('brief')">Brief</button>
|
||||
</div>
|
||||
<div class="terminal-output">${terminalOutput.replace(/[&<>]/g,c=>({'&':'&','<':'<','>':'>'}[c])).replace(/\n/g,'<br>')}</div>
|
||||
</div>
|
||||
<div class="g-panel right-signals">
|
||||
<div class="sec-head"><h3>${t('panels.crossSourceSignals','Cross-Source Signals')}</h3><span class="badge">${t('badges.worldview','WORLDVIEW')}</span></div>
|
||||
${signals}
|
||||
@@ -1839,10 +1897,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const hasInlineData = !!(D && D.meta);
|
||||
const canProbeApi = location.protocol !== 'file:';
|
||||
|
||||
if (canProbeApi && !hasInlineData) {
|
||||
if (canProbeApi) {
|
||||
// Server mode: always fetch live data from API (ignore any stale inline D)
|
||||
fetch('/api/data')
|
||||
.then(r => r.json())
|
||||
.then(r => { if(!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })
|
||||
.then(data => { D = data; init(); connectSSE(); })
|
||||
.catch(() => {
|
||||
// Should not reach here — server routes to loading.html when no data
|
||||
|
||||
Reference in New Issue
Block a user