// ── Admin Page (User Management) ── registerPage('admin', { async init() { if (!currentUser || !currentUser.isAdmin) { navigateTo('dashboard'); return; } var users = []; var editingUserId = null; var list = document.getElementById('adminUserList'); var newUserBtn = document.getElementById('adminNewUserBtn'); var userForm = document.getElementById('adminUserForm'); var formTitle = document.getElementById('adminFormTitle'); var usernameInput = document.getElementById('adminUsername'); var displayNameInput = document.getElementById('adminDisplayName'); var passwordInput = document.getElementById('adminPassword'); var passwordLabel = document.getElementById('adminPasswordLabel'); var defaultPathInput = document.getElementById('adminDefaultPath'); var defaultPathBrowse = document.getElementById('adminDefaultPathBrowse'); var isAdminCheckbox = document.getElementById('adminIsAdmin'); var canCreateAgentsCheckbox = document.getElementById('adminCanCreateAgents'); var canUseCliCheckbox = document.getElementById('adminCanUseCli'); var saveBtn = document.getElementById('adminFormSaveBtn'); function renderUsers() { list.innerHTML = ''; users.forEach(function(user) { var row = document.createElement('div'); row.className = 'admin-user-row'; var info = document.createElement('div'); info.className = 'admin-user-info'; var nameSpan = document.createElement('span'); nameSpan.className = 'admin-user-name'; nameSpan.textContent = user.displayName || user.username; var metaSpan = document.createElement('span'); metaSpan.className = 'admin-user-meta'; var metaParts = ['@' + user.username]; if (user.isAdmin) metaParts.push('Administrator'); if (user.defaultPath) metaParts.push(user.defaultPath); var perms = []; if (user.canCreateAgents === false) perms.push('keine Agents'); if (user.canUseCli === false) perms.push('keine CLI'); if (perms.length) metaParts.push(perms.join(', ')); metaSpan.textContent = metaParts.join(' · '); info.appendChild(nameSpan); info.appendChild(metaSpan); var actions = document.createElement('div'); actions.className = 'admin-user-actions'; var editBtn = document.createElement('button'); editBtn.className = 'icon-btn'; editBtn.title = 'Bearbeiten'; editBtn.innerHTML = ''; editBtn.addEventListener('click', function() { startEdit(user); }); actions.appendChild(editBtn); // Login-Link + Löschen (nicht für sich selbst) if (user.userId !== currentUser.userId) { var linkBtn = document.createElement('button'); linkBtn.className = 'icon-btn'; linkBtn.title = 'Login-Link generieren'; linkBtn.innerHTML = ''; linkBtn.addEventListener('click', function() { generateLoginLink(user); }); actions.appendChild(linkBtn); var deleteBtn = document.createElement('button'); deleteBtn.className = 'icon-btn'; deleteBtn.title = 'Löschen'; deleteBtn.innerHTML = ''; deleteBtn.addEventListener('click', function() { deleteUser(user); }); actions.appendChild(deleteBtn); } row.appendChild(info); row.appendChild(actions); list.appendChild(row); }); } async function loadUsers() { try { users = await apiAdminGetUsers(); renderUsers(); } catch (err) { showToast(err.message, 'error'); } } function startEdit(user) { editingUserId = user.userId; formTitle.textContent = 'Benutzer bearbeiten'; usernameInput.value = user.username; usernameInput.disabled = false; displayNameInput.value = user.displayName || ''; passwordInput.value = ''; passwordLabel.textContent = 'Neues Passwort (leer = unverändert)'; passwordInput.placeholder = 'Neues Passwort (optional)'; passwordInput.required = false; defaultPathInput.value = user.defaultPath || ''; isAdminCheckbox.checked = user.isAdmin; canCreateAgentsCheckbox.checked = user.canCreateAgents !== false; canUseCliCheckbox.checked = user.canUseCli !== false; saveBtn.textContent = 'Speichern'; userForm.hidden = false; usernameInput.focus(); } async function deleteUser(user) { if (!confirm('Benutzer "' + (user.displayName || user.username) + '" wirklich löschen?\n\nAlle Tokens werden ebenfalls gelöscht.')) { return; } try { await apiAdminDeleteUser(user.userId); await loadUsers(); } catch (err) { showToast(err.message, 'error'); } } async function generateLoginLink(user) { try { var result = await apiAdminGetLoginLink(user.userId); var link = window.location.origin + '/api/auth/autologin?token=' + result.token; showLoginLinkModal(user, link); } catch (err) { showToast(err.message, 'error'); } } function showLoginLinkModal(user, link) { const { body } = _createModal('Login-Link für ' + (user.displayName || user.username)); var desc = document.createElement('p'); desc.className = 'login-link-desc'; desc.textContent = 'Dieser Link loggt automatisch als dieser Benutzer ein. Teile ihn nur mit vertrauenswürdigen Personen.'; body.appendChild(desc); var inputRow = document.createElement('div'); inputRow.className = 'login-link-input-row'; var input = document.createElement('input'); input.type = 'text'; input.readOnly = true; input.value = link; input.className = 'login-link-input'; var copyBtn = document.createElement('button'); copyBtn.className = 'btn btn-primary'; copyBtn.innerHTML = ' Kopieren'; copyBtn.addEventListener('click', function() { navigator.clipboard.writeText(link).then(function() { copyBtn.innerHTML = ' Kopiert!'; setTimeout(function() { copyBtn.innerHTML = ' Kopieren'; }, 2000); }); }); inputRow.appendChild(input); inputRow.appendChild(copyBtn); body.appendChild(inputRow); // Input selektieren für einfaches Kopieren input.select(); } // ── Event-Listener ── // Default Path Browse if (defaultPathBrowse) { defaultPathBrowse.addEventListener('click', function() { openFolderBrowser({ startPath: defaultPathInput.value.trim() || '/', onSelect: function(path) { defaultPathInput.value = path; } }); }); } // Neuer Benutzer newUserBtn.addEventListener('click', function() { editingUserId = null; formTitle.textContent = 'Neuer Benutzer'; usernameInput.value = ''; usernameInput.disabled = false; displayNameInput.value = ''; passwordInput.value = ''; passwordLabel.textContent = 'Passwort'; passwordInput.placeholder = 'Passwort'; passwordInput.required = true; defaultPathInput.value = ''; isAdminCheckbox.checked = false; canCreateAgentsCheckbox.checked = true; canUseCliCheckbox.checked = true; saveBtn.textContent = 'Erstellen'; userForm.hidden = false; usernameInput.focus(); }); // Speichern saveBtn.addEventListener('click', () => withButtonLoading(saveBtn, saveBtn.textContent, async () => { try { if (editingUserId) { var data = { username: usernameInput.value.trim(), displayName: displayNameInput.value.trim(), defaultPath: defaultPathInput.value.trim() || null, isAdmin: isAdminCheckbox.checked, canCreateAgents: canCreateAgentsCheckbox.checked, canUseCli: canUseCliCheckbox.checked }; await apiAdminUpdateUser(editingUserId, data); var pw = passwordInput.value; if (pw) await apiAdminResetPassword(editingUserId, pw); showToast('Benutzer aktualisiert'); } else { var username = usernameInput.value.trim(); var password = passwordInput.value; if (!username || !password) { showToast('Benutzername und Passwort erforderlich', 'error'); return; } await apiAdminCreateUser({ username: username, password: password, displayName: displayNameInput.value.trim(), defaultPath: defaultPathInput.value.trim() || null, isAdmin: isAdminCheckbox.checked, canCreateAgents: canCreateAgentsCheckbox.checked, canUseCli: canUseCliCheckbox.checked }); showToast('Benutzer erstellt'); } userForm.hidden = true; await loadUsers(); } catch (err) { showToast(err.message, 'error'); } })); // ── Init: User laden ── await loadUsers(); }, destroy() {} });