chore: simplify js linting

This commit is contained in:
zhom
2025-05-29 11:00:19 +04:00
parent 8d1d970324
commit d87ef3ccf6
37 changed files with 162 additions and 287 deletions
+5
View File
@@ -40,5 +40,10 @@ jobs:
- name: Install dependencies from lockfile - name: Install dependencies from lockfile
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Install nodecar dependencies
run: |
cd nodecar
pnpm install --frozen-lockfile
- name: Run lint step - name: Run lint step
run: pnpm lint run: pnpm lint
+7
View File
@@ -0,0 +1,7 @@
node_modules/
dist/
.next/
src-tauri/target/
*.lock
pnpm-lock.yaml
*.log
+8
View File
@@ -0,0 +1,8 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": false,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false
}
-53
View File
@@ -1,53 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false,
"ignore": []
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"useHookAtTopLevel": "error"
},
"nursery": {
"useGoogleFontDisplay": "error",
"noDocumentImportInPage": "error",
"noHeadElement": "error",
"noHeadImportInDocument": "error",
"noImgElement": "off",
"useComponentExportOnlyModules": {
"level": "error",
"options": {
"allowExportNames": ["metadata"]
}
}
}
}
},
"css": {
"formatter": {
"quoteStyle": "double"
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
},
"globals": []
}
}
+5 -5
View File
@@ -13,9 +13,9 @@ const eslintConfig = tseslint.config(
...compat.extends("next/core-web-vitals"), ...compat.extends("next/core-web-vitals"),
{ {
// Disabled rules taken from https://biomejs.dev/linter/rules-sources for ones that // Disabled rules taken from https://biomejs.dev/linter/rules-sources for ones that
// are already handled by Biome // are already handled by Prettier and TypeScript or are not needed
rules: { rules: {
// eslint-plugin-jsx-a11y rules replaced by Biome // eslint-plugin-jsx-a11y rules - some disabled for performance/specific project needs
"jsx-a11y/alt-text": "off", "jsx-a11y/alt-text": "off",
"jsx-a11y/anchor-has-content": "off", "jsx-a11y/anchor-has-content": "off",
"jsx-a11y/anchor-is-valid": "off", "jsx-a11y/anchor-is-valid": "off",
@@ -49,7 +49,7 @@ const eslintConfig = tseslint.config(
"jsx-a11y/role-supports-aria-props": "off", "jsx-a11y/role-supports-aria-props": "off",
"jsx-a11y/scope": "off", "jsx-a11y/scope": "off",
"jsx-a11y/tabindex-no-positive": "off", "jsx-a11y/tabindex-no-positive": "off",
// eslint-plugin-react rules replaced by Biome // eslint-plugin-react rules - some disabled for performance/specific project needs
"react/button-has-type": "off", "react/button-has-type": "off",
"react/jsx-boolean-value": "off", "react/jsx-boolean-value": "off",
"react/jsx-curly-brace-presence": "off", "react/jsx-curly-brace-presence": "off",
@@ -64,10 +64,10 @@ const eslintConfig = tseslint.config(
"react/no-danger": "off", "react/no-danger": "off",
"react/no-danger-with-children": "off", "react/no-danger-with-children": "off",
"react/void-dom-elements-no-children": "off", "react/void-dom-elements-no-children": "off",
// eslint-plugin-react-hooks rules replaced by Biome // eslint-plugin-react-hooks rules - disabled for specific project needs
"react-hooks/exhaustive-deps": "off", "react-hooks/exhaustive-deps": "off",
"react-hooks/rules-of-hooks": "off", "react-hooks/rules-of-hooks": "off",
// typescript-eslint rules replaced by Biome // typescript-eslint rules - some handled by TypeScript compiler or disabled for project needs
"@typescript-eslint/adjacent-overload-signatures": "off", "@typescript-eslint/adjacent-overload-signatures": "off",
"@typescript-eslint/array-type": "off", "@typescript-eslint/array-type": "off",
"@typescript-eslint/ban-types": "off", "@typescript-eslint/ban-types": "off",
+5 -5
View File
@@ -11,9 +11,9 @@ const eslintConfig = tseslint.config(
...compat.extends("next/core-web-vitals"), ...compat.extends("next/core-web-vitals"),
{ {
// Disabled rules taken from https://biomejs.dev/linter/rules-sources for ones that // Disabled rules taken from https://biomejs.dev/linter/rules-sources for ones that
// are already handled by Biome // are already handled by Prettier and TypeScript or are not needed
rules: { rules: {
// eslint-plugin-jsx-a11y rules replaced by Biome // eslint-plugin-jsx-a11y rules - some disabled for performance/specific project needs
"jsx-a11y/alt-text": "off", "jsx-a11y/alt-text": "off",
"jsx-a11y/anchor-has-content": "off", "jsx-a11y/anchor-has-content": "off",
"jsx-a11y/anchor-is-valid": "off", "jsx-a11y/anchor-is-valid": "off",
@@ -47,7 +47,7 @@ const eslintConfig = tseslint.config(
"jsx-a11y/role-supports-aria-props": "off", "jsx-a11y/role-supports-aria-props": "off",
"jsx-a11y/scope": "off", "jsx-a11y/scope": "off",
"jsx-a11y/tabindex-no-positive": "off", "jsx-a11y/tabindex-no-positive": "off",
// eslint-plugin-react rules replaced by Biome // eslint-plugin-react rules - some disabled for performance/specific project needs
"react/button-has-type": "off", "react/button-has-type": "off",
"react/jsx-boolean-value": "off", "react/jsx-boolean-value": "off",
"react/jsx-curly-brace-presence": "off", "react/jsx-curly-brace-presence": "off",
@@ -62,10 +62,10 @@ const eslintConfig = tseslint.config(
"react/no-danger": "off", "react/no-danger": "off",
"react/no-danger-with-children": "off", "react/no-danger-with-children": "off",
"react/void-dom-elements-no-children": "off", "react/void-dom-elements-no-children": "off",
// eslint-plugin-react-hooks rules replaced by Biome // eslint-plugin-react-hooks rules - disabled for specific project needs
"react-hooks/exhaustive-deps": "off", "react-hooks/exhaustive-deps": "off",
"react-hooks/rules-of-hooks": "off", "react-hooks/rules-of-hooks": "off",
// typescript-eslint rules replaced by Biome // typescript-eslint rules - some handled by TypeScript compiler or disabled for project needs
"@typescript-eslint/adjacent-overload-signatures": "off", "@typescript-eslint/adjacent-overload-signatures": "off",
"@typescript-eslint/array-type": "off", "@typescript-eslint/array-type": "off",
"@typescript-eslint/ban-types": "off", "@typescript-eslint/ban-types": "off",
+2 -3
View File
@@ -7,11 +7,11 @@
"dev": "next dev --turbopack", "dev": "next dev --turbopack",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "biome check src/ && next lint", "lint": "prettier --check src/ && tsc --noEmit && next lint",
"tauri": "tauri", "tauri": "tauri",
"shadcn:add": "pnpm dlx shadcn@latest add", "shadcn:add": "pnpm dlx shadcn@latest add",
"prepare": "husky", "prepare": "husky",
"format:js": "biome format --write src/", "format:js": "prettier --write src/",
"format:rust": "cd src-tauri && cargo fmt --all", "format:rust": "cd src-tauri && cargo fmt --all",
"format": "pnpm format:js && pnpm format:rust", "format": "pnpm format:js && pnpm format:rust",
"prettier": "prettier --write" "prettier": "prettier --write"
@@ -43,7 +43,6 @@
"tailwind-merge": "^3.3.0" "tailwind-merge": "^3.3.0"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^1.9.4",
"@eslint/eslintrc": "^3.3.1", "@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.27.0", "@eslint/js": "^9.27.0",
"@next/eslint-plugin-next": "^15.3.2", "@next/eslint-plugin-next": "^15.3.2",
-91
View File
@@ -81,9 +81,6 @@ importers:
specifier: ^3.3.0 specifier: ^3.3.0
version: 3.3.0 version: 3.3.0
devDependencies: devDependencies:
'@biomejs/biome':
specifier: ^1.9.4
version: 1.9.4
'@eslint/eslintrc': '@eslint/eslintrc':
specifier: ^3.3.1 specifier: ^3.3.1
version: 3.3.1 version: 3.3.1
@@ -237,59 +234,6 @@ packages:
resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==} resolution: {integrity: sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@biomejs/biome@1.9.4':
resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
engines: {node: '>=14.21.3'}
hasBin: true
'@biomejs/cli-darwin-arm64@1.9.4':
resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
'@biomejs/cli-darwin-x64@1.9.4':
resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
'@biomejs/cli-linux-arm64-musl@1.9.4':
resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
'@biomejs/cli-linux-arm64@1.9.4':
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
'@biomejs/cli-linux-x64-musl@1.9.4':
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
'@biomejs/cli-linux-x64@1.9.4':
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
'@biomejs/cli-win32-arm64@1.9.4':
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
'@biomejs/cli-win32-x64@1.9.4':
resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
'@emnapi/core@1.4.3': '@emnapi/core@1.4.3':
resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
@@ -3285,41 +3229,6 @@ snapshots:
'@babel/helper-string-parser': 7.27.1 '@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1 '@babel/helper-validator-identifier': 7.27.1
'@biomejs/biome@1.9.4':
optionalDependencies:
'@biomejs/cli-darwin-arm64': 1.9.4
'@biomejs/cli-darwin-x64': 1.9.4
'@biomejs/cli-linux-arm64': 1.9.4
'@biomejs/cli-linux-arm64-musl': 1.9.4
'@biomejs/cli-linux-x64': 1.9.4
'@biomejs/cli-linux-x64-musl': 1.9.4
'@biomejs/cli-win32-arm64': 1.9.4
'@biomejs/cli-win32-x64': 1.9.4
'@biomejs/cli-darwin-arm64@1.9.4':
optional: true
'@biomejs/cli-darwin-x64@1.9.4':
optional: true
'@biomejs/cli-linux-arm64-musl@1.9.4':
optional: true
'@biomejs/cli-linux-arm64@1.9.4':
optional: true
'@biomejs/cli-linux-x64-musl@1.9.4':
optional: true
'@biomejs/cli-linux-x64@1.9.4':
optional: true
'@biomejs/cli-win32-arm64@1.9.4':
optional: true
'@biomejs/cli-win32-x64@1.9.4':
optional: true
'@emnapi/core@1.4.3': '@emnapi/core@1.4.3':
dependencies: dependencies:
'@emnapi/wasi-threads': 1.0.2 '@emnapi/wasi-threads': 1.0.2
+21 -21
View File
@@ -63,7 +63,7 @@ export default function Home() {
try { try {
const profileList = await invoke<BrowserProfile[]>( const profileList = await invoke<BrowserProfile[]>(
"list_browser_profiles", "list_browser_profiles"
); );
setProfiles(profileList); setProfiles(profileList);
@@ -94,7 +94,7 @@ export default function Home() {
() => { () => {
void checkForUpdates(); void checkForUpdates();
}, },
30 * 60 * 1000, 30 * 60 * 1000
); );
return () => { return () => {
@@ -107,7 +107,7 @@ export default function Home() {
try { try {
const shouldShow = await invoke<boolean>( const shouldShow = await invoke<boolean>(
"should_show_settings_on_startup", "should_show_settings_on_startup"
); );
if (shouldShow) { if (shouldShow) {
setSettingsDialogOpen(true); setSettingsDialogOpen(true);
@@ -122,7 +122,7 @@ export default function Home() {
try { try {
const hasStartupUrl = await invoke<boolean>( const hasStartupUrl = await invoke<boolean>(
"check_and_handle_startup_url", "check_and_handle_startup_url"
); );
if (hasStartupUrl) { if (hasStartupUrl) {
console.log("Handled startup URL successfully"); console.log("Handled startup URL successfully");
@@ -155,10 +155,10 @@ export default function Home() {
await listen<string>("show-create-profile-dialog", (event) => { await listen<string>("show-create-profile-dialog", (event) => {
console.log( console.log(
"Received show create profile dialog request:", "Received show create profile dialog request:",
event.payload, event.payload
); );
setError( 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); setCreateProfileDialogOpen(true);
}); });
@@ -180,7 +180,7 @@ export default function Home() {
} catch (error: any) { } catch (error: any) {
console.log( console.log(
"Smart URL opening failed or requires profile selection:", "Smart URL opening failed or requires profile selection:",
error, error
); );
// Check if it's the special error cases // Check if it's the special error cases
@@ -190,7 +190,7 @@ export default function Home() {
} else if (error === "no_profiles") { } else if (error === "no_profiles") {
// No profiles available, show error message // No profiles available, show error message
setError( setError(
"No profiles available. Please create a profile first before opening URLs.", "No profiles available. Please create a profile first before opening URLs."
); );
} else { } else {
// Some other error occurred // Some other error occurred
@@ -228,7 +228,7 @@ export default function Home() {
setError(`Failed to update proxy settings: ${JSON.stringify(err)}`); setError(`Failed to update proxy settings: ${JSON.stringify(err)}`);
} }
}, },
[currentProfileForProxy, loadProfiles], [currentProfileForProxy, loadProfiles]
); );
const handleCreateProfile = useCallback( const handleCreateProfile = useCallback(
@@ -247,7 +247,7 @@ export default function Home() {
name: profileData.name, name: profileData.name,
browserStr: profileData.browserStr, browserStr: profileData.browserStr,
version: profileData.version, version: profileData.version,
}, }
); );
// Update proxy if provided // Update proxy if provided
@@ -264,11 +264,11 @@ export default function Home() {
throw error; throw error;
} }
}, },
[loadProfiles], [loadProfiles]
); );
const [runningProfiles, setRunningProfiles] = useState<Set<string>>( const [runningProfiles, setRunningProfiles] = useState<Set<string>>(
new Set(), new Set()
); );
const runningProfilesRef = useRef<Set<string>>(new Set()); const runningProfilesRef = useRef<Set<string>>(new Set());
@@ -300,7 +300,7 @@ export default function Home() {
console.error("Failed to check browser status:", err); console.error("Failed to check browser status:", err);
} }
}, },
[isClient], [isClient]
); );
const launchProfile = useCallback( const launchProfile = useCallback(
@@ -315,12 +315,12 @@ export default function Home() {
"is_browser_disabled_for_update", "is_browser_disabled_for_update",
{ {
browser: profile.browser, browser: profile.browser,
}, }
); );
if (isDisabled || isUpdating(profile.browser)) { if (isDisabled || isUpdating(profile.browser)) {
setError( 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; return;
} }
@@ -331,7 +331,7 @@ export default function Home() {
try { try {
const updatedProfile = await invoke<BrowserProfile>( const updatedProfile = await invoke<BrowserProfile>(
"launch_browser_profile", "launch_browser_profile",
{ profile }, { profile }
); );
await loadProfiles(); await loadProfiles();
await checkBrowserStatus(updatedProfile); await checkBrowserStatus(updatedProfile);
@@ -340,7 +340,7 @@ export default function Home() {
setError(`Failed to launch browser: ${JSON.stringify(err)}`); setError(`Failed to launch browser: ${JSON.stringify(err)}`);
} }
}, },
[loadProfiles, checkBrowserStatus, isUpdating, isClient], [loadProfiles, checkBrowserStatus, isUpdating, isClient]
); );
useEffect(() => { useEffect(() => {
@@ -379,7 +379,7 @@ export default function Home() {
setError(`Failed to delete profile: ${JSON.stringify(err)}`); setError(`Failed to delete profile: ${JSON.stringify(err)}`);
} }
}, },
[loadProfiles], [loadProfiles]
); );
const handleRenameProfile = useCallback( const handleRenameProfile = useCallback(
@@ -394,7 +394,7 @@ export default function Home() {
throw err; throw err;
} }
}, },
[loadProfiles], [loadProfiles]
); );
const handleKillProfile = useCallback( const handleKillProfile = useCallback(
@@ -408,7 +408,7 @@ export default function Home() {
setError(`Failed to kill browser: ${JSON.stringify(err)}`); 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 // Don't render anything until we're on the client side to prevent hydration issues
@@ -554,7 +554,7 @@ export default function Home() {
isOpen={true} isOpen={true}
onClose={() => { onClose={() => {
setPendingUrls((prev) => setPendingUrls((prev) =>
prev.filter((u) => u.id !== pendingUrl.id), prev.filter((u) => u.id !== pendingUrl.id)
); );
}} }}
url={pendingUrl.url} url={pendingUrl.url}
+2 -2
View File
@@ -60,10 +60,10 @@ export function ChangeVersionDialog({
if (profile && selectedVersion) { if (profile && selectedVersion) {
// Check if this is a downgrade // Check if this is a downgrade
const currentVersionIndex = availableVersions.findIndex( const currentVersionIndex = availableVersions.findIndex(
(v) => v.tag_name === profile.version, (v) => v.tag_name === profile.version
); );
const selectedVersionIndex = availableVersions.findIndex( 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) // If selected version has a higher index, it's older (downgrade)
+4 -4
View File
@@ -65,7 +65,7 @@ export function CreateProfileDialog({
>([]); >([]);
const [isCreating, setIsCreating] = useState(false); const [isCreating, setIsCreating] = useState(false);
const [existingProfiles, setExistingProfiles] = useState<BrowserProfile[]>( const [existingProfiles, setExistingProfiles] = useState<BrowserProfile[]>(
[], []
); );
// Proxy settings // Proxy settings
@@ -120,7 +120,7 @@ export function CreateProfileDialog({
const loadSupportedBrowsers = async () => { const loadSupportedBrowsers = async () => {
try { try {
const browsers = await invoke<BrowserTypeString[]>( const browsers = await invoke<BrowserTypeString[]>(
"get_supported_browsers", "get_supported_browsers"
); );
setSupportedBrowsers(browsers); setSupportedBrowsers(browsers);
if (browsers.includes("mullvad-browser")) { if (browsers.includes("mullvad-browser")) {
@@ -156,7 +156,7 @@ export function CreateProfileDialog({
// Check for duplicate names (case insensitive) // Check for duplicate names (case insensitive)
const isDuplicate = existingProfiles.some( const isDuplicate = existingProfiles.some(
(profile) => profile.name.toLowerCase() === trimmedName.toLowerCase(), (profile) => profile.name.toLowerCase() === trimmedName.toLowerCase()
); );
if (isDuplicate) { if (isDuplicate) {
@@ -271,7 +271,7 @@ export function CreateProfileDialog({
{browser {browser
.split("-") .split("-")
.map( .map(
(word) => word.charAt(0).toUpperCase() + word.slice(1), (word) => word.charAt(0).toUpperCase() + word.slice(1)
) )
.join(" ")} .join(" ")}
</SelectItem> </SelectItem>
+6 -6
View File
@@ -298,7 +298,7 @@ export function showLoadingToast(
id?: string; id?: string;
description?: string; description?: string;
duration?: number; duration?: number;
}, }
) { ) {
return showToast({ return showToast({
type: "loading", type: "loading",
@@ -312,7 +312,7 @@ export function showDownloadToast(
version: string, version: string,
stage: "downloading" | "extracting" | "verifying" | "completed", stage: "downloading" | "extracting" | "verifying" | "completed",
progress?: { percentage: number; speed?: string; eta?: string }, progress?: { percentage: number; speed?: string; eta?: string },
options?: { suppressCompletionToast?: boolean }, options?: { suppressCompletionToast?: boolean }
) { ) {
const title = const title =
stage === "completed" stage === "completed"
@@ -349,7 +349,7 @@ export function showVersionUpdateToast(
found: number; found: number;
}; };
duration?: number; duration?: number;
}, }
) { ) {
return showToast({ return showToast({
type: "version-update", type: "version-update",
@@ -364,7 +364,7 @@ export function showFetchingToast(
id?: string; id?: string;
description?: string; description?: string;
duration?: number; duration?: number;
}, }
) { ) {
return showToast({ return showToast({
type: "fetching", type: "fetching",
@@ -382,7 +382,7 @@ export function showSuccessToast(
id?: string; id?: string;
description?: string; description?: string;
duration?: number; duration?: number;
}, }
) { ) {
return showToast({ return showToast({
type: "success", type: "success",
@@ -397,7 +397,7 @@ export function showErrorToast(
id?: string; id?: string;
description?: string; description?: string;
duration?: number; duration?: number;
}, }
) { ) {
return showToast({ return showToast({
type: "error", type: "error",
+5 -5
View File
@@ -101,7 +101,7 @@ export function ProfilesDataTable({
setSorting(newSorting); setSorting(newSorting);
updateSorting(newSorting); updateSorting(newSorting);
}, },
[sorting, updateSorting, isClient], [sorting, updateSorting, isClient]
); );
const handleRename = async () => { const handleRename = async () => {
@@ -131,7 +131,7 @@ export function ProfilesDataTable({
const anyTorRunning = const anyTorRunning =
isClient && isClient &&
data.some( data.some(
(p) => p.browser === "tor-browser" && runningProfiles.has(p.name), (p) => p.browser === "tor-browser" && runningProfiles.has(p.name)
); );
const shouldDisableTorStart = const shouldDisableTorStart =
isTorBrowser && !isRunning && anyTorRunning; isTorBrowser && !isRunning && anyTorRunning;
@@ -392,7 +392,7 @@ export function ProfilesDataTable({
}, },
}, },
], ],
[isClient, runningProfiles, isUpdating, data], [isClient, runningProfiles, isUpdating, data]
); );
const table = useReactTable({ const table = useReactTable({
@@ -420,7 +420,7 @@ export function ProfilesDataTable({
? null ? null
: flexRender( : flexRender(
header.column.columnDef.header, header.column.columnDef.header,
header.getContext(), header.getContext()
)} )}
</TableHead> </TableHead>
); );
@@ -439,7 +439,7 @@ export function ProfilesDataTable({
<TableCell key={cell.id}> <TableCell key={cell.id}>
{flexRender( {flexRender(
cell.column.columnDef.cell, cell.column.columnDef.cell,
cell.getContext(), cell.getContext()
)} )}
</TableCell> </TableCell>
))} ))}
+7 -7
View File
@@ -58,7 +58,7 @@ export function ProfileSelectorDialog({
setIsLoading(true); setIsLoading(true);
try { try {
const profileList = await invoke<BrowserProfile[]>( const profileList = await invoke<BrowserProfile[]>(
"list_browser_profiles", "list_browser_profiles"
); );
// Sort profiles by name // Sort profiles by name
@@ -92,14 +92,14 @@ export function ProfileSelectorDialog({
const canUseProfileForLinks = ( const canUseProfileForLinks = (
profile: BrowserProfile, profile: BrowserProfile,
allProfiles: BrowserProfile[], allProfiles: BrowserProfile[],
runningProfiles: Set<string>, runningProfiles: Set<string>
): boolean => { ): boolean => {
const isRunning = runningProfiles.has(profile.name); const isRunning = runningProfiles.has(profile.name);
// For TOR browser: Check if any TOR browser is running // For TOR browser: Check if any TOR browser is running
if (profile.browser === "tor-browser") { if (profile.browser === "tor-browser") {
const runningTorProfiles = allProfiles.filter( 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 // If no TOR browser is running, allow any TOR profile
@@ -126,7 +126,7 @@ export function ProfileSelectorDialog({
if (profile.browser === "tor-browser") { if (profile.browser === "tor-browser") {
const runningTorProfiles = profiles.filter( 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 // If another TOR profile is running, this one is not available
@@ -192,7 +192,7 @@ export function ProfileSelectorDialog({
return canUseProfileForLinks( return canUseProfileForLinks(
selectedProfileData, selectedProfileData,
profiles, profiles,
runningProfiles, runningProfiles
); );
}; };
@@ -261,7 +261,7 @@ export function ProfileSelectorDialog({
const canUseForLinks = canUseProfileForLinks( const canUseForLinks = canUseProfileForLinks(
profile, profile,
profiles, profiles,
runningProfiles, runningProfiles
); );
const tooltipContent = getProfileTooltipContent(profile); const tooltipContent = getProfileTooltipContent(profile);
@@ -281,7 +281,7 @@ export function ProfileSelectorDialog({
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{(() => { {(() => {
const IconComponent = getBrowserIcon( const IconComponent = getBrowserIcon(
profile.browser, profile.browser
); );
return IconComponent ? ( return IconComponent ? (
<IconComponent className="h-4 w-4" /> <IconComponent className="h-4 w-4" />
+2 -2
View File
@@ -17,7 +17,7 @@ interface CustomThemeProviderProps {
function getSystemTheme(): string { function getSystemTheme(): string {
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
const isDarkMode = window.matchMedia( const isDarkMode = window.matchMedia(
"(prefers-color-scheme: dark)", "(prefers-color-scheme: dark)"
).matches; ).matches;
return isDarkMode ? "dark" : "light"; return isDarkMode ? "dark" : "light";
} }
@@ -39,7 +39,7 @@ export function CustomThemeProvider({ children }: CustomThemeProviderProps) {
const systemTheme = getSystemTheme(); const systemTheme = getSystemTheme();
console.log( console.log(
"First-time user detected, applying system theme:", "First-time user detected, applying system theme:",
systemTheme, systemTheme
); );
// Save the detected theme as the default // Save the detected theme as the default
+3 -3
View File
@@ -16,7 +16,7 @@ const alertVariants = cva(
defaultVariants: { defaultVariants: {
variant: "default", variant: "default",
}, },
}, }
); );
function Alert({ function Alert({
@@ -40,7 +40,7 @@ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
data-slot="alert-title" data-slot="alert-title"
className={cn( className={cn(
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", "col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
className, className
)} )}
{...props} {...props}
/> />
@@ -56,7 +56,7 @@ function AlertDescription({
data-slot="alert-description" data-slot="alert-description"
className={cn( className={cn(
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed", "text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
className, className
)} )}
{...props} {...props}
/> />
+1 -1
View File
@@ -22,7 +22,7 @@ const badgeVariants = cva(
defaultVariants: { defaultVariants: {
variant: "default", variant: "default",
}, },
}, }
); );
function Badge({ function Badge({
+1 -1
View File
@@ -32,7 +32,7 @@ const buttonVariants = cva(
variant: "default", variant: "default",
size: "default", size: "default",
}, },
}, }
); );
export type ButtonProps = React.ComponentProps<"button"> & export type ButtonProps = React.ComponentProps<"button"> &
+3 -3
View File
@@ -8,7 +8,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card" data-slot="card"
className={cn( className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
className, className
)} )}
{...props} {...props}
/> />
@@ -21,7 +21,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-header" data-slot="card-header"
className={cn( 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", "@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} {...props}
/> />
@@ -54,7 +54,7 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-action" data-slot="card-action"
className={cn( className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end", "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className, className
)} )}
{...props} {...props}
/> />
+1 -1
View File
@@ -15,7 +15,7 @@ function Checkbox({
data-slot="checkbox" data-slot="checkbox"
className={cn( 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", "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} {...props}
> >
+1 -1
View File
@@ -79,7 +79,7 @@ export function ComboboxDemo() {
<LuCheck <LuCheck
className={cn( className={cn(
"mr-2 h-4 w-4", "mr-2 h-4 w-4",
value === framework.value ? "opacity-100" : "opacity-0", value === framework.value ? "opacity-100" : "opacity-0"
)} )}
/> />
{framework.label} {framework.label}
+6 -6
View File
@@ -22,7 +22,7 @@ function Command({
data-slot="command" data-slot="command"
className={cn( className={cn(
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md", "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
className, className
)} )}
{...props} {...props}
/> />
@@ -67,7 +67,7 @@ function CommandInput({
data-slot="command-input" data-slot="command-input"
className={cn( 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", "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} {...props}
/> />
@@ -84,7 +84,7 @@ function CommandList({
data-slot="command-list" data-slot="command-list"
className={cn( className={cn(
"max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto", "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
className, className
)} )}
{...props} {...props}
/> />
@@ -112,7 +112,7 @@ function CommandGroup({
data-slot="command-group" data-slot="command-group"
className={cn( 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", "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} {...props}
/> />
@@ -141,7 +141,7 @@ function CommandItem({
data-slot="command-item" data-slot="command-item"
className={cn( 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", "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} {...props}
/> />
@@ -157,7 +157,7 @@ function CommandShortcut({
data-slot="command-shortcut" data-slot="command-shortcut"
className={cn( className={cn(
"text-muted-foreground ml-auto text-xs tracking-widest", "text-muted-foreground ml-auto text-xs tracking-widest",
className, className
)} )}
{...props} {...props}
/> />
+3 -3
View File
@@ -39,7 +39,7 @@ function DialogOverlay({
data-slot="dialog-overlay" data-slot="dialog-overlay"
className={cn( 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", "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} {...props}
/> />
@@ -58,7 +58,7 @@ function DialogContent({
data-slot="dialog-content" data-slot="dialog-content"
className={cn( 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", "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} {...props}
> >
@@ -88,7 +88,7 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
data-slot="dialog-footer" data-slot="dialog-footer"
className={cn( className={cn(
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
className, className
)} )}
{...props} {...props}
/> />
+8 -8
View File
@@ -43,7 +43,7 @@ function DropdownMenuContent({
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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", "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} {...props}
/> />
@@ -75,7 +75,7 @@ function DropdownMenuItem({
data-variant={variant} data-variant={variant}
className={cn( 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", "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} {...props}
/> />
@@ -93,7 +93,7 @@ function DropdownMenuCheckboxItem({
data-slot="dropdown-menu-checkbox-item" data-slot="dropdown-menu-checkbox-item"
className={cn( 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", "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} checked={checked}
{...props} {...props}
@@ -129,7 +129,7 @@ function DropdownMenuRadioItem({
data-slot="dropdown-menu-radio-item" data-slot="dropdown-menu-radio-item"
className={cn( 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", "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} {...props}
> >
@@ -156,7 +156,7 @@ function DropdownMenuLabel({
data-inset={inset} data-inset={inset}
className={cn( className={cn(
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
className, className
)} )}
{...props} {...props}
/> />
@@ -185,7 +185,7 @@ function DropdownMenuShortcut({
data-slot="dropdown-menu-shortcut" data-slot="dropdown-menu-shortcut"
className={cn( className={cn(
"text-muted-foreground ml-auto text-xs tracking-widest", "text-muted-foreground ml-auto text-xs tracking-widest",
className, className
)} )}
{...props} {...props}
/> />
@@ -212,7 +212,7 @@ function DropdownMenuSubTrigger({
data-inset={inset} data-inset={inset}
className={cn( 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", "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} {...props}
> >
@@ -231,7 +231,7 @@ function DropdownMenuSubContent({
data-slot="dropdown-menu-sub-content" data-slot="dropdown-menu-sub-content"
className={cn( 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", "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} {...props}
/> />
+1 -1
View File
@@ -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", "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]", "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", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className, className
)} )}
{...props} {...props}
/> />
+1 -1
View File
@@ -14,7 +14,7 @@ function Label({
data-slot="label" data-slot="label"
className={cn( 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", "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} {...props}
/> />
+1 -1
View File
@@ -31,7 +31,7 @@ function PopoverContent({
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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", "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} {...props}
/> />
+1 -1
View File
@@ -15,7 +15,7 @@ function Progress({
data-slot="progress" data-slot="progress"
className={cn( className={cn(
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full", "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
className, className
)} )}
{...props} {...props}
> >
+1 -1
View File
@@ -43,7 +43,7 @@ function ScrollBar({
"h-full w-2.5 border-l border-l-transparent", "h-full w-2.5 border-l border-l-transparent",
orientation === "horizontal" && orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent", "h-2.5 flex-col border-t border-t-transparent",
className, className
)} )}
{...props} {...props}
> >
+6 -6
View File
@@ -38,7 +38,7 @@ function SelectTrigger({
data-size={size} data-size={size}
className={cn( 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", "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} {...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", "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" && 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", "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} position={position}
{...props} {...props}
@@ -74,7 +74,7 @@ function SelectContent({
className={cn( className={cn(
"p-1", "p-1",
position === "popper" && 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} {children}
@@ -108,7 +108,7 @@ function SelectItem({
data-slot="select-item" data-slot="select-item"
className={cn( 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", "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} {...props}
> >
@@ -144,7 +144,7 @@ function SelectScrollUpButton({
data-slot="select-scroll-up-button" data-slot="select-scroll-up-button"
className={cn( className={cn(
"flex cursor-default items-center justify-center py-1", "flex cursor-default items-center justify-center py-1",
className, className
)} )}
{...props} {...props}
> >
@@ -162,7 +162,7 @@ function SelectScrollDownButton({
data-slot="select-scroll-down-button" data-slot="select-scroll-down-button"
className={cn( className={cn(
"flex cursor-default items-center justify-center py-1", "flex cursor-default items-center justify-center py-1",
className, className
)} )}
{...props} {...props}
> >
+4 -4
View File
@@ -45,7 +45,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
data-slot="table-footer" data-slot="table-footer"
className={cn( className={cn(
"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0", "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
className, className
)} )}
{...props} {...props}
/> />
@@ -58,7 +58,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
data-slot="table-row" data-slot="table-row"
className={cn( className={cn(
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors", "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
className, className
)} )}
{...props} {...props}
/> />
@@ -71,7 +71,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
data-slot="table-head" data-slot="table-head"
className={cn( 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]", "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} {...props}
/> />
@@ -84,7 +84,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
data-slot="table-cell" data-slot="table-cell"
className={cn( className={cn(
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className, className
)} )}
{...props} {...props}
/> />
+1 -1
View File
@@ -47,7 +47,7 @@ function TooltipContent({
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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", "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} {...props}
> >
+8 -8
View File
@@ -112,7 +112,7 @@ function UpdateNotificationComponent({
export function useUpdateNotifications() { export function useUpdateNotifications() {
const [notifications, setNotifications] = useState<UpdateNotification[]>([]); const [notifications, setNotifications] = useState<UpdateNotification[]>([]);
const [updatingBrowsers, setUpdatingBrowsers] = useState<Set<string>>( const [updatingBrowsers, setUpdatingBrowsers] = useState<Set<string>>(
new Set(), new Set()
); );
const [isClient, setIsClient] = useState(false); const [isClient, setIsClient] = useState(false);
@@ -126,7 +126,7 @@ export function useUpdateNotifications() {
try { try {
const updates = await invoke<UpdateNotification[]>( const updates = await invoke<UpdateNotification[]>(
"check_for_browser_updates", "check_for_browser_updates"
); );
setNotifications(updates); setNotifications(updates);
@@ -145,7 +145,7 @@ export function useUpdateNotifications() {
// Dismiss all notifications for this browser first // Dismiss all notifications for this browser first
const browserNotifications = notifications.filter( const browserNotifications = notifications.filter(
(n) => n.browser === browser, (n) => n.browser === browser
); );
for (const notification of browserNotifications) { for (const notification of browserNotifications) {
toast.dismiss(notification.id); toast.dismiss(notification.id);
@@ -164,7 +164,7 @@ export function useUpdateNotifications() {
if (isDownloaded) { if (isDownloaded) {
// Browser already exists, skip download and go straight to profile update // Browser already exists, skip download and go straight to profile update
console.log( console.log(
`${browserDisplayName} ${newVersion} already exists, skipping download`, `${browserDisplayName} ${newVersion} already exists, skipping download`
); );
} else { } else {
// Mark download as auto-update in the backend for toast suppression // Mark download as auto-update in the backend for toast suppression
@@ -186,7 +186,7 @@ export function useUpdateNotifications() {
{ {
browser, browser,
newVersion, newVersion,
}, }
); );
// Show success message based on whether profiles were updated // Show success message based on whether profiles were updated
@@ -252,7 +252,7 @@ export function useUpdateNotifications() {
}); });
} }
}, },
[notifications, checkForUpdates], [notifications, checkForUpdates]
); );
const handleDismiss = useCallback( const handleDismiss = useCallback(
@@ -267,7 +267,7 @@ export function useUpdateNotifications() {
console.error("Failed to dismiss notification:", error); console.error("Failed to dismiss notification:", error);
} }
}, },
[checkForUpdates, isClient], [checkForUpdates, isClient]
); );
// Separate effect to show toasts when notifications change // Separate effect to show toasts when notifications change
@@ -292,7 +292,7 @@ export function useUpdateNotifications() {
position: "top-right", position: "top-right",
// Remove transparent styling to fix background issue // Remove transparent styling to fix background issue
style: undefined, style: undefined,
}, }
); );
}); });
}, [notifications, updatingBrowsers, handleUpdate, handleDismiss, isClient]); }, [notifications, updatingBrowsers, handleUpdate, handleDismiss, isClient]);
+3 -3
View File
@@ -91,7 +91,7 @@ export function VersionSelector({
<CommandGroup> <CommandGroup>
{availableVersions.map((version) => { {availableVersions.map((version) => {
const isDownloaded = downloadedVersions.includes( const isDownloaded = downloadedVersions.includes(
version.tag_name, version.tag_name
); );
return ( return (
<CommandItem <CommandItem
@@ -101,7 +101,7 @@ export function VersionSelector({
onVersionSelect( onVersionSelect(
currentValue === selectedVersion currentValue === selectedVersion
? null ? null
: currentValue, : currentValue
); );
setVersionPopoverOpen(false); setVersionPopoverOpen(false);
}} }}
@@ -111,7 +111,7 @@ export function VersionSelector({
"mr-2 h-4 w-4", "mr-2 h-4 w-4",
selectedVersion === version.tag_name selectedVersion === version.tag_name
? "opacity-100" ? "opacity-100"
: "opacity-0", : "opacity-0"
)} )}
/> />
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
+14 -14
View File
@@ -72,7 +72,7 @@ const isAlphaVersion = (version: string): boolean => {
export function useBrowserDownload() { export function useBrowserDownload() {
const [availableVersions, setAvailableVersions] = useState<GithubRelease[]>( const [availableVersions, setAvailableVersions] = useState<GithubRelease[]>(
[], []
); );
const [downloadedVersions, setDownloadedVersions] = useState<string[]>([]); const [downloadedVersions, setDownloadedVersions] = useState<string[]>([]);
const [isDownloading, setIsDownloading] = useState(false); const [isDownloading, setIsDownloading] = useState(false);
@@ -128,7 +128,7 @@ export function useBrowserDownload() {
undefined, undefined,
{ {
suppressCompletionToast: isAutoUpdate, suppressCompletionToast: isAutoUpdate,
}, }
); );
setDownloadProgress(null); setDownloadProgress(null);
} }
@@ -167,7 +167,7 @@ export function useBrowserDownload() {
`Found ${progress.new_versions_found} new browser versions!`, `Found ${progress.new_versions_found} new browser versions!`,
{ {
duration: 3000, duration: 3000,
}, }
); );
} }
// Dismiss any update toasts // Dismiss any update toasts
@@ -179,7 +179,7 @@ export function useBrowserDownload() {
}); });
toast.dismiss(); toast.dismiss();
} }
}, }
); );
return () => { return () => {
@@ -224,7 +224,7 @@ export function useBrowserDownload() {
try { try {
const versionInfos = await invoke<BrowserVersionInfo[]>( const versionInfos = await invoke<BrowserVersionInfo[]>(
"fetch_browser_versions_cached_first", "fetch_browser_versions_cached_first",
{ browserStr }, { browserStr }
); );
// Convert BrowserVersionInfo to GithubRelease format for compatibility // Convert BrowserVersionInfo to GithubRelease format for compatibility
@@ -234,7 +234,7 @@ export function useBrowserDownload() {
assets: [], assets: [],
published_at: versionInfo.date, published_at: versionInfo.date,
is_alpha: versionInfo.is_prerelease, is_alpha: versionInfo.is_prerelease,
}), })
); );
setAvailableVersions(githubReleases); setAvailableVersions(githubReleases);
@@ -259,13 +259,13 @@ export function useBrowserDownload() {
// Get versions with new count info and cached detailed info // Get versions with new count info and cached detailed info
const result = await invoke<BrowserVersionsResult>( const result = await invoke<BrowserVersionsResult>(
"fetch_browser_versions_with_count_cached_first", "fetch_browser_versions_with_count_cached_first",
{ browserStr }, { browserStr }
); );
// Get detailed version info for compatibility // Get detailed version info for compatibility
const versionInfos = await invoke<BrowserVersionInfo[]>( const versionInfos = await invoke<BrowserVersionInfo[]>(
"fetch_browser_versions_cached_first", "fetch_browser_versions_cached_first",
{ browserStr }, { browserStr }
); );
// Convert BrowserVersionInfo to GithubRelease format for compatibility // Convert BrowserVersionInfo to GithubRelease format for compatibility
@@ -275,7 +275,7 @@ export function useBrowserDownload() {
assets: [], assets: [],
published_at: versionInfo.date, published_at: versionInfo.date,
is_alpha: versionInfo.is_prerelease, is_alpha: versionInfo.is_prerelease,
}), })
); );
setAvailableVersions(githubReleases); setAvailableVersions(githubReleases);
@@ -287,7 +287,7 @@ export function useBrowserDownload() {
{ {
duration: 3000, duration: 3000,
description: `Total available: ${result.total_versions_count} versions`, description: `Total available: ${result.total_versions_count} versions`,
}, }
); );
} }
@@ -307,7 +307,7 @@ export function useBrowserDownload() {
try { try {
const downloadedVersions = await invoke<string[]>( const downloadedVersions = await invoke<string[]>(
"get_downloaded_browser_versions", "get_downloaded_browser_versions",
{ browserStr }, { browserStr }
); );
setDownloadedVersions(downloadedVersions); setDownloadedVersions(downloadedVersions);
return downloadedVersions; return downloadedVersions;
@@ -321,7 +321,7 @@ export function useBrowserDownload() {
async ( async (
browserStr: string, browserStr: string,
version: string, version: string,
suppressNotifications = false, suppressNotifications = false
) => { ) => {
const browserName = getBrowserDisplayName(browserStr); const browserName = getBrowserDisplayName(browserStr);
setIsDownloading(true); setIsDownloading(true);
@@ -345,14 +345,14 @@ export function useBrowserDownload() {
setIsDownloading(false); setIsDownloading(false);
} }
}, },
[loadDownloadedVersions], [loadDownloadedVersions]
); );
const isVersionDownloaded = useCallback( const isVersionDownloaded = useCallback(
(version: string) => { (version: string) => {
return downloadedVersions.includes(version); return downloadedVersions.includes(version);
}, },
[downloadedVersions], [downloadedVersions]
); );
return { return {
+3 -3
View File
@@ -15,7 +15,7 @@ export function useTableSorting() {
const loadSettings = async () => { const loadSettings = async () => {
try { try {
const settings = await invoke<TableSortingSettings>( const settings = await invoke<TableSortingSettings>(
"get_table_sorting_settings", "get_table_sorting_settings"
); );
setSortingSettings(settings); setSortingSettings(settings);
} catch (error) { } catch (error) {
@@ -39,7 +39,7 @@ export function useTableSorting() {
console.error("Failed to save table sorting settings:", error); console.error("Failed to save table sorting settings:", error);
} }
}, },
[], []
); );
// Convert our settings to tanstack table sorting format // Convert our settings to tanstack table sorting format
@@ -67,7 +67,7 @@ export function useTableSorting() {
void saveSortingSettings(newSettings); void saveSortingSettings(newSettings);
} }
}, },
[saveSortingSettings, isLoaded], [saveSortingSettings, isLoaded]
); );
return { return {
+12 -12
View File
@@ -61,7 +61,7 @@ export function useVersionUpdater() {
total: progress.total_browsers, total: progress.total_browsers,
found: progress.new_versions_found, found: progress.new_versions_found,
}, },
}, }
); );
} else { } else {
showLoadingToast("Starting version update check...", { showLoadingToast("Starting version update check...", {
@@ -81,7 +81,7 @@ export function useVersionUpdater() {
duration: 4000, duration: 4000,
description: description:
"Version information has been updated in the background", "Version information has been updated in the background",
}, }
); );
} else { } else {
toast.success("No new browser versions found", { toast.success("No new browser versions found", {
@@ -103,7 +103,7 @@ export function useVersionUpdater() {
description: "Check your internet connection and try again", description: "Check your internet connection and try again",
}); });
} }
}, }
); );
return () => { return () => {
@@ -130,7 +130,7 @@ export function useVersionUpdater() {
const loadUpdateStatus = useCallback(async () => { const loadUpdateStatus = useCallback(async () => {
try { try {
const [lastUpdate, timeUntilNext] = await invoke<[number | null, number]>( const [lastUpdate, timeUntilNext] = await invoke<[number | null, number]>(
"get_version_update_status", "get_version_update_status"
); );
setLastUpdateTime(lastUpdate); setLastUpdateTime(lastUpdate);
setTimeUntilNextUpdate(timeUntilNext); setTimeUntilNextUpdate(timeUntilNext);
@@ -143,18 +143,18 @@ export function useVersionUpdater() {
try { try {
setIsUpdating(true); setIsUpdating(true);
const results = await invoke<BackgroundUpdateResult[]>( const results = await invoke<BackgroundUpdateResult[]>(
"trigger_manual_version_update", "trigger_manual_version_update"
); );
const totalNewVersions = results.reduce( const totalNewVersions = results.reduce(
(sum, result) => sum + result.new_versions_count, (sum, result) => sum + result.new_versions_count,
0, 0
); );
const successfulUpdates = results.filter( const successfulUpdates = results.filter(
(r) => r.updated_successfully, (r) => r.updated_successfully
).length; ).length;
const failedUpdates = results.filter( const failedUpdates = results.filter(
(r) => !r.updated_successfully, (r) => !r.updated_successfully
).length; ).length;
if (failedUpdates > 0) { if (failedUpdates > 0) {
@@ -194,7 +194,7 @@ export function useVersionUpdater() {
try { try {
const result = await invoke<BrowserVersionsResult>( const result = await invoke<BrowserVersionsResult>(
"fetch_browser_versions_with_count", "fetch_browser_versions_with_count",
{ browserStr }, { browserStr }
); );
// Show notification about new versions if any were found // Show notification about new versions if any were found
@@ -205,7 +205,7 @@ export function useVersionUpdater() {
{ {
duration: 3000, duration: 3000,
description: `Total available: ${result.total_versions_count} versions`, description: `Total available: ${result.total_versions_count} versions`,
}, }
); );
} }
@@ -215,7 +215,7 @@ export function useVersionUpdater() {
throw error; throw error;
} }
}, },
[], []
); );
const formatTimeUntilUpdate = useCallback((seconds: number): string => { const formatTimeUntilUpdate = useCallback((seconds: number): string => {
@@ -251,7 +251,7 @@ export function useVersionUpdater() {
return "Just now"; return "Just now";
} }
}, },
[], []
); );
return { return {