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
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Notifications — Nexus One AI</title>
|
||||
<link rel="stylesheet" href="style.css?v=4">
|
||||
<link rel="stylesheet" href="style.css?v=12">
|
||||
<style>
|
||||
.nt-layout { display: grid; grid-template-columns: 220px 1fr; min-height: calc(100vh - 64px); }
|
||||
@media(max-width:700px){ .nt-layout { grid-template-columns: 1fr; } .nt-sidebar { display:none; } }
|
||||
@@ -23,7 +23,16 @@
|
||||
}
|
||||
.nt-filter-btn:hover { background: rgba(124,58,237,.07); color: var(--ink); }
|
||||
.nt-filter-btn.active { background: rgba(124,58,237,.12); color: var(--purple); font-weight: 700; }
|
||||
.nt-filter-icon { font-size: 15px; width: 20px; text-align: center; }
|
||||
.nt-filter-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: currentColor;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.nt-filter-icon svg { width: 16px; height: 16px; }
|
||||
.nt-filter-count {
|
||||
margin-left: auto; background: var(--purple); color: white;
|
||||
font-size: 10px; font-weight: 800; padding: 2px 7px;
|
||||
@@ -49,7 +58,14 @@
|
||||
/* List */
|
||||
.nt-list { display: flex; flex-direction: column; gap: 8px; }
|
||||
.nt-empty { text-align: center; padding: 60px 20px; color: var(--lt); }
|
||||
.nt-empty-icon { font-size: 40px; margin-bottom: 12px; opacity: .35; }
|
||||
.nt-empty-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 auto 12px;
|
||||
opacity: .35;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.nt-empty-icon svg { width: 100%; height: 100%; }
|
||||
|
||||
.nt-item {
|
||||
display: flex; gap: 14px; align-items: flex-start;
|
||||
@@ -66,8 +82,9 @@
|
||||
.nt-item-icon {
|
||||
width: 38px; height: 38px; border-radius: 10px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
font-size: 18px; flex-shrink: 0;
|
||||
color: currentColor; flex-shrink: 0;
|
||||
}
|
||||
.nt-item-icon svg { width: 18px; height: 18px; }
|
||||
.nt-item-icon.info { background: rgba(124,58,237,.12); }
|
||||
.nt-item-icon.warning { background: rgba(245,158,11,.12); }
|
||||
.nt-item-icon.error { background: rgba(239,68,68,.12); }
|
||||
@@ -154,6 +171,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>
|
||||
@@ -192,8 +210,11 @@
|
||||
<a href="chatrooms.html">Chat Rooms</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="notifications.html" class="active" style="position:relative">
|
||||
🔔 <span id="nav-badge" class="nt-filter-count hidden" style="position:absolute;top:-4px;right:-8px;font-size:9px;padding:1px 5px"></span>
|
||||
<a href="notifications.html" class="nav-icon-btn active" style="position:relative" title="Notifications">
|
||||
<span class="icon-svg icon-md" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
|
||||
</span>
|
||||
<span id="nav-badge" class="nt-filter-count hidden" style="position:absolute;top:-4px;right:-8px;font-size:9px;padding:1px 5px"></span>
|
||||
</a>
|
||||
</nav>
|
||||
<span class="badge" data-brand="tier">Basic Tier</span>
|
||||
@@ -206,58 +227,58 @@
|
||||
<div class="nt-sidebar">
|
||||
<div class="nt-sidebar-title">Filter</div>
|
||||
<button class="nt-filter-btn active" onclick="setFilter('all', this)">
|
||||
<span class="nt-filter-icon">📬</span> All
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 4h16v16H4z"/><path d="m4 7 8 6 8-6"/></svg></span> All
|
||||
<span class="nt-filter-count hidden" id="cnt-all"></span>
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('unread', this)">
|
||||
<span class="nt-filter-icon">🔵</span> Unread
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="5"/></svg></span> Unread
|
||||
<span class="nt-filter-count hidden" id="cnt-unread"></span>
|
||||
</button>
|
||||
|
||||
<div style="margin: 14px 8px 6px; font-size:11px;font-weight:700;color:var(--lt);text-transform:uppercase;letter-spacing:.4px">By Source</div>
|
||||
<button class="nt-filter-btn" onclick="setFilter('guardrail', this)">
|
||||
<span class="nt-filter-icon">🛡</span> Guardrails
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></span> Guardrails
|
||||
<span class="nt-filter-count hidden" id="cnt-guardrail"></span>
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('scheduler', this)">
|
||||
<span class="nt-filter-icon">⏱</span> Scheduler
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="13" r="8"/><path d="M12 9v4l2 2"/><path d="M9 2h6"/><path d="M12 2v3"/></svg></span> Scheduler
|
||||
<span class="nt-filter-count hidden" id="cnt-scheduler"></span>
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('agent', this)">
|
||||
<span class="nt-filter-icon">🤖</span> Agents
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="7" y="8" width="10" height="8" rx="2"/><path d="M12 4v4M9 16v2M15 16v2M6 10H4M20 10h-2"/><circle cx="10" cy="12" r="1"/><circle cx="14" cy="12" r="1"/></svg></span> Agents
|
||||
<span class="nt-filter-count hidden" id="cnt-agent"></span>
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('rag', this)">
|
||||
<span class="nt-filter-icon">📚</span> RAG / KB
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg></span> RAG / KB
|
||||
<span class="nt-filter-count hidden" id="cnt-rag"></span>
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('system', this)">
|
||||
<span class="nt-filter-icon">⚙️</span> System
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.01A1.65 1.65 0 0 0 10.5 3.1V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h.01a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v.01a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span> System
|
||||
<span class="nt-filter-count hidden" id="cnt-system"></span>
|
||||
</button>
|
||||
|
||||
<div style="margin: 14px 8px 6px; font-size:11px;font-weight:700;color:var(--lt);text-transform:uppercase;letter-spacing:.4px">By Severity</div>
|
||||
<button class="nt-filter-btn" onclick="setFilter('sev-critical', this)">
|
||||
<span class="nt-filter-icon">🔴</span> Critical
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg></span> Critical
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('sev-error', this)">
|
||||
<span class="nt-filter-icon">🟠</span> Error
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="m15 9-6 6M9 9l6 6"/></svg></span> Error
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('sev-warning', this)">
|
||||
<span class="nt-filter-icon">🟡</span> Warning
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg></span> Warning
|
||||
</button>
|
||||
<button class="nt-filter-btn" onclick="setFilter('sev-info', this)">
|
||||
<span class="nt-filter-icon">🔵</span> Info
|
||||
<span class="nt-filter-icon icon-svg" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 12v4"/><path d="M12 8h.01"/></svg></span> Info
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Main -->
|
||||
<div class="nt-main">
|
||||
<div class="nt-header">
|
||||
<div class="nt-title">🔔 Notifications</div>
|
||||
<div class="nt-title icon-label"><span class="icon-svg icon-lg" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg></span>Notifications</div>
|
||||
<div class="nt-header-actions">
|
||||
<button class="nt-btn" onclick="markAllRead()">✓ Mark all read</button>
|
||||
<button class="nt-btn danger" onclick="clearAll()">🗑 Clear all</button>
|
||||
<button class="nt-btn" onclick="markAllRead()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="m20 6-11 11-5-5"/></svg></span>Mark all read</span></button>
|
||||
<button class="nt-btn danger" onclick="clearAll()"><span class="icon-label"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/></svg></span>Clear all</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -282,14 +303,25 @@
|
||||
</div>
|
||||
|
||||
<div class="nt-list" id="nt-list">
|
||||
<div class="nt-empty"><div class="nt-empty-icon">🔔</div><p>Loading…</p></div>
|
||||
<div class="nt-empty"><div class="nt-empty-icon icon-svg"><svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg></div><p>Loading…</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const SOURCE_ICONS = { guardrail:'🛡', scheduler:'⏱', agent:'🤖', rag:'📚', system:'⚙️' };
|
||||
const SEV_ICONS = { info:'ℹ️', warning:'⚠️', error:'❌', critical:'🚨' };
|
||||
const SOURCE_ICONS = {
|
||||
guardrail:'<span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></span>',
|
||||
scheduler:'<span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="13" r="8"/><path d="M12 9v4l2 2"/><path d="M9 2h6"/><path d="M12 2v3"/></svg></span>',
|
||||
agent:'<span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="7" y="8" width="10" height="8" rx="2"/><path d="M12 4v4M9 16v2M15 16v2M6 10H4M20 10h-2"/><circle cx="10" cy="12" r="1"/><circle cx="14" cy="12" r="1"/></svg></span>',
|
||||
rag:'<span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg></span>',
|
||||
system:'<span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.01A1.65 1.65 0 0 0 10.5 3.1V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h.01a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v.01a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span>'
|
||||
};
|
||||
const SEV_ICONS = {
|
||||
info:'<span class="icon-svg icon-md" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 12v4"/><path d="M12 8h.01"/></svg></span>',
|
||||
warning:'<span class="icon-svg icon-md" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg></span>',
|
||||
error:'<span class="icon-svg icon-md" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="m15 9-6 6M9 9l6 6"/></svg></span>',
|
||||
critical:'<span class="icon-svg icon-md" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg></span>'
|
||||
};
|
||||
|
||||
let allNotifications = [];
|
||||
let currentFilter = 'all';
|
||||
@@ -373,25 +405,25 @@ function render() {
|
||||
const list = document.getElementById('nt-list');
|
||||
const items = getFiltered();
|
||||
if (!items.length) {
|
||||
list.innerHTML = `<div class="nt-empty"><div class="nt-empty-icon">✅</div><p>No notifications here.</p></div>`;
|
||||
list.innerHTML = `<div class="nt-empty"><div class="nt-empty-icon icon-svg"><svg viewBox="0 0 24 24"><path d="m20 6-11 11-5-5"/></svg></div><p>No notifications here.</p></div>`;
|
||||
return;
|
||||
}
|
||||
list.innerHTML = items.map(n => `
|
||||
<div class="nt-item ${n.is_read ? '' : 'unread'} sev-${n.severity}" onclick="markRead(${n.id})" id="nt-${n.id}">
|
||||
<div class="nt-item-icon ${n.severity}">${SEV_ICONS[n.severity] || '📌'}</div>
|
||||
<div class="nt-item-icon ${n.severity}">${SEV_ICONS[n.severity] || ''}</div>
|
||||
<div class="nt-item-body">
|
||||
<div class="nt-item-header">
|
||||
<span class="nt-item-title">${n.title}</span>
|
||||
<span class="nt-sev-badge ${n.severity}">${n.severity}</span>
|
||||
<span class="nt-src-badge">${SOURCE_ICONS[n.source]||''} ${n.source}</span>
|
||||
<span class="nt-src-badge"><span class="icon-label">${SOURCE_ICONS[n.source]||''}<span>${n.source}</span></span></span>
|
||||
<span class="nt-item-time">${timeAgo(n.created_at)}</span>
|
||||
</div>
|
||||
<div class="nt-item-body-text">${n.body}</div>
|
||||
${n.link ? `<a class="nt-item-link" href="${n.link}" onclick="event.stopPropagation()">→ View details</a>` : ''}
|
||||
${n.link ? `<a class="nt-item-link" href="${n.link}" onclick="event.stopPropagation()">View details</a>` : ''}
|
||||
</div>
|
||||
<div class="nt-item-actions">
|
||||
<button class="nt-icon-btn" onclick="event.stopPropagation();markRead(${n.id})" title="Mark read">✓</button>
|
||||
<button class="nt-icon-btn del" onclick="event.stopPropagation();deleteNotif(${n.id})" title="Delete">✕</button>
|
||||
<button class="nt-icon-btn" onclick="event.stopPropagation();markRead(${n.id})" title="Mark read"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="m20 6-11 11-5-5"/></svg></span></button>
|
||||
<button class="nt-icon-btn del" onclick="event.stopPropagation();deleteNotif(${n.id})" title="Delete"><span class="icon-svg icon-sm" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M6 6l12 12M18 6 6 18"/></svg></span></button>
|
||||
</div>
|
||||
<div class="nt-unread-dot ${n.is_read ? 'hidden' : ''}"></div>
|
||||
</div>
|
||||
@@ -437,6 +469,6 @@ setInterval(loadNotifications, 30000);
|
||||
</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