agentic-os/dashboard/pages/settings.js

184 lines
8.6 KiB
JavaScript

async function renderSettings() {
const content = document.getElementById('pageContent');
content.innerHTML = `
<div class="page-header">
<div class="page-header-left">
<h1 class="page-title">Settings</h1>
<p class="page-subtitle">Configure Agentic OS behavior</p>
</div>
<button class="btn btn-primary" onclick="saveAllSettings()">💾 Save All</button>
</div>
<div id="settingsForm"><div class="loading"><div class="loading-spinner"></div></div></div>
`;
try {
const settings = await api.getSettings();
const prefs = settings.agent_preferences || {};
const dashboard = settings.dashboard || {};
const limits = settings.free_tier_limits || {};
const apiKeys = settings.api_keys || {};
document.getElementById('settingsForm').innerHTML = `
<div class="card">
<div class="card-header"><span class="card-title">🤖 Agent Preferences</span></div>
<div class="grid grid-3">
${['opencode', 'hermes', 'agy'].map(a => `
<div class="card" style="padding:14px">
<div class="flex items-center gap-2 mb-2">
<div class="agent-dot ${prefs[a] && prefs[a].enabled !== false ? 'online' : 'offline'}" style="width:10px;height:10px"></div>
<strong style="font-size:13px">${a}</strong>
</div>
<label class="switch" style="margin:8px 0">
<input type="checkbox" id="agent_${a}" ${prefs[a] && prefs[a].enabled !== false ? 'checked' : ''} onchange="toggleAgent('${a}')">
<span class="switch-slider"></span>
</label>
<div class="form-group" style="margin-bottom:0;margin-top:8px">
<label class="form-label">Binary Path</label>
<input id="bin_${a}" class="form-input" value="${escapeHtml((prefs[a] && prefs[a].binary) || a)}" style="font-size:12px">
</div>
</div>
`).join('')}
</div>
</div>
<div class="card">
<div class="card-header"><span class="card-title">🎨 Dashboard</span></div>
<div class="form-row">
<div class="form-group">
<label class="form-label">Port</label>
<input id="setPort" class="form-input" type="number" value="${dashboard.port || 8080}">
</div>
<div class="form-group">
<label class="form-label">Host</label>
<input id="setHost" class="form-input" value="${escapeHtml(dashboard.host || '127.0.0.1')}">
</div>
</div>
<div class="form-group">
<label class="switch" style="width:auto;display:flex;align-items:center;gap:10px">
<input type="checkbox" id="setDarkMode" ${dashboard.dark_mode !== false ? 'checked' : ''}>
<span class="switch-slider" style="position:relative;display:inline-block;width:40px;height:22px"></span>
<span style="font-size:13px">Dark Mode</span>
</label>
</div>
</div>
<div class="card">
<div class="card-header"><span class="card-title">🔑 API Keys</span></div>
<div class="form-row">
<div class="form-group">
<label class="form-label">Gemini API Key</label>
<input id="keyGemini" class="form-input" type="password" value="${escapeHtml(apiKeys.gemini || '')}" placeholder="Enter Gemini API key">
</div>
<div class="form-group">
<label class="form-label">OpenRouter API Key</label>
<input id="keyOpenrouter" class="form-input" type="password" value="${escapeHtml(apiKeys.openrouter || '')}" placeholder="Enter OpenRouter API key">
</div>
</div>
</div>
<div class="card">
<div class="card-header"><span class="card-title">💰 Free Tier Limits</span></div>
<div class="form-row">
<div class="form-group">
<label class="form-label">Gemini Flash — Requests/Day</label>
<input id="limGReqs" class="form-input" type="number" value="${(limits.gemini_flash && limits.gemini_flash.requests_per_day) || 1500}">
</div>
<div class="form-group">
<label class="form-label">Gemini Flash — Tokens/Day</label>
<input id="limGTokens" class="form-input" type="number" value="${(limits.gemini_flash && limits.gemini_flash.tokens_per_day) || 1000000}">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">OpenRouter Free — Requests/Day</label>
<input id="limORReqs" class="form-input" type="number" value="${(limits.openrouter_free && limits.openrouter_free.requests_per_day) || 100}">
</div>
<div class="form-group">
<label class="form-label">OpenRouter Free — Tokens/Day</label>
<input id="limORTokens" class="form-input" type="number" value="${(limits.openrouter_free && limits.openrouter_free.tokens_per_day) || 200000}">
</div>
</div>
</div>
<div class="card" style="border-color:var(--red)">
<div class="card-header"><span class="card-title" style="color:var(--red)">⚠ Danger Zone</span></div>
<p style="font-size:13px;color:var(--text-secondary);margin-bottom:12px">Reset all settings to factory defaults.</p>
<button class="btn btn-danger" onclick="resetSettings()">Reset to Defaults</button>
</div>
`;
} catch (err) {
document.getElementById('settingsForm').innerHTML = `<div class="empty-state"><div class="empty-state-icon">⚠</div><div class="empty-state-title">${escapeHtml(err.message)}</div></div>`;
}
}
function toggleAgent(name) {
const cb = document.getElementById(`agent_${name}`);
const card = cb.closest('.card');
const dot = card.querySelector('.agent-dot');
dot.className = `agent-dot ${cb.checked ? 'online' : 'offline'}`;
}
async function saveAllSettings() {
try {
const settings = {
agent_preferences: {
opencode: { enabled: document.getElementById('agent_opencode').checked, binary: document.getElementById('bin_opencode').value },
hermes: { enabled: document.getElementById('agent_hermes').checked, binary: document.getElementById('bin_hermes').value },
agy: { enabled: document.getElementById('agent_agy').checked, binary: document.getElementById('bin_agy').value },
},
dashboard: {
port: parseInt(document.getElementById('setPort').value) || 8080,
host: document.getElementById('setHost').value || '127.0.0.1',
dark_mode: document.getElementById('setDarkMode').checked,
},
api_keys: {
gemini: document.getElementById('keyGemini').value,
openrouter: document.getElementById('keyOpenrouter').value,
},
free_tier_limits: {
gemini_flash: {
requests_per_day: parseInt(document.getElementById('limGReqs').value) || 1500,
tokens_per_day: parseInt(document.getElementById('limGTokens').value) || 1000000,
},
openrouter_free: {
requests_per_day: parseInt(document.getElementById('limORReqs').value) || 100,
tokens_per_day: parseInt(document.getElementById('limORTokens').value) || 200000,
},
},
};
await api.updateSettings(settings);
showToast('Settings saved successfully', 'success');
} catch (err) {
showToast(`Error: ${err.message}`, 'error');
}
}
async function resetSettings() {
showModal('Reset to Defaults', `
<div class="card" style="background:var(--red-dim);border-color:transparent">
<div class="flex items-center gap-2"><span style="font-size:18px">⚠</span><div><strong style="font-size:13px">Warning</strong><div style="font-size:12px;color:var(--text-secondary);margin-top:2px">This will reset all settings to factory defaults and cannot be undone.</div></div></div>
</div>
`, `
<button class="btn btn-ghost" onclick="closeModal()">Cancel</button>
<button class="btn btn-danger" onclick="confirmReset()">Reset</button>
`);
}
async function confirmReset() {
const defaults = {
theme: 'dark',
agent_preferences: { opencode: { enabled: true, binary: 'opencode' }, hermes: { enabled: true, binary: 'hermes' }, agy: { enabled: true, binary: 'agy' } },
dashboard: { port: 8080, host: '127.0.0.1', dark_mode: true },
api_keys: { gemini: '', openrouter: '' },
free_tier_limits: { gemini_flash: { requests_per_day: 1500, tokens_per_day: 1000000 }, openrouter_free: { requests_per_day: 100, tokens_per_day: 200000 } },
};
try {
await api.updateSettings(defaults);
closeModal();
showToast('Settings reset to defaults', 'success');
renderSettings();
} catch (err) {
showToast(`Error: ${err.message}`, 'error');
}
}