@electerm/electerm-react 1.39.119 → 1.40.1
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 +0 -1
- package/client/components/bookmark-form/color-picker.jsx +18 -9
- package/client/components/bookmark-form/form-ssh-common.jsx +4 -2
- package/client/components/bookmark-form/profile-form-item.jsx +43 -0
- package/client/components/bookmark-form/rdp-form-ui.jsx +10 -9
- package/client/components/bookmark-form/render-auth-ssh.jsx +6 -3
- package/client/components/bookmark-form/render-profile-item.jsx +0 -0
- package/client/components/bookmark-form/telnet-form-ui.jsx +19 -40
- package/client/components/bookmark-form/vnc-form-ui.jsx +6 -1
- package/client/components/bookmark-form/web-form-ui.jsx +1 -1
- package/client/components/profile/profile-form-elem.jsx +14 -28
- package/client/components/profile/profile-form-rdp.jsx +31 -0
- package/client/components/profile/profile-form-ssh.jsx +41 -0
- package/client/components/profile/profile-form-telnet.jsx +35 -0
- package/client/components/profile/profile-form-vnc.jsx +31 -0
- package/client/components/profile/profile-tabs.jsx +32 -0
- package/client/components/rdp/rdp-session.jsx +3 -9
- package/client/components/setting-panel/tab-themes.jsx +2 -2
- package/client/components/terminal/attach-addon-custom.js +11 -11
- package/client/components/terminal/index.jsx +37 -3
- package/client/components/theme/theme-edit-slot.jsx +28 -0
- package/client/components/theme/theme-editor.jsx +37 -0
- package/client/components/{terminal-theme/index.jsx → theme/theme-form.jsx} +103 -34
- package/client/components/theme/theme-form.styl +10 -0
- package/client/components/vnc/vnc-session.jsx +2 -1
- package/client/store/common.js +25 -4
- package/client/store/sync.js +0 -3
- package/package.json +1 -1
- /package/client/components/{terminal-theme → theme}/terminal-theme-list.styl +0 -0
- /package/client/components/{terminal-theme → theme}/theme-list.jsx +0 -0
|
@@ -324,7 +324,6 @@ export const sshTunnelHelpLink = 'https://github.com/electerm/electerm/wiki/How-
|
|
|
324
324
|
export const batchOpHelpLink = 'https://github.com/electerm/electerm/wiki/batch-operation'
|
|
325
325
|
export const proxyHelpLink = 'https://github.com/electerm/electerm/wiki/proxy-format'
|
|
326
326
|
export const regexHelpLink = 'https://github.com/electerm/electerm/wiki/Terminal-keywords-highlight-regular-expression-exmaples'
|
|
327
|
-
export const rdpHelpLink = 'https://github.com/electerm/electerm/wiki/RDP-limitation'
|
|
328
327
|
export const modals = {
|
|
329
328
|
hide: 0,
|
|
330
329
|
setting: 1,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import { Popover } from 'antd'
|
|
3
|
-
import { HexColorPicker } from 'react-colorful'
|
|
3
|
+
import { HexColorPicker, RgbaColorPicker } from 'react-colorful'
|
|
4
4
|
import { defaultColors, getRandomHexColor } from '../../common/rand-hex-color.js'
|
|
5
5
|
import { HexInput } from './hex-input.jsx'
|
|
6
6
|
import './color-picker.styl'
|
|
@@ -20,6 +20,7 @@ export const ColorPicker = React.forwardRef((props, ref) => {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function renderContent () {
|
|
23
|
+
const Picker = props.isRgba ? RgbaColorPicker : HexColorPicker
|
|
23
24
|
return (
|
|
24
25
|
<div className='color-picker-box'>
|
|
25
26
|
<div className='fix'>
|
|
@@ -55,7 +56,7 @@ export const ColorPicker = React.forwardRef((props, ref) => {
|
|
|
55
56
|
}
|
|
56
57
|
</div>
|
|
57
58
|
<div className='fright'>
|
|
58
|
-
<
|
|
59
|
+
<Picker
|
|
59
60
|
color={value}
|
|
60
61
|
onChange={handleChange}
|
|
61
62
|
/>
|
|
@@ -71,6 +72,20 @@ export const ColorPicker = React.forwardRef((props, ref) => {
|
|
|
71
72
|
)
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
const inner = (
|
|
76
|
+
<div
|
|
77
|
+
ref={ref}
|
|
78
|
+
className='color-picker-choose'
|
|
79
|
+
style={{
|
|
80
|
+
backgroundColor: value
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (props.disabled) {
|
|
86
|
+
return inner
|
|
87
|
+
}
|
|
88
|
+
|
|
74
89
|
return (
|
|
75
90
|
<Popover
|
|
76
91
|
content={renderContent()}
|
|
@@ -79,13 +94,7 @@ export const ColorPicker = React.forwardRef((props, ref) => {
|
|
|
79
94
|
placement='bottomLeft'
|
|
80
95
|
onOpenChange={handleVisibleChange}
|
|
81
96
|
>
|
|
82
|
-
|
|
83
|
-
ref={ref}
|
|
84
|
-
className='color-picker-choose'
|
|
85
|
-
style={{
|
|
86
|
-
backgroundColor: value
|
|
87
|
-
}}
|
|
88
|
-
/>
|
|
97
|
+
{inner}
|
|
89
98
|
</Popover>
|
|
90
99
|
)
|
|
91
100
|
})
|
|
@@ -36,9 +36,11 @@ export default function renderCommon (props) {
|
|
|
36
36
|
bookmarkGroups = [],
|
|
37
37
|
ips,
|
|
38
38
|
form,
|
|
39
|
-
onChangeAuthType
|
|
39
|
+
onChangeAuthType,
|
|
40
|
+
filterAuthType = a => a
|
|
40
41
|
} = props
|
|
41
42
|
const tree = formatBookmarkGroups(bookmarkGroups)
|
|
43
|
+
const authTypesFiltered = authTypes.filter(filterAuthType)
|
|
42
44
|
|
|
43
45
|
// ips is ipaddress string[]
|
|
44
46
|
function renderIps () {
|
|
@@ -115,7 +117,7 @@ export default function renderCommon (props) {
|
|
|
115
117
|
buttonStyle='solid'
|
|
116
118
|
>
|
|
117
119
|
{
|
|
118
|
-
|
|
120
|
+
authTypesFiltered.map(t => {
|
|
119
121
|
return (
|
|
120
122
|
<RadioButton value={t} key={t}>
|
|
121
123
|
{e(t)}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bookmark form
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
Form,
|
|
6
|
+
Select
|
|
7
|
+
} from 'antd'
|
|
8
|
+
import { formItemLayout } from '../../common/form-layout'
|
|
9
|
+
import './bookmark-form.styl'
|
|
10
|
+
|
|
11
|
+
const FormItem = Form.Item
|
|
12
|
+
const e = window.translate
|
|
13
|
+
|
|
14
|
+
export default function ProfileItem (props) {
|
|
15
|
+
const {
|
|
16
|
+
store,
|
|
17
|
+
profileFilter = (d) => d
|
|
18
|
+
} = props
|
|
19
|
+
const opts = {
|
|
20
|
+
options: store.profiles
|
|
21
|
+
.filter(profileFilter)
|
|
22
|
+
.map(d => {
|
|
23
|
+
return {
|
|
24
|
+
label: d.name,
|
|
25
|
+
value: d.id
|
|
26
|
+
}
|
|
27
|
+
}),
|
|
28
|
+
placeholder: e('profiles'),
|
|
29
|
+
allowClear: true
|
|
30
|
+
}
|
|
31
|
+
return (
|
|
32
|
+
<FormItem
|
|
33
|
+
{...formItemLayout}
|
|
34
|
+
label={e('profiles')}
|
|
35
|
+
name='profile'
|
|
36
|
+
hasFeedback
|
|
37
|
+
>
|
|
38
|
+
<Select
|
|
39
|
+
{...opts}
|
|
40
|
+
/>
|
|
41
|
+
</FormItem>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -12,17 +12,16 @@ import {
|
|
|
12
12
|
import { formItemLayout } from '../../common/form-layout'
|
|
13
13
|
import {
|
|
14
14
|
newBookmarkIdPrefix,
|
|
15
|
-
terminalRdpType
|
|
16
|
-
rdpHelpLink
|
|
15
|
+
terminalRdpType
|
|
17
16
|
} from '../../common/constants'
|
|
18
17
|
import useSubmit from './use-submit'
|
|
19
18
|
import copy from 'json-deep-copy'
|
|
20
|
-
import
|
|
21
|
-
import { defaults } from 'lodash-es'
|
|
19
|
+
import { defaults, isEmpty } from 'lodash-es'
|
|
22
20
|
import { ColorPickerItem } from './color-picker-item.jsx'
|
|
23
21
|
import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
|
|
24
22
|
import formatBookmarkGroups from './bookmark-group-tree-format'
|
|
25
23
|
import findBookmarkGroupId from '../../common/find-bookmark-group-id'
|
|
24
|
+
import ProfileItem from './profile-form-item'
|
|
26
25
|
|
|
27
26
|
const FormItem = Form.Item
|
|
28
27
|
const e = window.translate
|
|
@@ -56,6 +55,7 @@ export default function RdpFormUi (props) {
|
|
|
56
55
|
port: 3389,
|
|
57
56
|
category: initBookmarkGroupId,
|
|
58
57
|
color: getRandomDefaultColor()
|
|
58
|
+
|
|
59
59
|
}
|
|
60
60
|
initialValues = defaults(initialValues, defaultValues)
|
|
61
61
|
function renderCommon () {
|
|
@@ -65,9 +65,6 @@ export default function RdpFormUi (props) {
|
|
|
65
65
|
const tree = formatBookmarkGroups(bookmarkGroups)
|
|
66
66
|
return (
|
|
67
67
|
<div className='pd1x'>
|
|
68
|
-
<p className='alignright'>
|
|
69
|
-
<Link to={rdpHelpLink}>Wiki: {rdpHelpLink}</Link>
|
|
70
|
-
</p>
|
|
71
68
|
<FormItem
|
|
72
69
|
{...formItemLayout}
|
|
73
70
|
label={e('title')}
|
|
@@ -102,11 +99,15 @@ export default function RdpFormUi (props) {
|
|
|
102
99
|
step={1}
|
|
103
100
|
/>
|
|
104
101
|
</FormItem>
|
|
102
|
+
<ProfileItem
|
|
103
|
+
store={props.store}
|
|
104
|
+
profileFilter={d => !isEmpty(d.rdp)}
|
|
105
|
+
/>
|
|
105
106
|
<FormItem
|
|
106
107
|
{...formItemLayout}
|
|
107
|
-
label={e('
|
|
108
|
+
label={e('userName')}
|
|
108
109
|
hasFeedback
|
|
109
|
-
name='
|
|
110
|
+
name='userName'
|
|
110
111
|
required
|
|
111
112
|
>
|
|
112
113
|
<Input />
|
|
@@ -21,7 +21,9 @@ export default function renderAuth (props) {
|
|
|
21
21
|
const {
|
|
22
22
|
store,
|
|
23
23
|
form,
|
|
24
|
-
authType
|
|
24
|
+
authType,
|
|
25
|
+
formItemName = 'password',
|
|
26
|
+
profileFilter = (d) => d
|
|
25
27
|
} = props
|
|
26
28
|
const beforeUpload = async (file) => {
|
|
27
29
|
const privateKey = await window.fs.readFile(file.path)
|
|
@@ -50,7 +52,7 @@ export default function renderAuth (props) {
|
|
|
50
52
|
<FormItem
|
|
51
53
|
{...formItemLayout}
|
|
52
54
|
label={e('password')}
|
|
53
|
-
name=
|
|
55
|
+
name={formItemName}
|
|
54
56
|
hasFeedback
|
|
55
57
|
rules={[{
|
|
56
58
|
max: 1024, message: '1024 chars max'
|
|
@@ -67,6 +69,7 @@ export default function renderAuth (props) {
|
|
|
67
69
|
if (authType === 'profiles') {
|
|
68
70
|
const opts = {
|
|
69
71
|
options: store.profiles
|
|
72
|
+
.filter(profileFilter)
|
|
70
73
|
.map(d => {
|
|
71
74
|
return {
|
|
72
75
|
label: d.name,
|
|
@@ -74,7 +77,7 @@ export default function renderAuth (props) {
|
|
|
74
77
|
}
|
|
75
78
|
}),
|
|
76
79
|
placeholder: e('profiles'),
|
|
77
|
-
allowClear:
|
|
80
|
+
allowClear: true
|
|
78
81
|
}
|
|
79
82
|
return (
|
|
80
83
|
<FormItem
|
|
File without changes
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* bookmark form
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import {
|
|
6
6
|
Input,
|
|
7
7
|
Tabs,
|
|
8
|
-
AutoComplete,
|
|
9
8
|
Form
|
|
10
9
|
} from 'antd'
|
|
10
|
+
import { useState, useEffect } from 'react'
|
|
11
11
|
import {
|
|
12
12
|
newBookmarkIdPrefix,
|
|
13
|
-
terminalTelnetType
|
|
13
|
+
terminalTelnetType,
|
|
14
|
+
authTypeMap
|
|
14
15
|
} from '../../common/constants'
|
|
15
16
|
import { formItemLayout } from '../../common/form-layout'
|
|
16
17
|
import findBookmarkGroupId from '../../common/find-bookmark-group-id'
|
|
@@ -21,7 +22,8 @@ import useQm from './use-quick-commands'
|
|
|
21
22
|
import renderCommon from './form-ssh-common'
|
|
22
23
|
import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
|
|
23
24
|
import copy from 'json-deep-copy'
|
|
24
|
-
import { defaultsDeep,
|
|
25
|
+
import { defaultsDeep, isEmpty } from 'lodash-es'
|
|
26
|
+
import renderAuth from './render-auth-ssh'
|
|
25
27
|
import './bookmark-form.styl'
|
|
26
28
|
|
|
27
29
|
const FormItem = Form.Item
|
|
@@ -33,6 +35,7 @@ export default function TelnetFormUI (props) {
|
|
|
33
35
|
handleFinish,
|
|
34
36
|
submitUi
|
|
35
37
|
] = useSubmit(props)
|
|
38
|
+
const [authType, setAuthType] = useState(props.formData.authType || authTypeMap.password)
|
|
36
39
|
useEffect(() => {
|
|
37
40
|
if ((props.formData.id || '').startsWith(newBookmarkIdPrefix)) {
|
|
38
41
|
form.setFieldsValue({
|
|
@@ -53,6 +56,9 @@ export default function TelnetFormUI (props) {
|
|
|
53
56
|
? findBookmarkGroupId(bookmarkGroups, id)
|
|
54
57
|
: currentBookmarkGroupId
|
|
55
58
|
let initialValues = copy(props.formData)
|
|
59
|
+
function onChangeAuthType (e) {
|
|
60
|
+
setAuthType(e.target.value)
|
|
61
|
+
}
|
|
56
62
|
const defaultValues = {
|
|
57
63
|
port: 23,
|
|
58
64
|
id: '',
|
|
@@ -63,47 +69,20 @@ export default function TelnetFormUI (props) {
|
|
|
63
69
|
term: defaultSettings.terminalType,
|
|
64
70
|
displayRaw: false,
|
|
65
71
|
type: terminalTelnetType,
|
|
66
|
-
category: initBookmarkGroupId
|
|
72
|
+
category: initBookmarkGroupId,
|
|
73
|
+
authType: authTypeMap.password
|
|
67
74
|
}
|
|
68
75
|
initialValues = defaultsDeep(initialValues, defaultValues)
|
|
69
|
-
|
|
70
|
-
const opts = {
|
|
71
|
-
options: uniqBy(
|
|
72
|
-
props.store.bookmarks
|
|
73
|
-
.filter(d => d.password),
|
|
74
|
-
(d) => d.password
|
|
75
|
-
)
|
|
76
|
-
.map(d => {
|
|
77
|
-
return {
|
|
78
|
-
label: `${d.title ? `(${d.title})` : ''}${d.username || ''}:${d.host}-******`,
|
|
79
|
-
value: d.password
|
|
80
|
-
}
|
|
81
|
-
}),
|
|
82
|
-
placeholder: e('password'),
|
|
83
|
-
allowClear: false
|
|
84
|
-
}
|
|
85
|
-
return (
|
|
86
|
-
<FormItem
|
|
87
|
-
{...formItemLayout}
|
|
88
|
-
label={e('password')}
|
|
89
|
-
name='password'
|
|
90
|
-
hasFeedback
|
|
91
|
-
rules={[{
|
|
92
|
-
max: 1024, message: '1024 chars max'
|
|
93
|
-
}]}
|
|
94
|
-
>
|
|
95
|
-
<AutoComplete
|
|
96
|
-
{...opts}
|
|
97
|
-
>
|
|
98
|
-
<Input.Password />
|
|
99
|
-
</AutoComplete>
|
|
100
|
-
</FormItem>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
76
|
+
|
|
103
77
|
const tprops = {
|
|
104
78
|
...props,
|
|
105
79
|
renderAuth,
|
|
106
|
-
|
|
80
|
+
authType,
|
|
81
|
+
onChangeAuthType,
|
|
82
|
+
form,
|
|
83
|
+
bookmarkType: terminalTelnetType,
|
|
84
|
+
filterAuthType: a => a !== 'privateKey',
|
|
85
|
+
profileFilter: d => !isEmpty(d.telnet)
|
|
107
86
|
}
|
|
108
87
|
|
|
109
88
|
function renderTabs () {
|
|
@@ -18,13 +18,14 @@ import {
|
|
|
18
18
|
} from '../../common/constants'
|
|
19
19
|
import useSubmit from './use-submit'
|
|
20
20
|
import copy from 'json-deep-copy'
|
|
21
|
-
import { defaults } from 'lodash-es'
|
|
21
|
+
import { defaults, isEmpty } from 'lodash-es'
|
|
22
22
|
import { ColorPickerItem } from './color-picker-item.jsx'
|
|
23
23
|
import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
|
|
24
24
|
import formatBookmarkGroups from './bookmark-group-tree-format'
|
|
25
25
|
import findBookmarkGroupId from '../../common/find-bookmark-group-id'
|
|
26
26
|
import renderProxy from './proxy'
|
|
27
27
|
import ConnectionHopping from './render-connection-hopping.jsx'
|
|
28
|
+
import ProfileItem from './profile-form-item'
|
|
28
29
|
|
|
29
30
|
const FormItem = Form.Item
|
|
30
31
|
const e = window.translate
|
|
@@ -152,6 +153,10 @@ export default function VncFormUi (props) {
|
|
|
152
153
|
>
|
|
153
154
|
<Switch />
|
|
154
155
|
</FormItem>
|
|
156
|
+
<ProfileItem
|
|
157
|
+
store={props.store}
|
|
158
|
+
profileFilter={d => !isEmpty(d.vnc)}
|
|
159
|
+
/>
|
|
155
160
|
<FormItem
|
|
156
161
|
{...formItemLayout}
|
|
157
162
|
label={e('username')}
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
1
2
|
import {
|
|
2
3
|
Form,
|
|
3
4
|
message,
|
|
4
|
-
Button
|
|
5
|
-
Input
|
|
5
|
+
Button
|
|
6
6
|
} from 'antd'
|
|
7
7
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
8
|
-
import renderAuth from '../bookmark-form/render-auth-ssh'
|
|
9
8
|
import { formItemLayout } from '../../common/form-layout'
|
|
10
9
|
import {
|
|
11
10
|
settingMap
|
|
12
11
|
} from '../../common/constants'
|
|
12
|
+
|
|
13
|
+
import ProfileTabs from './profile-tabs'
|
|
14
|
+
|
|
13
15
|
const FormItem = Form.Item
|
|
14
16
|
const e = window.translate
|
|
15
17
|
|
|
16
|
-
export default function
|
|
18
|
+
export default function ProfileFormElem (props) {
|
|
17
19
|
const [form] = Form.useForm()
|
|
20
|
+
const [activeTab, setActiveTab] = useState('ssh')
|
|
18
21
|
const { autofocustrigger, profiles } = props.store
|
|
19
22
|
function genId () {
|
|
20
23
|
let count = profiles.length ? profiles.length : ''
|
|
@@ -42,6 +45,12 @@ export default function QuickCommandForm (props) {
|
|
|
42
45
|
}
|
|
43
46
|
message.success(e('saved'))
|
|
44
47
|
}
|
|
48
|
+
const tabsProps = {
|
|
49
|
+
activeTab,
|
|
50
|
+
onChangeTab: setActiveTab,
|
|
51
|
+
form,
|
|
52
|
+
store: props.store
|
|
53
|
+
}
|
|
45
54
|
return (
|
|
46
55
|
<Form
|
|
47
56
|
form={form}
|
|
@@ -67,30 +76,7 @@ export default function QuickCommandForm (props) {
|
|
|
67
76
|
autofocustrigger={autofocustrigger}
|
|
68
77
|
/>
|
|
69
78
|
</FormItem>
|
|
70
|
-
<
|
|
71
|
-
{...formItemLayout}
|
|
72
|
-
label={e('username')}
|
|
73
|
-
hasFeedback
|
|
74
|
-
name='username'
|
|
75
|
-
rules={[{
|
|
76
|
-
max: 128, message: '128 chars max'
|
|
77
|
-
}]}
|
|
78
|
-
>
|
|
79
|
-
<Input />
|
|
80
|
-
</FormItem>
|
|
81
|
-
{
|
|
82
|
-
renderAuth({
|
|
83
|
-
store: props.store,
|
|
84
|
-
form,
|
|
85
|
-
authType: 'password'
|
|
86
|
-
})
|
|
87
|
-
}
|
|
88
|
-
{
|
|
89
|
-
renderAuth({
|
|
90
|
-
store: props.store,
|
|
91
|
-
form
|
|
92
|
-
})
|
|
93
|
-
}
|
|
79
|
+
<ProfileTabs {...tabsProps} />
|
|
94
80
|
<FormItem>
|
|
95
81
|
<Button
|
|
96
82
|
type='primary'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
Input
|
|
4
|
+
} from 'antd'
|
|
5
|
+
import { formItemLayout } from '../../common/form-layout'
|
|
6
|
+
|
|
7
|
+
const FormItem = Form.Item
|
|
8
|
+
const e = window.translate
|
|
9
|
+
|
|
10
|
+
export default function ProfileFormRdp (props) {
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
<FormItem
|
|
14
|
+
{...formItemLayout}
|
|
15
|
+
label={e('username')}
|
|
16
|
+
hasFeedback
|
|
17
|
+
name={['rdp', 'userName']}
|
|
18
|
+
>
|
|
19
|
+
<Input />
|
|
20
|
+
</FormItem>
|
|
21
|
+
<FormItem
|
|
22
|
+
{...formItemLayout}
|
|
23
|
+
label={e('password')}
|
|
24
|
+
hasFeedback
|
|
25
|
+
name={['rdp', 'password']}
|
|
26
|
+
>
|
|
27
|
+
<Input.Password />
|
|
28
|
+
</FormItem>
|
|
29
|
+
</>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
Input
|
|
4
|
+
} from 'antd'
|
|
5
|
+
import renderAuth from '../bookmark-form/render-auth-ssh'
|
|
6
|
+
import { formItemLayout } from '../../common/form-layout'
|
|
7
|
+
|
|
8
|
+
const FormItem = Form.Item
|
|
9
|
+
const e = window.translate
|
|
10
|
+
|
|
11
|
+
export default function ProfileFormSsh (props) {
|
|
12
|
+
const { form } = props.store
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<FormItem
|
|
16
|
+
{...formItemLayout}
|
|
17
|
+
label={e('username')}
|
|
18
|
+
hasFeedback
|
|
19
|
+
name='username'
|
|
20
|
+
rules={[{
|
|
21
|
+
max: 128, message: '128 chars max'
|
|
22
|
+
}]}
|
|
23
|
+
>
|
|
24
|
+
<Input />
|
|
25
|
+
</FormItem>
|
|
26
|
+
{
|
|
27
|
+
renderAuth({
|
|
28
|
+
store: props.store,
|
|
29
|
+
form,
|
|
30
|
+
authType: 'password'
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
{
|
|
34
|
+
renderAuth({
|
|
35
|
+
store: props.store,
|
|
36
|
+
form
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
</>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
Input
|
|
4
|
+
} from 'antd'
|
|
5
|
+
import { formItemLayout } from '../../common/form-layout'
|
|
6
|
+
import renderAuth from '../bookmark-form/render-auth-ssh'
|
|
7
|
+
|
|
8
|
+
const FormItem = Form.Item
|
|
9
|
+
const e = window.translate
|
|
10
|
+
|
|
11
|
+
export default function ProfileFormTelnet (props) {
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
<FormItem
|
|
15
|
+
{...formItemLayout}
|
|
16
|
+
label={e('username')}
|
|
17
|
+
hasFeedback
|
|
18
|
+
name={['telnet', 'username']}
|
|
19
|
+
rules={[{
|
|
20
|
+
max: 128, message: '128 chars max'
|
|
21
|
+
}]}
|
|
22
|
+
>
|
|
23
|
+
<Input />
|
|
24
|
+
</FormItem>
|
|
25
|
+
{
|
|
26
|
+
renderAuth({
|
|
27
|
+
store: props.store,
|
|
28
|
+
form: props.form,
|
|
29
|
+
authType: 'password',
|
|
30
|
+
formItemName: ['telnet', 'password']
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
</>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
Input
|
|
4
|
+
} from 'antd'
|
|
5
|
+
import { formItemLayout } from '../../common/form-layout'
|
|
6
|
+
|
|
7
|
+
const FormItem = Form.Item
|
|
8
|
+
const e = window.translate
|
|
9
|
+
|
|
10
|
+
export default function ProfileFormVnc (props) {
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
<FormItem
|
|
14
|
+
{...formItemLayout}
|
|
15
|
+
label={e('username')}
|
|
16
|
+
hasFeedback
|
|
17
|
+
name={['vnc', 'username']}
|
|
18
|
+
>
|
|
19
|
+
<Input />
|
|
20
|
+
</FormItem>
|
|
21
|
+
<FormItem
|
|
22
|
+
{...formItemLayout}
|
|
23
|
+
label={e('password')}
|
|
24
|
+
hasFeedback
|
|
25
|
+
name={['vnc', 'password']}
|
|
26
|
+
>
|
|
27
|
+
<Input.Password />
|
|
28
|
+
</FormItem>
|
|
29
|
+
</>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Tabs } from 'antd'
|
|
2
|
+
import ProfileFormSsh from './profile-form-ssh'
|
|
3
|
+
import ProfileFormRdp from './profile-form-rdp'
|
|
4
|
+
import ProfileFormVnc from './profile-form-vnc'
|
|
5
|
+
import ProfileFormTelnet from './profile-form-telnet'
|
|
6
|
+
|
|
7
|
+
const { TabPane } = Tabs
|
|
8
|
+
|
|
9
|
+
export default function ProfileTabs (props) {
|
|
10
|
+
const { activeTab, onChangeTab, form, store } = props
|
|
11
|
+
const tabsProps = {
|
|
12
|
+
activeKey: activeTab,
|
|
13
|
+
onChange: onChangeTab
|
|
14
|
+
}
|
|
15
|
+
return (
|
|
16
|
+
<Tabs {...tabsProps}>
|
|
17
|
+
<TabPane tab='ssh' key='ssh' forceRender>
|
|
18
|
+
<ProfileFormSsh form={form} store={store} />
|
|
19
|
+
</TabPane>
|
|
20
|
+
<TabPane tab='telnet' key='telnet' forceRender>
|
|
21
|
+
<ProfileFormTelnet form={form} store={store} />
|
|
22
|
+
</TabPane>
|
|
23
|
+
<TabPane tab='vnc' key='vnc' forceRender>
|
|
24
|
+
<ProfileFormVnc />
|
|
25
|
+
</TabPane>
|
|
26
|
+
<TabPane tab='rdp' key='rdp' forceRender>
|
|
27
|
+
<ProfileFormRdp />
|
|
28
|
+
</TabPane>
|
|
29
|
+
</Tabs>
|
|
30
|
+
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -4,8 +4,7 @@ import deepCopy from 'json-deep-copy'
|
|
|
4
4
|
import clone from '../../common/to-simple-obj'
|
|
5
5
|
import { handleErr } from '../../common/fetch'
|
|
6
6
|
import {
|
|
7
|
-
statusMap
|
|
8
|
-
rdpHelpLink
|
|
7
|
+
statusMap
|
|
9
8
|
} from '../../common/constants'
|
|
10
9
|
import {
|
|
11
10
|
notification,
|
|
@@ -17,7 +16,6 @@ import {
|
|
|
17
16
|
ReloadOutlined,
|
|
18
17
|
EditOutlined
|
|
19
18
|
} from '@ant-design/icons'
|
|
20
|
-
import HelpIcon from '../common/help-icon'
|
|
21
19
|
import * as ls from '../../common/safe-local-storage'
|
|
22
20
|
import scanCode from './code-scan'
|
|
23
21
|
import resolutions from './resolutions'
|
|
@@ -84,7 +82,7 @@ export default class RdpSession extends Component {
|
|
|
84
82
|
server = ''
|
|
85
83
|
} = config
|
|
86
84
|
const { sessionId, id } = this.props
|
|
87
|
-
const tab = deepCopy(this.props.tab || {})
|
|
85
|
+
const tab = window.store.applyProfile(deepCopy(this.props.tab || {}))
|
|
88
86
|
const {
|
|
89
87
|
type,
|
|
90
88
|
term: terminalType
|
|
@@ -347,11 +345,7 @@ export default class RdpSession extends Component {
|
|
|
347
345
|
}
|
|
348
346
|
|
|
349
347
|
renderHelp = () => {
|
|
350
|
-
return
|
|
351
|
-
<HelpIcon
|
|
352
|
-
link={rdpHelpLink}
|
|
353
|
-
/>
|
|
354
|
-
)
|
|
348
|
+
return null
|
|
355
349
|
}
|
|
356
350
|
|
|
357
351
|
renderControl = () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import SettingCol from './col'
|
|
2
|
-
import TerminalThemeForm from '../
|
|
3
|
-
import TerminalThemeList from '../
|
|
2
|
+
import TerminalThemeForm from '../theme/theme-form'
|
|
3
|
+
import TerminalThemeList from '../theme/theme-list'
|
|
4
4
|
import {
|
|
5
5
|
settingMap
|
|
6
6
|
} from '../../common/constants'
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* customize AttachAddon
|
|
3
3
|
*/
|
|
4
4
|
import { AttachAddon } from 'xterm-addon-attach'
|
|
5
|
-
import
|
|
5
|
+
import regEscape from 'escape-string-regexp'
|
|
6
6
|
|
|
7
7
|
export default class AttachAddonCustom extends AttachAddon {
|
|
8
8
|
constructor (term, socket, isWindowsShell) {
|
|
@@ -63,16 +63,16 @@ export default class AttachAddonCustom extends AttachAddon {
|
|
|
63
63
|
const nss = str.split('\r')
|
|
64
64
|
const nnss = []
|
|
65
65
|
for (const str1 of nss) {
|
|
66
|
-
const ns =
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
nnss.push(
|
|
66
|
+
const ns = str1.trim()
|
|
67
|
+
if (cwdId) {
|
|
68
|
+
const cwdIdEscaped = regEscape(cwdId)
|
|
69
|
+
const dirRegex = new RegExp(`${cwdIdEscaped}([^\\n]+?)${cwdIdEscaped}`, 'g')
|
|
70
|
+
if (ns.match(dirRegex)) {
|
|
71
|
+
const cwd = dirRegex.exec(ns)[1].trim()
|
|
72
|
+
if (cwd === '~' || cwd === '%d' || cwd === '%/' || cwd === '$PWD') term.parent.setCwd('')
|
|
73
|
+
else term.parent.setCwd(cwd)
|
|
74
|
+
nnss.push(ns.replaceAll(dirRegex, ''))
|
|
75
|
+
} else nnss.push(str1)
|
|
76
76
|
} else {
|
|
77
77
|
nnss.push(str1)
|
|
78
78
|
}
|
|
@@ -125,6 +125,34 @@ class Term extends Component {
|
|
|
125
125
|
if (themeChanged) {
|
|
126
126
|
this.term.options.theme = deepCopy(this.props.themeConfig)
|
|
127
127
|
}
|
|
128
|
+
|
|
129
|
+
const sftpPathFollowSshChanged = !isEqual(
|
|
130
|
+
this.props.sftpPathFollowSsh,
|
|
131
|
+
prevProps.sftpPathFollowSsh
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if (sftpPathFollowSshChanged) {
|
|
135
|
+
const ps1Cmd = `\recho $0|grep csh >/dev/null && set prompt_bak="$prompt" && set prompt="$prompt${cwdId}%/${cwdId}"\r
|
|
136
|
+
echo $0|grep zsh >/dev/null && PS1_bak=$PS1&&PS1=$PS1'${cwdId}%d${cwdId}'\r
|
|
137
|
+
echo $0|grep ash >/dev/null && PS1_bak=$PS1&&PS1=$PS1'\`echo ${cwdId}$PWD${cwdId}\`'\r
|
|
138
|
+
echo $0|grep ksh >/dev/null && PS1_bak=$PS1&&PS1=$PS1'\`echo ${cwdId}$PWD${cwdId}\`'\r
|
|
139
|
+
echo $0|grep '^sh' >/dev/null && PS1_bak=$PS1&&PS1=$PS1'\`echo ${cwdId}$PWD${cwdId}\`'\r
|
|
140
|
+
clear\r`
|
|
141
|
+
const ps1RestoreCmd = `\recho $0|grep csh >/dev/null && set prompt="$prompt_bak"\r
|
|
142
|
+
echo $0|grep zsh >/dev/null && PS1="$PS1_bak"\r
|
|
143
|
+
echo $0|grep ash >/dev/null && PS1="$PS1_bak"\r
|
|
144
|
+
echo $0|grep ksh >/dev/null && PS1="$PS1_bak"\r
|
|
145
|
+
echo $0|grep '^sh' >/dev/null && PS1="$PS1_bak"\r
|
|
146
|
+
clear\r`
|
|
147
|
+
|
|
148
|
+
if (this.props.sftpPathFollowSsh) {
|
|
149
|
+
this.socket.send(ps1Cmd)
|
|
150
|
+
this.term.cwdId = cwdId
|
|
151
|
+
} else {
|
|
152
|
+
this.socket.send(ps1RestoreCmd)
|
|
153
|
+
delete this.term.cwdId
|
|
154
|
+
}
|
|
155
|
+
}
|
|
128
156
|
}
|
|
129
157
|
|
|
130
158
|
componentWillUnmount () {
|
|
@@ -908,11 +936,17 @@ class Term extends Component {
|
|
|
908
936
|
getCwd = () => {
|
|
909
937
|
if (
|
|
910
938
|
this.props.sftpPathFollowSsh &&
|
|
911
|
-
this.term.buffer.active.type !== 'alternate'
|
|
939
|
+
this.term.buffer.active.type !== 'alternate' && !this.term.cwdId
|
|
912
940
|
) {
|
|
913
|
-
const cmd = `\recho "${cwdId}$PWD"\r`
|
|
914
941
|
this.term.cwdId = cwdId
|
|
915
|
-
|
|
942
|
+
|
|
943
|
+
const ps1Cmd = `\recho $0|grep csh >/dev/null && set prompt_bak="$prompt" && set prompt="$prompt${cwdId}%/${cwdId}"\r
|
|
944
|
+
echo $0|grep zsh >/dev/null && PS1_bak=$PS1&&PS1=$PS1'${cwdId}%d${cwdId}'\r
|
|
945
|
+
echo $0|grep ash >/dev/null && PS1_bak=$PS1&&PS1=$PS1'\`echo ${cwdId}$PWD${cwdId}\`'\r
|
|
946
|
+
echo $0|grep ksh >/dev/null && PS1_bak=$PS1&&PS1=$PS1'\`echo ${cwdId}$PWD${cwdId}\`'\r
|
|
947
|
+
clear\r`
|
|
948
|
+
|
|
949
|
+
this.socket.send(ps1Cmd)
|
|
916
950
|
}
|
|
917
951
|
}
|
|
918
952
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ColorPicker } from '../bookmark-form/color-picker'
|
|
2
|
+
|
|
3
|
+
export default function ThemeEditSlot (props) {
|
|
4
|
+
const {
|
|
5
|
+
name,
|
|
6
|
+
value,
|
|
7
|
+
disabled
|
|
8
|
+
} = props
|
|
9
|
+
function onChange (v) {
|
|
10
|
+
props.onChange(v, name)
|
|
11
|
+
}
|
|
12
|
+
const pickerProps = {
|
|
13
|
+
value,
|
|
14
|
+
onChange,
|
|
15
|
+
isRgba: value.startsWith('rgba'),
|
|
16
|
+
disabled
|
|
17
|
+
}
|
|
18
|
+
return (
|
|
19
|
+
<div className='theme-edit-slot'>
|
|
20
|
+
<span className='iblock mg1r'>{name}</span>
|
|
21
|
+
<span className='iblock'>
|
|
22
|
+
<ColorPicker
|
|
23
|
+
{...pickerProps}
|
|
24
|
+
/>
|
|
25
|
+
</span>
|
|
26
|
+
</div>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// import { buildDefaultThemes } from '../../common/terminal-theme'
|
|
2
|
+
import ThemeEditSlot from './theme-edit-slot'
|
|
3
|
+
|
|
4
|
+
export default function ThemeEditor (props) {
|
|
5
|
+
const { themeText, disabled } = props
|
|
6
|
+
const obj = themeText.split('\n').reduce((prev, line) => {
|
|
7
|
+
let [key = '', value = ''] = line.split('=')
|
|
8
|
+
key = key.trim()
|
|
9
|
+
value = value.trim()
|
|
10
|
+
if (!key || !value) {
|
|
11
|
+
return prev
|
|
12
|
+
}
|
|
13
|
+
prev[key] = value
|
|
14
|
+
return prev
|
|
15
|
+
}, {})
|
|
16
|
+
const keys = Object.keys(obj)
|
|
17
|
+
function onChange (value, name) {
|
|
18
|
+
props.onChange(value, name)
|
|
19
|
+
}
|
|
20
|
+
return (
|
|
21
|
+
<div className='editor-u-picker'>
|
|
22
|
+
{
|
|
23
|
+
keys.map(k => {
|
|
24
|
+
return (
|
|
25
|
+
<ThemeEditSlot
|
|
26
|
+
key={k}
|
|
27
|
+
name={k}
|
|
28
|
+
value={obj[k]}
|
|
29
|
+
disabled={disabled}
|
|
30
|
+
onChange={onChange}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
</div>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { useRef } from 'react'
|
|
2
|
-
import { Button, Input, message, Upload, Form } from 'antd'
|
|
1
|
+
import { useRef, useState } from 'react'
|
|
2
|
+
import { Button, Input, message, Upload, Form, Space } from 'antd'
|
|
3
3
|
import { convertTheme, convertThemeToText, exportTheme, validThemeProps, requiredThemeProps } from '../../common/terminal-theme'
|
|
4
4
|
import { defaultTheme, defaultThemeLight } from '../../common/constants'
|
|
5
5
|
import generate from '../../common/uid'
|
|
6
6
|
import Link from '../common/external-link'
|
|
7
7
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
8
|
+
import ThemePicker from './theme-editor'
|
|
9
|
+
// import './theme-form.styl'
|
|
8
10
|
|
|
9
11
|
const { TextArea } = Input
|
|
10
12
|
const FormItem = Form.Item
|
|
@@ -12,6 +14,8 @@ const e = window.translate
|
|
|
12
14
|
|
|
13
15
|
export default function ThemeForm (props) {
|
|
14
16
|
const [form] = Form.useForm()
|
|
17
|
+
const [txt, setTxt] = useState(convertThemeToText(props.formData))
|
|
18
|
+
const [editor, setEditor] = useState('theme-editor-color-picker')
|
|
15
19
|
const action = useRef('submit')
|
|
16
20
|
function exporter () {
|
|
17
21
|
exportTheme(props.formData.id)
|
|
@@ -82,18 +86,27 @@ export default function ThemeForm (props) {
|
|
|
82
86
|
return Promise.reject(message)
|
|
83
87
|
}
|
|
84
88
|
// Return an object with the flag and the message
|
|
89
|
+
setTxt(value)
|
|
85
90
|
return Promise.resolve()
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
async function handleSubmit (res) {
|
|
94
|
+
if (!res.themeText) {
|
|
95
|
+
res.themeText = txt
|
|
96
|
+
}
|
|
89
97
|
const { formData } = props
|
|
90
98
|
const {
|
|
91
99
|
themeName,
|
|
92
100
|
themeText
|
|
93
101
|
} = res
|
|
102
|
+
const converted = convertTheme(themeText)
|
|
103
|
+
|
|
104
|
+
if (converted.uiThemeConfig.main !== converted.themeConfig.background) {
|
|
105
|
+
converted.themeConfig.background = converted.uiThemeConfig.main
|
|
106
|
+
}
|
|
94
107
|
const update = {
|
|
95
108
|
name: themeName,
|
|
96
|
-
...
|
|
109
|
+
...converted
|
|
97
110
|
}
|
|
98
111
|
const update1 = {
|
|
99
112
|
...update,
|
|
@@ -135,15 +148,22 @@ export default function ThemeForm (props) {
|
|
|
135
148
|
async function beforeUpload (file) {
|
|
136
149
|
const txt = await window.fs.readFile(file.path)
|
|
137
150
|
const { name, themeConfig, uiThemeConfig } = convertTheme(txt)
|
|
151
|
+
const tt = convertThemeToText({
|
|
152
|
+
themeConfig, uiThemeConfig
|
|
153
|
+
})
|
|
138
154
|
form.setFieldsValue({
|
|
139
155
|
themeName: name,
|
|
140
|
-
themeText:
|
|
141
|
-
themeConfig, uiThemeConfig
|
|
142
|
-
})
|
|
156
|
+
themeText: tt
|
|
143
157
|
})
|
|
158
|
+
setTxt(tt)
|
|
144
159
|
return false
|
|
145
160
|
}
|
|
146
161
|
|
|
162
|
+
function handleSwitchEditor (e) {
|
|
163
|
+
e.preventDefault()
|
|
164
|
+
setEditor(editor === 'theme-editor-txt' ? 'theme-editor-color-picker' : 'theme-editor-txt')
|
|
165
|
+
}
|
|
166
|
+
|
|
147
167
|
function renderFuncs (id) {
|
|
148
168
|
if (!id) {
|
|
149
169
|
return null
|
|
@@ -160,6 +180,43 @@ export default function ThemeForm (props) {
|
|
|
160
180
|
)
|
|
161
181
|
}
|
|
162
182
|
|
|
183
|
+
function onPickerChange (value, name) {
|
|
184
|
+
const realName = name.includes('terminal:')
|
|
185
|
+
? name.replace('terminal:', '')
|
|
186
|
+
: name
|
|
187
|
+
const text = form.getFieldValue('themeText')
|
|
188
|
+
const obj = convertTheme(text)
|
|
189
|
+
if (obj.themeConfig[realName]) {
|
|
190
|
+
obj.themeConfig[realName] = value
|
|
191
|
+
} else if (obj.uiThemeConfig[realName]) {
|
|
192
|
+
obj.uiThemeConfig[realName] = value
|
|
193
|
+
}
|
|
194
|
+
form.setFieldsValue({
|
|
195
|
+
themeText: convertThemeToText(obj)
|
|
196
|
+
})
|
|
197
|
+
setTxt(convertThemeToText(obj))
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function renderTxt () {
|
|
201
|
+
return (
|
|
202
|
+
<FormItem
|
|
203
|
+
noStyle
|
|
204
|
+
name='themeText'
|
|
205
|
+
hasFeedback
|
|
206
|
+
rules={[{
|
|
207
|
+
max: 1000, message: '1000 chars max'
|
|
208
|
+
}, {
|
|
209
|
+
required: true,
|
|
210
|
+
message: 'theme config required'
|
|
211
|
+
}, {
|
|
212
|
+
validator: validateInput
|
|
213
|
+
}]}
|
|
214
|
+
>
|
|
215
|
+
<TextArea rows={33} disabled={disabled} />
|
|
216
|
+
</FormItem>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
163
220
|
const {
|
|
164
221
|
readonly,
|
|
165
222
|
id,
|
|
@@ -173,12 +230,18 @@ export default function ThemeForm (props) {
|
|
|
173
230
|
const { autofocustrigger } = props.store
|
|
174
231
|
const isDefaultTheme = id === defaultTheme.id || id === defaultThemeLight.id
|
|
175
232
|
const disabled = readonly || isDefaultTheme
|
|
233
|
+
const switchTxt = editor === 'theme-editor-txt' ? e('editWithColorPicker') : e('editWithTextEditor')
|
|
234
|
+
const pickerProps = {
|
|
235
|
+
onChange: onPickerChange,
|
|
236
|
+
themeText: txt,
|
|
237
|
+
disabled
|
|
238
|
+
}
|
|
176
239
|
return (
|
|
177
240
|
<Form
|
|
178
241
|
onFinish={handleSubmit}
|
|
179
242
|
form={form}
|
|
180
243
|
initialValues={initialValues}
|
|
181
|
-
className=
|
|
244
|
+
className={editor}
|
|
182
245
|
name='terminal-theme-form'
|
|
183
246
|
layout='vertical'
|
|
184
247
|
>
|
|
@@ -202,35 +265,41 @@ export default function ThemeForm (props) {
|
|
|
202
265
|
<FormItem
|
|
203
266
|
label={e('themeConfig')}
|
|
204
267
|
>
|
|
205
|
-
<div className='
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
268
|
+
<div className='mg1b fix'>
|
|
269
|
+
<span className='fleft'>
|
|
270
|
+
<Space compact>
|
|
271
|
+
<Button
|
|
272
|
+
type='dashed'
|
|
273
|
+
onClick={handleSwitchEditor}
|
|
274
|
+
>
|
|
275
|
+
{switchTxt}
|
|
276
|
+
</Button>
|
|
277
|
+
</Space>
|
|
278
|
+
</span>
|
|
279
|
+
<span className='fright'>
|
|
280
|
+
<Upload
|
|
281
|
+
beforeUpload={beforeUpload}
|
|
282
|
+
fileList={[]}
|
|
283
|
+
className='mg1b'
|
|
214
284
|
>
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
285
|
+
<Button
|
|
286
|
+
type='dashed'
|
|
287
|
+
disabled={disabled}
|
|
288
|
+
>
|
|
289
|
+
{e('importFromFile')}
|
|
290
|
+
</Button>
|
|
291
|
+
</Upload>
|
|
292
|
+
</span>
|
|
218
293
|
</div>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}, {
|
|
229
|
-
validator: validateInput
|
|
230
|
-
}]}
|
|
231
|
-
>
|
|
232
|
-
<TextArea rows={33} disabled={disabled} />
|
|
233
|
-
</FormItem>
|
|
294
|
+
{
|
|
295
|
+
editor === 'theme-editor-txt'
|
|
296
|
+
? renderTxt()
|
|
297
|
+
: (
|
|
298
|
+
<ThemePicker
|
|
299
|
+
{...pickerProps}
|
|
300
|
+
/>
|
|
301
|
+
)
|
|
302
|
+
}
|
|
234
303
|
</FormItem>
|
|
235
304
|
{
|
|
236
305
|
disabled
|
|
@@ -71,7 +71,8 @@ export default class VncSession extends RdpSession {
|
|
|
71
71
|
server = ''
|
|
72
72
|
} = config
|
|
73
73
|
const { sessionId, id } = this.props
|
|
74
|
-
const tab = deepCopy(this.props.tab || {})
|
|
74
|
+
const tab = window.store.applyProfile(deepCopy(this.props.tab || {}))
|
|
75
|
+
console.log('vnc tab', this.props.tab)
|
|
75
76
|
const {
|
|
76
77
|
type,
|
|
77
78
|
term: terminalType,
|
package/client/store/common.js
CHANGED
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
modals,
|
|
13
13
|
leftSidebarWidthKey,
|
|
14
14
|
rightSidebarWidthKey,
|
|
15
|
-
dismissDelKeyTipLsKey
|
|
15
|
+
dismissDelKeyTipLsKey,
|
|
16
|
+
connectionMap
|
|
16
17
|
} from '../common/constants'
|
|
17
18
|
import * as ls from '../common/safe-local-storage'
|
|
18
19
|
|
|
@@ -212,10 +213,11 @@ export default Store => {
|
|
|
212
213
|
|
|
213
214
|
Store.prototype.applyProfile = function (tab) {
|
|
214
215
|
const {
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
profile,
|
|
217
|
+
type,
|
|
218
|
+
authType
|
|
217
219
|
} = tab
|
|
218
|
-
if (authType !== 'profiles') {
|
|
220
|
+
if (!profile || authType !== 'profiles') {
|
|
219
221
|
return tab
|
|
220
222
|
}
|
|
221
223
|
const p = window.store.profiles.find(x => x.id === profile)
|
|
@@ -227,6 +229,25 @@ export default Store => {
|
|
|
227
229
|
// delete tab.passphrase
|
|
228
230
|
delete p.name
|
|
229
231
|
delete p.id
|
|
232
|
+
if (type === connectionMap.rdp) {
|
|
233
|
+
return {
|
|
234
|
+
...tab,
|
|
235
|
+
...p.rdp
|
|
236
|
+
}
|
|
237
|
+
} else if (type === connectionMap.vnc) {
|
|
238
|
+
return {
|
|
239
|
+
...tab,
|
|
240
|
+
...p.vnc
|
|
241
|
+
}
|
|
242
|
+
} else if (type === connectionMap.telnet) {
|
|
243
|
+
return {
|
|
244
|
+
...tab,
|
|
245
|
+
...p.telnet
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
delete p.rdp
|
|
249
|
+
delete p.vnc
|
|
250
|
+
delete p.telnet
|
|
230
251
|
return {
|
|
231
252
|
...tab,
|
|
232
253
|
...p
|
package/client/store/sync.js
CHANGED
|
@@ -120,7 +120,6 @@ export default (Store) => {
|
|
|
120
120
|
const { store } = window
|
|
121
121
|
const currentSyncType = store.syncType
|
|
122
122
|
const currentSettings = store.config.syncSetting || {}
|
|
123
|
-
console.log('currentSettings: ', currentSyncType, currentSettings)
|
|
124
123
|
// Create a new object without the current sync type's settings
|
|
125
124
|
const updatedSettings = Object.keys(currentSettings).reduce((acc, key) => {
|
|
126
125
|
if (!key.startsWith(currentSyncType)) {
|
|
@@ -128,8 +127,6 @@ export default (Store) => {
|
|
|
128
127
|
}
|
|
129
128
|
return acc
|
|
130
129
|
}, {})
|
|
131
|
-
console.log('updatedSettings: ', updatedSettings)
|
|
132
|
-
|
|
133
130
|
store.setConfig({
|
|
134
131
|
syncSetting: updatedSettings
|
|
135
132
|
})
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|