admin/shared: nodes can be deleted using Delete key
Massimo Melina committed
Apr 15, 2026 at 12:28 UTC
b0662c77168ee8ad8b1b2b0b04dea585d0082088
2 files changed
+11
-2
admin/src/VfsPage.ts
+1
@@ -190,6 +190,7 @@ export function reindexVfs({
190
if (clearMap)
191
id2vfsNode.clear()
192
recur(node, node.parent?.id || '/', node.parent)
193
+ state.vfsShowDiskContentFor = ''
194
// Reindex can update ids/references; remap caller-provided selections to canonical nodes from id2node.
195
if (select)
196
state.selectedFiles = onlyTruthy(select.map(x => id2vfsNode.get(typeof x === 'string' ? x : x.id)))
admin/src/VfsTree.ts
+10
-2
@@ -8,7 +8,7 @@ import {
8
RemoveRedEye, Web, Upload, Cloud, Delete, HighlightOff, UnfoldMore, UnfoldLess
9
} from '@mui/icons-material'
10
import { Box, Typography } from '@mui/material'
11
-import { id2vfsNode, isDescendantUri, reindexVfs, VfsNodeAdmin } from './VfsPage'
11
+import { deleteVfs, id2vfsNode, isDescendantUri, reindexVfs, VfsNodeAdmin } from './VfsPage'
12
import { getOrSet, onlyTruthy, pathEncode, prefix, toMutable, wantArray, Who, with_ } from './misc'
13
import { Flex, iconTooltip, useToggleButton } from './mui'
14
import VfsMenuBar from './VfsMenuBar'
@@ -39,6 +39,12 @@ export default function VfsTree({ statusApi }:{ statusApi: ApiObject }) {
39
void el.addEventListener('focusin', (e: any) => e.stopImmediatePropagation()))
40
ref.current = el
41
},
42
+ onKeyUp(ev) {
43
+ if (ev.key === 'Delete') {
44
+ deleteVfs([id])
45
+ ev.stopPropagation()
46
+ }
47
+ },
48
onDoubleClick: toggle,
49
label:
50
h(Box, {
@@ -91,7 +97,8 @@ export default function VfsTree({ statusApi }:{ statusApi: ApiObject }) {
97
collapseIcon: h(ExpandMore, { onClick: toggle }),
98
expandIcon: h(ChevronRight, { onClick: toggle }),
99
nodeId: id
94
- }, with_(node.source && isFolder ? "files from " + node.source : !node.children?.length && isRoot && "nothing here", x => x && h(TreeItem, { nodeId: SPECIAL_TREE_ITEM + id, label: h('i', {}, x) })),
100
+ }, with_(node.source && isFolder ? "files from " + node.source : !node.children?.length && isRoot && "nothing here", x =>
101
+ x && h(TreeItem, { nodeId: SPECIAL_TREE_ITEM + id, label: h('i', {}, x) })),
102
...node.children?.map(x => h(Branch, { key: x.id, node: x })) || []
103
)
104
@@ -147,6 +154,7 @@ export default function VfsTree({ statusApi }:{ statusApi: ApiObject }) {
154
},
155
onNodeSelect(_ev, ids) {
156
state.selectedFiles = onlyTruthy(wantArray(ids).map(id => id2vfsNode.get(id)))
157
+ // this is the only point where we have special node ids that don't fit selectedFiles
158
state.vfsShowDiskContentFor = ids.length === 1 && ids[0]?.[0] === SPECIAL_TREE_ITEM && id2vfsNode.get(ids[0].slice(1))?.source || ''
159
}
160
}, h(Branch, { node: vfs as Readonly<VfsNodeAdmin> }))