diff --git a/apps/desktop/src/lib/electron-app/factories/app/setup.ts b/apps/desktop/src/lib/electron-app/factories/app/setup.ts index 579fa340392..4c299e24c52 100644 --- a/apps/desktop/src/lib/electron-app/factories/app/setup.ts +++ b/apps/desktop/src/lib/electron-app/factories/app/setup.ts @@ -58,7 +58,9 @@ export async function makeAppSetup( // Always prevent in-app navigation for external URLs if (url.startsWith("http://") || url.startsWith("https://")) { event.preventDefault(); - shell.openExternal(url); + shell.openExternal(url).catch((error) => { + console.error("[app] Failed to open external URL:", url, error); + }); } }), ); diff --git a/apps/desktop/src/lib/electron-app/factories/windows/create.ts b/apps/desktop/src/lib/electron-app/factories/windows/create.ts index 479cb0faf03..d5a02931151 100644 --- a/apps/desktop/src/lib/electron-app/factories/windows/create.ts +++ b/apps/desktop/src/lib/electron-app/factories/windows/create.ts @@ -9,7 +9,9 @@ export function createWindow({ id, ...settings }: WindowProps) { // Open external URLs in the system browser instead of Electron window.webContents.setWindowOpenHandler(({ url }) => { if (url.startsWith("http://") || url.startsWith("https://")) { - shell.openExternal(url); + shell.openExternal(url).catch((error) => { + console.error("[window] Failed to open external URL:", url, error); + }); return { action: "deny" }; } return { action: "deny" }; diff --git a/apps/desktop/src/lib/trpc/routers/external/index.ts b/apps/desktop/src/lib/trpc/routers/external/index.ts index a0e2f9c659c..13d4450e672 100644 --- a/apps/desktop/src/lib/trpc/routers/external/index.ts +++ b/apps/desktop/src/lib/trpc/routers/external/index.ts @@ -1,4 +1,5 @@ import { settings } from "@superset/local-db"; +import { TRPCError } from "@trpc/server"; import { clipboard, shell } from "electron"; import { localDb } from "main/lib/local-db"; import { z } from "zod"; @@ -38,7 +39,17 @@ async function openPathInApp( export const createExternalRouter = () => { return router({ openUrl: publicProcedure.input(z.string()).mutation(async ({ input }) => { - await shell.openExternal(input); + try { + await shell.openExternal(input); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + console.error("[external/openUrl] Failed to open URL:", input, error); + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: errorMessage, + }); + } }), openInFinder: publicProcedure diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts index 6058503b816..3c92f907dd2 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts @@ -1,3 +1,4 @@ +import { toast } from "@superset/ui/sonner"; import { CanvasAddon } from "@xterm/addon-canvas"; import { ClipboardAddon } from "@xterm/addon-clipboard"; import { FitAddon } from "@xterm/addon-fit"; @@ -135,6 +136,12 @@ export function createTerminalInstance( const urlLinkProvider = new UrlLinkProvider(xterm, (_event, uri) => { trpcClient.external.openUrl.mutate(uri).catch((error) => { console.error("[Terminal] Failed to open URL:", uri, error); + toast.error("Failed to open URL", { + description: + error instanceof Error + ? error.message + : "Could not open URL in browser", + }); }); }); xterm.registerLinkProvider(urlLinkProvider);