refactor: disable mullvad and tor profile creation as well as nightly releases

This commit is contained in:
zhom
2025-08-10 06:57:45 +04:00
parent 92ef2798d2
commit daa36f008b
6 changed files with 88 additions and 126 deletions
+1 -1
View File
@@ -414,7 +414,7 @@ mod linux {
Err("Could not detect theme from system files".into())
}
fn is_command_available(command: &str) -> bool {
pub fn is_command_available(command: &str) -> bool {
Command::new("which")
.arg(command)
.output()
+24 -1
View File
@@ -23,7 +23,7 @@ import { useAppUpdateNotifications } from "@/hooks/use-app-update-notifications"
import type { PermissionType } from "@/hooks/use-permissions";
import { usePermissions } from "@/hooks/use-permissions";
import { useUpdateNotifications } from "@/hooks/use-update-notifications";
import { showErrorToast } from "@/lib/toast-utils";
import { showErrorToast, showToast } from "@/lib/toast-utils";
import type { BrowserProfile, CamoufoxConfig, GroupWithCount } from "@/types";
type BrowserTypeString =
@@ -713,6 +713,29 @@ export default function Home() {
loadGroups,
]);
// Show deprecation warning for unsupported profiles
useEffect(() => {
if (profiles.length === 0) return;
const hasDeprecated = profiles.some(
(p) =>
["tor-browser", "mullvad-browser"].includes(p.browser) ||
(p.release_type === "nightly" && p.browser !== "firefox-developer"),
);
if (hasDeprecated) {
// Use a stable id to avoid duplicate toasts on re-renders
showToast({
id: "deprecated-profiles-warning",
type: "error",
title: "Some profiles will be deprecated soon",
description:
"Tor, Mullvad Browser and nightly profiles (except Firefox Developers Edition) will be removed in upcoming versions. Please check GitHub for migration instructions which will be available soon.",
duration: 15000,
});
}
}, [profiles]);
useEffect(() => {
if (profiles.length === 0) return;
+34 -67
View File
@@ -2,11 +2,9 @@
import { invoke } from "@tauri-apps/api/core";
import { useCallback, useEffect, useState } from "react";
import { LuTriangleAlert } from "react-icons/lu";
import { LoadingButton } from "@/components/loading-button";
import { ReleaseTypeSelector } from "@/components/release-type-selector";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Checkbox } from "@/components/ui/checkbox";
import { Alert, AlertDescription } from "@/components/ui/alert";
import {
Dialog,
DialogContent,
@@ -39,8 +37,8 @@ export function ChangeVersionDialog({
const [releaseTypes, setReleaseTypes] = useState<BrowserReleaseTypes>({});
const [isLoadingReleaseTypes, setIsLoadingReleaseTypes] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);
const [showDowngradeWarning, setShowDowngradeWarning] = useState(false);
const [acknowledgeDowngrade, setAcknowledgeDowngrade] = useState(false);
// Nightly switching is disabled for non-nightly profiles (except Firefox Developer),
// so downgrade warnings are no longer applicable.
const {
downloadedVersions,
@@ -50,38 +48,36 @@ export function ChangeVersionDialog({
isVersionDownloaded,
} = useBrowserDownload();
const loadReleaseTypes = useCallback(async (browser: string) => {
setIsLoadingReleaseTypes(true);
try {
const releaseTypes = await invoke<BrowserReleaseTypes>(
"get_browser_release_types",
{ browserStr: browser },
);
setReleaseTypes(releaseTypes);
} catch (error) {
console.error("Failed to load release types:", error);
} finally {
setIsLoadingReleaseTypes(false);
}
}, []);
useEffect(() => {
if (
profile &&
selectedReleaseType &&
selectedReleaseType !== profile.release_type
) {
// For simplicity, we'll show downgrade warning when switching from stable to nightly
// since nightly versions might be considered "downgrades" in terms of stability
const isDowngrade =
profile.release_type === "stable" && selectedReleaseType === "nightly";
setShowDowngradeWarning(isDowngrade);
if (!isDowngrade) {
setAcknowledgeDowngrade(false);
const loadReleaseTypes = useCallback(
async (browser: string) => {
setIsLoadingReleaseTypes(true);
try {
const releaseTypes = await invoke<BrowserReleaseTypes>(
"get_browser_release_types",
{ browserStr: browser },
);
// Filter nightly visibility based on rules:
// - Firefox Developer Edition: allow nightly only
// - If profile is currently nightly: allow both stable and nightly
// - Otherwise: allow stable only
const filtered: BrowserReleaseTypes = {};
if (profile?.browser === "firefox-developer") {
if (releaseTypes.nightly) filtered.nightly = releaseTypes.nightly;
} else if (profile?.release_type === "nightly") {
if (releaseTypes.stable) filtered.stable = releaseTypes.stable;
if (releaseTypes.nightly) filtered.nightly = releaseTypes.nightly;
} else {
if (releaseTypes.stable) filtered.stable = releaseTypes.stable;
}
setReleaseTypes(filtered);
} catch (error) {
console.error("Failed to load release types:", error);
} finally {
setIsLoadingReleaseTypes(false);
}
}
}, [selectedReleaseType, profile]);
},
[profile?.browser, profile?.release_type],
);
const handleDownload = useCallback(async () => {
if (!profile || !selectedReleaseType) return;
@@ -129,14 +125,12 @@ export function ChangeVersionDialog({
selectedReleaseType &&
selectedReleaseType !== profile.release_type &&
selectedVersion &&
isVersionDownloaded(selectedVersion) &&
(!showDowngradeWarning || acknowledgeDowngrade);
isVersionDownloaded(selectedVersion);
useEffect(() => {
if (isOpen && profile) {
// Set current release type based on profile
setSelectedReleaseType(profile.release_type as "stable" | "nightly");
setAcknowledgeDowngrade(false);
void loadReleaseTypes(profile.browser);
void loadDownloadedVersions(profile.browser);
}
@@ -206,7 +200,6 @@ export function ChangeVersionDialog({
selectedReleaseType={selectedReleaseType}
onReleaseTypeSelect={setSelectedReleaseType}
availableReleaseTypes={releaseTypes}
browser={profile.browser}
isDownloading={isBrowserDownloading(profile.browser)}
onDownload={() => {
void handleDownload();
@@ -246,7 +239,6 @@ export function ChangeVersionDialog({
selectedReleaseType={selectedReleaseType}
onReleaseTypeSelect={setSelectedReleaseType}
availableReleaseTypes={releaseTypes}
browser={profile.browser}
isDownloading={isBrowserDownloading(profile.browser)}
onDownload={() => {
void handleDownload();
@@ -259,32 +251,7 @@ export function ChangeVersionDialog({
</div>
)}
{/* Downgrade Warning */}
{showDowngradeWarning && (
<Alert className="border-orange-700">
<LuTriangleAlert className="w-4 h-4 text-orange-700" />
<AlertTitle className="text-orange-700">
Stability Warning
</AlertTitle>
<AlertDescription className="text-orange-700">
You are about to switch from stable to nightly releases. Nightly
versions may be less stable and could contain bugs or incomplete
features.
<div className="flex items-center mt-3 space-x-2">
<Checkbox
id="acknowledge-downgrade"
checked={acknowledgeDowngrade}
onCheckedChange={(checked) => {
setAcknowledgeDowngrade(checked as boolean);
}}
/>
<Label htmlFor="acknowledge-downgrade" className="text-sm">
I understand the risks and want to proceed
</Label>
</div>
</AlertDescription>
</Alert>
)}
{/* Nightly switching disabled in UI; no downgrade warning needed. */}
</div>
<DialogFooter>
+25 -19
View File
@@ -191,10 +191,19 @@ export function CreateProfileDialog({
// Only update state if this browser is still the one we're loading
if (loadingBrowserRef.current === browser) {
// Filter to enforce stable-only creation, except Firefox Developer (nightly-only)
if (browser === "camoufox") {
setCamoufoxReleaseTypes(releaseTypes);
const filtered: BrowserReleaseTypes = {};
if (releaseTypes.stable) filtered.stable = releaseTypes.stable;
setCamoufoxReleaseTypes(filtered);
} else if (browser === "firefox-developer") {
const filtered: BrowserReleaseTypes = {};
if (releaseTypes.nightly) filtered.nightly = releaseTypes.nightly;
setAvailableReleaseTypes(filtered);
} else {
setAvailableReleaseTypes(releaseTypes);
const filtered: BrowserReleaseTypes = {};
if (releaseTypes.stable) filtered.stable = releaseTypes.stable;
setAvailableReleaseTypes(filtered);
}
// Load downloaded versions for this browser
@@ -241,26 +250,20 @@ export function CreateProfileDialog({
}
}, [selectedBrowser, loadReleaseTypes]);
// Helper function to get the best available version and release type
// Helper function to get the best available version respecting rules
const getBestAvailableVersion = useCallback(
(releaseTypes: BrowserReleaseTypes, browserType?: string) => {
// For Firefox Developer Edition, prefer nightly over stable
// Firefox Developer Edition: nightly-only
if (browserType === "firefox-developer" && releaseTypes.nightly) {
return {
version: releaseTypes.nightly,
releaseType: "nightly" as const,
};
}
// All others: stable-only
if (releaseTypes.stable) {
return { version: releaseTypes.stable, releaseType: "stable" as const };
}
if (releaseTypes.nightly) {
return {
version: releaseTypes.nightly,
releaseType: "nightly" as const,
};
}
return null;
},
[],
@@ -438,8 +441,11 @@ export function CreateProfileDialog({
<Label>Browser</Label>
<Combobox
options={browserOptions
.filter((browser) =>
supportedBrowsers.includes(browser.value),
.filter(
(browser) =>
supportedBrowsers.includes(browser.value) &&
browser.value !== "mullvad-browser" &&
browser.value !== "tor-browser",
)
.map((browser) => {
const IconComponent = getBrowserIcon(browser.value);
@@ -473,7 +479,7 @@ export function CreateProfileDialog({
availableReleaseTypes,
selectedBrowser,
);
return `${bestVersion?.releaseType === "stable" ? "Latest stable" : "Latest nightly"} version (${bestVersion?.version}) needs to be downloaded`;
return `Latest version (${bestVersion?.version}) needs to be downloaded`;
})()}
</p>
<LoadingButton
@@ -498,7 +504,7 @@ export function CreateProfileDialog({
availableReleaseTypes,
selectedBrowser,
);
return `${bestVersion?.releaseType === "stable" ? "Latest stable" : "Latest nightly"} version (${bestVersion?.version}) is available`;
return `Latest version (${bestVersion?.version}) is available`;
})()}
</div>
)}
@@ -509,7 +515,7 @@ export function CreateProfileDialog({
availableReleaseTypes,
selectedBrowser,
);
return `Downloading ${bestVersion?.releaseType === "stable" ? "stable" : "nightly"} version (${bestVersion?.version})...`;
return `Downloading version (${bestVersion?.version})...`;
})()}
</div>
)}
@@ -534,7 +540,7 @@ export function CreateProfileDialog({
camoufoxReleaseTypes,
"camoufox",
);
return `Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version}) needs to be downloaded`;
return `Camoufox version (${bestVersion?.version}) needs to be downloaded`;
})()}
</p>
<LoadingButton
@@ -559,7 +565,7 @@ export function CreateProfileDialog({
camoufoxReleaseTypes,
"camoufox",
);
return `✓ Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version}) is available`;
return `✓ Camoufox version (${bestVersion?.version}) is available`;
})()}
</div>
)}
@@ -570,7 +576,7 @@ export function CreateProfileDialog({
camoufoxReleaseTypes,
"camoufox",
);
return `Downloading Camoufox ${bestVersion?.releaseType} version (${bestVersion?.version})...`;
return `Downloading Camoufox version (${bestVersion?.version})...`;
})()}
</div>
)}
-30
View File
@@ -666,36 +666,6 @@ export function ProfilesDataTable({
);
},
},
{
accessorKey: "release_type",
header: "Release",
cell: ({ row }) => {
const releaseType: string = row.getValue("release_type");
const isNightly = releaseType === "nightly";
return (
<div className="flex items-center">
<span
className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${
isNightly
? "text-yellow-800 bg-yellow-100 dark:bg-yellow-900 dark:text-yellow-200"
: "text-green-800 bg-green-100 dark:bg-green-900 dark:text-green-200"
}`}
>
{isNightly ? "Nightly" : "Stable"}
</span>
</div>
);
},
enableSorting: true,
sortingFn: (rowA, rowB, columnId) => {
const releaseA: string = rowA.getValue(columnId);
const releaseB: string = rowB.getValue(columnId);
// Sort with "stable" before "nightly"
if (releaseA === "stable" && releaseB === "nightly") return -1;
if (releaseA === "nightly" && releaseB === "stable") return 1;
return 0;
},
},
{
id: "proxy",
header: "Proxy",
+4 -8
View File
@@ -24,7 +24,6 @@ interface ReleaseTypeSelectorProps {
selectedReleaseType: "stable" | "nightly" | null;
onReleaseTypeSelect: (releaseType: "stable" | "nightly" | null) => void;
availableReleaseTypes: BrowserReleaseTypes;
browser: string;
isDownloading: boolean;
onDownload: () => void;
placeholder?: string;
@@ -36,7 +35,7 @@ export function ReleaseTypeSelector({
selectedReleaseType,
onReleaseTypeSelect,
availableReleaseTypes,
browser,
// browser prop removed; callers control availableReleaseTypes
isDownloading,
onDownload,
placeholder = "Select release type...",
@@ -45,11 +44,13 @@ export function ReleaseTypeSelector({
}: ReleaseTypeSelectorProps) {
const [popoverOpen, setPopoverOpen] = useState(false);
// Nightly visibility is controlled by callers. This component will render
// whichever options are provided via availableReleaseTypes.
const releaseOptions = [
...(availableReleaseTypes.stable
? [{ type: "stable" as const, version: availableReleaseTypes.stable }]
: []),
...(availableReleaseTypes.nightly && browser !== "chromium"
...(availableReleaseTypes.nightly
? [{ type: "nightly" as const, version: availableReleaseTypes.nightly }]
: []),
];
@@ -159,11 +160,6 @@ export function ReleaseTypeSelector({
<span className="text-sm font-medium capitalize">
{releaseOptions[0].type}
</span>
{releaseOptions[0].type === "nightly" && (
<Badge variant="secondary" className="text-xs">
Nightly
</Badge>
)}
<Badge variant="outline" className="text-xs">
{releaseOptions[0].version}
</Badge>