Changeset 0.17.0 (#75)

This commit is contained in:
2026-02-27 16:25:39 +00:00
parent 8bb77710b9
commit c9141a6896
37 changed files with 2778 additions and 968 deletions

View File

@@ -199,6 +199,15 @@ async function startApp() {
}
UI.renderChatList();
UI.updateModelSelector();
// Restore last-active chat from sessionStorage (QOL: state restore on refresh)
try {
const savedChat = sessionStorage.getItem('cs-active-chat');
if (savedChat && App.chats.some(c => c.id === savedChat)) {
selectChat(savedChat);
}
} catch (_) {}
UI.updateUser();
UI.showAdminButton(API.isAdmin);
initListeners();
@@ -206,6 +215,13 @@ async function startApp() {
// Connect EventBus WebSocket (non-blocking, graceful if /ws not available yet)
try {
Events.connect((window.__BASE__ || '') + '/ws');
// Admin-only: persistent fallback alert banner (v0.17.0)
Events.on('role.fallback', (payload) => {
if (App.user?.role !== 'admin') return;
const data = typeof payload === 'string' ? JSON.parse(payload) : payload;
showFallbackBanner(data);
});
} catch (e) {
console.warn('EventBus WebSocket not available:', e.message);
}
@@ -213,6 +229,27 @@ async function startApp() {
console.log('✅ Chat Switchboard ready');
}
// ── Role Fallback Banner (v0.17.0) ──────────
function showFallbackBanner(data) {
let banner = document.getElementById('roleFallbackBanner');
if (!banner) {
// Create persistent banner above messages
banner = document.createElement('div');
banner.id = 'roleFallbackBanner';
banner.className = 'role-fallback-banner';
const msgs = document.getElementById('chatMessages');
if (msgs) msgs.parentNode.insertBefore(banner, msgs);
else return;
}
const msg = data.message || `Role "${data.role}" primary failed — using fallback`;
banner.innerHTML = `
<span class="fallback-icon">⚠️</span>
<span class="fallback-msg">${esc(msg)}</span>
<button class="btn-small" onclick="this.parentElement.remove()">Dismiss</button>`;
banner.style.display = '';
}
// ── Modal Helpers ───────────────────────────
function openModal(id) {
@@ -553,6 +590,9 @@ async function initBanners() {
// Storage capabilities (file upload, vision)
App.storageConfigured = !!data.storage_configured;
// Paste-to-file threshold (synced from backend, default 2000)
App.pasteToFileChars = data.paste_to_file_chars || 2000;
// Also flatten into serverSettings for backward compat
App.serverSettings = {};
if (data.banner) App.serverSettings.banner = data.banner;