@samitouri / QOSami-HFS / commits / 1fd8e979

admin/logs: show status code on tablets

Massimo Melina committed Jun 8, 2024 at 21:15 UTC 1fd8e979128979803c15ada8b732e7ead20653e9
5 files changed +31 -27
admin/src/DataTable.ts
+17 -11
@@ -6,6 +6,7 @@ import { createElement as h, Fragment, ReactNode, useEffect, useMemo, useRef, us
6 import { newDialog, onlyTruthy } from '@hfs/shared'
7 import _ from 'lodash'
8 import { Center, Flex, useBreakpoint } from './mui'
9 +import { SxProps } from '@mui/system'
10
11 const ACTIONS = 'Actions'
12
@@ -13,7 +14,8 @@ export type DataTableColumn<R extends GridValidRowModel=any> = GridColDef<R> & {
14 hidden?: boolean
15 hideUnder?: Breakpoint | number
16 dialogHidden?: boolean
16 - mergeRender?: { other: string, override?: Partial<GridColDef<R>> } & BoxProps
17 + sx?: SxProps
18 + mergeRender?: { [other: string]: false | { override?: Partial<GridColDef<R>> } & BoxProps }
19 }
20 interface DataTableProps<R extends GridValidRowModel=any> extends Omit<DataGridProps<R>, 'columns'> {
21 columns: Array<DataTableColumn<R>>
@@ -32,9 +34,9 @@ export function DataTable({ columns, initialState={}, actions, actionsProps, ini
34 const apiRef = useGridApiRef()
35 const [actionsLength, setActionsLength] = useState(0)
36 const manipulatedColumns = useMemo(() => {
35 - const { localeText } = enUS.components.MuiDataGrid.defaultProps
37 + const { localeText } = enUS.components.MuiDataGrid.defaultProps as any
38 const ret = columns.map(col => {
37 - const { type } = col
39 + const { type, sx } = col
40 if (!type || type === 'string') // offer negated version of default string operators
41 col.filterOperators ??= getGridStringOperators().flatMap(op => op.value.includes('Empty') ? op : [ // isEmpty already has isNotEmpty
42 op,
@@ -49,23 +51,27 @@ export function DataTable({ columns, initialState={}, actions, actionsProps, ini
51 const res = op.getApplyFilterFnV7?.(item, col)
52 return res ? _.negate(res) : null
53 } },
52 - label: "(not) " + ((localeText as any)['filterOperator' + _.upperFirst(op.value)] || op.value)
54 + label: "(not) " + (localeText['filterOperator' + _.upperFirst(op.value)] || op.value)
55 } satisfies typeof op
56 ])
55 - const { mergeRender } = col
56 - if (!mergeRender)
57 + if (!col.mergeRender)
58 return col
58 - const { other, override, ...props } = mergeRender
59 return {
60 ...col,
61 originalRenderCell: col.renderCell || true,
62 renderCell(params: any) {
63 const { columns } = params.api.store.getSnapshot()
64 - const showOther = columns.columnVisibilityModel[other] === false
65 - return h(Box, { maxHeight: '100%', sx: { textWrap: 'wrap' } }, // wrap if necessary, but stay within the row
64 + return h(Box, { maxHeight: '100%', sx: { textWrap: 'wrap', ...sx } }, // wrap if necessary, but stay within the row
65 col.renderCell ? col.renderCell(params) : params.formattedValue,
67 - showOther && h(Box, { ...compact && { lineHeight: '1em', fontSize: 'smaller' }, ...props },
68 - renderCell({ ...columns.lookup[other], ...override }, params.row) ) )
66 + h(Flex, { fontSize: 'smaller', flexWrap: 'wrap', mt: '2px' }, // wrap, normally causing overflow/hiding, if it doesn't fit
67 + ...onlyTruthy(_.map(col.mergeRender, (props, other) => {
68 + if (!props || columns.columnVisibilityModel[other] !== false) return null
69 + const { override, ...rest } = props
70 + const rendered = renderCell({ ...columns.lookup[other], ...override }, params.row)
71 + return rendered && h(Box, { ...rest, ...compact && { lineHeight: '1em' } }, rendered)
72 + }))
73 + )
74 + )
75 }
76 }
77 })
admin/src/InstalledPlugins.ts
+2 -2
@@ -38,7 +38,7 @@ export default function InstalledPlugins({ updates }: { updates?: true }) {
38 minWidth: 150,
39 renderCell: renderName,
40 valueGetter({ row }) { return row.repo || row.id },
41 - mergeRender: { other: 'description', fontSize: 'x-small' }
41 + mergeRender: { description: { fontSize: 'x-small' } }
42 },
43 {
44 field: 'version',
@@ -203,7 +203,7 @@ function UsernameField({ value, onChange, ...rest }: FieldProps<string>) {
203
204 export const descriptionField: DataTableColumn = {
205 field: 'description',
206 - mergeRender: { other: 'isTheme', sx: { float: 'left' } },
206 + mergeRender: { isTheme: { sx: { float: 'left' } }} ,
207 }
208
209 export const themeField: DataTableColumn = {
admin/src/LogsPage.ts
+9 -10
@@ -178,7 +178,7 @@ function LogFile({ file, addToFooter, hidden }: { hidden?: boolean, file: string
178 field: 'msg',
179 headerName: "Message",
180 flex: 1,
181 - mergeRender: { other: 'k', override: { valueFormatter: ({ value }) => value !== 'log' && value } }
181 + mergeRender: { k: { override: { valueFormatter: ({ value }) => value !== 'log' && value } } }
182 }
183 ] : file === 'ips' ? [
184 tsColumn,
@@ -200,14 +200,12 @@ function LogFile({ file, addToFooter, hidden }: { hidden?: boolean, file: string
200 field: 'ip',
201 headerName: "Address",
202 flex: .6,
203 - minWidth: 100,
203 + minWidth: 130,
204 maxWidth: 230,
205 mergeRender: {
206 - other: 'user',
207 - display: 'flex',
208 - justifyContent: 'space-between',
209 - gap: '.5em',
210 - override: { renderCell: ({ value, row }) => h(Fragment, {}, h('span', {}, value), h(Country, { code: row.extra?.country })) }
206 + user: { display: 'flex', justifyContent: 'space-between', gap: '.5em', },
207 + country: showCountry && {},
208 + ua: {},
209 },
210 },
211 {
@@ -268,7 +266,8 @@ function LogFile({ file, addToFooter, hidden }: { hidden?: boolean, file: string
266 headerName: "URI",
267 flex: 2,
268 minWidth: 100,
271 - mergeRender: { other: 'method', fontSize: 'small' },
269 + sx: { wordBreak: 'break-all' }, // be flexible, uri can be a mess
270 + mergeRender: { method: {}, status: {} },
271 renderCell: ({ value, row }) => {
272 const [path, query] = splitAt('?', value).map(decodeURIComponent)
273 const ul = row.extra?.ul
@@ -319,11 +318,11 @@ export function agentIcons(agent: string | undefined) {
318 win: UW + '0/0a/Unofficial_Windows_logo_variant_-_2002%E2%80%932012_%28Multicolored%29.svg',
319 apple: UW + '7/74/Apple_logo_dark_grey.svg', // grey works for both themes
320 })
322 - return hTooltip(agent, undefined, h('span', { fontSize: '18px' }, browserIcon || short, ' ', osIcon) )
321 + return hTooltip(agent, undefined, h('span', {}, browserIcon || short, ' ', osIcon) )
322
323 function icon(k: string, map: Dict<string>) {
324 const src = map[k]
326 - return src && h('img', { src, style: { height: '1em', verticalAlign: 'bottom', marginRight: '.2em' } })
325 + return src && h('img', { src, style: { height: '1.3em', verticalAlign: 'bottom', marginRight: '.2em' } })
326 }
327 }
328
admin/src/MonitorPage.ts
+2 -3
@@ -31,7 +31,6 @@ function MoreInfo() {
31 if (status && connections)
32 Object.assign(status, connections)
33 const [allInfo, setAllInfo] = useState(false)
34 - const lg = useBreakpoint('lg')
34 const md = useBreakpoint('md')
35 const sm = useBreakpoint('sm')
36 const formatDuration = createDurationFormatter({ maxTokens: 2, skipZeroes: true })
@@ -132,7 +131,7 @@ function Connections() {
131 flex: 1,
132 maxWidth: 400,
133 renderCell: ({ row, value }) => ipForUrl(value) + ' :' + row.port,
135 - mergeRender: { other: 'user', fontSize: 'small' },
134 + mergeRender: { user: { fontSize: 'small' } },
135 },
136 {
137 field: 'country',
@@ -184,7 +183,7 @@ function Connections() {
183 hideUnder: 'sm',
184 type: 'number',
185 renderCell: ({ value, row }) => formatSpeedK(Math.max(value||0, row.inSpeed||0) || undefined),
187 - mergeRender: { other: 'sent', fontSize: 'small', textAlign: 'right' }
186 + mergeRender: { sent: { fontSize: 'small', textAlign: 'right' }}
187 },
188 {
189 field: 'sent',
admin/src/OnlinePlugins.ts
+1 -1
@@ -40,7 +40,7 @@ export default function OnlinePlugins() {
40 headerName: "name",
41 flex: 1,
42 renderCell: renderName,
43 - mergeRender: { other: 'description', fontSize: 'x-small' },
43 + mergeRender: { description: { fontSize: 'x-small' } },
44 },
45 {
46 field: 'version',