@electerm/electerm-react 1.39.2 → 1.39.18
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 +2 -0
- package/client/components/bookmark-form/form-ssh-common.jsx +1 -1
- package/client/components/bookmark-form/rdp-form-ui.jsx +37 -2
- 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/web-form-ui.jsx +31 -1
- package/client/components/footer/footer-entry.jsx +12 -6
- package/client/components/main/main.jsx +1 -1
- package/client/components/quick-commands/quick-commands-list-form.jsx +54 -3
- package/client/components/{session → rdp}/rdp-session.jsx +7 -2
- package/client/components/session/session.jsx +1 -1
- package/client/components/session/sessions.jsx +1 -1
- package/client/components/setting-panel/setting-modal.jsx +9 -6
- package/client/components/setting-panel/setting-wrap.jsx +5 -1
- package/client/components/setting-panel/setting-wrap.styl +5 -3
- package/client/components/tabs/index.jsx +1 -1
- package/client/components/tabs/tab.jsx +9 -4
- package/client/components/terminal/index.jsx +11 -2
- package/client/components/terminal/term-search.jsx +12 -0
- package/client/store/load-data.js +9 -1
- package/client/store/sync.js +7 -3
- package/package.json +1 -1
- /package/client/components/{session → rdp}/code-scan.js +0 -0
- /package/client/components/{session → rdp}/resolution-edit.jsx +0 -0
- /package/client/components/{session → rdp}/resolution-form.jsx +0 -0
- /package/client/components/{session → rdp}/resolutions.js +0 -0
- /package/client/components/{session → web}/web-session.jsx +0 -0
|
@@ -238,6 +238,7 @@ export const terminalActions = {
|
|
|
238
238
|
openTerminalSearch: 'open-terminal-search',
|
|
239
239
|
doSearchNext: 'do-search-next',
|
|
240
240
|
doSearchPrev: 'do-search-prev',
|
|
241
|
+
clearSearch: 'clear-search',
|
|
241
242
|
zoom: 'zoom-terminal'
|
|
242
243
|
}
|
|
243
244
|
export const fileActions = {
|
|
@@ -317,6 +318,7 @@ export const sshTunnelHelpLink = 'https://github.com/electerm/electerm/wiki/How-
|
|
|
317
318
|
export const batchOpHelpLink = 'https://github.com/electerm/electerm/wiki/batch-operation'
|
|
318
319
|
export const proxyHelpLink = 'https://github.com/electerm/electerm/wiki/proxy-format'
|
|
319
320
|
export const regexHelpLink = 'https://github.com/electerm/electerm/wiki/Terminal-keywords-highlight-regular-expression-exmaples'
|
|
321
|
+
export const rdpHelpLink = 'https://github.com/electerm/electerm/wiki/RDP-limitation'
|
|
320
322
|
export const modals = {
|
|
321
323
|
hide: 0,
|
|
322
324
|
setting: 1,
|
|
@@ -6,22 +6,28 @@ import { useEffect } from 'react'
|
|
|
6
6
|
import {
|
|
7
7
|
Input,
|
|
8
8
|
Form,
|
|
9
|
-
InputNumber
|
|
9
|
+
InputNumber,
|
|
10
|
+
TreeSelect
|
|
10
11
|
} from 'antd'
|
|
11
12
|
import { formItemLayout } from '../../common/form-layout'
|
|
12
13
|
import {
|
|
13
14
|
newBookmarkIdPrefix,
|
|
14
|
-
terminalRdpType
|
|
15
|
+
terminalRdpType,
|
|
16
|
+
rdpHelpLink
|
|
15
17
|
} from '../../common/constants'
|
|
16
18
|
import useSubmit from './use-submit'
|
|
17
19
|
import copy from 'json-deep-copy'
|
|
20
|
+
import Link from '../common/external-link.jsx'
|
|
18
21
|
import { defaults } from 'lodash-es'
|
|
19
22
|
import { ColorPickerItem } from './color-picker-item.jsx'
|
|
20
23
|
import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
|
|
24
|
+
import formatBookmarkGroups from './bookmark-group-tree-format'
|
|
25
|
+
import findBookmarkGroupId from '../../common/find-bookmark-group-id'
|
|
21
26
|
|
|
22
27
|
const FormItem = Form.Item
|
|
23
28
|
const { prefix } = window
|
|
24
29
|
const e = prefix('form')
|
|
30
|
+
const c = prefix('common')
|
|
25
31
|
|
|
26
32
|
export default function LocalFormUi (props) {
|
|
27
33
|
const [
|
|
@@ -36,16 +42,34 @@ export default function LocalFormUi (props) {
|
|
|
36
42
|
})
|
|
37
43
|
}
|
|
38
44
|
}, [props.currentBookmarkGroupId])
|
|
45
|
+
const {
|
|
46
|
+
id = ''
|
|
47
|
+
} = props.formData
|
|
48
|
+
const {
|
|
49
|
+
bookmarkGroups = [],
|
|
50
|
+
currentBookmarkGroupId
|
|
51
|
+
} = props
|
|
39
52
|
let initialValues = copy(props.formData)
|
|
53
|
+
const initBookmarkGroupId = !id.startsWith(newBookmarkIdPrefix)
|
|
54
|
+
? findBookmarkGroupId(bookmarkGroups, id)
|
|
55
|
+
: currentBookmarkGroupId
|
|
40
56
|
const defaultValues = {
|
|
41
57
|
type: terminalRdpType,
|
|
42
58
|
port: 3389,
|
|
59
|
+
category: initBookmarkGroupId,
|
|
43
60
|
color: getRandomDefaultColor()
|
|
44
61
|
}
|
|
45
62
|
initialValues = defaults(initialValues, defaultValues)
|
|
46
63
|
function renderCommon () {
|
|
64
|
+
const {
|
|
65
|
+
bookmarkGroups = []
|
|
66
|
+
} = props
|
|
67
|
+
const tree = formatBookmarkGroups(bookmarkGroups)
|
|
47
68
|
return (
|
|
48
69
|
<div className='pd1x'>
|
|
70
|
+
<p className='alignright'>
|
|
71
|
+
<Link to={rdpHelpLink}>Wiki: {rdpHelpLink}</Link>
|
|
72
|
+
</p>
|
|
49
73
|
<FormItem
|
|
50
74
|
{...formItemLayout}
|
|
51
75
|
label={e('title')}
|
|
@@ -114,6 +138,17 @@ export default function LocalFormUi (props) {
|
|
|
114
138
|
>
|
|
115
139
|
<Input />
|
|
116
140
|
</FormItem>
|
|
141
|
+
<FormItem
|
|
142
|
+
{...formItemLayout}
|
|
143
|
+
label={c('bookmarkCategory')}
|
|
144
|
+
name='category'
|
|
145
|
+
>
|
|
146
|
+
<TreeSelect
|
|
147
|
+
treeData={tree}
|
|
148
|
+
treeDefaultExpandAll
|
|
149
|
+
showSearch
|
|
150
|
+
/>
|
|
151
|
+
</FormItem>
|
|
117
152
|
<FormItem
|
|
118
153
|
{...formItemLayout}
|
|
119
154
|
label='type'
|
|
@@ -35,10 +35,14 @@ export default function renderSshTunnels (props) {
|
|
|
35
35
|
sshTunnelRemotePort: 12300,
|
|
36
36
|
sshTunnelRemoteHost: '127.0.0.1'
|
|
37
37
|
})
|
|
38
|
+
const [isDynamic, setter] = useState(formData.sshTunnel === 'dynamicForward')
|
|
38
39
|
const [list, setList] = useState(formData.sshTunnels || [])
|
|
39
40
|
function onSubmit () {
|
|
40
41
|
formChild.submit()
|
|
41
42
|
}
|
|
43
|
+
function onChange (e) {
|
|
44
|
+
setter(e.target.value === 'dynamicForward')
|
|
45
|
+
}
|
|
42
46
|
function handleFinish (data) {
|
|
43
47
|
const nd = {
|
|
44
48
|
...data,
|
|
@@ -80,7 +84,7 @@ export default function renderSshTunnels (props) {
|
|
|
80
84
|
title: e('sshTunnel'),
|
|
81
85
|
key: 'sshTunnel',
|
|
82
86
|
render: (k, item) => {
|
|
83
|
-
// sshTunnel is forwardRemoteToLocal or forwardLocalToRemote
|
|
87
|
+
// sshTunnel is forwardRemoteToLocal or forwardLocalToRemote or dynamicForward
|
|
84
88
|
const {
|
|
85
89
|
sshTunnel,
|
|
86
90
|
sshTunnelRemoteHost = '127.0.0.1',
|
|
@@ -89,6 +93,9 @@ export default function renderSshTunnels (props) {
|
|
|
89
93
|
sshTunnelLocalPort,
|
|
90
94
|
name
|
|
91
95
|
} = item
|
|
96
|
+
if (sshTunnel === 'dynamicForward') {
|
|
97
|
+
return `socks5://${sshTunnelLocalHost}:${sshTunnelLocalPort}`
|
|
98
|
+
}
|
|
92
99
|
const to = sshTunnel === 'forwardRemoteToLocal'
|
|
93
100
|
? `${s('local')}:${sshTunnelLocalHost}:${sshTunnelLocalPort}`
|
|
94
101
|
: `${s('remote')}:${sshTunnelRemoteHost}:${sshTunnelRemotePort}`
|
|
@@ -148,6 +155,49 @@ export default function renderSshTunnels (props) {
|
|
|
148
155
|
)
|
|
149
156
|
}
|
|
150
157
|
|
|
158
|
+
function renderDynamicForward () {
|
|
159
|
+
return (
|
|
160
|
+
<p><UserOutlined /> → socks proxy → url</p>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function renderRemote () {
|
|
165
|
+
if (isDynamic) {
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
168
|
+
return (
|
|
169
|
+
<FormItem
|
|
170
|
+
label={s('remote')}
|
|
171
|
+
{...formItemLayout}
|
|
172
|
+
required
|
|
173
|
+
className='ssh-tunnels-host'
|
|
174
|
+
>
|
|
175
|
+
<Space.Compact>
|
|
176
|
+
<FormItem
|
|
177
|
+
name='sshTunnelRemoteHost'
|
|
178
|
+
label=''
|
|
179
|
+
required
|
|
180
|
+
>
|
|
181
|
+
<Input
|
|
182
|
+
placeholder={e('host')}
|
|
183
|
+
/>
|
|
184
|
+
</FormItem>
|
|
185
|
+
<FormItem
|
|
186
|
+
label=''
|
|
187
|
+
name='sshTunnelRemotePort'
|
|
188
|
+
required
|
|
189
|
+
>
|
|
190
|
+
<InputNumber
|
|
191
|
+
min={1}
|
|
192
|
+
max={65535}
|
|
193
|
+
placeholder={e('port')}
|
|
194
|
+
/>
|
|
195
|
+
</FormItem>
|
|
196
|
+
</Space.Compact>
|
|
197
|
+
</FormItem>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
151
201
|
return (
|
|
152
202
|
<div>
|
|
153
203
|
<FormItem
|
|
@@ -168,7 +218,7 @@ export default function renderSshTunnels (props) {
|
|
|
168
218
|
{...formItemLayout}
|
|
169
219
|
required
|
|
170
220
|
>
|
|
171
|
-
<RadioGroup>
|
|
221
|
+
<RadioGroup onChange={onChange}>
|
|
172
222
|
<RadioButton
|
|
173
223
|
value='forwardRemoteToLocal'
|
|
174
224
|
>
|
|
@@ -183,37 +233,16 @@ export default function renderSshTunnels (props) {
|
|
|
183
233
|
<span>L→R <QuestionCircleOutlined /></span>
|
|
184
234
|
</Tooltip>
|
|
185
235
|
</RadioButton>
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
<FormItem
|
|
189
|
-
label={s('remote')}
|
|
190
|
-
{...formItemLayout}
|
|
191
|
-
required
|
|
192
|
-
className='ssh-tunnels-host'
|
|
193
|
-
>
|
|
194
|
-
<Space.Compact>
|
|
195
|
-
<FormItem
|
|
196
|
-
name='sshTunnelRemoteHost'
|
|
197
|
-
label=''
|
|
198
|
-
required
|
|
199
|
-
>
|
|
200
|
-
<Input
|
|
201
|
-
placeholder={e('host')}
|
|
202
|
-
/>
|
|
203
|
-
</FormItem>
|
|
204
|
-
<FormItem
|
|
205
|
-
label=''
|
|
206
|
-
name='sshTunnelRemotePort'
|
|
207
|
-
required
|
|
236
|
+
<RadioButton
|
|
237
|
+
value='dynamicForward'
|
|
208
238
|
>
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
</FormItem>
|
|
215
|
-
</Space.Compact>
|
|
239
|
+
<Tooltip title={renderDynamicForward()}>
|
|
240
|
+
<span>{e('dynamicForward')}(socks proxy) <QuestionCircleOutlined /></span>
|
|
241
|
+
</Tooltip>
|
|
242
|
+
</RadioButton>
|
|
243
|
+
</RadioGroup>
|
|
216
244
|
</FormItem>
|
|
245
|
+
{renderRemote()}
|
|
217
246
|
<FormItem
|
|
218
247
|
label={s('local')}
|
|
219
248
|
{...formItemLayout}
|
|
@@ -87,6 +87,18 @@ export default function useBookmarkFormUI (props) {
|
|
|
87
87
|
step={1}
|
|
88
88
|
placeholder={defaultFontSize}
|
|
89
89
|
/>
|
|
90
|
+
</FormItem>,
|
|
91
|
+
<FormItem
|
|
92
|
+
key='keepaliveInterval'
|
|
93
|
+
{...formItemLayout}
|
|
94
|
+
label={s('keepaliveIntervalDesc')}
|
|
95
|
+
name='keepaliveInterval'
|
|
96
|
+
>
|
|
97
|
+
<InputNumber
|
|
98
|
+
min={0}
|
|
99
|
+
max={20000000}
|
|
100
|
+
step={1000}
|
|
101
|
+
/>
|
|
90
102
|
</FormItem>
|
|
91
103
|
]
|
|
92
104
|
}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
import { useEffect } from 'react'
|
|
6
6
|
import {
|
|
7
7
|
Input,
|
|
8
|
-
Form
|
|
8
|
+
Form,
|
|
9
|
+
TreeSelect
|
|
9
10
|
} from 'antd'
|
|
10
11
|
import { formItemLayout } from '../../common/form-layout'
|
|
11
12
|
import {
|
|
@@ -17,10 +18,13 @@ import copy from 'json-deep-copy'
|
|
|
17
18
|
import { defaults } from 'lodash-es'
|
|
18
19
|
import { ColorPickerItem } from './color-picker-item.jsx'
|
|
19
20
|
import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
|
|
21
|
+
import formatBookmarkGroups from './bookmark-group-tree-format'
|
|
22
|
+
import findBookmarkGroupId from '../../common/find-bookmark-group-id'
|
|
20
23
|
|
|
21
24
|
const FormItem = Form.Item
|
|
22
25
|
const { prefix } = window
|
|
23
26
|
const e = prefix('form')
|
|
27
|
+
const c = prefix('common')
|
|
24
28
|
|
|
25
29
|
export default function LocalFormUi (props) {
|
|
26
30
|
const [
|
|
@@ -35,13 +39,28 @@ export default function LocalFormUi (props) {
|
|
|
35
39
|
})
|
|
36
40
|
}
|
|
37
41
|
}, [props.currentBookmarkGroupId])
|
|
42
|
+
const {
|
|
43
|
+
id = ''
|
|
44
|
+
} = props.formData
|
|
45
|
+
const {
|
|
46
|
+
bookmarkGroups = [],
|
|
47
|
+
currentBookmarkGroupId
|
|
48
|
+
} = props
|
|
49
|
+
const initBookmarkGroupId = !id.startsWith(newBookmarkIdPrefix)
|
|
50
|
+
? findBookmarkGroupId(bookmarkGroups, id)
|
|
51
|
+
: currentBookmarkGroupId
|
|
38
52
|
let initialValues = copy(props.formData)
|
|
39
53
|
const defaultValues = {
|
|
40
54
|
type: terminalWebType,
|
|
55
|
+
category: initBookmarkGroupId,
|
|
41
56
|
color: getRandomDefaultColor()
|
|
42
57
|
}
|
|
43
58
|
initialValues = defaults(initialValues, defaultValues)
|
|
44
59
|
function renderCommon () {
|
|
60
|
+
const {
|
|
61
|
+
bookmarkGroups = []
|
|
62
|
+
} = props
|
|
63
|
+
const tree = formatBookmarkGroups(bookmarkGroups)
|
|
45
64
|
return (
|
|
46
65
|
<div className='pd1x'>
|
|
47
66
|
<FormItem
|
|
@@ -70,6 +89,17 @@ export default function LocalFormUi (props) {
|
|
|
70
89
|
>
|
|
71
90
|
<Input.TextArea rows={1} />
|
|
72
91
|
</FormItem>
|
|
92
|
+
<FormItem
|
|
93
|
+
{...formItemLayout}
|
|
94
|
+
label={c('bookmarkCategory')}
|
|
95
|
+
name='category'
|
|
96
|
+
>
|
|
97
|
+
<TreeSelect
|
|
98
|
+
treeData={tree}
|
|
99
|
+
treeDefaultExpandAll
|
|
100
|
+
showSearch
|
|
101
|
+
/>
|
|
102
|
+
</FormItem>
|
|
73
103
|
<FormItem
|
|
74
104
|
{...formItemLayout}
|
|
75
105
|
label='type'
|
|
@@ -76,21 +76,27 @@ export default class SystemMenu extends Component {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
renderEncodingInfo () {
|
|
79
|
+
const selectProps = {
|
|
80
|
+
style: {
|
|
81
|
+
minWidth: 30
|
|
82
|
+
},
|
|
83
|
+
placeholder: f('encode'),
|
|
84
|
+
defaultValue: this.props.currentTab?.encode,
|
|
85
|
+
onSelect: this.handleSwitchEncoding,
|
|
86
|
+
size: 'small',
|
|
87
|
+
popupMatchSelectWidth: false
|
|
88
|
+
}
|
|
79
89
|
return (
|
|
80
90
|
<div className='terminal-footer-unit terminal-footer-info'>
|
|
81
91
|
<div className='fleft relative'>
|
|
82
92
|
<Select
|
|
83
|
-
|
|
84
|
-
placeholder={f('encode')}
|
|
85
|
-
defaultValue={this.props.currentTab?.encode}
|
|
86
|
-
onSelect={this.handleSwitchEncoding}
|
|
87
|
-
size='small'
|
|
93
|
+
{...selectProps}
|
|
88
94
|
>
|
|
89
95
|
{
|
|
90
96
|
encodes.map(k => {
|
|
91
97
|
return (
|
|
92
98
|
<Option key={k} value={k}>
|
|
93
|
-
{k}
|
|
99
|
+
{k.toUpperCase()}
|
|
94
100
|
</Option>
|
|
95
101
|
)
|
|
96
102
|
})
|
|
@@ -11,7 +11,7 @@ import BatchOp from '../batch-op/batch-op'
|
|
|
11
11
|
import CssOverwrite from './css-overwrite'
|
|
12
12
|
import UiTheme from './ui-theme'
|
|
13
13
|
import CustomCss from './custom-css.jsx'
|
|
14
|
-
import Resolutions from '../
|
|
14
|
+
import Resolutions from '../rdp/resolution-edit'
|
|
15
15
|
import TerminalInteractive from '../terminal/terminal-interactive'
|
|
16
16
|
import ConfirmModalStore from '../sftp/confirm-modal-store.jsx'
|
|
17
17
|
import TransferConflictStore from '../sftp/transfer-conflict-store.jsx'
|
|
@@ -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
|
>
|
|
@@ -4,7 +4,8 @@ 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
|
|
7
|
+
statusMap,
|
|
8
|
+
rdpHelpLink
|
|
8
9
|
} from '../../common/constants'
|
|
9
10
|
import {
|
|
10
11
|
notification,
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
ReloadOutlined,
|
|
17
18
|
EditOutlined
|
|
18
19
|
} from '@ant-design/icons'
|
|
20
|
+
import HelpIcon from '../common/help-icon'
|
|
19
21
|
import * as ls from '../../common/safe-local-storage'
|
|
20
22
|
import scanCode from './code-scan'
|
|
21
23
|
import resolutions from './resolutions'
|
|
@@ -388,9 +390,12 @@ export default class RdpSession extends Component {
|
|
|
388
390
|
onClick={this.handleEditResolutions}
|
|
389
391
|
className='mg2r mg1l pointer'
|
|
390
392
|
/>
|
|
391
|
-
<span className='mg2l'>
|
|
393
|
+
<span className='mg2l mg2r'>
|
|
392
394
|
{username}@{host}:{port}
|
|
393
395
|
</span>
|
|
396
|
+
<HelpIcon
|
|
397
|
+
link={rdpHelpLink}
|
|
398
|
+
/>
|
|
394
399
|
</div>
|
|
395
400
|
)
|
|
396
401
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Component } from '../common/react-subx'
|
|
2
2
|
import Session from './session'
|
|
3
|
-
import WebSession from '
|
|
3
|
+
import WebSession from '../web/web-session.jsx'
|
|
4
4
|
import { findIndex, pick } from 'lodash-es'
|
|
5
5
|
import classNames from 'classnames'
|
|
6
6
|
import generate from '../../common/uid'
|
|
@@ -94,15 +94,18 @@ export default class SettingModalWrap extends Component {
|
|
|
94
94
|
children: null
|
|
95
95
|
}
|
|
96
96
|
]
|
|
97
|
+
const tabsProps = {
|
|
98
|
+
activeKey: settingTab,
|
|
99
|
+
animated: false,
|
|
100
|
+
items,
|
|
101
|
+
onChange: store.handleChangeSettingTab,
|
|
102
|
+
destroyInactiveTabPane: true,
|
|
103
|
+
className: 'setting-tabs'
|
|
104
|
+
}
|
|
97
105
|
return (
|
|
98
106
|
<div>
|
|
99
107
|
<Tabs
|
|
100
|
-
|
|
101
|
-
animated={false}
|
|
102
|
-
items={items}
|
|
103
|
-
onChange={store.handleChangeSettingTab}
|
|
104
|
-
destroyInactiveTabPane
|
|
105
|
-
className='setting-tabs'
|
|
108
|
+
{...tabsProps}
|
|
106
109
|
/>
|
|
107
110
|
<TabHistory
|
|
108
111
|
listProps={props0}
|
|
@@ -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
|
|
@@ -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
|
)
|
|
@@ -363,6 +363,13 @@ class Term extends Component {
|
|
|
363
363
|
)
|
|
364
364
|
) {
|
|
365
365
|
this.searchPrev(keyword, options)
|
|
366
|
+
} else if (
|
|
367
|
+
action === terminalActions.clearSearch &&
|
|
368
|
+
(
|
|
369
|
+
propSplitId === activeSplitId
|
|
370
|
+
)
|
|
371
|
+
) {
|
|
372
|
+
this.searchAddon.clearDecorations()
|
|
366
373
|
} else if (
|
|
367
374
|
action === commonActions.getTermLogState &&
|
|
368
375
|
pid === statePid
|
|
@@ -1018,8 +1025,9 @@ class Term extends Component {
|
|
|
1018
1025
|
const cmd = `ssh ${title.split(/\s/g)[0]}\r`
|
|
1019
1026
|
return this.attachAddon._sendData(cmd)
|
|
1020
1027
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1028
|
+
const startFolder = startDirectory || window.initFolder
|
|
1029
|
+
if (startFolder) {
|
|
1030
|
+
const cmd = `cd ${startFolder}\r`
|
|
1023
1031
|
this.attachAddon._sendData(cmd)
|
|
1024
1032
|
}
|
|
1025
1033
|
if (runScripts && runScripts.length) {
|
|
@@ -1119,6 +1127,7 @@ class Term extends Component {
|
|
|
1119
1127
|
'execLinuxArgs',
|
|
1120
1128
|
'debug'
|
|
1121
1129
|
]),
|
|
1130
|
+
keepaliveInterval: tab.keepaliveInterval === undefined ? config.keepaliveInterval : tab.keepaliveInterval,
|
|
1122
1131
|
sessionId,
|
|
1123
1132
|
tabId: id,
|
|
1124
1133
|
srcTabId: tab.id,
|
|
@@ -55,6 +55,9 @@ class TermSearch extends Component {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
toggleSearch = () => {
|
|
58
|
+
if (this.props.store.termSearchOpen) {
|
|
59
|
+
this.clearSearch()
|
|
60
|
+
}
|
|
58
61
|
this.props.store.toggleTerminalSearch()
|
|
59
62
|
setTimeout(window.store.focus, 200)
|
|
60
63
|
}
|
|
@@ -89,7 +92,16 @@ class TermSearch extends Component {
|
|
|
89
92
|
this.prev()
|
|
90
93
|
}
|
|
91
94
|
|
|
95
|
+
clearSearch = () => {
|
|
96
|
+
const { activeTerminalId } = this.props.store
|
|
97
|
+
postMessage({
|
|
98
|
+
action: terminalActions.clearSearch,
|
|
99
|
+
activeSplitId: activeTerminalId
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
92
103
|
close = () => {
|
|
104
|
+
this.clearSearch()
|
|
93
105
|
this.props.store.termSearchOpen = false
|
|
94
106
|
}
|
|
95
107
|
|
|
@@ -60,7 +60,8 @@ export async function addTabFromCommandLine (store, opts) {
|
|
|
60
60
|
enableSsh: !options.sftpOnly,
|
|
61
61
|
authType: 'password',
|
|
62
62
|
pane: options.type || 'terminal',
|
|
63
|
-
term: defaultSettings.terminalType
|
|
63
|
+
term: defaultSettings.terminalType,
|
|
64
|
+
startDirectoryLocal: options.initFolder
|
|
64
65
|
}
|
|
65
66
|
if (options.setEnv) {
|
|
66
67
|
update.setEnv = options.setEnv
|
|
@@ -79,8 +80,15 @@ export async function addTabFromCommandLine (store, opts) {
|
|
|
79
80
|
conf.privateKey = await fs.readFile(options.privateKeyPath)
|
|
80
81
|
}
|
|
81
82
|
log.debug('command line opts', conf)
|
|
83
|
+
console.log(options.initFolder, !(store.config.onStartSessions || []).length, store.config.initDefaultTabOnStart)
|
|
82
84
|
if (conf.username && conf.host) {
|
|
83
85
|
store.addTab(conf)
|
|
86
|
+
} else if (
|
|
87
|
+
options.initFolder &&
|
|
88
|
+
!(store.config.onStartSessions || []).length &&
|
|
89
|
+
store.config.initDefaultTabOnStart
|
|
90
|
+
) {
|
|
91
|
+
window.initFolder = options.initFolder
|
|
84
92
|
}
|
|
85
93
|
if (options && options.batchOp) {
|
|
86
94
|
window.store.runBatchOp(options.batchOp)
|
package/client/store/sync.js
CHANGED
|
@@ -233,9 +233,13 @@ export default (Store) => {
|
|
|
233
233
|
for (const n of names) {
|
|
234
234
|
let str = get(gist, `files["${n}.json"].content`)
|
|
235
235
|
if (!str) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
if (n === settingMap.bookmarks) {
|
|
237
|
+
store.isSyncingSetting = false
|
|
238
|
+
store.isSyncDownload = false
|
|
239
|
+
throw new Error(('Seems you have a empty gist, you can try use existing gist ID or upload first'))
|
|
240
|
+
} else {
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
239
243
|
}
|
|
240
244
|
if (!isJSON(str)) {
|
|
241
245
|
str = await window.pre.runGlobalAsync('decryptAsync', str, pass)
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|