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> {