@electerm/electerm-react 5.3.15 → 5.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +246 -12
- package/client/common/choose-save-folder.js +21 -2
- package/client/common/constants.js +23 -6
- package/client/common/create-title.jsx +6 -0
- package/client/common/default-setting.js +14 -0
- package/client/common/init-setting-item.js +5 -0
- package/client/common/platform.js +24 -0
- package/client/components/ai/agent-tool-call-card.jsx +10 -2
- package/client/components/ai/agent.js +4 -1
- package/client/components/ai/ai-attachments.js +87 -0
- package/client/components/ai/ai-chat-empty.jsx +43 -0
- package/client/components/ai/ai-chat-entry.jsx +13 -4
- package/client/components/ai/ai-chat-history-item.jsx +28 -4
- package/client/components/ai/ai-chat-history.jsx +2 -1
- package/client/components/ai/ai-chat.jsx +104 -13
- package/client/components/ai/ai-config-props.js +4 -130
- package/client/components/ai/ai-config.jsx +135 -15
- package/client/components/ai/ai-presets.js +173 -0
- package/client/components/ai/ai.styl +83 -0
- package/client/components/bg/css-overwrite.jsx +11 -0
- package/client/components/bookmark-form/bookmark-schema.js +4 -0
- package/client/components/bookmark-form/common/fields.jsx +3 -0
- package/client/components/bookmark-form/config/common-fields.js +12 -0
- package/client/components/bookmark-form/config/local.js +3 -2
- package/client/components/bookmark-form/config/serial.js +3 -2
- package/client/components/bookmark-form/config/ssh.js +2 -1
- package/client/components/bookmark-form/config/telnet.js +3 -2
- package/client/components/bookmark-form/index.jsx +10 -8
- package/client/components/common/item-filter.jsx +76 -0
- package/client/components/common/item-filter.styl +54 -0
- package/client/components/common/lazy-boundary.jsx +34 -0
- package/client/components/common/opacity.jsx +3 -1
- package/client/components/footer/footer-entry.jsx +35 -5
- package/client/components/footer/footer.styl +8 -1
- package/client/components/layout/layout.jsx +23 -31
- package/client/components/layout/pixed.js +3 -0
- package/client/components/main/main.jsx +80 -28
- package/client/components/main/term-fullscreen.styl +9 -3
- package/client/components/quick-commands/qm.styl +3 -2
- package/client/components/rdp/file-transfer.js +4 -4
- package/client/components/remote-monitor/monitor-details.jsx +458 -0
- package/client/components/remote-monitor/monitor-details.styl +87 -0
- package/client/components/remote-monitor/monitor-model.js +764 -0
- package/client/components/remote-monitor/remote-monitor-bar-entry.jsx +18 -0
- package/client/components/remote-monitor/remote-monitor-bar.jsx +344 -0
- package/client/components/remote-monitor/remote-monitor-bar.styl +106 -0
- package/client/components/remote-monitor/session-monitor.js +361 -0
- package/client/components/remote-monitor/use-monitor-details.js +10 -0
- package/client/components/remote-monitor/visibility.js +18 -0
- package/client/components/session/session-control.jsx +29 -2
- package/client/components/session/session.jsx +40 -18
- package/client/components/session/sessions.jsx +5 -2
- package/client/components/setting-panel/col.jsx +32 -6
- package/client/components/setting-panel/list.styl +12 -0
- package/client/components/setting-panel/setting-common.jsx +25 -56
- package/client/components/setting-panel/setting-mobile-breadcrumb.jsx +29 -0
- package/client/components/setting-panel/setting-modal.jsx +64 -44
- package/client/components/setting-panel/setting-terminal.jsx +7 -2
- package/client/components/setting-panel/setting-wrap.jsx +0 -3
- package/client/components/setting-panel/setting-wrap.styl +80 -11
- package/client/components/setting-panel/setting.styl +1 -1
- package/client/components/setting-panel/tab-triggers.jsx +71 -0
- package/client/components/sftp/file-compare-modal.jsx +6 -3
- package/client/components/sftp/file-item.jsx +5 -3
- package/client/components/sftp/owner-list.js +11 -2
- package/client/components/side-panel-r/side-panel-r.jsx +2 -2
- package/client/components/sidebar/index.jsx +28 -21
- package/client/components/sidebar/left-sidebar-icons.jsx +1 -1
- package/client/components/sidebar/sidebar.styl +16 -0
- package/client/components/sys-menu/menu-btn.jsx +30 -1
- package/client/components/tabs/index.jsx +2 -2
- package/client/components/tabs/tab-title.jsx +3 -2
- package/client/components/tabs/tab.jsx +5 -1
- package/client/components/tabs/tabs.styl +4 -0
- package/client/components/terminal/attach-addon-custom.js +295 -49
- package/client/components/terminal/automation/index.js +64 -0
- package/client/components/terminal/automation/keys.js +49 -0
- package/client/components/terminal/automation/stream-matcher.js +82 -0
- package/client/components/terminal/automation/strip-ansi.js +19 -0
- package/client/components/terminal/automation/trigger-engine.js +233 -0
- package/client/components/terminal/automation/trigger-presets.js +110 -0
- package/client/components/terminal/command-tracker-addon.js +31 -1
- package/client/components/terminal/mixins/index.js +27 -0
- package/client/components/terminal/mixins/term-attach.js +123 -0
- package/client/components/terminal/mixins/term-config.jsx +84 -0
- package/client/components/terminal/mixins/term-content.js +88 -0
- package/client/components/terminal/mixins/term-context-menu.jsx +291 -0
- package/client/components/terminal/mixins/term-file-drop.js +149 -0
- package/client/components/terminal/mixins/term-init.js +122 -0
- package/client/components/terminal/mixins/term-log.jsx +96 -0
- package/client/components/terminal/mixins/term-resize.js +87 -0
- package/client/components/terminal/mixins/term-socket.js +433 -0
- package/client/components/terminal/mixins/term-suggestions.js +224 -0
- package/client/components/terminal/mixins/term-theme.js +190 -0
- package/client/components/terminal/mixins/term-touch.js +136 -0
- package/client/components/terminal/shell-detect.js +37 -0
- package/client/components/terminal/shell.js +0 -28
- package/client/components/terminal/shortcut-bar-entry.jsx +32 -27
- package/client/components/terminal/shortcut-bar.jsx +4 -6
- package/client/components/terminal/shortcut-bar.styl +4 -0
- package/client/components/terminal/ssh-reload-state.js +56 -0
- package/client/components/terminal/startup-queue.js +379 -0
- package/client/components/terminal/terminal-interactive.jsx +32 -0
- package/client/components/terminal/terminal.jsx +102 -2007
- package/client/components/terminal/transfer-client-base.js +5 -29
- package/client/components/terminal/trzsz-client.js +1 -3
- package/client/components/terminal/xmodem-client.js +1 -3
- package/client/components/terminal/xterm-loader.js +7 -0
- package/client/components/terminal/zmodem-client.js +1 -3
- package/client/components/terminal-info/base.jsx +18 -70
- package/client/components/terminal-info/terminal-info-entry.jsx +13 -5
- package/client/components/terminal-info/terminal-info.jsx +50 -59
- package/client/components/terminal-info/terminal-info.styl +6 -49
- package/client/components/text-editor/open-text-editor.js +30 -0
- package/client/components/text-editor/text-editor-entry.jsx +17 -6
- package/client/components/text-editor/text-editor.jsx +14 -0
- package/client/components/theme/theme-form.jsx +22 -0
- package/client/components/tree-list/bookmark-transport.jsx +7 -31
- package/client/components/tree-list/tree-list.styl +13 -0
- package/client/components/triggers/trigger-editor.jsx +246 -0
- package/client/components/triggers/trigger-form.jsx +200 -0
- package/client/components/triggers/trigger-session-modal.jsx +199 -0
- package/client/components/triggers/trigger-setting-list.jsx +89 -0
- package/client/components/triggers/trigger-transport.jsx +60 -0
- package/client/components/triggers/triggers-field.jsx +19 -0
- package/client/components/widgets/widgets-list.jsx +11 -1
- package/client/css/mobile.styl +9 -1
- package/client/store/common.js +12 -1
- package/client/store/init-state.js +14 -0
- package/client/store/mcp-handler.js +158 -30
- package/client/store/setting.js +20 -0
- package/client/store/sidebar.js +12 -0
- package/client/store/store.js +2 -0
- package/client/store/sync.js +45 -9
- package/client/store/system-menu.js +2 -0
- package/client/store/tab.js +41 -3
- package/client/store/trigger.js +118 -0
- package/client/store/watch.js +13 -5
- package/client/views/index.pug +3 -0
- package/package.json +1 -1
- package/client/components/terminal-info/activity.jsx +0 -57
- package/client/components/terminal-info/data-cols-parser.jsx +0 -54
- package/client/components/terminal-info/disk.jsx +0 -45
- package/client/components/terminal-info/format-disks.js +0 -45
- package/client/components/terminal-info/network.jsx +0 -121
- package/client/components/terminal-info/resource.jsx +0 -99
- package/client/components/terminal-info/run-cmd.jsx +0 -263
- package/client/components/terminal-info/sys-info.jsx +0 -56
- package/client/components/terminal-info/up.jsx +0 -17
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* network info
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { Table } from 'antd'
|
|
6
|
-
import { isEmpty } from 'lodash-es'
|
|
7
|
-
import { useEffect, useState } from 'react'
|
|
8
|
-
import { filesize } from 'filesize'
|
|
9
|
-
import copy from 'json-deep-copy'
|
|
10
|
-
import { ApiOutlined } from '@ant-design/icons'
|
|
11
|
-
|
|
12
|
-
export default function TerminalInfoDisk (props) {
|
|
13
|
-
const { network, isRemote, terminalInfos } = props
|
|
14
|
-
if (isEmpty(network) || !isRemote || !terminalInfos.includes('network')) {
|
|
15
|
-
return null
|
|
16
|
-
}
|
|
17
|
-
const [state, setter] = useState({
|
|
18
|
-
network: props.network,
|
|
19
|
-
time: Date.now()
|
|
20
|
-
})
|
|
21
|
-
function setState (ext) {
|
|
22
|
-
setter(s => {
|
|
23
|
-
return Object.assign({}, s, ext)
|
|
24
|
-
})
|
|
25
|
-
}
|
|
26
|
-
function updateTraffic () {
|
|
27
|
-
const network = copy(props.network)
|
|
28
|
-
const keys = Object.keys(network)
|
|
29
|
-
const net = copy(state.network)
|
|
30
|
-
const now = Date.now()
|
|
31
|
-
const { time } = state
|
|
32
|
-
const diff = (now - time) / 1000
|
|
33
|
-
for (const k of keys) {
|
|
34
|
-
const p = network[k]
|
|
35
|
-
const pv = net[k]
|
|
36
|
-
if (
|
|
37
|
-
diff > 0 &&
|
|
38
|
-
p &&
|
|
39
|
-
pv &&
|
|
40
|
-
p.download &&
|
|
41
|
-
pv.download &&
|
|
42
|
-
p.download > pv.download
|
|
43
|
-
) {
|
|
44
|
-
p.down = Math.floor((p.download - pv.download) / diff)
|
|
45
|
-
}
|
|
46
|
-
if (
|
|
47
|
-
diff > 0 &&
|
|
48
|
-
p &&
|
|
49
|
-
pv &&
|
|
50
|
-
p.upload &&
|
|
51
|
-
pv.upload &&
|
|
52
|
-
p.upload > pv.upload
|
|
53
|
-
) {
|
|
54
|
-
p.up = Math.floor((p.upload - pv.upload) / diff)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
setState({
|
|
58
|
-
network,
|
|
59
|
-
time: now
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
updateTraffic()
|
|
64
|
-
}, [props.network])
|
|
65
|
-
if (isEmpty(state)) {
|
|
66
|
-
return null
|
|
67
|
-
}
|
|
68
|
-
const arr = Object.keys(state.network).map(k => {
|
|
69
|
-
return {
|
|
70
|
-
name: k,
|
|
71
|
-
...state.network[k]
|
|
72
|
-
}
|
|
73
|
-
}).sort((a, b) => {
|
|
74
|
-
const ai = a.name.startsWith('eth') ? 100 : 10
|
|
75
|
-
const bi = b.name.startsWith('eth') ? 100 : 10
|
|
76
|
-
if (ai !== bi) {
|
|
77
|
-
return bi - ai
|
|
78
|
-
}
|
|
79
|
-
return a.name > b.name ? 1 : -1
|
|
80
|
-
})
|
|
81
|
-
const map = {
|
|
82
|
-
up: '↑',
|
|
83
|
-
down: '↓',
|
|
84
|
-
name: 'name',
|
|
85
|
-
ip: 'ipv4'
|
|
86
|
-
}
|
|
87
|
-
const col = ['name', 'ip', 'up', 'down'].map((k, i) => {
|
|
88
|
-
return {
|
|
89
|
-
title: map[k],
|
|
90
|
-
dataIndex: k,
|
|
91
|
-
key: k,
|
|
92
|
-
sorter: (a, b) => {
|
|
93
|
-
return a[k] > b[k] ? 1 : -1
|
|
94
|
-
},
|
|
95
|
-
render: (v) => {
|
|
96
|
-
if (k === 'up' || k === 'down') {
|
|
97
|
-
return filesize(Number.isFinite(v) ? v : 0)
|
|
98
|
-
}
|
|
99
|
-
return v
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
const ps = {
|
|
104
|
-
rowKey: 'name',
|
|
105
|
-
dataSource: arr,
|
|
106
|
-
bordered: true,
|
|
107
|
-
size: 'small',
|
|
108
|
-
columns: col,
|
|
109
|
-
pagination: false,
|
|
110
|
-
scroll: {
|
|
111
|
-
y: 180,
|
|
112
|
-
x: 'max-content'
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return (
|
|
116
|
-
<div className='terminal-info-section terminal-info-network'>
|
|
117
|
-
<div className='pd1y bold'><ApiOutlined /> Network</div>
|
|
118
|
-
<Table {...ps} />
|
|
119
|
-
</div>
|
|
120
|
-
)
|
|
121
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* cpu/swap/mem general usage
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { isEmpty } from 'lodash-es'
|
|
6
|
-
import { Progress } from 'antd'
|
|
7
|
-
import parseInt10 from '../../common/parse-int10'
|
|
8
|
-
|
|
9
|
-
function toNumber (n = '') {
|
|
10
|
-
let f = 1
|
|
11
|
-
if (n.includes('G')) {
|
|
12
|
-
f = 1024 * 1024
|
|
13
|
-
} else if (n.includes('T')) {
|
|
14
|
-
f = 1024 * 1024 * 1024
|
|
15
|
-
} else if (n.includes('M')) {
|
|
16
|
-
f = 1024
|
|
17
|
-
}
|
|
18
|
-
return f * parseFloat(n)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function computePercent (used, total) {
|
|
22
|
-
const u = toNumber(used)
|
|
23
|
-
const t = toNumber(total)
|
|
24
|
-
return Math.floor(u * 100 / (t || (u + 1)))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default function TerminalInfoResource (props) {
|
|
28
|
-
const { cpu, mem, swap, isRemote, terminalInfos } = props
|
|
29
|
-
if (
|
|
30
|
-
!isRemote ||
|
|
31
|
-
(!terminalInfos.includes('cpu') &&
|
|
32
|
-
!terminalInfos.includes('mem') &&
|
|
33
|
-
!terminalInfos.includes('swap'))
|
|
34
|
-
) {
|
|
35
|
-
return null
|
|
36
|
-
}
|
|
37
|
-
function getColorForPercent (percent) {
|
|
38
|
-
if (percent >= 90) return '#ff4d4f'
|
|
39
|
-
if (percent >= 70) return '#faad14'
|
|
40
|
-
if (percent >= 50) return '#1890ff'
|
|
41
|
-
return '#52c41a'
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function renderItem (obj) {
|
|
45
|
-
if (isEmpty(obj)) {
|
|
46
|
-
return <div className='pd1b' key={obj.name}>NA</div>
|
|
47
|
-
}
|
|
48
|
-
const {
|
|
49
|
-
used,
|
|
50
|
-
total,
|
|
51
|
-
percent,
|
|
52
|
-
name
|
|
53
|
-
} = obj
|
|
54
|
-
const hasPercent = Number.isFinite(percent)
|
|
55
|
-
const p = hasPercent
|
|
56
|
-
? percent
|
|
57
|
-
: computePercent(used, total) || 0
|
|
58
|
-
const color = getColorForPercent(p)
|
|
59
|
-
const fmt = hasPercent
|
|
60
|
-
? (p) => `${name}: ${p || ''}%`
|
|
61
|
-
: (p) => `${name}: ${p || ''}%(${used || ''}/${total || ''})`
|
|
62
|
-
return (
|
|
63
|
-
<div className='pd1b' key={name}>
|
|
64
|
-
<Progress
|
|
65
|
-
style={{ width: '50%' }}
|
|
66
|
-
percent={p}
|
|
67
|
-
format={fmt}
|
|
68
|
-
strokeColor={color}
|
|
69
|
-
/>
|
|
70
|
-
</div>
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
const data = []
|
|
74
|
-
if (terminalInfos.includes('cpu')) {
|
|
75
|
-
data.push({
|
|
76
|
-
name: 'cpu',
|
|
77
|
-
percent: parseInt10(cpu) || 0
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
if (terminalInfos.includes('mem')) {
|
|
81
|
-
data.push({
|
|
82
|
-
name: 'mem',
|
|
83
|
-
...mem
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
if (terminalInfos.includes('swap')) {
|
|
87
|
-
data.push({
|
|
88
|
-
name: 'swap',
|
|
89
|
-
...swap
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
return (
|
|
93
|
-
<div className='terminal-info-section terminal-info-resource'>
|
|
94
|
-
{
|
|
95
|
-
data.map(renderItem)
|
|
96
|
-
}
|
|
97
|
-
</div>
|
|
98
|
-
)
|
|
99
|
-
}
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* run command in remote terminal
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { runCmd } from '../terminal/terminal-apis'
|
|
6
|
-
import { useEffect } from 'react'
|
|
7
|
-
import wait from '../../common/wait'
|
|
8
|
-
import parseInt10 from '../../common/parse-int10'
|
|
9
|
-
import formatDisks from './format-disks'
|
|
10
|
-
|
|
11
|
-
function formatActivities (str) {
|
|
12
|
-
if (!str) {
|
|
13
|
-
return {
|
|
14
|
-
activities: []
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
const r = str.split('\n')
|
|
18
|
-
.map(a => a.trim())
|
|
19
|
-
.filter(s => s)
|
|
20
|
-
.map(st => {
|
|
21
|
-
const arr = st.split(/ +/)
|
|
22
|
-
return {
|
|
23
|
-
pid: arr[0],
|
|
24
|
-
user: arr[1],
|
|
25
|
-
cpu: parseFloat(arr[2]),
|
|
26
|
-
mem: parseInt10(arr[3]),
|
|
27
|
-
cmd: arr.slice(4).join(' ')
|
|
28
|
-
}
|
|
29
|
-
}).filter(d => d.pid)
|
|
30
|
-
return {
|
|
31
|
-
activities: r
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function formatSysInfo (unameStr, prettyName) {
|
|
36
|
-
if (!unameStr) {
|
|
37
|
-
return {}
|
|
38
|
-
}
|
|
39
|
-
const parts = unameStr.trim().split(/\s+/)
|
|
40
|
-
if (parts.length < 4) {
|
|
41
|
-
return {}
|
|
42
|
-
}
|
|
43
|
-
const [sysname, hostname, kernel, arch] = parts
|
|
44
|
-
let os = sysname
|
|
45
|
-
const m = (prettyName || '').match(/PRETTY_NAME="?([^"\r\n]+)"?/)
|
|
46
|
-
if (m) {
|
|
47
|
-
os = m[1].trim()
|
|
48
|
-
} else if (sysname === 'Darwin') {
|
|
49
|
-
os = 'macOS'
|
|
50
|
-
}
|
|
51
|
-
return {
|
|
52
|
-
sysInfo: {
|
|
53
|
-
os,
|
|
54
|
-
sysname,
|
|
55
|
-
hostname,
|
|
56
|
-
kernel,
|
|
57
|
-
arch
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function formatCpu (str) {
|
|
63
|
-
if (!str) {
|
|
64
|
-
return {
|
|
65
|
-
cpu: ''
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return {
|
|
69
|
-
cpu: str.split(' ')[1]
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function formatMem (str) {
|
|
74
|
-
if (!str) {
|
|
75
|
-
return {}
|
|
76
|
-
}
|
|
77
|
-
const names = ['mem', 'swap']
|
|
78
|
-
return str
|
|
79
|
-
.split('\n')
|
|
80
|
-
.filter(d => d)
|
|
81
|
-
.slice(1)
|
|
82
|
-
.reduce((p, d, i) => {
|
|
83
|
-
const arr = d.split(/\s+/)
|
|
84
|
-
if (!arr[1]) {
|
|
85
|
-
return p
|
|
86
|
-
}
|
|
87
|
-
p[names[i]] = {
|
|
88
|
-
total: arr[1],
|
|
89
|
-
used: arr[2],
|
|
90
|
-
free: arr[3]
|
|
91
|
-
}
|
|
92
|
-
return p
|
|
93
|
-
}, {})
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const ipSplitReg = /\n[\d]{1,5}:\s+/
|
|
97
|
-
const ipNameReg = /inet\s+([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3})\/\d/
|
|
98
|
-
|
|
99
|
-
function formatIps (ips) {
|
|
100
|
-
if (!ips) {
|
|
101
|
-
return {}
|
|
102
|
-
}
|
|
103
|
-
const arr = ips.split(ipSplitReg)
|
|
104
|
-
return arr.reduce((p, s) => {
|
|
105
|
-
const name = s.replace(/^[\d]{1,5}:\s+/, '').split(/:\s+/)[0]
|
|
106
|
-
const arr1 = s.match(ipNameReg)
|
|
107
|
-
return {
|
|
108
|
-
...p,
|
|
109
|
-
[name]: {
|
|
110
|
-
ip: arr1 ? arr1[1] : ''
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}, {})
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function formatTraffic (traffic, ipObj) {
|
|
117
|
-
if (!traffic) {
|
|
118
|
-
return ipObj
|
|
119
|
-
}
|
|
120
|
-
const arr = traffic.split(ipSplitReg)
|
|
121
|
-
return arr.reduce((p, s) => {
|
|
122
|
-
const name = s.replace(/^[\d]{1,5}:\s+/, '').split(/:\s+/)[0]
|
|
123
|
-
const arr1 = s.split('\n')
|
|
124
|
-
let download = 0
|
|
125
|
-
let upload = 0
|
|
126
|
-
const len = arr1.length
|
|
127
|
-
for (let i = 0; i < len; i++) {
|
|
128
|
-
const line = arr1[i]
|
|
129
|
-
if (line.toLowerCase().trim().startsWith('rx')) {
|
|
130
|
-
download = Number(arr1[i + 1].trim().split(/\s+/)[0])
|
|
131
|
-
} else if (line.trim().toLowerCase().startsWith('tx')) {
|
|
132
|
-
upload = Number(arr1[i + 1].trim().split(/\s+/)[0])
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (!p[name]) {
|
|
136
|
-
p[name] = {}
|
|
137
|
-
}
|
|
138
|
-
Object.assign(p[name], {
|
|
139
|
-
download, upload
|
|
140
|
-
})
|
|
141
|
-
return p
|
|
142
|
-
}, ipObj)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function formatNetwork (traffic, ips) {
|
|
146
|
-
const ipObj = formatIps(ips)
|
|
147
|
-
return {
|
|
148
|
-
network: formatTraffic(traffic, ipObj)
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export async function runCmds (props, cmds) {
|
|
153
|
-
const {
|
|
154
|
-
pid
|
|
155
|
-
} = props
|
|
156
|
-
const ress = []
|
|
157
|
-
for (const cmd of cmds) {
|
|
158
|
-
const res = await runCmd(pid, cmd)
|
|
159
|
-
ress.push(res || '')
|
|
160
|
-
}
|
|
161
|
-
return ress
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function InfoGetter (props) {
|
|
165
|
-
const {
|
|
166
|
-
// name,
|
|
167
|
-
cmd,
|
|
168
|
-
cmds,
|
|
169
|
-
interval,
|
|
170
|
-
formatter,
|
|
171
|
-
delay
|
|
172
|
-
} = props.options
|
|
173
|
-
const { pid } = props
|
|
174
|
-
const cms = cmds || [cmd]
|
|
175
|
-
useEffect(() => {
|
|
176
|
-
const run = async () => {
|
|
177
|
-
await wait(delay)
|
|
178
|
-
const ress = await runCmds(props, cms)
|
|
179
|
-
const update = formatter(...ress)
|
|
180
|
-
props.setState(update)
|
|
181
|
-
}
|
|
182
|
-
run()
|
|
183
|
-
if (interval > 0) {
|
|
184
|
-
const ref = setInterval(run, interval)
|
|
185
|
-
return () => {
|
|
186
|
-
clearInterval(ref)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}, [pid])
|
|
190
|
-
return null
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export default (props) => {
|
|
194
|
-
if (!props.isRemote) {
|
|
195
|
-
return null
|
|
196
|
-
}
|
|
197
|
-
const cmds = [
|
|
198
|
-
{
|
|
199
|
-
name: 'sysinfo',
|
|
200
|
-
cmds: [
|
|
201
|
-
'uname -s -n -r -m',
|
|
202
|
-
'grep PRETTY_NAME= /etc/os-release 2>/dev/null || echo'
|
|
203
|
-
],
|
|
204
|
-
interval: 0,
|
|
205
|
-
delay: 0,
|
|
206
|
-
formatter: formatSysInfo
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
name: 'uptime',
|
|
210
|
-
cmd: 'uptime -p',
|
|
211
|
-
interval: 5000,
|
|
212
|
-
delay: 0,
|
|
213
|
-
formatter: d => ({ uptime: d })
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
name: 'activities',
|
|
217
|
-
cmd: 'ps --no-headers -o pid,user,%cpu,size,command ax | sort -b -k3 -r',
|
|
218
|
-
interval: 5000,
|
|
219
|
-
delay: 800,
|
|
220
|
-
formatter: formatActivities
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
name: 'disks',
|
|
224
|
-
cmd: 'df -hP',
|
|
225
|
-
interval: 10000,
|
|
226
|
-
delay: 1600,
|
|
227
|
-
formatter: formatDisks
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
name: 'cpu',
|
|
231
|
-
cmd: '(grep \'cpu \' /proc/stat;sleep 0.1;grep \'cpu \' /proc/stat)|awk -v RS="" \'{print "CPU "($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5)"%"}\'',
|
|
232
|
-
interval: 5000,
|
|
233
|
-
formatter: formatCpu,
|
|
234
|
-
delay: 2400
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
name: 'mem',
|
|
238
|
-
cmd: 'free -h',
|
|
239
|
-
interval: 5000,
|
|
240
|
-
delay: 3200,
|
|
241
|
-
formatter: formatMem
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
name: 'network',
|
|
245
|
-
cmds: [
|
|
246
|
-
'ip -s link',
|
|
247
|
-
'ip addr'
|
|
248
|
-
],
|
|
249
|
-
delay: 4000,
|
|
250
|
-
formatter: formatNetwork,
|
|
251
|
-
interval: 5000
|
|
252
|
-
}
|
|
253
|
-
]
|
|
254
|
-
return cmds.map(options => {
|
|
255
|
-
return (
|
|
256
|
-
<InfoGetter
|
|
257
|
-
key={'info-getter-' + options.name}
|
|
258
|
-
{...props}
|
|
259
|
-
options={options}
|
|
260
|
-
/>
|
|
261
|
-
)
|
|
262
|
-
})
|
|
263
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* system info: os / hostname / kernel / arch (+ shell for local terminals)
|
|
3
|
-
* remote info comes from uname via the session runCmd bridge,
|
|
4
|
-
* local info from the os module + a shell version probe
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { useEffect, useState } from 'react'
|
|
8
|
-
import { DesktopOutlined } from '@ant-design/icons'
|
|
9
|
-
import resolveLocalInfo from './local-info-resolver'
|
|
10
|
-
|
|
11
|
-
export default function TerminalInfoSys (props) {
|
|
12
|
-
const { sysInfo, isRemote, pid } = props
|
|
13
|
-
const [localInfo, setLocalInfo] = useState(null)
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
if (isRemote) {
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
resolveLocalInfo(pid).then(setLocalInfo)
|
|
20
|
-
}, [isRemote, pid])
|
|
21
|
-
|
|
22
|
-
const info = isRemote ? sysInfo : localInfo
|
|
23
|
-
if (!info || !info.os) {
|
|
24
|
-
return null
|
|
25
|
-
}
|
|
26
|
-
const rows = [
|
|
27
|
-
['os', info.os],
|
|
28
|
-
['hostname', info.hostname],
|
|
29
|
-
['kernel', info.kernel],
|
|
30
|
-
['arch', info.arch]
|
|
31
|
-
]
|
|
32
|
-
if (info.shell) {
|
|
33
|
-
rows.push(['shell', info.shellVersion ? `${info.shell} ${info.shellVersion}` : info.shell])
|
|
34
|
-
}
|
|
35
|
-
const final = rows.filter(d => d[1])
|
|
36
|
-
if (!final.length) {
|
|
37
|
-
return null
|
|
38
|
-
}
|
|
39
|
-
return (
|
|
40
|
-
<div className='terminal-info-section terminal-info-sys'>
|
|
41
|
-
<div className='pd1y bold'><DesktopOutlined /> System</div>
|
|
42
|
-
<div className='terminal-info-sys-rows'>
|
|
43
|
-
{
|
|
44
|
-
final.map(([k, v]) => {
|
|
45
|
-
return (
|
|
46
|
-
<div className='terminal-info-sys-row' key={k}>
|
|
47
|
-
<span className='terminal-info-sys-key'>{k}</span>
|
|
48
|
-
<span className='terminal-info-sys-val' title={v}>{v}</span>
|
|
49
|
-
</div>
|
|
50
|
-
)
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* up time info
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { ClockCircleOutlined } from '@ant-design/icons'
|
|
6
|
-
|
|
7
|
-
export default function TerminalInfoUp (props) {
|
|
8
|
-
const { uptime, isRemote, terminalInfos } = props
|
|
9
|
-
if (!isRemote || !terminalInfos.includes('uptime')) {
|
|
10
|
-
return null
|
|
11
|
-
}
|
|
12
|
-
return (
|
|
13
|
-
<div className='terminal-info-section terminal-info-up'>
|
|
14
|
-
<b><ClockCircleOutlined /> uptime</b>: {uptime}
|
|
15
|
-
</div>
|
|
16
|
-
)
|
|
17
|
-
}
|