@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,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
message,
|
|
4
|
+
Button
|
|
5
|
+
} from 'antd'
|
|
6
|
+
import generate from '../../common/uid'
|
|
7
|
+
import InputAutoFocus from '../common/input-auto-focus'
|
|
8
|
+
import renderAuth from '../bookmark-form/render-auth-ssh'
|
|
9
|
+
import { formItemLayout } from '../../common/form-layout'
|
|
10
|
+
import {
|
|
11
|
+
settingMap
|
|
12
|
+
} from '../../common/constants'
|
|
13
|
+
const FormItem = Form.Item
|
|
14
|
+
const { prefix } = window
|
|
15
|
+
const e = prefix('form')
|
|
16
|
+
const s = prefix('setting')
|
|
17
|
+
const ss = prefix('sftp')
|
|
18
|
+
|
|
19
|
+
export default function QuickCommandForm (props) {
|
|
20
|
+
const [form] = Form.useForm()
|
|
21
|
+
const { autofocustrigger } = props.store
|
|
22
|
+
async function handleSubmit (res) {
|
|
23
|
+
const { formData } = props
|
|
24
|
+
console.log(res)
|
|
25
|
+
const update1 = {
|
|
26
|
+
...res,
|
|
27
|
+
id: generate()
|
|
28
|
+
}
|
|
29
|
+
if (formData.id) {
|
|
30
|
+
props.store.editItem(formData.id, res, settingMap.profiles)
|
|
31
|
+
} else {
|
|
32
|
+
props.store.addItem(update1, settingMap.profiles)
|
|
33
|
+
props.store.setSettingItem({
|
|
34
|
+
id: '',
|
|
35
|
+
name: e('profile')
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
message.success(s('saved'))
|
|
39
|
+
}
|
|
40
|
+
return (
|
|
41
|
+
<Form
|
|
42
|
+
form={form}
|
|
43
|
+
onFinish={handleSubmit}
|
|
44
|
+
className='form-wrap pd2l'
|
|
45
|
+
layout='vertical'
|
|
46
|
+
initialValues={props.formData}
|
|
47
|
+
>
|
|
48
|
+
<FormItem
|
|
49
|
+
label={e('profileName')}
|
|
50
|
+
{...formItemLayout}
|
|
51
|
+
rules={[{
|
|
52
|
+
max: 60, message: '60 chars max'
|
|
53
|
+
}, {
|
|
54
|
+
required: true, message: 'Name required'
|
|
55
|
+
}]}
|
|
56
|
+
hasFeedback
|
|
57
|
+
name='name'
|
|
58
|
+
>
|
|
59
|
+
<InputAutoFocus
|
|
60
|
+
selectall='yes'
|
|
61
|
+
autofocustrigger={autofocustrigger}
|
|
62
|
+
/>
|
|
63
|
+
</FormItem>
|
|
64
|
+
{
|
|
65
|
+
renderAuth({
|
|
66
|
+
store: props.store,
|
|
67
|
+
form,
|
|
68
|
+
authType: 'password'
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
{
|
|
72
|
+
renderAuth({
|
|
73
|
+
store: props.store,
|
|
74
|
+
form
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
<FormItem>
|
|
78
|
+
<Button
|
|
79
|
+
type='primary'
|
|
80
|
+
htmlType='submit'
|
|
81
|
+
>
|
|
82
|
+
{ss('submit')}
|
|
83
|
+
</Button>
|
|
84
|
+
</FormItem>
|
|
85
|
+
</Form>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { PureComponent } from 'react'
|
|
2
|
+
import ProfileCommandForm from './profile-form-elem'
|
|
3
|
+
import { LoadingOutlined } from '@ant-design/icons'
|
|
4
|
+
|
|
5
|
+
export default class ProfleFormIndex extends PureComponent {
|
|
6
|
+
state = {
|
|
7
|
+
ready: false
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
componentDidMount () {
|
|
11
|
+
this.timer = setTimeout(() => {
|
|
12
|
+
this.setState({
|
|
13
|
+
ready: true
|
|
14
|
+
})
|
|
15
|
+
}, 200)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
componentWillUnmount () {
|
|
19
|
+
clearTimeout(this.timer)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
render () {
|
|
23
|
+
const { ready } = this.state
|
|
24
|
+
if (!ready) {
|
|
25
|
+
return (
|
|
26
|
+
<div className='pd3 aligncenter'>
|
|
27
|
+
<LoadingOutlined />
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
return <ProfileCommandForm {...this.props} />
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* quick command list render
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import List from '../setting-panel/list'
|
|
6
|
+
import { PlusOutlined } from '@ant-design/icons'
|
|
7
|
+
import classnames from 'classnames'
|
|
8
|
+
import highlight from '../common/highlight'
|
|
9
|
+
import ProfileTransport from './profile-transport'
|
|
10
|
+
import {
|
|
11
|
+
settingMap
|
|
12
|
+
} from '../../common/constants'
|
|
13
|
+
|
|
14
|
+
export default class ProfileList extends List {
|
|
15
|
+
del = (item, e) => {
|
|
16
|
+
e.stopPropagation()
|
|
17
|
+
this.props.store.delItem(item, settingMap.profiles)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
onClickItem = (item) => {
|
|
21
|
+
this.props.onClickItem(item)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
renderItem = (item, i) => {
|
|
25
|
+
if (!item) {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
const { activeItemId } = this.props
|
|
29
|
+
const { name, id } = item
|
|
30
|
+
const cls = classnames(
|
|
31
|
+
'item-list-unit theme-item',
|
|
32
|
+
{
|
|
33
|
+
active: activeItemId === id
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
let title = name
|
|
37
|
+
title = highlight(
|
|
38
|
+
title,
|
|
39
|
+
this.state.keyword
|
|
40
|
+
)
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
key={i + id}
|
|
44
|
+
className={cls}
|
|
45
|
+
onClick={() => this.onClickItem(item)}
|
|
46
|
+
data-id={id}
|
|
47
|
+
>
|
|
48
|
+
<div className='elli pd1y pd2x' title={name}>
|
|
49
|
+
{
|
|
50
|
+
!id
|
|
51
|
+
? <PlusOutlined className='mg1r' />
|
|
52
|
+
: null
|
|
53
|
+
}
|
|
54
|
+
{title}
|
|
55
|
+
</div>
|
|
56
|
+
{this.renderDelBtn(item)}
|
|
57
|
+
</div>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
renderTransport = () => {
|
|
62
|
+
return (
|
|
63
|
+
<ProfileTransport
|
|
64
|
+
store={this.props.store}
|
|
65
|
+
/>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
filter = list => {
|
|
70
|
+
const { keyword } = this.state
|
|
71
|
+
return keyword
|
|
72
|
+
? list.filter((item) => {
|
|
73
|
+
const n = (item.name || '').toLowerCase()
|
|
74
|
+
const k = keyword.toLowerCase()
|
|
75
|
+
return n.includes(k)
|
|
76
|
+
})
|
|
77
|
+
: list
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ProfileTransportMod from './profile-transport-mod'
|
|
2
|
+
import { Component } from '../common/react-subx'
|
|
3
|
+
|
|
4
|
+
export default class ProfileTransport extends Component {
|
|
5
|
+
render () {
|
|
6
|
+
return (
|
|
7
|
+
<div className='pd1b'>
|
|
8
|
+
<ProfileTransportMod store={this.props.store} />
|
|
9
|
+
</div>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -4,13 +4,14 @@ import time from '../../common/time'
|
|
|
4
4
|
import copy from 'json-deep-copy'
|
|
5
5
|
|
|
6
6
|
export default class QmTransport extends BookmarkTransport {
|
|
7
|
+
name = 'quickCommands'
|
|
7
8
|
beforeUpload = async (file) => {
|
|
8
9
|
const { store } = this.props
|
|
9
10
|
const txt = await window.fs.readFile(file.path)
|
|
10
11
|
try {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const bmTreeOld =
|
|
12
|
+
const arr = JSON.parse(txt)
|
|
13
|
+
const arrOld = copy(store[this.name])
|
|
14
|
+
const bmTreeOld = arrOld.reduce((p, v) => {
|
|
14
15
|
return {
|
|
15
16
|
...p,
|
|
16
17
|
[v.id]: v
|
|
@@ -18,19 +19,19 @@ export default class QmTransport extends BookmarkTransport {
|
|
|
18
19
|
}, {})
|
|
19
20
|
const add = []
|
|
20
21
|
const dbAdd = []
|
|
21
|
-
|
|
22
|
+
arr.forEach(bg => {
|
|
22
23
|
if (!bmTreeOld[bg.id]) {
|
|
23
|
-
|
|
24
|
+
arrOld.push(bg)
|
|
24
25
|
add.push(bg)
|
|
25
26
|
dbAdd.push({
|
|
26
|
-
db:
|
|
27
|
+
db: this.name,
|
|
27
28
|
obj: bg
|
|
28
29
|
})
|
|
29
30
|
}
|
|
30
31
|
})
|
|
31
|
-
store.
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
store.setState(
|
|
33
|
+
this.name, arrOld
|
|
34
|
+
)
|
|
34
35
|
store.batchDbAdd(dbAdd)
|
|
35
36
|
} catch (e) {
|
|
36
37
|
store.onError(e)
|
|
@@ -44,11 +45,9 @@ export default class QmTransport extends BookmarkTransport {
|
|
|
44
45
|
|
|
45
46
|
handleDownload = () => {
|
|
46
47
|
const { store } = this.props
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
} = store
|
|
50
|
-
const txt = JSON.stringify(quickCommands, null, 2)
|
|
48
|
+
const arr = store[this.name]
|
|
49
|
+
const txt = JSON.stringify(arr, null, 2)
|
|
51
50
|
const stamp = time(undefined, 'YYYY-MM-DD-HH-mm-ss')
|
|
52
|
-
download('
|
|
51
|
+
download('electerm-' + this.name + '-' + stamp + '.json', txt)
|
|
53
52
|
}
|
|
54
53
|
}
|
|
@@ -3,10 +3,14 @@ import {
|
|
|
3
3
|
InputNumber,
|
|
4
4
|
Space,
|
|
5
5
|
Button,
|
|
6
|
-
Input
|
|
6
|
+
Input,
|
|
7
|
+
Tag
|
|
7
8
|
} from 'antd'
|
|
8
9
|
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'
|
|
9
10
|
import { formItemLayout } from '../../common/form-layout'
|
|
11
|
+
import HelpIcon from '../common/help-icon'
|
|
12
|
+
import { copy } from '../../common/clipboard'
|
|
13
|
+
import { useRef } from 'react'
|
|
10
14
|
|
|
11
15
|
const FormItem = Form.Item
|
|
12
16
|
const FormList = Form.List
|
|
@@ -14,6 +18,7 @@ const { prefix } = window
|
|
|
14
18
|
const t = prefix('quickCommands')
|
|
15
19
|
|
|
16
20
|
export default function renderQm () {
|
|
21
|
+
const focused = useRef(0)
|
|
17
22
|
function renderItem (field, i, add, remove) {
|
|
18
23
|
return (
|
|
19
24
|
<Space
|
|
@@ -43,7 +48,10 @@ export default function renderQm () {
|
|
|
43
48
|
<Input.TextArea
|
|
44
49
|
rows={1}
|
|
45
50
|
placeholder={t('quickCommand')}
|
|
46
|
-
className='compact-input'
|
|
51
|
+
className='compact-input qm-input'
|
|
52
|
+
onFocus={() => {
|
|
53
|
+
focused.current = i
|
|
54
|
+
}}
|
|
47
55
|
/>
|
|
48
56
|
</FormItem>
|
|
49
57
|
<Button
|
|
@@ -54,9 +62,52 @@ export default function renderQm () {
|
|
|
54
62
|
</Space>
|
|
55
63
|
)
|
|
56
64
|
}
|
|
65
|
+
const commonCmds = [
|
|
66
|
+
{ cmd: 'ls', desc: 'List directory contents' },
|
|
67
|
+
{ cmd: 'cd', desc: 'Change the current directory' },
|
|
68
|
+
{ cmd: 'pwd', desc: 'Print the current working directory' },
|
|
69
|
+
{ cmd: 'cp', desc: 'Copy files and directories' },
|
|
70
|
+
{ cmd: 'mv', desc: 'Move/rename files and directories' },
|
|
71
|
+
{ cmd: 'rm', desc: 'Remove files or directories' },
|
|
72
|
+
{ cmd: 'mkdir', desc: 'Create new directories' },
|
|
73
|
+
{ cmd: 'rmdir', desc: 'Remove empty directories' },
|
|
74
|
+
{ cmd: 'touch', desc: 'Create empty files or update file timestamps' },
|
|
75
|
+
{ cmd: 'chmod', desc: 'Change file modes or Access Control Lists' },
|
|
76
|
+
{ cmd: 'chown', desc: 'Change file owner and group' },
|
|
77
|
+
{ cmd: 'cat', desc: 'Concatenate and display file content' },
|
|
78
|
+
{ cmd: 'echo', desc: 'Display message or variable value' },
|
|
79
|
+
{ cmd: 'grep', desc: 'Search text using patterns' },
|
|
80
|
+
{ cmd: 'find', desc: 'Search for files in a directory hierarchy' },
|
|
81
|
+
{ cmd: 'df', desc: 'Report file system disk space usage' },
|
|
82
|
+
{ cmd: 'du', desc: 'Estimate file space usage' },
|
|
83
|
+
{ cmd: 'top', desc: 'Display Linux tasks' },
|
|
84
|
+
{ cmd: 'ps', desc: 'Report a snapshot of current processes' },
|
|
85
|
+
{ cmd: 'kill', desc: 'Send a signal to a process' }
|
|
86
|
+
]
|
|
57
87
|
|
|
88
|
+
const cmds = commonCmds.map(c => {
|
|
89
|
+
return (
|
|
90
|
+
<Tag
|
|
91
|
+
title={c.desc}
|
|
92
|
+
key={c.cmd}
|
|
93
|
+
onClick={() => {
|
|
94
|
+
copy(c.cmd)
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
<b className='pointer'>{c.cmd}</b>
|
|
98
|
+
</Tag>
|
|
99
|
+
)
|
|
100
|
+
})
|
|
101
|
+
const label = (
|
|
102
|
+
<div>
|
|
103
|
+
{t('commonCommands')}
|
|
104
|
+
<HelpIcon
|
|
105
|
+
title={cmds}
|
|
106
|
+
/>
|
|
107
|
+
</div>
|
|
108
|
+
)
|
|
58
109
|
return (
|
|
59
|
-
<FormItem {...formItemLayout} label={
|
|
110
|
+
<FormItem {...formItemLayout} label={label}>
|
|
60
111
|
<FormList
|
|
61
112
|
name='commands'
|
|
62
113
|
>
|
|
@@ -70,7 +70,7 @@ export default class RdpSession extends Component {
|
|
|
70
70
|
openedSideBar
|
|
71
71
|
} = this.props
|
|
72
72
|
return {
|
|
73
|
-
width: width - (pinned && openedSideBar ? leftSidebarWidth : 0),
|
|
73
|
+
width: width - (pinned && openedSideBar ? leftSidebarWidth : 0) - 42,
|
|
74
74
|
height: height - tabsHeight
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -235,7 +235,7 @@ export default class RdpSession extends Component {
|
|
|
235
235
|
const isHorizontal = false
|
|
236
236
|
const delta = isHorizontal ? e.deltaX : e.deltaY
|
|
237
237
|
const step = Math.round(Math.abs(delta) * 15 / 8)
|
|
238
|
-
console.log(x, y, step, delta, isHorizontal)
|
|
238
|
+
// console.log(x, y, step, delta, isHorizontal)
|
|
239
239
|
params = [x, y, step, delta > 0, isHorizontal]
|
|
240
240
|
} else if (type === 'keydown' || type === 'keyup') {
|
|
241
241
|
params = [keyCode, pressed]
|
|
@@ -349,6 +349,14 @@ export default class RdpSession extends Component {
|
|
|
349
349
|
this.setState(res, this.handleReInit)
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
renderHelp = () => {
|
|
353
|
+
return (
|
|
354
|
+
<HelpIcon
|
|
355
|
+
link={rdpHelpLink}
|
|
356
|
+
/>
|
|
357
|
+
)
|
|
358
|
+
}
|
|
359
|
+
|
|
352
360
|
renderControl = () => {
|
|
353
361
|
const {
|
|
354
362
|
id
|
|
@@ -358,45 +366,54 @@ export default class RdpSession extends Component {
|
|
|
358
366
|
onChange: this.handleResChange,
|
|
359
367
|
popupMatchSelectWidth: false
|
|
360
368
|
}
|
|
369
|
+
return (
|
|
370
|
+
<div className='pd1 fix session-v-info'>
|
|
371
|
+
<div className='fleft'>
|
|
372
|
+
<ReloadOutlined
|
|
373
|
+
onClick={this.handleReInit}
|
|
374
|
+
className='mg2r mg1l pointer'
|
|
375
|
+
/>
|
|
376
|
+
<Select
|
|
377
|
+
{...sleProps}
|
|
378
|
+
>
|
|
379
|
+
{
|
|
380
|
+
this.getAllRes().map(d => {
|
|
381
|
+
const v = d.id
|
|
382
|
+
return (
|
|
383
|
+
<Option
|
|
384
|
+
key={v}
|
|
385
|
+
value={v}
|
|
386
|
+
>
|
|
387
|
+
{d.width}x{d.height}
|
|
388
|
+
</Option>
|
|
389
|
+
)
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
</Select>
|
|
393
|
+
<EditOutlined
|
|
394
|
+
onClick={this.handleEditResolutions}
|
|
395
|
+
className='mg2r mg1l pointer'
|
|
396
|
+
/>
|
|
397
|
+
{this.renderInfo()}
|
|
398
|
+
{this.renderHelp()}
|
|
399
|
+
</div>
|
|
400
|
+
<div className='fright'>
|
|
401
|
+
{this.props.fullscreenIcon()}
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
renderInfo () {
|
|
361
408
|
const {
|
|
362
409
|
host,
|
|
363
410
|
port,
|
|
364
411
|
username
|
|
365
412
|
} = this.props.tab
|
|
366
413
|
return (
|
|
367
|
-
<
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
className='mg2r mg1l pointer'
|
|
371
|
-
/>
|
|
372
|
-
<Select
|
|
373
|
-
{...sleProps}
|
|
374
|
-
>
|
|
375
|
-
{
|
|
376
|
-
this.getAllRes().map(d => {
|
|
377
|
-
const v = d.id
|
|
378
|
-
return (
|
|
379
|
-
<Option
|
|
380
|
-
key={v}
|
|
381
|
-
value={v}
|
|
382
|
-
>
|
|
383
|
-
{d.width}x{d.height}
|
|
384
|
-
</Option>
|
|
385
|
-
)
|
|
386
|
-
})
|
|
387
|
-
}
|
|
388
|
-
</Select>
|
|
389
|
-
<EditOutlined
|
|
390
|
-
onClick={this.handleEditResolutions}
|
|
391
|
-
className='mg2r mg1l pointer'
|
|
392
|
-
/>
|
|
393
|
-
<span className='mg2l mg2r'>
|
|
394
|
-
{username}@{host}:{port}
|
|
395
|
-
</span>
|
|
396
|
-
<HelpIcon
|
|
397
|
-
link={rdpHelpLink}
|
|
398
|
-
/>
|
|
399
|
-
</div>
|
|
414
|
+
<span className='mg2l mg2r'>
|
|
415
|
+
{username}@{host}:{port}
|
|
416
|
+
</span>
|
|
400
417
|
)
|
|
401
418
|
}
|
|
402
419
|
|
|
@@ -425,7 +442,7 @@ export default class RdpSession extends Component {
|
|
|
425
442
|
<Spin spinning={loading}>
|
|
426
443
|
<div
|
|
427
444
|
{...rdpProps}
|
|
428
|
-
className='rdp-session-wrap
|
|
445
|
+
className='rdp-session-wrap session-v-wrap'
|
|
429
446
|
>
|
|
430
447
|
{this.renderControl()}
|
|
431
448
|
<canvas
|
|
@@ -5,6 +5,7 @@ import { Component } from 'react'
|
|
|
5
5
|
import Term from '../terminal'
|
|
6
6
|
import Sftp from '../sftp/sftp-entry'
|
|
7
7
|
import RdpSession from '../rdp/rdp-session'
|
|
8
|
+
import VncSession from '../vnc/vnc-session'
|
|
8
9
|
import {
|
|
9
10
|
BorderVerticleOutlined,
|
|
10
11
|
BorderHorizontalOutlined,
|
|
@@ -29,7 +30,8 @@ import {
|
|
|
29
30
|
footerHeight,
|
|
30
31
|
terminalActions,
|
|
31
32
|
connectionMap,
|
|
32
|
-
terminalRdpType
|
|
33
|
+
terminalRdpType,
|
|
34
|
+
terminalVncType
|
|
33
35
|
} from '../../common/constants'
|
|
34
36
|
import ResizeWrap from '../common/resize-wrap'
|
|
35
37
|
import safeName from '../../common/safe-name'
|
|
@@ -325,7 +327,7 @@ export default class SessionWrapper extends Component {
|
|
|
325
327
|
const {
|
|
326
328
|
pane, type
|
|
327
329
|
} = this.props.tab
|
|
328
|
-
if (type === terminalRdpType) {
|
|
330
|
+
if (type === terminalRdpType || type === terminalVncType) {
|
|
329
331
|
const rdpProps = {
|
|
330
332
|
tab: this.props.tab,
|
|
331
333
|
sessionId,
|
|
@@ -339,14 +341,23 @@ export default class SessionWrapper extends Component {
|
|
|
339
341
|
'openedSideBar',
|
|
340
342
|
'delTab',
|
|
341
343
|
'config',
|
|
344
|
+
'reloadTab',
|
|
342
345
|
'editTab'
|
|
343
346
|
]),
|
|
344
347
|
...pick(
|
|
345
348
|
this,
|
|
346
349
|
[
|
|
350
|
+
'fullscreenIcon',
|
|
347
351
|
'setSessionState'
|
|
348
352
|
])
|
|
349
353
|
}
|
|
354
|
+
if (type === terminalVncType) {
|
|
355
|
+
return (
|
|
356
|
+
<VncSession
|
|
357
|
+
{...rdpProps}
|
|
358
|
+
/>
|
|
359
|
+
)
|
|
360
|
+
}
|
|
350
361
|
return (
|
|
351
362
|
<RdpSession
|
|
352
363
|
{...rdpProps}
|
|
@@ -506,7 +517,7 @@ export default class SessionWrapper extends Component {
|
|
|
506
517
|
const { splitDirection, terminals, sftpPathFollowSsh } = this.state
|
|
507
518
|
const { props } = this
|
|
508
519
|
const { pane, enableSsh, type } = props.tab
|
|
509
|
-
if (type === terminalRdpType) {
|
|
520
|
+
if (type === terminalRdpType || type === terminalVncType) {
|
|
510
521
|
return null
|
|
511
522
|
}
|
|
512
523
|
const termType = props.tab?.type
|
|
@@ -59,6 +59,11 @@
|
|
|
59
59
|
.web-session-wrap
|
|
60
60
|
height 100vh
|
|
61
61
|
background main
|
|
62
|
-
.
|
|
62
|
+
.session-v-wrap
|
|
63
63
|
background main
|
|
64
|
-
overflow scroll
|
|
64
|
+
overflow scroll
|
|
65
|
+
z-index 99
|
|
66
|
+
.vnc-session-wrap > div
|
|
67
|
+
display block !important
|
|
68
|
+
width auto !important
|
|
69
|
+
height auto !important
|
|
@@ -15,11 +15,13 @@ import TabHistory from './tab-history'
|
|
|
15
15
|
import TabQuickCommands from './tab-quick-commands'
|
|
16
16
|
import TabSettings from './tab-settings'
|
|
17
17
|
import TabThemes from './tab-themes'
|
|
18
|
+
import TabProfiles from './tab-profiles'
|
|
18
19
|
|
|
19
20
|
const { prefix } = window
|
|
20
21
|
const m = prefix('common')
|
|
21
22
|
const t = prefix('terminalThemes')
|
|
22
23
|
const q = prefix('quickCommands')
|
|
24
|
+
const f = prefix('profiles')
|
|
23
25
|
|
|
24
26
|
export default class SettingModalWrap extends Component {
|
|
25
27
|
selectItem = (item) => {
|
|
@@ -92,17 +94,25 @@ export default class SettingModalWrap extends Component {
|
|
|
92
94
|
key: settingMap.quickCommands,
|
|
93
95
|
label: q(settingMap.quickCommands),
|
|
94
96
|
children: null
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
key: settingMap.profiles,
|
|
100
|
+
label: f(settingMap.profiles),
|
|
101
|
+
children: null
|
|
95
102
|
}
|
|
96
103
|
]
|
|
104
|
+
const tabsProps = {
|
|
105
|
+
activeKey: settingTab,
|
|
106
|
+
animated: false,
|
|
107
|
+
items,
|
|
108
|
+
onChange: store.handleChangeSettingTab,
|
|
109
|
+
destroyInactiveTabPane: true,
|
|
110
|
+
className: 'setting-tabs'
|
|
111
|
+
}
|
|
97
112
|
return (
|
|
98
113
|
<div>
|
|
99
114
|
<Tabs
|
|
100
|
-
|
|
101
|
-
animated={false}
|
|
102
|
-
items={items}
|
|
103
|
-
onChange={store.handleChangeSettingTab}
|
|
104
|
-
destroyInactiveTabPane
|
|
105
|
-
className='setting-tabs'
|
|
115
|
+
{...tabsProps}
|
|
106
116
|
/>
|
|
107
117
|
<TabHistory
|
|
108
118
|
listProps={props0}
|
|
@@ -136,6 +146,13 @@ export default class SettingModalWrap extends Component {
|
|
|
136
146
|
store={store}
|
|
137
147
|
settingTab={settingTab}
|
|
138
148
|
/>
|
|
149
|
+
<TabProfiles
|
|
150
|
+
listProps={props0}
|
|
151
|
+
settingItem={settingItem}
|
|
152
|
+
formProps={formProps}
|
|
153
|
+
store={store}
|
|
154
|
+
settingTab={settingTab}
|
|
155
|
+
/>
|
|
139
156
|
</div>
|
|
140
157
|
)
|
|
141
158
|
}
|
|
@@ -71,7 +71,7 @@ export default class SettingTerminal extends Component {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
handleChangeDelMode = v => this.onChangeValue(v, 'backspaceMode')
|
|
74
|
-
handleChangeRenderType = v => this.onChangeValue(v, '
|
|
74
|
+
handleChangeRenderType = v => this.onChangeValue(v, 'rendererType')
|
|
75
75
|
|
|
76
76
|
handleChangeFont = (values) => {
|
|
77
77
|
this.onChangeValue(
|
|
@@ -36,7 +36,11 @@ export default class SettingWrap extends Component {
|
|
|
36
36
|
{...pops}
|
|
37
37
|
>
|
|
38
38
|
<CloseCircleOutlined
|
|
39
|
-
className='close-setting-wrap'
|
|
39
|
+
className='close-setting-wrap-icon close-setting-wrap'
|
|
40
|
+
onClick={this.props.onCancel}
|
|
41
|
+
/>
|
|
42
|
+
<CloseCircleOutlined
|
|
43
|
+
className='close-setting-wrap-icon alt-close-setting-wrap'
|
|
40
44
|
onClick={this.props.onCancel}
|
|
41
45
|
/>
|
|
42
46
|
{
|
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
body .ant-drawer .ant-drawer-content-wrapper
|
|
7
7
|
left 43px
|
|
8
|
-
|
|
9
|
-
.close-setting-wrap
|
|
8
|
+
.close-setting-wrap-icon
|
|
10
9
|
position absolute
|
|
11
|
-
left 20px
|
|
12
10
|
top 70px
|
|
13
11
|
font-size 16px
|
|
14
12
|
color text
|
|
@@ -16,6 +14,10 @@ body .ant-drawer .ant-drawer-content-wrapper
|
|
|
16
14
|
z-index 889
|
|
17
15
|
&:hover
|
|
18
16
|
color text
|
|
17
|
+
.alt-close-setting-wrap
|
|
18
|
+
right 20px
|
|
19
|
+
.close-setting-wrap
|
|
20
|
+
top 70px
|
|
19
21
|
.setting-row
|
|
20
22
|
position absolute
|
|
21
23
|
top 127px
|