|
import { api } from '../api.js';
|
|
|
|
export class AdminDashboard extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.users = [];
|
|
this.boundHandleClick = this.handleClick.bind(this);
|
|
this.boundHandleSubmit = this.handleSubmit.bind(this);
|
|
}
|
|
|
|
async connectedCallback() {
|
|
this.addEventListener('click', this.boundHandleClick);
|
|
this.addEventListener('submit', this.boundHandleSubmit);
|
|
await this.loadUsers();
|
|
}
|
|
|
|
disconnectedCallback() {
|
|
this.removeEventListener('click', this.boundHandleClick);
|
|
this.removeEventListener('submit', this.boundHandleSubmit);
|
|
}
|
|
|
|
async loadUsers() {
|
|
try {
|
|
this.users = await api.listUsers();
|
|
this.render();
|
|
} catch (error) {
|
|
console.error('Failed to load users:', error);
|
|
this.innerHTML = '<p class="error-message">Failed to load users. Do you have admin privileges?</p>';
|
|
}
|
|
}
|
|
|
|
render() {
|
|
this.innerHTML = `
|
|
<div class="admin-dashboard-container">
|
|
<h2>Admin Dashboard</h2>
|
|
|
|
<div class="admin-section">
|
|
<h3>User Management</h3>
|
|
<button id="createUserButton" class="button button-primary">Create New User</button>
|
|
<div class="user-list">
|
|
${this.users.map(user => this.renderUser(user)).join('')}
|
|
</div>
|
|
</div>
|
|
|
|
<div id="userModal" class="modal" style="display: none;">
|
|
<div class="modal-content">
|
|
<span class="close-button">×</span>
|
|
<h3>Edit User</h3>
|
|
<form id="userForm">
|
|
<input type="hidden" id="userId">
|
|
<label for="username">Username:</label>
|
|
<input type="text" id="username" class="input-field" required>
|
|
<label for="email">Email:</label>
|
|
<input type="email" id="email" class="input-field" required>
|
|
<label for="password">Password (leave blank to keep current):</label>
|
|
<input type="password" id="password" class="input-field">
|
|
<label for="isSuperuser">Superuser:</label>
|
|
<input type="checkbox" id="isSuperuser">
|
|
<label for="isActive">Active:</label>
|
|
<input type="checkbox" id="isActive">
|
|
<label for="is2faEnabled">2FA Enabled:</label>
|
|
<input type="checkbox" id="is2faEnabled">
|
|
<label for="storageQuotaBytes">Storage Quota (Bytes):</label>
|
|
<input type="number" id="storageQuotaBytes" class="input-field">
|
|
<label for="planType">Plan Type:</label>
|
|
<input type="text" id="planType" class="input-field">
|
|
<button type="submit" class="button button-primary">Save</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
handleClick(e) {
|
|
const target = e.target;
|
|
|
|
if (target.id === 'createUserButton') {
|
|
this._showUserModal();
|
|
return;
|
|
}
|
|
|
|
if (target.classList.contains('close-button')) {
|
|
this.querySelector('#userModal').style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
const userItem = target.closest('.user-item');
|
|
if (userItem) {
|
|
const userId = userItem.dataset.userId;
|
|
if (target.classList.contains('button-danger')) {
|
|
this._deleteUser(userId);
|
|
} else if (target.classList.contains('button')) {
|
|
this._showUserModal(userId);
|
|
}
|
|
}
|
|
}
|
|
|
|
handleSubmit(e) {
|
|
if (e.target.id === 'userForm') {
|
|
this._handleUserFormSubmit(e);
|
|
}
|
|
}
|
|
|
|
_showUserModal(userId = null) {
|
|
const modal = this.querySelector('#userModal');
|
|
const form = this.querySelector('#userForm');
|
|
form.reset(); // Clear previous form data
|
|
|
|
if (userId) {
|
|
const user = this.users.find(u => u.id == userId);
|
|
if (user) {
|
|
this.querySelector('#userId').value = user.id;
|
|
this.querySelector('#username').value = user.username;
|
|
this.querySelector('#email').value = user.email;
|
|
this.querySelector('#isSuperuser').checked = user.is_superuser;
|
|
this.querySelector('#isActive').checked = user.is_active;
|
|
this.querySelector('#is2faEnabled').checked = user.is_2fa_enabled;
|
|
this.querySelector('#storageQuotaBytes').value = user.storage_quota_bytes;
|
|
this.querySelector('#planType').value = user.plan_type;
|
|
this.querySelector('h3').textContent = 'Edit User';
|
|
}
|
|
} else {
|
|
this.querySelector('#userId').value = '';
|
|
this.querySelector('h3').textContent = 'Create New User';
|
|
}
|
|
modal.style.display = 'block';
|
|
}
|
|
|
|
async _handleUserFormSubmit(event) {
|
|
event.preventDefault();
|
|
const userId = this.querySelector('#userId').value;
|
|
const userData = {
|
|
username: this.querySelector('#username').value,
|
|
email: this.querySelector('#email').value,
|
|
password: this.querySelector('#password').value || undefined, // Only send if not empty
|
|
is_superuser: this.querySelector('#isSuperuser').checked,
|
|
is_active: this.querySelector('#isActive').checked,
|
|
is_2fa_enabled: this.querySelector('#is2faEnabled').checked,
|
|
storage_quota_bytes: parseInt(this.querySelector('#storageQuotaBytes').value),
|
|
plan_type: this.querySelector('#planType').value,
|
|
};
|
|
|
|
try {
|
|
if (userId) {
|
|
await api.updateUser(userId, userData);
|
|
} else {
|
|
await api.createUser(userData);
|
|
}
|
|
this.querySelector('#userModal').style.display = 'none';
|
|
await this.loadUsers(); // Refresh the list
|
|
} catch (error) {
|
|
console.error('Failed to save user:', error);
|
|
alert('Failed to save user: ' + error.message);
|
|
}
|
|
}
|
|
|
|
async _deleteUser(userId) {
|
|
if (!confirm('Are you sure you want to delete this user?')) {
|
|
return;
|
|
}
|
|
try {
|
|
await api.deleteUser(userId);
|
|
await this.loadUsers(); // Refresh the list
|
|
} catch (error) {
|
|
console.error('Failed to delete user:', error);
|
|
alert('Failed to delete user: ' + error.message);
|
|
}
|
|
}
|
|
|
|
renderUser(user) {
|
|
const formatBytes = (bytes) => {
|
|
if (bytes === 0) return '0 Bytes';
|
|
const k = 1024;
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
};
|
|
|
|
return `
|
|
<div class="user-item" data-user-id="${user.id}">
|
|
<span>
|
|
${user.username} (${user.email}) - Superuser: ${user.is_superuser ? 'Yes' : 'No'} - 2FA: ${user.is_2fa_enabled ? 'Yes' : 'No'} - Active: ${user.is_active ? 'Yes' : 'No'} - Storage: ${formatBytes(user.storage_quota_bytes)} - Plan: ${user.plan_type}
|
|
</span>
|
|
<div class="user-actions">
|
|
<button class="button button-small">Edit</button>
|
|
<button class="button button-small button-danger">Delete</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
customElements.define('admin-dashboard', AdminDashboard);
|