diff --git a/frontend/src-tauri/capabilities/default.json b/frontend/src-tauri/capabilities/default.json index e5a1a41ea..65f9bb444 100644 --- a/frontend/src-tauri/capabilities/default.json +++ b/frontend/src-tauri/capabilities/default.json @@ -65,6 +65,9 @@ }, { "url": "https://opensecret.cloud/*" + }, + { + "url": "https://*" } ] }, diff --git a/frontend/src-tauri/capabilities/mobile-android.json b/frontend/src-tauri/capabilities/mobile-android.json index 220126637..223abc712 100644 --- a/frontend/src-tauri/capabilities/mobile-android.json +++ b/frontend/src-tauri/capabilities/mobile-android.json @@ -75,6 +75,9 @@ }, { "url": "https://*.google.com/*" + }, + { + "url": "https://*" } ] } diff --git a/frontend/src-tauri/capabilities/mobile-ios.json b/frontend/src-tauri/capabilities/mobile-ios.json index 324da9fbf..8fb36bd8f 100644 --- a/frontend/src-tauri/capabilities/mobile-ios.json +++ b/frontend/src-tauri/capabilities/mobile-ios.json @@ -32,6 +32,9 @@ }, { "url": "https://opensecret.cloud/*" + }, + { + "url": "https://*" } ] }, diff --git a/frontend/src/components/ExternalUrlConfirmDialog.tsx b/frontend/src/components/ExternalUrlConfirmDialog.tsx new file mode 100644 index 000000000..cf59feeaf --- /dev/null +++ b/frontend/src/components/ExternalUrlConfirmDialog.tsx @@ -0,0 +1,49 @@ +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; + +interface ExternalUrlConfirmDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + onConfirm: () => void; + url: string; +} + +export function ExternalUrlConfirmDialog({ + open, + onOpenChange, + onConfirm, + url +}: ExternalUrlConfirmDialogProps) { + const handleConfirm = (e: React.MouseEvent) => { + e.preventDefault(); + onConfirm(); + onOpenChange(false); + }; + + return ( + + + + Open External Link? + + You are about to open an external URL in your browser: +
{url}
+
+
+ + + + +
+
+ ); +} diff --git a/frontend/src/components/ExternalUrlConfirmHandler.tsx b/frontend/src/components/ExternalUrlConfirmHandler.tsx new file mode 100644 index 000000000..eca30a57a --- /dev/null +++ b/frontend/src/components/ExternalUrlConfirmHandler.tsx @@ -0,0 +1,32 @@ +import { useEffect, useState } from "react"; +import { ExternalUrlConfirmDialog } from "@/components/ExternalUrlConfirmDialog"; +import { setUrlConfirmationCallback, openExternalUrl } from "@/utils/openUrl"; + +export function ExternalUrlConfirmHandler() { + const [pendingUrl, setPendingUrl] = useState(null); + + useEffect(() => { + const register = (url: string) => { + // Only set if no pending URL (ignore rapid clicks while dialog is open) + setPendingUrl((current) => (current !== null ? current : url)); + }; + setUrlConfirmationCallback(register); + return () => setUrlConfirmationCallback(null); + }, []); + + const handleConfirm = () => { + if (pendingUrl) { + openExternalUrl(pendingUrl); + setPendingUrl(null); + } + }; + + return ( + !open && setPendingUrl(null)} + onConfirm={handleConfirm} + url={pendingUrl || ""} + /> + ); +} diff --git a/frontend/src/components/UnifiedChat.tsx b/frontend/src/components/UnifiedChat.tsx index a8b97b7d3..d3b3db8e6 100644 --- a/frontend/src/components/UnifiedChat.tsx +++ b/frontend/src/components/UnifiedChat.tsx @@ -245,9 +245,9 @@ function ToolCallRenderer({ {query ? `Searched: "${query}"` : "Web Search"} - {/* Search result - indented to align with text */} -
- {isExpanded ? output : preview} + {/* Search result - indented to align with text, render as markdown for links */} +
+ {hasMore && (
- {/* Tool output - indented */} -
- {isExpanded ? output : preview} + {/* Tool output - indented, render as markdown for links */} +
+ {hasMore && (
-
- {isExpanded ? output : preview} +
+ {hasMore && (