Changeset 0.24.2 (#158)
This commit is contained in:
@@ -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>';
|
||||
|
||||
Reference in New Issue
Block a user