Backend: - _list_groups(): reads /etc/group, returns groups with gid >= 1000 plus a small whitelist (root, staff, sambashare, www-data) - GET/POST /api/groups: list and create groups (groupadd) - DELETE /api/groups/<name>: delete group (groupdel) - POST /api/groups/<name>/members: add user to group (gpasswd -a) - DELETE /api/groups/<name>/members/<user>: remove user (gpasswd -d) Frontend: - Users tab now has a Groups section: table with GID, member badges with × remove buttons, per-row "add member" select populated with users not already in the group, delete group button - loadUsers() caches result in _cachedUsers for groups table to use - openEditModal is now async; fetches /api/users + /api/groups before rendering so Owner and Group inputs have datalist autocomplete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
22 lines
678 B
JavaScript
22 lines
678 B
JavaScript
const REFRESH_INTERVAL = 30;
|
|
let _countdownTimer = null;
|
|
|
|
function _startRefreshCountdown() {
|
|
if (_countdownTimer) clearInterval(_countdownTimer);
|
|
let secs = REFRESH_INTERVAL;
|
|
const el = document.getElementById('lastRefresh');
|
|
const update = () => {
|
|
const t = new Date().toLocaleTimeString();
|
|
el.textContent = `Updated ${t} — next in ${secs}s`;
|
|
if (secs <= 0) secs = REFRESH_INTERVAL; else secs--;
|
|
};
|
|
update();
|
|
_countdownTimer = setInterval(update, 1000);
|
|
}
|
|
|
|
loadDashboard();
|
|
loadShares();
|
|
loadUsers();
|
|
loadGroups();
|
|
setInterval(() => { loadDashboard(); loadShares(); loadUsers(); loadGroups(); }, REFRESH_INTERVAL * 1000);
|