diff --git a/emain/emain.ts b/emain/emain.ts index 995b355d85..5e0748e390 100644 --- a/emain/emain.ts +++ b/emain/emain.ts @@ -373,6 +373,19 @@ electron.ipcMain.on("quicklook", (event, filePath: string) => { } }); +electron.ipcMain.handle("clear-webview-storage", async (event, webContentsId: number) => { + try { + const wc = electron.webContents.fromId(webContentsId); + if (wc && wc.session) { + await wc.session.clearStorageData(); + console.log("Cleared cookies and storage for webContentsId:", webContentsId); + } + } catch (e) { + console.error("Failed to clear cookies and storage:", e); + throw e; + } +}); + electron.ipcMain.on("open-native-path", (event, filePath: string) => { console.log("open-native-path", filePath); filePath = filePath.replace("~", electronApp.getPath("home")); diff --git a/emain/preload.ts b/emain/preload.ts index 812279a481..6545769fa3 100644 --- a/emain/preload.ts +++ b/emain/preload.ts @@ -56,6 +56,7 @@ contextBridge.exposeInMainWorld("api", { openNativePath: (filePath: string) => ipcRenderer.send("open-native-path", filePath), captureScreenshot: (rect: Rectangle) => ipcRenderer.invoke("capture-screenshot", rect), setKeyboardChordMode: () => ipcRenderer.send("set-keyboard-chord-mode"), + clearWebviewStorage: (webContentsId: number) => ipcRenderer.invoke("clear-webview-storage", webContentsId), setWaveAIOpen: (isOpen: boolean) => ipcRenderer.send("set-waveai-open", isOpen), }); diff --git a/frontend/app/view/webview/webview.tsx b/frontend/app/view/webview/webview.tsx index 546ad1fb10..0067ea863a 100644 --- a/frontend/app/view/webview/webview.tsx +++ b/frontend/app/view/webview/webview.tsx @@ -411,19 +411,19 @@ export class WebViewModel implements ViewModel { const searchTemplate = globalStore.get(defaultSearchAtom); const nextUrl = this.ensureUrlScheme(newUrl, searchTemplate); console.log("webview loadUrlPromise", reason, nextUrl, "cur=", this.webviewRef.current?.getURL()); - + if (!this.webviewRef.current) { return Promise.reject(new Error("WebView ref not available")); } - + if (newUrl != nextUrl) { globalStore.set(this.url, nextUrl); } - + if (this.webviewRef.current.getURL() != nextUrl) { return this.webviewRef.current.loadURL(nextUrl); } - + return Promise.resolve(); } @@ -495,6 +495,25 @@ export class WebViewModel implements ViewModel { } } + clearHistory() { + try { + this.webviewRef.current?.clearHistory(); + } catch (e) { + console.error("Failed to clear history", e); + } + } + + async clearCookiesAndStorage() { + try { + const webContentsId = this.webviewRef.current?.getWebContentsId(); + if (webContentsId) { + await getApi().clearWebviewStorage(webContentsId); + } + } catch (e) { + console.error("Failed to clear cookies and storage", e); + } + } + keyDownHandler(e: WaveKeyboardEvent): boolean { if (checkKeyPressed(e, "Cmd:l")) { this.urlInputRef?.current?.focus(); @@ -619,6 +638,17 @@ export class WebViewModel implements ViewModel { } }, }, + { + type: "separator", + }, + { + label: "Clear History", + click: () => this.clearHistory(), + }, + { + label: "Clear Cookies and Storage (All Web Widgets)", + click: () => fireAndForget(() => this.clearCookiesAndStorage()), + }, ]; } } diff --git a/frontend/types/custom.d.ts b/frontend/types/custom.d.ts index 1ad3d55c5e..3117291753 100644 --- a/frontend/types/custom.d.ts +++ b/frontend/types/custom.d.ts @@ -106,6 +106,7 @@ declare global { openNativePath(filePath: string): void; // open-native-path captureScreenshot(rect: Electron.Rectangle): Promise; // capture-screenshot setKeyboardChordMode: () => void; // set-keyboard-chord-mode + clearWebviewStorage: (webContentsId: number) => Promise; // clear-webview-storage setWaveAIOpen: (isOpen: boolean) => void; // set-waveai-open };