From 90f9885baa5854fd8d189b1356e6ac88aac1a8f1 Mon Sep 17 00:00:00 2001 From: FTCHD <144691102+FTCHD@users.noreply.github.com> Date: Sun, 31 Aug 2025 01:45:31 +0200 Subject: [PATCH] use sep() for platform aware separator & cleanup Signed-off-by: FTCHD <144691102+FTCHD@users.noreply.github.com> --- lib/format.ts | 4 +++- lib/fs.ts | 3 ++- lib/rclone/common.ts | 14 ++------------ lib/rclone/init.ts | 10 ++++------ src-tauri/src/lib.rs | 2 +- src/components/ConfigCreateDrawer.tsx | 11 +++-------- src/components/ConfigSyncDrawer.tsx | 18 ++++-------------- src/components/PathFinder.tsx | 17 +++++------------ src/pages/Jobs.tsx | 4 ++-- src/pages/Mount.tsx | 7 ++----- 10 files changed, 28 insertions(+), 62 deletions(-) diff --git a/lib/format.ts b/lib/format.ts index 4a20013..6ec9728 100644 --- a/lib/format.ts +++ b/lib/format.ts @@ -1,3 +1,5 @@ +import { sep } from '@tauri-apps/api/path' + export function formatBytes(bytes: number) { if (bytes < 1024) { return `${bytes} B` @@ -36,7 +38,7 @@ export function buildReadablePath(path: string, type: 'short' | 'long' = 'long') return '' } - const lastSegment = path.split('\\').slice(-1).join('').split('/').slice(-1).join('') + const lastSegment = path.split(sep()).slice(-1).join('') if (type === 'short') { return lastSegment diff --git a/lib/fs.ts b/lib/fs.ts index b3dbab2..aa4124b 100644 --- a/lib/fs.ts +++ b/lib/fs.ts @@ -1,4 +1,5 @@ import * as Sentry from '@sentry/browser' +import { sep } from '@tauri-apps/api/path' import { readDir } from '@tauri-apps/plugin-fs' export async function isDirectoryEmpty(path: string): Promise { @@ -13,5 +14,5 @@ export async function isDirectoryEmpty(path: string): Promise { } export function isRemotePath(path: string): boolean { - return path.includes(':/') && !path.startsWith('/') + return path.includes(':/') && !path.startsWith(sep()) } diff --git a/lib/rclone/common.ts b/lib/rclone/common.ts index 123e9a7..c80ab06 100644 --- a/lib/rclone/common.ts +++ b/lib/rclone/common.ts @@ -1,7 +1,6 @@ -import { appLocalDataDir } from '@tauri-apps/api/path' +import { appLocalDataDir, sep } from '@tauri-apps/api/path' import { exists } from '@tauri-apps/plugin-fs' import { fetch } from '@tauri-apps/plugin-http' -import { platform } from '@tauri-apps/plugin-os' import { Command } from '@tauri-apps/plugin-shell' export async function getDefaultPaths() { @@ -84,16 +83,7 @@ export async function getConfigPath({ id, validate = true }: { id: string; valid const appLocalDataDirPath = await appLocalDataDir() console.log('[getConfigPath] appLocalDataDirPath', appLocalDataDirPath) - const slashSymbol = platform() === 'windows' ? '\\' : '/' - - let configPath = - appLocalDataDirPath + - slashSymbol + - 'configs' + - slashSymbol + - id + - slashSymbol + - 'rclone.conf' + let configPath = appLocalDataDirPath + sep() + 'configs' + sep() + id + sep() + 'rclone.conf' console.log('[getConfigPath] configPath', configPath) diff --git a/lib/rclone/init.ts b/lib/rclone/init.ts index 56d09c0..6d2ae6a 100644 --- a/lib/rclone/init.ts +++ b/lib/rclone/init.ts @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/browser' import { invoke } from '@tauri-apps/api/core' -import { BaseDirectory, appLocalDataDir } from '@tauri-apps/api/path' +import { BaseDirectory, appLocalDataDir, sep } from '@tauri-apps/api/path' import { tempDir } from '@tauri-apps/api/path' import { ask, message } from '@tauri-apps/plugin-dialog' import { copyFile, exists, mkdir, readTextFile, remove } from '@tauri-apps/plugin-fs' @@ -104,8 +104,7 @@ export async function initRclone(args: string[]) { ) if (activeConfigFile.sync) { - const slashSymbol = platform() === 'windows' ? '\\' : '/' - if (!(await exists(configFolderPath + slashSymbol + 'rclone.conf'))) { + if (!(await exists(configFolderPath + sep() + 'rclone.conf'))) { await message('The config file could not be found. Switching to the default config.', { title: 'Invalid synced config', kind: 'error', @@ -176,7 +175,7 @@ export async function provisionRclone() { console.log('currentOs', currentOs) let tempDirPath = await tempDir() - if (tempDirPath.endsWith('/') || tempDirPath.endsWith('\\')) { + if (tempDirPath.endsWith(sep())) { tempDirPath = tempDirPath.slice(0, -1) } console.log('[provisionRclone] tempDirPath', tempDirPath) @@ -265,8 +264,7 @@ export async function provisionRclone() { const binaryName = currentPlatform === 'windows' ? 'rclone.exe' : 'rclone' - // "/" here looks to be working on windows - const rcloneBinaryPath = unarchivedPath + '/' + binaryName + const rcloneBinaryPath = unarchivedPath + sep() + binaryName console.log('[provisionRclone] rcloneBinaryPath', rcloneBinaryPath) try { diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b2c0a63..ce24764 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -28,7 +28,7 @@ fn unzip_file(zip_path: &str, output_folder: &str) -> Result<(), String> { let mut file = archive.by_index(i).map_err(|e| e.to_string())?; let outpath = Path::new(output_folder).join(file.name()); - if file.name().ends_with('/') { + if file.name().ends_with('/') || file.name().ends_with('\\') { fs::create_dir_all(&outpath).map_err(|e| e.to_string())?; } else { if let Some(p) = outpath.parent() { diff --git a/src/components/ConfigCreateDrawer.tsx b/src/components/ConfigCreateDrawer.tsx index a3593d0..a5d6896 100644 --- a/src/components/ConfigCreateDrawer.tsx +++ b/src/components/ConfigCreateDrawer.tsx @@ -8,9 +8,9 @@ import { Textarea, } from '@heroui/react' import { Button } from '@heroui/react' +import { sep } from '@tauri-apps/api/path' import { message, open } from '@tauri-apps/plugin-dialog' import { mkdir, readTextFile, writeTextFile } from '@tauri-apps/plugin-fs' -import { platform } from '@tauri-apps/plugin-os' import { UploadIcon } from 'lucide-react' import { useCallback, useMemo, useState } from 'react' import { getConfigPath } from '../../lib/rclone/common' @@ -59,9 +59,7 @@ export default function ConfigCreateDrawer({ const configPath = await getConfigPath({ id: generatedId, validate: false }) - const slashSymbol = platform() === 'windows' ? '\\' : '/' - - await mkdir(configPath.replace(slashSymbol + 'rclone.conf', ''), { + await mkdir(configPath.replace(sep() + 'rclone.conf', ''), { recursive: true, }) await writeTextFile(configPath, content) @@ -202,15 +200,12 @@ export default function ConfigCreateDrawer({ }, '') } - const slashSymbol = - platform() === 'windows' ? '\\' : '/' - setConfigContent(content) setConfig({ ...config, label: config.label || - selectedFile.split(slashSymbol).pop() || + selectedFile.split(sep()).pop() || 'New Config', isEncrypted: content.includes('RCLONE_ENCRYPT_V0:'), diff --git a/src/components/ConfigSyncDrawer.tsx b/src/components/ConfigSyncDrawer.tsx index 9ffe50e..f228011 100644 --- a/src/components/ConfigSyncDrawer.tsx +++ b/src/components/ConfigSyncDrawer.tsx @@ -8,9 +8,9 @@ import { Switch, } from '@heroui/react' import { Button } from '@heroui/react' +import { sep } from '@tauri-apps/api/path' import { message, open } from '@tauri-apps/plugin-dialog' import { exists, readTextFile } from '@tauri-apps/plugin-fs' -import { platform } from '@tauri-apps/plugin-os' import { UploadIcon } from 'lucide-react' import { useCallback, useState } from 'react' import { usePersistedStore } from '../../lib/store' @@ -221,10 +221,7 @@ export default function ConfigSyncDrawer({ return } - if ( - selectedFolder.endsWith('/') || - selectedFolder.endsWith('\\') - ) { + if (selectedFolder.endsWith(sep())) { selectedFolder = selectedFolder.slice( 0, -1 @@ -237,13 +234,8 @@ export default function ConfigSyncDrawer({ ) } - const slashSymbol = - platform() === 'windows' ? '\\' : '/' - const configPath = - selectedFolder + - slashSymbol + - 'rclone.conf' + selectedFolder + sep() + 'rclone.conf' let content: string | null = null @@ -265,9 +257,7 @@ export default function ConfigSyncDrawer({ ...config, label: config.label || - configPath - .split(slashSymbol) - .pop() || + configPath.split(sep()).pop() || 'New Config', sync: selectedFolder, }) diff --git a/src/components/PathFinder.tsx b/src/components/PathFinder.tsx index 1353f33..fa8faa0 100644 --- a/src/components/PathFinder.tsx +++ b/src/components/PathFinder.tsx @@ -2,9 +2,9 @@ import { Autocomplete, Tooltip } from '@heroui/react' import { AutocompleteItem, Button } from '@heroui/react' import { cn } from '@heroui/react' import * as Sentry from '@sentry/browser' +import { sep } from '@tauri-apps/api/path' import { open } from '@tauri-apps/plugin-dialog' import { readDir } from '@tauri-apps/plugin-fs' -import { platform } from '@tauri-apps/plugin-os' import { ArrowDownUp, FolderOpen, XIcon } from 'lucide-react' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useDebounce } from 'use-debounce' @@ -256,8 +256,6 @@ export function PathField({ // console.log('fetching suggestions for', path, field) - const slashSymbol = platform() === 'windows' ? '\\' : '/' - try { // If path is empty, show list of remotes if (!searchPath) { @@ -282,17 +280,14 @@ export function PathField({ console.error('Failed to fetch local suggestions:', err) try { // we also retry in case the last part of the path is wrong - cleanedPath = searchPath - .split(slashSymbol) - .slice(0, -1) - .join(slashSymbol) + cleanedPath = searchPath.split(sep()).slice(0, -1).join(sep()) localEntries = await readDir(cleanedPath) } catch (err) { console.error('Failed to fetch local suggestions (again):', err) } } - const extraSlash = cleanedPath.endsWith(slashSymbol) ? '' : slashSymbol + const extraSlash = cleanedPath.endsWith(sep()) ? '' : sep() const localSuggestions = localEntries .filter((entry) => !entry.isSymlink) @@ -484,8 +479,6 @@ export function MultiPathField({ // console.log('fetching suggestions for', path, field) - const slashSymbol = platform() === 'windows' ? '\\' : '/' - try { // If path is empty, show list of remotes if (!path) { @@ -510,14 +503,14 @@ export function MultiPathField({ console.error('Failed to fetch local suggestions:', err) try { // we also retry in case the last part of the path is wrong - cleanedPath = path.split(slashSymbol).slice(0, -1).join(slashSymbol) + cleanedPath = path.split(sep()).slice(0, -1).join(sep()) localEntries = await readDir(cleanedPath) } catch (err) { console.error('Failed to fetch local suggestions (again):', err) } } - const extraSlash = cleanedPath.endsWith(slashSymbol) ? '' : slashSymbol + const extraSlash = cleanedPath.endsWith(sep()) ? '' : sep() const localSuggestions = localEntries .filter((entry) => !entry.isSymlink) diff --git a/src/pages/Jobs.tsx b/src/pages/Jobs.tsx index 84c466d..2614237 100644 --- a/src/pages/Jobs.tsx +++ b/src/pages/Jobs.tsx @@ -36,14 +36,13 @@ export default function Jobs() { await fetchJobs() }, 2000) - // prevents jobs being refreshed after closing the window const unlisten = listen('tauri://close-requested', () => { clearInterval(interval) }) return () => { clearInterval(interval) - unlisten.then((unlisten) => unlisten()) + unlisten.then((u) => u()) } }, [fetchJobs]) @@ -69,6 +68,7 @@ export default function Jobs() {