@electerm/electerm-react 5.3.26 → 5.5.9
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 +20 -6
- package/client/common/create-title.jsx +6 -0
- package/client/common/default-setting.js +15 -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/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/cmd-history.jsx +132 -45
- package/client/components/footer/cmd-history.styl +42 -4
- package/client/components/footer/footer-entry.jsx +35 -5
- package/client/components/footer/footer.styl +8 -1
- package/client/components/footer/multi-tab-run-modal.jsx +83 -0
- package/client/components/footer/tab-select.jsx +34 -17
- package/client/components/layout/layout.jsx +23 -31
- package/client/components/layout/pixed.js +3 -0
- package/client/components/main/main.jsx +55 -28
- package/client/components/main/term-fullscreen.styl +9 -3
- package/client/components/quick-commands/qm.styl +3 -2
- package/client/components/quick-commands/quick-command-create-modal.jsx +60 -0
- package/client/components/quick-commands/quick-commands-form-elem.jsx +10 -4
- 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/setting-common.jsx +25 -56
- package/client/components/setting-panel/setting-modal.jsx +57 -42
- package/client/components/setting-panel/setting-terminal.jsx +8 -2
- 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/sftp/sftp-entry.jsx +4 -0
- package/client/components/side-panel-r/side-panel-r.jsx +2 -2
- package/client/components/sidebar/side-panel.jsx +1 -1
- 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/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 +126 -0
- package/client/components/terminal/mixins/term-context-menu.jsx +323 -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 +523 -0
- package/client/components/terminal/shell-detect.js +37 -0
- package/client/components/terminal/shell.js +0 -28
- package/client/components/terminal/shortcut-bar-defs.js +30 -4
- package/client/components/terminal/shortcut-bar-edit.jsx +40 -9
- package/client/components/terminal/shortcut-bar-entry.jsx +6 -3
- package/client/components/terminal/shortcut-bar.jsx +17 -10
- package/client/components/terminal/shortcut-bar.styl +4 -0
- package/client/components/terminal/ssh-reload-state.js +96 -0
- package/client/components/terminal/startup-queue.js +433 -0
- package/client/components/terminal/terminal-interactive.jsx +32 -0
- package/client/components/terminal/terminal-select-text.jsx +69 -0
- package/client/components/terminal/terminal.jsx +227 -2064
- package/client/components/terminal/terminal.styl +61 -0
- 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/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 +29 -8
- package/client/store/common.js +12 -1
- package/client/store/init-state.js +7 -0
- package/client/store/mcp-handler.js +158 -30
- package/client/store/setting.js +9 -0
- package/client/store/store.js +2 -0
- package/client/store/sync.js +2 -0
- package/client/store/tab.js +42 -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
|
@@ -53,6 +53,67 @@
|
|
|
53
53
|
background-position center
|
|
54
54
|
background-color transparent !important
|
|
55
55
|
|
|
56
|
+
// Full-screen plain-text view of the buffer, opened from the touch context
|
|
57
|
+
// menu (see terminal-select-text.jsx) so the platform's own selection handles
|
|
58
|
+
// and Copy callout can be used instead of xterm's canvas.
|
|
59
|
+
//
|
|
60
|
+
// 900 clears the touch shortcut bar (400) and the terminal panes, while
|
|
61
|
+
// staying below antd's modal (1000) and message (1010) layers so a "copied"
|
|
62
|
+
// toast still shows up over this panel.
|
|
63
|
+
//
|
|
64
|
+
// The callout/user-select resets are load-bearing, not decoration: the
|
|
65
|
+
// component is portalled onto <body>, but `.term-wrap` switches off
|
|
66
|
+
// -webkit-touch-callout for the terminal's own gestures and the property is
|
|
67
|
+
// inherited — if this panel is ever rendered in place again, without the
|
|
68
|
+
// resets the native Copy callout would never appear on the textarea.
|
|
69
|
+
.terminal-select-text
|
|
70
|
+
position fixed
|
|
71
|
+
left 0
|
|
72
|
+
top 0
|
|
73
|
+
width 100%
|
|
74
|
+
height 100%
|
|
75
|
+
z-index 900
|
|
76
|
+
display flex
|
|
77
|
+
flex-direction column
|
|
78
|
+
background var(--main)
|
|
79
|
+
color var(--text)
|
|
80
|
+
-webkit-touch-callout default
|
|
81
|
+
-webkit-user-select text
|
|
82
|
+
user-select text
|
|
83
|
+
|
|
84
|
+
.terminal-select-text-bar
|
|
85
|
+
flex-shrink 0
|
|
86
|
+
display flex
|
|
87
|
+
align-items center
|
|
88
|
+
justify-content space-between
|
|
89
|
+
height 40px
|
|
90
|
+
padding 0 10px
|
|
91
|
+
font-size 14px
|
|
92
|
+
background var(--main-lighter)
|
|
93
|
+
.terminal-select-text-btns
|
|
94
|
+
a
|
|
95
|
+
margin-left 16px
|
|
96
|
+
color var(--text)
|
|
97
|
+
&:hover
|
|
98
|
+
color var(--text-light)
|
|
99
|
+
|
|
100
|
+
.terminal-select-text-area
|
|
101
|
+
flex 1
|
|
102
|
+
width 100%
|
|
103
|
+
margin 0
|
|
104
|
+
padding 8px 10px
|
|
105
|
+
border 0
|
|
106
|
+
outline none
|
|
107
|
+
resize none
|
|
108
|
+
background var(--main)
|
|
109
|
+
color var(--text)
|
|
110
|
+
font-family monospace
|
|
111
|
+
font-size 13px
|
|
112
|
+
line-height 1.4
|
|
113
|
+
-webkit-touch-callout default
|
|
114
|
+
-webkit-user-select text
|
|
115
|
+
user-select text
|
|
116
|
+
|
|
56
117
|
.terminal-normal-buffer
|
|
57
118
|
position absolute
|
|
58
119
|
left 0
|
|
@@ -4,16 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// import { transferTypeMap } from '../../common/constants.js'
|
|
7
|
-
import {
|
|
7
|
+
import { chooseSaveDirectory } from '../../common/choose-save-folder.js'
|
|
8
8
|
import { getLocalFileInfo } from '../sftp/file-read.js'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* TransferClientBase class - abstract base for file transfer protocols
|
|
12
12
|
*/
|
|
13
13
|
export class TransferClientBase {
|
|
14
|
-
constructor (terminal
|
|
14
|
+
constructor (terminal) {
|
|
15
15
|
this.terminal = terminal
|
|
16
|
-
this.storageKey = storageKey
|
|
17
16
|
this.socket = null
|
|
18
17
|
this.isActive = false
|
|
19
18
|
this.currentTransfer = null
|
|
@@ -233,38 +232,15 @@ export class TransferClientBase {
|
|
|
233
232
|
if (window._apiControlSelectFolder) {
|
|
234
233
|
const folder = window._apiControlSelectFolder
|
|
235
234
|
delete window._apiControlSelectFolder
|
|
236
|
-
if (this.storageKey) {
|
|
237
|
-
setItem(this.storageKey, folder)
|
|
238
|
-
}
|
|
239
235
|
return folder
|
|
240
236
|
}
|
|
241
237
|
|
|
242
|
-
//
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
const savePaths = await window.api.openDialog({
|
|
246
|
-
title: 'Choose a folder to save file(s)',
|
|
247
|
-
message: 'Choose a folder to save file(s)',
|
|
248
|
-
defaultPath: lastPath || undefined,
|
|
249
|
-
properties: [
|
|
250
|
-
'openDirectory',
|
|
251
|
-
'showHiddenFiles',
|
|
252
|
-
'createDirectory',
|
|
253
|
-
'noResolveAliases',
|
|
254
|
-
'treatPackageAsDirectory',
|
|
255
|
-
'dontAddToRecent'
|
|
256
|
-
],
|
|
238
|
+
// Last saved path is remembered by chooseSaveDirectory in localStorage
|
|
239
|
+
const savePath = await chooseSaveDirectory({
|
|
257
240
|
noBrowserTransfer: true
|
|
258
241
|
}).catch(() => false)
|
|
259
242
|
|
|
260
|
-
|
|
261
|
-
return null
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (this.storageKey) {
|
|
265
|
-
setItem(this.storageKey, savePaths[0])
|
|
266
|
-
}
|
|
267
|
-
return savePaths[0]
|
|
243
|
+
return savePath || null
|
|
268
244
|
}
|
|
269
245
|
|
|
270
246
|
/**
|
|
@@ -8,14 +8,12 @@ import { filesize } from 'filesize'
|
|
|
8
8
|
import { TransferClientBase } from './transfer-client-base.js'
|
|
9
9
|
import { transferTypeMap } from '../../common/constants.js'
|
|
10
10
|
|
|
11
|
-
const TRZSZ_SAVE_PATH_KEY = 'trzsz-save-path'
|
|
12
|
-
|
|
13
11
|
/**
|
|
14
12
|
* TrzszClient class handles trzsz UI and client-side logic
|
|
15
13
|
*/
|
|
16
14
|
export class TrzszClient extends TransferClientBase {
|
|
17
15
|
constructor (terminal) {
|
|
18
|
-
super(terminal
|
|
16
|
+
super(terminal)
|
|
19
17
|
this.transferStartTime = 0
|
|
20
18
|
this.totalTransferred = 0
|
|
21
19
|
this.totalSpeed = 0
|
|
@@ -9,14 +9,12 @@ import { filesize } from 'filesize'
|
|
|
9
9
|
import { TransferClientBase } from './transfer-client-base.js'
|
|
10
10
|
import { transferTypeMap } from '../../common/constants.js'
|
|
11
11
|
|
|
12
|
-
const XMODEM_SAVE_PATH_KEY = 'xmodem-save-path'
|
|
13
|
-
|
|
14
12
|
/**
|
|
15
13
|
* XmodemClient class handles XMODEM UI and client-side logic
|
|
16
14
|
*/
|
|
17
15
|
export class XmodemClient extends TransferClientBase {
|
|
18
16
|
constructor (terminal) {
|
|
19
|
-
super(terminal
|
|
17
|
+
super(terminal)
|
|
20
18
|
this.transferStartTime = 0
|
|
21
19
|
this.pendingMode = null // 'send' or 'receive' - waiting for user action
|
|
22
20
|
}
|
|
@@ -72,6 +72,13 @@ export async function loadImageAddon () {
|
|
|
72
72
|
return window.xtermAddons.ImageAddon
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
export async function loadSerializeAddon () {
|
|
76
|
+
if (window.xtermAddons.SerializeAddon) return window.xtermAddons.SerializeAddon
|
|
77
|
+
const mod = await import('@xterm/addon-serialize')
|
|
78
|
+
window.xtermAddons.SerializeAddon = mod.SerializeAddon
|
|
79
|
+
return window.xtermAddons.SerializeAddon
|
|
80
|
+
}
|
|
81
|
+
|
|
75
82
|
export function getTerminal () {
|
|
76
83
|
return window.xtermAddons.Terminal
|
|
77
84
|
}
|
|
@@ -8,14 +8,12 @@ import { filesize } from 'filesize'
|
|
|
8
8
|
import { TransferClientBase } from './transfer-client-base.js'
|
|
9
9
|
import { transferTypeMap } from '../../common/constants.js'
|
|
10
10
|
|
|
11
|
-
const ZMODEM_SAVE_PATH_KEY = 'zmodem-save-path'
|
|
12
|
-
|
|
13
11
|
/**
|
|
14
12
|
* ZmodemClient class handles zmodem UI and client-side logic
|
|
15
13
|
*/
|
|
16
14
|
export class ZmodemClient extends TransferClientBase {
|
|
17
15
|
constructor (terminal) {
|
|
18
|
-
super(terminal
|
|
16
|
+
super(terminal)
|
|
19
17
|
this.transferStartTime = 0
|
|
20
18
|
}
|
|
21
19
|
|
|
@@ -2,23 +2,10 @@
|
|
|
2
2
|
* show base terminal info, id sessionID
|
|
3
3
|
*/
|
|
4
4
|
import { Component } from 'react'
|
|
5
|
-
import
|
|
6
|
-
Button,
|
|
7
|
-
Dropdown
|
|
8
|
-
} from 'antd'
|
|
5
|
+
import ItemFilter from '../common/item-filter'
|
|
9
6
|
import SwitchLabel from '../common/switch'
|
|
10
|
-
import
|
|
7
|
+
import { INFO_PANEL_ITEM_IDS } from '../remote-monitor/monitor-model'
|
|
11
8
|
import { toggleTerminalLog, toggleTerminalLogTimestamp } from '../terminal/terminal-apis'
|
|
12
|
-
import {
|
|
13
|
-
ClockCircleOutlined,
|
|
14
|
-
BorderlessTableOutlined,
|
|
15
|
-
DatabaseOutlined,
|
|
16
|
-
BarsOutlined,
|
|
17
|
-
ApiOutlined,
|
|
18
|
-
PartitionOutlined,
|
|
19
|
-
FilterOutlined,
|
|
20
|
-
CheckOutlined
|
|
21
|
-
} from '@ant-design/icons'
|
|
22
9
|
import { refs } from '../common/ref'
|
|
23
10
|
import ShowItem from '../common/show-item'
|
|
24
11
|
import { osResolve } from '../../common/resolve'
|
|
@@ -26,15 +13,6 @@ import createDefaultLogPath from '../../common/default-log-path'
|
|
|
26
13
|
|
|
27
14
|
const e = window.translate
|
|
28
15
|
|
|
29
|
-
const mapper = {
|
|
30
|
-
uptime: <ClockCircleOutlined />,
|
|
31
|
-
cpu: <BorderlessTableOutlined />,
|
|
32
|
-
mem: <DatabaseOutlined />,
|
|
33
|
-
activities: <BarsOutlined />,
|
|
34
|
-
network: <ApiOutlined />,
|
|
35
|
-
disks: <PartitionOutlined />
|
|
36
|
-
}
|
|
37
|
-
|
|
38
16
|
export default class TerminalInfoBase extends Component {
|
|
39
17
|
state = {
|
|
40
18
|
saveTerminalLogToFile: false,
|
|
@@ -73,14 +51,14 @@ export default class TerminalInfoBase extends Component {
|
|
|
73
51
|
})
|
|
74
52
|
}
|
|
75
53
|
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
54
|
+
handleToggleInfo = (id) => {
|
|
55
|
+
const selected = new Set(this.props.terminalInfos || [])
|
|
56
|
+
if (selected.has(id)) {
|
|
57
|
+
selected.delete(id)
|
|
58
|
+
} else {
|
|
59
|
+
selected.add(id)
|
|
60
|
+
}
|
|
61
|
+
window.store.setTerminalInfos(INFO_PANEL_ITEM_IDS.filter(x => selected.has(x)))
|
|
84
62
|
}
|
|
85
63
|
|
|
86
64
|
handleToggle = () => {
|
|
@@ -134,43 +112,13 @@ export default class TerminalInfoBase extends Component {
|
|
|
134
112
|
)
|
|
135
113
|
}
|
|
136
114
|
|
|
137
|
-
|
|
138
|
-
const {
|
|
139
|
-
terminalInfos
|
|
140
|
-
} = this.props
|
|
141
|
-
const items = defaults.terminalInfos.map(f => {
|
|
142
|
-
const checked = terminalInfos.includes(f)
|
|
143
|
-
return {
|
|
144
|
-
key: f,
|
|
145
|
-
label: (
|
|
146
|
-
<span
|
|
147
|
-
className='term-info-filter-label'
|
|
148
|
-
style={{
|
|
149
|
-
display: 'flex',
|
|
150
|
-
alignItems: 'center',
|
|
151
|
-
gap: '6px'
|
|
152
|
-
}}
|
|
153
|
-
>
|
|
154
|
-
<span style={{ width: '14px' }}>{checked ? <CheckOutlined /> : null}</span>
|
|
155
|
-
{mapper[f]} {f}
|
|
156
|
-
</span>
|
|
157
|
-
),
|
|
158
|
-
onClick: () => this.toggleTerminalLogInfo(f)
|
|
159
|
-
}
|
|
160
|
-
})
|
|
115
|
+
renderInfoFilter () {
|
|
161
116
|
return (
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
<Button
|
|
168
|
-
size='small'
|
|
169
|
-
icon={<FilterOutlined />}
|
|
170
|
-
>
|
|
171
|
-
{e('filter')}({terminalInfos.length}/{defaults.terminalInfos.length})
|
|
172
|
-
</Button>
|
|
173
|
-
</Dropdown>
|
|
117
|
+
<ItemFilter
|
|
118
|
+
ids={INFO_PANEL_ITEM_IDS}
|
|
119
|
+
onToggle={this.handleToggleInfo}
|
|
120
|
+
selected={this.props.terminalInfos || []}
|
|
121
|
+
/>
|
|
174
122
|
)
|
|
175
123
|
}
|
|
176
124
|
|
|
@@ -209,9 +157,9 @@ export default class TerminalInfoBase extends Component {
|
|
|
209
157
|
)
|
|
210
158
|
: null
|
|
211
159
|
}
|
|
212
|
-
<div className='
|
|
160
|
+
<div className='terminal-info-filter-wrap'>
|
|
213
161
|
{
|
|
214
|
-
this.
|
|
162
|
+
this.renderInfoFilter()
|
|
215
163
|
}
|
|
216
164
|
</div>
|
|
217
165
|
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { lazy, Suspense } from 'react'
|
|
2
|
+
import { auto } from 'manate/react'
|
|
3
|
+
import { getRemoteMonitorTab } from '../remote-monitor/visibility'
|
|
4
|
+
import LazyBoundary from '../common/lazy-boundary'
|
|
2
5
|
|
|
3
6
|
const TerminalInfo = lazy(() => import('./terminal-info'))
|
|
4
7
|
|
|
5
|
-
export default function TerminalInfoEntry (props) {
|
|
8
|
+
export default auto(function TerminalInfoEntry (props) {
|
|
9
|
+
const tab = getRemoteMonitorTab(props.store)
|
|
10
|
+
if (props.store.rightPanelTab !== 'info' || props.pid !== tab?.id) return null
|
|
11
|
+
|
|
6
12
|
return (
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
13
|
+
<LazyBoundary>
|
|
14
|
+
<Suspense fallback={null}>
|
|
15
|
+
<TerminalInfo {...props} />
|
|
16
|
+
</Suspense>
|
|
17
|
+
</LazyBoundary>
|
|
10
18
|
)
|
|
11
|
-
}
|
|
19
|
+
})
|
|
@@ -1,65 +1,56 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { PureComponent } from 'react'
|
|
1
|
+
import { auto } from 'manate/react'
|
|
2
|
+
import { useEffect, useState } from 'react'
|
|
6
3
|
import TerminalInfoBase from './base'
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import RunCmd from './run-cmd'
|
|
4
|
+
import MonitorDetails from '../remote-monitor/monitor-details'
|
|
5
|
+
import { getInfoPanelItems } from '../remote-monitor/monitor-model'
|
|
6
|
+
import { useMonitorDetails } from '../remote-monitor/use-monitor-details'
|
|
7
|
+
import { createEmptyMonitorSnapshot } from '../remote-monitor/session-monitor'
|
|
8
|
+
import { getRemoteMonitorTab } from '../remote-monitor/visibility'
|
|
9
|
+
import { statusMap } from '../../common/constants'
|
|
14
10
|
import { runCmd } from '../terminal/terminal-apis'
|
|
11
|
+
import resolveLocalInfo from './local-info-resolver'
|
|
15
12
|
import './terminal-info.styl'
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
setStateRef = (...args) => {
|
|
30
|
-
this.setState(...args)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
killProcess = async (id) => {
|
|
34
|
-
const {
|
|
35
|
-
pid
|
|
36
|
-
} = this.props
|
|
37
|
-
const cmd = `kill ${id}`
|
|
38
|
-
runCmd(pid, cmd)
|
|
39
|
-
}
|
|
14
|
+
function LocalSystemInfo ({ pid }) {
|
|
15
|
+
const [info, setInfo] = useState(null)
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let active = true
|
|
18
|
+
resolveLocalInfo(pid).then(info => { if (active) setInfo(info) })
|
|
19
|
+
return () => { active = false }
|
|
20
|
+
}, [pid])
|
|
21
|
+
if (!info) return null
|
|
22
|
+
const snapshot = createEmptyMonitorSnapshot(pid)
|
|
23
|
+
snapshot.groups.sysinfo = { status: 'ready', data: info }
|
|
24
|
+
return <MonitorDetails id='hostname' snapshot={snapshot} config={{}} tab={{}} />
|
|
25
|
+
}
|
|
40
26
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{...state}
|
|
57
|
-
killProcess={this.killProcess}
|
|
58
|
-
/>
|
|
59
|
-
<TerminalInfoNetwork {...props} {...state} />
|
|
60
|
-
<TerminalInfoDisk {...props} {...state} />
|
|
61
|
-
<RunCmd {...props} setState={this.setStateRef} />
|
|
62
|
-
</>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
27
|
+
function RemoteInfo ({ tab, config }) {
|
|
28
|
+
const items = getInfoPanelItems(config.terminalInfos)
|
|
29
|
+
const { snapshot, levels } = useMonitorDetails(tab.id, items, tab.status === statusMap.success)
|
|
30
|
+
return items.map(id => (
|
|
31
|
+
<MonitorDetails
|
|
32
|
+
key={id}
|
|
33
|
+
id={id}
|
|
34
|
+
snapshot={snapshot}
|
|
35
|
+
levels={levels}
|
|
36
|
+
tab={tab}
|
|
37
|
+
config={config}
|
|
38
|
+
includeActivity={false}
|
|
39
|
+
onKillProcess={pid => runCmd(tab.id, `kill ${pid}`)}
|
|
40
|
+
/>
|
|
41
|
+
))
|
|
65
42
|
}
|
|
43
|
+
|
|
44
|
+
export default auto(function TerminalInfo ({ store, ...props }) {
|
|
45
|
+
const tab = getRemoteMonitorTab(store)
|
|
46
|
+
if (store.rightPanelTab !== 'info' || props.pid !== tab?.id) return null
|
|
47
|
+
const config = store.config
|
|
48
|
+
return (
|
|
49
|
+
<>
|
|
50
|
+
<TerminalInfoBase {...props} terminalInfos={config.terminalInfos} />
|
|
51
|
+
{props.isRemote
|
|
52
|
+
? <RemoteInfo key={tab.id} tab={tab} config={config} />
|
|
53
|
+
: <LocalSystemInfo key={tab.id} pid={tab.id} />}
|
|
54
|
+
</>
|
|
55
|
+
)
|
|
56
|
+
})
|
|
@@ -2,53 +2,10 @@
|
|
|
2
2
|
color var(--text-dark)
|
|
3
3
|
&:hover
|
|
4
4
|
color var(--text)
|
|
5
|
-
.info-
|
|
6
|
-
|
|
7
|
-
right 0
|
|
8
|
-
top 100px
|
|
9
|
-
bottom 0
|
|
10
|
-
width 500px
|
|
11
|
-
background var(--main)
|
|
12
|
-
border 1px solid var(--main-darker)
|
|
13
|
-
border-radius 5px 0 0 5px
|
|
14
|
-
border-right none
|
|
15
|
-
color var(--text)
|
|
16
|
-
z-index 100
|
|
17
|
-
overflow-y scroll
|
|
18
|
-
|
|
19
|
-
.drag-handle
|
|
20
|
-
left 0
|
|
21
|
-
right auto
|
|
22
|
-
display block
|
|
23
|
-
.terminal-info-section
|
|
5
|
+
.terminal-info-section,
|
|
6
|
+
.right-side-panel-content > .remote-monitor-details
|
|
24
7
|
padding 10px 0
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
flex-direction column
|
|
30
|
-
gap 4px
|
|
31
|
-
.terminal-info-sys-row
|
|
32
|
-
display flex
|
|
33
|
-
gap 8px
|
|
34
|
-
align-items baseline
|
|
35
|
-
font-size 12px
|
|
36
|
-
.terminal-info-sys-key
|
|
37
|
-
flex none
|
|
38
|
-
width 80px
|
|
39
|
-
color var(--text-dark)
|
|
40
|
-
text-transform capitalize
|
|
41
|
-
.terminal-info-sys-val
|
|
42
|
-
flex 1
|
|
43
|
-
overflow hidden
|
|
44
|
-
text-overflow ellipsis
|
|
45
|
-
white-space nowrap
|
|
46
|
-
.activity-item
|
|
47
|
-
max-height 1.6em
|
|
48
|
-
line-height 1.6
|
|
49
|
-
overflow hidden
|
|
50
|
-
&:hover
|
|
51
|
-
max-height none
|
|
52
|
-
.info-panel-wrap-pin
|
|
53
|
-
.toggle-info-panel-wrap
|
|
54
|
-
color var(--success)
|
|
8
|
+
|
|
9
|
+
.terminal-info-filter-wrap
|
|
10
|
+
display flex
|
|
11
|
+
justify-content flex-end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* open the text editor, load/mount it on demand
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { refsStatic } from '../common/ref'
|
|
6
|
+
|
|
7
|
+
let pending = null
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* request to open the text editor with file data,
|
|
11
|
+
* if the editor is not mounted yet, mount it first
|
|
12
|
+
* and keep the data as pending, editor will consume
|
|
13
|
+
* it on mount
|
|
14
|
+
* @param {object} data { id, file }
|
|
15
|
+
*/
|
|
16
|
+
export function openTextEditor (data) {
|
|
17
|
+
const editor = refsStatic.get('text-editor')
|
|
18
|
+
if (editor) {
|
|
19
|
+
editor.openEditor(data)
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
pending = data
|
|
23
|
+
window.store.textEditorRequested = true
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function takePendingTextEditorData () {
|
|
27
|
+
const data = pending
|
|
28
|
+
pending = null
|
|
29
|
+
return data
|
|
30
|
+
}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
import { lazy, Suspense } from 'react'
|
|
2
|
-
|
|
3
|
-
const TextEditor = lazy(() => import('./text-editor'))
|
|
1
|
+
import { lazy, Suspense, useMemo } from 'react'
|
|
2
|
+
import LazyBoundary from '../common/lazy-boundary'
|
|
4
3
|
|
|
5
4
|
export default function TextEditorEntry (props) {
|
|
5
|
+
// one lazy component per mount: the entry is remounted (the mount latch is
|
|
6
|
+
// released by the boundary below) exactly when a previous load failed, and
|
|
7
|
+
// React.lazy caches a rejected import() forever — so a retry has to go
|
|
8
|
+
// through a *new* lazy component
|
|
9
|
+
const TextEditor = useMemo(() => lazy(() => import('./text-editor')), [])
|
|
10
|
+
const onError = () => {
|
|
11
|
+
// release the mount latch so the next "edit file" request mounts a fresh
|
|
12
|
+
// lazy component and retries the fetch
|
|
13
|
+
window.store.textEditorRequested = false
|
|
14
|
+
}
|
|
6
15
|
return (
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
16
|
+
<LazyBoundary onError={onError}>
|
|
17
|
+
<Suspense fallback={null}>
|
|
18
|
+
<TextEditor {...props} />
|
|
19
|
+
</Suspense>
|
|
20
|
+
</LazyBoundary>
|
|
10
21
|
)
|
|
11
22
|
}
|
|
@@ -13,6 +13,7 @@ import Modal from '../common/modal'
|
|
|
13
13
|
import resolve from '../../common/resolve'
|
|
14
14
|
import { safeGetItem } from '../../common/safe-local-storage.js'
|
|
15
15
|
import { refsStatic, refs } from '../common/ref'
|
|
16
|
+
import { takePendingTextEditorData } from './open-text-editor'
|
|
16
17
|
|
|
17
18
|
const e = window.translate
|
|
18
19
|
|
|
@@ -27,6 +28,19 @@ export default class TextEditor extends PureComponent {
|
|
|
27
28
|
|
|
28
29
|
componentDidMount () {
|
|
29
30
|
refsStatic.add('text-editor', this)
|
|
31
|
+
// editor may be mounted by an open request,
|
|
32
|
+
// consume the pending data now
|
|
33
|
+
const data = takePendingTextEditorData()
|
|
34
|
+
if (data) {
|
|
35
|
+
this.openEditor(data)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
componentWillUnmount () {
|
|
40
|
+
// the entry can be unmounted (a failed chunk load releases the mount
|
|
41
|
+
// latch); without this a later request would find this dead instance and
|
|
42
|
+
// call openEditor on it, so the modal would never show up
|
|
43
|
+
refsStatic.remove('text-editor')
|
|
30
44
|
}
|
|
31
45
|
|
|
32
46
|
setStateProxy = (state, cb) => {
|