fix: admin/fs: save button was not closing the dialog on mobile
Massimo Melina committed
Apr 14, 2024 at 16:01 UTC
c65918db824f290275ce915ff216a55e6066eef2
2 files changed
+23
-18
admin/src/FileForm.ts
+9
-6
@@ -6,8 +6,10 @@ import { Alert, Box, Collapse, FormHelperText, Link, MenuItem, MenuList, useThem
6
import { BoolField, DisplayField, Field, FieldProps, Form, MultiSelectField, SelectField, StringField
7
} from '@hfs/mui-grid-form'
8
import { apiCall, UseApi } from './api'
9
-import { basename, defaultPerms, formatBytes, formatTimestamp, isEqualLax, isWhoObject, newDialog, objSameKeys,
10
- onlyTruthy, prefix, VfsPerms, wantArray, Who, WhoObject, matches, HTTP_MESSAGES, xlate, md } from './misc'
9
+import {
10
+ basename, defaultPerms, formatBytes, formatTimestamp, isEqualLax, isWhoObject, newDialog, objSameKeys,
11
+ onlyTruthy, prefix, VfsPerms, wantArray, Who, WhoObject, matches, HTTP_MESSAGES, xlate, md, Callback
12
+} from './misc'
13
import { Btn, IconBtn, LinkBtn, modifiedProps, useBreakpoint, wikiLink } from './mui'
14
import { reloadVfs, VfsNode } from './VfsPage'
15
import _ from 'lodash'
@@ -20,6 +22,8 @@ import QrCreator from 'qr-creator';
22
import MenuButton from './MenuButton'
23
import addFiles, { addLink, addVirtual } from './addFiles'
24
25
+const ACCEPT_LINK = "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept"
26
+
27
export interface Account { username: string }
28
29
interface FileFormProps {
@@ -27,11 +31,9 @@ interface FileFormProps {
31
addToBar?: ReactNode
32
statusApi: UseApi
33
accounts: Account[]
34
+ saved: Callback
35
}
31
-
32
-const ACCEPT_LINK = "https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept"
33
-
34
-export default function FileForm({ file, addToBar, statusApi, accounts }: FileFormProps) {
36
+export default function FileForm({ file, addToBar, statusApi, accounts, saved }: FileFormProps) {
37
const { parent, children, isRoot, byMasks, ...rest } = file
38
const [values, setValues] = useState(rest)
39
useEffect(() => {
@@ -135,6 +137,7 @@ export default function FileForm({ file, addToBar, statusApi, accounts }: FileFo
137
if (props.name !== file.name) // when the name changes, the id of the selected file is changing too, and we have to update it in the state if we want it to be correctly re-selected after reload
138
state.selectedFiles[0].id = file.parent!.id + props.name + (isDir ? '/' : '')
139
reloadVfs()
140
+ saved()
141
}
142
},
143
fields: [
admin/src/VfsPage.ts
+14
-12
@@ -1,6 +1,6 @@
1
// This file is part of HFS - Copyright 2021-2023, 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, useApiEx } from './api'
5
import { Alert, Box, Button, Card, CardContent, Grid, Link, List, ListItem, ListItemText, Typography } from '@mui/material'
6
import { state, useSnapState } from './state'
@@ -34,9 +34,18 @@ export default function VfsPage() {
34
const single = selectedFiles.length < 2 && (selectedFiles[0] as VfsNode || vfs)
35
const accountsApi = useApiEx<{ list: Account[] }>('get_accounts') // load accounts once and for all, or !isSideBreakpoint will cause a call for each selection
36
37
- const sideContent = accountsApi.element || !vfs ? null : single ? h(FileForm, {
37
+ // this will take care of closing the dialog, for user's convenience, after "cut" button is pressed
38
+ const closeDialogRef = useRef(_.noop)
39
+ useEffect(() => {
40
+ if (movingFile === selectedFiles[0]?.id)
41
+ closeDialogRef.current()
42
+ }, [movingFile])
43
+
44
+ const sideContent = accountsApi.element || !vfs ? null
45
+ : single ? h(FileForm, {
46
addToBar: isSideBreakpoint && h(Box, { flex: 1, textAlign: 'right', mr: 1, color: '#8883' }, vfsNodeIcon(single)),
47
statusApi,
48
+ saved: () => closeDialogRef.current(),
49
accounts: accountsApi?.data?.list ?? [],
50
file: single // it's actually Snapshot<VfsNode> but it's easier this way
51
})
@@ -51,13 +60,6 @@ export default function VfsPage() {
60
)
61
)
62
54
- // this will take care of closing the dialog, for user's convenience, after "cut" button is pressed
55
- const [closeDialog, setCloseDialog] = useState(() => _.noop)
56
- useEffect(() => {
57
- if (movingFile === selectedFiles[0]?.id)
58
- closeDialog()
59
- }, [movingFile, closeDialog])
60
-
63
useEffect(() => {
64
if (isSideBreakpoint || !sideContent || !selectedFiles.length) return
65
const ancestors = ['']
@@ -80,9 +82,9 @@ export default function VfsPage() {
82
state.selectedFiles = []
83
},
84
})
83
- setCloseDialog(() => close)
85
+ closeDialogRef.current = close
86
return close // auto-close dialog if we are switching to side-panel
85
- }, [isSideBreakpoint, selectedFiles])
87
+ }, [isSideBreakpoint, _.last(selectedFiles)?.id])
88
89
useEffect(() => {
90
state.vfs = undefined
@@ -100,7 +102,7 @@ export default function VfsPage() {
102
103
function consumeSelectOnReload() {
104
if (selectOnReload)
103
- closeDialog() // noop when side-paneling
105
+ closeDialogRef.current() // noop when side-paneling
106
const ret = selectOnReload && onlyTruthy(selectOnReload.map(id => id2node.get(id)))
107
selectOnReload = undefined
108
return ret