prevent stale data in caches, add toolbar actions (#18 )

This commit is contained in:
FTCHD
2026-01-10 20:17:32 +07:00
parent cea94d0a4e
commit 712d0e5811
4 changed files with 145 additions and 8 deletions
+22 -3
View File
@@ -98,6 +98,15 @@ export default function Toolbar() {
refetchInterval: 5_000,
})
const { data: vfsList } = useQuery({
queryKey: ['vfs', 'list'],
queryFn: async () => {
const response = await rclone('/vfs/list')
return response?.vfses ?? []
},
refetchInterval: 5_000,
})
const remotes = useMemo(() => remotesQuery.data ?? [], [remotesQuery.data])
const remoteTypes = useMemo(() => remoteTypesQuery.data ?? {}, [remoteTypesQuery.data])
@@ -115,12 +124,13 @@ export default function Toolbar() {
useEffect(() => {
console.log(`${mountList?.length} mounts`)
console.log(`${serveList?.length} serves`)
console.log(`${vfsList?.length} vfses`)
const { results } = runToolbarEngine(searchStringDebounced, remotes, remoteTypes)
startTransition(() => {
setEngineResults(results)
})
}, [mountList, serveList, searchStringDebounced, remotes, remoteTypes])
}, [mountList, serveList, vfsList, searchStringDebounced, remotes, remoteTypes])
useEffect(() => {
let unlisten: (() => void) | undefined
@@ -190,16 +200,25 @@ export default function Toolbar() {
}, [])
const handleExecute = useCallback(async (result: ResolvedToolbarResult) => {
await closeToolbar()
setSearchString('')
let keepOpen = false
try {
const action = result.resolve()
await action.onPress(result.args, {
openWindow,
updateText: (text: string) => {
setSearchString(text)
keepOpen = true
},
})
} catch (error) {
console.error('[Toolbar] Failed to execute action', error)
}
if (!keepOpen) {
await closeToolbar()
setSearchString('')
}
}, [])
const executeShortcutAtIndex = useCallback(
+117 -5
View File
@@ -755,6 +755,7 @@ const actions: ToolbarActionDefinition[] = [
)
)
}
results.push(createBaseResult('Back', 'Return to menu', { _action: 'back' }, 50))
return results
}
@@ -780,15 +781,17 @@ const actions: ToolbarActionDefinition[] = [
return results
},
onPress: async (args) => {
onPress: async (args, context) => {
if (args._action === 'back') {
context.updateText('')
return
}
const remote =
typeof args.remote === 'string' && args.remote.length > 0 ? args.remote : undefined
if (!remote) {
await notify({
title: 'Error',
body: 'Please specify a remote to browse',
})
context.updateText('Browse ')
return
}
@@ -1146,6 +1149,115 @@ const actions: ToolbarActionDefinition[] = [
await getCurrentWindow().emit('close-app')
},
},
{
id: 'vfs',
label: 'VFS',
description: COMMAND_DESCRIPTIONS.vfs,
keywords: COMMAND_KEYWORDS.vfs,
getDefaultResult: () => createBaseResult('VFS', 'Specify a cache to forget', {}, 35),
getResults: ({ query }) => {
if (query && !matchesKeyword(query, COMMAND_KEYWORDS.vfs)) {
return []
}
const results: ToolbarActionResult[] = []
const activeVfses = queryClient.getQueryData(['vfs', 'list']) as string[] | undefined
if (activeVfses && activeVfses.length > 0) {
for (const vfs of activeVfses) {
results.push(
createBaseResult(
`Forget ${vfs}`,
'Clear the VFS directory cache',
{ _action: 'forget', _fs: vfs },
180
)
)
}
if (activeVfses.length >= 2) {
results.push(
createBaseResult(
`Forget All VFS Caches (${activeVfses.length} active)`,
'Clear all VFS directory caches',
{ _action: 'forget_all' },
170
)
)
}
} else {
results.push(
createBaseResult('Back', 'No active VFS caches', { _action: 'back' }, 35)
)
}
return results
},
onPress: async (args, context) => {
if (!args._action) {
context.updateText('VFS ')
return
}
if (args._action === 'back') {
context.updateText('')
return
}
if (args._action === 'forget') {
const fs = args._fs as string
try {
await rclone('/vfs/forget', {
params: {
query: {
fs,
},
},
})
await notify({
title: 'VFS Cache Cleared',
body: `Directory cache for ${fs} has been cleared`,
})
queryClient.setQueryData(
['vfs', 'list'],
(old: string[] | undefined) => old?.filter((v) => v !== fs) ?? []
)
} catch (error) {
console.error('[toolbar] failed to forget VFS cache', error)
await message(
error instanceof Error ? error.message : 'Failed to clear VFS cache',
{
title: 'VFS Forget',
kind: 'error',
}
)
}
return
}
if (args._action === 'forget_all') {
try {
await rclone('/vfs/forget')
await notify({
title: 'All VFS Caches Cleared',
body: 'All VFS directory caches have been cleared',
})
queryClient.setQueryData(['vfs', 'list'], [])
} catch (error) {
console.error('[toolbar] failed to forget all VFS caches', error)
await message(
error instanceof Error ? error.message : 'Failed to clear all VFS caches',
{
title: 'VFS Forget All',
kind: 'error',
}
)
}
return
}
},
},
]
export function getToolbarActions(): ToolbarActionDefinition[] {
+4
View File
@@ -24,6 +24,7 @@ const REMOTE_EDIT_DESCRIPTION = 'Edit a remote.'
const REMOTE_AUTO_MOUNT_DESCRIPTION = 'Configure auto mount options for a remote.'
const REMOTE_LIST_DESCRIPTION = 'Show all configured remotes.'
const QUIT_DESCRIPTION = 'Quit the application.'
const VFS_DESCRIPTION = 'Forget the local cache for one or all remotes.'
export const COMMAND_CONFIG = {
copy: { route: '/copy', windowLabel: 'Copy' },
@@ -47,6 +48,7 @@ export const COMMAND_CONFIG = {
remoteAutoMount: {},
remoteList: {},
quit: {},
vfs: {},
} as const
export const COMMAND_DESCRIPTIONS: Record<ToolbarCommandId, string> = {
@@ -71,6 +73,7 @@ export const COMMAND_DESCRIPTIONS: Record<ToolbarCommandId, string> = {
remoteAutoMount: REMOTE_AUTO_MOUNT_DESCRIPTION,
remoteList: REMOTE_LIST_DESCRIPTION,
quit: QUIT_DESCRIPTION,
vfs: VFS_DESCRIPTION,
}
export const COMMAND_KEYWORDS: Record<ToolbarCommandId, string[]> = {
@@ -95,4 +98,5 @@ export const COMMAND_KEYWORDS: Record<ToolbarCommandId, string[]> = {
remoteAutoMount: ['mount', 'remote', 'update', 'change'],
remoteList: ['remote', 'list', 'show'],
quit: ['quit', 'exit', 'close'],
vfs: ['vfs', 'cache', 'forget'],
}
+2
View File
@@ -20,6 +20,7 @@ export type ToolbarCommandId =
| 'remoteAutoMount'
| 'quit'
| 'remoteList'
| 'vfs'
export type ToolbarActionArgs = Record<string, any>
@@ -32,6 +33,7 @@ export interface ToolbarActionResult {
export interface ToolbarActionOnPressContext {
openWindow: (options: { name: string; url: string }) => Promise<unknown>
updateText: (text: string) => void
}
export interface ToolbarActionPath {