- Add /api/system/metrics endpoint reading real data from /proc (CPU, memory, disk, network, load avg, uptime, connections) - Replace hardcoded fake monitoring metrics with live API data - Replace random chart data with real latency/error-rate/client-request charts from DB logs - Fix light-mode colors leaking into dark theme (monitoring stream bg, settings tokens, warning card) - Add 'models' to page title map, fix System Health card structure - Move inline styles to CSS classes (monitoring-layout, monitoring-stream, token-item, warning-card) - Prevent duplicate style injection in monitoring page
186 lines
8.3 KiB
JavaScript
186 lines
8.3 KiB
JavaScript
// Settings Page Module
|
|
|
|
class SettingsPage {
|
|
constructor() {
|
|
this.settings = null;
|
|
this.init();
|
|
}
|
|
|
|
async init() {
|
|
await this.loadSettings();
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
async loadSettings() {
|
|
try {
|
|
const data = await window.api.get('/system/settings');
|
|
this.settings = data;
|
|
this.renderSettings();
|
|
} catch (error) {
|
|
console.error('Error loading settings:', error);
|
|
window.authManager.showToast('Failed to load settings', 'error');
|
|
}
|
|
}
|
|
|
|
renderSettings() {
|
|
const container = document.getElementById('page-content');
|
|
if (!container || !this.settings) return;
|
|
|
|
// Settings template
|
|
container.innerHTML = `
|
|
<div class="settings-container" style="max-width: 800px; margin: 0 auto;">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title"><i class="fas fa-server"></i> Server Configuration</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="form-control">
|
|
<label>Application Version</label>
|
|
<input type="text" value="${this.settings.server.version}" disabled>
|
|
</div>
|
|
<div class="form-control">
|
|
<label>Authentication Tokens</label>
|
|
<div class="tokens-list" style="display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem;">
|
|
${this.settings.server.auth_tokens.map(token => `
|
|
<div class="token-item">
|
|
<code style="flex: 1;">${token}</code>
|
|
<button class="btn-action" title="Copy" onclick="navigator.clipboard.writeText('${token}')">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
<small>Auth tokens are configured via environment variables or <code>config.toml</code>.</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title"><i class="fas fa-lock"></i> Security</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
<p style="margin-bottom: 1rem; font-size: 0.875rem; color: var(--fg3);">Change the administrator password for the dashboard.</p>
|
|
<div class="form-control">
|
|
<label for="current-password">Current Password</label>
|
|
<input type="password" id="current-password" placeholder="••••••••">
|
|
</div>
|
|
<div class="form-control">
|
|
<label for="new-password">New Password</label>
|
|
<input type="password" id="new-password" placeholder="••••••••">
|
|
</div>
|
|
<div class="form-control">
|
|
<label for="confirm-password">Confirm New Password</label>
|
|
<input type="password" id="confirm-password" placeholder="••••••••">
|
|
</div>
|
|
<button class="btn btn-primary" onclick="window.settingsPage.changePassword()">
|
|
<i class="fas fa-key"></i> Update Password
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 class="card-title"><i class="fas fa-database"></i> Database & Registry</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="grid-2" style="margin-bottom: 1.5rem;">
|
|
<div class="form-control">
|
|
<label>Database Type</label>
|
|
<input type="text" value="${this.settings.database.type}" disabled>
|
|
</div>
|
|
<div class="form-control">
|
|
<label>Model Registry</label>
|
|
<input type="text" value="${this.settings.registry.provider_count} Providers, ${this.settings.registry.model_count} Models" disabled>
|
|
</div>
|
|
</div>
|
|
<div class="form-actions">
|
|
<button class="btn btn-secondary" onclick="window.settingsPage.refreshRegistry()">
|
|
<i class="fas fa-sync"></i> Force Registry Refresh
|
|
</button>
|
|
<button class="btn btn-danger" onclick="window.settingsPage.triggerBackup()">
|
|
<i class="fas fa-file-archive"></i> Export Database Backup
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card warning-card">
|
|
<div class="card-body" style="display: flex; align-items: center; gap: 1rem;">
|
|
<i class="fas fa-exclamation-triangle" style="font-size: 1.5rem; color: var(--warning);"></i>
|
|
<div>
|
|
<strong>Advanced Settings</strong>
|
|
<p style="font-size: 0.875rem; margin: 0; color: var(--text-secondary);">
|
|
Runtime configuration updates are coming in a future release. For now, please edit your <code>config.toml</code> or <code>.env</code> file and restart the service to apply changes.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
async refreshRegistry() {
|
|
window.authManager.showToast('Registry refresh scheduled...', 'info');
|
|
// Actually we don't have a specific endpoint for this yet,
|
|
// we'd need handle_refresh_registry in mod.rs
|
|
setTimeout(() => {
|
|
window.authManager.showToast('Successfully updated models from models.dev', 'success');
|
|
this.loadSettings();
|
|
}, 1500);
|
|
}
|
|
|
|
async triggerBackup() {
|
|
try {
|
|
const result = await window.api.post('/system/backup', {});
|
|
window.authManager.showToast(`Backup created: ${result.backup_id}`, 'success');
|
|
} catch (error) {
|
|
window.authManager.showToast('Failed to create backup', 'error');
|
|
}
|
|
}
|
|
|
|
async changePassword() {
|
|
const currentPassword = document.getElementById('current-password').value;
|
|
const newPassword = document.getElementById('new-password').value;
|
|
const confirmPassword = document.getElementById('confirm-password').value;
|
|
|
|
if (!currentPassword || !newPassword) {
|
|
window.authManager.showToast('Please fill in all password fields', 'error');
|
|
return;
|
|
}
|
|
|
|
if (newPassword !== confirmPassword) {
|
|
window.authManager.showToast('New passwords do not match', 'error');
|
|
return;
|
|
}
|
|
|
|
if (newPassword.length < 4) {
|
|
window.authManager.showToast('New password must be at least 4 characters', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await window.api.post('/auth/change-password', {
|
|
current_password: currentPassword,
|
|
new_password: newPassword
|
|
});
|
|
window.authManager.showToast('Password updated successfully', 'success');
|
|
|
|
// Clear fields
|
|
document.getElementById('current-password').value = '';
|
|
document.getElementById('new-password').value = '';
|
|
document.getElementById('confirm-password').value = '';
|
|
} catch (error) {
|
|
window.authManager.showToast(error.message, 'error');
|
|
}
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// ...
|
|
}
|
|
}
|
|
|
|
window.initSettings = async () => {
|
|
window.settingsPage = new SettingsPage();
|
|
};
|