@electerm/electerm-react 1.39.5 → 1.39.31
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/common/constants.js +7 -3
- package/client/common/create-title.jsx +12 -2
- package/client/common/default-setting.js +5 -0
- package/client/common/init-setting-item.js +6 -0
- package/client/components/bookmark-form/form-ssh-common.jsx +1 -1
- package/client/components/bookmark-form/index.jsx +6 -2
- package/client/components/bookmark-form/rdp-form-ui.jsx +1 -1
- package/client/components/bookmark-form/rdp-form.jsx +1 -1
- package/client/components/bookmark-form/render-auth-ssh.jsx +27 -1
- package/client/components/bookmark-form/render-ssh-tunnel.jsx +60 -31
- package/client/components/bookmark-form/use-ui.jsx +12 -0
- package/client/components/bookmark-form/vnc-form-ui.jsx +179 -0
- package/client/components/bookmark-form/vnc-form.jsx +16 -0
- package/client/components/footer/footer-entry.jsx +13 -6
- package/client/components/main/term-fullscreen.styl +4 -1
- package/client/components/profile/profile-form-elem.jsx +87 -0
- package/client/components/profile/profile-form.jsx +33 -0
- package/client/components/profile/profile-list.jsx +79 -0
- package/client/components/profile/profile-transport-mod.jsx +5 -0
- package/client/components/profile/profile-transport.jsx +12 -0
- package/client/components/quick-commands/quick-command-transport-mod.jsx +13 -14
- package/client/components/quick-commands/quick-commands-list-form.jsx +54 -3
- package/client/components/rdp/rdp-session.jsx +53 -36
- package/client/components/session/session.jsx +14 -3
- package/client/components/session/session.styl +7 -2
- package/client/components/setting-panel/setting-modal.jsx +23 -6
- package/client/components/setting-panel/setting-terminal.jsx +1 -1
- package/client/components/setting-panel/setting-wrap.jsx +5 -1
- package/client/components/setting-panel/setting-wrap.styl +5 -3
- package/client/components/setting-panel/tab-profiles.jsx +38 -0
- package/client/components/sftp/list-table-ui.jsx +99 -46
- package/client/components/sftp/sftp-entry.jsx +1 -0
- package/client/components/sftp/sftp.styl +4 -1
- package/client/components/sftp/transfer-common.js +1 -1
- package/client/components/tabs/index.jsx +1 -1
- package/client/components/tabs/tab.jsx +9 -4
- package/client/components/terminal/index.jsx +5 -5
- package/client/components/vnc/vnc-form.jsx +66 -0
- package/client/components/vnc/vnc-session.jsx +297 -0
- package/client/store/common.js +21 -0
- package/client/store/index.js +1 -0
- package/client/store/init-state.js +4 -23
- package/client/store/load-data.js +9 -2
- package/client/store/sync.js +7 -3
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import SettingCol from './col'
|
|
2
|
+
import ProfileForm from '../profile/profile-form'
|
|
3
|
+
import ProfileList from '../profile/profile-list'
|
|
4
|
+
import {
|
|
5
|
+
settingMap
|
|
6
|
+
} from '../../common/constants'
|
|
7
|
+
|
|
8
|
+
export default function TabProfiles (props) {
|
|
9
|
+
const {
|
|
10
|
+
settingTab
|
|
11
|
+
} = props
|
|
12
|
+
if (settingTab !== settingMap.profiles) {
|
|
13
|
+
return null
|
|
14
|
+
}
|
|
15
|
+
const {
|
|
16
|
+
settingItem,
|
|
17
|
+
listProps,
|
|
18
|
+
formProps,
|
|
19
|
+
store
|
|
20
|
+
} = props
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
className='setting-tabs-profile'
|
|
24
|
+
>
|
|
25
|
+
<SettingCol>
|
|
26
|
+
<ProfileList
|
|
27
|
+
{...listProps}
|
|
28
|
+
quickCommandId={store.quickCommandId}
|
|
29
|
+
/>
|
|
30
|
+
<ProfileForm
|
|
31
|
+
{...formProps}
|
|
32
|
+
quickCommandTags={store.quickCommandTags}
|
|
33
|
+
key={settingItem.id}
|
|
34
|
+
/>
|
|
35
|
+
</SettingCol>
|
|
36
|
+
</div>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* - click header to sort
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import { Component } from '../common/react-subx'
|
|
10
10
|
import classnames from 'classnames'
|
|
11
11
|
import { isEqual, pick, find, isNull, isArray, isUndefined } from 'lodash-es'
|
|
12
12
|
import generate from '../../common/uid'
|
|
@@ -17,24 +17,32 @@ import {
|
|
|
17
17
|
maxDragMove,
|
|
18
18
|
sftpControlHeight,
|
|
19
19
|
eventTypes,
|
|
20
|
-
paneMap
|
|
21
|
-
commonActions
|
|
20
|
+
paneMap
|
|
22
21
|
} from '../../common/constants'
|
|
23
22
|
import copy from 'json-deep-copy'
|
|
24
23
|
import FileSection from './file-item'
|
|
25
24
|
import PagedList from './paged-list'
|
|
26
25
|
import {
|
|
27
26
|
DownOutlined,
|
|
28
|
-
UpOutlined
|
|
27
|
+
UpOutlined,
|
|
28
|
+
CheckOutlined
|
|
29
29
|
} from '@ant-design/icons'
|
|
30
|
+
import IconHolder from '../context-menu/icon-holder'
|
|
30
31
|
|
|
31
32
|
const { prefix } = window
|
|
32
33
|
const e = prefix('sftp')
|
|
33
34
|
|
|
34
|
-
export default class FileListTable extends
|
|
35
|
+
export default class FileListTable extends Component {
|
|
35
36
|
constructor (props) {
|
|
36
37
|
super(props)
|
|
37
|
-
this.state =
|
|
38
|
+
this.state = {
|
|
39
|
+
...this.initFromProps(),
|
|
40
|
+
showContextMenu: false,
|
|
41
|
+
contextMenuPos: {
|
|
42
|
+
left: 0,
|
|
43
|
+
top: 0
|
|
44
|
+
}
|
|
45
|
+
}
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
componentDidMount () {
|
|
@@ -61,10 +69,37 @@ export default class FileListTable extends React.Component {
|
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
componentWillUnmount () {
|
|
64
|
-
window.removeEventListener('message', this.onContextAction)
|
|
65
72
|
window.removeEventListener('message', this.onMsg)
|
|
66
73
|
}
|
|
67
74
|
|
|
75
|
+
setOnCloseEvent = () => {
|
|
76
|
+
const dom = document
|
|
77
|
+
.querySelector('.ant-drawer')
|
|
78
|
+
if (dom) {
|
|
79
|
+
dom.addEventListener('click', this.onTriggerClose)
|
|
80
|
+
}
|
|
81
|
+
document
|
|
82
|
+
.getElementById('outside-context')
|
|
83
|
+
.addEventListener('click', this.onTriggerClose)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
onTriggerClose = (e) => {
|
|
87
|
+
if (e.target.closest('.context-menu')) {
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
this.setState({
|
|
91
|
+
showContextMenu: false
|
|
92
|
+
})
|
|
93
|
+
const dom = document
|
|
94
|
+
.querySelector('.ant-drawer')
|
|
95
|
+
if (dom) {
|
|
96
|
+
dom.removeEventListener('click', this.onTriggerClose)
|
|
97
|
+
}
|
|
98
|
+
document
|
|
99
|
+
.getElementById('outside-context')
|
|
100
|
+
.removeEventListener('click', this.onTriggerClose)
|
|
101
|
+
}
|
|
102
|
+
|
|
68
103
|
toVisible = (prevProps, props) => {
|
|
69
104
|
return (
|
|
70
105
|
prevProps.pane === paneMap.ssh ||
|
|
@@ -128,7 +163,7 @@ export default class FileListTable extends React.Component {
|
|
|
128
163
|
}
|
|
129
164
|
|
|
130
165
|
getPropsDefault = () => {
|
|
131
|
-
return [
|
|
166
|
+
return this.props.store.config.filePropsEnabled || [
|
|
132
167
|
'name',
|
|
133
168
|
'size',
|
|
134
169
|
'modifyTime'
|
|
@@ -229,10 +264,7 @@ export default class FileListTable extends React.Component {
|
|
|
229
264
|
}
|
|
230
265
|
|
|
231
266
|
computePos = (e, height) => {
|
|
232
|
-
return
|
|
233
|
-
left: e.clientX,
|
|
234
|
-
top: e.clientY
|
|
235
|
-
}
|
|
267
|
+
return e.target.getBoundingClientRect()
|
|
236
268
|
}
|
|
237
269
|
|
|
238
270
|
onToggleProp = name => {
|
|
@@ -244,41 +276,22 @@ export default class FileListTable extends React.Component {
|
|
|
244
276
|
: [...names, name]
|
|
245
277
|
const props = all.filter(g => newProps.includes(g))
|
|
246
278
|
const update = this.initFromProps(props)
|
|
279
|
+
this.props.store.setConfig({
|
|
280
|
+
filePropsEnabled: props
|
|
281
|
+
})
|
|
247
282
|
this.setState(update)
|
|
248
283
|
}
|
|
249
284
|
|
|
250
|
-
onContextAction = e => {
|
|
251
|
-
const {
|
|
252
|
-
action,
|
|
253
|
-
id,
|
|
254
|
-
args = [],
|
|
255
|
-
func
|
|
256
|
-
} = e.data || {}
|
|
257
|
-
if (
|
|
258
|
-
action !== commonActions.clickContextMenu ||
|
|
259
|
-
id !== this.uid ||
|
|
260
|
-
!this[func]
|
|
261
|
-
) {
|
|
262
|
-
return false
|
|
263
|
-
}
|
|
264
|
-
window.removeEventListener('message', this.onContextAction)
|
|
265
|
-
this[func](...args)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
285
|
handleContextMenu = e => {
|
|
269
286
|
e && e.preventDefault()
|
|
270
|
-
const items = this.renderContext()
|
|
271
287
|
const pos = e
|
|
272
288
|
? this.computePos(e)
|
|
273
289
|
: this.pos
|
|
274
|
-
this.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
id: this.uid,
|
|
278
|
-
items,
|
|
279
|
-
pos
|
|
290
|
+
this.setState({
|
|
291
|
+
contextMenuPos: pos,
|
|
292
|
+
showContextMenu: true
|
|
280
293
|
})
|
|
281
|
-
|
|
294
|
+
this.setOnCloseEvent()
|
|
282
295
|
}
|
|
283
296
|
|
|
284
297
|
onClickName = (e) => {
|
|
@@ -318,18 +331,23 @@ export default class FileListTable extends React.Component {
|
|
|
318
331
|
const selected = selectedNames.includes(p)
|
|
319
332
|
const disabled = !i
|
|
320
333
|
const cls = classnames(
|
|
334
|
+
'context-item',
|
|
321
335
|
{ selected },
|
|
322
336
|
{ unselected: !selected }
|
|
323
337
|
)
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
disabled,
|
|
329
|
-
args: [p],
|
|
330
|
-
noCloseMenu: true,
|
|
331
|
-
className: cls
|
|
338
|
+
const icon = disabled || selected ? <CheckOutlined /> : <IconHolder />
|
|
339
|
+
const obj = {
|
|
340
|
+
className: cls,
|
|
341
|
+
onClick: () => this.onToggleProp(p)
|
|
332
342
|
}
|
|
343
|
+
return (
|
|
344
|
+
<div
|
|
345
|
+
{...obj}
|
|
346
|
+
key={p}
|
|
347
|
+
>
|
|
348
|
+
{icon} {e(p)}
|
|
349
|
+
</div>
|
|
350
|
+
)
|
|
333
351
|
})
|
|
334
352
|
}
|
|
335
353
|
|
|
@@ -519,6 +537,40 @@ export default class FileListTable extends React.Component {
|
|
|
519
537
|
)
|
|
520
538
|
}
|
|
521
539
|
|
|
540
|
+
renderContextMenu = () => {
|
|
541
|
+
const {
|
|
542
|
+
showContextMenu
|
|
543
|
+
} = this.state
|
|
544
|
+
if (!showContextMenu) {
|
|
545
|
+
return null
|
|
546
|
+
}
|
|
547
|
+
const {
|
|
548
|
+
left,
|
|
549
|
+
top
|
|
550
|
+
} = this.state.contextMenuPos
|
|
551
|
+
const outerProps = {
|
|
552
|
+
className: 'context-menu file-header-context-menu',
|
|
553
|
+
style: {
|
|
554
|
+
left: left + 'px',
|
|
555
|
+
top: top + 'px'
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
const innerProps = {
|
|
559
|
+
className: 'context-menu-inner'
|
|
560
|
+
}
|
|
561
|
+
return (
|
|
562
|
+
<div
|
|
563
|
+
{...outerProps}
|
|
564
|
+
>
|
|
565
|
+
<div
|
|
566
|
+
{...innerProps}
|
|
567
|
+
>
|
|
568
|
+
{this.renderContext()}
|
|
569
|
+
</div>
|
|
570
|
+
</div>
|
|
571
|
+
)
|
|
572
|
+
}
|
|
573
|
+
|
|
522
574
|
render () {
|
|
523
575
|
const { fileList, height, type } = this.props
|
|
524
576
|
const tableHeaderHeight = 30
|
|
@@ -539,6 +591,7 @@ export default class FileListTable extends React.Component {
|
|
|
539
591
|
return (
|
|
540
592
|
<div className={cls}>
|
|
541
593
|
{this.renderTableHeader()}
|
|
594
|
+
{this.renderContextMenu()}
|
|
542
595
|
<div
|
|
543
596
|
{...props}
|
|
544
597
|
>
|
|
@@ -358,9 +358,14 @@ class Tab extends Component {
|
|
|
358
358
|
sshTunnelLocalHost = '127.0.0.1',
|
|
359
359
|
name
|
|
360
360
|
} = obj
|
|
361
|
-
let tunnel
|
|
362
|
-
|
|
363
|
-
|
|
361
|
+
let tunnel
|
|
362
|
+
if (sshTunnel === 'dynamicForward') {
|
|
363
|
+
tunnel = `sock5://${sshTunnelLocalHost}:${sshTunnelLocalPort}`
|
|
364
|
+
} else {
|
|
365
|
+
tunnel = sshTunnel === 'forwardRemoteToLocal'
|
|
366
|
+
? `-> ${s('remote')}:${sshTunnelRemoteHost}:${sshTunnelRemotePort} -> ${sshTunnelLocalHost}:${sshTunnelLocalPort}`
|
|
367
|
+
: `-> ${s('local')}:${sshTunnelLocalHost}:${sshTunnelLocalPort} -> ${sshTunnelRemoteHost}:${sshTunnelRemotePort}`
|
|
368
|
+
}
|
|
364
369
|
if (error) {
|
|
365
370
|
tunnel = `error: ${tunnel}`
|
|
366
371
|
}
|
|
@@ -371,7 +376,7 @@ class Tab extends Component {
|
|
|
371
376
|
})
|
|
372
377
|
return (
|
|
373
378
|
<div>
|
|
374
|
-
<div
|
|
379
|
+
<div>{title}</div>
|
|
375
380
|
{list}
|
|
376
381
|
</div>
|
|
377
382
|
)
|
|
@@ -1025,8 +1025,9 @@ class Term extends Component {
|
|
|
1025
1025
|
const cmd = `ssh ${title.split(/\s/g)[0]}\r`
|
|
1026
1026
|
return this.attachAddon._sendData(cmd)
|
|
1027
1027
|
}
|
|
1028
|
-
|
|
1029
|
-
|
|
1028
|
+
const startFolder = startDirectory || window.initFolder
|
|
1029
|
+
if (startFolder) {
|
|
1030
|
+
const cmd = `cd "${startFolder}"\r`
|
|
1030
1031
|
this.attachAddon._sendData(cmd)
|
|
1031
1032
|
}
|
|
1032
1033
|
if (runScripts && runScripts.length) {
|
|
@@ -1048,8 +1049,6 @@ class Term extends Component {
|
|
|
1048
1049
|
}
|
|
1049
1050
|
}
|
|
1050
1051
|
|
|
1051
|
-
count = 0
|
|
1052
|
-
|
|
1053
1052
|
setStatus = status => {
|
|
1054
1053
|
const id = this.props.tab?.id
|
|
1055
1054
|
this.props.editTab(id, {
|
|
@@ -1093,7 +1092,7 @@ class Term extends Component {
|
|
|
1093
1092
|
server = ''
|
|
1094
1093
|
} = config
|
|
1095
1094
|
const { sessionId, terminalIndex, id, logName } = this.props
|
|
1096
|
-
const tab = deepCopy(this.props.tab || {})
|
|
1095
|
+
const tab = window.store.applyProfile(deepCopy(this.props.tab || {}))
|
|
1097
1096
|
const {
|
|
1098
1097
|
srcId, from = 'bookmarks',
|
|
1099
1098
|
type,
|
|
@@ -1126,6 +1125,7 @@ class Term extends Component {
|
|
|
1126
1125
|
'execLinuxArgs',
|
|
1127
1126
|
'debug'
|
|
1128
1127
|
]),
|
|
1128
|
+
keepaliveInterval: tab.keepaliveInterval === undefined ? config.keepaliveInterval : tab.keepaliveInterval,
|
|
1129
1129
|
sessionId,
|
|
1130
1130
|
tabId: id,
|
|
1131
1131
|
srcTabId: tab.id,
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* web form
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Input,
|
|
7
|
+
Form,
|
|
8
|
+
Button
|
|
9
|
+
} from 'antd'
|
|
10
|
+
import { formItemLayout, tailFormItemLayout } from '../../common/form-layout'
|
|
11
|
+
|
|
12
|
+
const FormItem = Form.Item
|
|
13
|
+
const { prefix } = window
|
|
14
|
+
const e = prefix('form')
|
|
15
|
+
const s = prefix('sftp')
|
|
16
|
+
|
|
17
|
+
export default function VncForm (props) {
|
|
18
|
+
const [form] = Form.useForm()
|
|
19
|
+
|
|
20
|
+
const initialValues = props.types.reduce((acc, cur) => {
|
|
21
|
+
acc[cur] = ''
|
|
22
|
+
return acc
|
|
23
|
+
}, {})
|
|
24
|
+
function renderCommon () {
|
|
25
|
+
const {
|
|
26
|
+
types
|
|
27
|
+
} = props
|
|
28
|
+
return types.map((type, index) => {
|
|
29
|
+
const Elem = type === 'password' ? Input.Password : Input
|
|
30
|
+
return (
|
|
31
|
+
<FormItem
|
|
32
|
+
{...formItemLayout}
|
|
33
|
+
label={e(type)}
|
|
34
|
+
name={type}
|
|
35
|
+
key={type}
|
|
36
|
+
autoFocus={index === 0}
|
|
37
|
+
>
|
|
38
|
+
<Elem />
|
|
39
|
+
</FormItem>
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Form
|
|
46
|
+
form={form}
|
|
47
|
+
onFinish={props.handleFinish}
|
|
48
|
+
initialValues={initialValues}
|
|
49
|
+
name='vnc-form'
|
|
50
|
+
>
|
|
51
|
+
<div className='pd3t pd1b'>
|
|
52
|
+
{renderCommon()}
|
|
53
|
+
<FormItem
|
|
54
|
+
{...tailFormItemLayout}
|
|
55
|
+
>
|
|
56
|
+
<Button
|
|
57
|
+
type='primary'
|
|
58
|
+
htmlType='submit'
|
|
59
|
+
>
|
|
60
|
+
{s('submit')}
|
|
61
|
+
</Button>
|
|
62
|
+
</FormItem>
|
|
63
|
+
</div>
|
|
64
|
+
</Form>
|
|
65
|
+
)
|
|
66
|
+
}
|