// ==========================================
// Chat Switchboard - Admin Surface Scaffold
// ==========================================
// Injects section-specific DOM into adminDynamic, wires listeners,
// and calls the appropriate ADMIN_LOADERS[section]() from ui-admin.js.
// Loaded only on the admin surface (/admin/:section).
(function() {
'use strict';
// Each admin section loader (ui-admin.js) expects specific container
// elements. SCAFFOLDING maps section name -> HTML to inject before
// the loader runs.
var SCAFFOLDING = {};
// -- People -----------------------------------------------------------
SCAFFOLDING.users =
'
';
SCAFFOLDING.teams =
'
' +
'' +
'
' +
'← Back ' +
'
' +
'' +
'
' +
'Require private providers (BYOK) ' +
'Allow team providers ' +
'
' +
'
' +
'
' +
'
+ Add Member ' +
'
';
SCAFFOLDING.groups =
'
' +
'' +
'
' +
'← Back ' +
'
' +
' ' +
'' +
/* ── Permissions (v0.24.2) ── */
'
' +
'
Permissions ' +
'
' +
'
' +
/* ── Token Budgets ── */
'
' +
'
Token Budgets ' +
'
' +
'
' +
/* ── Model Allowlist ── */
'
' +
'
Allowed Models ' +
'
Leave empty for unrestricted access to all enabled models.
' +
'
' +
'
' +
/* ── Save button ── */
'
' +
'Save Permissions & Budgets ' +
' ' +
'
' +
'
' +
/* ── Members (existing) ── */
'
Members ' +
'
' +
'
' +
'
+ Add Member ' +
'
';
// -- AI ---------------------------------------------------------------
SCAFFOLDING.providers =
'
';
SCAFFOLDING.models =
'' +
'Fetch Models ' +
' ' +
'
' +
'
';
SCAFFOLDING.personas =
'
';
SCAFFOLDING.roles = '
';
SCAFFOLDING.knowledgeBases = '
';
SCAFFOLDING.memory = '
';
// -- System -----------------------------------------------------------
SCAFFOLDING.settings =
'';
SCAFFOLDING.storage = '
';
SCAFFOLDING.extensions =
'
' +
'';
// -- Routing ----------------------------------------------------------
SCAFFOLDING.health =
'
' +
'
';
SCAFFOLDING.routing =
'+ New Policy
' +
'
' +
'
' +
'Test Routing ' +
'
' +
'
' +
'
';
SCAFFOLDING.capabilities =
'';
// -- Monitoring -------------------------------------------------------
SCAFFOLDING.usage =
'
' +
'
' +
'
' +
'
' +
'
';
SCAFFOLDING.audit =
'' +
'' +
'';
SCAFFOLDING.stats =
'';
SCAFFOLDING.channels =
'' +
'';
SCAFFOLDING.surfaces =
'
';
// === Add button actions ==============================================
var ADD_ACTIONS = {
users: function() {
openModal('createUserModal');
var n = document.getElementById('adminNewUsername');
if (n) n.focus();
},
teams: function() {
openModal('createTeamModal');
var n = document.getElementById('adminTeamName');
if (n) n.focus();
},
providers: function() {
if (typeof UI !== 'undefined' && UI._adminProvForm) UI._adminProvForm.setCreateMode();
document.getElementById('providerFormTitle').textContent = 'Add Provider';
openModal('providerFormModal');
},
personas: function() {
if (typeof ensureAdminPersonaForm === 'function') {
var form = ensureAdminPersonaForm();
if (form) { form.setSubmitLabel('Create'); form.clearForm(); }
}
document.getElementById('personaFormTitle').textContent = 'Create Persona';
openModal('personaFormModal');
},
groups: function() {
openModal('createGroupModal');
var n = document.getElementById('adminGroupName');
if (n) n.focus();
},
extensions: function() {
var f = document.getElementById('adminInstallExtForm');
if (f) f.style.display = f.style.display === 'none' ? '' : 'none';
},
};
// === Init on DOMContentLoaded ========================================
document.addEventListener('DOMContentLoaded', function() {
var el = document.getElementById('adminContentBody');
if (!el) return;
var section = el.dataset.section;
if (!section) return;
// -- Category / nav resolution -----------
// Derive from ADMIN_SECTIONS + ADMIN_LABELS (ui-admin.js) — single source of truth.
// admin-scaffold.js previously had its own duplicate catMap/secMap.
var cat = 'people';
if (typeof ADMIN_SECTIONS !== 'undefined') {
for (var c in ADMIN_SECTIONS) {
if (ADMIN_SECTIONS[c].indexOf(section) !== -1) { cat = c; break; }
}
}
var secMap;
if (typeof ADMIN_SECTIONS !== 'undefined' && typeof ADMIN_LABELS !== 'undefined') {
secMap = {};
for (var c in ADMIN_SECTIONS) {
secMap[c] = ADMIN_SECTIONS[c].map(function(id) {
return { id: id, l: ADMIN_LABELS[id] || id };
});
}
}
// Rebuild left nav for current category
var navEl = document.getElementById('adminNav');
var base = window.__BASE__ || '';
if (navEl && secMap[cat]) {
navEl.innerHTML = secMap[cat].map(function(s) {
return '' + s.l + ' ';
}).join('');
}
// Update section title
var titleEl = document.getElementById('adminSectionTitle');
var curSec = secMap[cat] && secMap[cat].find(function(s) { return s.id === section; });
if (titleEl && curSec) titleEl.textContent = curSec.l;
// -- Inject scaffolding ------------------
var target = document.getElementById('adminDynamic');
if (target && SCAFFOLDING[section]) {
target.innerHTML = SCAFFOLDING[section];
} else if (target) {
target.innerHTML = 'Section: ' + section + '
';
}
// -- Show/wire Add button for sections that have one --
var addBtn = document.getElementById('adminAddBtn');
if (addBtn && ADD_ACTIONS[section]) {
addBtn.style.display = '';
addBtn.addEventListener('click', ADD_ACTIONS[section]);
}
// -- Wire install extension cancel -------
var extCancel = document.getElementById('adminInstallExtCancelBtn');
if (extCancel) {
extCancel.addEventListener('click', function() {
document.getElementById('adminInstallExtForm').style.display = 'none';
});
}
// -- Wire admin-handlers.js listeners (uses ?. so missing elements are safe) --
if (typeof _initAdminListeners === 'function') _initAdminListeners();
// -- Wire settings toggle show/hide listeners (banner, compaction, etc.) --
if (typeof _initAdminSettingsToggles === 'function') _initAdminSettingsToggles();
// -- Call the section data loader --------
if (typeof ADMIN_LOADERS !== 'undefined' && ADMIN_LOADERS[section]) {
ADMIN_LOADERS[section]();
}
});
})();