173
src/js/state.js
173
src/js/state.js
@@ -1,5 +1,8 @@
|
||||
// ==========================================
|
||||
// State Management
|
||||
// State Management (Mode-Aware)
|
||||
// ==========================================
|
||||
// In unmanaged mode: localStorage (same as before)
|
||||
// In managed mode: backend API with local cache
|
||||
// ==========================================
|
||||
|
||||
const State = {
|
||||
@@ -23,6 +26,8 @@ const State = {
|
||||
abortController: null
|
||||
};
|
||||
|
||||
// ── Settings (always localStorage) ──────────
|
||||
|
||||
function loadSettings() {
|
||||
const saved = Storage.get('chatSwitchboard_settings');
|
||||
if (saved) {
|
||||
@@ -34,6 +39,8 @@ function saveSettings() {
|
||||
Storage.set('chatSwitchboard_settings', State.settings);
|
||||
}
|
||||
|
||||
// ── Models (always localStorage) ────────────
|
||||
|
||||
function loadModels() {
|
||||
State.models = Storage.get('chatSwitchboard_models', []);
|
||||
}
|
||||
@@ -42,42 +49,130 @@ function saveModels() {
|
||||
Storage.set('chatSwitchboard_models', State.models);
|
||||
}
|
||||
|
||||
function loadChats() {
|
||||
State.chats = Storage.get('chatSwitchboard_chats', []);
|
||||
// ── Chats ───────────────────────────────────
|
||||
|
||||
async function loadChats() {
|
||||
if (Backend.isManaged) {
|
||||
try {
|
||||
const resp = await Backend.listChats(1, 100);
|
||||
State.chats = (resp.data || []).map(c => ({
|
||||
id: c.id,
|
||||
title: c.title,
|
||||
model: c.model || '',
|
||||
systemPrompt: c.system_prompt || '',
|
||||
isArchived: c.is_archived,
|
||||
isPinned: c.is_pinned,
|
||||
messageCount: c.message_count || 0,
|
||||
messages: [], // loaded on demand
|
||||
createdAt: c.created_at,
|
||||
updatedAt: c.updated_at
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error('Failed to load chats from backend:', e);
|
||||
showToast('⚠️ Failed to load chats', 'error');
|
||||
}
|
||||
} else {
|
||||
State.chats = Storage.get('chatSwitchboard_chats', []);
|
||||
}
|
||||
}
|
||||
|
||||
function saveChats() {
|
||||
if (State.settings.saveHistory) {
|
||||
// In managed mode, individual operations handle persistence.
|
||||
// In unmanaged mode, write to localStorage.
|
||||
if (!Backend.isManaged && State.settings.saveHistory) {
|
||||
Storage.set('chatSwitchboard_chats', State.chats);
|
||||
}
|
||||
}
|
||||
|
||||
function createChat(title, messages) {
|
||||
const chat = {
|
||||
id: Date.now().toString(),
|
||||
title,
|
||||
messages,
|
||||
model: State.settings.model,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
State.chats.unshift(chat);
|
||||
if (State.chats.length > 100) {
|
||||
State.chats = State.chats.slice(0, 100);
|
||||
async function createChat(title, messages) {
|
||||
if (Backend.isManaged) {
|
||||
try {
|
||||
const resp = await Backend.createChat(
|
||||
title,
|
||||
State.settings.model,
|
||||
State.settings.systemPrompt
|
||||
);
|
||||
const chat = {
|
||||
id: resp.id,
|
||||
title: resp.title,
|
||||
model: resp.model || '',
|
||||
systemPrompt: resp.system_prompt || '',
|
||||
messages: messages || [],
|
||||
messageCount: 0,
|
||||
createdAt: resp.created_at,
|
||||
updatedAt: resp.updated_at
|
||||
};
|
||||
State.chats.unshift(chat);
|
||||
|
||||
// Persist any initial messages (system prompt, first user msg)
|
||||
for (const msg of (messages || [])) {
|
||||
await Backend.createMessage(chat.id, msg.role, msg.content, msg.model);
|
||||
}
|
||||
chat.messageCount = (messages || []).length;
|
||||
|
||||
return chat;
|
||||
} catch (e) {
|
||||
console.error('Failed to create chat:', e);
|
||||
showToast('⚠️ Failed to create chat', 'error');
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
const chat = {
|
||||
id: Date.now().toString(),
|
||||
title,
|
||||
messages: messages || [],
|
||||
model: State.settings.model,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
};
|
||||
State.chats.unshift(chat);
|
||||
if (State.chats.length > 100) {
|
||||
State.chats = State.chats.slice(0, 100);
|
||||
}
|
||||
saveChats();
|
||||
return chat;
|
||||
}
|
||||
saveChats();
|
||||
return chat;
|
||||
}
|
||||
|
||||
function updateChat(chatId, updates) {
|
||||
async function updateChat(chatId, updates) {
|
||||
const chat = State.chats.find(c => c.id === chatId);
|
||||
if (chat) {
|
||||
if (!chat) return;
|
||||
|
||||
if (Backend.isManaged) {
|
||||
// Separate backend-updateable fields from local-only fields
|
||||
const backendUpdates = {};
|
||||
if (updates.title !== undefined) backendUpdates.title = updates.title;
|
||||
if (updates.model !== undefined) backendUpdates.model = updates.model;
|
||||
if (updates.is_archived !== undefined) backendUpdates.is_archived = updates.is_archived;
|
||||
if (updates.is_pinned !== undefined) backendUpdates.is_pinned = updates.is_pinned;
|
||||
|
||||
if (Object.keys(backendUpdates).length > 0) {
|
||||
try {
|
||||
await Backend.updateChat(chatId, backendUpdates);
|
||||
} catch (e) {
|
||||
console.error('Failed to update chat:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Update local cache
|
||||
Object.assign(chat, updates, { updatedAt: new Date().toISOString() });
|
||||
} else {
|
||||
Object.assign(chat, updates, { updatedAt: new Date().toISOString() });
|
||||
saveChats();
|
||||
}
|
||||
}
|
||||
|
||||
function deleteChat(chatId) {
|
||||
async function deleteChat(chatId) {
|
||||
if (Backend.isManaged) {
|
||||
try {
|
||||
await Backend.deleteChat(chatId);
|
||||
} catch (e) {
|
||||
console.error('Failed to delete chat:', e);
|
||||
showToast('⚠️ Failed to delete chat', 'error');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
State.chats = State.chats.filter(c => c.id !== chatId);
|
||||
saveChats();
|
||||
}
|
||||
@@ -89,3 +184,39 @@ function getChat(chatId) {
|
||||
function getCurrentChat() {
|
||||
return State.currentChatId ? getChat(State.currentChatId) : null;
|
||||
}
|
||||
|
||||
// ── Messages (managed mode) ─────────────────
|
||||
|
||||
async function loadMessages(chatId) {
|
||||
if (!Backend.isManaged) return;
|
||||
|
||||
const chat = getChat(chatId);
|
||||
if (!chat) return;
|
||||
|
||||
// Skip if already loaded
|
||||
if (chat.messages && chat.messages.length > 0) return;
|
||||
|
||||
try {
|
||||
const resp = await Backend.listMessages(chatId, 1, 200);
|
||||
chat.messages = (resp.data || []).map(m => ({
|
||||
role: m.role,
|
||||
content: m.content,
|
||||
model: m.model || '',
|
||||
timestamp: m.created_at,
|
||||
_backendId: m.id
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error('Failed to load messages:', e);
|
||||
showToast('⚠️ Failed to load messages', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function persistMessage(chatId, role, content, model) {
|
||||
if (!Backend.isManaged) return;
|
||||
|
||||
try {
|
||||
await Backend.createMessage(chatId, role, content, model);
|
||||
} catch (e) {
|
||||
console.error('Failed to persist message:', e);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user