@electerm/electerm-react 1.100.56 → 1.101.10
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/check-skip-src.js +16 -0
- package/client/components/bookmark-form/{bookmark-select.jsx → common/bookmark-select.jsx} +11 -44
- package/client/components/bookmark-form/{bookmark-category-select.jsx → common/category-select.jsx} +10 -4
- package/client/components/bookmark-form/{color-picker-item.jsx → common/color-picker-item.jsx} +2 -3
- package/client/components/bookmark-form/{color-picker.jsx → common/color-picker.jsx} +10 -46
- package/client/components/bookmark-form/{render-connection-hopping.jsx → common/connection-hopping.jsx} +7 -7
- package/client/components/bookmark-form/common/fields.jsx +202 -0
- package/client/components/bookmark-form/common/hex-input.jsx +22 -0
- package/client/components/bookmark-form/common/init-values.js +83 -0
- package/client/components/bookmark-form/common/profile-item.jsx +34 -0
- package/client/components/bookmark-form/{proxy.jsx → common/proxy.jsx} +1 -1
- package/client/components/bookmark-form/{use-quick-commands.jsx → common/quick-commands.jsx} +1 -1
- package/client/components/bookmark-form/common/rdp-alert.jsx +13 -0
- package/client/components/bookmark-form/common/render-auth-ssh.jsx +119 -0
- package/client/components/bookmark-form/{render-delayed-scripts.jsx → common/run-scripts.jsx} +6 -2
- package/client/components/bookmark-form/common/serial-path-selector.jsx +39 -0
- package/client/components/bookmark-form/{render-auth-ssh.jsx → common/ssh-auth-selector.jsx} +3 -4
- package/client/components/bookmark-form/common/ssh-auth-type-selector.jsx +38 -0
- package/client/components/bookmark-form/common/ssh-host-selector.jsx +61 -0
- package/client/components/bookmark-form/{render-ssh-tunnel.jsx → common/ssh-tunnels.jsx} +4 -4
- package/client/components/bookmark-form/common/submit-buttons.jsx +42 -0
- package/client/components/bookmark-form/{render-bg.jsx → common/terminal-background.jsx} +2 -2
- package/client/components/bookmark-form/{x11.jsx → common/x11.jsx} +2 -2
- package/client/components/bookmark-form/config/common-fields.js +305 -0
- package/client/components/bookmark-form/config/ftp.js +40 -0
- package/client/components/bookmark-form/config/local.js +96 -0
- package/client/components/bookmark-form/config/rdp.js +39 -0
- package/client/components/bookmark-form/config/serial.js +69 -0
- package/client/components/bookmark-form/config/session-config.js +23 -0
- package/client/components/bookmark-form/config/ssh.js +47 -0
- package/client/components/bookmark-form/config/telnet.js +40 -0
- package/client/components/bookmark-form/config/vnc.js +44 -0
- package/client/components/bookmark-form/config/web.js +45 -0
- package/client/components/bookmark-form/form-renderer.jsx +328 -0
- package/client/components/bookmark-form/index.jsx +32 -91
- package/client/components/bookmark-form/render-form.jsx +11 -0
- package/client/components/common/password.jsx +21 -12
- package/client/components/footer/footer-entry.jsx +1 -1
- package/client/components/main/main.jsx +12 -2
- package/client/components/main/upgrade.jsx +3 -3
- package/client/components/profile/profile-form-ftp.jsx +35 -0
- package/client/components/profile/profile-form-ssh.jsx +3 -3
- package/client/components/profile/profile-form-telnet.jsx +1 -1
- package/client/components/profile/profile-tabs.jsx +4 -0
- package/client/components/setting-panel/setting-modal.jsx +1 -1
- package/client/components/setting-panel/setting-wrap.jsx +1 -1
- package/client/components/setting-panel/text-bg-modal.jsx +2 -2
- package/client/components/sidebar/info-modal.jsx +3 -3
- package/client/components/theme/theme-edit-slot.jsx +1 -1
- package/client/components/tree-list/category-color-picker.jsx +1 -1
- package/client/components/tree-list/move-item-modal.jsx +1 -1
- package/client/entry/basic.js +6 -1
- package/client/store/load-data.js +1 -1
- package/package.json +1 -1
- package/client/components/bookmark-form/form-ssh-common.jsx +0 -219
- package/client/components/bookmark-form/form-tabs.jsx +0 -66
- package/client/components/bookmark-form/ftp-form-ui.jsx +0 -160
- package/client/components/bookmark-form/ftp-form.jsx +0 -16
- package/client/components/bookmark-form/hex-input.jsx +0 -39
- package/client/components/bookmark-form/local-form-ui.jsx +0 -151
- package/client/components/bookmark-form/local-form.jsx +0 -16
- package/client/components/bookmark-form/profile-form-item.jsx +0 -43
- package/client/components/bookmark-form/quick-command-list.jsx +0 -31
- package/client/components/bookmark-form/quick-command.jsx +0 -227
- package/client/components/bookmark-form/rdp-form-ui.jsx +0 -179
- package/client/components/bookmark-form/rdp-form.jsx +0 -16
- package/client/components/bookmark-form/render-profile-item.jsx +0 -0
- package/client/components/bookmark-form/serial-form-ui.jsx +0 -309
- package/client/components/bookmark-form/serial-form.jsx +0 -20
- package/client/components/bookmark-form/sftp-enable.jsx +0 -41
- package/client/components/bookmark-form/ssh-form-ui.jsx +0 -121
- package/client/components/bookmark-form/ssh-form.jsx +0 -292
- package/client/components/bookmark-form/telnet-form-ui.jsx +0 -140
- package/client/components/bookmark-form/telnet-form.jsx +0 -16
- package/client/components/bookmark-form/use-form-funcs.jsx +0 -50
- package/client/components/bookmark-form/use-submit.jsx +0 -67
- package/client/components/bookmark-form/use-ui.jsx +0 -97
- package/client/components/bookmark-form/vnc-form-ui.jsx +0 -213
- package/client/components/bookmark-form/vnc-form.jsx +0 -16
- package/client/components/bookmark-form/web-form-ui.jsx +0 -143
- package/client/components/bookmark-form/web-form.jsx +0 -16
- /package/client/components/bookmark-form/{bookmark-group-tree-format.js → common/bookmark-group-tree-format.js} +0 -0
- /package/client/components/bookmark-form/{color-picker.styl → common/color-picker.styl} +0 -0
- /package/client/components/bookmark-form/{encodes.js → common/encodes.js} +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
|
+
import { terminalVncType } from '../../../common/constants.js'
|
|
3
|
+
import { createBaseInitValues } from '../common/init-values.js'
|
|
4
|
+
import { isEmpty } from 'lodash-es'
|
|
5
|
+
import { commonFields, connectionHoppingTab } from './common-fields.js'
|
|
6
|
+
|
|
7
|
+
const e = window.translate
|
|
8
|
+
|
|
9
|
+
const vncConfig = {
|
|
10
|
+
key: 'vnc',
|
|
11
|
+
type: terminalVncType,
|
|
12
|
+
initValues: (props) => {
|
|
13
|
+
return createBaseInitValues(props, terminalVncType, {
|
|
14
|
+
port: 5900,
|
|
15
|
+
viewOnly: false,
|
|
16
|
+
scaleViewport: true,
|
|
17
|
+
connectionHoppings: []
|
|
18
|
+
})
|
|
19
|
+
},
|
|
20
|
+
layout: formItemLayout,
|
|
21
|
+
tabs: () => [
|
|
22
|
+
{
|
|
23
|
+
key: 'auth',
|
|
24
|
+
label: e('auth'),
|
|
25
|
+
fields: [
|
|
26
|
+
commonFields.category,
|
|
27
|
+
commonFields.colorTitle,
|
|
28
|
+
{ type: 'input', name: 'host', label: e('host'), rules: [{ required: true, message: e('host') + ' required' }] },
|
|
29
|
+
commonFields.port,
|
|
30
|
+
{ type: 'switch', name: 'viewOnly', label: e('viewOnly'), valuePropName: 'checked' },
|
|
31
|
+
{ type: 'switch', name: 'scaleViewport', label: e('scaleViewport'), valuePropName: 'checked' },
|
|
32
|
+
{ type: 'profileItem', name: '__profile__', label: '', profileFilter: d => !isEmpty(d.vnc) },
|
|
33
|
+
commonFields.username,
|
|
34
|
+
commonFields.password,
|
|
35
|
+
commonFields.description,
|
|
36
|
+
commonFields.proxy,
|
|
37
|
+
commonFields.type
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
connectionHoppingTab()
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default vncConfig
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
|
+
import { terminalWebType } from '../../../common/constants.js'
|
|
3
|
+
import { createBaseInitValues } from '../common/init-values.js'
|
|
4
|
+
import { commonFields } from './common-fields.js'
|
|
5
|
+
|
|
6
|
+
const e = window.translate
|
|
7
|
+
|
|
8
|
+
const webConfig = {
|
|
9
|
+
key: 'web',
|
|
10
|
+
type: terminalWebType,
|
|
11
|
+
initValues: (props) => {
|
|
12
|
+
return createBaseInitValues(props, terminalWebType)
|
|
13
|
+
},
|
|
14
|
+
layout: formItemLayout,
|
|
15
|
+
tabs: () => [
|
|
16
|
+
{
|
|
17
|
+
key: 'main',
|
|
18
|
+
label: e('auth'),
|
|
19
|
+
fields: [
|
|
20
|
+
commonFields.category,
|
|
21
|
+
commonFields.colorTitle,
|
|
22
|
+
{
|
|
23
|
+
type: 'input',
|
|
24
|
+
name: 'url',
|
|
25
|
+
label: e('URL'),
|
|
26
|
+
rules: [
|
|
27
|
+
{ required: true, message: e('Please input URL') },
|
|
28
|
+
{
|
|
29
|
+
validator: (_, value) =>
|
|
30
|
+
/^[a-z\d.+-]+:\/\/[^\s/$.?#].[^\s]*$/i.test(value)
|
|
31
|
+
? Promise.resolve()
|
|
32
|
+
: Promise.reject(new Error(e('URL must start with http:// or https://')))
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
commonFields.description,
|
|
37
|
+
{ type: 'input', name: 'useragent', label: e('useragent') },
|
|
38
|
+
{ type: 'switch', name: 'hideAddressBar', label: 'hideAddressBar', valuePropName: 'checked' },
|
|
39
|
+
commonFields.type
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default webConfig
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic form renderer driven by config (flattened path)
|
|
3
|
+
*/
|
|
4
|
+
import React, { useEffect, useState, useRef } from 'react'
|
|
5
|
+
import { Form, Tabs, message } from 'antd'
|
|
6
|
+
import { renderFormItem } from './common/fields'
|
|
7
|
+
import SubmitButtons from './common/submit-buttons'
|
|
8
|
+
import { uniq } from 'lodash-es'
|
|
9
|
+
import {
|
|
10
|
+
authTypeMap,
|
|
11
|
+
settingMap,
|
|
12
|
+
newBookmarkIdPrefix,
|
|
13
|
+
defaultBookmarkGroupId
|
|
14
|
+
} from '../../common/constants'
|
|
15
|
+
import copy from 'json-deep-copy'
|
|
16
|
+
import generate from '../../common/uid'
|
|
17
|
+
import runIdle from '../../common/run-idle'
|
|
18
|
+
import getInitItem from '../../common/init-setting-item'
|
|
19
|
+
import testCon from '../../common/test-connection'
|
|
20
|
+
import newTerm from '../../common/new-terminal'
|
|
21
|
+
import { isValidIP } from '../../common/is-ip'
|
|
22
|
+
import { action as manateAction } from 'manate'
|
|
23
|
+
|
|
24
|
+
export default function FormRenderer ({ config, props }) {
|
|
25
|
+
const [form] = Form.useForm()
|
|
26
|
+
const [ips, setIps] = useState([])
|
|
27
|
+
const [authType, setAuthType] = useState(props.formData.authType || authTypeMap.password)
|
|
28
|
+
const [testing, setTesting] = useState(false)
|
|
29
|
+
const action = useRef('submit')
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const init = config.initValues(props)
|
|
33
|
+
form.resetFields()
|
|
34
|
+
form.setFieldsValue(init)
|
|
35
|
+
}, [
|
|
36
|
+
props.currentBookmarkGroupId,
|
|
37
|
+
props.formData?.id,
|
|
38
|
+
config.key
|
|
39
|
+
])
|
|
40
|
+
|
|
41
|
+
const updateBookmarkGroups = manateAction((bookmark, categoryId) => {
|
|
42
|
+
const {
|
|
43
|
+
bookmarkGroups
|
|
44
|
+
} = window.store
|
|
45
|
+
let index = bookmarkGroups.findIndex(
|
|
46
|
+
bg => bg.id === categoryId
|
|
47
|
+
)
|
|
48
|
+
if (index < 0) {
|
|
49
|
+
index = bookmarkGroups.findIndex(
|
|
50
|
+
bg => bg.id === defaultBookmarkGroupId
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
const bid = bookmark.id
|
|
54
|
+
const bg = bookmarkGroups[index]
|
|
55
|
+
if (!bg.bookmarkIds.includes(bid)) {
|
|
56
|
+
bg.bookmarkIds.unshift(bid)
|
|
57
|
+
}
|
|
58
|
+
bg.bookmarkIds = uniq(bg.bookmarkIds)
|
|
59
|
+
bookmarkGroups.forEach((bg, i) => {
|
|
60
|
+
if (i === index) {
|
|
61
|
+
return bg
|
|
62
|
+
}
|
|
63
|
+
bg.bookmarkIds = bg.bookmarkIds.filter(
|
|
64
|
+
g => g !== bid
|
|
65
|
+
)
|
|
66
|
+
return bg
|
|
67
|
+
})
|
|
68
|
+
message.success('OK', 3)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const setNewItem = (settingItem = getInitItem([], settingMap.bookmarks)) => {
|
|
72
|
+
const { store } = props
|
|
73
|
+
store.setSettingItem(settingItem)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const submit = (evt, item, type = props.type) => {
|
|
77
|
+
if (item.host) {
|
|
78
|
+
item.host = item.host.trim()
|
|
79
|
+
}
|
|
80
|
+
const obj = item
|
|
81
|
+
if (obj.connectionHoppings?.length) {
|
|
82
|
+
obj.hasHopping = true
|
|
83
|
+
}
|
|
84
|
+
const { addItem, editItem } = props.store
|
|
85
|
+
const categoryId = obj.category
|
|
86
|
+
delete obj.category
|
|
87
|
+
if (!obj.id.startsWith(newBookmarkIdPrefix)) {
|
|
88
|
+
const tar = copy(obj)
|
|
89
|
+
delete tar.id
|
|
90
|
+
runIdle(() => {
|
|
91
|
+
editItem(obj.id, tar, settingMap.bookmarks)
|
|
92
|
+
})
|
|
93
|
+
updateBookmarkGroups(
|
|
94
|
+
obj,
|
|
95
|
+
categoryId
|
|
96
|
+
)
|
|
97
|
+
if (evt === 'saveAndCreateNew') {
|
|
98
|
+
setNewItem()
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
obj.id = generate()
|
|
102
|
+
runIdle(() => {
|
|
103
|
+
addItem(obj, settingMap.bookmarks)
|
|
104
|
+
})
|
|
105
|
+
updateBookmarkGroups(
|
|
106
|
+
obj,
|
|
107
|
+
categoryId
|
|
108
|
+
)
|
|
109
|
+
setNewItem(evt === 'saveAndCreateNew'
|
|
110
|
+
? getInitItem([], settingMap.bookmarks)
|
|
111
|
+
: obj
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const test = async (update) => {
|
|
117
|
+
let options = copy({
|
|
118
|
+
...props.formData,
|
|
119
|
+
...update
|
|
120
|
+
})
|
|
121
|
+
let msg = ''
|
|
122
|
+
setTesting(true)
|
|
123
|
+
options = window.store.applyProfileToTabs(options)
|
|
124
|
+
const res = await testCon(options)
|
|
125
|
+
.then(r => r)
|
|
126
|
+
.catch((e) => {
|
|
127
|
+
msg = e.message
|
|
128
|
+
return false
|
|
129
|
+
})
|
|
130
|
+
setTesting(false)
|
|
131
|
+
if (res) {
|
|
132
|
+
message.success('connection ok')
|
|
133
|
+
} else {
|
|
134
|
+
const err = 'connection fails' +
|
|
135
|
+
(msg ? `: ${msg}` : '')
|
|
136
|
+
message.error(err)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const onSelectProxy = (proxy, form) => {
|
|
141
|
+
const obj = Object.keys(proxy)
|
|
142
|
+
.reduce((prev, c) => {
|
|
143
|
+
return {
|
|
144
|
+
...prev,
|
|
145
|
+
[`proxy.${c}`]: proxy[c]
|
|
146
|
+
}
|
|
147
|
+
}, {})
|
|
148
|
+
form.setFieldsValue(obj)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const handleSubmit = async (evt, res, isTest = false) => {
|
|
152
|
+
if (res.enableSsh === false && res.enableSftp === false) {
|
|
153
|
+
return message.warning('SSH and SFTP all disabled')
|
|
154
|
+
}
|
|
155
|
+
const obj = {
|
|
156
|
+
...props.formData,
|
|
157
|
+
...res
|
|
158
|
+
}
|
|
159
|
+
if (isTest) {
|
|
160
|
+
return test(obj)
|
|
161
|
+
}
|
|
162
|
+
if (evt && evt !== 'connect') {
|
|
163
|
+
submit(evt, obj)
|
|
164
|
+
}
|
|
165
|
+
if (evt !== 'save' && evt !== 'saveAndCreateNew') {
|
|
166
|
+
window.store.currentLayoutBatch = window.openTabBatch || 0
|
|
167
|
+
props.store.addTab({
|
|
168
|
+
...copy(obj),
|
|
169
|
+
...newTerm(true, true),
|
|
170
|
+
batch: window.openTabBatch ?? window.store.currentLayoutBatch
|
|
171
|
+
})
|
|
172
|
+
delete window.openTabBatch
|
|
173
|
+
props.hide()
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Button handlers - exactly like original use-form-funcs
|
|
178
|
+
const save = () => {
|
|
179
|
+
action.current = 'save'
|
|
180
|
+
form.submit()
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const saveAndCreateNew = () => {
|
|
184
|
+
action.current = 'saveAndCreateNew'
|
|
185
|
+
form.submit()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const testConnection = () => {
|
|
189
|
+
action.current = 'testConnection'
|
|
190
|
+
form.submit()
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const connect = () => {
|
|
194
|
+
action.current = 'connect'
|
|
195
|
+
form.submit()
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const handleFinish = (res) => {
|
|
199
|
+
if (action.current === 'save') {
|
|
200
|
+
handleSubmit('save', res, false)
|
|
201
|
+
} else if (action.current === 'saveAndCreateNew') {
|
|
202
|
+
handleSubmit('saveAndCreateNew', res, false)
|
|
203
|
+
} else if (action.current === 'connect') {
|
|
204
|
+
handleSubmit('connect', res, false)
|
|
205
|
+
} else if (action.current === 'testConnection') {
|
|
206
|
+
handleSubmit('test', res, true)
|
|
207
|
+
} else {
|
|
208
|
+
handleSubmit('submit', res, false)
|
|
209
|
+
}
|
|
210
|
+
action.current = 'submit'
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const trim = (v) => {
|
|
214
|
+
return (v || '').replace(/^\s+|\s+$/g, '')
|
|
215
|
+
}
|
|
216
|
+
const useIp = (form, ip) => {
|
|
217
|
+
form.setFieldsValue({
|
|
218
|
+
host: ip
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
const onPaste = (e, form) => {
|
|
222
|
+
const txt = e.clipboardData.getData('Text')
|
|
223
|
+
// support name:passsword@host:23
|
|
224
|
+
const arr = txt.match(/([^:@]+)(:[^:@]+)?@([^:@]+)(:\d+)?/)
|
|
225
|
+
if (!arr) {
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
const username = arr[1]
|
|
229
|
+
const password = arr[2] ? arr[2].slice(1) : ''
|
|
230
|
+
const host = arr[3]
|
|
231
|
+
const port = arr[4] ? arr[4].slice(1) : ''
|
|
232
|
+
const obj = {
|
|
233
|
+
username,
|
|
234
|
+
host
|
|
235
|
+
}
|
|
236
|
+
if (password) {
|
|
237
|
+
obj.password = password
|
|
238
|
+
}
|
|
239
|
+
if (port) {
|
|
240
|
+
obj.port = port
|
|
241
|
+
}
|
|
242
|
+
setTimeout(() => {
|
|
243
|
+
form.setFieldsValue(obj)
|
|
244
|
+
}, 20)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const onBlur = async (e) => {
|
|
248
|
+
const value = e.target.value.trim()
|
|
249
|
+
const { type } = props
|
|
250
|
+
if (
|
|
251
|
+
type !== settingMap.bookmarks ||
|
|
252
|
+
!value ||
|
|
253
|
+
isValidIP(value)
|
|
254
|
+
) {
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
const ips = await window.pre.runGlobalAsync('lookup', value)
|
|
258
|
+
.catch(err => {
|
|
259
|
+
log.debug(err)
|
|
260
|
+
})
|
|
261
|
+
setIps(ips || [])
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function onChangeAuthType (e) {
|
|
265
|
+
const newAuthType = e.target.value
|
|
266
|
+
setAuthType(newAuthType)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Context props for specialized components
|
|
270
|
+
const ctxProps = {
|
|
271
|
+
...props,
|
|
272
|
+
form,
|
|
273
|
+
authType,
|
|
274
|
+
ips,
|
|
275
|
+
testing,
|
|
276
|
+
loaddingSerials: props.loaddingSerials || false,
|
|
277
|
+
trim,
|
|
278
|
+
onSelectProxy,
|
|
279
|
+
onChangeAuthType,
|
|
280
|
+
handleBlur: onBlur,
|
|
281
|
+
onPaste,
|
|
282
|
+
useIp
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const initialValues = config.initValues(props)
|
|
286
|
+
const tabs = typeof config.tabs === 'function' ? (config.tabs() || []) : (config.tabs || [])
|
|
287
|
+
let content = null
|
|
288
|
+
|
|
289
|
+
if (tabs.length <= 1) {
|
|
290
|
+
const fields = tabs.length === 1
|
|
291
|
+
? (tabs[0].fields || [])
|
|
292
|
+
: (config.fields || [])
|
|
293
|
+
content = (
|
|
294
|
+
<div className='pd1x'>
|
|
295
|
+
{fields.map((f, index) => renderFormItem(f, config.layout, form, ctxProps, index))}
|
|
296
|
+
</div>
|
|
297
|
+
)
|
|
298
|
+
} else {
|
|
299
|
+
const items = (tabs || []).map(tab => ({
|
|
300
|
+
key: tab.key,
|
|
301
|
+
label: tab.label,
|
|
302
|
+
forceRender: true,
|
|
303
|
+
children: (
|
|
304
|
+
<div className='pd1x'>
|
|
305
|
+
{(tab.fields || []).map((f, index) => renderFormItem(f, config.layout, form, ctxProps, index))}
|
|
306
|
+
</div>
|
|
307
|
+
)
|
|
308
|
+
}))
|
|
309
|
+
content = <Tabs items={items} />
|
|
310
|
+
}
|
|
311
|
+
const formName = `${config.key}-form`
|
|
312
|
+
return (
|
|
313
|
+
<Form
|
|
314
|
+
form={form}
|
|
315
|
+
onFinish={handleFinish}
|
|
316
|
+
initialValues={initialValues}
|
|
317
|
+
name={formName}
|
|
318
|
+
>
|
|
319
|
+
{content}
|
|
320
|
+
<SubmitButtons
|
|
321
|
+
onSave={save}
|
|
322
|
+
onSaveAndCreateNew={saveAndCreateNew}
|
|
323
|
+
onConnect={connect}
|
|
324
|
+
onTestConnection={testConnection}
|
|
325
|
+
/>
|
|
326
|
+
</Form>
|
|
327
|
+
)
|
|
328
|
+
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* bookmark form
|
|
2
|
+
* Config-driven bookmark form (drop-in replacement)
|
|
3
3
|
*/
|
|
4
4
|
import { PureComponent } from 'react'
|
|
5
|
-
import {
|
|
6
|
-
Radio
|
|
7
|
-
} from 'antd'
|
|
5
|
+
import { Radio } from 'antd'
|
|
8
6
|
import {
|
|
9
7
|
settingMap,
|
|
10
8
|
connectionMap,
|
|
@@ -17,78 +15,46 @@ import {
|
|
|
17
15
|
terminalFtpType,
|
|
18
16
|
newBookmarkIdPrefix
|
|
19
17
|
} from '../../common/constants'
|
|
20
|
-
import SshForm from './ssh-form'
|
|
21
|
-
import SerialForm from './serial-form'
|
|
22
|
-
import LocalForm from './local-form'
|
|
23
|
-
import TelnetForm from './telnet-form'
|
|
24
|
-
import WebForm from './web-form'
|
|
25
|
-
import RdpForm from './rdp-form'
|
|
26
|
-
import VncForm from './vnc-form'
|
|
27
|
-
import FtpForm from './ftp-form'
|
|
28
18
|
import { createTitleWithTag } from '../../common/create-title'
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
import { LoadingOutlined, BookOutlined } from '@ant-design/icons'
|
|
20
|
+
import sessionConfig from './config/session-config'
|
|
21
|
+
import renderForm from './render-form'
|
|
22
|
+
import './bookmark-form.styl'
|
|
33
23
|
|
|
34
24
|
const e = window.translate
|
|
35
25
|
|
|
36
|
-
export default class
|
|
26
|
+
export default class BookmarkIndex2 extends PureComponent {
|
|
37
27
|
constructor (props) {
|
|
38
28
|
super(props)
|
|
39
29
|
let initType = props.formData.type
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
].includes(initType)
|
|
50
|
-
) {
|
|
30
|
+
if (![
|
|
31
|
+
terminalTelnetType,
|
|
32
|
+
terminalWebType,
|
|
33
|
+
terminalLocalType,
|
|
34
|
+
terminalSerialType,
|
|
35
|
+
terminalRdpType,
|
|
36
|
+
terminalVncType,
|
|
37
|
+
terminalFtpType
|
|
38
|
+
].includes(initType)) {
|
|
51
39
|
initType = connectionMap.ssh
|
|
52
40
|
}
|
|
53
|
-
this.state = {
|
|
54
|
-
ready: false,
|
|
55
|
-
bookmarkType: initType
|
|
56
|
-
}
|
|
41
|
+
this.state = { ready: false, bookmarkType: initType }
|
|
57
42
|
}
|
|
58
43
|
|
|
59
44
|
componentDidMount () {
|
|
60
|
-
this.timer = setTimeout(() => {
|
|
61
|
-
this.setState({
|
|
62
|
-
ready: true
|
|
63
|
-
})
|
|
64
|
-
}, 50)
|
|
45
|
+
this.timer = setTimeout(() => this.setState({ ready: true }), 75)
|
|
65
46
|
}
|
|
66
47
|
|
|
67
48
|
componentWillUnmount () {
|
|
68
49
|
clearTimeout(this.timer)
|
|
69
50
|
}
|
|
70
51
|
|
|
71
|
-
static mapper = {
|
|
72
|
-
[connectionMap.ssh]: SshForm,
|
|
73
|
-
[connectionMap.telnet]: TelnetForm,
|
|
74
|
-
[connectionMap.serial]: SerialForm,
|
|
75
|
-
[connectionMap.local]: LocalForm,
|
|
76
|
-
[connectionMap.web]: WebForm,
|
|
77
|
-
[connectionMap.rdp]: RdpForm,
|
|
78
|
-
[connectionMap.vnc]: VncForm,
|
|
79
|
-
[connectionMap.ftp]: FtpForm
|
|
80
|
-
}
|
|
81
|
-
|
|
82
52
|
handleChange = (e) => {
|
|
83
|
-
this.setState({
|
|
84
|
-
bookmarkType: e.target.value
|
|
85
|
-
})
|
|
53
|
+
this.setState({ bookmarkType: e.target.value })
|
|
86
54
|
}
|
|
87
55
|
|
|
88
56
|
renderTypes (bookmarkType, isNew, keys) {
|
|
89
|
-
if (!isNew)
|
|
90
|
-
return null
|
|
91
|
-
}
|
|
57
|
+
if (!isNew) return null
|
|
92
58
|
return (
|
|
93
59
|
<Radio.Group
|
|
94
60
|
buttonStyle='solid'
|
|
@@ -98,23 +64,16 @@ export default class BookmarkIndex extends PureComponent {
|
|
|
98
64
|
disabled={!isNew}
|
|
99
65
|
onChange={this.handleChange}
|
|
100
66
|
>
|
|
101
|
-
{
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<Radio.Button key={v} value={v}>{txt}</Radio.Button>
|
|
107
|
-
)
|
|
108
|
-
})
|
|
109
|
-
}
|
|
67
|
+
{keys.map(v => {
|
|
68
|
+
const txt = v === 'ssh' ? 'Ssh/Sftp' : e(v)
|
|
69
|
+
return (<Radio.Button key={v} value={v}>{txt}</Radio.Button>)
|
|
70
|
+
})}
|
|
110
71
|
</Radio.Group>
|
|
111
72
|
)
|
|
112
73
|
}
|
|
113
74
|
|
|
114
75
|
renderTitle (formData, isNew) {
|
|
115
|
-
if (isNew)
|
|
116
|
-
return null
|
|
117
|
-
}
|
|
76
|
+
if (isNew) return null
|
|
118
77
|
return (
|
|
119
78
|
<b className='mg1x'>
|
|
120
79
|
{createTitleWithTag(formData)}
|
|
@@ -124,16 +83,10 @@ export default class BookmarkIndex extends PureComponent {
|
|
|
124
83
|
|
|
125
84
|
render () {
|
|
126
85
|
const { formData } = this.props
|
|
127
|
-
const {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const {
|
|
131
|
-
type
|
|
132
|
-
} = this.props
|
|
133
|
-
if (type !== settingMap.bookmarks) {
|
|
134
|
-
return null
|
|
135
|
-
}
|
|
136
|
-
const { ready } = this.state
|
|
86
|
+
const { id = '' } = formData
|
|
87
|
+
const { type } = this.props
|
|
88
|
+
if (type !== settingMap.bookmarks) return null
|
|
89
|
+
const { ready, bookmarkType } = this.state
|
|
137
90
|
if (!ready) {
|
|
138
91
|
return (
|
|
139
92
|
<div className='pd3 aligncenter'>
|
|
@@ -141,31 +94,19 @@ export default class BookmarkIndex extends PureComponent {
|
|
|
141
94
|
</div>
|
|
142
95
|
)
|
|
143
96
|
}
|
|
144
|
-
const {
|
|
145
|
-
bookmarkType
|
|
146
|
-
} = this.state
|
|
147
|
-
const Form = BookmarkIndex.mapper[bookmarkType]
|
|
148
97
|
const isNew = id.startsWith(newBookmarkIdPrefix)
|
|
149
|
-
const keys = Object.keys(
|
|
150
|
-
// if (isWin) {
|
|
151
|
-
// keys = keys.filter(k => k !== connectionMap.serial)
|
|
152
|
-
// }
|
|
98
|
+
const keys = Object.keys(sessionConfig)
|
|
153
99
|
return (
|
|
154
100
|
<div className='form-wrap pd1x'>
|
|
155
101
|
<div className='form-title pd1t pd1x pd2b'>
|
|
156
102
|
<BookOutlined className='mg1r' />
|
|
157
103
|
<span>
|
|
158
|
-
{
|
|
159
|
-
(!isNew
|
|
160
|
-
? e('edit')
|
|
161
|
-
: e('new')
|
|
162
|
-
) + ' ' + e(settingMap.bookmarks)
|
|
163
|
-
}
|
|
104
|
+
{((!isNew ? e('edit') : e('new')) + ' ' + e(settingMap.bookmarks))}
|
|
164
105
|
</span>
|
|
165
106
|
{this.renderTitle(formData, isNew)}
|
|
166
107
|
{this.renderTypes(bookmarkType, isNew, keys)}
|
|
167
108
|
</div>
|
|
168
|
-
|
|
109
|
+
{renderForm(bookmarkType, this.props)}
|
|
169
110
|
</div>
|
|
170
111
|
)
|
|
171
112
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render proper form according to session config
|
|
3
|
+
*/
|
|
4
|
+
import sessionConfig from './config/session-config'
|
|
5
|
+
import { connectionMap } from '../../common/constants'
|
|
6
|
+
import FormRenderer from './form-renderer'
|
|
7
|
+
|
|
8
|
+
export default function renderForm (type, props) {
|
|
9
|
+
const conf = sessionConfig[type] || sessionConfig[connectionMap.ssh]
|
|
10
|
+
return <FormRenderer config={conf} props={props} />
|
|
11
|
+
}
|
|
@@ -49,25 +49,34 @@ export default forwardRef(function Password (props, ref) {
|
|
|
49
49
|
}
|
|
50
50
|
}, [props.onBlur])
|
|
51
51
|
|
|
52
|
-
//
|
|
53
|
-
const
|
|
54
|
-
? (
|
|
55
|
-
<Tag
|
|
56
|
-
color='red'
|
|
57
|
-
>
|
|
58
|
-
A
|
|
59
|
-
</Tag>
|
|
60
|
-
)
|
|
61
|
-
: null
|
|
52
|
+
// Keep addonBefore as-is from props; must be null when caps lock is off
|
|
53
|
+
const addonBefore = props.addonBefore ?? null
|
|
62
54
|
|
|
63
|
-
//
|
|
64
|
-
|
|
55
|
+
// Show caps lock indicator inside prefix to avoid remounting the input wrapper
|
|
56
|
+
let capsPrefix = null
|
|
57
|
+
if (isCapsLockOn) {
|
|
58
|
+
capsPrefix = (
|
|
59
|
+
<Tag color='orange' style={{ marginRight: 4 }}>CAPS</Tag>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Merge any existing prefix from props with our caps indicator
|
|
64
|
+
let prefix = capsPrefix
|
|
65
|
+
if (props.prefix) {
|
|
66
|
+
prefix = (
|
|
67
|
+
<>
|
|
68
|
+
{capsPrefix}
|
|
69
|
+
{props.prefix}
|
|
70
|
+
</>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
65
73
|
|
|
66
74
|
return (
|
|
67
75
|
<Input.Password
|
|
68
76
|
{...props}
|
|
69
77
|
ref={ref}
|
|
70
78
|
addonBefore={addonBefore}
|
|
79
|
+
prefix={prefix}
|
|
71
80
|
onKeyDown={handleKeyEvent}
|
|
72
81
|
onKeyUp={handleKeyEvent}
|
|
73
82
|
onFocus={handleFocus}
|
|
@@ -6,7 +6,7 @@ import { InfoCircleOutlined } from '@ant-design/icons'
|
|
|
6
6
|
import './footer.styl'
|
|
7
7
|
import { statusMap } from '../../common/constants'
|
|
8
8
|
import BatchInput from './batch-input'
|
|
9
|
-
import encodes from '../bookmark-form/encodes'
|
|
9
|
+
import encodes from '../bookmark-form/common/encodes'
|
|
10
10
|
import { refs } from '../common/ref'
|
|
11
11
|
import Qm from '../quick-commands/quick-commands-select'
|
|
12
12
|
import AIIcon from '../icons/ai-icon'
|