@electerm/electerm-react 1.50.21 → 1.50.40
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/layout/layout-item.jsx +69 -1
- package/client/components/layout/layout.jsx +1 -1
- package/client/components/layout/layout.styl +4 -1
- package/client/components/layout/layouts.jsx +2 -1
- package/client/components/main/css-overwrite.jsx +0 -1
- package/client/components/main/custom-css.jsx +1 -1
- package/client/components/main/main.jsx +15 -5
- package/client/components/main/ui-theme.jsx +1 -1
- package/client/components/session/session.jsx +3 -13
- package/client/components/session/sessions.jsx +73 -31
- package/client/components/setting-sync/setting-sync-form.jsx +1 -1
- package/client/components/shortcuts/shortcut-handler.js +3 -0
- package/client/components/shortcuts/shortcuts-defaults.js +5 -5
- package/client/components/tabs/tab.jsx +13 -26
- package/client/components/tabs/tabs.styl +2 -2
- package/client/components/terminal/attach-addon-custom.js +1 -1
- package/client/components/terminal/command-tracker-addon.js +75 -0
- package/client/components/terminal/index.jsx +25 -26
- package/client/components/terminal/terminal.styl +4 -1
- package/client/components/web/address-bar.jsx +50 -0
- package/client/components/web/web-session.jsx +32 -10
- package/client/entry/index.jsx +5 -10
- package/client/store/db-upgrade.js +1 -1
- package/client/store/event.js +1 -0
- package/client/store/quick-command.js +1 -1
- package/client/store/setting.js +1 -1
- package/client/store/tab.js +27 -2
- package/client/store/watch.js +0 -5
- package/client/views/index.pug +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
tabActions
|
|
3
|
+
} from '../../common/constants'
|
|
4
|
+
import postMsg from '../../common/post-msg'
|
|
5
|
+
|
|
1
6
|
export default function LayoutItem (props) {
|
|
2
7
|
const {
|
|
3
8
|
children,
|
|
4
9
|
i,
|
|
10
|
+
batch,
|
|
5
11
|
...itemProps
|
|
6
12
|
} = props
|
|
7
13
|
function handleClick (e) {
|
|
@@ -12,13 +18,75 @@ export default function LayoutItem (props) {
|
|
|
12
18
|
}
|
|
13
19
|
currentElement = currentElement.parentElement
|
|
14
20
|
}
|
|
21
|
+
window.store.currentLayoutBatch = i
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getDom () {
|
|
25
|
+
return document.querySelector(`.layout-item.v${batch + 1}`)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function onDrop (e) {
|
|
29
|
+
e.preventDefault()
|
|
30
|
+
const { target } = e
|
|
31
|
+
if (!target) {
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
let currentElement = target
|
|
35
|
+
while (currentElement) {
|
|
36
|
+
if (currentElement.classList && currentElement.classList.contains('tab')) {
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
currentElement = currentElement.parentElement
|
|
40
|
+
}
|
|
41
|
+
// debug('target drop', target)
|
|
42
|
+
const fromTab = JSON.parse(e.dataTransfer.getData('fromFile'))
|
|
43
|
+
const onDropElem = getDom
|
|
44
|
+
if (!onDropElem || !fromTab || fromTab.batch === batch) {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
const { store } = window
|
|
48
|
+
const { tabs } = store
|
|
49
|
+
const t = tabs.find(t => t.id === fromTab.id)
|
|
50
|
+
if (!t) {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
t.batch = batch
|
|
54
|
+
postMsg({
|
|
55
|
+
action: tabActions.changeCurrentTabId,
|
|
56
|
+
currentTabId: store.currentTabId
|
|
57
|
+
})
|
|
58
|
+
store.setTabs(tabs)
|
|
59
|
+
clearCls()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function clearCls () {
|
|
63
|
+
getDom()?.classList.remove('drag-over')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function addCls () {
|
|
67
|
+
getDom()?.classList.add('drag-over')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function onDragEnter () {
|
|
71
|
+
addCls()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function onDragLeave (e) {
|
|
75
|
+
clearCls()
|
|
76
|
+
}
|
|
15
77
|
|
|
16
|
-
|
|
78
|
+
function onDragEnd (e) {
|
|
79
|
+
clearCls()
|
|
80
|
+
e && e.dataTransfer && e.dataTransfer.clearData()
|
|
17
81
|
}
|
|
18
82
|
return (
|
|
19
83
|
<div
|
|
20
84
|
{...itemProps}
|
|
21
85
|
onClick={handleClick}
|
|
86
|
+
onDragEnter={onDragEnter}
|
|
87
|
+
onDragLeave={onDragLeave}
|
|
88
|
+
onDragEnd={onDragEnd}
|
|
89
|
+
onDrop={onDrop}
|
|
22
90
|
>
|
|
23
91
|
{children}
|
|
24
92
|
</div>
|
|
@@ -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)
|
|
@@ -64,7 +74,7 @@ export default auto(function Index (props) {
|
|
|
64
74
|
if (window.et.isWebApp) {
|
|
65
75
|
window.onbeforeunload = store.beforeExit
|
|
66
76
|
}
|
|
67
|
-
store.
|
|
77
|
+
store.isSecondInstance = window.pre.runSync('isSecondInstance')
|
|
68
78
|
store.initData()
|
|
69
79
|
store.checkForDbUpgrade()
|
|
70
80
|
window.pre.runGlobalAsync('registerDeepLink')
|
|
@@ -76,7 +86,7 @@ export default auto(function Index (props) {
|
|
|
76
86
|
config,
|
|
77
87
|
terminalFullScreen,
|
|
78
88
|
pinned,
|
|
79
|
-
|
|
89
|
+
isSecondInstance,
|
|
80
90
|
pinnedQuickCommandBar,
|
|
81
91
|
wsInited,
|
|
82
92
|
upgradeInfo,
|
|
@@ -98,7 +108,7 @@ export default auto(function Index (props) {
|
|
|
98
108
|
pinned,
|
|
99
109
|
'qm-pinned': pinnedQuickCommandBar,
|
|
100
110
|
'term-fullscreen': terminalFullScreen,
|
|
101
|
-
'is-main': !
|
|
111
|
+
'is-main': !isSecondInstance
|
|
102
112
|
})
|
|
103
113
|
const ext1 = {
|
|
104
114
|
className: cls
|
|
@@ -20,7 +20,6 @@ import generate from '../../common/uid'
|
|
|
20
20
|
import copy from 'json-deep-copy'
|
|
21
21
|
import classnames from 'classnames'
|
|
22
22
|
import {
|
|
23
|
-
termControlHeight,
|
|
24
23
|
paneMap,
|
|
25
24
|
terminalActions,
|
|
26
25
|
connectionMap,
|
|
@@ -89,15 +88,6 @@ export default class SessionWrapper extends Component {
|
|
|
89
88
|
})
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
computeHeight = () => {
|
|
93
|
-
const {
|
|
94
|
-
tabsHeight
|
|
95
|
-
} = this.props
|
|
96
|
-
return this.props.height -
|
|
97
|
-
tabsHeight -
|
|
98
|
-
termControlHeight
|
|
99
|
-
}
|
|
100
|
-
|
|
101
91
|
editTab = (up) => {
|
|
102
92
|
const {
|
|
103
93
|
tab,
|
|
@@ -131,7 +121,7 @@ export default class SessionWrapper extends Component {
|
|
|
131
121
|
|
|
132
122
|
computePosition = (index) => {
|
|
133
123
|
const windowWidth = this.getWidth()
|
|
134
|
-
const heightAll = this.computeHeight()
|
|
124
|
+
const heightAll = this.props.computeHeight()
|
|
135
125
|
return {
|
|
136
126
|
height: heightAll,
|
|
137
127
|
width: windowWidth,
|
|
@@ -196,7 +186,7 @@ export default class SessionWrapper extends Component {
|
|
|
196
186
|
const cls = pane === paneMap.terminal
|
|
197
187
|
? 'terms-box'
|
|
198
188
|
: 'terms-box hide'
|
|
199
|
-
const height = this.computeHeight()
|
|
189
|
+
const height = this.props.computeHeight()
|
|
200
190
|
const { tab } = this.props
|
|
201
191
|
const width = this.getWidth()
|
|
202
192
|
const themeConfig = copy(window.store.getThemeConfig())
|
|
@@ -246,7 +236,7 @@ export default class SessionWrapper extends Component {
|
|
|
246
236
|
if (type === terminalRdpType) {
|
|
247
237
|
return null
|
|
248
238
|
}
|
|
249
|
-
const height = this.computeHeight(pane)
|
|
239
|
+
const height = this.props.computeHeight(pane)
|
|
250
240
|
const cls = pane === paneMap.terminal
|
|
251
241
|
? 'hide'
|
|
252
242
|
: ''
|
|
@@ -8,15 +8,13 @@ import copy from 'json-deep-copy'
|
|
|
8
8
|
import wait from '../../common/wait.js'
|
|
9
9
|
import Tabs from '../tabs/index.jsx'
|
|
10
10
|
import {
|
|
11
|
-
commonActions,
|
|
12
11
|
tabActions,
|
|
13
12
|
paneMap,
|
|
14
13
|
statusMap,
|
|
15
|
-
terminalWebType
|
|
14
|
+
terminalWebType,
|
|
15
|
+
termControlHeight
|
|
16
16
|
} from '../../common/constants.js'
|
|
17
17
|
import newTerm, { updateCount } from '../../common/new-terminal.js'
|
|
18
|
-
import postMsg from '../../common/post-msg.js'
|
|
19
|
-
|
|
20
18
|
import LogoElem from '../common/logo-elem.jsx'
|
|
21
19
|
import { Button } from 'antd'
|
|
22
20
|
import toSimpleObj from '../../common/to-simple-obj.js'
|
|
@@ -45,9 +43,7 @@ class Sessions extends Component {
|
|
|
45
43
|
this.props.tabs &&
|
|
46
44
|
!deepEqual(prevProps.tabs, this.props.tabs)
|
|
47
45
|
) {
|
|
48
|
-
this.
|
|
49
|
-
tabs: copy(this.props.tabs)
|
|
50
|
-
})
|
|
46
|
+
this.updateTabs(this.props.tabs)
|
|
51
47
|
}
|
|
52
48
|
}
|
|
53
49
|
|
|
@@ -58,11 +54,29 @@ class Sessions extends Component {
|
|
|
58
54
|
this.timer = null
|
|
59
55
|
}
|
|
60
56
|
|
|
57
|
+
updateTabs = (propTabs) => {
|
|
58
|
+
const update = {
|
|
59
|
+
tabs: copy(propTabs)
|
|
60
|
+
}
|
|
61
|
+
const currentTab = propTabs.find(t => t.id === this.state.currentTabId)
|
|
62
|
+
if (!currentTab) {
|
|
63
|
+
update.currentTabId = propTabs[0]?.id
|
|
64
|
+
}
|
|
65
|
+
this.setState(update)
|
|
66
|
+
}
|
|
67
|
+
|
|
61
68
|
initShortcuts () {
|
|
62
69
|
window.addEventListener('keydown', this.bindHandleKeyboardEvent)
|
|
63
70
|
}
|
|
64
71
|
|
|
72
|
+
notCurrentTab = (tab) => {
|
|
73
|
+
return this.state.currentTabId !== window.store.currentTabId
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
closeCurrentTabShortcut = (e) => {
|
|
77
|
+
if (this.notCurrentTab()) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
66
80
|
e.stopPropagation()
|
|
67
81
|
this.delTab(
|
|
68
82
|
this.state.currentTabId
|
|
@@ -70,12 +84,23 @@ class Sessions extends Component {
|
|
|
70
84
|
}
|
|
71
85
|
|
|
72
86
|
reloadCurrentTabShortcut = (e) => {
|
|
87
|
+
if (this.notCurrentTab()) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
73
90
|
e.stopPropagation()
|
|
74
91
|
this.reloadTab(
|
|
75
92
|
this.getCurrentTab()
|
|
76
93
|
)
|
|
77
94
|
}
|
|
78
95
|
|
|
96
|
+
cloneToNextLayoutShortcut = (e) => {
|
|
97
|
+
if (this.notCurrentTab()) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
e.stopPropagation()
|
|
101
|
+
window.store.cloneToNextLayout()
|
|
102
|
+
}
|
|
103
|
+
|
|
79
104
|
watch = () => {
|
|
80
105
|
window.addEventListener('message', this.onEvent)
|
|
81
106
|
}
|
|
@@ -94,18 +119,8 @@ class Sessions extends Component {
|
|
|
94
119
|
currentTabId: id
|
|
95
120
|
})
|
|
96
121
|
} else {
|
|
97
|
-
|
|
122
|
+
document.querySelector('.tab.active')?.click()
|
|
98
123
|
}
|
|
99
|
-
postMsg({
|
|
100
|
-
action: commonActions.updateStore,
|
|
101
|
-
value: id,
|
|
102
|
-
prop: 'currentTabId'
|
|
103
|
-
})
|
|
104
|
-
postMsg({
|
|
105
|
-
action: commonActions.updateStore,
|
|
106
|
-
value: id,
|
|
107
|
-
prop: 'currentTabId' + this.props.batch
|
|
108
|
-
})
|
|
109
124
|
}
|
|
110
125
|
|
|
111
126
|
getCurrentTab = () => {
|
|
@@ -123,17 +138,15 @@ class Sessions extends Component {
|
|
|
123
138
|
if (tab) {
|
|
124
139
|
Object.assign(tab, update)
|
|
125
140
|
}
|
|
126
|
-
this.updateStoreTabs(tabs)
|
|
127
141
|
return {
|
|
128
142
|
tabs
|
|
129
143
|
}
|
|
144
|
+
}, () => {
|
|
145
|
+
this.updateStoreTabs(this.state.tabs)
|
|
130
146
|
})
|
|
131
147
|
}
|
|
132
148
|
|
|
133
|
-
addTab = (
|
|
134
|
-
_tab,
|
|
135
|
-
_index
|
|
136
|
-
) => {
|
|
149
|
+
addTab = (_tab, _index) => {
|
|
137
150
|
this.setState((oldState) => {
|
|
138
151
|
const tabs = copy(oldState.tabs)
|
|
139
152
|
const index = typeof _index === 'undefined'
|
|
@@ -147,15 +160,17 @@ class Sessions extends Component {
|
|
|
147
160
|
}
|
|
148
161
|
tab.batch = this.props.batch
|
|
149
162
|
tabs.splice(index, 0, tab)
|
|
150
|
-
this.updateStoreTabs(tabs)
|
|
151
|
-
this.updateStoreCurrentTabId(tab.id)
|
|
152
163
|
return {
|
|
153
164
|
currentTabId: tab.id,
|
|
154
165
|
tabs
|
|
155
166
|
}
|
|
167
|
+
}, () => {
|
|
168
|
+
this.updateStoreTabs(this.state.tabs)
|
|
169
|
+
this.updateStoreCurrentTabId(this.state.currentTabId)
|
|
156
170
|
})
|
|
157
171
|
}
|
|
158
172
|
|
|
173
|
+
// After
|
|
159
174
|
delTab = (id) => {
|
|
160
175
|
this.setState((oldState) => {
|
|
161
176
|
const tabs = copy(oldState.tabs)
|
|
@@ -168,13 +183,16 @@ class Sessions extends Component {
|
|
|
168
183
|
i = i ? i - 1 : i + 1
|
|
169
184
|
const next = tabs[i] || {}
|
|
170
185
|
up.currentTabId = next.id || ''
|
|
171
|
-
this.updateStoreCurrentTabId(next.id)
|
|
172
186
|
}
|
|
173
187
|
up.tabs = tabs.filter(t => {
|
|
174
188
|
return t.id !== id
|
|
175
189
|
})
|
|
176
|
-
this.updateStoreTabs(up.tabs)
|
|
177
190
|
return up
|
|
191
|
+
}, () => {
|
|
192
|
+
this.updateStoreTabs(this.state.tabs)
|
|
193
|
+
if (this.state.currentTabId !== id) {
|
|
194
|
+
this.updateStoreCurrentTabId(this.state.currentTabId)
|
|
195
|
+
}
|
|
178
196
|
})
|
|
179
197
|
}
|
|
180
198
|
|
|
@@ -185,6 +203,10 @@ class Sessions extends Component {
|
|
|
185
203
|
this.addTab(tab)
|
|
186
204
|
}
|
|
187
205
|
|
|
206
|
+
handleClick = () => {
|
|
207
|
+
window.store.currentTabId = this.state.currentTabId
|
|
208
|
+
}
|
|
209
|
+
|
|
188
210
|
reloadTab = async (tabToReload) => {
|
|
189
211
|
this.setState(async oldState => {
|
|
190
212
|
const tab = copy(
|
|
@@ -228,11 +250,15 @@ class Sessions extends Component {
|
|
|
228
250
|
if (!matchedTab) {
|
|
229
251
|
return
|
|
230
252
|
}
|
|
231
|
-
|
|
232
|
-
|
|
253
|
+
|
|
254
|
+
// Batch the updates
|
|
233
255
|
this.setState({
|
|
234
256
|
currentTabId: id
|
|
235
|
-
},
|
|
257
|
+
}, () => {
|
|
258
|
+
this.updateStoreCurrentTabId(id)
|
|
259
|
+
this.timer = setTimeout(window.store.triggerResize, 500)
|
|
260
|
+
this.postChange()
|
|
261
|
+
})
|
|
236
262
|
}
|
|
237
263
|
|
|
238
264
|
setTabs = tabs => {
|
|
@@ -347,6 +373,15 @@ class Sessions extends Component {
|
|
|
347
373
|
)
|
|
348
374
|
}
|
|
349
375
|
|
|
376
|
+
computeHeight = () => {
|
|
377
|
+
const {
|
|
378
|
+
tabsHeight
|
|
379
|
+
} = this.props
|
|
380
|
+
return this.props.height -
|
|
381
|
+
tabsHeight -
|
|
382
|
+
termControlHeight
|
|
383
|
+
}
|
|
384
|
+
|
|
350
385
|
renderSessions () {
|
|
351
386
|
const {
|
|
352
387
|
config, width, height
|
|
@@ -389,6 +424,7 @@ class Sessions extends Component {
|
|
|
389
424
|
'onChangeTabId',
|
|
390
425
|
'onDuplicateTab',
|
|
391
426
|
'reloadTab',
|
|
427
|
+
'computeHeight',
|
|
392
428
|
'delTab',
|
|
393
429
|
'addTab',
|
|
394
430
|
'editTab'
|
|
@@ -396,7 +432,12 @@ class Sessions extends Component {
|
|
|
396
432
|
}
|
|
397
433
|
if (type === terminalWebType) {
|
|
398
434
|
const webProps = {
|
|
399
|
-
tab
|
|
435
|
+
tab,
|
|
436
|
+
width,
|
|
437
|
+
height: this.computeHeight(),
|
|
438
|
+
...pick(this, [
|
|
439
|
+
'reloadTab'
|
|
440
|
+
])
|
|
400
441
|
}
|
|
401
442
|
return (
|
|
402
443
|
<div className={cls} key={id}>
|
|
@@ -461,6 +502,7 @@ class Sessions extends Component {
|
|
|
461
502
|
<div
|
|
462
503
|
className='sessions'
|
|
463
504
|
key='main-sess'
|
|
505
|
+
onClick={this.handleClick}
|
|
464
506
|
>
|
|
465
507
|
{this.renderSessions()}
|
|
466
508
|
</div>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* bookmark form
|
|
7
7
|
*/
|
|
8
|
-
import { useDelta, useConditionalEffect } from 'react-delta'
|
|
8
|
+
import { useDelta, useConditionalEffect } from 'react-delta-hooks'
|
|
9
9
|
import { ArrowDownOutlined, ArrowUpOutlined, SaveOutlined, ClearOutlined } from '@ant-design/icons'
|
|
10
10
|
import { Button, Input, notification, Form } from 'antd'
|
|
11
11
|
import Link from '../common/external-link'
|
|
@@ -10,6 +10,11 @@ export default () => {
|
|
|
10
10
|
shortcut: 'alt+r',
|
|
11
11
|
shortcutMac: 'alt+r'
|
|
12
12
|
},
|
|
13
|
+
{
|
|
14
|
+
name: 'app_cloneToNextLayout',
|
|
15
|
+
shortcut: 'ctrl+/',
|
|
16
|
+
shortcutMac: 'meta+/'
|
|
17
|
+
},
|
|
13
18
|
{
|
|
14
19
|
name: 'app_newBookmark',
|
|
15
20
|
shortcut: 'ctrl+n',
|
|
@@ -40,11 +45,6 @@ export default () => {
|
|
|
40
45
|
shortcut: 'ctrl+tab',
|
|
41
46
|
shortcutMac: 'ctrl+tab'
|
|
42
47
|
},
|
|
43
|
-
{
|
|
44
|
-
name: 'terminal_split',
|
|
45
|
-
shortcut: 'ctrl+/',
|
|
46
|
-
shortcutMac: 'meta+/'
|
|
47
|
-
},
|
|
48
48
|
{
|
|
49
49
|
name: 'terminal_clear',
|
|
50
50
|
shortcut: 'ctrl+l,ctrl+shift+l',
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
Loading3QuartersOutlined,
|
|
10
10
|
BorderlessTableOutlined
|
|
11
11
|
} from '@ant-design/icons'
|
|
12
|
-
import generate from '../../common/id-with-stamp'
|
|
13
12
|
import { Tooltip, message } from 'antd'
|
|
14
13
|
import classnames from 'classnames'
|
|
15
14
|
import copy from 'json-deep-copy'
|
|
@@ -18,10 +17,7 @@ import Input from '../common/input-auto-focus'
|
|
|
18
17
|
import createName from '../../common/create-title'
|
|
19
18
|
import { addClass, removeClass } from '../../common/class'
|
|
20
19
|
import {
|
|
21
|
-
terminalSshConfigType
|
|
22
|
-
splitConfig,
|
|
23
|
-
paneMap,
|
|
24
|
-
statusMap
|
|
20
|
+
terminalSshConfigType
|
|
25
21
|
} from '../../common/constants'
|
|
26
22
|
import { shortcutDescExtend } from '../shortcuts/shortcut-handler.js'
|
|
27
23
|
|
|
@@ -203,18 +199,7 @@ class Tab extends Component {
|
|
|
203
199
|
}
|
|
204
200
|
|
|
205
201
|
cloneToNextLayout = () => {
|
|
206
|
-
|
|
207
|
-
const { batch, layout } = this.props
|
|
208
|
-
const ntb = copy(this.state.tab)
|
|
209
|
-
Object.assign(ntb, {
|
|
210
|
-
id: generate(),
|
|
211
|
-
status: defaultStatus,
|
|
212
|
-
isTransporting: undefined,
|
|
213
|
-
pane: paneMap.terminal
|
|
214
|
-
})
|
|
215
|
-
const maxBatch = splitConfig[layout].children
|
|
216
|
-
ntb.batch = (batch + 1) % maxBatch
|
|
217
|
-
window.store.addTab(ntb)
|
|
202
|
+
window.store.cloneToNextLayout()
|
|
218
203
|
}
|
|
219
204
|
|
|
220
205
|
newTab = () => {
|
|
@@ -280,17 +265,20 @@ class Tab extends Component {
|
|
|
280
265
|
}
|
|
281
266
|
|
|
282
267
|
renderContext = () => {
|
|
283
|
-
const { tabs, tab
|
|
268
|
+
const { tabs, tab } = this.props
|
|
284
269
|
const len = tabs.length
|
|
285
270
|
const index = findIndex(tabs, t => t.id === tab.id)
|
|
286
271
|
const noRight = index >= len - 1
|
|
287
272
|
const isSshConfig = tab.type === terminalSshConfigType
|
|
288
273
|
const res = []
|
|
289
274
|
const reloadShortcut = this.getShortcut('app_reloadCurrentTab')
|
|
275
|
+
const closeShortcut = this.getShortcut('app_closeCurrentTab')
|
|
276
|
+
const cloneToNextShortcut = this.getShortcut('app_cloneToNextLayout')
|
|
290
277
|
res.push({
|
|
291
278
|
func: 'handleClose',
|
|
292
279
|
icon: 'CloseOutlined',
|
|
293
|
-
text: e('close')
|
|
280
|
+
text: e('close'),
|
|
281
|
+
subText: closeShortcut
|
|
294
282
|
})
|
|
295
283
|
res.push({
|
|
296
284
|
func: 'closeOther',
|
|
@@ -314,13 +302,12 @@ class Tab extends Component {
|
|
|
314
302
|
icon: 'CopyOutlined',
|
|
315
303
|
text: e('duplicate')
|
|
316
304
|
})
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
305
|
+
res.push({
|
|
306
|
+
func: 'cloneToNextLayout',
|
|
307
|
+
icon: 'CopyOutlined',
|
|
308
|
+
text: e('cloneToNextLayout'),
|
|
309
|
+
subText: cloneToNextShortcut
|
|
310
|
+
})
|
|
324
311
|
res.push({
|
|
325
312
|
disabled: isSshConfig,
|
|
326
313
|
func: 'doRename',
|
|
@@ -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
|
+
}
|
|
@@ -31,25 +31,24 @@ import {
|
|
|
31
31
|
} from '../../common/constants'
|
|
32
32
|
import deepCopy from 'json-deep-copy'
|
|
33
33
|
import { readClipboardAsync, copy } from '../../common/clipboard'
|
|
34
|
-
import { FitAddon } from 'xterm
|
|
34
|
+
import { FitAddon } from '@xterm/addon-fit'
|
|
35
35
|
import AttachAddon from './attach-addon-custom'
|
|
36
|
-
import { SearchAddon } from 'xterm
|
|
37
|
-
import { WebLinksAddon } from 'xterm
|
|
38
|
-
import { CanvasAddon } from 'xterm
|
|
39
|
-
import { WebglAddon } from 'xterm
|
|
40
|
-
import { LigaturesAddon } from 'xterm
|
|
36
|
+
import { SearchAddon } from '@xterm/addon-search'
|
|
37
|
+
import { WebLinksAddon } from '@xterm/addon-web-links'
|
|
38
|
+
import { CanvasAddon } from '@xterm/addon-canvas'
|
|
39
|
+
import { WebglAddon } from '@xterm/addon-webgl'
|
|
40
|
+
import { LigaturesAddon } from '@xterm/addon-ligatures'
|
|
41
41
|
import getProxy from '../../common/get-proxy'
|
|
42
42
|
import { AddonZmodem } from './xterm-zmodem'
|
|
43
|
-
import { Unicode11Addon } from 'xterm
|
|
43
|
+
import { Unicode11Addon } from '@xterm/addon-unicode11'
|
|
44
44
|
import keyControlPressed from '../../common/key-control-pressed'
|
|
45
|
-
import { Terminal } from 'xterm'
|
|
45
|
+
import { Terminal } from '@xterm/xterm'
|
|
46
46
|
import NormalBuffer from './normal-buffer'
|
|
47
47
|
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,
|
|
@@ -1237,6 +1235,7 @@ clear\r`
|
|
|
1237
1235
|
new KeywordHighlighterAddon(keywords)
|
|
1238
1236
|
)
|
|
1239
1237
|
window.store.triggerResize()
|
|
1238
|
+
window.store.focus()
|
|
1240
1239
|
}
|
|
1241
1240
|
|
|
1242
1241
|
onResize = throttle(() => {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Input,
|
|
3
|
+
Tooltip
|
|
4
|
+
} from 'antd'
|
|
5
|
+
import { copy } from '../../common/clipboard'
|
|
6
|
+
import {
|
|
7
|
+
ReloadOutlined,
|
|
8
|
+
GlobalOutlined
|
|
9
|
+
} from '@ant-design/icons'
|
|
10
|
+
|
|
11
|
+
export default function AddressBar (props) {
|
|
12
|
+
const {
|
|
13
|
+
url,
|
|
14
|
+
onReload,
|
|
15
|
+
onOpen,
|
|
16
|
+
title,
|
|
17
|
+
description
|
|
18
|
+
} = props
|
|
19
|
+
const content = (
|
|
20
|
+
<div>
|
|
21
|
+
<h1>{title}</h1>
|
|
22
|
+
<p>{description}</p>
|
|
23
|
+
</div>
|
|
24
|
+
)
|
|
25
|
+
function handleClick () {
|
|
26
|
+
copy(url)
|
|
27
|
+
}
|
|
28
|
+
return (
|
|
29
|
+
<div className='web-address-bar pd1'>
|
|
30
|
+
<Tooltip
|
|
31
|
+
title={content}
|
|
32
|
+
>
|
|
33
|
+
<Input
|
|
34
|
+
value={url}
|
|
35
|
+
onClick={handleClick}
|
|
36
|
+
addonBefore={
|
|
37
|
+
<ReloadOutlined
|
|
38
|
+
onClick={onReload}
|
|
39
|
+
/>
|
|
40
|
+
}
|
|
41
|
+
addonAfter={
|
|
42
|
+
<GlobalOutlined
|
|
43
|
+
onClick={onOpen}
|
|
44
|
+
/>
|
|
45
|
+
}
|
|
46
|
+
/>
|
|
47
|
+
</Tooltip>
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -1,19 +1,41 @@
|
|
|
1
|
-
import
|
|
2
|
-
import Link from '../common/external-link'
|
|
1
|
+
import AddressBar from './address-bar'
|
|
3
2
|
|
|
4
3
|
export default function WebSession (props) {
|
|
5
4
|
const {
|
|
6
|
-
tab
|
|
5
|
+
tab,
|
|
6
|
+
width,
|
|
7
|
+
height,
|
|
8
|
+
reloadTab
|
|
7
9
|
} = props
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const addrProps = {
|
|
11
|
+
url: tab.url,
|
|
12
|
+
title: tab.title,
|
|
13
|
+
description: tab.description,
|
|
14
|
+
onOpen: () => {
|
|
15
|
+
window.openLink(tab.url)
|
|
16
|
+
},
|
|
17
|
+
onReload: () => {
|
|
18
|
+
reloadTab(
|
|
19
|
+
tab
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const viewProps = {
|
|
24
|
+
src: tab.url,
|
|
25
|
+
style: {
|
|
26
|
+
width: (width - 10) + 'px',
|
|
27
|
+
height: (height - 12) + 'px'
|
|
28
|
+
},
|
|
29
|
+
disableblinkfeatures: 'true',
|
|
30
|
+
disablewebsecurity: 'true'
|
|
31
|
+
}
|
|
11
32
|
return (
|
|
12
33
|
<div className='web-session-wrap'>
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
<
|
|
16
|
-
|
|
34
|
+
<AddressBar {...addrProps} />
|
|
35
|
+
<div className='pd1'>
|
|
36
|
+
<webview
|
|
37
|
+
{...viewProps}
|
|
38
|
+
/>
|
|
17
39
|
</div>
|
|
18
40
|
</div>
|
|
19
41
|
)
|
package/client/entry/index.jsx
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRoot } from 'react-dom/client'
|
|
2
2
|
import 'antd/dist/reset.css'
|
|
3
|
-
import 'xterm/css/xterm.css'
|
|
3
|
+
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
|
-
const rootElement = document.getElementById('container')
|
|
13
|
-
render(
|
|
14
|
-
<Main
|
|
15
|
-
rootElement
|
|
8
|
+
const rootElement = createRoot(document.getElementById('container'))
|
|
9
|
+
rootElement.render(
|
|
10
|
+
<Main />
|
|
16
11
|
)
|
|
@@ -9,7 +9,7 @@ import initWatch from './watch'
|
|
|
9
9
|
export default (Store) => {
|
|
10
10
|
Store.prototype.checkForDbUpgrade = async function () {
|
|
11
11
|
const { store } = window
|
|
12
|
-
if (store.
|
|
12
|
+
if (store.isSecondInstance) {
|
|
13
13
|
return false
|
|
14
14
|
}
|
|
15
15
|
const shouldUpgrade = await window.pre.runGlobalAsync('checkDbUpgrade')
|
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/setting.js
CHANGED
package/client/store/tab.js
CHANGED
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
import { uniq, debounce, findIndex } from 'lodash-es'
|
|
6
6
|
import {
|
|
7
7
|
tabActions,
|
|
8
|
-
splitConfig
|
|
8
|
+
splitConfig,
|
|
9
|
+
statusMap,
|
|
10
|
+
paneMap
|
|
9
11
|
} from '../common/constants'
|
|
10
12
|
import postMsg from '../common/post-msg'
|
|
11
13
|
import * as ls from '../common/safe-local-storage'
|
|
12
14
|
import deepCopy from 'json-deep-copy'
|
|
15
|
+
import generate from '../common/id-with-stamp'
|
|
13
16
|
|
|
14
17
|
export default Store => {
|
|
15
18
|
Store.prototype.updateTabsStatus = function () {
|
|
@@ -63,7 +66,7 @@ export default Store => {
|
|
|
63
66
|
postMsg({
|
|
64
67
|
action: tabActions.addTab,
|
|
65
68
|
tab,
|
|
66
|
-
batch: window.openTabBatch ?? window.store.currentLayoutBatch,
|
|
69
|
+
batch: tab?.batch ?? window.openTabBatch ?? window.store.currentLayoutBatch,
|
|
67
70
|
index
|
|
68
71
|
})
|
|
69
72
|
}
|
|
@@ -96,6 +99,28 @@ export default Store => {
|
|
|
96
99
|
}
|
|
97
100
|
}
|
|
98
101
|
|
|
102
|
+
Store.prototype.cloneToNextLayout = function () {
|
|
103
|
+
const { store } = window
|
|
104
|
+
const defaultStatus = statusMap.processing
|
|
105
|
+
const { currentTab, layout, currentLayoutBatch } = store
|
|
106
|
+
const ntb = deepCopy(currentTab)
|
|
107
|
+
Object.assign(ntb, {
|
|
108
|
+
id: generate(),
|
|
109
|
+
status: defaultStatus,
|
|
110
|
+
isTransporting: undefined,
|
|
111
|
+
pane: paneMap.terminal
|
|
112
|
+
})
|
|
113
|
+
let maxBatch = splitConfig[layout].children
|
|
114
|
+
if (maxBatch < 2) {
|
|
115
|
+
maxBatch = 2
|
|
116
|
+
}
|
|
117
|
+
ntb.batch = (currentLayoutBatch + 1) % maxBatch
|
|
118
|
+
store.addTab(ntb)
|
|
119
|
+
if (layout === 'c1') {
|
|
120
|
+
store.setLayout('c2')
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
99
124
|
Store.prototype.setLayout = function (layout) {
|
|
100
125
|
const {
|
|
101
126
|
store
|
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
|