- scenario-form.js: fix ReferenceError body is not defined in renderEditor() - utils.js: relativeTime(iso) → 3ч 12м / 2д 5ч / только что - instances.js: columns created / modified with relativeTime() - index.html: instanceUid under displayName in infra column
61 lines
2.2 KiB
JavaScript
61 lines
2.2 KiB
JavaScript
// utils.js — общие хелперы: _esc, busy lock, validateJson, лог-панель
|
||
|
||
function _esc(s){
|
||
/* HTML-экранирование: " → " & → & < → < */
|
||
return String(s||'').replace(/&/g,'&').replace(/"/g,'"').replace(/</g,'<');
|
||
}
|
||
|
||
function validateJson(el,quiet){
|
||
/* Проверить что значение в поле — валидный JSON.
|
||
quiet=true — не менять внешний вид (для batch-проверки перед отправкой). */
|
||
const errEl=el.parentElement.querySelector('.json-err');
|
||
const v=el.value.trim();
|
||
if(!v) return true;
|
||
try{ JSON.parse(v); }
|
||
catch(e){
|
||
if(!quiet&&errEl){ errEl.style.display='inline'; errEl.textContent='Ошибка JSON: '+e.message; }
|
||
el.style.borderColor='var(--destructive)';
|
||
return false;
|
||
}
|
||
if(!quiet&&errEl) errEl.style.display='none';
|
||
el.style.borderColor='';
|
||
return true;
|
||
}
|
||
|
||
// === Панель логов ===
|
||
let logPollTimer=null;
|
||
function startLogPoll(){
|
||
if(logPollTimer) return;
|
||
logPollTimer=setInterval(async()=>{
|
||
const el=document.getElementById('log-panel');
|
||
if(!el||el.style.display==='none') return;
|
||
try{
|
||
const r=await fetch('/api/log');
|
||
const lines=await r.json();
|
||
el.innerHTML=lines.map(l=>`<div>${_esc(l)}</div>`).join('');
|
||
el.scrollTop=el.scrollHeight;
|
||
}catch(e){}
|
||
},2000);
|
||
}
|
||
function toggleLog(){
|
||
const el=document.getElementById('log-panel');
|
||
if(!el) return;
|
||
if(el.style.display==='none'){ el.style.display='block'; startLogPoll(); }
|
||
else el.style.display='none';
|
||
}
|
||
|
||
function relativeTime(iso) {
|
||
if (!iso) return '-';
|
||
const d = new Date(iso);
|
||
if (isNaN(d.getTime())) return '-';
|
||
const sec = Math.floor((Date.now() - d.getTime()) / 1000);
|
||
if (sec < 0) return 'только что';
|
||
if (sec < 60) return sec + 'с';
|
||
const min = Math.floor(sec / 60);
|
||
if (min < 60) return min + 'м';
|
||
const hr = Math.floor(min / 60);
|
||
if (hr < 24) return hr + 'ч ' + (min % 60) + 'м';
|
||
const days = Math.floor(hr / 24);
|
||
return days + 'д ' + (hr % 24) + 'ч';
|
||
}
|