(function () {
'use strict';
const d = window.DBN_DASHBOARD || {};
const apiBase = (d.apiBase || '/api/dashboard') + '/engines.php';
const $context = document.getElementById('engContext');
const $tier = document.getElementById('engTierPanel');
const $persona = document.getElementById('engPersonaPanel');
const $refresh = document.getElementById('engRefresh');
const safe = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&':'&','<':'<','>':'>','"':'"' }[c]));
let tierEngines = [];
let reviewerModels = [];
function optionsHtml(list, selected) {
return list.map(o =>
''
).join('');
}
function toolLabel(row) {
if (row.tool_slug === '*') {
return row.scope.indexOf('persona') === 0 ? 'All personas' : 'All tier tools';
}
return row.tool_slug;
}
function rowHtml(row, list) {
const list2 = list;
const sel = row.override || row.code_default;
const badge = row.override
? 'override'
: 'default';
const meta = row.override && row.updated_by
? '
by ' + safe(row.updated_by) + (row.updated_at ? ' · ' + safe(row.updated_at) : '') + '
'
: '';
return '' +
'
' + safe(toolLabel(row)) + '' +
'
default: ' + safe(row.code_default || '—') + '
' + meta + '
' +
'
' + safe(row.scope) + '
' +
'
' +
'
' + badge +
(row.override ? '' : '') +
'
' +
'
';
}
function headHtml() {
return '';
}
function render(data) {
tierEngines = data.tier_engines || [];
reviewerModels = data.reviewer_models || [];
const ctx = data.context || {};
$context.innerHTML = 'Bedrock: ' + (ctx.bedrock_enabled ? 'ON' : 'OFF') + ' — ' + safe(ctx.note || '');
const rows = data.rows || [];
const tierRows = rows.filter(r => r.scope.indexOf('persona') !== 0);
const personaRows = rows.filter(r => r.scope.indexOf('persona') === 0);
$tier.innerHTML = headHtml() + tierRows.map(r => rowHtml(r, tierEngines)).join('');
$persona.innerHTML = headHtml() + personaRows.map(r => rowHtml(r, reviewerModels)).join('');
bind($tier);
bind($persona);
}
function bind(panel) {
panel.querySelectorAll('.eng-row').forEach(rowEl => {
const tool = rowEl.getAttribute('data-tool');
const scope = rowEl.getAttribute('data-scope');
const select = rowEl.querySelector('.eng-select');
const clearBtn = rowEl.querySelector('.eng-clear');
if (select) {
select.addEventListener('change', () => save(tool, scope, select.value, rowEl));
}
if (clearBtn) {
clearBtn.addEventListener('click', () => clear(tool, scope, rowEl));
}
});
}
function setBusy(rowEl, busy) {
rowEl.querySelectorAll('select, button').forEach(el => { el.disabled = busy; });
}
async function post(action, body) {
const r = await fetch(apiBase + '?action=' + action, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const data = await r.json();
if (!data.ok) throw new Error(data.message || 'Request failed');
return data;
}
async function save(tool, scope, engine, rowEl) {
setBusy(rowEl, true);
try {
await post('set', { tool_slug: tool, scope: scope, engine: engine });
await load();
} catch (e) {
alert('Could not save: ' + e.message);
setBusy(rowEl, false);
}
}
async function clear(tool, scope, rowEl) {
setBusy(rowEl, true);
try {
await post('clear', { tool_slug: tool, scope: scope });
await load();
} catch (e) {
alert('Could not clear: ' + e.message);
setBusy(rowEl, false);
}
}
async function load() {
$tier.innerHTML = '';
$persona.innerHTML = '';
try {
const r = await fetch(apiBase, { credentials: 'same-origin' });
const data = await r.json();
if (!data.ok) throw new Error(data.message || 'Could not load engine map');
render(data);
} catch (e) {
$context.textContent = 'Could not load: ' + e.message;
$tier.innerHTML = '';
$persona.innerHTML = '';
}
}
if ($refresh) $refresh.addEventListener('click', load);
load();
})();