91334a46b5
Co-authored-by: Cursor <cursoragent@cursor.com>
308 lines
12 KiB
JavaScript
308 lines
12 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
function ready(fn) {
|
|
if (document.readyState !== 'loading') {
|
|
fn();
|
|
} else {
|
|
document.addEventListener('DOMContentLoaded', fn);
|
|
}
|
|
}
|
|
|
|
function el(tag, cls) {
|
|
var node = document.createElement(tag);
|
|
if (cls) {
|
|
node.className = cls;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
function text(tag, cls, value) {
|
|
var node = el(tag, cls);
|
|
node.textContent = value || '';
|
|
return node;
|
|
}
|
|
|
|
function parseLabels(raw) {
|
|
try {
|
|
return JSON.parse(raw || '{}') || {};
|
|
} catch (e) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
function setProgress(root, current, total, strings) {
|
|
var fill = root.querySelector('[data-meetlet-progress-fill]');
|
|
var label = root.querySelector('[data-meetlet-progress-label]');
|
|
var pct = total ? Math.round((current / total) * 100) : 0;
|
|
if (fill) {
|
|
fill.style.width = pct + '%';
|
|
}
|
|
if (label) {
|
|
label.textContent = strings.progress
|
|
.replace('{$a->current}', String(current))
|
|
.replace('{$a->total}', String(total))
|
|
.replace('{$a->percent}', String(pct));
|
|
}
|
|
}
|
|
|
|
function buildCard(index, total, step, label, strings) {
|
|
var wrap = el('div', 'meetlet-conntest__card meetlet-conntest__card--pending');
|
|
wrap.setAttribute('data-step', step);
|
|
wrap.setAttribute('data-index', String(index));
|
|
|
|
var top = el('div', 'meetlet-conntest__rowtop');
|
|
top.appendChild(text('span', 'meetlet-conntest__num', String(index + 1)));
|
|
top.appendChild(el('span', 'meetlet-dot meetlet-dot--pending'));
|
|
top.appendChild(text('span', 'meetlet-conntest__label', label));
|
|
top.appendChild(text('span', 'meetlet-pill meetlet-pill--pending', strings.waiting));
|
|
wrap.appendChild(top);
|
|
wrap.appendChild(text('div', 'meetlet-conntest__detail meetlet-conntest__card-detail', ''));
|
|
return wrap;
|
|
}
|
|
|
|
function setCardState(card, state, strings, detail) {
|
|
card.className = 'meetlet-conntest__card meetlet-conntest__card--' + state;
|
|
var dot = card.querySelector('.meetlet-dot');
|
|
var pill = card.querySelector('.meetlet-pill');
|
|
var detailNode = card.querySelector('.meetlet-conntest__card-detail');
|
|
if (dot) {
|
|
dot.className = 'meetlet-dot meetlet-dot--' + state;
|
|
}
|
|
if (pill) {
|
|
pill.className = 'meetlet-pill meetlet-pill--' + state;
|
|
if (state === 'pending') {
|
|
pill.textContent = strings.waiting;
|
|
} else if (state === 'running') {
|
|
pill.textContent = strings.runningstep;
|
|
} else if (state === 'ok') {
|
|
pill.textContent = strings.ok;
|
|
} else if (state === 'fail') {
|
|
pill.textContent = strings.fail;
|
|
} else if (state === 'skipped') {
|
|
pill.textContent = strings.skipped;
|
|
}
|
|
}
|
|
if (detailNode) {
|
|
detailNode.textContent = detail || '';
|
|
detailNode.style.display = detail ? '' : 'none';
|
|
}
|
|
}
|
|
|
|
function setSubResults(card, subresults, strings) {
|
|
var wrap = card.querySelector('[data-meetlet-subresults]');
|
|
if (!wrap) {
|
|
wrap = el('div', 'meetlet-conntest__subs');
|
|
wrap.setAttribute('data-meetlet-subresults', '1');
|
|
card.appendChild(wrap);
|
|
}
|
|
wrap.innerHTML = '';
|
|
if (!subresults || !subresults.length) {
|
|
wrap.style.display = 'none';
|
|
return;
|
|
}
|
|
wrap.style.display = '';
|
|
subresults.forEach(function (sub) {
|
|
var substate = 'fail';
|
|
var pillText = strings.fail;
|
|
if (sub.skipped) {
|
|
substate = 'skipped';
|
|
pillText = strings.skipped;
|
|
} else if (sub.ok) {
|
|
substate = 'ok';
|
|
pillText = strings.ok;
|
|
}
|
|
var subcard = el('div', 'meetlet-conntest__sub meetlet-conntest__sub--' + substate);
|
|
var top = el('div', 'meetlet-conntest__rowtop');
|
|
top.appendChild(el('span', 'meetlet-dot meetlet-dot--' + substate));
|
|
top.appendChild(text('span', 'meetlet-conntest__sublabel', sub.label || sub.id || ''));
|
|
top.appendChild(text('span', 'meetlet-pill meetlet-pill--' + substate, pillText));
|
|
subcard.appendChild(top);
|
|
if (sub.detail) {
|
|
subcard.appendChild(text('div', 'meetlet-conntest__detail', sub.detail));
|
|
}
|
|
wrap.appendChild(subcard);
|
|
});
|
|
}
|
|
|
|
function sleep(ms) {
|
|
return new Promise(function (resolve) {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
}
|
|
|
|
ready(function () {
|
|
var SAVE_ICON = '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">'
|
|
+ '<path fill="currentColor" d="M17 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7l-4-4zm-5 16a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm3-10H5V5h10v4z"/>'
|
|
+ '</svg>';
|
|
|
|
document.querySelectorAll('#adminsettings .offset-sm-3').forEach(function (el) {
|
|
if (!el.querySelector('button.btn-primary, input.btn-primary[type="submit"]')) {
|
|
return;
|
|
}
|
|
el.classList.remove('offset-sm-3', 'col-sm-3', 'col-md-3');
|
|
el.classList.add('col-12', 'meetlet-savebar');
|
|
});
|
|
|
|
document.querySelectorAll(
|
|
'#adminsettings button.btn-primary[type="submit"],'
|
|
+ ' #adminsettings input.btn-primary[type="submit"]'
|
|
).forEach(function (btn) {
|
|
if (btn.getAttribute('data-meetlet-save-icon') === '1') {
|
|
return;
|
|
}
|
|
btn.setAttribute('data-meetlet-save-icon', '1');
|
|
btn.classList.add('meetlet-btn-with-icon');
|
|
if (btn.tagName === 'INPUT') {
|
|
var replacement = document.createElement('button');
|
|
replacement.type = 'submit';
|
|
replacement.name = btn.name || 'submitbutton';
|
|
replacement.value = btn.value || '';
|
|
replacement.id = btn.id || '';
|
|
replacement.className = btn.className;
|
|
replacement.setAttribute('data-meetlet-save-icon', '1');
|
|
replacement.innerHTML = SAVE_ICON
|
|
+ '<span class="meetlet-btn-with-icon__label">'
|
|
+ (btn.value || btn.getAttribute('value') || 'Save changes')
|
|
+ '</span>';
|
|
btn.parentNode.replaceChild(replacement, btn);
|
|
return;
|
|
}
|
|
if (btn.querySelector('svg')) {
|
|
return;
|
|
}
|
|
var label = (btn.textContent || '').trim() || 'Save changes';
|
|
btn.textContent = '';
|
|
btn.insertAdjacentHTML('afterbegin', SAVE_ICON);
|
|
var span = document.createElement('span');
|
|
span.className = 'meetlet-btn-with-icon__label';
|
|
span.textContent = label;
|
|
btn.appendChild(span);
|
|
});
|
|
|
|
var root = document.getElementById('meetlet-acb-conntest');
|
|
if (!root) {
|
|
return;
|
|
}
|
|
var btn = root.querySelector('[data-meetlet-run-test]');
|
|
var grid = root.querySelector('[data-meetlet-test-grid]');
|
|
var status = root.querySelector('[data-meetlet-test-status]');
|
|
var progressWrap = root.querySelector('[data-meetlet-progress]');
|
|
if (!btn || !grid) {
|
|
return;
|
|
}
|
|
|
|
var endpoint = root.getAttribute('data-endpoint');
|
|
var sesskey = root.getAttribute('data-sesskey');
|
|
var steps = (root.getAttribute('data-steps') || 'login,folders,user,sso,cleanup')
|
|
.split(',')
|
|
.map(function (s) { return s.trim(); })
|
|
.filter(Boolean);
|
|
var labels = parseLabels(root.getAttribute('data-step-labels'));
|
|
var strings = {
|
|
ok: root.getAttribute('data-str-ok') || 'OK',
|
|
fail: root.getAttribute('data-str-fail') || 'Fail',
|
|
running: root.getAttribute('data-str-running') || 'Running…',
|
|
idle: root.getAttribute('data-str-idle') || '',
|
|
waiting: root.getAttribute('data-str-waiting') || 'Waiting',
|
|
runningstep: root.getAttribute('data-str-runningstep') || 'Testing',
|
|
skipped: root.getAttribute('data-str-skipped') || 'Skipped',
|
|
progress: root.getAttribute('data-str-progress') || 'Step {$a->current} of {$a->total} ({$a->percent}%)'
|
|
};
|
|
|
|
btn.addEventListener('click', function () {
|
|
if (btn.disabled) {
|
|
return;
|
|
}
|
|
btn.disabled = true;
|
|
grid.innerHTML = '';
|
|
if (progressWrap) {
|
|
progressWrap.hidden = false;
|
|
}
|
|
if (status) {
|
|
status.textContent = strings.running;
|
|
}
|
|
|
|
var cards = {};
|
|
steps.forEach(function (step, index) {
|
|
var label = labels[step] || step;
|
|
var card = buildCard(index, steps.length, step, label, strings);
|
|
setCardState(card, 'pending', strings, '');
|
|
grid.appendChild(card);
|
|
cards[step] = card;
|
|
});
|
|
setProgress(root, 0, steps.length, strings);
|
|
|
|
(async function () {
|
|
var skipToCleanup = false;
|
|
var completed = 0;
|
|
for (var i = 0; i < steps.length; i++) {
|
|
var step = steps[i];
|
|
var card = cards[step];
|
|
|
|
if (skipToCleanup && step !== 'cleanup') {
|
|
setCardState(card, 'skipped', strings, '');
|
|
completed++;
|
|
setProgress(root, completed, steps.length, strings);
|
|
continue;
|
|
}
|
|
|
|
setCardState(card, 'running', strings, '');
|
|
setProgress(root, completed, steps.length, strings);
|
|
|
|
var url = endpoint +
|
|
(endpoint.indexOf('?') === -1 ? '?' : '&') +
|
|
'step=' + encodeURIComponent(step) +
|
|
'&sesskey=' + encodeURIComponent(sesskey);
|
|
var response = await fetch(url, {
|
|
credentials: 'same-origin',
|
|
headers: { 'Accept': 'application/json' }
|
|
});
|
|
var result = await response.json();
|
|
setCardState(
|
|
card,
|
|
result.ok ? 'ok' : 'fail',
|
|
strings,
|
|
result.detail || ''
|
|
);
|
|
if (result.subresults && result.subresults.length) {
|
|
setSubResults(card, result.subresults, strings);
|
|
}
|
|
completed++;
|
|
setProgress(root, completed, steps.length, strings);
|
|
await sleep(220);
|
|
|
|
if (result.abort || (result.done && step !== 'cleanup')) {
|
|
skipToCleanup = true;
|
|
if (result.done && step !== 'cleanup') {
|
|
// Mark remaining non-cleanup as skipped, then stop if no cleanup needed.
|
|
for (var j = i + 1; j < steps.length; j++) {
|
|
if (steps[j] === 'cleanup') {
|
|
continue;
|
|
}
|
|
setCardState(cards[steps[j]], 'skipped', strings, '');
|
|
completed++;
|
|
}
|
|
// Still run cleanup if present later in loop via skipToCleanup.
|
|
}
|
|
if (step === 'cleanup') {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
setProgress(root, steps.length, steps.length, strings);
|
|
})().catch(function (err) {
|
|
var firstPending = grid.querySelector('.meetlet-conntest__card--pending, .meetlet-conntest__card--running');
|
|
if (firstPending) {
|
|
setCardState(firstPending, 'fail', strings, String(err && err.message ? err.message : err));
|
|
}
|
|
}).finally(function () {
|
|
btn.disabled = false;
|
|
if (status) {
|
|
status.textContent = strings.idle;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
})();
|