@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.
Files changed (146) hide show
  1. package/README.md +246 -12
  2. package/client/common/choose-save-folder.js +21 -2
  3. package/client/common/constants.js +20 -6
  4. package/client/common/create-title.jsx +6 -0
  5. package/client/common/default-setting.js +15 -0
  6. package/client/common/init-setting-item.js +5 -0
  7. package/client/common/platform.js +24 -0
  8. package/client/components/ai/agent-tool-call-card.jsx +10 -2
  9. package/client/components/ai/agent.js +4 -1
  10. package/client/components/ai/ai-attachments.js +87 -0
  11. package/client/components/ai/ai-chat-empty.jsx +43 -0
  12. package/client/components/ai/ai-chat-entry.jsx +13 -4
  13. package/client/components/ai/ai-chat-history-item.jsx +28 -4
  14. package/client/components/ai/ai-chat-history.jsx +2 -1
  15. package/client/components/ai/ai-chat.jsx +104 -13
  16. package/client/components/ai/ai-config-props.js +4 -130
  17. package/client/components/ai/ai-config.jsx +135 -15
  18. package/client/components/ai/ai-presets.js +173 -0
  19. package/client/components/ai/ai.styl +83 -0
  20. package/client/components/bg/css-overwrite.jsx +11 -0
  21. package/client/components/bookmark-form/bookmark-schema.js +4 -0
  22. package/client/components/bookmark-form/common/fields.jsx +3 -0
  23. package/client/components/bookmark-form/config/common-fields.js +12 -0
  24. package/client/components/bookmark-form/config/local.js +3 -2
  25. package/client/components/bookmark-form/config/serial.js +3 -2
  26. package/client/components/bookmark-form/config/ssh.js +2 -1
  27. package/client/components/bookmark-form/config/telnet.js +3 -2
  28. package/client/components/common/item-filter.jsx +76 -0
  29. package/client/components/common/item-filter.styl +54 -0
  30. package/client/components/common/lazy-boundary.jsx +34 -0
  31. package/client/components/common/opacity.jsx +3 -1
  32. package/client/components/footer/cmd-history.jsx +132 -45
  33. package/client/components/footer/cmd-history.styl +42 -4
  34. package/client/components/footer/footer-entry.jsx +35 -5
  35. package/client/components/footer/footer.styl +8 -1
  36. package/client/components/footer/multi-tab-run-modal.jsx +83 -0
  37. package/client/components/footer/tab-select.jsx +34 -17
  38. package/client/components/layout/layout.jsx +23 -31
  39. package/client/components/layout/pixed.js +3 -0
  40. package/client/components/main/main.jsx +55 -28
  41. package/client/components/main/term-fullscreen.styl +9 -3
  42. package/client/components/quick-commands/qm.styl +3 -2
  43. package/client/components/quick-commands/quick-command-create-modal.jsx +60 -0
  44. package/client/components/quick-commands/quick-commands-form-elem.jsx +10 -4
  45. package/client/components/rdp/file-transfer.js +4 -4
  46. package/client/components/remote-monitor/monitor-details.jsx +458 -0
  47. package/client/components/remote-monitor/monitor-details.styl +87 -0
  48. package/client/components/remote-monitor/monitor-model.js +764 -0
  49. package/client/components/remote-monitor/remote-monitor-bar-entry.jsx +18 -0
  50. package/client/components/remote-monitor/remote-monitor-bar.jsx +344 -0
  51. package/client/components/remote-monitor/remote-monitor-bar.styl +106 -0
  52. package/client/components/remote-monitor/session-monitor.js +361 -0
  53. package/client/components/remote-monitor/use-monitor-details.js +10 -0
  54. package/client/components/remote-monitor/visibility.js +18 -0
  55. package/client/components/session/session-control.jsx +29 -2
  56. package/client/components/session/session.jsx +40 -18
  57. package/client/components/session/sessions.jsx +5 -2
  58. package/client/components/setting-panel/setting-common.jsx +25 -56
  59. package/client/components/setting-panel/setting-modal.jsx +57 -42
  60. package/client/components/setting-panel/setting-terminal.jsx +8 -2
  61. package/client/components/setting-panel/setting.styl +1 -1
  62. package/client/components/setting-panel/tab-triggers.jsx +71 -0
  63. package/client/components/sftp/file-compare-modal.jsx +6 -3
  64. package/client/components/sftp/file-item.jsx +5 -3
  65. package/client/components/sftp/owner-list.js +11 -2
  66. package/client/components/sftp/sftp-entry.jsx +4 -0
  67. package/client/components/side-panel-r/side-panel-r.jsx +2 -2
  68. package/client/components/sidebar/side-panel.jsx +1 -1
  69. package/client/components/sys-menu/menu-btn.jsx +30 -1
  70. package/client/components/tabs/index.jsx +2 -2
  71. package/client/components/tabs/tab-title.jsx +3 -2
  72. package/client/components/tabs/tab.jsx +5 -1
  73. package/client/components/terminal/attach-addon-custom.js +295 -49
  74. package/client/components/terminal/automation/index.js +64 -0
  75. package/client/components/terminal/automation/keys.js +49 -0
  76. package/client/components/terminal/automation/stream-matcher.js +82 -0
  77. package/client/components/terminal/automation/strip-ansi.js +19 -0
  78. package/client/components/terminal/automation/trigger-engine.js +233 -0
  79. package/client/components/terminal/automation/trigger-presets.js +110 -0
  80. package/client/components/terminal/command-tracker-addon.js +31 -1
  81. package/client/components/terminal/mixins/index.js +27 -0
  82. package/client/components/terminal/mixins/term-attach.js +123 -0
  83. package/client/components/terminal/mixins/term-config.jsx +84 -0
  84. package/client/components/terminal/mixins/term-content.js +126 -0
  85. package/client/components/terminal/mixins/term-context-menu.jsx +323 -0
  86. package/client/components/terminal/mixins/term-file-drop.js +149 -0
  87. package/client/components/terminal/mixins/term-init.js +122 -0
  88. package/client/components/terminal/mixins/term-log.jsx +96 -0
  89. package/client/components/terminal/mixins/term-resize.js +87 -0
  90. package/client/components/terminal/mixins/term-socket.js +433 -0
  91. package/client/components/terminal/mixins/term-suggestions.js +224 -0
  92. package/client/components/terminal/mixins/term-theme.js +190 -0
  93. package/client/components/terminal/mixins/term-touch.js +523 -0
  94. package/client/components/terminal/shell-detect.js +37 -0
  95. package/client/components/terminal/shell.js +0 -28
  96. package/client/components/terminal/shortcut-bar-defs.js +30 -4
  97. package/client/components/terminal/shortcut-bar-edit.jsx +40 -9
  98. package/client/components/terminal/shortcut-bar-entry.jsx +6 -3
  99. package/client/components/terminal/shortcut-bar.jsx +17 -10
  100. package/client/components/terminal/shortcut-bar.styl +4 -0
  101. package/client/components/terminal/ssh-reload-state.js +96 -0
  102. package/client/components/terminal/startup-queue.js +433 -0
  103. package/client/components/terminal/terminal-interactive.jsx +32 -0
  104. package/client/components/terminal/terminal-select-text.jsx +69 -0
  105. package/client/components/terminal/terminal.jsx +227 -2064
  106. package/client/components/terminal/terminal.styl +61 -0
  107. package/client/components/terminal/transfer-client-base.js +5 -29
  108. package/client/components/terminal/trzsz-client.js +1 -3
  109. package/client/components/terminal/xmodem-client.js +1 -3
  110. package/client/components/terminal/xterm-loader.js +7 -0
  111. package/client/components/terminal/zmodem-client.js +1 -3
  112. package/client/components/terminal-info/base.jsx +18 -70
  113. package/client/components/terminal-info/terminal-info-entry.jsx +13 -5
  114. package/client/components/terminal-info/terminal-info.jsx +50 -59
  115. package/client/components/terminal-info/terminal-info.styl +6 -49
  116. package/client/components/text-editor/open-text-editor.js +30 -0
  117. package/client/components/text-editor/text-editor-entry.jsx +17 -6
  118. package/client/components/text-editor/text-editor.jsx +14 -0
  119. package/client/components/triggers/trigger-editor.jsx +246 -0
  120. package/client/components/triggers/trigger-form.jsx +200 -0
  121. package/client/components/triggers/trigger-session-modal.jsx +199 -0
  122. package/client/components/triggers/trigger-setting-list.jsx +89 -0
  123. package/client/components/triggers/trigger-transport.jsx +60 -0
  124. package/client/components/triggers/triggers-field.jsx +19 -0
  125. package/client/components/widgets/widgets-list.jsx +11 -1
  126. package/client/css/mobile.styl +29 -8
  127. package/client/store/common.js +12 -1
  128. package/client/store/init-state.js +7 -0
  129. package/client/store/mcp-handler.js +158 -30
  130. package/client/store/setting.js +9 -0
  131. package/client/store/store.js +2 -0
  132. package/client/store/sync.js +2 -0
  133. package/client/store/tab.js +42 -3
  134. package/client/store/trigger.js +118 -0
  135. package/client/store/watch.js +13 -5
  136. package/client/views/index.pug +3 -0
  137. package/package.json +1 -1
  138. package/client/components/terminal-info/activity.jsx +0 -57
  139. package/client/components/terminal-info/data-cols-parser.jsx +0 -54
  140. package/client/components/terminal-info/disk.jsx +0 -45
  141. package/client/components/terminal-info/format-disks.js +0 -45
  142. package/client/components/terminal-info/network.jsx +0 -121
  143. package/client/components/terminal-info/resource.jsx +0 -99
  144. package/client/components/terminal-info/run-cmd.jsx +0 -263
  145. package/client/components/terminal-info/sys-info.jsx +0 -56
  146. package/client/components/terminal-info/up.jsx +0 -17
@@ -0,0 +1,122 @@
1
+ import {
2
+ loadTerminal,
3
+ loadFitAddon,
4
+ loadSerializeAddon,
5
+ loadSearchAddon,
6
+ loadLigaturesAddon,
7
+ loadUnicode11Addon,
8
+ loadImageAddon
9
+ } from '../xterm-loader.js'
10
+ import { CommandTrackerAddon } from '../command-tracker-addon.js'
11
+ import { Osc52Addon } from '../osc52-addon.js'
12
+ import { rendererTypes } from '../../../common/constants.js'
13
+ import { refsStatic } from '../../common/ref.js'
14
+ import keyControlPressed from '../../../common/key-control-pressed.js'
15
+
16
+ /**
17
+ * Terminal bootstrap: create the xterm instance, load every addon and wire
18
+ * the handlers that must exist before the connection is opened. Connection
19
+ * setup continues in `socketMixin.remoteInit`.
20
+ */
21
+ export const initMixin = {
22
+ async initTerminal () {
23
+ const { themeConfig, tab = {}, config = {} } = this.props
24
+ const tc = this.getRendererThemeConfig(themeConfig)
25
+ const Terminal = await loadTerminal()
26
+ const term = new Terminal({
27
+ allowProposedApi: true,
28
+ scrollback: config.scrollback,
29
+ rightClickSelectsWord: config.rightClickSelectsWord || false,
30
+ fontFamily: tab.fontFamily || config.fontFamily,
31
+ theme: tc,
32
+ allowTransparency: true,
33
+ wordSeparator: config.terminalWordSeparator,
34
+ cursorStyle: config.cursorStyle,
35
+ cursorBlink: config.cursorBlink,
36
+ fontSize: tab.fontSize || config.fontSize,
37
+ screenReaderMode: config.screenReaderMode
38
+ })
39
+
40
+ term.parent = this
41
+ term.onSelectionChange(this.onSelection)
42
+ term.open(this.domRef.current, true)
43
+ this.registerTerminalColorQueryHandlers(term, themeConfig)
44
+ await this.loadRenderer(term, config)
45
+ this.fixSelectionColors(term)
46
+ // Re-apply the theme after the renderer is loaded. The Terminal was
47
+ // constructed before UiTheme's useEffect ran, so the initial theme
48
+ // may have a stale background. Pass `term` directly because this.term
49
+ // is not assigned yet. Use deferred=true so a second repaint picks up
50
+ // any CSS --main changes applied by UiTheme's useEffect.
51
+ if (config.rendererType === rendererTypes.webGL) {
52
+ this.applyTerminalTheme(true, term)
53
+ }
54
+
55
+ const FitAddon = await loadFitAddon()
56
+ this.fitAddon = new FitAddon()
57
+ this.cmdAddon = new CommandTrackerAddon()
58
+ const SerializeAddon = await loadSerializeAddon()
59
+ this.serializeAddon = new SerializeAddon()
60
+ this.cmdAddon.onCommandExecuted((cmd) => {
61
+ if (cmd && cmd.trim()) {
62
+ window.store.addCmdHistory(cmd.trim())
63
+ }
64
+ })
65
+ this.cmdAddon.onCwdChanged((cwd) => {
66
+ this.setCwd(cwd)
67
+ })
68
+ const SearchAddon = await loadSearchAddon()
69
+ this.searchAddon = new SearchAddon()
70
+ const LigaturesAddon = await loadLigaturesAddon()
71
+ const ligtureAddon = new LigaturesAddon()
72
+ this.searchAddon.onDidChangeResults(this.onSearchResultsChange)
73
+ const Unicode11Addon = await loadUnicode11Addon()
74
+ const unicode11Addon = new Unicode11Addon()
75
+ term.loadAddon(unicode11Addon)
76
+ term.loadAddon(ligtureAddon)
77
+ term.unicode.activeVersion = '11'
78
+ term.loadAddon(this.fitAddon)
79
+ term.loadAddon(this.searchAddon)
80
+ term.loadAddon(this.cmdAddon)
81
+ term.loadAddon(this.serializeAddon)
82
+ this.osc52Addon = new Osc52Addon()
83
+ term.loadAddon(this.osc52Addon)
84
+ if (tab.enableTerminalImage) {
85
+ const ImageAddon = await loadImageAddon()
86
+ this.imageAddon = new ImageAddon({
87
+ pixelLimit: 33554432
88
+ })
89
+ term.loadAddon(this.imageAddon)
90
+ }
91
+ term.onData(this.onData)
92
+ this.term = term
93
+ term.onSelectionChange(this.onSelectionChange)
94
+ term.attachCustomKeyEventHandler(this.handleKeyboardEvent.bind(this))
95
+ // 容器不可见(隐藏标签 display:none)时不 fit,避免算出 0 列把 shell
96
+ // 提示符逐字符错误换行;待标签激活可见后由 fitAndRefresh 重新适配。
97
+ if (this.isElementVisible()) {
98
+ this.fitAddon.fit()
99
+ }
100
+ await this.restoreReloadScreen(term)
101
+ await this.remoteInit(term)
102
+ },
103
+
104
+ onSelectionChange () {
105
+ const hasSelection = this.term.hasSelection()
106
+ const txt = hasSelection ? this.term.getSelection().trim() : ''
107
+ this.setState({ hasSelection })
108
+ refsStatic.get('unix-timestamp-tooltip')?.onSelection(txt)
109
+ },
110
+
111
+ webLinkHandler (event, url) {
112
+ if (event?.button === 2) {
113
+ return false
114
+ }
115
+ if (!this.props.config.ctrlOrMetaOpenTerminalLink) {
116
+ return window.openLink(url, '_blank')
117
+ }
118
+ if (keyControlPressed(event)) {
119
+ window.openLink(url, '_blank')
120
+ }
121
+ }
122
+ }
@@ -0,0 +1,96 @@
1
+ import { pick } from 'lodash-es'
2
+ import { notification } from '../../common/notification'
3
+ import ShowItem from '../../common/show-item.jsx'
4
+ import { refs } from '../../common/ref.js'
5
+ import { startTerminalLogFile, toggleTerminalLog } from '../terminal-apis.js'
6
+ import { getFolderFromFilePath } from '../../sftp/file-read.js'
7
+
8
+ const e = window.translate
9
+
10
+ /**
11
+ * Session logging / recording: dumping the buffer to disk and keeping the
12
+ * timestamped log file running.
13
+ */
14
+ export const logMixin = {
15
+ syncTermInfo (stateUpdate) {
16
+ this.setState(stateUpdate)
17
+ const infoUpdate = pick(stateUpdate, ['saveTerminalLogToFile', 'addTimeStampToTermLog', 'logPath', 'logFileName'])
18
+ if (Object.keys(infoUpdate).length) {
19
+ refs.get('term-info-' + this.props.tab.id)?.setState(infoUpdate)
20
+ }
21
+ },
22
+
23
+ async openLogSaveDialog (titleKey) {
24
+ const { logName } = this.props
25
+ const result = await window.api.saveDialog({
26
+ title: e(titleKey),
27
+ defaultPath: logName + '.log',
28
+ filters: [
29
+ { name: 'Log files', extensions: ['log'] }
30
+ ],
31
+ properties: ['createDirectory', 'showOverwriteConfirmation']
32
+ })
33
+ if (result.canceled || !result.filePath) {
34
+ return null
35
+ }
36
+ return result.filePath
37
+ },
38
+
39
+ async onSaveTerminalLog () {
40
+ const filePath = await this.openLogSaveDialog('saveTerminalLogToFile')
41
+ if (!filePath) {
42
+ return
43
+ }
44
+ const content = this.getTerminalBufferText()
45
+ await window.fs.writeFile(filePath, content).catch(window.store.onError)
46
+ const { addTimeStampToTermLog } = this.state
47
+ startTerminalLogFile(this.pid, filePath, addTimeStampToTermLog).catch(window.store.onError)
48
+ const { path: logPath, name: logFileName } = getFolderFromFilePath(filePath, false)
49
+ this.syncTermInfo({ saveTerminalLogToFile: true, logPath, logFileName })
50
+ notification.success({
51
+ message: e('saveTerminalLogToFile'),
52
+ description: <ShowItem to={filePath}>{filePath}</ShowItem>,
53
+ duration: 5
54
+ })
55
+ },
56
+
57
+ async onRecord () {
58
+ const filePath = await this.openLogSaveDialog('record')
59
+ if (!filePath) {
60
+ return
61
+ }
62
+ const { addTimeStampToTermLog } = this.state
63
+ startTerminalLogFile(this.pid, filePath, addTimeStampToTermLog).catch(window.store.onError)
64
+ const { path: logPath, name: logFileName } = getFolderFromFilePath(filePath, false)
65
+ this.syncTermInfo({ saveTerminalLogToFile: true, logPath, logFileName })
66
+ this.setState({ recording: true, recordingFilePath: filePath })
67
+ notification.success({
68
+ message: e('record'),
69
+ description: <ShowItem to={filePath}>{filePath}</ShowItem>,
70
+ duration: 5
71
+ })
72
+ },
73
+
74
+ onStopRecord () {
75
+ const { recordingFilePath } = this.state
76
+ toggleTerminalLog(this.pid).catch(window.store.onError)
77
+ this.syncTermInfo({ saveTerminalLogToFile: false })
78
+ this.setState({ recording: false, recordingFilePath: '' })
79
+ notification.success({
80
+ message: e('stopRecord'),
81
+ description: <ShowItem to={recordingFilePath}>{recordingFilePath}</ShowItem>
82
+ })
83
+ },
84
+
85
+ handleShowInfo () {
86
+ const { logName, tab } = this.props
87
+ const infoProps = {
88
+ logName,
89
+ id: tab.id,
90
+ pid: tab.id,
91
+ isRemote: this.isRemote(),
92
+ isActive: this.isActiveTerminal()
93
+ }
94
+ Object.assign(window.store.terminalInfoProps, infoProps)
95
+ }
96
+ }
@@ -0,0 +1,87 @@
1
+ import { throttle } from 'lodash-es'
2
+ import { resizeTerm } from '../terminal-apis.js'
3
+ import { minTerminalFontSize } from '../../../common/constants.js'
4
+
5
+ /**
6
+ * Sizing: fitting the terminal into its (possibly hidden) container, font
7
+ * zoom, and keeping the remote pty in sync with the on-screen size.
8
+ */
9
+ export const resizeMixin = {
10
+ // 判断终端挂载容器当前是否真实可见(非 display:none)。
11
+ // 隐藏标签的 clientWidth/clientHeight 为 0,此时不应 fit,否则会算出 0 列。
12
+ isElementVisible () {
13
+ const el = this.domRef.current
14
+ if (!el) {
15
+ return false
16
+ }
17
+ return el.clientWidth > 0 && el.clientHeight > 0
18
+ },
19
+
20
+ // 重新适配终端尺寸并强制重绘可见区域。
21
+ // 仅当容器真正可见时才 fit:隐藏标签(display:none)下 clientWidth 为 0,
22
+ // 若在此时 fit 会算出 0/极小列数,使 shell 提示符被逐字符错误换行,
23
+ // 出现快速连续打开多个连接时的虚假/重复提示符。因此隐藏态跳过 fit,
24
+ // 保留 xterm 默认 80x24,待标签激活可见后再 fit 重绘,从根上避免换行损坏。
25
+ fitAndRefresh () {
26
+ if (!this.term || !this.fitAddon || this.onClose) {
27
+ return
28
+ }
29
+ if (!this.isElementVisible()) {
30
+ return
31
+ }
32
+ try {
33
+ this.fitAddon.fit()
34
+ this.term.refresh(0, this.term.rows - 1)
35
+ } catch (e) {
36
+ console.info('resize failed', e)
37
+ }
38
+ },
39
+
40
+ // One throttled runner per terminal: a module level one would let tabs
41
+ // throttle each other.
42
+ onResize () {
43
+ if (!this._resizeThrottled) {
44
+ this._resizeThrottled = throttle(() => this.fitAndRefresh(), 200)
45
+ }
46
+ this._resizeThrottled()
47
+ },
48
+
49
+ onResizeTerminal (size) {
50
+ const { cols, rows } = size
51
+ resizeTerm(this.pid, cols, rows)
52
+ },
53
+
54
+ zoom (v) {
55
+ const { term } = this
56
+ if (!term) {
57
+ return
58
+ }
59
+ const next = Math.max(
60
+ minTerminalFontSize,
61
+ term.options.fontSize + v
62
+ )
63
+ const changed = next - term.options.fontSize
64
+ if (changed === 0) {
65
+ return
66
+ }
67
+ term.options.fontSize = next
68
+ window.store.triggerResize()
69
+ if (this.originalFontSize == null) {
70
+ this.originalFontSize = next - changed
71
+ }
72
+ this.setState({
73
+ fontSizeChanged: next !== this.originalFontSize
74
+ })
75
+ },
76
+
77
+ handleResetFontSize () {
78
+ const { term } = this
79
+ if (!term || this.originalFontSize == null) {
80
+ return
81
+ }
82
+ term.options.fontSize = this.originalFontSize
83
+ window.store.triggerResize()
84
+ this.setState({ fontSizeChanged: false })
85
+ term.focus()
86
+ }
87
+ }