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:
Mario Zechner 2025-10-06 16:33:33 +02:00
parent 2d68594711
commit 5f04960f6d
5 changed files with 94 additions and 25 deletions

View file

@ -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.

View file

@ -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");

View file

@ -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

View file

@ -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();

View file

@ -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);
}