fix: admin/shared: reload button didn't provide any visual clue of activity

Massimo Melina committed Nov 1, 2025 at 12:47 UTC a0d331e85bf478fc9c18f3148fe886f127c727ad
2 files changed +6 -3
admin/src/VfsPage.ts
+5 -2
@@ -6,7 +6,7 @@ import { Alert, Box, Button, Card, CardContent, Grid, Link, List, ListItem, List
6 import { state, useSnapState } from './state'
7 import VfsTree, { vfsNodeIcon } from './VfsTree'
8 import {
9 - CFG, matches, newDialog, normalizeHost, onlyTruthy, pathEncode, prefix, VfsNodeAdminSend, HIDE_IN_TESTS
9 + CFG, matches, newDialog, normalizeHost, onlyTruthy, pathEncode, prefix, VfsNodeAdminSend, HIDE_IN_TESTS, wait
10 } from './misc'
11 import { Flex, useBreakpoint } from './mui'
12 import { reactJoin } from '@hfs/shared'
@@ -18,11 +18,13 @@ import { alertDialog, confirmDialog } from './dialog'
18 import { PageProps } from './App'
19
20 let selectOnReload: string[] | undefined
21 +let exposeVfsLoading: Promise<unknown> | undefined
22
23 export default function VfsPage({ setTitleSide }: PageProps) {
24 const [id2node] = useState(() => new Map<string, VfsNode>())
25 const { vfs, selectedFiles, movingFile } = useSnapState()
25 - const { data, reload, element } = useApiEx('get_vfs')
26 + const { data, reload, element, loading } = useApiEx('get_vfs')
27 + exposeVfsLoading = loading
28 useMemo(() => vfs || reload(), [vfs, reload])
29 const { data: config } = useApiEx('get_config', { only: [CFG.force_address, CFG.base_url] })
30 const sideBreakpoint = 'md'
@@ -171,6 +173,7 @@ export default function VfsPage({ setTitleSide }: PageProps) {
173 export function reloadVfs(pleaseSelect?: string[]) {
174 selectOnReload = pleaseSelect
175 state.vfs = undefined
176 + return wait(100).then(() => exposeVfsLoading) // ensure the loading started and finished. Not great, but does the job. Consider a cleaner solution.
177 }
178
179 async function deleteFiles() {
src/api.vfs.ts
+1 -1
@@ -10,7 +10,7 @@ import { ApiError, ApiHandlers } from './apiMiddleware'
10 import { dirname, extname, join, resolve } from 'path'
11 import {
12 enforceFinal, enforceStarting, isDirectory, isValidFileName, isWindowsDrive, makeMatcher, PERM_KEYS,
13 - VfsNodeAdminSend
13 + VfsNodeAdminSend, wait
14 } from './misc'
15 import {
16 IS_WINDOWS, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR, HTTP_CONFLICT, HTTP_NOT_ACCEPTABLE,