better code

Massimo Melina committed Dec 7, 2023 at 17:55 UTC 110ac4c2dea7ff28f8ad25c5b8acd4edf9a6018f
8 files changed +30 -33
admin/src/InternetPage.ts
+1 -1
@@ -1,6 +1,6 @@
1 import { createElement as h, ReactNode, useEffect, useMemo, useState } from 'react'
2 import { Alert, Box, Button, Card, CardContent, CircularProgress, Divider, LinearProgress, Link } from '@mui/material'
3 -import { CardMembership, HomeWorkTwoTone, Lock, Public, PublicTwoTone, RestartAlt, RouterTwoTone, Send, Storage,
3 +import { CardMembership, HomeWorkTwoTone, Lock, Public, PublicTwoTone, RouterTwoTone, Send, Storage,
4 SvgIconComponent } from '@mui/icons-material'
5 import { apiCall, useApiEx } from './api'
6 import { closeDialog, DAY, formatTimestamp, wait, wantArray, with_ } from '@hfs/shared'
admin/src/OptionsPage.ts
+3 -3
@@ -95,8 +95,8 @@ export default function OptionsPage() {
95 return { sm: 6 }
96 },
97 fields: [
98 - { k: 'port', comp: ServerPort, md: 4, label:"HTTP port", status: status?.http||true, suggestedPort: 80 },
99 - { k: 'https_port', comp: ServerPort, md: 4, label: "HTTPS port", status: status?.https||true, suggestedPort: 443,
98 + { k: 'port', comp: PortField, md: 4, label:"HTTP port", status: status?.http||true, suggestedPort: 80 },
99 + { k: 'https_port', comp: PortField, md: 4, label: "HTTPS port", status: status?.https||true, suggestedPort: 443,
100 onChange(v: number) {
101 if (v >= 0 && !httpsEnabled && !values.cert)
102 suggestMakingCert().then()
@@ -265,7 +265,7 @@ export function isKeyError(error: any) {
265 return /private key/.test(error)
266 }
267
268 -function ServerPort({ label, value, onChange, setApi, status, suggestedPort=1, error, helperText }: FieldProps<number | null>) {
268 +function PortField({ label, value, onChange, setApi, status, suggestedPort=1, error, helperText }: FieldProps<number | null>) {
269 const lastCustom = useRef(suggestedPort)
270 if (value! > 0)
271 lastCustom.current = value!
admin/src/VfsMenuBar.ts
+9 -15
@@ -8,7 +8,6 @@ import addFiles, { addLink, addVirtual } from './addFiles'
8 import MenuButton from './MenuButton'
9 import { Btn, reloadBtn } from './misc'
10 import { apiCall, useApi } from './api'
11 -import { confirmDialog } from './dialog'
11
12 export default function VfsMenuBar({ status }: any) {
13 const { data: integrated, reload } = useApi(status?.platform === 'win32' && 'windows_integrated')
@@ -40,7 +39,15 @@ export default function VfsMenuBar({ status }: any) {
39 doneMessage: true,
40 ...(!integrated?.is ? {
41 children: "System integration",
43 - onClick: () => windowsIntegration().then(reload),
42 + onClick: () => apiCall('windows_integration').then(reload),
43 + confirm: h(Box, {}, "We are going to add a command in the right-click of Windows File Manager",
44 + h('img', { src: 'win-shell.png', style: {
45 + display: 'block',
46 + width: 'min(30em, 80vw)',
47 + marginTop: '1em',
48 + } }),
49 + h(Alert, { severity: 'info' }, "It will also automatically copy the URL, ready to paste!"),
50 + )
51 } : {
52 confirm: true,
53 children: "Remove integration",
@@ -49,16 +56,3 @@ export default function VfsMenuBar({ status }: any) {
56 }),
57 )
58 }
52 -
53 -async function windowsIntegration() {
54 - const msg = h(Box, {}, "We are going to add a command in the right-click of Windows File Manager",
55 - h('img', { src: 'win-shell.png', style: {
56 - display: 'block',
57 - width: 'min(30em, 80vw)',
58 - marginTop: '1em',
59 - } }),
60 - h(Alert, { severity: 'info' }, "It will also automatically copy the URL, ready to paste!"),
61 - )
62 - return await confirmDialog(msg)
63 - && apiCall('windows_integration')
64 -}
admin/src/mui.ts
+1 -1
@@ -130,7 +130,7 @@ interface BtnProps extends Omit<LoadingButtonProps,'disabled'|'title'|'onClick'>
130 disabled?: boolean | string
131 progress?: boolean | number
132 link?: string
133 - confirm?: boolean | string
133 + confirm?: boolean | ReactNode
134 labelFrom?: Breakpoint
135 doneMessage?: boolean | string // displayed only if the result of onClick !== false
136 tooltipProps?: TooltipProps
shared/api.ts
+11 -6
@@ -84,12 +84,15 @@ export function useApi<T=any>(cmd: string | Falsy, params?: object, options: Api
84 loadingRef.current?.abort()
85 setData(undefined)
86 setError(undefined)
87 - if (!cmd) return
87 let aborted = false
88 let req: undefined | ReturnType<typeof apiCall>
89 const wholePromise = wait(0) // postpone a bit, so that if it is aborted immediately, it is never really fired (happens mostly in dev mode)
91 - .then(() => aborted ? undefined : req = apiCall<T>(cmd, params, options))
92 - .then(res => aborted || setData(res), err => aborted || setError(err) || setData(undefined))
90 + .then(() => !cmd || aborted ? undefined : req = apiCall<T>(cmd, params, options))
91 + .then(res => aborted || setData(res), err => {
92 + if (aborted) return
93 + setError(err)
94 + setData(undefined)
95 + })
96 .finally(() => loadingRef.current = reloadingRef.current = undefined)
97 loadingRef.current = Object.assign(wholePromise, {
98 abort() {
@@ -99,9 +102,11 @@ export function useApi<T=any>(cmd: string | Falsy, params?: object, options: Api
102 })
103 reloadingRef.current?.resolve(wholePromise)
104 }, [cmd, JSON.stringify(params), forcer]) //eslint-disable-line -- json-ize to detect deep changes
102 - const reload = useCallback(() => loadingRef.current
103 - || setForcer(v => v+1) || (reloadingRef.current = pendingPromise()),
104 - [setForcer])
105 + const reload = useCallback(() => {
106 + if (loadingRef.current) return
107 + setForcer(v => v + 1)
108 + reloadingRef.current = pendingPromise()
109 + }, [setForcer])
110 return { data, setData, error, reload, loading: Boolean(loadingRef.current || reloadingRef.current) }
111 }
112
src/const.ts
+4
@@ -7,6 +7,10 @@ import { mkdirSync } from 'fs'
7 import { basename, dirname, join } from 'path'
8 export * from './cross-const'
9
10 +export const API_VERSION = 8.6
11 +export const COMPATIBLE_API_VERSION = 1 // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
12 +export const HFS_REPO = 'rejetto/hfs'
13 +
14 export const argv = minimist(process.argv.slice(2))
15 export const DEV = process.env.DEV || argv.dev ? 'DEV' : ''
16 export const ORIGINAL_CWD = process.cwd()
src/cross-const.ts
-6
@@ -1,9 +1,3 @@
1 -
2 -export const API_VERSION = 8.4
3 -export const COMPATIBLE_API_VERSION = 1 // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
4 -
5 -export const HFS_REPO = 'rejetto/hfs'
6 -
1 export const SPECIAL_URI = '/~/'
2 export const FRONTEND_URI = SPECIAL_URI + 'frontend/'
3 export const ADMIN_URI = SPECIAL_URI + 'admin/'
src/vfs.ts
+1 -1
@@ -154,7 +154,7 @@ export function getNodeName(node: VfsNode) {
154 if (!source)
155 return '' // should happen only for root
156 if (source === '/')
157 - return 'root'
157 + return 'root' // better name than
158 if (/^[a-zA-Z]:\\?$/.test(source))
159 return source.slice(0, 2) // exclude trailing slash
160 const base = basename(source)