diff --git a/surfsense_desktop/src/ipc/channels.ts b/surfsense_desktop/src/ipc/channels.ts index 1a2a9993e..25ec1bc0e 100644 --- a/surfsense_desktop/src/ipc/channels.ts +++ b/surfsense_desktop/src/ipc/channels.ts @@ -3,5 +3,7 @@ export const IPC_CHANNELS = { GET_APP_VERSION: 'get-app-version', DEEP_LINK: 'deep-link', QUICK_ASK_TEXT: 'quick-ask-text', + SET_QUICK_ASK_MODE: 'set-quick-ask-mode', + GET_QUICK_ASK_MODE: 'get-quick-ask-mode', REPLACE_TEXT: 'replace-text', } as const; diff --git a/surfsense_desktop/src/modules/quick-ask.ts b/surfsense_desktop/src/modules/quick-ask.ts index 6c7e7a711..4a8b4c315 100644 --- a/surfsense_desktop/src/modules/quick-ask.ts +++ b/surfsense_desktop/src/modules/quick-ask.ts @@ -7,6 +7,7 @@ import { getServerPort } from './server'; const SHORTCUT = 'CommandOrControl+Option+S'; let quickAskWindow: BrowserWindow | null = null; let pendingText = ''; +let pendingMode = ''; let sourceApp = ''; let savedClipboard = ''; @@ -15,6 +16,7 @@ function destroyQuickAsk(): void { quickAskWindow.close(); } quickAskWindow = null; + pendingMode = ''; } function clampToScreen(x: number, y: number, w: number, h: number): { x: number; y: number } { @@ -102,6 +104,14 @@ export function registerQuickAsk(): void { return pendingText; }); + ipcMain.handle(IPC_CHANNELS.SET_QUICK_ASK_MODE, (_event, mode: string) => { + pendingMode = mode; + }); + + ipcMain.handle(IPC_CHANNELS.GET_QUICK_ASK_MODE, () => { + return pendingMode; + }); + ipcMain.handle(IPC_CHANNELS.REPLACE_TEXT, async (_event, text: string) => { if (!sourceApp) return; diff --git a/surfsense_desktop/src/preload.ts b/surfsense_desktop/src/preload.ts index fbb272108..264ec25b3 100644 --- a/surfsense_desktop/src/preload.ts +++ b/surfsense_desktop/src/preload.ts @@ -18,5 +18,7 @@ contextBridge.exposeInMainWorld('electronAPI', { }; }, getQuickAskText: () => ipcRenderer.invoke(IPC_CHANNELS.QUICK_ASK_TEXT), + setQuickAskMode: (mode: string) => ipcRenderer.invoke(IPC_CHANNELS.SET_QUICK_ASK_MODE, mode), + getQuickAskMode: () => ipcRenderer.invoke(IPC_CHANNELS.GET_QUICK_ASK_MODE), replaceText: (text: string) => ipcRenderer.invoke(IPC_CHANNELS.REPLACE_TEXT, text), }); diff --git a/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx b/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx index b0928d9b2..ac203157a 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/new-chat/[[...chat_id]]/page.tsx @@ -1621,4 +1621,4 @@ export default function NewChatPage() { ); -} +} \ No newline at end of file diff --git a/surfsense_web/app/dashboard/quick-ask/page.tsx b/surfsense_web/app/dashboard/quick-ask/page.tsx index e4fb18dde..dca398254 100644 --- a/surfsense_web/app/dashboard/quick-ask/page.tsx +++ b/surfsense_web/app/dashboard/quick-ask/page.tsx @@ -35,16 +35,16 @@ export default function QuickAskPage() { }); }, []); - const navigateToChat = (prompt: string, mode: string) => { - sessionStorage.setItem("quickAskMode", mode); + const navigateToChat = async (prompt: string, mode: string) => { + await window.electronAPI?.setQuickAskMode(mode); sessionStorage.setItem("quickAskAutoSubmit", "true"); const encoded = encodeURIComponent(prompt); window.location.href = `/dashboard?quickAskPrompt=${encoded}`; }; - const navigateWithInitialText = () => { + const navigateWithInitialText = async () => { if (!clipboardText) return; - sessionStorage.setItem("quickAskMode", "explore"); + await window.electronAPI?.setQuickAskMode("explore"); sessionStorage.setItem("quickAskAutoSubmit", "false"); sessionStorage.setItem("quickAskInitialText", clipboardText); window.location.href = `/dashboard?quickAskPrompt=${encodeURIComponent(clipboardText)}`; diff --git a/surfsense_web/components/assistant-ui/assistant-message.tsx b/surfsense_web/components/assistant-ui/assistant-message.tsx index d9837b224..af4d8def4 100644 --- a/surfsense_web/components/assistant-ui/assistant-message.tsx +++ b/surfsense_web/components/assistant-ui/assistant-message.tsx @@ -9,7 +9,7 @@ import { import { useAtomValue } from "jotai"; import { CheckIcon, ClipboardPaste, CopyIcon, DownloadIcon, MessageSquare, RefreshCwIcon } from "lucide-react"; import type { FC } from "react"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { commentsEnabledAtom, targetCommentIdAtom } from "@/atoms/chat/current-thread.atom"; import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms"; import { MarkdownText } from "@/components/assistant-ui/markdown-text"; @@ -274,11 +274,16 @@ export const AssistantMessage: FC = () => { const AssistantActionBar: FC = () => { const isLast = useAuiState((s) => s.message.isLast); const aui = useAui(); - const isTransform = - isLast && - typeof window !== "undefined" && - !!window.electronAPI?.replaceText && - sessionStorage.getItem("quickAskMode") === "transform"; + const [quickAskMode, setQuickAskMode] = useState(""); + + useEffect(() => { + if (!isLast || !window.electronAPI?.getQuickAskMode) return; + window.electronAPI.getQuickAskMode().then((mode) => { + if (mode) setQuickAskMode(mode); + }); + }, [isLast]); + + const isTransform = isLast && !!window.electronAPI?.replaceText && quickAskMode === "transform"; return ( Promise; onDeepLink: (callback: (url: string) => void) => () => void; getQuickAskText: () => Promise; + setQuickAskMode: (mode: string) => Promise; + getQuickAskMode: () => Promise; replaceText: (text: string) => Promise; }