PathFinder suggestions for local path

This commit is contained in:
FTCHD
2025-02-28 15:52:08 +02:00
parent 8d031754d4
commit 4c910b729d
+38 -18
View File
@@ -1,6 +1,7 @@
import { Autocomplete } from '@nextui-org/autocomplete' import { Autocomplete } from '@nextui-org/autocomplete'
import { AutocompleteItem, Button } from '@nextui-org/react' import { AutocompleteItem, Button } from '@nextui-org/react'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { readDir } from '@tauri-apps/plugin-fs'
import { ArrowDownUp, FolderOpen } from 'lucide-react' import { ArrowDownUp, FolderOpen } from 'lucide-react'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { isRemotePath } from '../../lib/fs' import { isRemotePath } from '../../lib/fs'
@@ -64,9 +65,7 @@ export default function PathFinder({
source: [], source: [],
dest: [], dest: [],
}) })
const [activeSuggestionField, setActiveSuggestionField] = useState<'source' | 'dest' | null>(
null
)
const [isLoading, setIsLoading] = useState<{ source: boolean; dest: boolean }>({ const [isLoading, setIsLoading] = useState<{ source: boolean; dest: boolean }>({
source: false, source: false,
dest: false, dest: false,
@@ -118,7 +117,7 @@ export default function PathFinder({
setIsLoading((prev) => ({ ...prev, [field]: true })) setIsLoading((prev) => ({ ...prev, [field]: true }))
setError((prev) => ({ ...prev, [field]: null })) setError((prev) => ({ ...prev, [field]: null }))
console.log('fetching suggestions for', path, field) // console.log('fetching suggestions for', path, field)
try { try {
// If path is empty, show list of remotes // If path is empty, show list of remotes
@@ -132,9 +131,37 @@ export default function PathFinder({
return return
} }
// Only fetch suggestions for remote paths // Fetch suggestions for local paths
if (!isRemotePath(path)) { if (!isRemotePath(path)) {
setSuggestions((prev) => ({ ...prev, [field]: [] })) let localEntries: Awaited<ReturnType<typeof readDir>> = []
let cleanedPath = path
try {
localEntries = await readDir(cleanedPath)
} catch (err) {
// most likely due to the path being a file
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('/').slice(0, -1).join('/')
localEntries = await readDir(cleanedPath)
} catch (err) {
console.error('Failed to fetch local suggestions (again):', err)
}
}
const extraSlash = cleanedPath.endsWith('/') ? '' : '/'
const localSuggestions = localEntries
.filter((entry) => !entry.isSymlink)
.map((entry) => ({
IsDir: entry.isDirectory,
Name: entry.name,
Path: `${cleanedPath}${extraSlash}${entry.name}`,
}))
setSuggestions((prev) => ({ ...prev, [field]: localSuggestions }))
return return
} }
@@ -189,15 +216,12 @@ export default function PathFinder({
) )
useEffect(() => { useEffect(() => {
if (activeSuggestionField) { fetchSuggestions(sourcePath, 'source')
const path = activeSuggestionField === 'source' ? sourcePath : destPath }, [sourcePath, fetchSuggestions])
const timeoutId = setTimeout(() => {
fetchSuggestions(path, activeSuggestionField)
}, 300)
return () => clearTimeout(timeoutId) useEffect(() => {
} fetchSuggestions(destPath, 'dest')
}, [sourcePath, destPath, activeSuggestionField, fetchSuggestions]) }, [destPath, fetchSuggestions])
//! suggestions close because component re-renders //! suggestions close because component re-renders
const renderField = useCallback( const renderField = useCallback(
@@ -229,14 +253,10 @@ export default function PathFinder({
inputValue={value} inputValue={value}
onInputChange={(e) => setValue(e)} onInputChange={(e) => setValue(e)}
onFocus={() => { onFocus={() => {
setActiveSuggestionField(field)
if (!value) { if (!value) {
fetchSuggestions('', field) fetchSuggestions('', field)
} }
}} }}
onBlur={() => {
setActiveSuggestionField(null)
}}
shouldCloseOnBlur={false} shouldCloseOnBlur={false}
placeholder={ placeholder={
isSource ? sourceOptions.placeholder : destOptions.placeholder isSource ? sourceOptions.placeholder : destOptions.placeholder