Changeset 0.22.10 (#152)
This commit is contained in:
@@ -30,10 +30,22 @@
|
||||
.banner { flex-shrink: 0; }
|
||||
</style>
|
||||
<meta name="theme-color" content="#0e0e10">
|
||||
<script>
|
||||
// Early theme application — prevents flash of wrong theme on all surfaces
|
||||
(function() {
|
||||
try {
|
||||
var p = JSON.parse(localStorage.getItem('cs-appearance') || '{}');
|
||||
var mode = p.theme || 'system';
|
||||
var resolved = mode;
|
||||
if (mode === 'system') resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
if (resolved === 'light') document.documentElement.setAttribute('data-theme', 'light');
|
||||
} catch(e) {}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body data-surface="{{.Surface}}" data-base-path="{{.BasePath}}" data-theme="{{or .Theme "dark"}}">
|
||||
<body data-surface="{{.Surface}}" data-base-path="{{.BasePath}}">
|
||||
{{if .Banner.Visible}}
|
||||
<div class="banner banner-top" style="background:{{.Banner.Background}};color:{{.Banner.Color}};height:var(--banner-h);line-height:var(--banner-h);text-align:center;font-size:12px;font-weight:600;overflow:hidden;">
|
||||
<div class="banner banner-top active" style="background:{{.Banner.Background}};color:{{.Banner.Color}};height:var(--banner-h);line-height:var(--banner-h);text-align:center;font-size:12px;font-weight:600;overflow:hidden;">
|
||||
{{.Banner.Text}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -49,7 +61,7 @@
|
||||
</div>
|
||||
|
||||
{{if .Banner.Visible}}
|
||||
<div class="banner banner-bottom" style="background:{{.Banner.Background}};color:{{.Banner.Color}};height:var(--banner-h);line-height:var(--banner-h);text-align:center;font-size:12px;font-weight:600;overflow:hidden;">
|
||||
<div class="banner banner-bottom active" style="background:{{.Banner.Background}};color:{{.Banner.Color}};height:var(--banner-h);line-height:var(--banner-h);text-align:center;font-size:12px;font-weight:600;overflow:hidden;">
|
||||
{{.Banner.Text}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
|
||||
<div class="auth-tabs anim anim-a2">
|
||||
<button class="auth-tab active" id="tabLogin" onclick="_switchTab('login')">Log In</button>
|
||||
<button class="auth-tab" id="tabRegister" onclick="_switchTab('register')">Register</button>
|
||||
{{if .RegistrationOpen}}<button class="auth-tab" id="tabRegister" onclick="_switchTab('register')">Register</button>{{end}}
|
||||
</div>
|
||||
|
||||
<!-- LOGIN FORM -->
|
||||
@@ -229,6 +229,7 @@
|
||||
</div>
|
||||
|
||||
<!-- REGISTER FORM -->
|
||||
{{if .RegistrationOpen}}
|
||||
<div id="registerForm" style="display:none;">
|
||||
<div class="form-field">
|
||||
<label for="regUsername">Username</label>
|
||||
@@ -249,6 +250,7 @@
|
||||
<p class="auth-error" id="regError" style="display:none;"></p>
|
||||
<button class="btn-login" id="regBtn" onclick="_doRegister()">Create Account</button>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="auth-footer">
|
||||
<p>Self-hosted instance · Your data stays on your infrastructure</p>
|
||||
@@ -272,15 +274,18 @@
|
||||
<script>
|
||||
function _switchTab(tab) {
|
||||
document.getElementById('loginForm').style.display = tab === 'login' ? '' : 'none';
|
||||
document.getElementById('registerForm').style.display = tab === 'register' ? '' : 'none';
|
||||
const regForm = document.getElementById('registerForm');
|
||||
if (regForm) regForm.style.display = tab === 'register' ? '' : 'none';
|
||||
document.getElementById('tabLogin').classList.toggle('active', tab === 'login');
|
||||
document.getElementById('tabRegister').classList.toggle('active', tab === 'register');
|
||||
const regTab = document.getElementById('tabRegister');
|
||||
if (regTab) regTab.classList.toggle('active', tab === 'register');
|
||||
document.getElementById('authTitle').textContent = tab === 'login' ? 'Welcome back' : 'Create account';
|
||||
document.getElementById('authSubtitle').textContent = tab === 'login'
|
||||
? 'Sign in to your Switchboard instance'
|
||||
: 'Join your team on Switchboard';
|
||||
document.getElementById('loginError').textContent = '';
|
||||
document.getElementById('regError').textContent = '';
|
||||
const regErr = document.getElementById('regError');
|
||||
if (regErr) { regErr.textContent = ''; regErr.style.display = 'none'; }
|
||||
}
|
||||
|
||||
async function _doRegister() {
|
||||
@@ -291,10 +296,11 @@
|
||||
const errEl = document.getElementById('regError');
|
||||
const btn = document.getElementById('regBtn');
|
||||
|
||||
if (!username || !password) { errEl.textContent = 'Username and password are required'; return; }
|
||||
if (password.length < 8) { errEl.textContent = 'Password must be at least 8 characters'; return; }
|
||||
if (password !== confirm) { errEl.textContent = 'Passwords do not match'; return; }
|
||||
if (!username || !password) { errEl.textContent = 'Username and password are required'; errEl.style.display = ''; return; }
|
||||
if (password.length < 8) { errEl.textContent = 'Password must be at least 8 characters'; errEl.style.display = ''; return; }
|
||||
if (password !== confirm) { errEl.textContent = 'Passwords do not match'; errEl.style.display = ''; return; }
|
||||
|
||||
errEl.style.display = 'none';
|
||||
errEl.textContent = '';
|
||||
btn.disabled = true; btn.textContent = 'Creating account\u2026';
|
||||
|
||||
@@ -313,7 +319,8 @@
|
||||
if (data.pending) {
|
||||
errEl.textContent = 'Account created — pending admin approval.';
|
||||
errEl.style.color = 'var(--success)';
|
||||
setTimeout(() => { errEl.style.color = ''; _switchTab('login'); }, 3000);
|
||||
errEl.style.display = '';
|
||||
setTimeout(() => { errEl.style.color = ''; errEl.style.display = 'none'; _switchTab('login'); }, 3000);
|
||||
} else {
|
||||
// Auto-login
|
||||
const storageKey = base ? 'sb_auth_' + base.replace(/\//g, '') : 'sb_auth';
|
||||
@@ -325,6 +332,7 @@
|
||||
}
|
||||
} catch (e) {
|
||||
errEl.textContent = e.message;
|
||||
errEl.style.display = '';
|
||||
} finally {
|
||||
btn.disabled = false; btn.textContent = 'Create Account';
|
||||
}
|
||||
@@ -337,7 +345,7 @@
|
||||
document.getElementById('loginUsername').addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') document.getElementById('loginPassword').focus();
|
||||
});
|
||||
document.getElementById('regConfirm').addEventListener('keydown', e => {
|
||||
document.getElementById('regConfirm')?.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') _doRegister();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
Back to Chat
|
||||
</a>
|
||||
<div class="admin-topbar-sep"></div>
|
||||
<span class="admin-topbar-title">🔀 Administration</span>
|
||||
<span class="admin-topbar-title"><img src="{{.BasePath}}/favicon.svg?v={{.Version}}" alt="" width="18" height="18" style="vertical-align: -3px;"> Administration</span>
|
||||
|
||||
{{/* Category tabs */}}
|
||||
<div class="admin-category-tabs" id="adminCategoryTabs">
|
||||
@@ -95,6 +95,133 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Create User modal */}}
|
||||
<div id="createUserModal" class="modal-overlay">
|
||||
<div class="modal" style="max-width:440px;">
|
||||
<div class="modal-header">
|
||||
<h2>Create User</h2>
|
||||
<button class="modal-close" onclick="closeModal('createUserModal')">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group"><label>Username</label><input type="text" id="adminNewUsername" placeholder="username" autocomplete="off"></div>
|
||||
<div class="form-group"><label>Email</label><input type="text" id="adminNewEmail" placeholder="email@example.com" autocomplete="off"></div>
|
||||
<div class="form-group"><label>Password</label><input type="password" id="adminNewPassword" placeholder="min 8 chars" autocomplete="new-password"></div>
|
||||
<div class="form-group"><label>Role</label><select id="adminNewRole"><option value="user">User</option><option value="admin">Admin</option></select></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-md btn-ghost" onclick="closeModal('createUserModal')">Cancel</button>
|
||||
<button class="btn-md btn-primary" id="adminCreateUserBtn">Create User</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Reset Password modal */}}
|
||||
<div id="resetPwModal" class="modal-overlay">
|
||||
<div class="modal" style="max-width:440px;">
|
||||
<div class="modal-header">
|
||||
<h2>Reset Password</h2>
|
||||
<button class="modal-close" onclick="closeModal('resetPwModal')">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p id="resetPwUser" style="font-weight:600;margin-bottom:8px;"></p>
|
||||
<div class="admin-warning" style="background:var(--danger-dim);border:1px solid var(--danger);border-radius:var(--radius);padding:10px 12px;font-size:12px;margin-bottom:12px;color:var(--danger);">
|
||||
<strong>Warning:</strong> This will destroy the user's personal vault. All personal API keys (BYOK) will be permanently deleted.
|
||||
</div>
|
||||
<div class="form-group"><label>New Password</label><input type="password" id="resetPwInput" placeholder="min 8 chars" autocomplete="new-password"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-md btn-ghost" onclick="closeModal('resetPwModal')">Cancel</button>
|
||||
<button class="btn-md btn-danger" id="resetPwConfirmBtn">Reset Password & Destroy Vault</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Approve User modal */}}
|
||||
<div id="approveUserModal" class="modal-overlay">
|
||||
<div class="modal" style="max-width:440px;">
|
||||
<div class="modal-header">
|
||||
<h2 id="approveUserTitle">Approve User</h2>
|
||||
<button class="modal-close" onclick="closeModal('approveUserModal')">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="approveUserId">
|
||||
<div id="approveTeamsList"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-md btn-ghost" onclick="closeModal('approveUserModal')">Cancel</button>
|
||||
<button class="btn-md btn-primary" id="approveUserSubmitBtn">Activate User</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Create Team modal */}}
|
||||
<div id="createTeamModal" class="modal-overlay">
|
||||
<div class="modal" style="max-width:440px;">
|
||||
<div class="modal-header">
|
||||
<h2>Create Team</h2>
|
||||
<button class="modal-close" onclick="closeModal('createTeamModal')">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group"><label>Name</label><input type="text" id="adminTeamName" placeholder="Team name"></div>
|
||||
<div class="form-group"><label>Description</label><input type="text" id="adminTeamDesc" placeholder="Optional description"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-md btn-ghost" onclick="closeModal('createTeamModal')">Cancel</button>
|
||||
<button class="btn-md btn-primary" id="adminCreateTeamBtn">Create Team</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Create Group modal */}}
|
||||
<div id="createGroupModal" class="modal-overlay">
|
||||
<div class="modal" style="max-width:440px;">
|
||||
<div class="modal-header">
|
||||
<h2>Create Group</h2>
|
||||
<button class="modal-close" onclick="closeModal('createGroupModal')">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group"><label>Name</label><input type="text" id="adminGroupName" placeholder="Group name"></div>
|
||||
<div class="form-group"><label>Description</label><input type="text" id="adminGroupDesc" placeholder="Optional description"></div>
|
||||
<div style="display:flex;gap:12px;">
|
||||
<div class="form-group" style="flex:1"><label>Scope</label><select id="adminGroupScope"><option value="global">Global</option><option value="team">Team</option></select></div>
|
||||
<div class="form-group" id="adminGroupTeamRow" style="flex:1;display:none"><label>Team</label><select id="adminGroupTeam"></select></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-md btn-ghost" onclick="closeModal('createGroupModal')">Cancel</button>
|
||||
<button class="btn-md btn-primary" id="adminCreateGroupBtn">Create Group</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Provider form modal */}}
|
||||
<div id="providerFormModal" class="modal-overlay">
|
||||
<div class="modal" style="max-width:520px;">
|
||||
<div class="modal-header">
|
||||
<h2 id="providerFormTitle">Add Provider</h2>
|
||||
<button class="modal-close" onclick="closeModal('providerFormModal')">✕</button>
|
||||
</div>
|
||||
<div class="modal-body" id="adminAddProviderForm"></div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-md btn-ghost" onclick="closeModal('providerFormModal')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Persona form modal */}}
|
||||
<div id="personaFormModal" class="modal-overlay">
|
||||
<div class="modal" style="max-width:520px;">
|
||||
<div class="modal-header">
|
||||
<h2 id="personaFormTitle">Create Persona</h2>
|
||||
<button class="modal-close" onclick="closeModal('personaFormModal')">✕</button>
|
||||
</div>
|
||||
<div class="modal-body" id="adminAddPersonaForm"></div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn-md btn-ghost" onclick="closeModal('personaFormModal')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{/* CSS: loaded via base.html (variables, layout, primitives, modals, chat, panels, surfaces, splash) */}}
|
||||
|
||||
@@ -98,11 +98,11 @@ window.addEventListener('unhandledrejection', function(e) {
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</button>
|
||||
<div id="newChatDropdown" class="split-dropdown">
|
||||
<button class="split-dropdown-item" onclick="document.getElementById('newChatDropdown').classList.remove('open'); newChat();">
|
||||
<button class="split-dropdown-item" onclick="closeNewChatMenu(); newChat();">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
||||
<span>New Chat</span>
|
||||
</button>
|
||||
<button class="split-dropdown-item" onclick="document.getElementById('newChatDropdown').classList.remove('open'); if(typeof createProject==='function') createProject();">
|
||||
<button class="split-dropdown-item" onclick="closeNewChatMenu(); if(typeof createProject==='function') createProject();">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
|
||||
<span>New Project</span>
|
||||
</button>
|
||||
@@ -153,6 +153,11 @@ window.addEventListener('unhandledrejection', function(e) {
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
|
||||
<span class="sb-label">Notes</span>
|
||||
</button>
|
||||
{{/* Editor shortcut */}}
|
||||
<a href="{{.BasePath}}/editor" class="sb-btn sidebar-editor-btn" title="Editor">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
|
||||
<span class="sb-label">Editor</span>
|
||||
</a>
|
||||
<div class="sidebar-bottom-divider"></div>
|
||||
<button id="userMenuBtn" class="user-btn">
|
||||
<div id="userAvatar" class="user-avatar">
|
||||
@@ -594,50 +599,104 @@ window.addEventListener('unhandledrejection', function(e) {
|
||||
|
||||
{{/* ── Team Admin Modal ────────────────────── */}}
|
||||
<div id="teamAdminModal" class="modal-overlay">
|
||||
<div class="modal-content modal-lg">
|
||||
<div class="modal-header">
|
||||
<div class="modal-content modal-lg" style="max-width:900px;height:80vh;display:flex;flex-direction:column;">
|
||||
<div class="modal-header" style="flex-shrink:0;">
|
||||
<h2 id="teamAdminTitle">Team Admin</h2>
|
||||
<button id="teamAdminCloseBtn" class="modal-close">✕</button>
|
||||
</div>
|
||||
<div class="modal-body" style="display:flex;min-height:300px;">
|
||||
<div id="teamAdminPicker" class="admin-sidebar">
|
||||
<div class="modal-body" style="display:flex;flex:1;min-height:0;padding:0;">
|
||||
{{/* Team picker (multi-team admins) */}}
|
||||
<div id="teamAdminPicker" style="padding:20px;flex:1;overflow-y:auto;">
|
||||
<div id="teamAdminPickerList"></div>
|
||||
</div>
|
||||
<div id="teamAdminContent" style="flex:1;overflow-y:auto;padding:16px;">
|
||||
<div id="adminCurrentUser" style="display:none;"></div>
|
||||
<div id="adminTeamDetail" style="display:none;">
|
||||
<h3 id="adminTeamDetailName"></h3>
|
||||
<div id="adminMemberList"></div>
|
||||
<div id="adminAddMemberForm" style="display:none;">
|
||||
<select id="adminMemberUser"></select>
|
||||
</div>
|
||||
<div id="adminTeamAllowProviders" style="display:none;"></div>
|
||||
<div id="adminTeamPrivatePolicy" style="display:none;"></div>
|
||||
|
||||
{{/* Tabbed team management */}}
|
||||
<div id="teamAdminContent" style="display:none;flex:1;display:flex;flex-direction:column;min-width:0;">
|
||||
{{/* Tab bar */}}
|
||||
<div id="teamAdminTabs" style="display:flex;gap:2px;padding:8px 16px;border-bottom:1px solid var(--border);flex-shrink:0;overflow-x:auto;">
|
||||
<button class="admin-tab active" data-ttab="members" onclick="UI.switchTeamTab('members')">Members</button>
|
||||
<button class="admin-tab" data-ttab="providers" onclick="UI.switchTeamTab('providers')">Providers</button>
|
||||
<button class="admin-tab" data-ttab="personas" onclick="UI.switchTeamTab('personas')">Personas</button>
|
||||
<button class="admin-tab" data-ttab="knowledge" onclick="UI.switchTeamTab('knowledge')">Knowledge</button>
|
||||
<button class="admin-tab" data-ttab="groups" onclick="UI.switchTeamTab('groups')">Groups</button>
|
||||
<button class="admin-tab" data-ttab="settings" onclick="UI.switchTeamTab('settings')">Settings</button>
|
||||
<button class="admin-tab" data-ttab="usage" onclick="UI.switchTeamTab('usage')">Usage</button>
|
||||
<button class="admin-tab" data-ttab="activity" onclick="UI.switchTeamTab('activity')">Activity</button>
|
||||
</div>
|
||||
<div id="adminGroupDetail" style="display:none;">
|
||||
<div id="adminGroupDetailMeta"></div>
|
||||
<h3 id="adminGroupDetailName"></h3>
|
||||
<div id="adminGroupList" style="display:none;"></div>
|
||||
<div id="adminGroupMemberList"></div>
|
||||
<div id="adminAddGroupMemberForm" style="display:none;">
|
||||
<select id="adminGroupMemberUser"></select>
|
||||
|
||||
{{/* Tab content panels */}}
|
||||
<div style="flex:1;overflow-y:auto;padding:16px;">
|
||||
{{/* Members */}}
|
||||
<div id="teamTabMembers" class="team-tab-content">
|
||||
<div id="settingsTeamMembers"></div>
|
||||
<div id="settingsTeamAddMember" class="admin-inline-form" style="display:none;margin-top:12px;">
|
||||
<div style="display:flex;gap:8px;align-items:flex-end;">
|
||||
<div class="form-group" style="flex:1"><label>User</label><select id="settingsTeamMemberUser"><option value="">Select user...</option></select></div>
|
||||
<div class="form-group"><label>Role</label><select id="settingsTeamMemberRole"><option value="member">Member</option><option value="admin">Admin</option></select></div>
|
||||
<button class="btn-small btn-primary" id="settingsTeamAddMemberSubmit">Add</button>
|
||||
<button class="btn-small" onclick="document.getElementById('settingsTeamAddMember').style.display='none'">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-small" id="settingsTeamAddMemberBtn" style="margin-top:8px">+ Add Member</button>
|
||||
</div>
|
||||
|
||||
{{/* Providers */}}
|
||||
<div id="teamTabProviders" class="team-tab-content" style="display:none;">
|
||||
<div id="settingsTeamProviders"></div>
|
||||
<div id="settingsTeamProviderForm" style="display:none;margin-top:12px;"></div>
|
||||
<button class="btn-small" id="settingsTeamAddProviderBtn" style="margin-top:8px">+ Add Provider</button>
|
||||
</div>
|
||||
|
||||
{{/* Personas */}}
|
||||
<div id="teamTabPersonas" class="team-tab-content" style="display:none;">
|
||||
<div id="teamPersonaList"></div>
|
||||
<div id="settingsTeamPersonas" style="display:none;"></div>
|
||||
<div style="display:none;"><select id="teamPersona_model"></select></div>
|
||||
</div>
|
||||
|
||||
{{/* Knowledge */}}
|
||||
<div id="teamTabKnowledge" class="team-tab-content" style="display:none;">
|
||||
<div id="teamKBContent"></div>
|
||||
</div>
|
||||
|
||||
{{/* Groups */}}
|
||||
<div id="teamTabGroups" class="team-tab-content" style="display:none;">
|
||||
<div id="settingsTeamGroups"></div>
|
||||
</div>
|
||||
|
||||
{{/* Settings */}}
|
||||
<div id="teamTabSettings" class="team-tab-content" style="display:none;">
|
||||
<div style="max-width:500px;">
|
||||
<div class="form-group" style="margin-bottom:12px;">
|
||||
<label class="toggle-label"><input type="checkbox" id="teamSettingPrivatePolicy"><span class="toggle-track"></span><span>Require private providers (BYOK)</span></label>
|
||||
<div class="toggle-hint">Team members must use their own API keys</div>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom:12px;">
|
||||
<label class="toggle-label"><input type="checkbox" id="teamSettingAllowProviders" checked><span class="toggle-track"></span><span>Allow team providers</span></label>
|
||||
<div class="toggle-hint">Team admins can add shared provider configs</div>
|
||||
</div>
|
||||
<button class="btn-small btn-primary" id="teamSettingSaveBtn">Save Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Usage */}}
|
||||
<div id="teamTabUsage" class="team-tab-content" style="display:none;">
|
||||
<div id="settingsTeamUsageTotals"></div>
|
||||
</div>
|
||||
|
||||
{{/* Activity (Audit) */}}
|
||||
<div id="teamTabActivity" class="team-tab-content" style="display:none;">
|
||||
<div style="margin-bottom:8px;">
|
||||
<select id="teamAuditFilterAction" style="font-size:12px;padding:4px 8px;"><option value="">All actions</option></select>
|
||||
</div>
|
||||
<div id="settingsTeamAudit"></div>
|
||||
<div id="teamAuditPagination" style="display:flex;gap:8px;align-items:center;margin-top:8px;">
|
||||
<button id="teamAuditPrevBtn" class="btn-small" disabled>← Prev</button>
|
||||
<span id="teamAuditPageInfo" class="text-muted" style="font-size:12px;"></span>
|
||||
<button id="teamAuditNextBtn" class="btn-small">Next →</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="adminAddTeamForm" style="display:none;"></div>
|
||||
<div id="adminAddGroupForm" style="display:none;"></div>
|
||||
<div id="adminAddProviderForm" style="display:none;"></div>
|
||||
{{/* Team audit (inside team admin modal) */}}
|
||||
<div id="teamKBContent" style="display:none;"></div>
|
||||
<div style="display:none;">
|
||||
<select id="teamAuditFilterAction"><option value="">All</option></select>
|
||||
<div id="teamAuditPagination" style="display:flex;gap:8px;align-items:center;">
|
||||
<button id="teamAuditPrevBtn" class="btn-small" disabled>←</button>
|
||||
<span id="teamAuditPageInfo"></span>
|
||||
<button id="teamAuditNextBtn" class="btn-small">→</button>
|
||||
</div>
|
||||
</div>
|
||||
{{/* Team persona model select */}}
|
||||
<div style="display:none;"><select id="teamPersona_model"></select></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -89,9 +89,9 @@
|
||||
<div class="settings-section">
|
||||
<h3>Theme</h3>
|
||||
<div id="themeToggle" class="toggle-group">
|
||||
<button class="toggle-btn" data-theme="light">☀ Light</button>
|
||||
<button class="toggle-btn" data-theme="dark">☾ Dark</button>
|
||||
<button class="toggle-btn" data-theme="system">⊞ System</button>
|
||||
<button class="theme-btn" data-theme="light">☀ Light</button>
|
||||
<button class="theme-btn" data-theme="dark">☾ Dark</button>
|
||||
<button class="theme-btn" data-theme="system">⊞ System</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-section">
|
||||
|
||||
Reference in New Issue
Block a user