@electerm/electerm-react 1.50.31 → 1.50.46
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/client/components/main/css-overwrite.jsx +0 -1
- package/client/components/main/main.jsx +12 -2
- package/client/components/session/sessions.jsx +20 -13
- package/client/components/shortcuts/shortcut-handler.js +3 -0
- package/client/components/tabs/index.jsx +1 -1
- package/client/components/tabs/tabs.styl +2 -2
- package/client/components/terminal/command-tracker-addon.js +75 -0
- package/client/components/terminal/index.jsx +16 -18
- package/client/components/terminal/terminal.styl +4 -1
- package/client/entry/index.jsx +0 -4
- package/client/store/event.js +1 -0
- package/client/store/watch.js +0 -5
- package/client/views/index.pug +1 -1
- package/package.json +1 -1
|
@@ -23,20 +23,30 @@ import { isMac, isWin } from '../../common/constants'
|
|
|
23
23
|
import TermFullscreenControl from './term-fullscreen-control'
|
|
24
24
|
import TerminalInfo from '../terminal-info/terminal-info'
|
|
25
25
|
import { LoadingUI } from './loading'
|
|
26
|
-
import { ConfigProvider, notification } from 'antd'
|
|
26
|
+
import { ConfigProvider, notification, message } from 'antd'
|
|
27
27
|
import InfoModal from '../sidebar/info-modal.jsx'
|
|
28
28
|
import RightSidePanel from '../side-panel-r/side-panel-r'
|
|
29
29
|
import { pick } from 'lodash-es'
|
|
30
30
|
import './wrapper.styl'
|
|
31
31
|
|
|
32
|
+
function setupGlobalMessageDismiss () {
|
|
33
|
+
document.addEventListener('click', (event) => {
|
|
34
|
+
const messageElement = event.target.closest('.ant-message-notice')
|
|
35
|
+
if (messageElement) {
|
|
36
|
+
message.destroy()
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
32
41
|
export default auto(function Index (props) {
|
|
33
42
|
useEffect(() => {
|
|
34
43
|
notification.config({
|
|
35
44
|
placement: 'bottomRight'
|
|
36
45
|
})
|
|
46
|
+
setupGlobalMessageDismiss()
|
|
37
47
|
const { store } = props
|
|
38
48
|
window.addEventListener('resize', store.onResize)
|
|
39
|
-
store.
|
|
49
|
+
setTimeout(store.triggerResize, 200)
|
|
40
50
|
store.initStoreEvents()
|
|
41
51
|
const { ipcOnEvent } = window.pre
|
|
42
52
|
ipcOnEvent('checkupdate', store.onCheckUpdate)
|
|
@@ -119,7 +119,7 @@ class Sessions extends Component {
|
|
|
119
119
|
currentTabId: id
|
|
120
120
|
})
|
|
121
121
|
} else {
|
|
122
|
-
document.querySelector('.tab.active')
|
|
122
|
+
document.querySelector('.tab.active')?.click()
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -138,17 +138,15 @@ class Sessions extends Component {
|
|
|
138
138
|
if (tab) {
|
|
139
139
|
Object.assign(tab, update)
|
|
140
140
|
}
|
|
141
|
-
this.updateStoreTabs(tabs)
|
|
142
141
|
return {
|
|
143
142
|
tabs
|
|
144
143
|
}
|
|
144
|
+
}, () => {
|
|
145
|
+
this.updateStoreTabs(this.state.tabs)
|
|
145
146
|
})
|
|
146
147
|
}
|
|
147
148
|
|
|
148
|
-
addTab = (
|
|
149
|
-
_tab,
|
|
150
|
-
_index
|
|
151
|
-
) => {
|
|
149
|
+
addTab = (_tab, _index) => {
|
|
152
150
|
this.setState((oldState) => {
|
|
153
151
|
const tabs = copy(oldState.tabs)
|
|
154
152
|
const index = typeof _index === 'undefined'
|
|
@@ -162,15 +160,17 @@ class Sessions extends Component {
|
|
|
162
160
|
}
|
|
163
161
|
tab.batch = this.props.batch
|
|
164
162
|
tabs.splice(index, 0, tab)
|
|
165
|
-
this.updateStoreTabs(tabs)
|
|
166
|
-
this.updateStoreCurrentTabId(tab.id)
|
|
167
163
|
return {
|
|
168
164
|
currentTabId: tab.id,
|
|
169
165
|
tabs
|
|
170
166
|
}
|
|
167
|
+
}, () => {
|
|
168
|
+
this.updateStoreTabs(this.state.tabs)
|
|
169
|
+
this.updateStoreCurrentTabId(this.state.currentTabId)
|
|
171
170
|
})
|
|
172
171
|
}
|
|
173
172
|
|
|
173
|
+
// After
|
|
174
174
|
delTab = (id) => {
|
|
175
175
|
this.setState((oldState) => {
|
|
176
176
|
const tabs = copy(oldState.tabs)
|
|
@@ -183,13 +183,16 @@ class Sessions extends Component {
|
|
|
183
183
|
i = i ? i - 1 : i + 1
|
|
184
184
|
const next = tabs[i] || {}
|
|
185
185
|
up.currentTabId = next.id || ''
|
|
186
|
-
this.updateStoreCurrentTabId(next.id)
|
|
187
186
|
}
|
|
188
187
|
up.tabs = tabs.filter(t => {
|
|
189
188
|
return t.id !== id
|
|
190
189
|
})
|
|
191
|
-
this.updateStoreTabs(up.tabs)
|
|
192
190
|
return up
|
|
191
|
+
}, () => {
|
|
192
|
+
this.updateStoreTabs(this.state.tabs)
|
|
193
|
+
if (this.state.currentTabId !== id) {
|
|
194
|
+
this.updateStoreCurrentTabId(this.state.currentTabId)
|
|
195
|
+
}
|
|
193
196
|
})
|
|
194
197
|
}
|
|
195
198
|
|
|
@@ -247,11 +250,15 @@ class Sessions extends Component {
|
|
|
247
250
|
if (!matchedTab) {
|
|
248
251
|
return
|
|
249
252
|
}
|
|
250
|
-
|
|
251
|
-
|
|
253
|
+
|
|
254
|
+
// Batch the updates
|
|
252
255
|
this.setState({
|
|
253
256
|
currentTabId: id
|
|
254
|
-
},
|
|
257
|
+
}, () => {
|
|
258
|
+
this.updateStoreCurrentTabId(id)
|
|
259
|
+
this.timer = setTimeout(window.store.triggerResize, 500)
|
|
260
|
+
this.postChange()
|
|
261
|
+
})
|
|
255
262
|
}
|
|
256
263
|
|
|
257
264
|
setTabs = tabs => {
|
|
@@ -483,7 +483,7 @@ export default class Tabs extends React.Component {
|
|
|
483
483
|
menu={{ items }}
|
|
484
484
|
placement='bottomRight'
|
|
485
485
|
>
|
|
486
|
-
<span className='tabs-dd-icon mg1l'>
|
|
486
|
+
<span className='tabs-dd-icon layout-dd-icon mg1l'>
|
|
487
487
|
<Icon /> <DownOutlined />
|
|
488
488
|
</span>
|
|
489
489
|
</Dropdown>
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
::-webkit-scrollbar
|
|
8
8
|
width 0
|
|
9
9
|
display none
|
|
10
|
+
.not-system-ui.is-mac .layout-item.v1 .tabs-inner
|
|
11
|
+
margin-left 42px
|
|
10
12
|
.not-system-ui.is-mac.not-webapp .layout-item.v1
|
|
11
13
|
.tabs-inner
|
|
12
14
|
margin-left 72px
|
|
@@ -25,8 +27,6 @@
|
|
|
25
27
|
height 36px
|
|
26
28
|
overflow-x scroll
|
|
27
29
|
overflow-y hidden
|
|
28
|
-
.layout-item.v1 .tabs-inner
|
|
29
|
-
margin-left 42px
|
|
30
30
|
|
|
31
31
|
.tabs-wrapper
|
|
32
32
|
z-index 3
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export class CommandTrackerAddon {
|
|
2
|
+
constructor () {
|
|
3
|
+
this.terminal = undefined
|
|
4
|
+
this.activeCommand = ''
|
|
5
|
+
this.currentCommand = ''
|
|
6
|
+
this.cursorPosition = 0
|
|
7
|
+
this.timeout = null
|
|
8
|
+
this.handleKey = this.debounce(this._handleKey, 200) // 10ms debounce
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
debounce = (func, wait) => {
|
|
12
|
+
return (...args) => {
|
|
13
|
+
const later = () => {
|
|
14
|
+
clearTimeout(this.timeout)
|
|
15
|
+
func.apply(this, args)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
clearTimeout(this.timeout)
|
|
19
|
+
this.timeout = setTimeout(later, wait)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
activate (terminal) {
|
|
24
|
+
this.terminal = terminal
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
dispose () {
|
|
28
|
+
this.term = null
|
|
29
|
+
if (this._disposables) {
|
|
30
|
+
this._disposables.forEach(d => d.dispose())
|
|
31
|
+
this._disposables.length = 0
|
|
32
|
+
}
|
|
33
|
+
if (this.timeout) {
|
|
34
|
+
clearTimeout(this.timeout)
|
|
35
|
+
this.timeout = null
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
handleData = (data) => {
|
|
40
|
+
// Handle regular input
|
|
41
|
+
this.activeCommand = this.activeCommand.slice(0, this.cursorPosition) + data + this.activeCommand.slice(this.cursorPosition)
|
|
42
|
+
this.cursorPosition += data.length
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// This is now our internal handler
|
|
46
|
+
_handleKey = (e) => {
|
|
47
|
+
const { key } = e
|
|
48
|
+
if (key === 'Enter') {
|
|
49
|
+
// Command executed, reset
|
|
50
|
+
this.currentCommand = this.activeCommand
|
|
51
|
+
this.activeCommand = ''
|
|
52
|
+
this.cursorPosition = 0
|
|
53
|
+
} else if (key === 'Backspace') {
|
|
54
|
+
// Handle backspace
|
|
55
|
+
if (this.cursorPosition > 0) {
|
|
56
|
+
this.activeCommand = this.activeCommand.slice(0, this.cursorPosition - 1) + this.activeCommand.slice(this.cursorPosition)
|
|
57
|
+
this.cursorPosition--
|
|
58
|
+
}
|
|
59
|
+
} else if (key === 'ArrowLeft') {
|
|
60
|
+
// Move cursor left
|
|
61
|
+
if (this.cursorPosition > 0) {
|
|
62
|
+
this.cursorPosition--
|
|
63
|
+
}
|
|
64
|
+
} else if (key === 'ArrowRight') {
|
|
65
|
+
// Move cursor right
|
|
66
|
+
if (this.cursorPosition < this.activeCommand.length) {
|
|
67
|
+
this.cursorPosition++
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getCurrentCommand () {
|
|
73
|
+
return this.activeCommand || this.currentCommand
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -48,8 +48,7 @@ import { createTerm, resizeTerm } from './terminal-apis'
|
|
|
48
48
|
import { shortcutExtend, shortcutDescExtend } from '../shortcuts/shortcut-handler.js'
|
|
49
49
|
import { KeywordHighlighterAddon } from './highlight-addon.js'
|
|
50
50
|
import { getLocalFileInfo } from '../sftp/file-read.js'
|
|
51
|
-
import {
|
|
52
|
-
import strip from '@electerm/strip-ansi'
|
|
51
|
+
import { CommandTrackerAddon } from './command-tracker-addon.js'
|
|
53
52
|
import { formatBytes } from '../../common/byte-format.js'
|
|
54
53
|
import * as fs from './fs.js'
|
|
55
54
|
|
|
@@ -184,8 +183,13 @@ clear\r`
|
|
|
184
183
|
this.fitAddon = null
|
|
185
184
|
this.zmodemAddon = null
|
|
186
185
|
this.searchAddon = null
|
|
187
|
-
this.serializeAddon = null
|
|
188
186
|
this.fitAddon = null
|
|
187
|
+
this.cmdAddon = null
|
|
188
|
+
// Clear the notification if it exists
|
|
189
|
+
if (this.socketCloseWarning) {
|
|
190
|
+
notification.destroy(this.socketCloseWarning.key)
|
|
191
|
+
this.socketCloseWarning = null
|
|
192
|
+
}
|
|
189
193
|
}
|
|
190
194
|
|
|
191
195
|
terminalConfigProps = [
|
|
@@ -928,17 +932,8 @@ clear\r`
|
|
|
928
932
|
return result
|
|
929
933
|
}
|
|
930
934
|
|
|
931
|
-
// onKey = ({ key }) => {
|
|
932
|
-
// if (key === '\r') {
|
|
933
|
-
// this.getCmd()
|
|
934
|
-
// }
|
|
935
|
-
// }
|
|
936
|
-
|
|
937
935
|
getCmd = () => {
|
|
938
|
-
|
|
939
|
-
const arr = strip(str).split(/ +/)
|
|
940
|
-
const len = arr.length
|
|
941
|
-
return arr[len - 1]
|
|
936
|
+
return this.cmdAddon.getCurrentCommand()
|
|
942
937
|
}
|
|
943
938
|
|
|
944
939
|
getCwd = () => {
|
|
@@ -963,13 +958,15 @@ clear\r`
|
|
|
963
958
|
}
|
|
964
959
|
|
|
965
960
|
onData = (d) => {
|
|
966
|
-
|
|
961
|
+
if (this.cmdAddon) {
|
|
962
|
+
this.cmdAddon.handleData(d)
|
|
963
|
+
}
|
|
967
964
|
if (!d.includes('\r')) {
|
|
968
965
|
delete this.userTypeExit
|
|
969
966
|
} else {
|
|
970
|
-
const data = this.getCmd()
|
|
967
|
+
const data = this.getCmd().trim()
|
|
971
968
|
if (this.term.buffer.active.type !== 'alternate') {
|
|
972
|
-
setTimeout(this.getCwd, 200)
|
|
969
|
+
this.timers.getCwd = setTimeout(this.getCwd, 200)
|
|
973
970
|
}
|
|
974
971
|
const exitCmds = [
|
|
975
972
|
'exit',
|
|
@@ -1028,18 +1025,18 @@ clear\r`
|
|
|
1028
1025
|
|
|
1029
1026
|
// term.on('keydown', this.handleEvent)
|
|
1030
1027
|
this.fitAddon = new FitAddon()
|
|
1028
|
+
this.cmdAddon = new CommandTrackerAddon()
|
|
1031
1029
|
this.searchAddon = new SearchAddon()
|
|
1032
1030
|
const ligtureAddon = new LigaturesAddon()
|
|
1033
1031
|
this.searchAddon.onDidChangeResults(this.onSearchResultsChange)
|
|
1034
1032
|
const unicode11Addon = new Unicode11Addon()
|
|
1035
1033
|
term.loadAddon(unicode11Addon)
|
|
1036
|
-
this.serializeAddon = new SerializeAddon()
|
|
1037
|
-
term.loadAddon(this.serializeAddon)
|
|
1038
1034
|
term.loadAddon(ligtureAddon)
|
|
1039
1035
|
// activate the new version
|
|
1040
1036
|
term.unicode.activeVersion = '11'
|
|
1041
1037
|
term.loadAddon(this.fitAddon)
|
|
1042
1038
|
term.loadAddon(this.searchAddon)
|
|
1039
|
+
term.loadAddon(this.cmdAddon)
|
|
1043
1040
|
term.onData(this.onData)
|
|
1044
1041
|
this.term = term
|
|
1045
1042
|
term.attachCustomKeyEventHandler(this.handleKeyboardEvent.bind(this))
|
|
@@ -1056,6 +1053,7 @@ clear\r`
|
|
|
1056
1053
|
}
|
|
1057
1054
|
|
|
1058
1055
|
runInitScript = () => {
|
|
1056
|
+
window.store.triggerResize()
|
|
1059
1057
|
const {
|
|
1060
1058
|
type,
|
|
1061
1059
|
title,
|
package/client/entry/index.jsx
CHANGED
|
@@ -4,10 +4,6 @@ import '@xterm/xterm/css/xterm.css'
|
|
|
4
4
|
import '../common/trzsz'
|
|
5
5
|
import 'firacode/distr/fira_code.css'
|
|
6
6
|
import Main from '../components/main/index.jsx'
|
|
7
|
-
import { notification } from 'antd'
|
|
8
|
-
notification.config({
|
|
9
|
-
placement: 'bottomRight'
|
|
10
|
-
})
|
|
11
7
|
|
|
12
8
|
const rootElement = createRoot(document.getElementById('container'))
|
|
13
9
|
rootElement.render(
|
package/client/store/event.js
CHANGED
|
@@ -63,6 +63,7 @@ export default Store => {
|
|
|
63
63
|
|
|
64
64
|
Store.prototype.triggerResize = function () {
|
|
65
65
|
window.store.resizeTrigger = window.store.resizeTrigger ? 0 : 1
|
|
66
|
+
window.dispatchEvent(new Event('resize'))
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
Store.prototype.toggleTermFullscreen = function (terminalFullScreen) {
|
package/client/store/watch.js
CHANGED
|
@@ -99,11 +99,6 @@ export default store => {
|
|
|
99
99
|
return store._checkedKeys
|
|
100
100
|
}).start()
|
|
101
101
|
|
|
102
|
-
// autoRun(store, () => {
|
|
103
|
-
// window.store.onLayoutChange()
|
|
104
|
-
// return store.layout
|
|
105
|
-
// }).start()
|
|
106
|
-
|
|
107
102
|
autoRun(store, () => {
|
|
108
103
|
const tabs = store.getTabs()
|
|
109
104
|
const { currentTabId } = store
|
package/client/views/index.pug
CHANGED
|
@@ -27,7 +27,7 @@ html
|
|
|
27
27
|
}
|
|
28
28
|
- if (!isDev)
|
|
29
29
|
link(rel='stylesheet', href='css/' + version + '-basic.css')
|
|
30
|
-
link(rel='stylesheet', href='css/' + version + '-
|
|
30
|
+
link(rel='stylesheet', href='css/' + version + '-electerm.css')
|
|
31
31
|
style(id='theme-css').
|
|
32
32
|
style(id='custom-css').
|
|
33
33
|
body
|