better code: typing

Massimo Melina committed May 3, 2023 at 09:57 UTC 0b51c0d5bc0c1a1ba596dc1d4cd24c3bf9052287
2 files changed +9 -6
admin/src/HomePage.ts
+8 -5
@@ -3,7 +3,7 @@
3 import { createElement as h } from 'react'
4 import { Box, Button, LinearProgress, Link } from '@mui/material'
5 import { apiCall, useApi, useApiEx, useApiList } from './api'
6 -import { Dict, dontBotherWithKeys, InLink, objSameKeys, onlyTruthy } from './misc'
6 +import { dontBotherWithKeys, InLink, objSameKeys, onlyTruthy } from './misc'
7 import { CheckCircle, Error, Info, Launch, Warning } from '@mui/icons-material'
8 import md from './md'
9 import { useSnapState } from './state'
@@ -11,15 +11,17 @@ import { confirmDialog } from './dialog'
11 import { isCertError, isKeyError, makeCertAndSave } from './OptionsPage'
12 import { VfsNode } from './VfsPage'
13 import { Account } from './AccountsPage'
14 +import _ from 'lodash'
15
16 export const REPO_URL = 'https://github.com/rejetto/hfs/'
17
18 interface ServerStatus { listening: boolean, port: number, error?: string, busy?: string }
19 +interface Status { http: ServerStatus, https: ServerStatus, frpDetected: boolean }
20
21 export default function HomePage() {
22 const SOLUTION_SEP = " — "
23 const { username } = useSnapState()
22 - const { data: status, reload: reloadStatus, element: statusEl } = useApiEx<Dict<ServerStatus>>('get_status')
24 + const { data: status, reload: reloadStatus, element: statusEl } = useApiEx<Status>('get_status')
25 const { data: vfs } = useApiEx<{ root?: VfsNode }>('get_vfs')
26 const [account] = useApi<Account>(username && 'get_account')
27 const { data: cfg, reload: reloadCfg } = useApiEx('get_config', { only: ['https_port', 'cert', 'private_key', 'proxies'] })
@@ -30,10 +32,11 @@ export default function HomePage() {
32 const goSecure = !http?.listening && https?.listening ? 's' : ''
33 const srv = goSecure ? https : (http?.listening && http)
34 const href = srv && `http${goSecure}://`+window.location.hostname + (srv.port === (goSecure ? 443 : 80) ? '' : ':'+srv.port)
33 - const errorMap = objSameKeys(status, v =>
35 + const serverStatus = _.pick(status, ['http', 'https'])
36 + const serverErrors = objSameKeys(serverStatus, v =>
37 v.busy ? [`port ${v.port} already used by ${v.busy}${SOLUTION_SEP}choose a `, cfgLink('different port'), ` or stop ${v.busy}`]
38 : v.error )
36 - const errors = errorMap && onlyTruthy(Object.entries(errorMap).map(([k,v]) =>
39 + const errors = serverErrors && onlyTruthy(Object.entries(serverErrors).map(([k,v]) =>
40 v && [md(`Protocol _${k}_ cannot work: `), v,
41 (isCertError(v) || isKeyError(v)) && [
42 SOLUTION_SEP, h(Link, { sx: { cursor: 'pointer' }, onClick() { makeCertAndSave().then(reloadCfg).then(reloadStatus) } }, "make one"),
@@ -48,7 +51,7 @@ export default function HomePage() {
51 : entry('', md("This is Admin-panel, where you manage your server. Access your files on "),
52 h(Link, { target:'frontend', href: '/' }, "Front-end", h(Launch, { sx: { verticalAlign: 'sub', ml: '.2em' } }))),
53 !href && entry('warning', "Frontend unreachable: ",
51 - ['http','https'].map(k => k + " " + (errorMap[k] ? "is in error" : "is off")).join(', '),
54 + _.map(serverErrors, (v,k) => k + " " + (v ? "is in error" : "is off")).join(', '),
55 !errors.length && [ SOLUTION_SEP, cfgLink("switch http or https on") ]
56 ),
57 plugins.find(x => x.badApi) && entry('warning', "Some plugins may be incompatible"),
shared/index.ts
+1 -1
@@ -52,7 +52,7 @@ export function getCookie(name: string) {
52 return ''
53 }
54
55 -export function objSameKeys<S extends object,VR=any>(src: S, newValue:(value:Truthy<S[keyof S]>, key:keyof S)=>any) {
55 +export function objSameKeys<S extends object,VR=any>(src: S, newValue:(value:Truthy<S[keyof S]>, key:keyof S)=>VR) {
56 return Object.fromEntries(Object.entries(src).map(([k,v]) => [k, newValue(v,k as keyof S)])) as { [K in keyof S]:VR }
57 }
58