mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-04-29 15:26:05 +02:00
chore: remove prettier to not conflict with biome
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.next/
|
||||
src-tauri/target/
|
||||
*.lock
|
||||
pnpm-lock.yaml
|
||||
*.log
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"semi": true,
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": false,
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false
|
||||
}
|
||||
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
"cSpell.words": [
|
||||
"autologin",
|
||||
"CFURL",
|
||||
"clippy",
|
||||
"donutbrowser",
|
||||
"launchservices",
|
||||
"mountpoint",
|
||||
|
||||
+4
-7
@@ -7,16 +7,15 @@
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "biome ci src/ && tsc --noEmit && next lint",
|
||||
"lint": "biome check src/ && tsc --noEmit && next lint",
|
||||
"lint:rust": "cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings -D clippy::all",
|
||||
"tauri": "tauri",
|
||||
"shadcn:add": "pnpm dlx shadcn@latest add",
|
||||
"prepare": "husky",
|
||||
"format:js": "biome check src/ --fix && prettier --write src/",
|
||||
"format:js": "biome check src/ --fix",
|
||||
"format:rust": "cd src-tauri && cargo fmt --all",
|
||||
"format:biome": "biome check src/ --fix",
|
||||
"format": "pnpm format:js && pnpm format:rust",
|
||||
"prettier": "prettier --write"
|
||||
"format": "pnpm format:js && pnpm format:rust"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-checkbox": "^1.3.2",
|
||||
@@ -62,7 +61,6 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.3.0",
|
||||
"prettier": "^3.5.3",
|
||||
"tailwindcss": "^4.1.7",
|
||||
"tw-animate-css": "^1.3.0",
|
||||
"typescript": "~5.8.3",
|
||||
@@ -71,8 +69,7 @@
|
||||
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977",
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx,ts,tsx,json,css,md}": [
|
||||
"biome check --fix",
|
||||
"prettier --write"
|
||||
"biome check --fix"
|
||||
],
|
||||
"src-tauri/**/*.rs": [
|
||||
"cd src-tauri && cargo fmt --all",
|
||||
|
||||
Generated
-10
@@ -132,9 +132,6 @@ importers:
|
||||
lint-staged:
|
||||
specifier: ^15.3.0
|
||||
version: 15.5.2
|
||||
prettier:
|
||||
specifier: ^3.5.3
|
||||
version: 3.5.3
|
||||
tailwindcss:
|
||||
specifier: ^4.1.7
|
||||
version: 4.1.7
|
||||
@@ -2700,11 +2697,6 @@ packages:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
prettier@3.5.3:
|
||||
resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
|
||||
@@ -5707,8 +5699,6 @@ snapshots:
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prettier@3.5.3: {}
|
||||
|
||||
prop-types@15.8.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
@@ -104,15 +104,9 @@ impl VersionComponent {
|
||||
|
||||
// Extract kind and number
|
||||
let (kind, number) = if let Some(stripped) = pre_release.strip_prefix("alpha") {
|
||||
(
|
||||
PreReleaseKind::Alpha,
|
||||
Self::extract_number(stripped),
|
||||
)
|
||||
(PreReleaseKind::Alpha, Self::extract_number(stripped))
|
||||
} else if let Some(stripped) = pre_release.strip_prefix("beta") {
|
||||
(
|
||||
PreReleaseKind::Beta,
|
||||
Self::extract_number(stripped),
|
||||
)
|
||||
(PreReleaseKind::Beta, Self::extract_number(stripped))
|
||||
} else if let Some(stripped) = pre_release.strip_prefix("rc") {
|
||||
(PreReleaseKind::RC, Self::extract_number(stripped))
|
||||
} else if let Some(stripped) = pre_release.strip_prefix("dev") {
|
||||
@@ -120,15 +114,9 @@ impl VersionComponent {
|
||||
} else if let Some(stripped) = pre_release.strip_prefix("pre") {
|
||||
(PreReleaseKind::Pre, Self::extract_number(stripped))
|
||||
} else if let Some(stripped) = pre_release.strip_prefix('a') {
|
||||
(
|
||||
PreReleaseKind::Alpha,
|
||||
Self::extract_number(stripped),
|
||||
)
|
||||
(PreReleaseKind::Alpha, Self::extract_number(stripped))
|
||||
} else if let Some(stripped) = pre_release.strip_prefix('b') {
|
||||
(
|
||||
PreReleaseKind::Beta,
|
||||
Self::extract_number(stripped),
|
||||
)
|
||||
(PreReleaseKind::Beta, Self::extract_number(stripped))
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
+21
-21
@@ -63,7 +63,7 @@ export default function Home() {
|
||||
|
||||
try {
|
||||
const profileList = await invoke<BrowserProfile[]>(
|
||||
"list_browser_profiles"
|
||||
"list_browser_profiles",
|
||||
);
|
||||
setProfiles(profileList);
|
||||
|
||||
@@ -94,7 +94,7 @@ export default function Home() {
|
||||
() => {
|
||||
void checkForUpdates();
|
||||
},
|
||||
30 * 60 * 1000
|
||||
30 * 60 * 1000,
|
||||
);
|
||||
|
||||
return () => {
|
||||
@@ -107,7 +107,7 @@ export default function Home() {
|
||||
|
||||
try {
|
||||
const shouldShow = await invoke<boolean>(
|
||||
"should_show_settings_on_startup"
|
||||
"should_show_settings_on_startup",
|
||||
);
|
||||
if (shouldShow) {
|
||||
setSettingsDialogOpen(true);
|
||||
@@ -122,7 +122,7 @@ export default function Home() {
|
||||
|
||||
try {
|
||||
const hasStartupUrl = await invoke<boolean>(
|
||||
"check_and_handle_startup_url"
|
||||
"check_and_handle_startup_url",
|
||||
);
|
||||
if (hasStartupUrl) {
|
||||
console.log("Handled startup URL successfully");
|
||||
@@ -155,10 +155,10 @@ export default function Home() {
|
||||
await listen<string>("show-create-profile-dialog", (event) => {
|
||||
console.log(
|
||||
"Received show create profile dialog request:",
|
||||
event.payload
|
||||
event.payload,
|
||||
);
|
||||
setError(
|
||||
"No profiles available. Please create a profile first before opening URLs."
|
||||
"No profiles available. Please create a profile first before opening URLs.",
|
||||
);
|
||||
setCreateProfileDialogOpen(true);
|
||||
});
|
||||
@@ -180,7 +180,7 @@ export default function Home() {
|
||||
} catch (error: unknown) {
|
||||
console.log(
|
||||
"Smart URL opening failed or requires profile selection:",
|
||||
error
|
||||
error,
|
||||
);
|
||||
|
||||
// Show profile selector for manual selection
|
||||
@@ -216,7 +216,7 @@ export default function Home() {
|
||||
setError(`Failed to update proxy settings: ${JSON.stringify(err)}`);
|
||||
}
|
||||
},
|
||||
[currentProfileForProxy, loadProfiles]
|
||||
[currentProfileForProxy, loadProfiles],
|
||||
);
|
||||
|
||||
const handleCreateProfile = useCallback(
|
||||
@@ -235,7 +235,7 @@ export default function Home() {
|
||||
name: profileData.name,
|
||||
browserStr: profileData.browserStr,
|
||||
version: profileData.version,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Update proxy if provided
|
||||
@@ -249,16 +249,16 @@ export default function Home() {
|
||||
await loadProfiles();
|
||||
} catch (error) {
|
||||
setError(
|
||||
`Failed to create profile: ${error instanceof Error ? error.message : String(error)}`
|
||||
`Failed to create profile: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[loadProfiles]
|
||||
[loadProfiles],
|
||||
);
|
||||
|
||||
const [runningProfiles, setRunningProfiles] = useState<Set<string>>(
|
||||
new Set()
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const runningProfilesRef = useRef<Set<string>>(new Set());
|
||||
@@ -290,7 +290,7 @@ export default function Home() {
|
||||
console.error("Failed to check browser status:", err);
|
||||
}
|
||||
},
|
||||
[isClient]
|
||||
[isClient],
|
||||
);
|
||||
|
||||
const launchProfile = useCallback(
|
||||
@@ -305,12 +305,12 @@ export default function Home() {
|
||||
"is_browser_disabled_for_update",
|
||||
{
|
||||
browser: profile.browser,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (isDisabled || isUpdating(profile.browser)) {
|
||||
setError(
|
||||
`${profile.browser} is currently being updated. Please wait for the update to complete.`
|
||||
`${profile.browser} is currently being updated. Please wait for the update to complete.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -321,7 +321,7 @@ export default function Home() {
|
||||
try {
|
||||
const updatedProfile = await invoke<BrowserProfile>(
|
||||
"launch_browser_profile",
|
||||
{ profile }
|
||||
{ profile },
|
||||
);
|
||||
await loadProfiles();
|
||||
await checkBrowserStatus(updatedProfile);
|
||||
@@ -330,7 +330,7 @@ export default function Home() {
|
||||
setError(`Failed to launch browser: ${JSON.stringify(err)}`);
|
||||
}
|
||||
},
|
||||
[loadProfiles, checkBrowserStatus, isUpdating, isClient]
|
||||
[loadProfiles, checkBrowserStatus, isUpdating, isClient],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -369,7 +369,7 @@ export default function Home() {
|
||||
setError(`Failed to delete profile: ${JSON.stringify(err)}`);
|
||||
}
|
||||
},
|
||||
[loadProfiles]
|
||||
[loadProfiles],
|
||||
);
|
||||
|
||||
const handleRenameProfile = useCallback(
|
||||
@@ -384,7 +384,7 @@ export default function Home() {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
[loadProfiles]
|
||||
[loadProfiles],
|
||||
);
|
||||
|
||||
const handleKillProfile = useCallback(
|
||||
@@ -398,7 +398,7 @@ export default function Home() {
|
||||
setError(`Failed to kill browser: ${JSON.stringify(err)}`);
|
||||
}
|
||||
},
|
||||
[loadProfiles]
|
||||
[loadProfiles],
|
||||
);
|
||||
|
||||
// Don't render anything until we're on the client side to prevent hydration issues
|
||||
@@ -544,7 +544,7 @@ export default function Home() {
|
||||
isOpen={true}
|
||||
onClose={() => {
|
||||
setPendingUrls((prev) =>
|
||||
prev.filter((u) => u.id !== pendingUrl.id)
|
||||
prev.filter((u) => u.id !== pendingUrl.id),
|
||||
);
|
||||
}}
|
||||
url={pendingUrl.url}
|
||||
|
||||
@@ -60,10 +60,10 @@ export function ChangeVersionDialog({
|
||||
if (profile && selectedVersion) {
|
||||
// Check if this is a downgrade
|
||||
const currentVersionIndex = availableVersions.findIndex(
|
||||
(v) => v.tag_name === profile.version
|
||||
(v) => v.tag_name === profile.version,
|
||||
);
|
||||
const selectedVersionIndex = availableVersions.findIndex(
|
||||
(v) => v.tag_name === selectedVersion
|
||||
(v) => v.tag_name === selectedVersion,
|
||||
);
|
||||
|
||||
// If selected version has a higher index, it's older (downgrade)
|
||||
|
||||
@@ -65,7 +65,7 @@ export function CreateProfileDialog({
|
||||
>([]);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
const [existingProfiles, setExistingProfiles] = useState<BrowserProfile[]>(
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
// Proxy settings
|
||||
@@ -120,7 +120,7 @@ export function CreateProfileDialog({
|
||||
const loadSupportedBrowsers = async () => {
|
||||
try {
|
||||
const browsers = await invoke<BrowserTypeString[]>(
|
||||
"get_supported_browsers"
|
||||
"get_supported_browsers",
|
||||
);
|
||||
setSupportedBrowsers(browsers);
|
||||
if (browsers.includes("mullvad-browser")) {
|
||||
@@ -156,7 +156,7 @@ export function CreateProfileDialog({
|
||||
|
||||
// Check for duplicate names (case insensitive)
|
||||
const isDuplicate = existingProfiles.some(
|
||||
(profile) => profile.name.toLowerCase() === trimmedName.toLowerCase()
|
||||
(profile) => profile.name.toLowerCase() === trimmedName.toLowerCase(),
|
||||
);
|
||||
|
||||
if (isDuplicate) {
|
||||
@@ -271,7 +271,7 @@ export function CreateProfileDialog({
|
||||
{browser
|
||||
.split("-")
|
||||
.map(
|
||||
(word) => word.charAt(0).toUpperCase() + word.slice(1)
|
||||
(word) => word.charAt(0).toUpperCase() + word.slice(1),
|
||||
)
|
||||
.join(" ")}
|
||||
</SelectItem>
|
||||
|
||||
@@ -101,7 +101,7 @@ export function ProfilesDataTable({
|
||||
setSorting(newSorting);
|
||||
updateSorting(newSorting);
|
||||
},
|
||||
[sorting, updateSorting, isClient]
|
||||
[sorting, updateSorting, isClient],
|
||||
);
|
||||
|
||||
const handleRename = async () => {
|
||||
@@ -131,7 +131,7 @@ export function ProfilesDataTable({
|
||||
const anyTorRunning =
|
||||
isClient &&
|
||||
data.some(
|
||||
(p) => p.browser === "tor-browser" && runningProfiles.has(p.name)
|
||||
(p) => p.browser === "tor-browser" && runningProfiles.has(p.name),
|
||||
);
|
||||
const shouldDisableTorStart =
|
||||
isTorBrowser && !isRunning && anyTorRunning;
|
||||
@@ -402,7 +402,7 @@ export function ProfilesDataTable({
|
||||
onProxySettings,
|
||||
onDeleteProfile,
|
||||
onChangeVersion,
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
const table = useReactTable({
|
||||
@@ -430,7 +430,7 @@ export function ProfilesDataTable({
|
||||
? null
|
||||
: flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
header.getContext(),
|
||||
)}
|
||||
</TableHead>
|
||||
);
|
||||
@@ -449,7 +449,7 @@ export function ProfilesDataTable({
|
||||
<TableCell key={cell.id}>
|
||||
{flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
cell.getContext(),
|
||||
)}
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
@@ -58,7 +58,7 @@ export function ProfileSelectorDialog({
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const profileList = await invoke<BrowserProfile[]>(
|
||||
"list_browser_profiles"
|
||||
"list_browser_profiles",
|
||||
);
|
||||
|
||||
// Sort profiles by name
|
||||
@@ -92,14 +92,14 @@ export function ProfileSelectorDialog({
|
||||
const canUseProfileForLinks = (
|
||||
profile: BrowserProfile,
|
||||
allProfiles: BrowserProfile[],
|
||||
runningProfiles: Set<string>
|
||||
runningProfiles: Set<string>,
|
||||
): 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)
|
||||
(p) => p.browser === "tor-browser" && runningProfiles.has(p.name),
|
||||
);
|
||||
|
||||
// If no TOR browser is running, allow any TOR profile
|
||||
@@ -126,7 +126,7 @@ export function ProfileSelectorDialog({
|
||||
|
||||
if (profile.browser === "tor-browser") {
|
||||
const runningTorProfiles = profiles.filter(
|
||||
(p) => p.browser === "tor-browser" && runningProfiles.has(p.name)
|
||||
(p) => p.browser === "tor-browser" && runningProfiles.has(p.name),
|
||||
);
|
||||
|
||||
// If another TOR profile is running, this one is not available
|
||||
@@ -192,7 +192,7 @@ export function ProfileSelectorDialog({
|
||||
return canUseProfileForLinks(
|
||||
selectedProfileData,
|
||||
profiles,
|
||||
runningProfiles
|
||||
runningProfiles,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -261,7 +261,7 @@ export function ProfileSelectorDialog({
|
||||
const canUseForLinks = canUseProfileForLinks(
|
||||
profile,
|
||||
profiles,
|
||||
runningProfiles
|
||||
runningProfiles,
|
||||
);
|
||||
const tooltipContent = getProfileTooltipContent(profile);
|
||||
|
||||
@@ -281,7 +281,7 @@ export function ProfileSelectorDialog({
|
||||
<div className="flex items-center gap-2">
|
||||
{(() => {
|
||||
const IconComponent = getBrowserIcon(
|
||||
profile.browser
|
||||
profile.browser,
|
||||
);
|
||||
return IconComponent ? (
|
||||
<IconComponent className="h-4 w-4" />
|
||||
|
||||
@@ -17,7 +17,7 @@ interface CustomThemeProviderProps {
|
||||
function getSystemTheme(): string {
|
||||
if (typeof window !== "undefined") {
|
||||
const isDarkMode = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)"
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
return isDarkMode ? "dark" : "light";
|
||||
}
|
||||
@@ -39,7 +39,7 @@ export function CustomThemeProvider({ children }: CustomThemeProviderProps) {
|
||||
const systemTheme = getSystemTheme();
|
||||
console.log(
|
||||
"First-time user detected, applying system theme:",
|
||||
systemTheme
|
||||
systemTheme,
|
||||
);
|
||||
|
||||
// Save the detected theme as the default
|
||||
|
||||
@@ -16,7 +16,7 @@ const alertVariants = cva(
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function Alert({
|
||||
@@ -40,7 +40,7 @@ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||
data-slot="alert-title"
|
||||
className={cn(
|
||||
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -56,7 +56,7 @@ function AlertDescription({
|
||||
data-slot="alert-description"
|
||||
className={cn(
|
||||
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -22,7 +22,7 @@ const badgeVariants = cva(
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
function Badge({
|
||||
|
||||
@@ -32,7 +32,7 @@ const buttonVariants = cva(
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export type ButtonProps = React.ComponentProps<"button"> &
|
||||
|
||||
@@ -8,7 +8,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
|
||||
data-slot="card"
|
||||
className={cn(
|
||||
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -21,7 +21,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||
data-slot="card-header"
|
||||
className={cn(
|
||||
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -54,7 +54,7 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||
data-slot="card-action"
|
||||
className={cn(
|
||||
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -15,7 +15,7 @@ function Checkbox({
|
||||
data-slot="checkbox"
|
||||
className={cn(
|
||||
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -79,7 +79,7 @@ export function ComboboxDemo() {
|
||||
<LuCheck
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
value === framework.value ? "opacity-100" : "opacity-0"
|
||||
value === framework.value ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
/>
|
||||
{framework.label}
|
||||
|
||||
@@ -22,7 +22,7 @@ function Command({
|
||||
data-slot="command"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -67,7 +67,7 @@ function CommandInput({
|
||||
data-slot="command-input"
|
||||
className={cn(
|
||||
"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -84,7 +84,7 @@ function CommandList({
|
||||
data-slot="command-list"
|
||||
className={cn(
|
||||
"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -112,7 +112,7 @@ function CommandGroup({
|
||||
data-slot="command-group"
|
||||
className={cn(
|
||||
"text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-x-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium overflow-y-scroll",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -141,7 +141,7 @@ function CommandItem({
|
||||
data-slot="command-item"
|
||||
className={cn(
|
||||
"data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -157,7 +157,7 @@ function CommandShortcut({
|
||||
data-slot="command-shortcut"
|
||||
className={cn(
|
||||
"text-muted-foreground ml-auto text-xs tracking-widest",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -39,7 +39,7 @@ function DialogOverlay({
|
||||
data-slot="dialog-overlay"
|
||||
className={cn(
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -58,7 +58,7 @@ function DialogContent({
|
||||
data-slot="dialog-content"
|
||||
className={cn(
|
||||
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -88,7 +88,7 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||
data-slot="dialog-footer"
|
||||
className={cn(
|
||||
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -43,7 +43,7 @@ function DropdownMenuContent({
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -75,7 +75,7 @@ function DropdownMenuItem({
|
||||
data-variant={variant}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -93,7 +93,7 @@ function DropdownMenuCheckboxItem({
|
||||
data-slot="dropdown-menu-checkbox-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
@@ -129,7 +129,7 @@ function DropdownMenuRadioItem({
|
||||
data-slot="dropdown-menu-radio-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -156,7 +156,7 @@ function DropdownMenuLabel({
|
||||
data-inset={inset}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -185,7 +185,7 @@ function DropdownMenuShortcut({
|
||||
data-slot="dropdown-menu-shortcut"
|
||||
className={cn(
|
||||
"text-muted-foreground ml-auto text-xs tracking-widest",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -212,7 +212,7 @@ function DropdownMenuSubTrigger({
|
||||
data-inset={inset}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -231,7 +231,7 @@ function DropdownMenuSubContent({
|
||||
data-slot="dropdown-menu-sub-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -11,7 +11,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
||||
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
||||
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -14,7 +14,7 @@ function Label({
|
||||
data-slot="label"
|
||||
className={cn(
|
||||
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -31,7 +31,7 @@ function PopoverContent({
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -15,7 +15,7 @@ function Progress({
|
||||
data-slot="progress"
|
||||
className={cn(
|
||||
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -43,7 +43,7 @@ function ScrollBar({
|
||||
"h-full w-2.5 border-l border-l-transparent",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -38,7 +38,7 @@ function SelectTrigger({
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -64,7 +64,7 @@ function SelectContent({
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
@@ -74,7 +74,7 @@ function SelectContent({
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
@@ -108,7 +108,7 @@ function SelectItem({
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -144,7 +144,7 @@ function SelectScrollUpButton({
|
||||
data-slot="select-scroll-up-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
@@ -162,7 +162,7 @@ function SelectScrollDownButton({
|
||||
data-slot="select-scroll-down-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -45,7 +45,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
||||
data-slot="table-footer"
|
||||
className={cn(
|
||||
"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -58,7 +58,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
||||
data-slot="table-row"
|
||||
className={cn(
|
||||
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -71,7 +71,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
||||
data-slot="table-head"
|
||||
className={cn(
|
||||
"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
@@ -84,7 +84,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
||||
data-slot="table-cell"
|
||||
className={cn(
|
||||
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
@@ -47,7 +47,7 @@ function TooltipContent({
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
|
||||
@@ -91,7 +91,7 @@ export function VersionSelector({
|
||||
<CommandGroup>
|
||||
{availableVersions.map((version) => {
|
||||
const isDownloaded = downloadedVersions.includes(
|
||||
version.tag_name
|
||||
version.tag_name,
|
||||
);
|
||||
return (
|
||||
<CommandItem
|
||||
@@ -101,7 +101,7 @@ export function VersionSelector({
|
||||
onVersionSelect(
|
||||
currentValue === selectedVersion
|
||||
? null
|
||||
: currentValue
|
||||
: currentValue,
|
||||
);
|
||||
setVersionPopoverOpen(false);
|
||||
}}
|
||||
@@ -111,7 +111,7 @@ export function VersionSelector({
|
||||
"mr-2 h-4 w-4",
|
||||
selectedVersion === version.tag_name
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
: "opacity-0",
|
||||
)}
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -72,7 +72,7 @@ const isAlphaVersion = (version: string): boolean => {
|
||||
|
||||
export function useBrowserDownload() {
|
||||
const [availableVersions, setAvailableVersions] = useState<GithubRelease[]>(
|
||||
[]
|
||||
[],
|
||||
);
|
||||
const [downloadedVersions, setDownloadedVersions] = useState<string[]>([]);
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
@@ -128,7 +128,7 @@ export function useBrowserDownload() {
|
||||
undefined,
|
||||
{
|
||||
suppressCompletionToast: isAutoUpdate,
|
||||
}
|
||||
},
|
||||
);
|
||||
setDownloadProgress(null);
|
||||
}
|
||||
@@ -167,7 +167,7 @@ export function useBrowserDownload() {
|
||||
`Found ${progress.new_versions_found} new browser versions!`,
|
||||
{
|
||||
duration: 3000,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
// Dismiss any update toasts
|
||||
@@ -179,7 +179,7 @@ export function useBrowserDownload() {
|
||||
});
|
||||
toast.dismiss();
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
@@ -222,7 +222,7 @@ export function useBrowserDownload() {
|
||||
try {
|
||||
const versionInfos = await invoke<BrowserVersionInfo[]>(
|
||||
"fetch_browser_versions_cached_first",
|
||||
{ browserStr }
|
||||
{ browserStr },
|
||||
);
|
||||
|
||||
// Convert BrowserVersionInfo to GithubRelease format for compatibility
|
||||
@@ -232,7 +232,7 @@ export function useBrowserDownload() {
|
||||
assets: [],
|
||||
published_at: versionInfo.date,
|
||||
is_alpha: versionInfo.is_prerelease,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
setAvailableVersions(githubReleases);
|
||||
@@ -257,13 +257,13 @@ export function useBrowserDownload() {
|
||||
// Get versions with new count info and cached detailed info
|
||||
const result = await invoke<BrowserVersionsResult>(
|
||||
"fetch_browser_versions_with_count_cached_first",
|
||||
{ browserStr }
|
||||
{ browserStr },
|
||||
);
|
||||
|
||||
// Get detailed version info for compatibility
|
||||
const versionInfos = await invoke<BrowserVersionInfo[]>(
|
||||
"fetch_browser_versions_cached_first",
|
||||
{ browserStr }
|
||||
{ browserStr },
|
||||
);
|
||||
|
||||
// Convert BrowserVersionInfo to GithubRelease format for compatibility
|
||||
@@ -273,7 +273,7 @@ export function useBrowserDownload() {
|
||||
assets: [],
|
||||
published_at: versionInfo.date,
|
||||
is_alpha: versionInfo.is_prerelease,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
setAvailableVersions(githubReleases);
|
||||
@@ -285,7 +285,7 @@ export function useBrowserDownload() {
|
||||
{
|
||||
duration: 3000,
|
||||
description: `Total available: ${result.total_versions_count} versions`,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ export function useBrowserDownload() {
|
||||
try {
|
||||
const downloadedVersions = await invoke<string[]>(
|
||||
"get_downloaded_browser_versions",
|
||||
{ browserStr }
|
||||
{ browserStr },
|
||||
);
|
||||
setDownloadedVersions(downloadedVersions);
|
||||
return downloadedVersions;
|
||||
@@ -319,7 +319,7 @@ export function useBrowserDownload() {
|
||||
async (
|
||||
browserStr: string,
|
||||
version: string,
|
||||
suppressNotifications = false
|
||||
suppressNotifications = false,
|
||||
) => {
|
||||
const browserName = getBrowserDisplayName(browserStr);
|
||||
setIsDownloading(true);
|
||||
@@ -343,14 +343,14 @@ export function useBrowserDownload() {
|
||||
setIsDownloading(false);
|
||||
}
|
||||
},
|
||||
[loadDownloadedVersions]
|
||||
[loadDownloadedVersions],
|
||||
);
|
||||
|
||||
const isVersionDownloaded = useCallback(
|
||||
(version: string) => {
|
||||
return downloadedVersions.includes(version);
|
||||
},
|
||||
[downloadedVersions]
|
||||
[downloadedVersions],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -15,7 +15,7 @@ export function useTableSorting() {
|
||||
const loadSettings = async () => {
|
||||
try {
|
||||
const settings = await invoke<TableSortingSettings>(
|
||||
"get_table_sorting_settings"
|
||||
"get_table_sorting_settings",
|
||||
);
|
||||
setSortingSettings(settings);
|
||||
} catch (error) {
|
||||
@@ -39,7 +39,7 @@ export function useTableSorting() {
|
||||
console.error("Failed to save table sorting settings:", error);
|
||||
}
|
||||
},
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
// Convert our settings to tanstack table sorting format
|
||||
@@ -67,7 +67,7 @@ export function useTableSorting() {
|
||||
void saveSortingSettings(newSettings);
|
||||
}
|
||||
},
|
||||
[saveSortingSettings, isLoaded]
|
||||
[saveSortingSettings, isLoaded],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -18,7 +18,7 @@ interface UpdateNotification {
|
||||
export function useUpdateNotifications() {
|
||||
const [notifications, setNotifications] = useState<UpdateNotification[]>([]);
|
||||
const [updatingBrowsers, setUpdatingBrowsers] = useState<Set<string>>(
|
||||
new Set()
|
||||
new Set(),
|
||||
);
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
|
||||
@@ -32,7 +32,7 @@ export function useUpdateNotifications() {
|
||||
|
||||
try {
|
||||
const updates = await invoke<UpdateNotification[]>(
|
||||
"check_for_browser_updates"
|
||||
"check_for_browser_updates",
|
||||
);
|
||||
setNotifications(updates);
|
||||
|
||||
@@ -51,7 +51,7 @@ export function useUpdateNotifications() {
|
||||
|
||||
// Dismiss all notifications for this browser first
|
||||
const browserNotifications = notifications.filter(
|
||||
(n) => n.browser === browser
|
||||
(n) => n.browser === browser,
|
||||
);
|
||||
for (const notification of browserNotifications) {
|
||||
toast.dismiss(notification.id);
|
||||
@@ -70,7 +70,7 @@ export function useUpdateNotifications() {
|
||||
if (isDownloaded) {
|
||||
// Browser already exists, skip download and go straight to profile update
|
||||
console.log(
|
||||
`${browserDisplayName} ${newVersion} already exists, skipping download`
|
||||
`${browserDisplayName} ${newVersion} already exists, skipping download`,
|
||||
);
|
||||
} else {
|
||||
// Mark download as auto-update in the backend for toast suppression
|
||||
@@ -92,7 +92,7 @@ export function useUpdateNotifications() {
|
||||
{
|
||||
browser,
|
||||
newVersion,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Show success message based on whether profiles were updated
|
||||
@@ -158,7 +158,7 @@ export function useUpdateNotifications() {
|
||||
});
|
||||
}
|
||||
},
|
||||
[notifications, checkForUpdates]
|
||||
[notifications, checkForUpdates],
|
||||
);
|
||||
|
||||
const handleDismiss = useCallback(
|
||||
@@ -173,7 +173,7 @@ export function useUpdateNotifications() {
|
||||
console.error("Failed to dismiss notification:", error);
|
||||
}
|
||||
},
|
||||
[checkForUpdates, isClient]
|
||||
[checkForUpdates, isClient],
|
||||
);
|
||||
|
||||
// Separate effect to show toasts when notifications change
|
||||
@@ -198,7 +198,7 @@ export function useUpdateNotifications() {
|
||||
position: "top-right",
|
||||
// Remove transparent styling to fix background issue
|
||||
style: undefined,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}, [notifications, updatingBrowsers, handleUpdate, handleDismiss, isClient]);
|
||||
|
||||
@@ -61,7 +61,7 @@ export function useVersionUpdater() {
|
||||
total: progress.total_browsers,
|
||||
found: progress.new_versions_found,
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
showLoadingToast("Starting version update check...", {
|
||||
@@ -81,7 +81,7 @@ export function useVersionUpdater() {
|
||||
duration: 4000,
|
||||
description:
|
||||
"Version information has been updated in the background",
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
toast.success("No new browser versions found", {
|
||||
@@ -103,7 +103,7 @@ export function useVersionUpdater() {
|
||||
description: "Check your internet connection and try again",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
@@ -130,7 +130,7 @@ export function useVersionUpdater() {
|
||||
const loadUpdateStatus = useCallback(async () => {
|
||||
try {
|
||||
const [lastUpdate, timeUntilNext] = await invoke<[number | null, number]>(
|
||||
"get_version_update_status"
|
||||
"get_version_update_status",
|
||||
);
|
||||
setLastUpdateTime(lastUpdate);
|
||||
setTimeUntilNextUpdate(timeUntilNext);
|
||||
@@ -143,18 +143,18 @@ export function useVersionUpdater() {
|
||||
try {
|
||||
setIsUpdating(true);
|
||||
const results = await invoke<BackgroundUpdateResult[]>(
|
||||
"trigger_manual_version_update"
|
||||
"trigger_manual_version_update",
|
||||
);
|
||||
|
||||
const totalNewVersions = results.reduce(
|
||||
(sum, result) => sum + result.new_versions_count,
|
||||
0
|
||||
0,
|
||||
);
|
||||
const successfulUpdates = results.filter(
|
||||
(r) => r.updated_successfully
|
||||
(r) => r.updated_successfully,
|
||||
).length;
|
||||
const failedUpdates = results.filter(
|
||||
(r) => !r.updated_successfully
|
||||
(r) => !r.updated_successfully,
|
||||
).length;
|
||||
|
||||
if (failedUpdates > 0) {
|
||||
@@ -194,7 +194,7 @@ export function useVersionUpdater() {
|
||||
try {
|
||||
const result = await invoke<BrowserVersionsResult>(
|
||||
"fetch_browser_versions_with_count",
|
||||
{ browserStr }
|
||||
{ browserStr },
|
||||
);
|
||||
|
||||
// Show notification about new versions if any were found
|
||||
@@ -205,7 +205,7 @@ export function useVersionUpdater() {
|
||||
{
|
||||
duration: 3000,
|
||||
description: `Total available: ${result.total_versions_count} versions`,
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ export function useVersionUpdater() {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
const formatTimeUntilUpdate = useCallback((seconds: number): string => {
|
||||
@@ -251,7 +251,7 @@ export function useVersionUpdater() {
|
||||
}
|
||||
return "Just now";
|
||||
},
|
||||
[]
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -137,7 +137,7 @@ export function showLoadingToast(
|
||||
id?: string;
|
||||
description?: string;
|
||||
duration?: number;
|
||||
}
|
||||
},
|
||||
) {
|
||||
return showToast({
|
||||
type: "loading",
|
||||
@@ -151,7 +151,7 @@ export function showDownloadToast(
|
||||
version: string,
|
||||
stage: "downloading" | "extracting" | "verifying" | "completed",
|
||||
progress?: { percentage: number; speed?: string; eta?: string },
|
||||
options?: { suppressCompletionToast?: boolean }
|
||||
options?: { suppressCompletionToast?: boolean },
|
||||
) {
|
||||
const title =
|
||||
stage === "completed"
|
||||
@@ -188,7 +188,7 @@ export function showVersionUpdateToast(
|
||||
found: number;
|
||||
};
|
||||
duration?: number;
|
||||
}
|
||||
},
|
||||
) {
|
||||
return showToast({
|
||||
type: "version-update",
|
||||
@@ -203,7 +203,7 @@ export function showFetchingToast(
|
||||
id?: string;
|
||||
description?: string;
|
||||
duration?: number;
|
||||
}
|
||||
},
|
||||
) {
|
||||
return showToast({
|
||||
type: "fetching",
|
||||
@@ -221,7 +221,7 @@ export function showSuccessToast(
|
||||
id?: string;
|
||||
description?: string;
|
||||
duration?: number;
|
||||
}
|
||||
},
|
||||
) {
|
||||
return showToast({
|
||||
type: "success",
|
||||
@@ -236,7 +236,7 @@ export function showErrorToast(
|
||||
id?: string;
|
||||
description?: string;
|
||||
duration?: number;
|
||||
}
|
||||
},
|
||||
) {
|
||||
return showToast({
|
||||
type: "error",
|
||||
|
||||
Reference in New Issue
Block a user