fix: admin/home: link "get a free..." not working
Massimo Melina committed
Jun 19, 2024 at 11:50 UTC
85bfe1919db2208953563eb41e01e055deed11d0
5 files changed
+24
-9
admin/src/AccountsPage.ts
+1
-1
@@ -69,7 +69,7 @@ export default function AccountsPage() {
69
Content: () => sideContent,
70
onClose: selectNone,
71
})
72
- return close
72
+ return () => void close()
73
}, [isSideBreakpoint, sel, selectedAccount])
74
75
return element || h(Grid, { container: true, maxWidth: '80em' },
admin/src/OptionsPage.ts
+1
-1
@@ -353,7 +353,7 @@ export async function suggestMakingCert() {
353
onClose: resolve,
354
Content: () => h(Box, { p: 1, lineHeight: 1.5, },
355
h(Box, {}, "HTTPS needs a certificate to work."),
356
- h(Box, {}, "We suggest you to ", h(InLink, { to: 'internet', onClick: close }, "get a free but proper certificate"), '.'),
356
+ h(Box, {}, "We suggest you to ", h(InLink, { to: 'internet' }, "get a free but proper certificate"), '.'),
357
h(Box, {}, "If you don't have a domain ", h(LinkBtn, { onClick: makeCertAndSave }, "make a self-signed certificate"),
358
" but that ", wikiLink('HTTPS#certificate', " won't be perfect"), '.' ),
359
)
admin/src/VfsPage.ts
+1
-1
@@ -86,7 +86,7 @@ export default function VfsPage() {
86
},
87
})
88
closeDialogRef.current = close
89
- return close // auto-close dialog if we are switching to side-panel
89
+ return () => void close() // auto-close dialog if we are switching to side-panel
90
}, [isSideBreakpoint, _.last(selectedFiles)?.id])
91
92
useEffect(() => {
admin/src/mui.ts
+13
-3
@@ -7,12 +7,12 @@ import { createElement as h, forwardRef, Fragment, ReactElement, ReactNode, useC
7
ForwardedRef, useState, useMemo } from 'react'
8
import { Box, BoxProps, Breakpoint, ButtonProps, CircularProgress, IconButton, IconButtonProps, Link, LinkProps,
9
Tooltip, TooltipProps, useMediaQuery } from '@mui/material'
10
-import { formatPerc, isIpLan, isIpLocalHost, prefix, WIKI_URL, with_ } from './misc'
10
+import { anyDialogOpen, closeDialog, formatPerc, isIpLan, isIpLocalHost, prefix, WIKI_URL, with_ } from './misc'
11
import { dontBotherWithKeys, restartAnimation, useBatch, useStateMounted } from '@hfs/shared'
12
import { Promisable, StringField } from '@hfs/mui-grid-form'
13
import { alertDialog, confirmDialog, toast } from './dialog'
14
import { LoadingButton } from '@mui/lab'
15
-import { Link as RouterLink } from 'react-router-dom'
15
+import { Link as RouterLink, LinkProps as RouterLinkProps, useNavigate } from 'react-router-dom'
16
import { SvgIconProps } from '@mui/material/SvgIcon/SvgIcon'
17
import _ from 'lodash'
18
import { ALL as COUNTRIES } from './countries'
@@ -197,13 +197,23 @@ export function iconTooltip(icon: SvgIconComponent, tooltip: ReactNode, sx?: SxP
197
return hTooltip(tooltip, undefined, h(icon, { sx, ...props }) )
198
}
199
200
-export function InLink(props:any) {
200
+// link for internal navigation
201
+export function InLink({ ...props }: LinkProps & RouterLinkProps) {
202
+ // make links inside dialogs work correctly
203
+ const nav = useNavigate()
204
+ props.onClickCapture = async ev => {
205
+ ev.preventDefault()
206
+ while (anyDialogOpen())
207
+ await closeDialog()?.closed
208
+ nav(props.to)
209
+ }
210
return h(Link, { component: RouterLink, ...props })
211
}
212
213
export const Center = forwardRef((props: BoxProps, ref) =>
214
h(Box, { ref, display:'flex', height:'100%', width:'100%', justifyContent:'center', alignItems:'center', flexDirection: 'column', ...props }))
215
216
+// looks like a link, but it's a button
217
export function LinkBtn({ ...rest }: LinkProps) {
218
return h(Link, {
219
...rest,
shared/dialogs.ts
+8
-3
@@ -8,7 +8,8 @@ import { domOn, isPrimitive, objSameKeys, wait } from '.'
8
export interface DialogOptions {
9
Content: FunctionComponent<any>,
10
closable?: boolean,
11
- onClose?: (v?:any)=> any,
11
+ onClose?: (v?: any) => any,
12
+ closingValue?: any,
13
className?: string,
14
icon?: string | ReactNode | FunctionComponent,
15
closableProps?: any,
@@ -186,6 +187,7 @@ export function newDialog(options: DialogOptions) {
187
options = objSameKeys(options, x => isValidElement(x) ? ref(x) : x) as typeof options // encapsulate elements as react will try to write, but valtio makes them readonly
188
options.$opening = setTimeout(() => { // in case dialogs were just closed, account for window.history delay. This should be harmless as ux is unaffected, and programmatically you already didn't expect this to happen immediately but at state change
189
dialogs.push(options)
190
+ options = dialogs[dialogs.length - 1] // replace with proxy object, to stay in sync with its changes
191
if (options.closable !== false)
192
history.pushState({ $dialog: $id, ts, idx: history.state.idx + 1 }, '')
193
}, 10) // 10 for firefox, chrome125 seems to be ok with 1
@@ -197,7 +199,8 @@ export function newDialog(options: DialogOptions) {
199
if (i < 0) return
200
if (history.state.$dialog === $id)
201
options.closed = back()
200
- return closeDialogAt(i, v)
202
+ closeDialogAt(i, v)
203
+ return options
204
}
205
}
206
@@ -220,7 +223,9 @@ export function closeDialog(v?:any, skipHistory=false) {
223
function closeDialogAt(i: number, value?: any) {
224
const [d] = dialogs.splice(i,1)
225
;(focusBak.pop() as any)?.focus?.() // if element is not HTMLElement, it doesn't have focus method
223
- return d?.onClose?.(value)
226
+ d.closingValue = value
227
+ d?.onClose?.(value)
228
+ return d
229
}
230
231
export function anyDialogOpen() {