fix: admin/fs: inconsistent behavior of root button under linux
Massimo Melina committed
Jul 26, 2022 at 11:25 UTC
28f601423ce52d191da5ee2a84d7085cfa55a0eb
1 file changed
+33
-17
admin/src/FilePicker.ts
+33
-17
@@ -1,6 +1,6 @@
1
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
-import { createElement as h, Fragment, useEffect, useMemo, useState } from 'react'
3
+import { createElement as h, Fragment, useEffect, useMemo, useRef, useState } from 'react'
4
import { apiCall, useApiList } from './api'
5
import _ from 'lodash'
6
import {
@@ -15,7 +15,7 @@ import {
15
Typography
16
} from '@mui/material'
17
import { enforceFinal, formatBytes, isWindowsDrive, spinner, Center, err2msg } from './misc'
18
-import { ArrowUpward, Home } from '@mui/icons-material'
18
+import { ArrowUpward, VerticalAlignTop } from '@mui/icons-material'
19
import { StringField } from '@hfs/mui-grid-form'
20
import { FileIcon, FolderIcon } from './VfsTree'
21
import { FixedSizeList } from 'react-window'
@@ -34,10 +34,13 @@ interface FilePickerProps {
34
export default function FilePicker({ onSelect, multiple=true, files=true, folders=true, fileMask, from='' }: FilePickerProps) {
35
const [cwd, setCwd] = useState(from)
36
const [ready, setReady] = useState(false)
37
+ const isWindows = useRef(false)
38
useEffect(() => {
39
apiCall('resolve_path', { path: from, closestFolder: true }).then(res => {
39
- if (typeof res.path === 'string')
40
+ if (typeof res.path === 'string') {
41
setCwd(res.path)
42
+ isWindows.current = res.path[1] === ':'
43
+ }
44
}).finally(() => setReady(true))
45
}, [from])
46
const { list, error, loading } = useApiList<DirEntry>(ready && 'ls', { path: cwd, files, fileMask })
@@ -57,28 +60,41 @@ export default function FilePicker({ onSelect, multiple=true, files=true, folder
60
const filteredList = useMemo(() => list.filter(it => filterMatch(it.n)), [list,filterMatch])
61
if (loading)
62
return spinner()
60
- const pathDelimiter = /[:\\]/.test(cwd) ? '\\' : '/'
61
- const cwdPostfixed = enforceFinal(pathDelimiter, cwd)
63
+ const root = isWindows.current ? '' : '/'
64
+ const pathDelimiter = isWindows.current ? '\\' : '/'
65
+ const cwdDelimiter = enforceFinal(pathDelimiter, cwd)
66
+ const isRoot = cwd.length < 2
67
return h(Fragment, {},
63
- h(Box, { display:'flex', gap: 1 },
68
+ h(Box, { display: 'flex', gap: 1 },
69
h(Button, {
70
+ title: "root",
71
+ disabled: isRoot,
72
onClick() {
66
- const s = /[\\/]$/.test(cwd) ? cwd.slice(0,-1) : cwd // exclude final delimiter, if any
67
- setCwd( isWindowsDrive(s) ? '' : s.slice(0, s.lastIndexOf(pathDelimiter)) )
73
+ setCwd(root)
74
}
69
- }, h(ArrowUpward)),
75
+ }, h(VerticalAlignTop)),
76
h(Button, {
77
+ disabled: isRoot,
78
+ title: "parent folder",
79
onClick() {
72
- setCwd('')
80
+ const cwdND = /[\\/]$/.test(cwd) ? cwd.slice(0,-1) : cwd // exclude final delimiter, if any
81
+ const parent = isWindowsDrive(cwdND) ? root : cwdND.slice(0, cwdND.lastIndexOf(pathDelimiter) || 1)
82
+ setCwd(parent)
83
}
74
- }, h(Home)),
84
+ }, h(ArrowUpward)),
85
h(StringField, {
76
- label: 'Current path',
86
+ label: "Current path",
87
value: cwd,
78
- onChange: setCwd as any,
88
+ InputLabelProps: { shrink: true },
89
+ async onChange(v) {
90
+ if (!v)
91
+ return setCwd(root)
92
+ const res = await apiCall('resolve_path', { path: v })
93
+ setCwd(res.path)
94
+ },
95
}),
96
),
81
- error ? h(Alert, { severity:'error' }, err2msg(error))
97
+ error ? h(Alert, { severity: 'error' }, err2msg(error))
98
: h(Fragment, {},
99
h(Box, { sx: { flex: 1 } },
100
!list.length ? h(Center, { flex: 1, mt: '4em' }, "No elements in this folder") : h(AutoSizer, {
@@ -93,9 +109,9 @@ export default function FilePicker({ onSelect, multiple=true, files=true, folder
109
key: it.n,
110
onClick() {
111
if (isFolder)
96
- setCwd(cwdPostfixed + it.n)
112
+ setCwd(cwdDelimiter + it.n)
113
else
98
- onSelect([cwdPostfixed + it.n])
114
+ onSelect([cwdDelimiter + it.n])
115
}
116
},
117
multiple && h(Checkbox, {
@@ -126,7 +142,7 @@ export default function FilePicker({ onSelect, multiple=true, files=true, folder
142
disabled: !folders && !sel.length && files,
143
sx: { minWidth: 'max-content' },
144
onClick() {
129
- onSelect(sel.length ? sel.map(x => cwdPostfixed + x) : [cwd])
145
+ onSelect(sel.length ? sel.map(x => cwdDelimiter + x) : [cwd])
146
}
147
}, files && (sel.length || !folders) ? `Select (${sel.length})` : `Select this folder`),
148
h(TextField, {