ux: admin/config: avoid reloading form to reload status
Massimo Melina committed
Jun 3, 2022 at 13:31 UTC
a11398d18df3cf3542f5804f411d59b07bb21279
3 files changed
+23
-9
admin/src/ConfigPage.ts
+9
-8
@@ -2,7 +2,7 @@
2
3
import { Box, Button, FormHelperText, Link } from '@mui/material';
4
import { createElement as h, isValidElement, useEffect, useRef } from 'react';
5
-import { apiCall, useApi, useApiComp } from './api'
5
+import { apiCall, useApi, useApiEx, useApiComp } from './api'
6
import { state, useSnapState } from './state'
7
import { Info, Refresh } from '@mui/icons-material'
8
import { Dict, modifiedSx } from './misc'
@@ -26,18 +26,19 @@ export const logLabels = {
26
export default function ConfigPage() {
27
const [res, reloadConfig] = useApiComp('get_config', { omit: ['vfs'] })
28
let snap = useSnapState()
29
- const [status, reloadStatus] = useApiComp(res && 'get_status')
30
- useEffect(reloadStatus, [res, reloadStatus])
29
+ const statusApi = useApiEx(res && 'get_status')
30
+ const status = statusApi.data
31
+ useEffect(statusApi.reload, [res]) //eslint-disable-line
32
32
- exposedReloadStatus = reloadStatus
33
+ exposedReloadStatus = statusApi.reload
34
useEffect(() => () => exposedReloadStatus = undefined, []) // clear on unmount
35
36
const admins = useApi('get_admins')[0]?.list
37
38
if (isValidElement(res))
39
return res
39
- if (isValidElement(status))
40
- return status
40
+ if (statusApi.error)
41
+ return statusApi.element
42
const { changes } = snap
43
const values = (loaded !== res) ? (state.config = loaded = res) : snap.config
44
const maxSpeedDefaults = {
@@ -61,7 +62,7 @@ export default function ConfigPage() {
62
addToBar: [h(Button, {
63
onClick() {
64
reloadConfig()
64
- reloadStatus()
65
+ statusApi.reload()
66
},
67
startIcon: h(Refresh),
68
}, "Reload")],
@@ -139,7 +140,7 @@ export default function ConfigPage() {
140
await alertDialog("You are being redirected but in some cases this may fail. Hold on tight!", 'warning')
141
return window.location.href = loc.protocol + '//' + loc.hostname + ':' + newPort + loc.pathname
142
}
142
- setTimeout(reloadStatus, 2000) // in case of busy port, finding the name of the process can be a lengthy task. Worst case we'll get the generic error message
143
+ setTimeout(statusApi.reload, 2000) // in case of busy port, finding the name of the process can be a lengthy task. Worst case we'll get the generic error message
144
Object.assign(loaded, values) // since changes are recalculated subscribing state.config, but it depends on 'loaded' to (which cannot be subscribed), be sure to update loaded first
145
recalculateChanges()
146
toast("Changes applied", 'success')
admin/src/HomePage.ts
+1
-1
@@ -92,5 +92,5 @@ function cfgLink(text=`Configuration page`) {
92
}
93
94
export function proxyWarning(cfg: any, status: any) {
95
- return cfg && !cfg.proxies && !cfg.ignore_proxies && status.proxyDetected
95
+ return cfg && !cfg.proxies && !cfg.ignore_proxies && status?.proxyDetected
96
}
admin/src/api.ts
+13
@@ -18,6 +18,19 @@ export function useApiComp<T=any>(...args: Parameters<typeof useApi>): [T | Reac
18
[res, err, arg0, reload])
19
}
20
21
+export function useApiEx<T=any>(...args: Parameters<typeof useApi>) {
22
+ const [data, error, reload] = useApi<T>(...args)
23
+ const cmd = args[0]
24
+ const loading = data === undefined
25
+ const element = useMemo(() =>
26
+ !cmd ? null
27
+ : error ? h(Alert, { severity: 'error' }, String(error), h(IconBtn, { icon: Refresh, onClick: reload, sx: { m:'-8px 0 -8px 16px' } }))
28
+ : loading ? spinner()
29
+ : null,
30
+ [error, cmd, loading, reload])
31
+ return { data, error, reload, loading, element }
32
+}
33
+
34
const PREFIX = '/~/api/'
35
36
export function apiCall(cmd: string, params?: Dict) : Promise<any> {