164 lines
6.0 KiB
JavaScript
164 lines
6.0 KiB
JavaScript
/* ─────────────────────────────────────────────
|
|
Notification Preferences (v0.20.0 Phase 3)
|
|
Settings → Notifications tab
|
|
───────────────────────────────────────────── */
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
const NotifPrefs = {
|
|
_loaded: false,
|
|
_prefs: [],
|
|
|
|
// Known notification types for the UI
|
|
_types: [
|
|
{ key: 'kb.ready', label: 'Knowledge base ready' },
|
|
{ key: 'kb.error', label: 'Knowledge base error' },
|
|
{ key: 'role.fallback', label: 'Model fallback' },
|
|
{ key: 'grant.changed', label: 'Group membership change' },
|
|
{ key: '*', label: 'Default (all others)' },
|
|
],
|
|
|
|
async load() {
|
|
try {
|
|
this._prefs = await API.listNotifPrefs() || [];
|
|
} catch (e) {
|
|
console.warn('[notif-prefs] failed to load:', e.message);
|
|
this._prefs = [];
|
|
}
|
|
this._loaded = true;
|
|
this.render();
|
|
},
|
|
|
|
render() {
|
|
const container = document.getElementById('notifPrefsBody');
|
|
if (!container) return;
|
|
|
|
const prefMap = {};
|
|
for (const p of this._prefs) {
|
|
prefMap[p.type] = p;
|
|
}
|
|
|
|
let html = '';
|
|
for (const t of this._types) {
|
|
const p = prefMap[t.key];
|
|
const inApp = p ? p.in_app : true;
|
|
const email = p ? p.email : false;
|
|
|
|
html += `<tr class="notif-pref-row" data-type="${esc(t.key)}">
|
|
<td class="notif-pref-label">${esc(t.label)}</td>
|
|
<td class="notif-pref-toggle">
|
|
<label class="checkbox-label">
|
|
<input type="checkbox" class="notif-pref-inapp" ${inApp ? 'checked' : ''}>
|
|
</label>
|
|
</td>
|
|
<td class="notif-pref-toggle">
|
|
<label class="checkbox-label">
|
|
<input type="checkbox" class="notif-pref-email" ${email ? 'checked' : ''}>
|
|
</label>
|
|
</td>
|
|
</tr>`;
|
|
}
|
|
|
|
container.innerHTML = `<table class="notif-pref-table">
|
|
<thead><tr>
|
|
<th>Notification Type</th>
|
|
<th>In-App</th>
|
|
<th>Email</th>
|
|
</tr></thead>
|
|
<tbody>${html}</tbody>
|
|
</table>`;
|
|
|
|
// Attach change listeners
|
|
container.querySelectorAll('.notif-pref-row').forEach(row => {
|
|
const type = row.dataset.type;
|
|
row.querySelector('.notif-pref-inapp').addEventListener('change', (e) => {
|
|
this._save(type, { in_app: e.target.checked });
|
|
});
|
|
row.querySelector('.notif-pref-email').addEventListener('change', (e) => {
|
|
this._save(type, { email: e.target.checked });
|
|
});
|
|
});
|
|
},
|
|
|
|
async _save(type, patch) {
|
|
try {
|
|
await API.setNotifPref(type, patch);
|
|
// Update cache
|
|
const existing = this._prefs.find(p => p.type === type);
|
|
if (existing) {
|
|
Object.assign(existing, patch);
|
|
} else {
|
|
this._prefs.push({ type, in_app: true, email: false, ...patch });
|
|
}
|
|
} catch (e) {
|
|
UI.toast('Failed to save preference', 'error');
|
|
this.render(); // revert checkboxes
|
|
}
|
|
},
|
|
};
|
|
|
|
// ── Admin SMTP UI helpers ───────────────────
|
|
|
|
// Called from index.html onclick
|
|
// eslint-disable-next-line no-unused-vars
|
|
NotifPrefs._testEmail = async function() {
|
|
const status = document.getElementById('smtpTestStatus');
|
|
const btn = document.getElementById('adminSmtpTestBtn');
|
|
if (!status || !btn) return;
|
|
|
|
btn.disabled = true;
|
|
status.textContent = 'Sending…';
|
|
status.className = 'smtp-test-status';
|
|
|
|
try {
|
|
const result = await API.adminTestEmail();
|
|
status.textContent = `✓ Sent to ${result.sent_to}`;
|
|
status.className = 'smtp-test-status success';
|
|
} catch (e) {
|
|
status.textContent = '✗ ' + (e.message || 'Failed');
|
|
status.className = 'smtp-test-status error';
|
|
} finally {
|
|
btn.disabled = false;
|
|
}
|
|
};
|
|
|
|
NotifPrefs._initAdminSmtp = function() {
|
|
const toggle = document.getElementById('adminEmailEnabled');
|
|
const fields = document.getElementById('smtpConfigFields');
|
|
if (!toggle || !fields) return;
|
|
toggle.addEventListener('change', () => {
|
|
fields.style.display = toggle.checked ? '' : 'none';
|
|
});
|
|
};
|
|
|
|
NotifPrefs._loadAdminSmtp = function(cfg) {
|
|
if (!cfg) return;
|
|
const el = (id) => document.getElementById(id);
|
|
if (cfg.email_enabled) el('adminEmailEnabled').checked = true;
|
|
if (cfg.smtp_host) el('adminSmtpHost').value = cfg.smtp_host;
|
|
if (cfg.smtp_port) el('adminSmtpPort').value = cfg.smtp_port;
|
|
if (cfg.smtp_user) el('adminSmtpUser').value = cfg.smtp_user;
|
|
// Don't populate password (security)
|
|
if (cfg.smtp_from) el('adminSmtpFrom').value = cfg.smtp_from;
|
|
if (cfg.smtp_tls != null) el('adminSmtpTls').value = String(cfg.smtp_tls);
|
|
|
|
// Show/hide SMTP fields
|
|
const fields = document.getElementById('smtpConfigFields');
|
|
if (fields) fields.style.display = cfg.email_enabled ? '' : 'none';
|
|
};
|
|
|
|
NotifPrefs._getAdminSmtp = function() {
|
|
const el = (id) => document.getElementById(id);
|
|
const config = {
|
|
email_enabled: el('adminEmailEnabled')?.checked || false,
|
|
smtp_host: el('adminSmtpHost')?.value?.trim() || '',
|
|
smtp_port: parseInt(el('adminSmtpPort')?.value) || 587,
|
|
smtp_user: el('adminSmtpUser')?.value?.trim() || '',
|
|
smtp_from: el('adminSmtpFrom')?.value?.trim() || '',
|
|
smtp_tls: el('adminSmtpTls')?.value === 'true',
|
|
};
|
|
// Only include password if user typed something new
|
|
const pw = el('adminSmtpPassword')?.value;
|
|
if (pw) config.smtp_password = pw;
|
|
return config;
|
|
};
|