"use client"; import { LoadingButton } from "@/components/loading-button"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { getBrowserDisplayName, getBrowserIcon } from "@/lib/browser-utils"; import type { BrowserProfile } from "@/types"; import { invoke } from "@tauri-apps/api/core"; import { useEffect, useState } from "react"; import { LuCopy } from "react-icons/lu"; import { toast } from "sonner"; interface ProfileSelectorDialogProps { isOpen: boolean; onClose: () => void; url?: string; runningProfiles?: Set; } export function ProfileSelectorDialog({ isOpen, onClose, url, runningProfiles = new Set(), }: ProfileSelectorDialogProps) { const [profiles, setProfiles] = useState([]); const [selectedProfile, setSelectedProfile] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isLaunching, setIsLaunching] = useState(false); useEffect(() => { if (isOpen) { void loadProfiles(); } }, [isOpen]); const loadProfiles = async () => { setIsLoading(true); try { const profileList = await invoke( "list_browser_profiles", ); // Sort profiles by name profileList.sort((a, b) => a.name.localeCompare(b.name)); // Don't filter any profiles, show all of them setProfiles(profileList); // Auto-select first available profile for link opening if (profileList.length > 0) { // First, try to find a running profile that can be used for opening links const runningAvailableProfile = profileList.find((profile) => { const isRunning = runningProfiles.has(profile.name); return ( isRunning && canUseProfileForLinks(profile, profileList, runningProfiles) ); }); if (runningAvailableProfile) { setSelectedProfile(runningAvailableProfile.name); } else { // If no running profile is suitable, find the first profile that can be used for opening links const availableProfile = profileList.find((profile) => { return canUseProfileForLinks(profile, profileList, runningProfiles); }); if (availableProfile) { setSelectedProfile(availableProfile.name); } else { // If no suitable profile found, still select the first one to show UI setSelectedProfile(profileList[0].name); } } } } catch (error) { console.error("Failed to load profiles:", error); } finally { setIsLoading(false); } }; // Helper function to determine if a profile can be used for opening links const canUseProfileForLinks = ( profile: BrowserProfile, allProfiles: BrowserProfile[], runningProfiles: Set, ): boolean => { const isRunning = runningProfiles.has(profile.name); // For TOR browser: Check if any TOR browser is running if (profile.browser === "tor-browser") { const runningTorProfiles = allProfiles.filter( (p) => p.browser === "tor-browser" && runningProfiles.has(p.name), ); // If no TOR browser is running, allow any TOR profile if (runningTorProfiles.length === 0) { return true; } // If TOR browser(s) are running, only allow the running one(s) return isRunning; } // For Mullvad browser: never allow if running if (profile.browser === "mullvad-browser" && isRunning) { return false; } // For other browsers: always allow return true; }; // Helper function to get tooltip content for profiles const getProfileTooltipContent = (profile: BrowserProfile): string => { const isRunning = runningProfiles.has(profile.name); if (profile.browser === "tor-browser") { // If another TOR profile is running, this one is not available return "Only 1 instance can run at a time"; } if (profile.browser === "mullvad-browser") { if (isRunning) { return "Only launching the browser is supported, opening them in a running browser is not yet available"; } return "Only launching the browser is supported, opening them in a running browser is not yet available"; } if (isRunning) { return "URL will open in a new tab in the existing browser window"; } return ""; }; const handleOpenUrl = async () => { if (!selectedProfile || !url) return; setIsLaunching(true); try { await invoke("open_url_with_profile", { profileName: selectedProfile, url, }); onClose(); } catch (error) { console.error("Failed to open URL with profile:", error); } finally { setIsLaunching(false); } }; const handleCancel = () => { setSelectedProfile(null); onClose(); }; const handleCopyUrl = async () => { if (!url) return; try { await navigator.clipboard.writeText(url); toast.success("URL copied to clipboard!"); } catch (error) { console.error("Failed to copy URL:", error); toast.error("Failed to copy URL to clipboard"); } }; const selectedProfileData = profiles.find((p) => p.name === selectedProfile); // Check if the selected profile can be used for opening links const canOpenWithSelectedProfile = () => { if (!selectedProfileData) return false; return canUseProfileForLinks( selectedProfileData, profiles, runningProfiles, ); }; // Get tooltip content for disabled profiles const getTooltipContent = () => { if (!selectedProfileData) return ""; return getProfileTooltipContent(selectedProfileData); }; return ( Choose Profile
{url && (
{url}
)}
{isLoading ? (
Loading profiles...
) : profiles.length === 0 ? (
No profiles available. Please create a profile first.
Close this dialog and create a profile from the main window to get started.
) : ( <> )}
void handleOpenUrl()} disabled={ !selectedProfile || profiles.length === 0 || !canOpenWithSelectedProfile() } > Open
{getTooltipContent() && ( {getTooltipContent()} )}
); }