@electerm/electerm-react 3.1.26 → 3.3.8
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 +1 -3
- package/client/common/db.js +4 -2
- package/client/components/ai/ai-history.jsx +4 -4
- package/client/components/batch-op/batch-op-alert.jsx +42 -0
- package/client/components/batch-op/batch-op-editor.jsx +202 -0
- package/client/components/batch-op/batch-op-logs.jsx +53 -0
- package/client/components/batch-op/batch-op-runner.jsx +315 -0
- package/client/components/bookmark-form/ai-bookmark-form.jsx +2 -1
- package/client/components/bookmark-form/bookmark-from-history-modal.jsx +2 -1
- package/client/components/bookmark-form/common/bookmark-select.jsx +18 -2
- package/client/components/bookmark-form/common/connection-hopping-form.jsx +153 -0
- package/client/components/bookmark-form/common/connection-hopping.jsx +136 -129
- package/client/components/common/auto-check-update.jsx +31 -0
- package/client/components/common/notification.styl +1 -1
- package/client/components/file-transfer/conflict-resolve.jsx +3 -0
- package/client/components/footer/batch-input.jsx +10 -7
- package/client/components/main/error-wrapper.jsx +18 -7
- package/client/components/main/main.jsx +6 -7
- package/client/components/quick-commands/qm.styl +0 -2
- package/client/components/quick-commands/quick-commands-list-form.jsx +1 -1
- package/client/components/setting-panel/hotkey.jsx +9 -1
- package/client/components/setting-panel/list.jsx +0 -1
- package/client/components/setting-panel/list.styl +4 -0
- package/client/components/setting-panel/setting-modal.jsx +53 -47
- package/client/components/setting-sync/auto-sync.jsx +53 -0
- package/client/components/setting-sync/data-import.jsx +69 -8
- package/client/components/sftp/address-bar.jsx +7 -1
- package/client/components/shortcuts/shortcut-editor.jsx +4 -2
- package/client/components/sidebar/bookmark-select.jsx +3 -2
- package/client/components/sidebar/history-item.jsx +3 -1
- package/client/components/sidebar/history.jsx +1 -0
- package/client/components/sidebar/index.jsx +0 -9
- package/client/components/tabs/add-btn-menu.jsx +1 -1
- package/client/components/tabs/add-btn.jsx +9 -15
- package/client/components/tabs/quick-connect.jsx +6 -10
- package/client/components/terminal/attach-addon-custom.js +86 -0
- package/client/components/terminal/cmd-item.jsx +13 -3
- package/client/components/terminal/drop-file-modal.jsx +57 -0
- package/client/components/terminal/terminal-command-dropdown.jsx +91 -13
- package/client/components/terminal/terminal.jsx +107 -10
- package/client/components/terminal/terminal.styl +9 -0
- package/client/components/tree-list/tree-list-item.jsx +0 -1
- package/client/components/tree-list/tree-list.jsx +115 -10
- package/client/components/tree-list/tree-list.styl +3 -0
- package/client/components/tree-list/tree-search.jsx +9 -1
- package/client/components/vnc/vnc-session.jsx +2 -0
- package/client/components/widgets/widget-control.jsx +3 -0
- package/client/components/widgets/widget-form.jsx +6 -0
- package/client/components/widgets/widget-instance.jsx +26 -7
- package/client/css/includes/box.styl +3 -0
- package/client/store/common.js +0 -28
- package/client/store/init-state.js +2 -1
- package/client/store/load-data.js +6 -4
- package/client/store/mcp-handler.js +20 -2
- package/client/store/sync.js +25 -1
- package/client/store/tab.js +1 -1
- package/client/store/watch.js +10 -18
- package/client/store/widgets.js +54 -0
- package/client/views/index.pug +1 -2
- package/package.json +1 -1
- package/client/components/batch-op/batch-op.jsx +0 -694
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import React from 'react'
|
|
6
|
-
import { Button
|
|
6
|
+
import { Button } from 'antd'
|
|
7
|
+
import message from '../common/message'
|
|
7
8
|
import { PlusOutlined } from '@ant-design/icons'
|
|
8
9
|
import Modal from '../common/modal'
|
|
9
10
|
import { refsStatic } from '../common/ref'
|
|
@@ -4,6 +4,16 @@ import { TreeSelect } from 'antd'
|
|
|
4
4
|
|
|
5
5
|
const e = window.translate
|
|
6
6
|
|
|
7
|
+
const hoppingProps = [
|
|
8
|
+
'host',
|
|
9
|
+
'port',
|
|
10
|
+
'username',
|
|
11
|
+
'password',
|
|
12
|
+
'privateKey',
|
|
13
|
+
'passphrase',
|
|
14
|
+
'certificate'
|
|
15
|
+
]
|
|
16
|
+
|
|
7
17
|
function buildTreeData (bookmarkGroups, tree) {
|
|
8
18
|
const cats = bookmarkGroups
|
|
9
19
|
const btree = cats.reduce((p, k) => ({ ...p, [k.id]: k }), {})
|
|
@@ -53,8 +63,14 @@ export default function BookmarkSelect (props) {
|
|
|
53
63
|
function onSelect (id) {
|
|
54
64
|
const item = tree[id]
|
|
55
65
|
if (item) {
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
const selected = hoppingProps.reduce((p, k) => {
|
|
67
|
+
if (item[k] !== undefined) {
|
|
68
|
+
p[k] = item[k]
|
|
69
|
+
}
|
|
70
|
+
return p
|
|
71
|
+
}, {})
|
|
72
|
+
selected.bookmarkId = item.id
|
|
73
|
+
props.onSelect(selected)
|
|
58
74
|
}
|
|
59
75
|
}
|
|
60
76
|
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
InputNumber,
|
|
4
|
+
Input,
|
|
5
|
+
Radio,
|
|
6
|
+
Button
|
|
7
|
+
} from 'antd'
|
|
8
|
+
import {
|
|
9
|
+
formItemLayout,
|
|
10
|
+
tailFormItemLayout
|
|
11
|
+
} from '../../../common/form-layout'
|
|
12
|
+
import {
|
|
13
|
+
PlusOutlined,
|
|
14
|
+
SaveOutlined
|
|
15
|
+
} from '@ant-design/icons'
|
|
16
|
+
import RenderAuth from './render-auth-ssh'
|
|
17
|
+
import {
|
|
18
|
+
authTypeMap
|
|
19
|
+
} from '../../../common/constants'
|
|
20
|
+
import { useState } from 'react'
|
|
21
|
+
import BookmarkSelect from './bookmark-select'
|
|
22
|
+
|
|
23
|
+
const FormItem = Form.Item
|
|
24
|
+
const RadioButton = Radio.Button
|
|
25
|
+
const RadioGroup = Radio.Group
|
|
26
|
+
const e = window.translate
|
|
27
|
+
|
|
28
|
+
export default function ConnectionHoppingForm (props) {
|
|
29
|
+
const {
|
|
30
|
+
store,
|
|
31
|
+
formChild,
|
|
32
|
+
initialValues,
|
|
33
|
+
onFinish,
|
|
34
|
+
authTypes: authTypesProp,
|
|
35
|
+
trim,
|
|
36
|
+
isEdit
|
|
37
|
+
} = props
|
|
38
|
+
const [authType, setAuthType] = useState(initialValues.authType || authTypeMap.password)
|
|
39
|
+
|
|
40
|
+
function onChangeAuthType (e) {
|
|
41
|
+
setAuthType(e.target.value)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function onSubmit () {
|
|
45
|
+
formChild.submit()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const authTypes = authTypesProp || Object.keys(authTypeMap).map(k => k)
|
|
49
|
+
|
|
50
|
+
const treeProps = {
|
|
51
|
+
bookmarks: store.bookmarks.filter(d => {
|
|
52
|
+
return d.host && d.port && d.username
|
|
53
|
+
}),
|
|
54
|
+
bookmarkGroups: store.bookmarkGroups,
|
|
55
|
+
onSelect: onFinish
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Form
|
|
60
|
+
form={formChild}
|
|
61
|
+
onFinish={onFinish}
|
|
62
|
+
initialValues={initialValues}
|
|
63
|
+
component='div'
|
|
64
|
+
>
|
|
65
|
+
<FormItem
|
|
66
|
+
{...formItemLayout}
|
|
67
|
+
label={e('chooseFromBookmarks')}
|
|
68
|
+
className='mg60b'
|
|
69
|
+
style={{ display: isEdit ? 'none' : '' }}
|
|
70
|
+
>
|
|
71
|
+
<BookmarkSelect {...treeProps} />
|
|
72
|
+
</FormItem>
|
|
73
|
+
<FormItem
|
|
74
|
+
{...formItemLayout}
|
|
75
|
+
label={e('host')}
|
|
76
|
+
hasFeedback
|
|
77
|
+
rules={[{
|
|
78
|
+
max: 520, message: '520 chars max'
|
|
79
|
+
}, {
|
|
80
|
+
required: true, message: 'host required'
|
|
81
|
+
}]}
|
|
82
|
+
normalize={trim}
|
|
83
|
+
name='host'
|
|
84
|
+
>
|
|
85
|
+
<Input />
|
|
86
|
+
</FormItem>
|
|
87
|
+
<FormItem
|
|
88
|
+
{...formItemLayout}
|
|
89
|
+
label={e('port')}
|
|
90
|
+
hasFeedback
|
|
91
|
+
name='port'
|
|
92
|
+
rules={[{
|
|
93
|
+
required: true, message: 'port required'
|
|
94
|
+
}]}
|
|
95
|
+
>
|
|
96
|
+
<InputNumber
|
|
97
|
+
placeholder={e('port')}
|
|
98
|
+
min={1}
|
|
99
|
+
max={65535}
|
|
100
|
+
step={1}
|
|
101
|
+
/>
|
|
102
|
+
</FormItem>
|
|
103
|
+
<FormItem
|
|
104
|
+
{...formItemLayout}
|
|
105
|
+
label={e('username')}
|
|
106
|
+
hasFeedback
|
|
107
|
+
name='username'
|
|
108
|
+
rules={[{
|
|
109
|
+
max: 128, message: '128 chars max'
|
|
110
|
+
}]}
|
|
111
|
+
normalize={trim}
|
|
112
|
+
>
|
|
113
|
+
<Input />
|
|
114
|
+
</FormItem>
|
|
115
|
+
<FormItem
|
|
116
|
+
{...tailFormItemLayout}
|
|
117
|
+
className='mg1b'
|
|
118
|
+
name='authType'
|
|
119
|
+
>
|
|
120
|
+
<RadioGroup
|
|
121
|
+
size='small'
|
|
122
|
+
onChange={onChangeAuthType}
|
|
123
|
+
buttonStyle='solid'
|
|
124
|
+
>
|
|
125
|
+
{
|
|
126
|
+
authTypes.map(t => {
|
|
127
|
+
return (
|
|
128
|
+
<RadioButton value={t} key={t}>
|
|
129
|
+
{e(t)}
|
|
130
|
+
</RadioButton>
|
|
131
|
+
)
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
</RadioGroup>
|
|
135
|
+
</FormItem>
|
|
136
|
+
<RenderAuth
|
|
137
|
+
form={formChild}
|
|
138
|
+
store={store}
|
|
139
|
+
authType={authType}
|
|
140
|
+
/>
|
|
141
|
+
<FormItem {...tailFormItemLayout} className='mg60b'>
|
|
142
|
+
<Button
|
|
143
|
+
type='default'
|
|
144
|
+
htmlType='button'
|
|
145
|
+
icon={isEdit ? <SaveOutlined /> : <PlusOutlined />}
|
|
146
|
+
onClick={onSubmit}
|
|
147
|
+
>
|
|
148
|
+
{isEdit ? e('save') : e('connectionHopping')}
|
|
149
|
+
</Button>
|
|
150
|
+
</FormItem>
|
|
151
|
+
</Form>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
@@ -1,33 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Form,
|
|
3
|
-
InputNumber,
|
|
4
3
|
Input,
|
|
5
|
-
Radio,
|
|
6
|
-
Button,
|
|
7
4
|
Table
|
|
8
5
|
} from 'antd'
|
|
9
6
|
import {
|
|
10
|
-
formItemLayout,
|
|
11
7
|
tailFormItemLayout
|
|
12
8
|
} from '../../../common/form-layout'
|
|
13
9
|
import {
|
|
14
10
|
MinusCircleFilled,
|
|
15
|
-
|
|
11
|
+
EditOutlined,
|
|
12
|
+
HolderOutlined
|
|
16
13
|
} from '@ant-design/icons'
|
|
17
|
-
import RenderAuth from './render-auth-ssh'
|
|
18
14
|
import uid from '../../../common/uid'
|
|
19
15
|
import {
|
|
20
16
|
authTypeMap,
|
|
21
17
|
connectionHoppingWarnKey
|
|
22
18
|
} from '../../../common/constants'
|
|
23
|
-
import { useState } from 'react'
|
|
19
|
+
import { useState, useRef, useCallback } from 'react'
|
|
24
20
|
import ConnectionHoppingWarningText from '../../common/connection-hopping-warning-text'
|
|
25
|
-
import BookmarkSelect from './bookmark-select'
|
|
26
21
|
import * as ls from '../../../common/safe-local-storage'
|
|
22
|
+
import Modal from '../../common/modal'
|
|
23
|
+
import ConnectionHoppingForm from './connection-hopping-form'
|
|
27
24
|
|
|
28
25
|
const FormItem = Form.Item
|
|
29
|
-
const RadioButton = Radio.Button
|
|
30
|
-
const RadioGroup = Radio.Group
|
|
31
26
|
const e = window.translate
|
|
32
27
|
|
|
33
28
|
export default function renderConnectionHopping (props) {
|
|
@@ -37,28 +32,54 @@ export default function renderConnectionHopping (props) {
|
|
|
37
32
|
formData
|
|
38
33
|
} = props
|
|
39
34
|
const [formChild] = Form.useForm()
|
|
40
|
-
const [
|
|
35
|
+
const [editFormChild] = Form.useForm()
|
|
36
|
+
const [initialValues] = useState({
|
|
41
37
|
port: 22,
|
|
42
38
|
authType: authTypeMap.password
|
|
43
39
|
})
|
|
44
40
|
const [showWarn, setShowWarn] = useState(
|
|
45
41
|
window.store.hasOldConnectionHoppingBookmark && ls.getItem(connectionHoppingWarnKey) !== 'yes'
|
|
46
42
|
)
|
|
43
|
+
const [editModalVisible, setEditModalVisible] = useState(false)
|
|
44
|
+
const [editingItem, setEditingItem] = useState(null)
|
|
45
|
+
|
|
47
46
|
function closeWarn () {
|
|
48
47
|
setShowWarn(false)
|
|
49
48
|
}
|
|
50
49
|
const [list, setList] = useState(formData.connectionHoppings || [])
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
const dragItem = useRef(null)
|
|
51
|
+
const dragOverItem = useRef(null)
|
|
52
|
+
|
|
53
|
+
const handleDragStart = useCallback((index) => {
|
|
54
|
+
dragItem.current = index
|
|
55
|
+
}, [])
|
|
56
|
+
|
|
57
|
+
const handleDragEnter = useCallback((index) => {
|
|
58
|
+
dragOverItem.current = index
|
|
59
|
+
}, [])
|
|
60
|
+
|
|
61
|
+
const handleDragEnd = useCallback(() => {
|
|
62
|
+
if (dragItem.current === null || dragOverItem.current === null) {
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
if (dragItem.current === dragOverItem.current) {
|
|
66
|
+
dragItem.current = null
|
|
67
|
+
dragOverItem.current = null
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
setList(old => {
|
|
71
|
+
const newList = [...old]
|
|
72
|
+
const [removed] = newList.splice(dragItem.current, 1)
|
|
73
|
+
newList.splice(dragOverItem.current, 0, removed)
|
|
74
|
+
form.setFieldsValue({
|
|
75
|
+
connectionHoppings: newList
|
|
76
|
+
})
|
|
77
|
+
dragItem.current = null
|
|
78
|
+
dragOverItem.current = null
|
|
79
|
+
return newList
|
|
57
80
|
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
formChild.submit()
|
|
61
|
-
}
|
|
81
|
+
}, [form])
|
|
82
|
+
|
|
62
83
|
function handleFinish (data) {
|
|
63
84
|
const nd = {
|
|
64
85
|
...data,
|
|
@@ -74,14 +95,11 @@ export default function renderConnectionHopping (props) {
|
|
|
74
95
|
setList(old => {
|
|
75
96
|
return [
|
|
76
97
|
...old,
|
|
77
|
-
|
|
98
|
+
nd
|
|
78
99
|
]
|
|
79
100
|
})
|
|
80
101
|
formChild.resetFields()
|
|
81
102
|
}
|
|
82
|
-
const authTypes = props.authTypes || Object.keys(authTypeMap).map(k => {
|
|
83
|
-
return k
|
|
84
|
-
})
|
|
85
103
|
|
|
86
104
|
function remove (id) {
|
|
87
105
|
setList(old => {
|
|
@@ -93,7 +111,51 @@ export default function renderConnectionHopping (props) {
|
|
|
93
111
|
})
|
|
94
112
|
formChild.resetFields()
|
|
95
113
|
}
|
|
114
|
+
|
|
115
|
+
function openEdit (record) {
|
|
116
|
+
setEditingItem(record)
|
|
117
|
+
setEditModalVisible(true)
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
editFormChild.setFieldsValue(record)
|
|
120
|
+
}, 100)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function handleEditFinish (data) {
|
|
124
|
+
const updatedItem = {
|
|
125
|
+
...data,
|
|
126
|
+
id: editingItem.id
|
|
127
|
+
}
|
|
128
|
+
setList(old => {
|
|
129
|
+
return old.map(item => item.id === editingItem.id ? updatedItem : item)
|
|
130
|
+
})
|
|
131
|
+
const v = (form.getFieldValue('connectionHoppings') || []).map(
|
|
132
|
+
item => item.id === editingItem.id ? updatedItem : item
|
|
133
|
+
)
|
|
134
|
+
form.setFieldsValue({
|
|
135
|
+
connectionHoppings: v
|
|
136
|
+
})
|
|
137
|
+
setEditModalVisible(false)
|
|
138
|
+
setEditingItem(null)
|
|
139
|
+
editFormChild.resetFields()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function closeEditModal () {
|
|
143
|
+
setEditModalVisible(false)
|
|
144
|
+
setEditingItem(null)
|
|
145
|
+
editFormChild.resetFields()
|
|
146
|
+
}
|
|
147
|
+
|
|
96
148
|
const cols = [
|
|
149
|
+
{
|
|
150
|
+
title: '',
|
|
151
|
+
key: 'drag',
|
|
152
|
+
width: 30,
|
|
153
|
+
render: () => (
|
|
154
|
+
<HolderOutlined
|
|
155
|
+
className='drag'
|
|
156
|
+
/>
|
|
157
|
+
)
|
|
158
|
+
},
|
|
97
159
|
{
|
|
98
160
|
title: 'NO.',
|
|
99
161
|
dataIndex: 'index',
|
|
@@ -110,15 +172,21 @@ export default function renderConnectionHopping (props) {
|
|
|
110
172
|
return <span>{useProfile}{item.username}{pass}@{item.host}:{item.port}{pk}{ph}</span>
|
|
111
173
|
}
|
|
112
174
|
}, {
|
|
113
|
-
title: e('
|
|
175
|
+
title: e('op'),
|
|
114
176
|
key: 'op',
|
|
115
177
|
dataIndex: 'id',
|
|
116
|
-
render: (id) => {
|
|
178
|
+
render: (id, record) => {
|
|
117
179
|
return (
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
180
|
+
<span>
|
|
181
|
+
<EditOutlined
|
|
182
|
+
className='pointer mg1r'
|
|
183
|
+
onClick={() => openEdit(record)}
|
|
184
|
+
/>
|
|
185
|
+
<MinusCircleFilled
|
|
186
|
+
className='pointer'
|
|
187
|
+
onClick={() => remove(id)}
|
|
188
|
+
/>
|
|
189
|
+
</span>
|
|
122
190
|
)
|
|
123
191
|
}
|
|
124
192
|
}
|
|
@@ -140,6 +208,13 @@ export default function renderConnectionHopping (props) {
|
|
|
140
208
|
className='mg3b'
|
|
141
209
|
pagination={false}
|
|
142
210
|
size='small'
|
|
211
|
+
onRow={(record, index) => ({
|
|
212
|
+
draggable: true,
|
|
213
|
+
onDragStart: () => handleDragStart(index),
|
|
214
|
+
onDragEnter: () => handleDragEnter(index),
|
|
215
|
+
onDragEnd: handleDragEnd,
|
|
216
|
+
onDragOver: (e) => e.preventDefault()
|
|
217
|
+
})}
|
|
143
218
|
dataSource={list.map((d, i) => {
|
|
144
219
|
return {
|
|
145
220
|
...d,
|
|
@@ -161,13 +236,15 @@ export default function renderConnectionHopping (props) {
|
|
|
161
236
|
</FormItem>
|
|
162
237
|
)
|
|
163
238
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
239
|
+
|
|
240
|
+
const editModalProps = {
|
|
241
|
+
open: editModalVisible,
|
|
242
|
+
onCancel: closeEditModal,
|
|
243
|
+
footer: null,
|
|
244
|
+
title: e('edit') + ' ' + e('connectionHopping'),
|
|
245
|
+
width: 600
|
|
170
246
|
}
|
|
247
|
+
|
|
171
248
|
return (
|
|
172
249
|
<>
|
|
173
250
|
<FormItem
|
|
@@ -176,100 +253,30 @@ export default function renderConnectionHopping (props) {
|
|
|
176
253
|
>
|
|
177
254
|
<Input />
|
|
178
255
|
</FormItem>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
256
|
+
{renderList()}
|
|
257
|
+
{renderWarn()}
|
|
258
|
+
<ConnectionHoppingForm
|
|
259
|
+
store={store}
|
|
260
|
+
formChild={formChild}
|
|
182
261
|
initialValues={initialValues}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
{
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
rules={[{
|
|
199
|
-
max: 520, message: '520 chars max'
|
|
200
|
-
}, {
|
|
201
|
-
required: true, message: 'host required'
|
|
202
|
-
}]}
|
|
203
|
-
normalize={props.trim}
|
|
204
|
-
name='host'
|
|
205
|
-
>
|
|
206
|
-
<Input />
|
|
207
|
-
</FormItem>
|
|
208
|
-
<FormItem
|
|
209
|
-
{...formItemLayout}
|
|
210
|
-
label={e('port')}
|
|
211
|
-
hasFeedback
|
|
212
|
-
name='port'
|
|
213
|
-
rules={[{
|
|
214
|
-
required: true, message: 'port required'
|
|
215
|
-
}]}
|
|
216
|
-
>
|
|
217
|
-
<InputNumber
|
|
218
|
-
placeholder={e('port')}
|
|
219
|
-
min={1}
|
|
220
|
-
max={65535}
|
|
221
|
-
step={1}
|
|
262
|
+
onFinish={handleFinish}
|
|
263
|
+
authTypes={props.authTypes}
|
|
264
|
+
trim={props.trim}
|
|
265
|
+
/>
|
|
266
|
+
{editModalVisible && (
|
|
267
|
+
<Modal {...editModalProps}>
|
|
268
|
+
<ConnectionHoppingForm
|
|
269
|
+
key={editingItem?.id}
|
|
270
|
+
store={store}
|
|
271
|
+
formChild={editFormChild}
|
|
272
|
+
initialValues={editingItem}
|
|
273
|
+
onFinish={handleEditFinish}
|
|
274
|
+
authTypes={props.authTypes}
|
|
275
|
+
trim={props.trim}
|
|
276
|
+
isEdit
|
|
222
277
|
/>
|
|
223
|
-
</
|
|
224
|
-
|
|
225
|
-
{...formItemLayout}
|
|
226
|
-
label={e('username')}
|
|
227
|
-
hasFeedback
|
|
228
|
-
name='username'
|
|
229
|
-
rules={[{
|
|
230
|
-
max: 128, message: '128 chars max'
|
|
231
|
-
}]}
|
|
232
|
-
normalize={props.trim}
|
|
233
|
-
>
|
|
234
|
-
<Input />
|
|
235
|
-
</FormItem>
|
|
236
|
-
<FormItem
|
|
237
|
-
{...tailFormItemLayout}
|
|
238
|
-
className='mg1b'
|
|
239
|
-
name='authType'
|
|
240
|
-
>
|
|
241
|
-
<RadioGroup
|
|
242
|
-
size='small'
|
|
243
|
-
onChange={onChangeAuthType}
|
|
244
|
-
buttonStyle='solid'
|
|
245
|
-
>
|
|
246
|
-
{
|
|
247
|
-
authTypes.map(t => {
|
|
248
|
-
return (
|
|
249
|
-
<RadioButton value={t} key={t}>
|
|
250
|
-
{e(t)}
|
|
251
|
-
</RadioButton>
|
|
252
|
-
)
|
|
253
|
-
})
|
|
254
|
-
}
|
|
255
|
-
</RadioGroup>
|
|
256
|
-
</FormItem>
|
|
257
|
-
<RenderAuth
|
|
258
|
-
form={formChild}
|
|
259
|
-
store={store}
|
|
260
|
-
authType={initialValues.authType}
|
|
261
|
-
/>
|
|
262
|
-
<FormItem {...tailFormItemLayout} className='mg60b'>
|
|
263
|
-
<Button
|
|
264
|
-
type='default'
|
|
265
|
-
htmlType='button'
|
|
266
|
-
icon={<PlusOutlined />}
|
|
267
|
-
onClick={onSubmit}
|
|
268
|
-
>
|
|
269
|
-
{e('connectionHopping')}
|
|
270
|
-
</Button>
|
|
271
|
-
</FormItem>
|
|
272
|
-
</Form>
|
|
278
|
+
</Modal>
|
|
279
|
+
)}
|
|
273
280
|
</>
|
|
274
281
|
)
|
|
275
282
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
export default function AutoCheckUpdate ({ config }) {
|
|
4
|
+
const lastCheckTimeRef = useRef(0)
|
|
5
|
+
const intervalIdRef = useRef(null)
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (!config.checkUpdateOnStart) {
|
|
9
|
+
clearInterval(intervalIdRef.current)
|
|
10
|
+
return
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const checkForUpdate = () => {
|
|
14
|
+
const { store } = window
|
|
15
|
+
if (store.config.checkUpdateOnStart) {
|
|
16
|
+
store.onCheckUpdate(false)
|
|
17
|
+
}
|
|
18
|
+
lastCheckTimeRef.current = Date.now()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
intervalIdRef.current = setInterval(checkForUpdate, 60 * 60 * 1000)
|
|
22
|
+
|
|
23
|
+
return () => {
|
|
24
|
+
if (intervalIdRef.current) {
|
|
25
|
+
clearInterval(intervalIdRef.current)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}, [config.checkUpdateOnStart])
|
|
29
|
+
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
@@ -136,12 +136,10 @@ export default class BatchInput extends Component {
|
|
|
136
136
|
} = this.props
|
|
137
137
|
const opts = {
|
|
138
138
|
options: this.buildOptions(),
|
|
139
|
-
placeholder: e('batchInput'),
|
|
140
139
|
value: cmd,
|
|
141
140
|
onChange: this.handleChange,
|
|
142
141
|
defaultOpen: false,
|
|
143
142
|
open,
|
|
144
|
-
allowClear: true,
|
|
145
143
|
className: 'batch-input-wrap'
|
|
146
144
|
}
|
|
147
145
|
const cls = classNames(
|
|
@@ -155,6 +153,15 @@ export default class BatchInput extends Component {
|
|
|
155
153
|
placeholder: e('batchInput'),
|
|
156
154
|
className: 'batch-input-holder'
|
|
157
155
|
}
|
|
156
|
+
const textAreaProps = {
|
|
157
|
+
onPressEnter: this.handleEnter,
|
|
158
|
+
onClick: this.handleClick,
|
|
159
|
+
onBlur: this.handleBlur,
|
|
160
|
+
size: 'small',
|
|
161
|
+
autoSize: { minRows: 1 },
|
|
162
|
+
placeholder: e('batchInput'),
|
|
163
|
+
allowClear: true
|
|
164
|
+
}
|
|
158
165
|
const tabSelectProps = {
|
|
159
166
|
activeTabId: this.props.activeTabId,
|
|
160
167
|
tabs: this.getTabs(),
|
|
@@ -179,11 +186,7 @@ export default class BatchInput extends Component {
|
|
|
179
186
|
{...opts}
|
|
180
187
|
>
|
|
181
188
|
<Input.TextArea
|
|
182
|
-
|
|
183
|
-
onClick={this.handleClick}
|
|
184
|
-
onBlur={this.handleBlur}
|
|
185
|
-
size='small'
|
|
186
|
-
autoSize={{ minRows: 1 }}
|
|
189
|
+
{...textAreaProps}
|
|
187
190
|
/>
|
|
188
191
|
</AutoComplete>
|
|
189
192
|
<TabSelect {...tabSelectProps} />
|
|
@@ -77,12 +77,9 @@ export default class ErrorBoundary extends React.PureComponent {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
renderTroubleShoot = () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
} = packInfo
|
|
85
|
-
const bugUrl = `${bugReportLink}/new/choose`
|
|
80
|
+
if (window.et.isWebApp) {
|
|
81
|
+
return this.renderContacts()
|
|
82
|
+
}
|
|
86
83
|
return (
|
|
87
84
|
<div className='pd1y wordbreak'>
|
|
88
85
|
<h2>{e('troubleShoot')}</h2>
|
|
@@ -99,6 +96,20 @@ export default class ErrorBoundary extends React.PureComponent {
|
|
|
99
96
|
)
|
|
100
97
|
})
|
|
101
98
|
}
|
|
99
|
+
{this.renderContacts()}
|
|
100
|
+
</div>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
renderContacts () {
|
|
105
|
+
const {
|
|
106
|
+
bugs: {
|
|
107
|
+
url: bugReportLink
|
|
108
|
+
}
|
|
109
|
+
} = packInfo
|
|
110
|
+
const bugUrl = `${bugReportLink}/new/choose`
|
|
111
|
+
return (
|
|
112
|
+
<>
|
|
102
113
|
<div className='pd1b'>
|
|
103
114
|
<Link to={bugUrl}>{e('bugReport')}</Link>
|
|
104
115
|
</div>
|
|
@@ -112,7 +123,7 @@ export default class ErrorBoundary extends React.PureComponent {
|
|
|
112
123
|
className='mwm-100'
|
|
113
124
|
/>
|
|
114
125
|
</div>
|
|
115
|
-
|
|
126
|
+
</>
|
|
116
127
|
)
|
|
117
128
|
}
|
|
118
129
|
|