Changeset 0.24.2 (#158)

This commit is contained in:
2026-03-07 19:58:43 +00:00
parent b6cc4df6e7
commit ea082e2016
24 changed files with 954 additions and 119 deletions

View File

@@ -916,16 +916,94 @@ Object.assign(UI, {
document.getElementById('adminGroupDetailName').textContent = groupName;
document.getElementById('adminAddGroupMemberForm').style.display = 'none';
// Load group details for meta line
// Load group + available permissions + enabled models in parallel
try {
const g = await API.adminGetGroup(groupId);
const [g, permResp, modelsResp] = await Promise.all([
API.adminGetGroup(groupId),
API.adminListPermissions(),
API.listEnabledModels(),
]);
const scope = g.scope === 'global' ? 'Global group' : 'Team-scoped group';
document.getElementById('adminGroupDetailMeta').textContent = `${scope} · ${g.member_count} member${g.member_count !== 1 ? 's' : ''}`;
} catch (e) { /* proceed */ }
// ── Permission checkboxes ──
const allPerms = permResp.permissions || [];
const groupPerms = new Set(g.permissions || []);
const permDesc = {
'model.use': 'Use models for completions',
'model.select_any': 'Use any enabled model',
'kb.read': 'Search knowledge bases',
'kb.write': 'Upload / delete KB documents',
'kb.create': 'Create knowledge bases',
'channel.create': 'Create channels',
'channel.invite': 'Invite users to channels',
'persona.create': 'Create personas',
'persona.manage': 'Edit / delete team personas',
'workflow.create': 'Create workflows',
'admin.view': 'Read-only admin access',
'token.unlimited': 'Bypass token budgets',
};
const permEl = document.getElementById('adminGroupPermissions');
permEl.innerHTML = allPerms.map(p => `<label class="checkbox-label" style="font-size:12px;display:flex;align-items:baseline;gap:6px;margin-bottom:4px">
<input type="checkbox" class="group-perm-cb" value="${esc(p)}" ${groupPerms.has(p) ? 'checked' : ''}>
<span><strong>${esc(p)}</strong> <span class="text-muted">\u2014 ${esc(permDesc[p] || p)}</span></span>
</label>`).join('');
// ── Token budget fields ──
document.getElementById('adminGroupBudgetDaily').value = g.token_budget_daily != null ? g.token_budget_daily : '';
document.getElementById('adminGroupBudgetMonthly').value = g.token_budget_monthly != null ? g.token_budget_monthly : '';
// ── Model allowlist checkboxes ──
const models = (modelsResp.models || []).filter(m => !m.is_persona);
const allowedSet = g.allowed_models ? new Set(g.allowed_models) : null;
const modelEl = document.getElementById('adminGroupModels');
const seen = new Set();
const unique = models.filter(m => { if (seen.has(m.model_id)) return false; seen.add(m.model_id); return true; });
unique.sort((a, b) => a.model_id.localeCompare(b.model_id));
modelEl.innerHTML = unique.map(m => `<label class="checkbox-label" style="font-size:12px;display:flex;align-items:baseline;gap:6px;margin-bottom:4px">
<input type="checkbox" class="group-model-cb" value="${esc(m.model_id)}" ${allowedSet === null || allowedSet.has(m.model_id) ? 'checked' : ''}>
<span>${esc(m.display_name || m.model_id)} <span class="text-muted">${esc(m.provider_name || '')}</span></span>
</label>`).join('') || '<span class="text-muted" style="font-size:12px">No models available</span>';
} catch (e) {
console.error('openGroupDetail:', e);
}
// Wire save button
document.getElementById('adminGroupSavePermsBtn').onclick = () => this._saveGroupPerms(groupId);
await this.loadGroupMembers(groupId);
},
async _saveGroupPerms(groupId) {
const status = document.getElementById('adminGroupSaveStatus');
status.textContent = 'Saving\u2026';
const perms = [...document.querySelectorAll('.group-perm-cb:checked')].map(cb => cb.value);
const dailyRaw = document.getElementById('adminGroupBudgetDaily').value.trim();
const monthlyRaw = document.getElementById('adminGroupBudgetMonthly').value.trim();
const allModelCbs = document.querySelectorAll('.group-model-cb');
const checkedModelCbs = document.querySelectorAll('.group-model-cb:checked');
const allChecked = allModelCbs.length > 0 && checkedModelCbs.length === allModelCbs.length;
const update = { permissions: perms };
if (dailyRaw === '') { update.clear_budget_daily = true; }
else { update.token_budget_daily = parseInt(dailyRaw, 10); }
if (monthlyRaw === '') { update.clear_budget_monthly = true; }
else { update.token_budget_monthly = parseInt(monthlyRaw, 10); }
if (allChecked || allModelCbs.length === 0) { update.clear_allowed_models = true; }
else { update.allowed_models = [...checkedModelCbs].map(cb => cb.value); }
try {
await API.adminUpdateGroup(groupId, update);
status.textContent = 'Saved \u2713';
setTimeout(() => { status.textContent = ''; }, 2000);
} catch (e) {
status.textContent = 'Error: ' + e.message;
}
},
async loadGroupMembers(groupId) {
const el = document.getElementById('adminGroupMemberList');
el.innerHTML = '<div class="loading">Loading...</div>';