@samitouri / QOSami-HFS / commits / b0662c77

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> }))