@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,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if install source should skip upgrade check
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { srcsSkipUpgradeCheck } from './constants'
|
|
6
|
+
|
|
7
|
+
export const checkSkipSrc = (installSrc) => {
|
|
8
|
+
if (!installSrc) return false
|
|
9
|
+
return srcsSkipUpgradeCheck.some(skipSrc => {
|
|
10
|
+
if (skipSrc === 'skip-upgrade-check') {
|
|
11
|
+
return installSrc === skipSrc
|
|
12
|
+
}
|
|
13
|
+
// For file extensions like '.appx', '.snap', check if installSrc ends with them
|
|
14
|
+
return installSrc.endsWith(skipSrc)
|
|
15
|
+
})
|
|
16
|
+
}
|
|
@@ -1,23 +1,15 @@
|
|
|
1
|
-
// bookmark select tree
|
|
2
|
-
import createTitle from '
|
|
1
|
+
// bookmark select tree (copied from legacy)
|
|
2
|
+
import createTitle from '../../../common/create-title'
|
|
3
3
|
import { TreeSelect } from 'antd'
|
|
4
4
|
|
|
5
5
|
const e = window.translate
|
|
6
6
|
|
|
7
7
|
function buildTreeData (bookmarkGroups, tree) {
|
|
8
8
|
const cats = bookmarkGroups
|
|
9
|
-
const btree = cats
|
|
10
|
-
.reduce((p, k) => {
|
|
11
|
-
return {
|
|
12
|
-
...p,
|
|
13
|
-
[k.id]: k
|
|
14
|
-
}
|
|
15
|
-
}, {})
|
|
9
|
+
const btree = cats.reduce((p, k) => ({ ...p, [k.id]: k }), {})
|
|
16
10
|
function buildSubCats (id) {
|
|
17
11
|
const x = btree[id]
|
|
18
|
-
if (!x)
|
|
19
|
-
return ''
|
|
20
|
-
}
|
|
12
|
+
if (!x) return ''
|
|
21
13
|
const y = {
|
|
22
14
|
key: x.id,
|
|
23
15
|
value: x.id,
|
|
@@ -28,21 +20,13 @@ function buildTreeData (bookmarkGroups, tree) {
|
|
|
28
20
|
...(x.bookmarkGroupIds || []).map(buildSubCats),
|
|
29
21
|
...(x.bookmarkIds || []).map(buildLeaf)
|
|
30
22
|
].filter(d => d)
|
|
31
|
-
if (y.children && !y.children.length)
|
|
32
|
-
delete y.children
|
|
33
|
-
}
|
|
23
|
+
if (y.children && !y.children.length) delete y.children
|
|
34
24
|
return y
|
|
35
25
|
}
|
|
36
26
|
function buildLeaf (id) {
|
|
37
27
|
const x = tree[id]
|
|
38
|
-
if (!x)
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
value: x.id,
|
|
43
|
-
key: x.id,
|
|
44
|
-
title: createTitle(x)
|
|
45
|
-
}
|
|
28
|
+
if (!x) return ''
|
|
29
|
+
return { value: x.id, key: x.id, title: createTitle(x) }
|
|
46
30
|
}
|
|
47
31
|
const level1 = cats.filter(d => d.level !== 2)
|
|
48
32
|
.map(d => {
|
|
@@ -56,26 +40,15 @@ function buildTreeData (bookmarkGroups, tree) {
|
|
|
56
40
|
...(d.bookmarkIds || []).map(buildLeaf)
|
|
57
41
|
].filter(d => d)
|
|
58
42
|
}
|
|
59
|
-
if (!r.children.length)
|
|
60
|
-
return ''
|
|
61
|
-
}
|
|
43
|
+
if (!r.children.length) return ''
|
|
62
44
|
return r
|
|
63
45
|
}).filter(d => d)
|
|
64
46
|
return level1
|
|
65
47
|
}
|
|
66
48
|
|
|
67
49
|
export default function BookmarkSelect (props) {
|
|
68
|
-
const {
|
|
69
|
-
|
|
70
|
-
bookmarkGroups
|
|
71
|
-
} = props
|
|
72
|
-
const tree = bookmarks
|
|
73
|
-
.reduce((p, k) => {
|
|
74
|
-
return {
|
|
75
|
-
...p,
|
|
76
|
-
[k.id]: k
|
|
77
|
-
}
|
|
78
|
-
}, {})
|
|
50
|
+
const { bookmarks, bookmarkGroups } = props
|
|
51
|
+
const tree = bookmarks.reduce((p, k) => ({ ...p, [k.id]: k }), {})
|
|
79
52
|
|
|
80
53
|
function onSelect (id) {
|
|
81
54
|
const item = tree[id]
|
|
@@ -85,14 +58,8 @@ export default function BookmarkSelect (props) {
|
|
|
85
58
|
}
|
|
86
59
|
}
|
|
87
60
|
|
|
88
|
-
// Custom filter function to only match leaf nodes
|
|
89
61
|
function filterTreeNode (inputValue, treeNode) {
|
|
90
|
-
|
|
91
|
-
if (treeNode.selectable === false) {
|
|
92
|
-
return false
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Match against searchText which includes both title and host
|
|
62
|
+
if (treeNode.selectable === false) return false
|
|
96
63
|
return treeNode.title && treeNode.title.toLowerCase().includes(inputValue.toLowerCase())
|
|
97
64
|
}
|
|
98
65
|
|
package/client/components/bookmark-form/{bookmark-category-select.jsx → common/category-select.jsx}
RENAMED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import { useEffect } from 'react'
|
|
6
6
|
import { TreeSelect, Form } from 'antd'
|
|
7
7
|
import formatBookmarkGroups from './bookmark-group-tree-format'
|
|
8
|
+
import { formItemLayout as defaultFormItemLayout } from '../../../common/form-layout'
|
|
9
|
+
import { newBookmarkIdPrefix } from '../../../common/constants'
|
|
8
10
|
|
|
9
11
|
const FormItem = Form.Item
|
|
10
12
|
const e = window.translate
|
|
@@ -14,7 +16,8 @@ export default function BookmarkCategorySelect ({
|
|
|
14
16
|
form,
|
|
15
17
|
formItemLayout,
|
|
16
18
|
name = 'category',
|
|
17
|
-
onChange
|
|
19
|
+
onChange,
|
|
20
|
+
formData = {} // Add formData prop to access bookmark ID
|
|
18
21
|
}) {
|
|
19
22
|
const tree = formatBookmarkGroups(bookmarkGroups)
|
|
20
23
|
|
|
@@ -36,8 +39,9 @@ export default function BookmarkCategorySelect ({
|
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
// Watch for category field changes and update color accordingly
|
|
42
|
+
// Only update color for NEW bookmarks (like the old forms)
|
|
39
43
|
useEffect(() => {
|
|
40
|
-
if (categoryId) {
|
|
44
|
+
if (categoryId && formData.id && formData.id.startsWith(newBookmarkIdPrefix)) {
|
|
41
45
|
const category = findCategory(bookmarkGroups, categoryId)
|
|
42
46
|
if (category && category.color) {
|
|
43
47
|
form.setFieldsValue({
|
|
@@ -45,7 +49,7 @@ export default function BookmarkCategorySelect ({
|
|
|
45
49
|
})
|
|
46
50
|
}
|
|
47
51
|
}
|
|
48
|
-
}, [categoryId, bookmarkGroups, form])
|
|
52
|
+
}, [categoryId, bookmarkGroups, form, formData.id])
|
|
49
53
|
|
|
50
54
|
const handleCategoryChange = (categoryId) => {
|
|
51
55
|
const category = findCategory(bookmarkGroups, categoryId)
|
|
@@ -63,9 +67,11 @@ export default function BookmarkCategorySelect ({
|
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
|
|
70
|
+
const layout = formItemLayout || defaultFormItemLayout
|
|
71
|
+
|
|
66
72
|
return (
|
|
67
73
|
<FormItem
|
|
68
|
-
{...
|
|
74
|
+
{...layout}
|
|
69
75
|
label={e('bookmarkCategory')}
|
|
70
76
|
name={name}
|
|
71
77
|
>
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import { Popover } from 'antd'
|
|
3
3
|
import { HexColorPicker, RgbaColorPicker } from 'react-colorful'
|
|
4
|
-
import { defaultColors, getRandomHexColor } from '
|
|
4
|
+
import { defaultColors, getRandomHexColor } from '../../../common/rand-hex-color.js'
|
|
5
5
|
import { HexInput } from './hex-input.jsx'
|
|
6
6
|
import './color-picker.styl'
|
|
7
7
|
|
|
8
|
-
// Your Custom Color Picker component
|
|
9
8
|
export const ColorPicker = React.forwardRef((props, ref) => {
|
|
10
9
|
const { value, onChange } = props
|
|
11
10
|
const [visible, setVisible] = useState(false)
|
|
@@ -27,73 +26,38 @@ export const ColorPicker = React.forwardRef((props, ref) => {
|
|
|
27
26
|
<div className='fleft color-picker-defaults'>
|
|
28
27
|
{
|
|
29
28
|
[...defaultColors, 'random'].map((color) => {
|
|
30
|
-
const style = color === 'random'
|
|
31
|
-
|
|
32
|
-
color: '#000'
|
|
33
|
-
}
|
|
34
|
-
: {
|
|
35
|
-
color
|
|
36
|
-
}
|
|
37
|
-
const props = {
|
|
29
|
+
const style = color === 'random' ? { color: '#000' } : { color }
|
|
30
|
+
const p = {
|
|
38
31
|
className: 'color-picker-unit',
|
|
39
32
|
style,
|
|
40
33
|
onClick: () => {
|
|
41
|
-
if (color === 'random')
|
|
42
|
-
return handleChange(getRandomHexColor())
|
|
43
|
-
}
|
|
34
|
+
if (color === 'random') return handleChange(getRandomHexColor())
|
|
44
35
|
handleChange(color)
|
|
45
36
|
}
|
|
46
37
|
}
|
|
47
|
-
return
|
|
48
|
-
<div
|
|
49
|
-
{...props}
|
|
50
|
-
key={color}
|
|
51
|
-
>
|
|
52
|
-
● {color}
|
|
53
|
-
</div>
|
|
54
|
-
)
|
|
38
|
+
return <div {...p} key={color}>● {color}</div>
|
|
55
39
|
})
|
|
56
40
|
}
|
|
57
41
|
</div>
|
|
58
42
|
<div className='fright'>
|
|
59
|
-
<Picker
|
|
60
|
-
color={value}
|
|
61
|
-
onChange={handleChange}
|
|
62
|
-
/>
|
|
43
|
+
<Picker color={value} onChange={handleChange} />
|
|
63
44
|
</div>
|
|
64
45
|
</div>
|
|
65
46
|
<div className='pd1y'>
|
|
66
|
-
<HexInput
|
|
67
|
-
value={value}
|
|
68
|
-
onChange={handleChange}
|
|
69
|
-
/>
|
|
47
|
+
<HexInput value={value} onChange={handleChange} />
|
|
70
48
|
</div>
|
|
71
49
|
</div>
|
|
72
50
|
)
|
|
73
51
|
}
|
|
74
52
|
|
|
75
53
|
const inner = (
|
|
76
|
-
<div
|
|
77
|
-
ref={ref}
|
|
78
|
-
className='color-picker-choose'
|
|
79
|
-
style={{
|
|
80
|
-
backgroundColor: value
|
|
81
|
-
}}
|
|
82
|
-
/>
|
|
54
|
+
<div ref={ref} className='color-picker-choose' style={{ backgroundColor: value }} />
|
|
83
55
|
)
|
|
84
56
|
|
|
85
|
-
if (props.disabled)
|
|
86
|
-
return inner
|
|
87
|
-
}
|
|
57
|
+
if (props.disabled) return inner
|
|
88
58
|
|
|
89
59
|
return (
|
|
90
|
-
<Popover
|
|
91
|
-
content={renderContent()}
|
|
92
|
-
trigger='click'
|
|
93
|
-
open={visible}
|
|
94
|
-
placement='bottomLeft'
|
|
95
|
-
onOpenChange={handleVisibleChange}
|
|
96
|
-
>
|
|
60
|
+
<Popover content={renderContent()} trigger='click' open={visible} placement='bottomLeft' onOpenChange={handleVisibleChange}>
|
|
97
61
|
{inner}
|
|
98
62
|
</Popover>
|
|
99
63
|
)
|
|
@@ -9,21 +9,21 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
formItemLayout,
|
|
11
11
|
tailFormItemLayout
|
|
12
|
-
} from '
|
|
12
|
+
} from '../../../common/form-layout'
|
|
13
13
|
import {
|
|
14
14
|
MinusCircleFilled,
|
|
15
15
|
PlusOutlined
|
|
16
16
|
} from '@ant-design/icons'
|
|
17
17
|
import RenderAuth from './render-auth-ssh'
|
|
18
|
-
import uid from '
|
|
18
|
+
import uid from '../../../common/uid'
|
|
19
19
|
import {
|
|
20
20
|
authTypeMap,
|
|
21
21
|
connectionHoppingWarnKey
|
|
22
|
-
} from '
|
|
22
|
+
} from '../../../common/constants'
|
|
23
23
|
import { useState } from 'react'
|
|
24
|
-
import ConnectionHoppingWarningText from '
|
|
24
|
+
import ConnectionHoppingWarningText from '../../common/connection-hopping-warning-text'
|
|
25
25
|
import BookmarkSelect from './bookmark-select'
|
|
26
|
-
import * as ls from '
|
|
26
|
+
import * as ls from '../../../common/safe-local-storage'
|
|
27
27
|
|
|
28
28
|
const FormItem = Form.Item
|
|
29
29
|
const RadioButton = Radio.Button
|
|
@@ -65,7 +65,7 @@ export default function renderConnectionHopping (props) {
|
|
|
65
65
|
id: uid()
|
|
66
66
|
}
|
|
67
67
|
const v = [
|
|
68
|
-
...form.getFieldValue('connectionHoppings'),
|
|
68
|
+
...(form.getFieldValue('connectionHoppings') || []),
|
|
69
69
|
nd
|
|
70
70
|
]
|
|
71
71
|
form.setFieldsValue({
|
|
@@ -87,7 +87,7 @@ export default function renderConnectionHopping (props) {
|
|
|
87
87
|
setList(old => {
|
|
88
88
|
return old.filter(i => i.id !== id)
|
|
89
89
|
})
|
|
90
|
-
const v = form.getFieldValue('connectionHoppings').filter(i => i.id !== id)
|
|
90
|
+
const v = (form.getFieldValue('connectionHoppings') || []).filter(i => i.id !== id)
|
|
91
91
|
form.setFieldsValue({
|
|
92
92
|
connectionHoppings: v
|
|
93
93
|
})
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field renderers for config-driven forms
|
|
3
|
+
* Maps field types to React components
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import { Form, Input, InputNumber, Switch, Select, AutoComplete, Alert, Radio } from 'antd'
|
|
7
|
+
import { ColorPickerItem } from './color-picker-item.jsx'
|
|
8
|
+
import Password from '../../common/password.jsx'
|
|
9
|
+
import InputAutoFocus from '../../common/input-auto-focus.jsx'
|
|
10
|
+
import ProxyField from './proxy.jsx'
|
|
11
|
+
import X11Field from './x11.jsx'
|
|
12
|
+
import SshTunnels from './ssh-tunnels.jsx'
|
|
13
|
+
import ConnectionHopping from './connection-hopping.jsx'
|
|
14
|
+
import TerminalBackgroundField from './terminal-background.jsx'
|
|
15
|
+
import useQuickCmds from './quick-commands.jsx'
|
|
16
|
+
import ProfileItem from './profile-item.jsx'
|
|
17
|
+
import renderRunScripts from './run-scripts.jsx'
|
|
18
|
+
import SerialPathSelector from './serial-path-selector.jsx'
|
|
19
|
+
import SshHostSelector from './ssh-host-selector.jsx'
|
|
20
|
+
import SshAuthTypeSelector from './ssh-auth-type-selector.jsx'
|
|
21
|
+
import SshAuthSelector from './ssh-auth-selector.jsx'
|
|
22
|
+
import CategorySelect from './category-select.jsx'
|
|
23
|
+
import RdpAlert from './rdp-alert.jsx'
|
|
24
|
+
|
|
25
|
+
const Fragment = React.Fragment
|
|
26
|
+
|
|
27
|
+
const { TextArea } = Input
|
|
28
|
+
const commonRenderTypes = new Set([
|
|
29
|
+
'input',
|
|
30
|
+
'textarea',
|
|
31
|
+
'number',
|
|
32
|
+
'switch',
|
|
33
|
+
'select',
|
|
34
|
+
'autocomplete',
|
|
35
|
+
'radio',
|
|
36
|
+
'colorTitle',
|
|
37
|
+
'password'
|
|
38
|
+
])
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Render a single form item based on config
|
|
42
|
+
* @param {Object} item - Field configuration with type, name, label, rules, etc.
|
|
43
|
+
* @param {Object} formItemLayout - Ant Design form layout
|
|
44
|
+
* @param {Object} form - Ant Design form instance
|
|
45
|
+
* @param {Object} ctxProps - Context props (bookmarkGroups, formData, etc.)
|
|
46
|
+
* @param {number} index - Index for key generation
|
|
47
|
+
* @returns {JSX.Element|null} Rendered form item
|
|
48
|
+
*/
|
|
49
|
+
export function renderFormItem (item, formItemLayout, form, ctxProps, index) {
|
|
50
|
+
const { type, name, label, rules, valuePropName, hidden } = item
|
|
51
|
+
|
|
52
|
+
// Render simple AntD controls directly inside Form.Item
|
|
53
|
+
if (commonRenderTypes.has(type)) {
|
|
54
|
+
const cls = hidden ? 'hide' : undefined
|
|
55
|
+
let control = null
|
|
56
|
+
switch (type) {
|
|
57
|
+
case 'input':
|
|
58
|
+
control = <Input {...item.props} />
|
|
59
|
+
break
|
|
60
|
+
case 'textarea':
|
|
61
|
+
control = <TextArea autoSize={{ minRows: 1 }} {...item.props} />
|
|
62
|
+
break
|
|
63
|
+
case 'number':
|
|
64
|
+
control = <InputNumber min={1} max={65535} step={1} {...item.props} />
|
|
65
|
+
break
|
|
66
|
+
case 'switch':
|
|
67
|
+
control = <Switch {...item.props} />
|
|
68
|
+
break
|
|
69
|
+
case 'select':
|
|
70
|
+
control = <Select options={item.options} {...item.props} />
|
|
71
|
+
break
|
|
72
|
+
case 'autocomplete':
|
|
73
|
+
control = <AutoComplete options={item.options} {...item.props} />
|
|
74
|
+
break
|
|
75
|
+
case 'radio':
|
|
76
|
+
control = (
|
|
77
|
+
<Radio.Group
|
|
78
|
+
options={item.options}
|
|
79
|
+
optionType='button'
|
|
80
|
+
buttonStyle='solid'
|
|
81
|
+
size='small'
|
|
82
|
+
{...item.props}
|
|
83
|
+
/>
|
|
84
|
+
)
|
|
85
|
+
break
|
|
86
|
+
case 'colorTitle':
|
|
87
|
+
control = <InputAutoFocus addonBefore={<ColorPickerItem />} {...item.props} />
|
|
88
|
+
break
|
|
89
|
+
case 'password':
|
|
90
|
+
control = <Password {...item.props} />
|
|
91
|
+
break
|
|
92
|
+
default:
|
|
93
|
+
control = null
|
|
94
|
+
}
|
|
95
|
+
if (!control) return null
|
|
96
|
+
return (
|
|
97
|
+
<Form.Item
|
|
98
|
+
key={name}
|
|
99
|
+
{...formItemLayout}
|
|
100
|
+
className={cls}
|
|
101
|
+
label={label}
|
|
102
|
+
name={name}
|
|
103
|
+
rules={rules}
|
|
104
|
+
valuePropName={valuePropName}
|
|
105
|
+
>
|
|
106
|
+
{control}
|
|
107
|
+
</Form.Item>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Render complex/custom components directly (no extra wrapper component)
|
|
112
|
+
switch (type) {
|
|
113
|
+
case 'alert':
|
|
114
|
+
return <Alert key={name} {...item.props} />
|
|
115
|
+
case 'info':
|
|
116
|
+
return <Alert key={name} type='info' {...item.props} />
|
|
117
|
+
case 'warning':
|
|
118
|
+
return <Alert key={name} type='warning' {...item.props} />
|
|
119
|
+
case 'rdpWarning':
|
|
120
|
+
return <RdpAlert key={name} />
|
|
121
|
+
case 'categorySelect':
|
|
122
|
+
return (
|
|
123
|
+
<CategorySelect
|
|
124
|
+
key={name}
|
|
125
|
+
bookmarkGroups={ctxProps.bookmarkGroups || []}
|
|
126
|
+
form={ctxProps.form}
|
|
127
|
+
name={item.name}
|
|
128
|
+
formData={ctxProps.formData}
|
|
129
|
+
/>
|
|
130
|
+
)
|
|
131
|
+
case 'proxy':
|
|
132
|
+
return <ProxyField key={name} bookmarks={ctxProps.bookmarks} />
|
|
133
|
+
case 'x11':
|
|
134
|
+
return <X11Field key={name} form={form} />
|
|
135
|
+
case 'sshTunnels':
|
|
136
|
+
return <SshTunnels key={name} form={form} formData={ctxProps.formData} />
|
|
137
|
+
case 'connectionHopping':
|
|
138
|
+
return (
|
|
139
|
+
<ConnectionHopping
|
|
140
|
+
key={name}
|
|
141
|
+
form={form}
|
|
142
|
+
formData={ctxProps.formData || {}}
|
|
143
|
+
trim={ctxProps.trim}
|
|
144
|
+
store={ctxProps.store}
|
|
145
|
+
/>
|
|
146
|
+
)
|
|
147
|
+
case 'terminalBackground':
|
|
148
|
+
return <TerminalBackgroundField key={name} form={form} />
|
|
149
|
+
case 'profileItem':
|
|
150
|
+
return <ProfileItem key={name} store={ctxProps.store} profileFilter={item.profileFilter} />
|
|
151
|
+
case 'quickCommands':
|
|
152
|
+
return <Fragment key={name}>{useQuickCmds(form, ctxProps.formData || {})}</Fragment>
|
|
153
|
+
case 'runScripts':
|
|
154
|
+
return <Fragment key={name}>{renderRunScripts()}</Fragment>
|
|
155
|
+
case 'serialPathSelector':
|
|
156
|
+
return (
|
|
157
|
+
<SerialPathSelector
|
|
158
|
+
key={name}
|
|
159
|
+
serials={ctxProps.serials}
|
|
160
|
+
loaddingSerials={ctxProps.loaddingSerials}
|
|
161
|
+
store={ctxProps.store}
|
|
162
|
+
{...item.props}
|
|
163
|
+
/>
|
|
164
|
+
)
|
|
165
|
+
case 'sshHostSelector':
|
|
166
|
+
return (
|
|
167
|
+
<SshHostSelector
|
|
168
|
+
key={name}
|
|
169
|
+
ips={ctxProps.ips || []}
|
|
170
|
+
useIp={ctxProps.useIp}
|
|
171
|
+
form={ctxProps.form}
|
|
172
|
+
onBlur={ctxProps.handleBlur}
|
|
173
|
+
onPaste={ctxProps.handlePaste}
|
|
174
|
+
trim={ctxProps.trim}
|
|
175
|
+
{...item.props}
|
|
176
|
+
/>
|
|
177
|
+
)
|
|
178
|
+
case 'sshAuthTypeSelector':
|
|
179
|
+
return (
|
|
180
|
+
<SshAuthTypeSelector
|
|
181
|
+
key={name}
|
|
182
|
+
authType={ctxProps.authType}
|
|
183
|
+
handleChangeAuthType={ctxProps.onChangeAuthType}
|
|
184
|
+
{...item.props}
|
|
185
|
+
/>
|
|
186
|
+
)
|
|
187
|
+
case 'sshAuthSelector':
|
|
188
|
+
return (
|
|
189
|
+
<SshAuthSelector
|
|
190
|
+
key={name}
|
|
191
|
+
store={ctxProps.store}
|
|
192
|
+
form={form}
|
|
193
|
+
authType={ctxProps.authType}
|
|
194
|
+
profileFilter={item.profileFilter}
|
|
195
|
+
{...item.props}
|
|
196
|
+
/>
|
|
197
|
+
)
|
|
198
|
+
default:
|
|
199
|
+
console.warn(`Unknown field type: ${type}`)
|
|
200
|
+
return null
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Input } from 'antd'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import { CheckOutlined } from '@ant-design/icons'
|
|
4
|
+
|
|
5
|
+
export const HexInput = (props) => {
|
|
6
|
+
const [v, setV] = useState((props.value || '').replace('#', ''))
|
|
7
|
+
const handleChange = (event) => {
|
|
8
|
+
const vv = event.target.value
|
|
9
|
+
const hexRegex = /^[0-9a-fA-F]{0,6}$/
|
|
10
|
+
if (hexRegex.test(vv)) setV(vv)
|
|
11
|
+
}
|
|
12
|
+
function submit () {
|
|
13
|
+
props.onChange('#' + v)
|
|
14
|
+
}
|
|
15
|
+
function renderAfter () {
|
|
16
|
+
if (!/^[0-9a-fA-F]{6}$/.test(v)) return null
|
|
17
|
+
return <CheckOutlined className='pointer' onClick={submit} />
|
|
18
|
+
}
|
|
19
|
+
return (
|
|
20
|
+
<Input addonBefore='#' {...props} value={v} onChange={handleChange} addonAfter={renderAfter()} />
|
|
21
|
+
)
|
|
22
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common utilities for config initValues
|
|
3
|
+
*/
|
|
4
|
+
import { newBookmarkIdPrefix } from '../../../common/constants.js'
|
|
5
|
+
import { getColorFromCategory } from '../../../common/get-category-color.js'
|
|
6
|
+
import findBookmarkGroupId from '../../../common/find-bookmark-group-id.js'
|
|
7
|
+
import deepCopy from 'json-deep-copy'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates base init values that are common across all session types
|
|
11
|
+
* @param {Object} props - Props containing formData, bookmarkGroups, currentBookmarkGroupId, store
|
|
12
|
+
* @param {string} sessionType - The session type constant
|
|
13
|
+
* @param {Object} defaults - Session-specific default values
|
|
14
|
+
* @returns {Object} Combined init values
|
|
15
|
+
*/
|
|
16
|
+
export function createBaseInitValues (props, sessionType, defaults = {}) {
|
|
17
|
+
const { formData = {}, bookmarkGroups = [], currentBookmarkGroupId } = props
|
|
18
|
+
const id = formData.id || ''
|
|
19
|
+
|
|
20
|
+
// Determine bookmark group ID
|
|
21
|
+
const initBookmarkGroupId = !id.startsWith(newBookmarkIdPrefix)
|
|
22
|
+
? findBookmarkGroupId(bookmarkGroups, id)
|
|
23
|
+
: currentBookmarkGroupId
|
|
24
|
+
|
|
25
|
+
// Start with defaults and formData
|
|
26
|
+
const base = {
|
|
27
|
+
...defaults,
|
|
28
|
+
...deepCopy(formData),
|
|
29
|
+
type: sessionType,
|
|
30
|
+
category: initBookmarkGroupId
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Only set default color if no color exists (for new bookmarks)
|
|
34
|
+
if (!base.color) {
|
|
35
|
+
base.color = getColorFromCategory(bookmarkGroups, base.category)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return base
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Common terminal-related defaults
|
|
43
|
+
*/
|
|
44
|
+
export function getTerminalDefaults (store) {
|
|
45
|
+
return {
|
|
46
|
+
term: store?.config?.terminalType,
|
|
47
|
+
displayRaw: false,
|
|
48
|
+
encode: 'utf-8'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Common SSH-related defaults
|
|
54
|
+
*/
|
|
55
|
+
export function getSshDefaults () {
|
|
56
|
+
return {
|
|
57
|
+
enableSsh: true,
|
|
58
|
+
runScripts: [{
|
|
59
|
+
delay: 500,
|
|
60
|
+
script: ''
|
|
61
|
+
}]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Common terminal background defaults
|
|
67
|
+
*/
|
|
68
|
+
export function getTerminalBackgroundDefaults (defaultSetting) {
|
|
69
|
+
return {
|
|
70
|
+
terminalBackground: {
|
|
71
|
+
terminalBackgroundImagePath: defaultSetting.terminalBackgroundImagePath,
|
|
72
|
+
terminalBackgroundFilterOpacity: defaultSetting.terminalBackgroundFilterOpacity,
|
|
73
|
+
terminalBackgroundFilterBlur: defaultSetting.terminalBackgroundFilterBlur,
|
|
74
|
+
terminalBackgroundFilterBrightness: defaultSetting.terminalBackgroundFilterBrightness,
|
|
75
|
+
terminalBackgroundFilterGrayscale: defaultSetting.terminalBackgroundFilterGrayscale,
|
|
76
|
+
terminalBackgroundFilterContrast: defaultSetting.terminalBackgroundFilterContrast,
|
|
77
|
+
terminalBackgroundText: defaultSetting.terminalBackgroundText,
|
|
78
|
+
terminalBackgroundTextSize: defaultSetting.terminalBackgroundTextSize,
|
|
79
|
+
terminalBackgroundTextColor: defaultSetting.terminalBackgroundTextColor,
|
|
80
|
+
terminalBackgroundTextFontFamily: defaultSetting.terminalBackgroundTextFontFamily
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile selector component for config-driven forms
|
|
3
|
+
* Allows selecting from available profiles with filtering
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import { Form, Select } from 'antd'
|
|
7
|
+
import { formItemLayout } from '../../../common/form-layout'
|
|
8
|
+
|
|
9
|
+
const FormItem = Form.Item
|
|
10
|
+
const e = window.translate
|
|
11
|
+
|
|
12
|
+
export default function ProfileItem ({ store, profileFilter = (d) => d }) {
|
|
13
|
+
const opts = {
|
|
14
|
+
options: store.profiles
|
|
15
|
+
.filter(profileFilter)
|
|
16
|
+
.map(d => ({
|
|
17
|
+
label: d.name,
|
|
18
|
+
value: d.id
|
|
19
|
+
})),
|
|
20
|
+
placeholder: e('profiles'),
|
|
21
|
+
allowClear: true
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<FormItem
|
|
26
|
+
{...formItemLayout}
|
|
27
|
+
label={e('profiles')}
|
|
28
|
+
name='profile'
|
|
29
|
+
hasFeedback
|
|
30
|
+
>
|
|
31
|
+
<Select {...opts} />
|
|
32
|
+
</FormItem>
|
|
33
|
+
)
|
|
34
|
+
}
|
package/client/components/bookmark-form/{use-quick-commands.jsx → common/quick-commands.jsx}
RENAMED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
Space,
|
|
14
14
|
Button
|
|
15
15
|
} from 'antd'
|
|
16
|
-
import { formItemLayout } from '
|
|
16
|
+
import { formItemLayout } from '../../../common/form-layout'
|
|
17
17
|
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'
|
|
18
18
|
|
|
19
19
|
const FormItem = Form.Item
|