fix: adapt autotest to updated service APIs
This commit is contained in:
+71
-70
@@ -16,12 +16,12 @@
|
||||
// busy — флаг блокировки UI (пока идёт операция)
|
||||
// AUTOTEST_PREFIX — "autotest-" (фильтр "наших" инстансов)
|
||||
|
||||
let svcInstances=[], selectedInst=null, selectedOp=null;
|
||||
let currentSvcId=(window.APP&&window.APP.firstServiceId)||1;
|
||||
let currentSvcName='';
|
||||
let currentSvcShort='';
|
||||
let busy=false;
|
||||
const AUTOTEST_PREFIX='autotest-';
|
||||
let svcInstances = [], selectedInst = null, selectedOp = null;
|
||||
let currentSvcId = (window.APP && window.APP.firstServiceId) || 1;
|
||||
let currentSvcName = '';
|
||||
let currentSvcShort = '';
|
||||
let busy = false;
|
||||
const AUTOTEST_PREFIX = 'autotest-';
|
||||
|
||||
/**
|
||||
* Выбрать сервис — загрузить его инстансы и показать в списке.
|
||||
@@ -29,37 +29,37 @@ const AUTOTEST_PREFIX='autotest-';
|
||||
*
|
||||
* @param {number} svcId — ID сервиса
|
||||
*/
|
||||
async function selectService(svcId){
|
||||
if(busy) return; // блокировка — идёт операция
|
||||
async function selectService(svcId) {
|
||||
if (busy) return; // блокировка — идёт операция
|
||||
|
||||
// Сброс предыдущего состояния
|
||||
currentSvcId=svcId;
|
||||
selectedInst=null;
|
||||
selectedOp=null;
|
||||
currentSvcId = svcId;
|
||||
selectedInst = null;
|
||||
selectedOp = null;
|
||||
stopPoll(); // остановить поллинг предыдущей операции
|
||||
|
||||
// Скрыть панель параметров и этапы
|
||||
document.getElementById('params-area').style.display='none';
|
||||
document.querySelectorAll('.stages-box').forEach(e=>e.remove());
|
||||
document.getElementById('params-area').style.display = 'none';
|
||||
document.querySelectorAll('.stages-box').forEach(e => e.remove());
|
||||
|
||||
// Подсветка активного сервиса в списке
|
||||
document.querySelectorAll('.svc-item').forEach(e=>e.classList.remove('active'));
|
||||
const svcEl=document.querySelector(`.svc-item[onclick*="${svcId}"]`);
|
||||
if(svcEl) svcEl.classList.add('active');
|
||||
document.querySelectorAll('.svc-item').forEach(e => e.classList.remove('active'));
|
||||
const svcEl = document.querySelector(`.svc-item[onclick*="${svcId}"]`);
|
||||
if (svcEl) svcEl.classList.add('active');
|
||||
|
||||
try{
|
||||
try {
|
||||
// GET /api/operations/{svcId} — возвращает операции + autotest-инстансы
|
||||
const r=await fetch('/api/operations/'+svcId);
|
||||
const d=await r.json();
|
||||
svcInstances=d.instances||[];
|
||||
currentSvcName=d.svc||'';
|
||||
currentSvcShort=d.svcShort||'';
|
||||
const r = await fetch('/api/operations/' + svcId);
|
||||
const d = await r.json();
|
||||
svcInstances = d.instances || [];
|
||||
currentSvcName = d.svc || '';
|
||||
currentSvcShort = d.svcShort || '';
|
||||
// Обновить текст кнопки «Создать»
|
||||
const btnSpan=document.querySelector('#create-btn-area span');
|
||||
if(btnSpan) btnSpan.textContent='+ Создать новый инстанс '+(currentSvcName||'сервиса');
|
||||
const btnSpan = document.querySelector('#create-btn-area span');
|
||||
if (btnSpan) btnSpan.textContent = '+ Создать новый инстанс ' + (currentSvcName || 'сервиса');
|
||||
renderInstances(); // отрисовать список
|
||||
}catch(e){
|
||||
document.getElementById('inst-list').innerHTML=
|
||||
} catch (e) {
|
||||
document.getElementById('inst-list').innerHTML =
|
||||
'<span style="color:var(--destructive);font-size:11px;">Ошибка загрузки</span>';
|
||||
}
|
||||
}
|
||||
@@ -68,37 +68,38 @@ async function selectService(svcId){
|
||||
* Отрисовать список инстансов в #inst-list.
|
||||
* Каждый инстанс — строка: имя + сервис + статус + created + modified.
|
||||
*/
|
||||
function renderInstances(){
|
||||
let html='';
|
||||
svcInstances.forEach(i=>{
|
||||
function renderInstances() {
|
||||
let html = '';
|
||||
svcInstances.forEach(i => {
|
||||
// Статус: из нашего поля status (cloud-first) или explainedStatus
|
||||
const status=i.status||i.explainedStatus||'?';
|
||||
const sc=status==='running'?'badge-success':'';
|
||||
const status = i.status || i.explainedStatus || '?';
|
||||
const sc = (status === 'running' || status === 'Выполнен') ? 'badge-success' : '';
|
||||
const created = i.instanceConfigDtCreated || i.dtCreate || '';
|
||||
// Строка инстанса — кликабельна
|
||||
html+=`<div class="inst-item" onclick="toggleInstance('${i.instanceUid}')" data-iuid="${i.instanceUid}">
|
||||
html += `<div class="inst-item" onclick="toggleInstance('${i.instanceUid}')" data-iuid="${i.instanceUid}">
|
||||
<span style="display:inline-block;width:220px;">${_esc(i.displayName)}</span>
|
||||
<span style="display:inline-block;width:140px;color:var(--muted);font-size:11px;">${_esc(i.svc||'')}</span>
|
||||
<span style="display:inline-block;width:140px;color:var(--muted);font-size:11px;">${_esc(i.svc || '')}</span>
|
||||
<span class="badge ${sc}" style="font-size:9px;">${_esc(status)}</span>
|
||||
<span style="display:inline-block;width:60px;color:var(--muted);font-size:9px;text-align:right;" title="${i.instanceConfigDtCreated||''}">${relativeTime(i.instanceConfigDtCreated)}</span>
|
||||
<span style="display:inline-block;width:60px;color:var(--muted);font-size:9px;text-align:right;" title="${i.instanceConfigDtModified||''}">${relativeTime(i.instanceConfigDtModified)}</span>
|
||||
<span style="display:inline-block;width:60px;color:var(--muted);font-size:9px;text-align:right;" title="${created}">${relativeTime(created)}</span>
|
||||
<span style="display:inline-block;width:60px;color:var(--muted);font-size:9px;text-align:right;" title="${i.instanceConfigDtModified || ''}">${relativeTime(i.instanceConfigDtModified)}</span>
|
||||
</div>`;
|
||||
// Контейнер для кнопок операций (изначально скрыт)
|
||||
html+=`<div class="inst-ops" id="ops-${i.instanceUid}"></div>`;
|
||||
html += `<div class="inst-ops" id="ops-${i.instanceUid}"></div>`;
|
||||
});
|
||||
document.getElementById('inst-list').innerHTML=html;
|
||||
document.getElementById('inst-list').innerHTML = html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновить список инстансов (без смены сервиса).
|
||||
* Вызывается после завершения операции.
|
||||
*/
|
||||
async function refreshInstances(){
|
||||
try{
|
||||
const r=await fetch('/api/operations/'+currentSvcId);
|
||||
const d=await r.json();
|
||||
svcInstances=d.instances||[];
|
||||
async function refreshInstances() {
|
||||
try {
|
||||
const r = await fetch('/api/operations/' + currentSvcId);
|
||||
const d = await r.json();
|
||||
svcInstances = d.instances || [];
|
||||
renderInstances();
|
||||
}catch(e){}
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,52 +108,52 @@ async function refreshInstances(){
|
||||
*
|
||||
* @param {string} iuid — instanceUid
|
||||
*/
|
||||
async function toggleInstance(iuid){
|
||||
if(busy) return;
|
||||
selectedInst=iuid;
|
||||
async function toggleInstance(iuid) {
|
||||
if (busy) return;
|
||||
selectedInst = iuid;
|
||||
stopPoll();
|
||||
|
||||
// Подсветка выбранного инстанса
|
||||
document.querySelectorAll('[data-iuid]').forEach(e=>
|
||||
e.classList.toggle('active',e.dataset.iuid===iuid));
|
||||
document.querySelectorAll('[data-iuid]').forEach(e =>
|
||||
e.classList.toggle('active', e.dataset.iuid === iuid));
|
||||
|
||||
// Скрыть панель параметров (если была открыта для другого инстанса)
|
||||
document.getElementById('params-area').style.display='none';
|
||||
document.getElementById('params-area').style.display = 'none';
|
||||
|
||||
const opsEl=document.getElementById('ops-'+iuid);
|
||||
const opsEl = document.getElementById('ops-' + iuid);
|
||||
// Если уже открыт — закрыть (toggle)
|
||||
if(opsEl.classList.contains('open')){opsEl.classList.remove('open');return;}
|
||||
if (opsEl.classList.contains('open')) { opsEl.classList.remove('open'); return; }
|
||||
|
||||
// Закрыть ВСЕ другие открытые панели операций
|
||||
document.querySelectorAll('.inst-ops').forEach(e=>e.classList.remove('open'));
|
||||
document.querySelectorAll('.inst-ops').forEach(e => e.classList.remove('open'));
|
||||
|
||||
// Найти инстанс в списке (может быть из другого сервиса)
|
||||
const inst=svcInstances.find(x=>x.instanceUid===iuid);
|
||||
const svcId=inst?inst.serviceId:currentSvcId;
|
||||
const inst = svcInstances.find(x => x.instanceUid === iuid);
|
||||
const svcId = inst ? inst.serviceId : currentSvcId;
|
||||
|
||||
try{
|
||||
const r=await fetch('/api/operations/'+svcId);
|
||||
const d=await r.json();
|
||||
try {
|
||||
const r = await fetch('/api/operations/' + svcId);
|
||||
const d = await r.json();
|
||||
|
||||
// Фильтруем операции: убираем reconcile (техническая) и create (уже создан)
|
||||
let ops=(d.operations||[]).filter(o=>o.operation!=='reconcile'&&o.operation!=='create');
|
||||
let ops = (d.operations || []).filter(o => o.operation !== 'reconcile' && o.operation !== 'create');
|
||||
|
||||
// Для not created инстансов — только delete
|
||||
if(inst&&(inst.status||inst.explainedStatus)==='not created'){
|
||||
ops=ops.filter(o=>o.operation==='delete');
|
||||
if (inst && (inst.status || inst.explainedStatus) === 'not created') {
|
||||
ops = ops.filter(o => o.operation === 'delete');
|
||||
}
|
||||
|
||||
// Кнопки операций с цветовой маркировкой
|
||||
// o.operation в onclick — JS-escape: \ → \\, ' → \'
|
||||
// o.operation в тексте кнопки — HTML-escape через _esc()
|
||||
opsEl.innerHTML=ops.map(o=>{
|
||||
opsEl.innerHTML = ops.map(o => {
|
||||
const escOp = _esc(o.operation);
|
||||
const jsOp = o.operation.replace(/\\/g,'\\\\').replace(/'/g,"\\'");
|
||||
const jsOp = o.operation.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
||||
return `<button class="btn btn-sm op-btn ${opClass(o.operation)}" onclick="runOp('${jsOp}',${o.svcOperationId})">${escOp}</button>`;
|
||||
}).join('');
|
||||
opsEl.classList.add('open');
|
||||
}catch(e){
|
||||
opsEl.innerHTML='<span style="color:var(--destructive);font-size:11px;">Ошибка загрузки</span>';
|
||||
} catch (e) {
|
||||
opsEl.innerHTML = '<span style="color:var(--destructive);font-size:11px;">Ошибка загрузки</span>';
|
||||
opsEl.classList.add('open');
|
||||
}
|
||||
}
|
||||
@@ -163,12 +164,12 @@ async function toggleInstance(iuid){
|
||||
* @param {string} opName — "modify"/"delete"/"suspend"/...
|
||||
* @returns {string} CSS-класс
|
||||
*/
|
||||
function opClass(opName){
|
||||
if(opName==='modify') return 'op-btn-modify'; // синий
|
||||
if(opName==='suspend') return 'op-btn-suspend'; // оранжевый
|
||||
if(opName==='resume') return 'op-btn-resume'; // зелёный
|
||||
if(opName==='delete') return 'op-btn-delete'; // красный
|
||||
if(opName==='redeploy') return 'op-btn-redeploy'; // фиолетовый
|
||||
function opClass(opName) {
|
||||
if (opName === 'modify') return 'op-btn-modify'; // синий
|
||||
if (opName === 'suspend') return 'op-btn-suspend'; // оранжевый
|
||||
if (opName === 'resume') return 'op-btn-resume'; // зелёный
|
||||
if (opName === 'delete') return 'op-btn-delete'; // красный
|
||||
if (opName === 'redeploy') return 'op-btn-redeploy'; // фиолетовый
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user