Sync cezen-portal/ from live working copy (V1.0 GA polish + search-icon ordering fix)
Brings the ISO-packaged portal copy current with the live cezen-portal/ working directory, which had drifted across the entire V1.0 GA polish initiative (Phases 1-10) plus this session's topnav icon-order bugfix. - 52 existing files updated, 2 new pages added (about.html, health.html) - cgit/cezen-portal/ is now byte-identical to cezen-portal/ - Backend files (rag_ingest.py, cezen_license.py) already in sync; main.py intentionally left as-is (cgit is ahead there with workstation-category commercial-fit logic not yet backported to the live working copy) Next: rebuild the ISO (bash autoinstall/build-iso.sh) to bake this in.
This commit is contained in:
1 parent
7540da04a8
commit
b3eec34158
57 files changed
+2832
-1354
No files matched your search
+27
-19
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Knowledge Base — Nexus One AI</title>
|
||||
<link rel="stylesheet" href="style.css?v=4">
|
||||
<link rel="stylesheet" href="style.css?v=12">
|
||||
<style>
|
||||
/* ── Shared ───────────────────────────────────────────────── */
|
||||
.kb-card { background:var(--navy2); border:1px solid var(--bdr); border-radius:14px; padding:28px; margin-bottom:28px; }
|
||||
@@ -139,6 +139,7 @@
|
||||
<a href="dashboard.html">Dashboard</a>
|
||||
<a href="analytics.html">Usage Analytics</a>
|
||||
<a href="audit.html">Governance & Audit</a>
|
||||
<a href="health.html">Health Center</a>
|
||||
<a href="feedback.html">Feedback & Ratings</a>
|
||||
<span class="nav-drop-cat">MANAGE /</span>
|
||||
<a href="users.html">Users</a>
|
||||
@@ -178,7 +179,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<a href="notifications.html" style="position:relative">🔔</a>
|
||||
<a href="notifications.html" class="nav-icon-btn" style="position:relative" aria-label="Notifications"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M15 17h5l-1.4-1.4A2 2 0 0 1 18 14.2V11a6 6 0 1 0-12 0v3.2a2 2 0 0 1-.6 1.4L4 17h5"/><path d="M10 17a2 2 0 0 0 4 0"/></svg></span></a>
|
||||
<span class="badge" data-brand="tier">Basic Tier</span>
|
||||
<div id="nav-org-logo" class="nav-org-logo"></div>
|
||||
</header>
|
||||
@@ -213,12 +214,13 @@
|
||||
|
||||
<!-- ── 1. Collections ── -->
|
||||
<div class="kb-card">
|
||||
<div class="kb-card-title">📚 Collections</div>
|
||||
<div class="kb-card-title">Collections</div>
|
||||
<div class="kb-card-sub">A collection is a named group of documents that can be queried together. Create one per topic, department, or project.</div>
|
||||
|
||||
<div class="kb-toolbar">
|
||||
<button class="kb-btn primary" onclick="openCreateCollection()">+ New Collection</button>
|
||||
<button class="kb-btn ghost" onclick="loadCollections()">↺ Refresh</button>
|
||||
<button class="kb-btn ghost" onclick="loadCollections()">Refresh</button>
|
||||
<input type="text" id="col-filter" placeholder="Filter collections…" oninput="renderCollections()" style="margin-left:auto;padding:8px 10px;border:1px solid var(--bdr);border-radius:7px;font-size:12.5px;font-family:inherit;min-width:200px">
|
||||
</div>
|
||||
|
||||
<div class="col-grid" id="col-grid">
|
||||
@@ -229,14 +231,14 @@
|
||||
<!-- ── 2. Documents (shown when a collection is selected) ── -->
|
||||
<div class="kb-card docs-section" id="docs-section">
|
||||
<div class="docs-header">
|
||||
<span class="back-btn" onclick="deselectCollection()">← All collections</span>
|
||||
<span class="back-btn" onclick="deselectCollection()">All collections</span>
|
||||
<h3 id="docs-col-name">Documents</h3>
|
||||
<span id="docs-col-stats" style="font-size:12px;color:var(--lt)"></span>
|
||||
</div>
|
||||
|
||||
<div class="upload-zone" id="upload-zone" onclick="document.getElementById('file-input').click()">
|
||||
<input type="file" id="file-input" accept=".pdf,.txt,.md,.docx,.doc,.csv" multiple onchange="uploadFiles(this.files)">
|
||||
<div class="uz-icon">📄</div>
|
||||
<div class="uz-icon">Docs</div>
|
||||
<div class="uz-label">Click or drag to upload documents</div>
|
||||
<div class="uz-hint">.pdf · .docx · .txt · .md · .csv — max 200 MB each</div>
|
||||
</div>
|
||||
@@ -244,7 +246,7 @@
|
||||
|
||||
<div style="margin-top:20px;">
|
||||
<div class="kb-toolbar">
|
||||
<button class="kb-btn ghost" onclick="loadDocuments(selectedColId)">↺ Refresh</button>
|
||||
<button class="kb-btn ghost" onclick="loadDocuments(selectedColId)">Refresh</button>
|
||||
<span id="doc-auto-refresh" style="font-size:12px;color:var(--lt)"></span>
|
||||
</div>
|
||||
<div class="kb-table-wrap">
|
||||
@@ -262,7 +264,7 @@
|
||||
|
||||
<!-- ── 3. Query Tester ── -->
|
||||
<div class="kb-card">
|
||||
<div class="kb-card-title">🔍 Query Tester</div>
|
||||
<div class="kb-card-title">Query Tester</div>
|
||||
<div class="kb-card-sub">Ask a question and retrieve the most relevant document chunks. Use this to test retrieval quality before connecting a model.</div>
|
||||
|
||||
<div class="query-opts">
|
||||
@@ -307,7 +309,7 @@
|
||||
<input type="text" id="col-desc" class="modal-input" placeholder="What documents will this contain?">
|
||||
</div>
|
||||
<div class="modal-field">
|
||||
<label class="modal-label">Embedding Model</label>
|
||||
<label class="modal-label">Embedding Model <span class="cezen-help" tabindex="0" data-tip="The model that converts document text into searchable vectors. Once documents are indexed with one embedding model, switching later means re-indexing the whole collection — pick one and stick with it per collection.">?</span></label>
|
||||
<select id="col-embed" class="modal-select">
|
||||
<option value="nomic-embed-text">nomic-embed-text (recommended)</option>
|
||||
<option value="mxbai-embed-large">mxbai-embed-large</option>
|
||||
@@ -411,13 +413,19 @@ function renderCollections() {
|
||||
grid.innerHTML = '<div style="color:var(--lt);font-size:13px;padding:20px 0">No collections yet — create one to get started.</div>';
|
||||
return;
|
||||
}
|
||||
grid.innerHTML = collectionsCache.map(c => `
|
||||
const q = (document.getElementById('col-filter')?.value || '').trim().toLowerCase();
|
||||
const filtered = q ? collectionsCache.filter(c => (c.name || '').toLowerCase().includes(q) || (c.description || '').toLowerCase().includes(q)) : collectionsCache;
|
||||
if (!filtered.length) {
|
||||
grid.innerHTML = '<div class="cezen-list-empty">No collections match your filter.</div>';
|
||||
return;
|
||||
}
|
||||
grid.innerHTML = filtered.map(c => `
|
||||
<div class="col-card ${selectedColId === c.id ? 'selected' : ''}" onclick="selectCollection(${c.id})">
|
||||
<div class="col-card-name">📂 ${c.name}</div>
|
||||
<div class="col-card-name"><span class="icon-svg icon-xs" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/></svg></span> ${c.name}</div>
|
||||
<div class="col-card-desc">${c.description || '<span style="color:var(--lt);font-style:italic">No description</span>'}</div>
|
||||
<div class="col-card-meta">
|
||||
<span>📄 ${c.doc_count} doc${c.doc_count !== 1 ? 's' : ''}</span>
|
||||
<span>🧩 ${c.chunk_count.toLocaleString()} chunks</span>
|
||||
<span>${c.doc_count} doc${c.doc_count !== 1 ? 's' : ''}</span>
|
||||
<span><span class="icon-svg icon-xs" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 2 2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg></span> ${c.chunk_count.toLocaleString()} chunks</span>
|
||||
<span>${fmt(c.created_at)}</span>
|
||||
</div>
|
||||
<div class="col-card-actions">
|
||||
@@ -458,7 +466,7 @@ async function createCollection() {
|
||||
const d = await res.json();
|
||||
if (!res.ok) { errEl.textContent = d.detail || 'Failed to create'; errEl.classList.add('show'); return; }
|
||||
|
||||
toast(`✓ Collection "${name}" created`);
|
||||
toast(`Collection "${name}" created`);
|
||||
closeModals();
|
||||
document.getElementById('col-name').value = '';
|
||||
document.getElementById('col-desc').value = '';
|
||||
@@ -528,7 +536,7 @@ async function loadDocuments(colId) {
|
||||
<td><strong>${d.orig_name}</strong></td>
|
||||
<td>${d.chunk_count.toLocaleString()}</td>
|
||||
<td>${fmtBytes(d.size_bytes)}</td>
|
||||
<td><span class="doc-status ${d.status}">${d.status}${d.error_msg ? ` <span title="${d.error_msg.replace(/"/g,'"')}">⚠</span>` : ''}</span></td>
|
||||
<td><span class="doc-status ${d.status}">${d.status}${d.error_msg ? ` <span title="${d.error_msg.replace(/"/g,'"')}">Issue</span>` : ''}</span></td>
|
||||
<td>${fmt(d.uploaded_at)}</td>
|
||||
<td><button class="kb-btn danger" style="padding:5px 12px;font-size:12px" onclick="deleteDocument(${colId},${d.id},'${d.orig_name.replace(/'/g,"\\'")}')">Delete</button></td>
|
||||
</tr>
|
||||
@@ -537,7 +545,7 @@ async function loadDocuments(colId) {
|
||||
// Auto-refresh while any doc is still processing
|
||||
const hasPending = docs.some(d => d.status === 'pending' || d.status === 'processing');
|
||||
if (hasPending) {
|
||||
document.getElementById('doc-auto-refresh').textContent = '⟳ Auto-refreshing…';
|
||||
document.getElementById('doc-auto-refresh').textContent = 'Auto-refreshing...';
|
||||
startDocRefresh(colId);
|
||||
} else {
|
||||
document.getElementById('doc-auto-refresh').textContent = '';
|
||||
@@ -583,7 +591,7 @@ async function uploadFiles(files) {
|
||||
});
|
||||
const d = await res.json();
|
||||
if (!res.ok) throw new Error(d.detail || 'Upload failed');
|
||||
toast(`✓ ${file.name} uploaded — indexing started`);
|
||||
toast(`${file.name} uploaded - indexing started`);
|
||||
} catch(e) {
|
||||
toast(`${file.name}: ${e.message}`, true);
|
||||
}
|
||||
@@ -655,7 +663,7 @@ async function runQuery() {
|
||||
<div class="result-card" style="background:var(--navy2);border:1px solid var(--bdr)">
|
||||
<div class="result-meta">
|
||||
<span class="result-score" style="color:var(--purple)">Score: ${(r.score * 100).toFixed(1)}%</span>
|
||||
<span class="result-source">📄 ${r.source}</span>
|
||||
<span class="result-source">${r.source}</span>
|
||||
${r.page ? `<span>Page ${r.page}</span>` : ''}
|
||||
<span>Chunk ${r.chunk + 1}</span>
|
||||
<span style="margin-left:auto;font-weight:600;color:var(--ink)">#${i+1}</span>
|
||||
@@ -681,6 +689,6 @@ document.addEventListener('keydown', e => { if(e.key==='Escape') closeModals();
|
||||
loadCollections();
|
||||
</script>
|
||||
<script src="auth.js"></script>
|
||||
<script src="branding.js"></script>
|
||||
<script src="branding.js?v=3"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user