Changeset 0.37.12 (#224)
Co-authored-by: gobha <jasafpro@gmail.com> Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
@@ -1,54 +0,0 @@
|
||||
{{/* Admin models — model catalog table. */}}
|
||||
|
||||
{{define "admin-models"}}
|
||||
<div class="admin-page">
|
||||
<h2>Model Catalog</h2>
|
||||
<p class="section-hint">All models synced from providers. Toggle visibility to control what users can access.</p>
|
||||
|
||||
<div class="admin-toolbar">
|
||||
<input type="text" class="admin-search" id="modelSearch" placeholder="Filter models…" oninput="Pages.filterModels(this.value)">
|
||||
<select class="admin-search" style="min-width:120px;" id="modelTypeFilter" onchange="Pages.filterModels()">
|
||||
<option value="">All types</option>
|
||||
<option value="chat">Chat</option>
|
||||
<option value="embedding">Embedding</option>
|
||||
<option value="image">Image</option>
|
||||
</select>
|
||||
<select class="admin-search" style="min-width:140px;" id="modelProviderFilter" onchange="Pages.filterModels()">
|
||||
<option value="">All providers</option>
|
||||
{{range .Data.Providers}}
|
||||
<option value="{{.ID}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{if .Data.Models}}
|
||||
<table class="admin-table" id="modelTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Model</th>
|
||||
<th>Provider</th>
|
||||
<th>Type</th>
|
||||
<th>Capabilities</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Data.Models}}
|
||||
<tr data-provider="{{.ProviderConfigID}}" data-type="{{.ModelType}}" data-name="{{.DisplayName}} {{.ModelID}}">
|
||||
<td>
|
||||
<strong>{{.DisplayName}}</strong>
|
||||
{{if ne .DisplayName .ModelID}}<br><span style="font-size:11px;color:var(--text-tertiary,#666);">{{.ModelID}}</span>{{end}}
|
||||
</td>
|
||||
<td>{{.ProviderName}}</td>
|
||||
<td><span class="admin-badge">{{.ModelType}}</span></td>
|
||||
<td style="font-size:11px;color:var(--text-secondary);">—</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<div class="empty-hint">No models in catalog. Sync a provider to populate.</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,6 +0,0 @@
|
||||
{{define "admin-overview"}}
|
||||
<div class="admin-page">
|
||||
<h2>Admin Overview</h2>
|
||||
<p class="section-hint">System administration. Select a section from the navigation.</p>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,97 +0,0 @@
|
||||
{{/* Admin providers — server-rendered provider list with status. */}}
|
||||
|
||||
{{define "admin-providers"}}
|
||||
<div class="admin-page">
|
||||
<h2>Providers</h2>
|
||||
<p class="section-hint">AI provider configurations. Each provider connects to an API endpoint.</p>
|
||||
|
||||
<div class="admin-toolbar">
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.showProviderForm')">+ Add Provider</button>
|
||||
</div>
|
||||
|
||||
<div id="providerFormWrap" style="display:none;">
|
||||
{{template "admin-provider-form" .}}
|
||||
</div>
|
||||
|
||||
{{if .Data.Providers}}
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Scope</th>
|
||||
<th>Models</th>
|
||||
<th>Endpoint</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Data.ProviderDetails}}
|
||||
<tr>
|
||||
<td><strong>{{.Name}}</strong></td>
|
||||
<td><span class="admin-badge">{{.Provider}}</span></td>
|
||||
<td><span class="admin-badge admin-badge-{{.Scope}}">{{.Scope}}</span></td>
|
||||
<td>{{.ModelCount}}</td>
|
||||
<td style="max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-secondary);">{{.Endpoint}}</td>
|
||||
<td>
|
||||
<button class="btn-small" onclick="sb.call('Pages.syncProvider','{{.ID}}')">Sync</button>
|
||||
<button class="btn-small" onclick="sb.call('Pages.editProvider','{{.ID}}')">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<div class="empty-hint">No providers configured. Add one to get started.</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "admin-provider-form"}}
|
||||
<div class="admin-inline-form" id="providerForm">
|
||||
<h3 style="margin:0 0 12px;font-size:14px;" id="providerFormTitle">Add Provider</h3>
|
||||
<input type="hidden" id="providerFormId" value="">
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="flex:1;min-width:150px;">
|
||||
<label>Name</label>
|
||||
<input type="text" id="providerFormName" placeholder="My OpenAI">
|
||||
</div>
|
||||
<div class="form-group" style="flex:1;min-width:150px;">
|
||||
<label>Type</label>
|
||||
<select id="providerFormType">
|
||||
<option value="">— select —</option>
|
||||
{{range .Data.ProviderTypes}}
|
||||
<option value="{{.ID}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="flex:2;min-width:200px;">
|
||||
<label>Endpoint</label>
|
||||
<input type="text" id="providerFormEndpoint" placeholder="https://api.openai.com/v1">
|
||||
</div>
|
||||
<div class="form-group" style="flex:1;min-width:150px;">
|
||||
<label>API Key</label>
|
||||
<input type="password" id="providerFormKey" placeholder="sk-...">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="flex:1;min-width:150px;">
|
||||
<label>Scope</label>
|
||||
<select id="providerFormScope">
|
||||
<option value="global">Global</option>
|
||||
<option value="team">Team</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="flex:1;min-width:150px;" id="providerFormTeamWrap" style="display:none;">
|
||||
<label>Team</label>
|
||||
{{template "team-select" (dict "FieldName" "providerFormTeamId" "Label" "" "Teams" .Data.Teams "Selected" "" "AllowEmpty" false)}}
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;margin-top:8px;">
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.saveProvider')">Save</button>
|
||||
<button class="btn-small" onclick="sb.call('Pages.hideProviderForm')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,94 +0,0 @@
|
||||
{{/*
|
||||
admin/roles.html — Model Roles configuration page.
|
||||
Fixes bug #1: embedding models now appear via model_type filtering.
|
||||
*/}}
|
||||
{{define "admin-roles"}}
|
||||
<div class="admin-page">
|
||||
<h2>Model Roles</h2>
|
||||
<p class="section-hint">Configure which models serve background tasks. Each role has a primary and optional fallback.</p>
|
||||
|
||||
{{$providers := .Data.Providers}}
|
||||
{{$models := .Data.Models}}
|
||||
|
||||
{{range .Data.Roles}}
|
||||
<section class="settings-section" style="margin-bottom:16px">
|
||||
<h3 style="font-size:14px;margin:0 0 12px;text-transform:capitalize">{{.Name}} Role</h3>
|
||||
<p class="section-hint" style="margin-bottom:12px">
|
||||
{{if eq .Name "utility"}}Summarization, classification, routing — typically a fast, cheap chat model.{{end}}
|
||||
{{if eq .Name "embedding"}}Vector generation for knowledge base search and semantic note search.{{end}}
|
||||
</p>
|
||||
|
||||
{{$roleName := .Name}}
|
||||
{{$filterType := roleFilterType .Name}}
|
||||
{{$primaryProvID := ""}}
|
||||
{{$primaryModelID := ""}}
|
||||
{{$fallbackProvID := ""}}
|
||||
{{$fallbackModelID := ""}}
|
||||
{{if .Primary}}
|
||||
{{$primaryProvID = .Primary.ProviderID}}
|
||||
{{$primaryModelID = .Primary.ModelID}}
|
||||
{{end}}
|
||||
{{if .Fallback}}
|
||||
{{$fallbackProvID = .Fallback.ProviderID}}
|
||||
{{$fallbackModelID = .Fallback.ModelID}}
|
||||
{{end}}
|
||||
|
||||
<div class="role-config" data-role="{{$roleName}}">
|
||||
<div style="margin-bottom:8px">
|
||||
<label style="font-size:12px;color:var(--text-secondary)">Primary</label>
|
||||
<div class="form-row" style="gap:8px;align-items:center;margin-top:4px">
|
||||
<select class="model-provider-select"
|
||||
data-role="{{$roleName}}" data-slot="primary"
|
||||
data-filter-type="{{$filterType}}"
|
||||
onchange="Pages.roleProviderChanged(this)"
|
||||
style="min-width:140px">
|
||||
<option value="">— none —</option>
|
||||
{{range $providers}}
|
||||
<option value="{{.ID}}"{{if eq .ID $primaryProvID}} selected{{end}}>{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<select class="model-model-select"
|
||||
data-role="{{$roleName}}" data-slot="primary"
|
||||
style="min-width:200px">
|
||||
<option value="">— select model —</option>
|
||||
{{range $models}}
|
||||
{{if and (eq .ProviderConfigID $primaryProvID) (or (eq $filterType "") (eq .ModelType $filterType))}}
|
||||
<option value="{{.ModelID}}"{{if eq .ModelID $primaryModelID}} selected{{end}}>{{.DisplayName}}</option>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom:8px">
|
||||
<label style="font-size:12px;color:var(--text-secondary)">Fallback</label>
|
||||
<div class="form-row" style="gap:8px;align-items:center;margin-top:4px">
|
||||
<select class="model-provider-select"
|
||||
data-role="{{$roleName}}" data-slot="fallback"
|
||||
data-filter-type="{{$filterType}}"
|
||||
onchange="Pages.roleProviderChanged(this)"
|
||||
style="min-width:140px">
|
||||
<option value="">— none —</option>
|
||||
{{range $providers}}
|
||||
<option value="{{.ID}}"{{if eq .ID $fallbackProvID}} selected{{end}}>{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<select class="model-model-select"
|
||||
data-role="{{$roleName}}" data-slot="fallback"
|
||||
style="min-width:200px">
|
||||
<option value="">— select model —</option>
|
||||
{{range $models}}
|
||||
{{if and (eq .ProviderConfigID $fallbackProvID) (or (eq $filterType "") (eq .ModelType $filterType))}}
|
||||
<option value="{{.ModelID}}"{{if eq .ModelID $fallbackModelID}} selected{{end}}>{{.DisplayName}}</option>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.saveRole','{{$roleName}}')">Save</button>
|
||||
</div>
|
||||
</section>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,80 +0,0 @@
|
||||
{{/*
|
||||
admin/routing.html — Routing Policy management.
|
||||
Fixes bug #2: team scope uses a proper dropdown, not raw text.
|
||||
*/}}
|
||||
{{define "admin-routing"}}
|
||||
<div class="admin-page">
|
||||
<h2>Routing Policies</h2>
|
||||
<p class="section-hint">Define rules for model selection, cost limits, and team-specific routing.</p>
|
||||
|
||||
<div style="margin-bottom:12px">
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.showRoutingForm')">+ New Policy</button>
|
||||
</div>
|
||||
|
||||
<div id="routingPolicyForm" style="display:none" class="admin-inline-form">
|
||||
<input type="hidden" id="routingPolicyId">
|
||||
<div class="form-row" style="gap:8px">
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>Name</label>
|
||||
<input type="text" id="routingPolicyName" placeholder="e.g. Prefer local provider">
|
||||
</div>
|
||||
<div class="form-group" style="width:80px">
|
||||
<label>Priority</label>
|
||||
<input type="number" id="routingPolicyPriority" value="100" min="0" max="999">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row" style="gap:8px">
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>Type</label>
|
||||
<select id="routingPolicyType">
|
||||
<option value="provider_prefer">Provider Prefer</option>
|
||||
<option value="team_route">Team Route</option>
|
||||
<option value="cost_limit">Cost Limit</option>
|
||||
<option value="model_alias">Model Alias</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>Scope</label>
|
||||
<select id="routingPolicyScope" onchange="Pages.routingScopeChanged(this)">
|
||||
<option value="global">Global</option>
|
||||
<option value="team">Team</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* Team dropdown — shown when scope=team. Pre-populated from server. */}}
|
||||
<div class="form-row" id="routingTeamRow" style="display:none">
|
||||
<div class="form-group" style="flex:1">
|
||||
<label>Team</label>
|
||||
<select id="routingPolicyTeamId">
|
||||
<option value="">— select team —</option>
|
||||
{{range .Data.Teams}}
|
||||
<option value="{{.ID}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Config (JSON)</label>
|
||||
<textarea id="routingPolicyConfig" rows="4" placeholder='{"provider_config_id": "..."}'
|
||||
style="font-family:monospace;"></textarea>
|
||||
</div>
|
||||
<div class="form-row" style="gap:8px">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="routingPolicyActive" checked> Active
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-row" style="gap:8px;margin-top:8px">
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.saveRoutingPolicy')">Save</button>
|
||||
<button class="btn-small" onclick="sb.call('Pages.hideRoutingForm')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="routingPolicyList">
|
||||
{{if not .Data.Policies}}
|
||||
<div class="empty-hint">No routing policies configured.</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,83 +0,0 @@
|
||||
{{/* Admin settings — core system configuration. */}}
|
||||
|
||||
{{define "admin-settings"}}
|
||||
<div class="admin-page">
|
||||
<h2>Settings</h2>
|
||||
<p class="section-hint">Core system configuration. Changes take effect immediately.</p>
|
||||
|
||||
{{/* ── Registration ───────────────────── */}}
|
||||
<div class="settings-section">
|
||||
<h3 style="font-size:14px;margin:0 0 12px;">Registration</h3>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="settRegEnabled"> Allow new user registration
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Default new user state</label>
|
||||
<select id="settRegDefaultState" style="width:180px;">
|
||||
<option value="active">Active immediately</option>
|
||||
<option value="pending">Pending approval</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* ── User Permissions ─────────────────── */}}
|
||||
<div class="settings-section">
|
||||
<h3 style="font-size:14px;margin:0 0 12px;">User Permissions</h3>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="settUserBYOK"> Allow users to add own API keys (BYOK)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="settUserPersonas"> Allow users to create personas
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="settKBDirect"> Allow direct knowledge base access
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* ── Banner ─────────────────────────── */}}
|
||||
<div class="settings-section">
|
||||
<h3 style="font-size:14px;margin:0 0 12px;">Environment Banner</h3>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="settBannerEnabled"> Show banner
|
||||
</label>
|
||||
</div>
|
||||
<div id="bannerFields" style="display:none;">
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="flex:2;min-width:200px;">
|
||||
<label>Text</label>
|
||||
<input type="text" id="settBannerText" placeholder="DEVELOPMENT">
|
||||
</div>
|
||||
<div class="form-group" style="flex:1;min-width:100px;">
|
||||
<label>Background</label>
|
||||
<input type="color" id="settBannerBg" value="#007a33" style="width:60px;height:30px;padding:2px;">
|
||||
</div>
|
||||
<div class="form-group" style="flex:1;min-width:100px;">
|
||||
<label>Text Color</label>
|
||||
<input type="color" id="settBannerFg" value="#ffffff" style="width:60px;height:30px;padding:2px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/* ── System Prompt ──────────────────── */}}
|
||||
<div class="settings-section">
|
||||
<h3 style="font-size:14px;margin:0 0 12px;">Default System Prompt</h3>
|
||||
<div class="form-group">
|
||||
<textarea id="settSystemPrompt" rows="4" style="width:100%;resize:vertical;" placeholder="Optional system prompt applied to all new conversations"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:16px;">
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.saveSettings')">Save Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,62 +0,0 @@
|
||||
{{/* Admin teams — team list with member counts. */}}
|
||||
|
||||
{{define "admin-teams"}}
|
||||
<div class="admin-page">
|
||||
<h2>Teams</h2>
|
||||
<p class="section-hint">Organize users into teams for scoped access to providers, personas, and policies.</p>
|
||||
|
||||
<div class="admin-toolbar">
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.showTeamForm')">+ Create Team</button>
|
||||
</div>
|
||||
|
||||
<div id="teamFormWrap" style="display:none;">
|
||||
<div class="admin-inline-form" id="teamForm">
|
||||
<h3 style="margin:0 0 12px;font-size:14px;" id="teamFormTitle">Create Team</h3>
|
||||
<input type="hidden" id="teamFormId" value="">
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="flex:1;min-width:200px;">
|
||||
<label>Name</label>
|
||||
<input type="text" id="teamFormName" placeholder="Engineering">
|
||||
</div>
|
||||
<div class="form-group" style="flex:2;min-width:250px;">
|
||||
<label>Description</label>
|
||||
<input type="text" id="teamFormDescription" placeholder="Optional description">
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;margin-top:8px;">
|
||||
<button class="btn-small btn-primary" onclick="sb.call('Pages.saveTeam')">Save</button>
|
||||
<button class="btn-small" onclick="sb.call('Pages.hideTeamForm')">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if .Data.Teams}}
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Members</th>
|
||||
<th>Status</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Data.Teams}}
|
||||
<tr>
|
||||
<td><strong>{{.Name}}</strong></td>
|
||||
<td style="color:var(--text-secondary);">{{.Description}}</td>
|
||||
<td>{{.MemberCount}}</td>
|
||||
<td><span class="admin-badge admin-badge-{{if .IsActive}}active{{else}}inactive{{end}}">{{if .IsActive}}active{{else}}inactive{{end}}</span></td>
|
||||
<td>
|
||||
<button class="btn-small" onclick="sb.call('Pages.editTeam','{{.ID}}','{{.Name}}','{{.Description}}')">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<div class="empty-hint">No teams created yet.</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -1,48 +0,0 @@
|
||||
{{/* Admin users — user management table. */}}
|
||||
|
||||
{{define "admin-users"}}
|
||||
<div class="admin-page">
|
||||
<h2>Users</h2>
|
||||
<p class="section-hint">Manage user accounts, roles, and access.</p>
|
||||
|
||||
<div class="admin-toolbar">
|
||||
<input type="text" class="admin-search" id="userSearch" placeholder="Filter users…" oninput="Pages.filterUsers(this.value)">
|
||||
</div>
|
||||
|
||||
{{if .Data.Users}}
|
||||
<table class="admin-table" id="userTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Display Name</th>
|
||||
<th>Role</th>
|
||||
<th>Status</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Data.Users}}
|
||||
<tr data-name="{{.Username}} {{.Email}} {{.DisplayName}}">
|
||||
<td><strong>{{.Username}}</strong></td>
|
||||
<td style="color:var(--text-secondary);">{{.Email}}</td>
|
||||
<td>{{.DisplayName}}</td>
|
||||
<td><span class="admin-badge admin-badge-{{.Role}}">{{.Role}}</span></td>
|
||||
<td><span class="admin-badge admin-badge-{{if .IsActive}}active{{else}}inactive{{end}}">{{if .IsActive}}active{{else}}inactive{{end}}</span></td>
|
||||
<td>
|
||||
<button class="btn-small" onclick="sb.call('Pages.editUserRole','{{.ID}}','{{.Username}}','{{.Role}}')">Role</button>
|
||||
{{if .IsActive}}
|
||||
<button class="btn-small" onclick="sb.call('Pages.toggleUser','{{.ID}}',false)">Disable</button>
|
||||
{{else}}
|
||||
<button class="btn-small" onclick="sb.call('Pages.toggleUser','{{.ID}}',true)">Enable</button>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<div class="empty-hint">No users found.</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -15,7 +15,7 @@
|
||||
{{/* chat.css removed in v0.37.10 — replaced by sw-chat-surface.css + sw-chat-pane.css */}}
|
||||
{{/* panels.css, pane-container.css, chat-pane.css removed in v0.37.10 */}}
|
||||
<link rel="stylesheet" href="{{.BasePath}}/css/surfaces.css?v={{.Version}}">
|
||||
<link rel="stylesheet" href="{{.BasePath}}/css/splash.css?v={{.Version}}">
|
||||
{{/* splash.css removed in v0.37.12 — login is Preact with sw-login.css */}}
|
||||
<link rel="stylesheet" href="{{.BasePath}}/css/sw-primitives.css?v={{.Version}}">
|
||||
<link rel="stylesheet" href="{{.BasePath}}/css/sw-chat-pane.css?v={{.Version}}">
|
||||
<link rel="stylesheet" href="{{.BasePath}}/css/sw-notes-pane.css?v={{.Version}}">
|
||||
@@ -98,18 +98,15 @@
|
||||
should migrate to the Preact SDK (sw/sdk/). */}}
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/events.js?v={{.Version}}"></script>
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/ui-primitives.js?v={{.Version}}"></script>
|
||||
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/vendor/marked.min.js"></script>
|
||||
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/vendor/purify.min.js"></script>
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/ui-format.js?v={{.Version}}"></script>
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/virtual-scroll.js?v={{.Version}}"></script>
|
||||
{{/* marked.min.js + purify.min.js removed from base in v0.37.12 — surfaces load their own copies */}}
|
||||
{{/* ui-format.js, virtual-scroll.js removed in v0.37.12 */}}
|
||||
{{/* ui-core.js + pages.js removed in v0.37.10 */}}
|
||||
{{/* v0.25.0: Component scripts — available on all surfaces */}}
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/user-menu.js?v={{.Version}}"></script>
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/model-selector.js?v={{.Version}}"></script>
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/file-tree.js?v={{.Version}}"></script>
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/code-editor.js?v={{.Version}}"></script>
|
||||
{{/* chat-pane.js + pane-container.js removed in v0.37.10 — see sw/components/chat-pane/ */}}
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/drag-resize.js?v={{.Version}}"></script>
|
||||
{{/* model-selector.js, drag-resize.js removed in v0.37.12 */}}
|
||||
{{/* v0.28.5: SDK — composition layer over globals. Must load after all
|
||||
primitives/components it wraps, before extensions.js. */}}
|
||||
<script type="module" nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/switchboard-sdk.js?v={{.Version}}"></script>
|
||||
|
||||
Reference in New Issue
Block a user