diff --git a/src/app/components/uia-stages/SSOStage.tsx b/src/app/components/uia-stages/SSOStage.tsx index f85bcb3..b937329 100644 --- a/src/app/components/uia-stages/SSOStage.tsx +++ b/src/app/components/uia-stages/SSOStage.tsx @@ -1,3 +1,4 @@ +import { openExternalUrl } from '../../utils/tauri'; import { Box, Button, color, config, Dialog, Header, Icon, IconButton, Icons, Text } from 'folds'; import React, { useCallback, useEffect, useState } from 'react'; import { StageComponentProps } from './types'; @@ -20,8 +21,8 @@ export function SSOStage({ }, [submitAuthDict, session]); const handleContinue = () => { - const w = window.open(ssoRedirectURL, '_blank'); - setSSOWindow(w ?? undefined); + openExternalUrl(ssoRedirectURL); + setSSOWindow(undefined); }; useEffect(() => { diff --git a/src/app/components/user-profile/UserChips.tsx b/src/app/components/user-profile/UserChips.tsx index 53e6618..dff0c2a 100644 --- a/src/app/components/user-profile/UserChips.tsx +++ b/src/app/components/user-profile/UserChips.tsx @@ -1,4 +1,5 @@ import React, { MouseEventHandler, useCallback, useMemo, useState } from 'react'; +import { openExternalUrl } from '../../utils/tauri'; import { useNavigate } from 'react-router-dom'; import FocusTrap from 'focus-trap-react'; import { isKeyHotkey } from 'is-hotkey'; @@ -110,7 +111,7 @@ export function ServerChip({ server }: { server: string }) { size="300" radii="300" onClick={() => { - window.open(`https://${server}`, '_blank'); + openExternalUrl(`https://${server}`); close(); }} > diff --git a/src/app/features/settings/devices/OtherDevices.tsx b/src/app/features/settings/devices/OtherDevices.tsx index 4bd83dd..fba7356 100644 --- a/src/app/features/settings/devices/OtherDevices.tsx +++ b/src/app/features/settings/devices/OtherDevices.tsx @@ -1,4 +1,5 @@ import React, { useCallback, useState } from 'react'; +import { openExternalUrl } from '../../../utils/tauri'; import { Box, Button, config, Menu, Spinner, Text } from 'folds'; import { AuthDict, IMyDevice, MatrixError } from 'matrix-js-sdk'; import { SequenceCard } from '../../../components/sequence-card'; @@ -33,11 +34,10 @@ export function OtherDevices({ devices, refreshDeviceList, showVerification }: O const authUrl = authMetadata?.account_management_uri ?? authMetadata?.issuer; if (!authUrl) return; - window.open( + openExternalUrl( withSearchParam(authUrl, { action: accountManagementActions.sessionsList, - }), - '_blank' + }) ); }, [authMetadata, accountManagementActions]); @@ -46,12 +46,11 @@ export function OtherDevices({ devices, refreshDeviceList, showVerification }: O const authUrl = authMetadata?.account_management_uri ?? authMetadata?.issuer; if (!authUrl) return; - window.open( + openExternalUrl( withSearchParam(authUrl, { action: accountManagementActions.sessionEnd, device_id: deviceId, - }), - '_blank' + }) ); }, [authMetadata, accountManagementActions] diff --git a/src/app/features/settings/devices/Verification.tsx b/src/app/features/settings/devices/Verification.tsx index 6c7eab1..6abaf8d 100644 --- a/src/app/features/settings/devices/Verification.tsx +++ b/src/app/features/settings/devices/Verification.tsx @@ -35,6 +35,7 @@ import { stopPropagation } from '../../../utils/keyboard'; import { useAuthMetadata } from '../../../hooks/useAuthMetadata'; import { withSearchParam } from '../../../pages/pathUtils'; import { useAccountManagementActions } from '../../../hooks/useAccountManagement'; +import { openExternalUrl } from '../../../utils/tauri'; type VerificationStatusBadgeProps = { verificationStatus: VerificationStatus; @@ -273,11 +274,10 @@ export function DeviceVerificationOptions() { if (authMetadata) { const authUrl = authMetadata.account_management_uri ?? authMetadata.issuer; - window.open( + openExternalUrl( withSearchParam(authUrl, { action: accountManagementActions.crossSigningReset, - }), - '_blank' + }) ); return; } diff --git a/src/app/utils/tauri.ts b/src/app/utils/tauri.ts index c335571..a60417b 100644 --- a/src/app/utils/tauri.ts +++ b/src/app/utils/tauri.ts @@ -1,3 +1,19 @@ +/** + * Open an external URL using Tauri shell on desktop/mobile, or window.open in browser + * @param url The URL to open + */ +export const openExternalUrl = async (url: string): Promise => { + if (isTauri()) { + try { + const { open } = await import('@tauri-apps/plugin-shell'); + await open(url); + return; + } catch (err) { + console.warn('Tauri shell.open failed, falling back to window.open:', err); + } + } + window.open(url, '_blank'); +}; /** * Tauri-specific utilities for desktop and mobile platforms */