admin/monitor: added path column

Massimo Melina committed Mar 9, 2022 at 22:18 UTC fd1b751e92803df897e41705318e1db8e6cbcd53
5 files changed +43 -27
admin/src/MonitorPage.ts
+29 -19
@@ -3,8 +3,8 @@
3 import _ from "lodash"
4 import { isValidElement, createElement as h, useMemo, Fragment } from "react"
5 import { apiCall, useApiComp, useApiList } from "./api"
6 -import { Delete, Lock, Refresh } from '@mui/icons-material'
7 -import { Box, Grid, Typography } from '@mui/material'
6 +import { Delete, Lock } from '@mui/icons-material'
7 +import { Box, Chip, Typography } from '@mui/material'
8 import { DataGrid } from "@mui/x-data-grid"
9 import { Alert } from '@mui/material'
10 import { formatBytes, IconBtn, iconTooltip } from "./misc"
@@ -12,14 +12,10 @@ import { alertDialog } from "./dialog"
12 import { prefix } from './misc'
13
14 export default function MonitorPage() {
15 - return h(Box, { flex: 1, display: 'flex', flexDirection: 'column' },
16 - h(Grid, { container: true, flex: 1 },
17 - h(Grid, { item: true, md: 3, lg: 4, xl: 6 },
18 - h(MoreInfo) ),
19 - h(Grid, { item: true, md: 9, lg: 8, xl: 6, width: '100%', display: 'flex', flexDirection: 'column' },
20 - h(SectionTitle, {}, "Active connections"),
21 - h(Connections))
22 - )
15 + return h(Fragment, {},
16 + h(MoreInfo),
17 + h(SectionTitle, {}, "Active connections"),
18 + h(Connections),
19 )
20 }
21
@@ -30,11 +26,10 @@ function SectionTitle(props: object) {
26 }
27
28 function MoreInfo() {
33 - const [res, reload] = useApiComp('get_status')
34 - return h(Box, {},
35 - h(SectionTitle, {}, "Status", h(IconBtn, { sx: { ml: 2 }, icon: Refresh, onClick: reload })),
29 + const [res] = useApiComp('get_status')
30 + return h(Fragment, {},
31 isValidElement(res) ? res :
37 - h('ul', {},
32 + h(Box, { display: 'flex', flexWrap: 'wrap', gap: '1em', mb: 1 },
33 pair('started'),
34 pair('version'),
35 pair('build'),
@@ -53,7 +48,10 @@ function MoreInfo() {
48 v = render(v)
49 if (!label)
50 label = _.capitalize(k.replaceAll('_', ' '))
56 - return h('li', {}, label + ': ' + v)
51 + return h(Chip, {
52 + variant: 'filled',
53 + label: h(Fragment, {}, h('b',{},label), ': ', v),
54 + })
55 }
56 }
57
@@ -64,6 +62,7 @@ function Connections() {
62 return h(Alert, { severity: 'error' }, error)
63 return h(DataGrid, {
64 pageSize: 25,
65 + rows,
66 columns: [
67 {
68 field: 'ip',
@@ -75,15 +74,16 @@ function Connections() {
74 field: 'v',
75 headerName: 'Protocol',
76 align: 'center',
77 + hide: true,
78 renderCell: ({ value, row }) => h(Fragment, {},
79 'IPv' + value,
80 - row.secure && iconTooltip(Lock, "HTTPS", { opacity:.5 })
80 + row.secure && iconTooltip(Lock, "HTTPS", { opacity: .5 })
81 )
82 },
83 {
84 field: 'outSpeed',
85 headerName: 'Speed',
86 - valueGetter: ({ value }) => formatBytes(value*1000, 'B/s', 1000)
86 + valueGetter: ({ value }) => formatBytes(value * 1000, 'B/s', 1000)
87 },
88 {
89 field: 'sent',
@@ -95,6 +95,17 @@ function Connections() {
95 headerName: 'Started',
96 valueGetter: ({ value }) => new Date(value).toLocaleTimeString()
97 },
98 + {
99 + field: 'path',
100 + headerName: 'Path',
101 + flex: 1,
102 + renderCell: ({ value }) => {
103 + if (!value) return
104 + const i = value?.lastIndexOf('/')
105 + return h(Fragment, {}, value.slice(i + 1),
106 + i > 0 && h(Box, { ml: 2, color: 'text.secondary' }, value.slice(0, i)))
107 + }
108 + },
109 {
110 field: 'Actions ',
111 width: 80,
@@ -109,7 +120,6 @@ function Connections() {
120 })
121 }
122 }
112 - ],
113 - rows,
123 + ]
124 })
125 }
server/src/adminApis.ts
+8 -6
@@ -74,16 +74,18 @@ export const adminApis: ApiHandlers = {
74 ) )
75
76 function serializeConnection(conn: Connection, minimal?:true) {
77 - const { socket, started, secure, got } = conn
77 + const { socket, started, secure, got, path } = conn
78 return {
79 - v: minimal ? undefined : (socket.remoteFamily?.endsWith('6') ? 6 : 4),
79 port: socket.remotePort,
80 ip: socket.remoteAddress,
82 - got: minimal ? undefined : got,
83 - started: minimal ? undefined : started,
84 - secure: minimal ? undefined : (secure || undefined), // undefined will save some space once json-ed
81 + ...!minimal && {
82 + v: (socket.remoteFamily?.endsWith('6') ? 6 : 4),
83 + got,
84 + started,
85 + path,
86 + secure: (secure || undefined), // undefined will save some space once json-ed
87 + }
88 }
86 -
89 }
90 }
91
server/src/connections.ts
+2 -1
@@ -10,7 +10,8 @@ export interface Connection {
10 got: number
11 sent: number
12 outSpeed?: number
13 - [rest:symbol]: any, // let other modules add extra data, but using symbols to avoid name collision
13 + path?: string
14 + [rest:symbol]: any // let other modules add extra data, but using symbols to avoid name collision
15 }
16
17 const all: Connection[] = []
server/src/serveFile.ts
+4
@@ -11,6 +11,7 @@ import mm, { isMatch } from 'micromatch'
11 import _ from 'lodash'
12 import path from 'path'
13 import { promisify } from 'util'
14 +import { socket2connection, updateConnection } from './connections'
15
16 export function serveFileNode(node: VfsNode) : Koa.Middleware {
17 const { source, mime } = node
@@ -52,6 +53,9 @@ export function serveFile(source:string, mime?:string, modifier?:(s:string)=>str
53 if (ctx.fresh)
54 return ctx.status = 304
55
56 + const conn = socket2connection(ctx.socket)
57 + if (conn)
58 + updateConnection(conn, { path: ctx.path })
59 if (modifier)
60 return ctx.body = modifier(String(await fs.readFile(source)))
61 if (!range) {
todo.md
-1
@@ -5,7 +5,6 @@
5 - merge accounts in config
6 - frontend: ok button to inputDialogs
7 - admin: in a group, show linked accounts
8 -- admin/monitor: show file currently downloaded
8 - admin/config: use filepicker for https files
9 - admin: warn in case of items with same name
10 - allowed referer