mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 09:01:14 +00:00
Fix SessionListDialog behavior and document PersistentStorageDialog bug
- Fix SessionListDialog to not reload when user selects a session after deleting others - Track if dialog closed via selection vs other means - Only call delete callback if not closed via selection - Batch deletions to avoid reload on every delete - Comment out PersistentStorageDialog in both web-ui example and browser extension (TODO: fix) - Add Known Bugs section to both README.md files documenting PersistentStorageDialog issue - Clean up navigation tracking variable names in browser extension
This commit is contained in:
parent
2d68594711
commit
5f04960f6d
5 changed files with 94 additions and 25 deletions
|
|
@ -1182,3 +1182,7 @@ Error: Refused to evaluate a string as JavaScript because this document requires
|
|||
---
|
||||
|
||||
This CSP section should help both developers and LLMs understand the security constraints when working on extension features, especially those involving dynamic code execution or user-generated content.
|
||||
|
||||
## Known Bugs
|
||||
|
||||
- **PersistentStorageDialog**: Currently broken and commented out in sidepanel.ts. The dialog for requesting persistent storage does not work correctly and needs to be fixed.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
AppStorage,
|
||||
ChatPanel,
|
||||
ChromeStorageBackend,
|
||||
PersistentStorageDialog,
|
||||
// PersistentStorageDialog, // TODO: Fix - currently broken
|
||||
ProviderTransport,
|
||||
ProxyTab,
|
||||
SessionIndexedDBBackend,
|
||||
|
|
@ -71,9 +71,9 @@ let agent: Agent;
|
|||
let chatPanel: ChatPanel;
|
||||
let agentUnsubscribe: (() => void) | undefined;
|
||||
|
||||
// Track last navigation for inserting navigation messages
|
||||
let lastSubmittedUrl: string | undefined;
|
||||
let lastSubmittedTabIndex: number | undefined;
|
||||
// Track current active tab for real-time navigation updates
|
||||
let currentTabUrl: string | undefined;
|
||||
let currentTabIndex: number | undefined;
|
||||
|
||||
// ============================================================================
|
||||
// HELPERS
|
||||
|
|
@ -204,7 +204,7 @@ const renderApp = () => {
|
|||
loadSession(sessionId);
|
||||
},
|
||||
(deletedSessionId) => {
|
||||
// If the deleted session is the current one, start a new session
|
||||
// Only reload if the current session was deleted
|
||||
if (deletedSessionId === currentSessionId) {
|
||||
newSession();
|
||||
}
|
||||
|
|
@ -294,6 +294,41 @@ const renderApp = () => {
|
|||
render(appHtml, document.body);
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// TAB NAVIGATION TRACKING
|
||||
// ============================================================================
|
||||
|
||||
// Listen for tab updates to insert navigation messages in real-time
|
||||
chrome.tabs.onUpdated.addListener((_tabId, changeInfo, tab) => {
|
||||
// Only care about URL changes on the active tab
|
||||
if (changeInfo.url && tab.active && tab.url) {
|
||||
handleTabNavigation(tab.url, tab.title || "Untitled", tab.favIconUrl, tab.index);
|
||||
}
|
||||
});
|
||||
|
||||
// Listen for tab activation (user switches tabs)
|
||||
chrome.tabs.onActivated.addListener(async (activeInfo) => {
|
||||
const tab = await chrome.tabs.get(activeInfo.tabId);
|
||||
if (tab.url) {
|
||||
handleTabNavigation(tab.url, tab.title || "Untitled", tab.favIconUrl, tab.index);
|
||||
}
|
||||
});
|
||||
|
||||
function handleTabNavigation(url: string, title: string, favicon?: string, tabIndex?: number) {
|
||||
// Update current tab tracking
|
||||
const urlChanged = currentTabUrl !== url;
|
||||
const tabChanged = currentTabIndex !== tabIndex;
|
||||
|
||||
currentTabUrl = url;
|
||||
currentTabIndex = tabIndex;
|
||||
|
||||
// Only insert navigation message if something changed and we have an agent
|
||||
if ((urlChanged || tabChanged) && agent) {
|
||||
const navMessage = createNavigationMessage(url, title, favicon, tabIndex);
|
||||
agent.appendMessage(navMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// INIT
|
||||
// ============================================================================
|
||||
|
|
@ -308,10 +343,11 @@ async function initApp() {
|
|||
document.body,
|
||||
);
|
||||
|
||||
// TODO: Fix PersistentStorageDialog - currently broken
|
||||
// Request persistent storage
|
||||
if (storage.sessions) {
|
||||
await PersistentStorageDialog.request();
|
||||
}
|
||||
// if (storage.sessions) {
|
||||
// await PersistentStorageDialog.request();
|
||||
// }
|
||||
|
||||
// Create ChatPanel
|
||||
chatPanel = new ChatPanel();
|
||||
|
|
@ -322,21 +358,33 @@ async function initApp() {
|
|||
chatPanel.onBeforeSend = async () => {
|
||||
// Get current tab info
|
||||
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
if (!tab || !tab.url) return;
|
||||
if (!tab?.url) return;
|
||||
|
||||
// Check if navigation changed since last submit
|
||||
if (lastSubmittedUrl !== tab.url || lastSubmittedTabIndex !== tab.index) {
|
||||
// Insert navigation message
|
||||
// Find last navigation message in messages (reverse loop)
|
||||
const messages = agent.state.messages;
|
||||
let lastNavMessage: ReturnType<typeof createNavigationMessage> | undefined;
|
||||
for (let i = messages.length - 1; i >= 0; i--) {
|
||||
if (messages[i].role === "navigation") {
|
||||
lastNavMessage = messages[i] as ReturnType<typeof createNavigationMessage>;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only insert if URL or tab changed
|
||||
if (lastNavMessage?.url !== tab.url || lastNavMessage?.tabIndex !== tab.index) {
|
||||
const navMessage = createNavigationMessage(tab.url, tab.title || "Untitled", tab.favIconUrl, tab.index);
|
||||
agent.appendMessage(navMessage);
|
||||
|
||||
// Update tracking
|
||||
lastSubmittedUrl = tab.url;
|
||||
lastSubmittedTabIndex = tab.index;
|
||||
}
|
||||
};
|
||||
chatPanel.additionalTools = [browserJavaScriptTool];
|
||||
|
||||
// Initialize current tab state
|
||||
const [currentTab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
if (currentTab?.url) {
|
||||
currentTabUrl = currentTab.url;
|
||||
currentTabIndex = currentTab.index;
|
||||
}
|
||||
|
||||
// Check for session in URL
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
let sessionIdFromUrl = urlParams.get("session");
|
||||
|
|
|
|||
|
|
@ -322,6 +322,10 @@ setAppStorage(storage);
|
|||
|
||||
See [src/index.ts](src/index.ts) for the full public API.
|
||||
|
||||
## Known Bugs
|
||||
|
||||
- **PersistentStorageDialog**: Currently broken and commented out in examples. The dialog for requesting persistent storage does not work correctly and needs to be fixed.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
type AppMessage,
|
||||
AppStorage,
|
||||
ChatPanel,
|
||||
PersistentStorageDialog,
|
||||
// PersistentStorageDialog, // TODO: Fix - currently broken
|
||||
ProviderTransport,
|
||||
ProxyTab,
|
||||
SessionIndexedDBBackend,
|
||||
|
|
@ -192,7 +192,7 @@ const renderApp = () => {
|
|||
await loadSession(sessionId);
|
||||
},
|
||||
(deletedSessionId) => {
|
||||
// If the deleted session is the current one, start a new session
|
||||
// Only reload if the current session was deleted
|
||||
if (deletedSessionId === currentSessionId) {
|
||||
newSession();
|
||||
}
|
||||
|
|
@ -311,10 +311,11 @@ async function initApp() {
|
|||
app,
|
||||
);
|
||||
|
||||
// TODO: Fix PersistentStorageDialog - currently broken
|
||||
// Request persistent storage
|
||||
if (storage.sessions) {
|
||||
await PersistentStorageDialog.request();
|
||||
}
|
||||
// if (storage.sessions) {
|
||||
// await PersistentStorageDialog.request();
|
||||
// }
|
||||
|
||||
// Create ChatPanel
|
||||
chatPanel = new ChatPanel();
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ export class SessionListDialog extends DialogBase {
|
|||
|
||||
private onSelectCallback?: (sessionId: string) => void;
|
||||
private onDeleteCallback?: (sessionId: string) => void;
|
||||
private deletedSessions = new Set<string>();
|
||||
private closedViaSelection = false;
|
||||
|
||||
protected modalWidth = "min(600px, 90vw)";
|
||||
protected modalHeight = "min(700px, 90vh)";
|
||||
|
|
@ -57,16 +59,26 @@ export class SessionListDialog extends DialogBase {
|
|||
await storage.sessions.deleteSession(sessionId);
|
||||
await this.loadSessions();
|
||||
|
||||
// Notify callback that session was deleted
|
||||
if (this.onDeleteCallback) {
|
||||
this.onDeleteCallback(sessionId);
|
||||
}
|
||||
// Track deleted session
|
||||
this.deletedSessions.add(sessionId);
|
||||
} catch (err) {
|
||||
console.error("Failed to delete session:", err);
|
||||
}
|
||||
}
|
||||
|
||||
override close() {
|
||||
super.close();
|
||||
|
||||
// Only notify about deleted sessions if dialog wasn't closed via selection
|
||||
if (!this.closedViaSelection && this.onDeleteCallback && this.deletedSessions.size > 0) {
|
||||
for (const sessionId of this.deletedSessions) {
|
||||
this.onDeleteCallback(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private handleSelect(sessionId: string) {
|
||||
this.closedViaSelection = true;
|
||||
if (this.onSelectCallback) {
|
||||
this.onSelectCallback(sessionId);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue