// Page script for admin.html. Bootstrapping (auth cookie check, /info fetch, // header rendering, active-nav highlight) lives in js/app.js; this file wires // the "add user" form and the removable user list, and swaps between the // unauthorized / not-admin / admin panels depending on the /info payload. CollabCentral.init(function (ctx) { if (!ctx.info.isAdmin) { document.getElementById('notAdminPanel').classList.remove('hidden'); return; } document.getElementById('adminPanel').classList.remove('hidden'); var labelEl = document.getElementById('botLabelInline'); if (labelEl && ctx.info.label) labelEl.textContent = ctx.info.label; loadUsers(); }); function loadUsers() { fetch('/CollabCentral/' + CollabCentral.appName + '/admin/users') .then(function (res) { if (!res.ok) throw new Error('HTTP ' + res.status); return res.json(); }) .then(renderUsers) .catch(function (err) { console.error('Failed to load users:', err); flashAddStatus('Could not load the user list.', true); }); } function renderUsers(users) { var listEl = document.getElementById('userList'); var emptyEl = document.getElementById('userListEmpty'); if (!listEl) return; listEl.innerHTML = ''; if (!users || !users.length) { emptyEl.classList.remove('hidden'); return; } emptyEl.classList.add('hidden'); users .slice() .sort(function (a, b) { return String(a.displayName || '').localeCompare(String(b.displayName || '')); }) .forEach(function (u) { listEl.appendChild(userRow(u)); }); } function userRow(user) { var li = document.createElement('li'); li.className = 'userRow'; var avatar = document.createElement('div'); avatar.className = 'userRow__avatar'; if (user.avatar) { avatar.style.backgroundImage = 'url(' + JSON.stringify(user.avatar) + ')'; } else { avatar.textContent = (user.displayName || '?').slice(0, 1).toUpperCase(); avatar.classList.add('userRow__avatar--initials'); } li.appendChild(avatar); var meta = document.createElement('div'); meta.className = 'userRow__meta'; var name = document.createElement('div'); name.className = 'userRow__name'; name.textContent = user.displayName || '(no display name)'; var email = document.createElement('div'); email.className = 'userRow__email'; email.textContent = user.email || ''; var stats = document.createElement('div'); stats.className = 'userRow__stats'; stats.textContent = (user.groupCount === 1) ? '1 favorite group' : (user.groupCount || 0) + ' favorite groups'; meta.appendChild(name); meta.appendChild(email); meta.appendChild(stats); li.appendChild(meta); var actions = document.createElement('div'); actions.className = 'userRow__actions'; var removeBtn = document.createElement('button'); removeBtn.type = 'button'; removeBtn.className = 'btn btn-danger'; removeBtn.textContent = 'Remove'; removeBtn.dataset.userId = user.id; removeBtn.dataset.userName = user.displayName || ''; removeBtn.addEventListener('click', onRemoveUser); actions.appendChild(removeBtn); li.appendChild(actions); return li; } function onRemoveUser(event) { var btn = event.currentTarget; var userId = btn.dataset.userId; var userName = btn.dataset.userName || 'this user'; if (!userId) return; if (!window.confirm('Remove ' + userName + ' from this bot?')) return; btn.disabled = true; fetch('/CollabCentral/' + CollabCentral.appName + '/admin/users/' + encodeURIComponent(userId), { method: 'DELETE' }) .then(function (res) { if (!res.ok) throw new Error('HTTP ' + res.status); return res.json(); }) .then(function (body) { renderUsers(body.users || []); flashAddStatus('Removed ' + userName + '.'); }) .catch(function (err) { console.error('Failed to remove user:', err); btn.disabled = false; flashAddStatus('Could not remove ' + userName + '.', true); }); } document.getElementById('addUserForm').addEventListener('submit', function (event) { event.preventDefault(); var input = document.getElementById('newUserEmail'); var email = (input.value || '').trim(); if (!email) return; var submitBtn = event.target.querySelector('button[type="submit"]'); submitBtn.disabled = true; fetch('/CollabCentral/' + CollabCentral.appName + '/admin/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email }) }) .then(function (res) { return res.json().then(function (body) { return { ok: res.ok, status: res.status, body: body }; }) .catch(function () { return { ok: res.ok, status: res.status, body: null }; }); }) .then(function (result) { if (result.ok) { renderUsers((result.body && result.body.users) || []); var added = result.body && result.body.user; flashAddStatus(added ? 'Added ' + (added.displayName || added.email) + '.' : 'User added.'); input.value = ''; } else if (result.status === 404) { flashAddStatus('No Webex user found for that email.', true); } else if (result.status === 403) { flashAddStatus('You are not an administrator.', true); } else if (result.status === 502) { flashAddStatus('Could not reach the Webex directory. Try again.', true); } else { flashAddStatus('Something went wrong. Please try again.', true); } }) .catch(function (err) { console.error('Failed to add user:', err); flashAddStatus('Network error while adding user.', true); }) .finally(function () { submitBtn.disabled = false; }); }); function flashAddStatus(text, isError) { var el = document.getElementById('addUserStatus'); if (!el) return; el.textContent = text; el.classList.toggle('fieldStatus--error', !!isError); clearTimeout(flashAddStatus._t); flashAddStatus._t = setTimeout(function () { el.textContent = ''; el.classList.remove('fieldStatus--error'); }, 5000); }