feat: user roles - admins and users limited to the machines given to them, user editor with machines, password sign-in and its lock; direct address without Cloudflare as the agents' fallback and in the installer; version 0.1.2
This commit is contained in:
1 parent
36dc12b69d
commit
021da93229
29 files changed
+844
-97
No files matched your search
@@ -0,0 +1,105 @@
|
||||
// The users table in Settings: the role, the machines a user may use (a
|
||||
// dialog with a list to tick), the password sign-in and whether the user
|
||||
// may switch it themselves. Each change is saved at once.
|
||||
(function () {
|
||||
'use strict';
|
||||
var table = document.querySelector('table.users');
|
||||
if (!table) return;
|
||||
var $ = function (id) { return document.getElementById(id); };
|
||||
|
||||
function save(id, body) {
|
||||
return fetch('/api/panel/users/' + id, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(body)})
|
||||
.then(function (r) { return r.json(); })
|
||||
.catch(function () { return {ok: false, error: 'ошибка сети'}; });
|
||||
}
|
||||
function note(tr, text, bad) {
|
||||
var n = tr.querySelector('.u-note');
|
||||
if (!n) {
|
||||
n = document.createElement('div');
|
||||
n.className = 'u-note';
|
||||
tr.cells[0].appendChild(n);
|
||||
}
|
||||
n.textContent = text;
|
||||
n.classList.toggle('bad', !!bad);
|
||||
n.classList.remove('fade');
|
||||
void n.offsetWidth;
|
||||
n.classList.add('fade');
|
||||
}
|
||||
|
||||
table.addEventListener('change', function (ev) {
|
||||
var tr = ev.target.closest('tr'), id = tr && tr.dataset.id, el = ev.target;
|
||||
if (!id) return;
|
||||
var body = {}, undo;
|
||||
if (el.classList.contains('u-role')) {
|
||||
body.role = el.value;
|
||||
undo = function () { el.value = el.value === 'user' ? 'admin' : 'user'; };
|
||||
} else if (el.classList.contains('u-pw')) {
|
||||
body.password_off = !el.checked;
|
||||
undo = function () { el.checked = !el.checked; };
|
||||
} else if (el.classList.contains('u-lock')) {
|
||||
body.pw_locked = el.checked;
|
||||
undo = function () { el.checked = !el.checked; };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
save(id, body).then(function (r) {
|
||||
if (!r.ok) { undo(); note(tr, r.error || 'не сохранилось', true); return; }
|
||||
note(tr, 'сохранено');
|
||||
if (body.role) {
|
||||
var user = body.role === 'user';
|
||||
tr.querySelector('.u-agents').hidden = !user;
|
||||
tr.querySelector('.u-count').hidden = !user;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// ---- the machines of a user ----
|
||||
var dlg = $('uadlg'), list = $('ualist'), cur = null;
|
||||
function render(filter) {
|
||||
var f = (filter || '').toLowerCase();
|
||||
list.querySelectorAll('label').forEach(function (l) {
|
||||
l.hidden = f && l.textContent.toLowerCase().indexOf(f) < 0;
|
||||
});
|
||||
}
|
||||
table.addEventListener('click', function (ev) {
|
||||
var b = ev.target.closest('.u-agents');
|
||||
if (!b) return;
|
||||
var tr = b.closest('tr');
|
||||
cur = tr;
|
||||
$('uaname').textContent = tr.dataset.name;
|
||||
list.innerHTML = '<div class="muted">загрузка…</div>';
|
||||
$('uafilter').value = '';
|
||||
dlg.showModal();
|
||||
fetch('/api/panel/users/' + tr.dataset.id + '/agents', {cache: 'no-store'}).then(function (r) { return r.json(); }).then(function (d) {
|
||||
list.innerHTML = '';
|
||||
d.agents.forEach(function (a) {
|
||||
var l = document.createElement('label');
|
||||
l.className = 'ua-item';
|
||||
l.innerHTML = '<input type="checkbox"><span class="dot ' + (a.online ? 'on' : 'off') + '"></span><span class="ua-name"></span><span class="muted ua-host"></span>';
|
||||
l.querySelector('input').value = a.id;
|
||||
l.querySelector('input').checked = a.on;
|
||||
l.querySelector('.ua-name').textContent = a.name;
|
||||
l.querySelector('.ua-host').textContent = a.hostname;
|
||||
list.appendChild(l);
|
||||
});
|
||||
if (!d.agents.length) list.innerHTML = '<div class="muted">машин пока нет</div>';
|
||||
});
|
||||
});
|
||||
$('uafilter').addEventListener('input', function (ev) { render(ev.target.value); });
|
||||
$('uaall').onclick = function () { list.querySelectorAll('label:not([hidden]) input').forEach(function (i) { i.checked = true; }); };
|
||||
$('uanone').onclick = function () { list.querySelectorAll('label:not([hidden]) input').forEach(function (i) { i.checked = false; }); };
|
||||
$('uaclose').onclick = $('uacancel').onclick = function () { dlg.close(); };
|
||||
$('uasave').onclick = function () {
|
||||
var ids = [].map.call(list.querySelectorAll('input:checked'), function (i) { return i.value; });
|
||||
save(cur.dataset.id, {agents: ids}).then(function (r) {
|
||||
if (!r.ok) { note(cur, r.error || 'не сохранилось', true); return; }
|
||||
cur.querySelector('.u-count').textContent = ids.length;
|
||||
note(cur, 'машин: ' + ids.length);
|
||||
dlg.close();
|
||||
});
|
||||
};
|
||||
|
||||
// ---- a new user: the machines appear for a plain user ----
|
||||
var role = $('newrole'), pick = $('newagents');
|
||||
if (role) role.onchange = function () { pick.hidden = role.value !== 'user'; };
|
||||
})();
|
||||
Reference in new issue
Block a user