Files
meetletacbfree/amd/build/settings_conntest.min.js
T
mrxzamani 988aafce39 Commit AMD build artifacts required for Moodle Marketplace review.
Stop ignoring amd/build so generated modules ship with the plugin ZIP.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-20 12:42:19 +03:30

325 lines
13 KiB
JavaScript

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* @module mod_meetletacbfree/settings_conntest
* @copyright 2026 MeetLet <info@meetlet.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/ajax'], function(Ajax) {
'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);
});
}
function init() {
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 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 result = await new Promise(function(resolve, reject) {
Ajax.call([{
methodname: 'mod_meetletacbfree_run_conntest_step',
args: {step: step}
}])[0].then(resolve).catch(reject);
});
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;
}
});
});
}
return {init: init};
});