@electerm/electerm-react 2.8.16 → 2.10.26
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 +3 -3
- package/client/common/pre.js +1 -120
- package/client/components/ai/ai-config.jsx +26 -3
- package/client/components/ai/ai-history-item.jsx +46 -0
- package/client/components/ai/ai-history.jsx +104 -0
- package/client/components/bookmark-form/ai-bookmark-form.jsx +338 -0
- package/client/components/bookmark-form/bookmark-form.styl +1 -1
- package/client/components/bookmark-form/bookmark-schema.js +192 -0
- package/client/components/bookmark-form/common/ai-category-select.jsx +32 -0
- package/client/components/bookmark-form/common/category-select.jsx +2 -4
- package/client/components/bookmark-form/common/fields.jsx +0 -10
- package/client/components/bookmark-form/config/ftp.js +2 -0
- package/client/components/bookmark-form/config/rdp.js +0 -1
- package/client/components/bookmark-form/config/session-config.js +3 -1
- package/client/components/bookmark-form/config/spice.js +43 -0
- package/client/components/bookmark-form/config/vnc.js +1 -2
- package/client/components/bookmark-form/fix-bookmark-default.js +134 -0
- package/client/components/bookmark-form/index.jsx +74 -14
- package/client/components/common/notification.jsx +34 -2
- package/client/components/common/notification.styl +18 -2
- package/client/components/main/wrapper.styl +0 -7
- package/client/components/rdp/rdp-session.jsx +44 -11
- package/client/components/session/session.jsx +13 -3
- package/client/components/setting-panel/deep-link-control.jsx +3 -2
- package/client/components/setting-panel/keywords-transport.jsx +0 -1
- package/client/components/shortcuts/shortcut-editor.jsx +12 -36
- package/client/components/shortcuts/shortcut-handler.js +11 -5
- package/client/components/sidebar/index.jsx +11 -1
- package/client/components/spice/spice-session.jsx +296 -0
- package/client/components/spice/spice.styl +4 -0
- package/client/components/tabs/add-btn-menu.jsx +9 -2
- package/client/components/terminal/attach-addon-custom.js +20 -76
- package/client/components/terminal/terminal.jsx +34 -28
- package/client/components/terminal/transfer-client-base.js +232 -0
- package/client/components/terminal/trzsz-client.js +306 -0
- package/client/components/terminal/xterm-loader.js +109 -0
- package/client/components/terminal/zmodem-client.js +13 -166
- package/client/components/text-editor/simple-editor.jsx +1 -2
- package/client/components/vnc/vnc-session.jsx +1 -1
- package/client/entry/electerm.jsx +0 -2
- package/client/store/load-data.js +1 -1
- package/client/store/store.js +1 -1
- package/client/store/system-menu.js +10 -0
- package/package.json +1 -1
- package/client/common/trzsz.js +0 -46
- package/client/components/bookmark-form/common/wiki-alert.jsx +0 -9
- package/client/components/common/notification-with-details.jsx +0 -34
- package/client/components/terminal/fs.js +0 -59
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
const bookmarkSchema = {
|
|
2
|
+
ssh: {
|
|
3
|
+
type: 'ssh',
|
|
4
|
+
host: 'string (required) - hostname or IP address',
|
|
5
|
+
port: 'number (default: 22) - SSH port',
|
|
6
|
+
username: 'string (required) - SSH username',
|
|
7
|
+
password: 'string - password for authentication',
|
|
8
|
+
privateKey: 'string - private key content or path for key-based auth',
|
|
9
|
+
passphrase: 'string - passphrase for private key/cetificate',
|
|
10
|
+
certificate: 'string - certificate content',
|
|
11
|
+
authType: 'string - auth type (password|privateKey|profiles)',
|
|
12
|
+
profile: 'string - profile id to reuse saved auth',
|
|
13
|
+
title: 'string - bookmark title',
|
|
14
|
+
description: 'string - bookmark description',
|
|
15
|
+
startDirectoryRemote: 'string - remote starting directory',
|
|
16
|
+
startDirectoryLocal: 'string - local starting directory',
|
|
17
|
+
enableSsh: 'boolean - enable ssh, default is true',
|
|
18
|
+
enableSftp: 'boolean - enable sftp, default is true',
|
|
19
|
+
sshTunnels: 'array - ssh tunnel definitions (see sshTunnels items)',
|
|
20
|
+
connectionHoppings: 'array - connection hopping definitions',
|
|
21
|
+
useSshAgent: 'boolean - use SSH agent, default is true',
|
|
22
|
+
sshAgent: 'string - ssh agent path',
|
|
23
|
+
serverHostKey: 'array - server host key algorithms',
|
|
24
|
+
cipher: 'array - cipher list',
|
|
25
|
+
runScripts: 'array - run scripts after connected ({delay,script})',
|
|
26
|
+
quickCommands: 'array - quick commands ({name,command})',
|
|
27
|
+
proxy: 'string - proxy address (socks5://...)',
|
|
28
|
+
x11: 'boolean - enable x11 forwarding, default is false',
|
|
29
|
+
term: 'string - terminal type, default is xterm-256color, required',
|
|
30
|
+
displayRaw: 'boolean - display raw output, default is false',
|
|
31
|
+
encode: 'string - charset, default is utf8',
|
|
32
|
+
envLang: 'string - ENV LANG, default is en_US.UTF-8',
|
|
33
|
+
setEnv: 'string - environment variables, format: `KEY1=VALUE1 KEY2=VALUE2`',
|
|
34
|
+
color: 'string - tag color, like #000000',
|
|
35
|
+
interactiveValues: 'strings separated by newline'
|
|
36
|
+
},
|
|
37
|
+
sshTunnelsItem: {
|
|
38
|
+
sshTunnel: 'string - forwardRemoteToLocal|forwardLocalToRemote|dynamicForward',
|
|
39
|
+
sshTunnelLocalHost: 'string',
|
|
40
|
+
sshTunnelLocalPort: 'number',
|
|
41
|
+
sshTunnelRemoteHost: 'string',
|
|
42
|
+
sshTunnelRemotePort: 'number',
|
|
43
|
+
name: 'string - optional tunnel name'
|
|
44
|
+
},
|
|
45
|
+
connectionHoppingsItem: {
|
|
46
|
+
host: 'string',
|
|
47
|
+
port: 'number',
|
|
48
|
+
username: 'string',
|
|
49
|
+
password: 'string',
|
|
50
|
+
privateKey: 'string',
|
|
51
|
+
passphrase: 'string - passphrase',
|
|
52
|
+
certificate: 'string',
|
|
53
|
+
authType: 'string',
|
|
54
|
+
profile: 'string - profile id'
|
|
55
|
+
},
|
|
56
|
+
telnet: {
|
|
57
|
+
type: 'telnet',
|
|
58
|
+
host: 'string (required) - hostname or IP address',
|
|
59
|
+
port: 'number (default: 23) - Telnet port',
|
|
60
|
+
username: 'string - username',
|
|
61
|
+
password: 'string - password',
|
|
62
|
+
title: 'string - bookmark title',
|
|
63
|
+
description: 'string - bookmark description',
|
|
64
|
+
loginPrompt: 'string - login prompt regex',
|
|
65
|
+
passwordPrompt: 'string - password prompt regex',
|
|
66
|
+
runScripts: 'array - run scripts after connected ({delay,script})',
|
|
67
|
+
startDirectoryRemote: 'string - remote starting directory',
|
|
68
|
+
startDirectoryLocal: 'string - local starting directory',
|
|
69
|
+
profile: 'string - profile id',
|
|
70
|
+
proxy: 'string - proxy address (socks5://...)'
|
|
71
|
+
},
|
|
72
|
+
serial: {
|
|
73
|
+
type: 'serial',
|
|
74
|
+
path: 'string (required) - serial port path, e.g., /dev/ttyUSB0 or COM1',
|
|
75
|
+
baudRate: 'number (default: 9600) - baud rate',
|
|
76
|
+
dataBits: 'number (default: 8) - data bits',
|
|
77
|
+
stopBits: 'number (default: 1) - stop bits',
|
|
78
|
+
parity: 'string - "none", "even", "odd", "mark", "space"',
|
|
79
|
+
title: 'string - bookmark title',
|
|
80
|
+
rtscts: 'boolean - enable RTS/CTS flow control, default is false',
|
|
81
|
+
xon: 'boolean - enable XON flow control, default is false',
|
|
82
|
+
xoff: 'boolean - enable XOFF flow control, default is false',
|
|
83
|
+
xany: 'boolean - enable XANY flow control, default is false',
|
|
84
|
+
runScripts: 'array - run scripts after connected ({delay,script})',
|
|
85
|
+
description: 'string - bookmark description'
|
|
86
|
+
},
|
|
87
|
+
vnc: {
|
|
88
|
+
type: 'vnc',
|
|
89
|
+
host: 'string (required) - hostname or IP address',
|
|
90
|
+
port: 'number (default: 5900) - VNC port',
|
|
91
|
+
username: 'string - VNC username',
|
|
92
|
+
password: 'string - VNC password',
|
|
93
|
+
viewOnly: 'boolean - view only mode, default is false',
|
|
94
|
+
clipViewport: 'boolean - clip viewport to window, default is false',
|
|
95
|
+
scaleViewport: 'boolean - scale viewport to window, default is true',
|
|
96
|
+
qualityLevel: 'number (0-9) - VNC quality level, lower is faster, default is 3',
|
|
97
|
+
compressionLevel: 'number (0-9) - VNC compression level, lower is faster, default is 1',
|
|
98
|
+
shared: 'boolean - shared session, default is true',
|
|
99
|
+
proxy: 'string - proxy address (socks5://...)',
|
|
100
|
+
title: 'string - bookmark title',
|
|
101
|
+
description: 'string - bookmark description',
|
|
102
|
+
profile: 'string - profile id'
|
|
103
|
+
},
|
|
104
|
+
rdp: {
|
|
105
|
+
type: 'rdp',
|
|
106
|
+
host: 'string (required) - hostname or IP address',
|
|
107
|
+
port: 'number (default: 3389) - RDP port',
|
|
108
|
+
username: 'string - username',
|
|
109
|
+
password: 'string - password',
|
|
110
|
+
title: 'string - bookmark title',
|
|
111
|
+
description: 'string - bookmark description',
|
|
112
|
+
profile: 'string - profile id',
|
|
113
|
+
proxy: 'string - proxy address (socks5://...)',
|
|
114
|
+
domain: 'string - login domain'
|
|
115
|
+
},
|
|
116
|
+
ftp: {
|
|
117
|
+
type: 'ftp',
|
|
118
|
+
host: 'string (required) - hostname or IP address',
|
|
119
|
+
port: 'number (default: 21) - FTP port',
|
|
120
|
+
user: 'string - username',
|
|
121
|
+
secure: 'boolean - use secure FTP (FTPS), default is false',
|
|
122
|
+
password: 'string - password',
|
|
123
|
+
encode: 'string - charset for file names, default is utf-8',
|
|
124
|
+
title: 'string - bookmark title',
|
|
125
|
+
profile: 'string - profile id',
|
|
126
|
+
description: 'string - bookmark description'
|
|
127
|
+
},
|
|
128
|
+
web: {
|
|
129
|
+
type: 'web',
|
|
130
|
+
url: 'string (required) - website URL',
|
|
131
|
+
title: 'string - bookmark title',
|
|
132
|
+
description: 'string - bookmark description',
|
|
133
|
+
useragent: 'string - custom user agent'
|
|
134
|
+
},
|
|
135
|
+
local: {
|
|
136
|
+
type: 'local',
|
|
137
|
+
title: 'string - bookmark title',
|
|
138
|
+
description: 'string - bookmark description',
|
|
139
|
+
startDirectoryLocal: 'string - local starting directory',
|
|
140
|
+
runScripts: 'array - run scripts after connected ({delay,script})'
|
|
141
|
+
},
|
|
142
|
+
spice: {
|
|
143
|
+
type: 'spice',
|
|
144
|
+
host: 'string (required) - hostname or IP address',
|
|
145
|
+
port: 'number (default: 5900) - Spice port',
|
|
146
|
+
password: 'string - Spice password',
|
|
147
|
+
title: 'string - bookmark title',
|
|
148
|
+
viewOnly: 'boolean - view only mode, default is false',
|
|
149
|
+
scaleViewport: 'boolean - scale viewport to window, default is true',
|
|
150
|
+
description: 'string - bookmark description',
|
|
151
|
+
profile: 'string - profile id',
|
|
152
|
+
proxy: 'string - proxy address (socks5://...)'
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function buildPrompt (description) {
|
|
157
|
+
const lang = window.store.config.languageAI || window.store.getLangName()
|
|
158
|
+
const schemaDescription = Object.entries(bookmarkSchema)
|
|
159
|
+
.map(([type, fields]) => {
|
|
160
|
+
const fieldList = Object.entries(fields)
|
|
161
|
+
.map(([key, desc]) => ` ${key}: ${desc}`)
|
|
162
|
+
.join('\n')
|
|
163
|
+
return ` ${type}:\n${fieldList}`
|
|
164
|
+
})
|
|
165
|
+
.join('\n\n')
|
|
166
|
+
|
|
167
|
+
return `You are a bookmark configuration generator. Based on the user's natural language description, generate bookmark configurations in JSON format.
|
|
168
|
+
|
|
169
|
+
Available bookmark types and their fields:
|
|
170
|
+
${schemaDescription}
|
|
171
|
+
|
|
172
|
+
Important rules:
|
|
173
|
+
1. Analyze the user's description to determine the most appropriate connection type
|
|
174
|
+
2. For SSH connections, use type "ssh" and default port 22 unless specified
|
|
175
|
+
3. For Telnet connections, use type "telnet" and default port 23 unless specified
|
|
176
|
+
4. For VNC connections, use type "vnc" and default port 5900 unless specified
|
|
177
|
+
5. For RDP connections, use type "rdp" and default port 3389 unless specified
|
|
178
|
+
6. For FTP connections, use type "ftp" and default port 21 unless specified
|
|
179
|
+
7. For Serial connections, use type "serial"
|
|
180
|
+
8. For Web/Browser connections, use type "web" with a URL field
|
|
181
|
+
9. For Local terminal, use type "local"
|
|
182
|
+
10. Only include fields that are relevant to the connection type
|
|
183
|
+
11. Always include a meaningful title if not specified
|
|
184
|
+
12. Respond ONLY with valid JSON, no markdown formatting or explanations
|
|
185
|
+
13. Reply in ${lang} language
|
|
186
|
+
|
|
187
|
+
User description: ${description}
|
|
188
|
+
|
|
189
|
+
Generate the bookmark JSON:`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export default bookmarkSchema
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TreeSelect } from 'antd'
|
|
2
|
+
import formatBookmarkGroups from './bookmark-group-tree-format'
|
|
3
|
+
|
|
4
|
+
const e = window.translate
|
|
5
|
+
|
|
6
|
+
export default function AICategorySelect ({
|
|
7
|
+
bookmarkGroups = [],
|
|
8
|
+
value,
|
|
9
|
+
onChange
|
|
10
|
+
}) {
|
|
11
|
+
const tree = formatBookmarkGroups(bookmarkGroups)
|
|
12
|
+
|
|
13
|
+
const handleChange = (categoryId) => {
|
|
14
|
+
if (onChange) {
|
|
15
|
+
onChange(categoryId)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className='pd1b'>
|
|
21
|
+
<label className='iblock mg1r'>{e('bookmarkCategory')}</label>
|
|
22
|
+
<TreeSelect
|
|
23
|
+
value={value}
|
|
24
|
+
treeData={tree}
|
|
25
|
+
treeDefaultExpandAll
|
|
26
|
+
showSearch
|
|
27
|
+
onChange={handleChange}
|
|
28
|
+
style={{ minWidth: 200 }}
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -14,7 +14,7 @@ const e = window.translate
|
|
|
14
14
|
export default function BookmarkCategorySelect ({
|
|
15
15
|
bookmarkGroups = [],
|
|
16
16
|
form,
|
|
17
|
-
formItemLayout,
|
|
17
|
+
formItemLayout = defaultFormItemLayout,
|
|
18
18
|
name = 'category',
|
|
19
19
|
onChange,
|
|
20
20
|
formData = {} // Add formData prop to access bookmark ID
|
|
@@ -67,11 +67,9 @@ export default function BookmarkCategorySelect ({
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const layout = formItemLayout || defaultFormItemLayout
|
|
71
|
-
|
|
72
70
|
return (
|
|
73
71
|
<FormItem
|
|
74
|
-
{...
|
|
72
|
+
{...formItemLayout}
|
|
75
73
|
label={e('bookmarkCategory')}
|
|
76
74
|
name={name}
|
|
77
75
|
>
|
|
@@ -21,12 +21,6 @@ import SshHostSelector from './ssh-host-selector.jsx'
|
|
|
21
21
|
import SshAuthTypeSelector from './ssh-auth-type-selector.jsx'
|
|
22
22
|
import SshAuthSelector from './ssh-auth-selector.jsx'
|
|
23
23
|
import CategorySelect from './category-select.jsx'
|
|
24
|
-
import WikiAlert from './wiki-alert.jsx'
|
|
25
|
-
import {
|
|
26
|
-
rdpWikiLink,
|
|
27
|
-
vncWikiLink
|
|
28
|
-
} from '../../../common/constants.js'
|
|
29
|
-
|
|
30
24
|
const Fragment = React.Fragment
|
|
31
25
|
const FormItem = Form.Item
|
|
32
26
|
|
|
@@ -126,10 +120,6 @@ export function renderFormItem (item, formItemLayout, form, ctxProps, index) {
|
|
|
126
120
|
return <Alert key={name} type='info' {...item.props} />
|
|
127
121
|
case 'warning':
|
|
128
122
|
return <Alert key={name} type='warning' {...item.props} />
|
|
129
|
-
case 'rdpWarning':
|
|
130
|
-
return <WikiAlert key={name} wikiUrl={rdpWikiLink} />
|
|
131
|
-
case 'vncWarning':
|
|
132
|
-
return <WikiAlert key={name} wikiUrl={vncWikiLink} />
|
|
133
123
|
case 'categorySelect':
|
|
134
124
|
return (
|
|
135
125
|
<CategorySelect
|
|
@@ -15,6 +15,7 @@ const ftpConfig = {
|
|
|
15
15
|
user: '',
|
|
16
16
|
password: '',
|
|
17
17
|
secure: false,
|
|
18
|
+
encode: 'utf-8',
|
|
18
19
|
...getAuthTypeDefault(props)
|
|
19
20
|
})
|
|
20
21
|
},
|
|
@@ -32,6 +33,7 @@ const ftpConfig = {
|
|
|
32
33
|
{ type: 'input', name: 'user', label: () => e('username') },
|
|
33
34
|
{ type: 'password', name: 'password', label: () => e('password') },
|
|
34
35
|
{ type: 'switch', name: 'secure', label: () => e('secure'), valuePropName: 'checked' },
|
|
36
|
+
commonFields.encode,
|
|
35
37
|
commonFields.type
|
|
36
38
|
]
|
|
37
39
|
}
|
|
@@ -21,7 +21,6 @@ const rdpConfig = {
|
|
|
21
21
|
key: 'auth',
|
|
22
22
|
label: e('auth'),
|
|
23
23
|
fields: [
|
|
24
|
-
{ type: 'rdpWarning', name: 'rdpWarning' },
|
|
25
24
|
commonFields.category,
|
|
26
25
|
commonFields.colorTitle,
|
|
27
26
|
{ type: 'input', name: 'host', label: () => e('host'), rules: [{ required: true, message: e('host') + ' required' }] },
|
|
@@ -8,6 +8,7 @@ import serial from './serial'
|
|
|
8
8
|
import local from './local'
|
|
9
9
|
import rdp from './rdp'
|
|
10
10
|
import ftp from './ftp'
|
|
11
|
+
import spice from './spice'
|
|
11
12
|
|
|
12
13
|
const sessionConfig = {
|
|
13
14
|
[connectionMap.ssh]: ssh,
|
|
@@ -17,7 +18,8 @@ const sessionConfig = {
|
|
|
17
18
|
[connectionMap.vnc]: vnc,
|
|
18
19
|
[connectionMap.rdp]: rdp,
|
|
19
20
|
[connectionMap.ftp]: ftp,
|
|
20
|
-
[connectionMap.web]: web
|
|
21
|
+
[connectionMap.web]: web,
|
|
22
|
+
[connectionMap.spice]: spice
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export default sessionConfig
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
|
+
import { terminalSpiceType } from '../../../common/constants.js'
|
|
3
|
+
import { createBaseInitValues, getAuthTypeDefault } from '../common/init-values.js'
|
|
4
|
+
import { isEmpty } from 'lodash-es'
|
|
5
|
+
import { commonFields } from './common-fields.js'
|
|
6
|
+
|
|
7
|
+
const e = window.translate
|
|
8
|
+
|
|
9
|
+
const spiceConfig = {
|
|
10
|
+
key: 'spice',
|
|
11
|
+
type: terminalSpiceType,
|
|
12
|
+
initValues: (props) => {
|
|
13
|
+
return createBaseInitValues(props, terminalSpiceType, {
|
|
14
|
+
port: 5900,
|
|
15
|
+
viewOnly: false,
|
|
16
|
+
scaleViewport: true,
|
|
17
|
+
connectionHoppings: [],
|
|
18
|
+
...getAuthTypeDefault(props)
|
|
19
|
+
})
|
|
20
|
+
},
|
|
21
|
+
layout: formItemLayout,
|
|
22
|
+
tabs: () => [
|
|
23
|
+
{
|
|
24
|
+
key: 'auth',
|
|
25
|
+
label: e('auth'),
|
|
26
|
+
fields: [
|
|
27
|
+
commonFields.category,
|
|
28
|
+
commonFields.colorTitle,
|
|
29
|
+
{ type: 'input', name: 'host', label: () => e('host'), rules: [{ required: true, message: e('host') + ' required' }] },
|
|
30
|
+
commonFields.port,
|
|
31
|
+
{ type: 'switch', name: 'viewOnly', label: () => e('viewOnly'), valuePropName: 'checked' },
|
|
32
|
+
{ type: 'switch', name: 'scaleViewport', label: () => e('scaleViewport'), valuePropName: 'checked' },
|
|
33
|
+
{ type: 'profileItem', name: '__profile__', label: '', profileFilter: d => !isEmpty(d.spice) },
|
|
34
|
+
commonFields.password,
|
|
35
|
+
commonFields.description,
|
|
36
|
+
commonFields.proxy,
|
|
37
|
+
commonFields.type
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default spiceConfig
|
|
@@ -13,7 +13,7 @@ const vncConfig = {
|
|
|
13
13
|
return createBaseInitValues(props, terminalVncType, {
|
|
14
14
|
port: 5900,
|
|
15
15
|
viewOnly: false,
|
|
16
|
-
clipViewport:
|
|
16
|
+
clipViewport: false,
|
|
17
17
|
scaleViewport: true,
|
|
18
18
|
qualityLevel: 3, // 0-9, lower = faster performance, default 6
|
|
19
19
|
compressionLevel: 1, // 0-9, lower = faster performance, default 2
|
|
@@ -28,7 +28,6 @@ const vncConfig = {
|
|
|
28
28
|
key: 'auth',
|
|
29
29
|
label: e('auth'),
|
|
30
30
|
fields: [
|
|
31
|
-
{ type: 'vncWarning', name: 'vncWarning' },
|
|
32
31
|
commonFields.category,
|
|
33
32
|
commonFields.colorTitle,
|
|
34
33
|
{ type: 'input', name: 'host', label: () => e('host'), rules: [{ required: true, message: e('host') + ' required' }] },
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import bookmarkSchema from './bookmark-schema.js'
|
|
2
|
+
|
|
3
|
+
const defaultValues = {
|
|
4
|
+
ssh: {
|
|
5
|
+
port: 22,
|
|
6
|
+
enableSsh: true,
|
|
7
|
+
enableSftp: true,
|
|
8
|
+
useSshAgent: true,
|
|
9
|
+
x11: false,
|
|
10
|
+
term: 'xterm-256color',
|
|
11
|
+
displayRaw: false,
|
|
12
|
+
encode: 'utf8',
|
|
13
|
+
envLang: 'en_US.UTF-8'
|
|
14
|
+
},
|
|
15
|
+
telnet: {
|
|
16
|
+
port: 23
|
|
17
|
+
},
|
|
18
|
+
serial: {
|
|
19
|
+
baudRate: 9600,
|
|
20
|
+
dataBits: 8,
|
|
21
|
+
stopBits: 1,
|
|
22
|
+
parity: 'none',
|
|
23
|
+
rtscts: false,
|
|
24
|
+
xon: false,
|
|
25
|
+
xoff: false,
|
|
26
|
+
xany: false
|
|
27
|
+
},
|
|
28
|
+
vnc: {
|
|
29
|
+
port: 5900,
|
|
30
|
+
viewOnly: false,
|
|
31
|
+
clipViewport: false,
|
|
32
|
+
scaleViewport: true,
|
|
33
|
+
qualityLevel: 3,
|
|
34
|
+
compressionLevel: 1,
|
|
35
|
+
shared: true
|
|
36
|
+
},
|
|
37
|
+
rdp: {
|
|
38
|
+
port: 3389
|
|
39
|
+
},
|
|
40
|
+
ftp: {
|
|
41
|
+
port: 21,
|
|
42
|
+
secure: false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const requiredFields = {
|
|
47
|
+
ssh: ['host', 'username', 'term'],
|
|
48
|
+
telnet: ['host'],
|
|
49
|
+
serial: ['path'],
|
|
50
|
+
vnc: ['host'],
|
|
51
|
+
rdp: ['host'],
|
|
52
|
+
ftp: ['host'],
|
|
53
|
+
web: ['url']
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function fixBookmarkData (data) {
|
|
57
|
+
if (!data || typeof data !== 'object') {
|
|
58
|
+
return data
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const type = data.type || 'ssh'
|
|
62
|
+
const schema = bookmarkSchema[type]
|
|
63
|
+
|
|
64
|
+
if (!schema) {
|
|
65
|
+
return data
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const fixed = { ...data }
|
|
69
|
+
|
|
70
|
+
if (!fixed.type) {
|
|
71
|
+
fixed.type = type
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const defaults = defaultValues[type] || {}
|
|
75
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
76
|
+
if (fixed[key] === undefined || fixed[key] === null) {
|
|
77
|
+
fixed[key] = value
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (fixed.connectionHoppings?.length) {
|
|
82
|
+
fixed.hasHopping = true
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return fixed
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function validateBookmarkData (data) {
|
|
89
|
+
if (!data || typeof data !== 'object') {
|
|
90
|
+
return {
|
|
91
|
+
valid: false,
|
|
92
|
+
errors: ['Invalid data format']
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const type = data.type || 'ssh'
|
|
97
|
+
const required = requiredFields[type] || []
|
|
98
|
+
const errors = []
|
|
99
|
+
|
|
100
|
+
for (const field of required) {
|
|
101
|
+
if (!data[field]) {
|
|
102
|
+
errors.push(`Missing required field: ${field}`)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
valid: errors.length === 0,
|
|
108
|
+
errors
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function getMissingRequiredFields (data) {
|
|
113
|
+
if (!data || typeof data !== 'object') {
|
|
114
|
+
return []
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const type = data.type || 'ssh'
|
|
118
|
+
const required = requiredFields[type] || []
|
|
119
|
+
const missing = []
|
|
120
|
+
|
|
121
|
+
for (const field of required) {
|
|
122
|
+
if (!data[field]) {
|
|
123
|
+
missing.push(field)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return missing
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export default {
|
|
131
|
+
fixBookmarkData,
|
|
132
|
+
validateBookmarkData,
|
|
133
|
+
getMissingRequiredFields
|
|
134
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Config-driven bookmark form (drop-in replacement)
|
|
3
3
|
*/
|
|
4
4
|
import { PureComponent } from 'react'
|
|
5
|
-
import { Radio } from 'antd'
|
|
5
|
+
import { Radio, Button } from 'antd'
|
|
6
6
|
import {
|
|
7
7
|
settingMap,
|
|
8
8
|
connectionMap,
|
|
@@ -13,12 +13,14 @@ import {
|
|
|
13
13
|
terminalLocalType,
|
|
14
14
|
terminalTelnetType,
|
|
15
15
|
terminalFtpType,
|
|
16
|
-
newBookmarkIdPrefix
|
|
16
|
+
newBookmarkIdPrefix,
|
|
17
|
+
terminalSpiceType
|
|
17
18
|
} from '../../common/constants'
|
|
18
19
|
import { createTitleWithTag } from '../../common/create-title'
|
|
19
|
-
import { LoadingOutlined, BookOutlined } from '@ant-design/icons'
|
|
20
|
+
import { LoadingOutlined, BookOutlined, RobotOutlined } from '@ant-design/icons'
|
|
20
21
|
import sessionConfig from './config/session-config'
|
|
21
22
|
import renderForm from './render-form'
|
|
23
|
+
import AIBookmarkForm from './ai-bookmark-form'
|
|
22
24
|
import './bookmark-form.styl'
|
|
23
25
|
|
|
24
26
|
const e = window.translate
|
|
@@ -34,27 +36,56 @@ export default class BookmarkIndex2 extends PureComponent {
|
|
|
34
36
|
terminalSerialType,
|
|
35
37
|
terminalRdpType,
|
|
36
38
|
terminalVncType,
|
|
37
|
-
terminalFtpType
|
|
39
|
+
terminalFtpType,
|
|
40
|
+
terminalSpiceType
|
|
38
41
|
].includes(initType)) {
|
|
39
42
|
initType = connectionMap.ssh
|
|
40
43
|
}
|
|
41
|
-
|
|
44
|
+
const v = this.getInitAiModeState()
|
|
45
|
+
this.state = {
|
|
46
|
+
ready: v,
|
|
47
|
+
bookmarkType: initType,
|
|
48
|
+
aiMode: v
|
|
49
|
+
}
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
componentDidMount () {
|
|
45
|
-
this.timer = setTimeout(() =>
|
|
53
|
+
this.timer = setTimeout(() => {
|
|
54
|
+
this.setState({ ready: true })
|
|
55
|
+
}, 75)
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
componentWillUnmount () {
|
|
49
59
|
clearTimeout(this.timer)
|
|
50
60
|
}
|
|
51
61
|
|
|
62
|
+
getInitAiModeState () {
|
|
63
|
+
const v = window.et.openBookmarkWithAIMode
|
|
64
|
+
if (v !== true) {
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
delete window.et.openBookmarkWithAIMode
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
|
|
52
71
|
handleChange = (e) => {
|
|
53
72
|
this.setState({ bookmarkType: e.target.value })
|
|
54
73
|
}
|
|
55
74
|
|
|
75
|
+
handleCancelAiMode = () => {
|
|
76
|
+
this.setState({ aiMode: false })
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
handleToggleAIMode = () => {
|
|
80
|
+
if (window.store.aiConfigMissing()) {
|
|
81
|
+
window.store.toggleAIConfig()
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
this.setState(prev => ({ aiMode: !prev.aiMode }))
|
|
85
|
+
}
|
|
86
|
+
|
|
56
87
|
renderTypes (bookmarkType, isNew, keys) {
|
|
57
|
-
if (!isNew) return null
|
|
88
|
+
if (!isNew || this.state.aiMode) return null
|
|
58
89
|
return (
|
|
59
90
|
<Radio.Group
|
|
60
91
|
buttonStyle='solid'
|
|
@@ -66,11 +97,7 @@ export default class BookmarkIndex2 extends PureComponent {
|
|
|
66
97
|
>
|
|
67
98
|
{keys.map(v => {
|
|
68
99
|
const txt = v === 'ssh' ? 'Ssh/Sftp' : e(v)
|
|
69
|
-
|
|
70
|
-
if (v === connectionMap.vnc || v === connectionMap.rdp) {
|
|
71
|
-
sup = <sup className='color-red'>Beta</sup>
|
|
72
|
-
}
|
|
73
|
-
return (<Radio.Button key={v} value={v}>{txt}{sup}</Radio.Button>)
|
|
100
|
+
return (<Radio.Button key={v} value={v}>{txt}</Radio.Button>)
|
|
74
101
|
})}
|
|
75
102
|
</Radio.Group>
|
|
76
103
|
)
|
|
@@ -85,6 +112,38 @@ export default class BookmarkIndex2 extends PureComponent {
|
|
|
85
112
|
)
|
|
86
113
|
}
|
|
87
114
|
|
|
115
|
+
renderAIButton (isNew) {
|
|
116
|
+
if (!isNew || this.state.aiMode) {
|
|
117
|
+
return null
|
|
118
|
+
}
|
|
119
|
+
return (
|
|
120
|
+
<Button
|
|
121
|
+
size='small'
|
|
122
|
+
className='mg2l create-ai-btn'
|
|
123
|
+
icon={<RobotOutlined />}
|
|
124
|
+
onClick={this.handleToggleAIMode}
|
|
125
|
+
>
|
|
126
|
+
{e('createBookmarkByAI')}
|
|
127
|
+
</Button>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
renderAiForm () {
|
|
132
|
+
return (
|
|
133
|
+
<AIBookmarkForm
|
|
134
|
+
onCancel={this.handleCancelAiMode}
|
|
135
|
+
/>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
renderForm () {
|
|
140
|
+
const { bookmarkType, aiMode } = this.state
|
|
141
|
+
if (aiMode) {
|
|
142
|
+
return this.renderAiForm()
|
|
143
|
+
}
|
|
144
|
+
return renderForm(bookmarkType, this.props)
|
|
145
|
+
}
|
|
146
|
+
|
|
88
147
|
render () {
|
|
89
148
|
const { formData } = this.props
|
|
90
149
|
const { id = '' } = formData
|
|
@@ -102,15 +161,16 @@ export default class BookmarkIndex2 extends PureComponent {
|
|
|
102
161
|
const keys = Object.keys(sessionConfig)
|
|
103
162
|
return (
|
|
104
163
|
<div className='form-wrap pd1x'>
|
|
105
|
-
<div className='form-title pd1t pd1x pd2b'>
|
|
164
|
+
<div className='form-title pd1t pd1x pd2b bold'>
|
|
106
165
|
<BookOutlined className='mg1r' />
|
|
107
166
|
<span>
|
|
108
167
|
{((!isNew ? e('edit') : e('new')) + ' ' + e(settingMap.bookmarks))}
|
|
109
168
|
</span>
|
|
110
169
|
{this.renderTitle(formData, isNew)}
|
|
111
170
|
{this.renderTypes(bookmarkType, isNew, keys)}
|
|
171
|
+
{this.renderAIButton(isNew)}
|
|
112
172
|
</div>
|
|
113
|
-
{renderForm(
|
|
173
|
+
{this.renderForm()}
|
|
114
174
|
</div>
|
|
115
175
|
)
|
|
116
176
|
}
|