better code: prepare md to be shared with frontend

Massimo Melina committed Mar 20, 2024 at 15:30 UTC 023f7c5e802c11396f67484a8561d8b3b43271e8
13 files changed +24 -32
admin/src/AccountsPage.ts
+1 -2
@@ -4,12 +4,11 @@ import { createElement as h, useState, useEffect, Fragment } from "react"
4 import { apiCall, useApiEx } from './api'
5 import { Alert, Box, Card, CardContent, Grid, List, ListItem, ListItemText, Typography } from '@mui/material'
6 import { Close, Delete, DoNotDisturb, Group, MilitaryTech, Person, PersonAdd, Schedule } from '@mui/icons-material'
7 -import { newDialog, with_ } from './misc'
7 +import { newDialog, with_, md } from './misc'
8 import { Btn, Flex, IconBtn, iconTooltip, reloadBtn, useBreakpoint } from './mui'
9 import { TreeItem, TreeView } from '@mui/x-tree-view'
10 import MenuButton from './MenuButton'
11 import AccountForm from './AccountForm'
12 -import md from './md'
12 import _ from 'lodash'
13 import { alertDialog, confirmDialog } from './dialog'
14 import { useSnapState } from './state'
admin/src/CustomHtmlPage.ts
+1 -2
@@ -4,12 +4,11 @@ import { createElement as h, Fragment, useEffect, useMemo, useState } from 'reac
4 import { Field, SelectField } from '@hfs/mui-grid-form'
5 import { apiCall, useApiEx } from './api'
6 import { Alert, Box } from '@mui/material'
7 -import { Dict, HTTP_MESSAGES, isCtrlKey, prefix } from './misc';
7 +import { Dict, HTTP_MESSAGES, isCtrlKey, prefix, md } from './misc';
8 import { IconBtn, reloadBtn, wikiLink } from './mui';
9 import { Save } from '@mui/icons-material'
10 import _ from 'lodash'
11 import { useDebounce } from 'usehooks-ts'
12 -import md from './md'
12 import { TextEditor } from './TextEditor';
13
14 const names: any = {
admin/src/FileForm.ts
+1 -2
@@ -7,10 +7,9 @@ import { BoolField, DisplayField, Field, FieldProps, Form, MultiSelectField, Sel
7 } from '@hfs/mui-grid-form'
8 import { apiCall, UseApi, useApiEx } from './api'
9 import { basename, defaultPerms, formatBytes, formatTimestamp, isEqualLax, isWhoObject, newDialog, objSameKeys,
10 - onlyTruthy, prefix, VfsPerms, wantArray, Who, WhoObject, matches, HTTP_MESSAGES, xlate } from './misc'
10 + onlyTruthy, prefix, VfsPerms, wantArray, Who, WhoObject, matches, HTTP_MESSAGES, xlate, md } from './misc'
11 import { Btn, IconBtn, LinkBtn, modifiedProps, useBreakpoint, wikiLink } from './mui'
12 import { reloadVfs, VfsNode } from './VfsPage'
13 -import md from './md'
13 import _ from 'lodash'
14 import FileField from './FileField'
15 import { alertDialog, toast, useDialogBarColors } from './dialog'
admin/src/HomePage.ts
+5 -8
@@ -3,11 +3,10 @@
3 import { createElement as h, ReactNode, useState } from 'react'
4 import { Box, Card, CardContent, LinearProgress, Link } from '@mui/material'
5 import { apiCall, useApiEx, useApiList } from './api'
6 -import { dontBotherWithKeys, objSameKeys, onlyTruthy, prefix, REPO_URL,
7 - wait, with_ } from './misc'
6 +import { dontBotherWithKeys, objSameKeys, onlyTruthy, prefix, REPO_URL, md,
7 + replaceStringToReact, wait, with_ } from './misc'
8 import { Btn, Flex, InLink, LinkBtn, wikiLink, } from './mui'
9 import { BrowserUpdated as UpdateIcon, CheckCircle, Error, Info, Launch, OpenInNew, Warning } from '@mui/icons-material'
10 -import md, { replaceStringToReact } from './md'
10 import { state, useSnapState } from './state'
11 import { alertDialog, confirmDialog, promptDialog, toast } from './dialog'
12 import { isCertError, isKeyError, suggestMakingCert } from './OptionsPage'
@@ -132,12 +131,10 @@ export default function HomePage() {
131 }
132
133 function renderChangelog(s: string) {
135 - return md(s, { onText })
136 -
137 - function onText(s: string) {
138 - return replaceStringToReact(s, /(?<=^|\W)#(\d+)\b/g, m => // link issues
134 + return md(s, {
135 + onText: s => replaceStringToReact(s, /(?<=^|\W)#(\d+)\b/g, m => // link issues
136 h(Link, { href: REPO_URL + 'issues/' + m[1], target: '_blank' }, h(OpenInNew) ))
140 - }
137 + })
138 }
139
140 async function update(tag?: string) {
admin/src/InternetPage.ts
+1 -2
@@ -3,12 +3,11 @@ import { Alert, Box, Button, Card, CardContent, CircularProgress, Divider, Linea
3 import { CardMembership, Check, Dns, HomeWorkTwoTone, Lock, Public, PublicTwoTone, RouterTwoTone, Send, Storage,
4 Error as ErrorIcon, SvgIconComponent } from '@mui/icons-material'
5 import { apiCall, useApiEvents, useApiEx } from './api'
6 -import { closeDialog, DAY, formatTimestamp, wait, wantArray, with_, PORT_DISABLED, isIP, CFG,
6 +import { closeDialog, DAY, formatTimestamp, wait, wantArray, with_, PORT_DISABLED, isIP, CFG, md,
7 useRequestRender, replace, restartAnimation, prefix } from './misc'
8 import { Flex, LinkBtn, Btn, Country } from './mui'
9 import { alertDialog, confirmDialog, formDialog, promptDialog, toast, waitDialog } from './dialog'
10 import { BoolField, Form, MultiSelectField, NumberField, SelectField } from '@hfs/mui-grid-form'
11 -import md from './md'
11 import { suggestMakingCert } from './OptionsPage'
12 import { changeBaseUrl } from './FileForm'
13 import { getNatInfo } from '../../src/nat'
admin/src/LogsPage.ts
+1 -2
@@ -4,7 +4,7 @@ import { createElement as h, Fragment, ReactNode, useMemo, useState } from 'reac
4 import { Box, Tab, Tabs } from '@mui/material'
5 import { API_URL, useApi, useApiList } from './api'
6 import { DataTable } from './DataTable'
7 -import { CFG, Dict, formatBytes, HTTP_UNAUTHORIZED, newDialog, prefix, shortenAgent, splitAt, tryJson,
7 +import { CFG, Dict, formatBytes, HTTP_UNAUTHORIZED, newDialog, prefix, shortenAgent, splitAt, tryJson, md,
8 typedKeys, NBSP, _dbg, mapFilter } from '@hfs/shared'
9 import { logLabels } from './OptionsPage'
10 import {
@@ -14,7 +14,6 @@ import {
14 import { GridColDef } from '@mui/x-data-grid'
15 import _ from 'lodash'
16 import { ClearAll, Download, Settings, SmartToy } from '@mui/icons-material'
17 -import md from './md'
17 import { ConfigForm } from './ConfigForm'
18 import { BoolField, SelectField } from '@hfs/mui-grid-form'
19 import { toast, useDialogBarColors } from './dialog'
admin/src/MainMenu.ts
+1 -2
@@ -17,10 +17,9 @@ import LogoutPage from './LogoutPage';
17 import LangPage from './LangPage'
18 import LogsPage from './LogsPage';
19 import PluginsPage from './PluginsPage';
20 -import { getHFS } from '@hfs/shared'
20 +import { getHFS, replaceStringToReact } from '@hfs/shared'
21 import CustomHtmlPage from './CustomHtmlPage';
22 import InternetPage from './InternetPage'
23 -import { replaceStringToReact } from './md'
23 import { useWindowSize } from 'usehooks-ts'
24 import { hTooltip } from './mui'
25
admin/src/MonitorPage.ts
+1 -2
@@ -7,9 +7,8 @@ import { LinkOff, Lock, Block, FolderZip, Upload, Download, ChevronRight, Chevro
7 import { Box, Chip, ChipProps } from '@mui/material'
8 import { DataTable } from './DataTable'
9 import { formatBytes, ipForUrl, manipulateConfig, CFG, formatSpeed, with_, createDurationFormatter, formatTimestamp,
10 - formatPerc } from "./misc"
10 + formatPerc, md } from "./misc"
11 import { IconBtn, IconProgress, iconTooltip, usePauseButton, useBreakpoint, Country, hTooltip } from './mui'
12 -import md from './md'
12 import { Field, SelectField } from '@hfs/mui-grid-form'
13 import { StandardCSSProperties } from '@mui/system/styleFunctionSx/StandardCssProperties'
14 import { agentIcons } from './LogsPage'
admin/src/OptionsPage.ts
+1 -2
@@ -7,7 +7,7 @@ import { state, useSnapState } from './state'
7 import { Link as RouterLink } from 'react-router-dom'
8 import { CardMembership, EditNote, Refresh, Warning } from '@mui/icons-material'
9 import { Dict, MAX_TILE_SIZE, REPO_URL, isIpLocalHost, wait, with_, try_, ipForUrl, SORT_BY_OPTIONS, THEME_OPTIONS,
10 - CFG } from './misc'
10 + CFG, md } from './misc'
11 import { iconTooltip, InLink, LinkBtn, modifiedProps, wikiLink, useBreakpoint, NetmaskField, WildcardsSupported } from './mui'
12 import { Form, BoolField, NumberField, SelectField, FieldProps, Field, StringField } from '@hfs/mui-grid-form';
13 import { ArrayField } from './ArrayField'
@@ -16,7 +16,6 @@ import { alertDialog, confirmDialog, newDialog, toast, waitDialog } from './dial
16 import { proxyWarning } from './HomePage'
17 import _ from 'lodash';
18 import { proxy, subscribe, useSnapshot } from 'valtio'
19 -import md from './md'
19 import { TextEditorField } from './TextEditor'
20
21 let loaded: Dict | undefined
admin/src/dialog.ts
+1 -2
@@ -7,12 +7,11 @@ import { createElement as h, Dispatch, Fragment, isValidElement, ReactElement, R
7 } from 'react'
8 import { Check, Close, Error as ErrorIcon, Forward, Info, Warning } from '@mui/icons-material'
9 import { newDialog, closeDialog, dialogsDefaults, DialogOptions, componentOrNode, pendingPromise,
10 - focusSelector } from '@hfs/shared'
10 + focusSelector, md } from '@hfs/shared'
11 import { Form, FormProps } from '@hfs/mui-grid-form'
12 import { IconBtn, Flex, Center } from './mui'
13 import { useDark } from './theme'
14 import { useWindowSize } from 'usehooks-ts'
15 -import md from './md'
15 import _ from 'lodash'
16 import { err2msg } from './misc'
17 export * from '@hfs/shared/dialogs'
admin/src/misc.ts
+4 -1
@@ -1,9 +1,12 @@
1 // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3 import { apiCall } from './api'
4 -import { HTTP_MESSAGES } from '@hfs/shared'
4 +import { HTTP_MESSAGES, MD_TAGS } from '@hfs/shared'
5 +import { Link } from '@mui/material'
6 export * from '@hfs/shared'
7
8 +;(MD_TAGS as any).a = Link
9 +
10 export async function manipulateConfig(k: string, work:(data:any) => any) {
11 const cfg = await apiCall('get_config', { only: [k] })
12 const was = cfg[k]
shared/index.ts
+1
@@ -5,6 +5,7 @@ import { apiCall } from './api'
5 import { DAY, HOUR, MINUTE, objSameKeys, typedEntries } from '../src/cross'
6 export * from './react'
7 export * from './dialogs'
8 +export * from './md'
9 export * from '../src/srp'
10 export * from '../src/cross'
11
shared/md.ts renamed
+5 -5
@@ -1,21 +1,21 @@
1 // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3 import { createElement as h, Fragment, ReactNode } from 'react'
4 -import { Link } from '@mui/material'
4
6 -const TAGS = {
5 +export const MD_TAGS = {
6 + a: 'a',
7 '`': 'code',
8 '*': 'i',
9 '**': 'b',
10 }
11 type OnText = (s: string) => ReactNode
12 -export default function md(text: string | TemplateStringsArray, { linkTarget='_blank', onText=(x=>x) as OnText }={}) {
12 +export function md(text: string | TemplateStringsArray, { linkTarget='_blank', onText=(x=>x) as OnText }={}) {
13 if (typeof text !== 'string')
14 text = text[0]
15 return replaceStringToReact(text, /(`|_|\*\*?)(.+?)\1|(\n)|\[(.+?)\]\((.+?)\)|<([^ >/]+)>(.*?)<\/\6>|<([^ >/]+) *\/>/g, m =>
16 - m[4] ? h(Link, { href: m[5], target: linkTarget }, onText(m[4]))
16 + m[4] ? h(MD_TAGS.a, { href: m[5], target: linkTarget }, onText(m[4]))
17 : m[3] ? h('br')
18 - : m[1] ? h((TAGS as any)[ m[1] ] || Fragment, {}, onText(m[2]))
18 + : m[1] ? h((MD_TAGS as any)[ m[1] ] || Fragment, {}, onText(m[2]))
19 : h(m[6] || m[8], {}, m[7]),
20 onText)
21 }