@electerm/electerm-react 1.100.60 → 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.
Files changed (79) hide show
  1. package/client/components/bookmark-form/{bookmark-select.jsx → common/bookmark-select.jsx} +11 -44
  2. package/client/components/bookmark-form/{bookmark-category-select.jsx → common/category-select.jsx} +10 -4
  3. package/client/components/bookmark-form/{color-picker-item.jsx → common/color-picker-item.jsx} +2 -3
  4. package/client/components/bookmark-form/{color-picker.jsx → common/color-picker.jsx} +10 -46
  5. package/client/components/bookmark-form/{render-connection-hopping.jsx → common/connection-hopping.jsx} +7 -7
  6. package/client/components/bookmark-form/common/fields.jsx +202 -0
  7. package/client/components/bookmark-form/common/hex-input.jsx +22 -0
  8. package/client/components/bookmark-form/common/init-values.js +83 -0
  9. package/client/components/bookmark-form/common/profile-item.jsx +34 -0
  10. package/client/components/bookmark-form/{proxy.jsx → common/proxy.jsx} +1 -1
  11. package/client/components/bookmark-form/{use-quick-commands.jsx → common/quick-commands.jsx} +1 -1
  12. package/client/components/bookmark-form/common/rdp-alert.jsx +13 -0
  13. package/client/components/bookmark-form/common/render-auth-ssh.jsx +119 -0
  14. package/client/components/bookmark-form/{render-delayed-scripts.jsx → common/run-scripts.jsx} +6 -2
  15. package/client/components/bookmark-form/common/serial-path-selector.jsx +39 -0
  16. package/client/components/bookmark-form/{render-auth-ssh.jsx → common/ssh-auth-selector.jsx} +3 -4
  17. package/client/components/bookmark-form/common/ssh-auth-type-selector.jsx +38 -0
  18. package/client/components/bookmark-form/common/ssh-host-selector.jsx +61 -0
  19. package/client/components/bookmark-form/{render-ssh-tunnel.jsx → common/ssh-tunnels.jsx} +4 -4
  20. package/client/components/bookmark-form/common/submit-buttons.jsx +42 -0
  21. package/client/components/bookmark-form/{render-bg.jsx → common/terminal-background.jsx} +2 -2
  22. package/client/components/bookmark-form/{x11.jsx → common/x11.jsx} +2 -2
  23. package/client/components/bookmark-form/config/common-fields.js +305 -0
  24. package/client/components/bookmark-form/config/ftp.js +40 -0
  25. package/client/components/bookmark-form/config/local.js +96 -0
  26. package/client/components/bookmark-form/config/rdp.js +39 -0
  27. package/client/components/bookmark-form/config/serial.js +69 -0
  28. package/client/components/bookmark-form/config/session-config.js +23 -0
  29. package/client/components/bookmark-form/config/ssh.js +47 -0
  30. package/client/components/bookmark-form/config/telnet.js +40 -0
  31. package/client/components/bookmark-form/config/vnc.js +44 -0
  32. package/client/components/bookmark-form/config/web.js +45 -0
  33. package/client/components/bookmark-form/form-renderer.jsx +328 -0
  34. package/client/components/bookmark-form/index.jsx +32 -91
  35. package/client/components/bookmark-form/render-form.jsx +11 -0
  36. package/client/components/footer/footer-entry.jsx +1 -1
  37. package/client/components/main/main.jsx +12 -2
  38. package/client/components/profile/profile-form-ftp.jsx +35 -0
  39. package/client/components/profile/profile-form-ssh.jsx +3 -3
  40. package/client/components/profile/profile-form-telnet.jsx +1 -1
  41. package/client/components/profile/profile-tabs.jsx +4 -0
  42. package/client/components/setting-panel/setting-modal.jsx +1 -1
  43. package/client/components/setting-panel/setting-wrap.jsx +1 -1
  44. package/client/components/setting-panel/text-bg-modal.jsx +2 -2
  45. package/client/components/theme/theme-edit-slot.jsx +1 -1
  46. package/client/components/tree-list/category-color-picker.jsx +1 -1
  47. package/client/components/tree-list/move-item-modal.jsx +1 -1
  48. package/client/store/load-data.js +1 -1
  49. package/package.json +1 -1
  50. package/client/components/bookmark-form/form-ssh-common.jsx +0 -219
  51. package/client/components/bookmark-form/form-tabs.jsx +0 -66
  52. package/client/components/bookmark-form/ftp-form-ui.jsx +0 -160
  53. package/client/components/bookmark-form/ftp-form.jsx +0 -16
  54. package/client/components/bookmark-form/hex-input.jsx +0 -39
  55. package/client/components/bookmark-form/local-form-ui.jsx +0 -151
  56. package/client/components/bookmark-form/local-form.jsx +0 -16
  57. package/client/components/bookmark-form/profile-form-item.jsx +0 -43
  58. package/client/components/bookmark-form/quick-command-list.jsx +0 -31
  59. package/client/components/bookmark-form/quick-command.jsx +0 -227
  60. package/client/components/bookmark-form/rdp-form-ui.jsx +0 -179
  61. package/client/components/bookmark-form/rdp-form.jsx +0 -16
  62. package/client/components/bookmark-form/render-profile-item.jsx +0 -0
  63. package/client/components/bookmark-form/serial-form-ui.jsx +0 -309
  64. package/client/components/bookmark-form/serial-form.jsx +0 -20
  65. package/client/components/bookmark-form/sftp-enable.jsx +0 -41
  66. package/client/components/bookmark-form/ssh-form-ui.jsx +0 -121
  67. package/client/components/bookmark-form/ssh-form.jsx +0 -292
  68. package/client/components/bookmark-form/telnet-form-ui.jsx +0 -140
  69. package/client/components/bookmark-form/telnet-form.jsx +0 -16
  70. package/client/components/bookmark-form/use-form-funcs.jsx +0 -50
  71. package/client/components/bookmark-form/use-submit.jsx +0 -67
  72. package/client/components/bookmark-form/use-ui.jsx +0 -97
  73. package/client/components/bookmark-form/vnc-form-ui.jsx +0 -213
  74. package/client/components/bookmark-form/vnc-form.jsx +0 -16
  75. package/client/components/bookmark-form/web-form-ui.jsx +0 -143
  76. package/client/components/bookmark-form/web-form.jsx +0 -16
  77. /package/client/components/bookmark-form/{bookmark-group-tree-format.js → common/bookmark-group-tree-format.js} +0 -0
  78. /package/client/components/bookmark-form/{color-picker.styl → common/color-picker.styl} +0 -0
  79. /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
- LoadingOutlined,
31
- BookOutlined
32
- } from '@ant-design/icons'
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 BookmarkIndex extends PureComponent {
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
- terminalTelnetType,
43
- terminalWebType,
44
- terminalLocalType,
45
- terminalSerialType,
46
- terminalRdpType,
47
- terminalVncType,
48
- terminalFtpType
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
- keys.map(k => {
103
- const v = connectionMap[k]
104
- const txt = v === 'ssh' ? 'Ssh/Sftp' : e(v)
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
- id = ''
129
- } = formData
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(connectionMap)
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
- <Form {...this.props} />
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
+ }
@@ -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'
@@ -79,6 +79,7 @@ export default auto(function Index (props) {
79
79
  store.isSecondInstance = window.pre.runSync('isSecondInstance')
80
80
  store.initData()
81
81
  store.checkForDbUpgrade()
82
+ store.handleGetSerials()
82
83
  // window.pre.runGlobalAsync('registerDeepLink')
83
84
  }, [])
84
85
 
@@ -117,12 +118,20 @@ export default auto(function Index (props) {
117
118
  const ext1 = {
118
119
  className: cls
119
120
  }
121
+ // Get active tab IDs
122
+ const activeTabIds = [
123
+ store.activeTabId0,
124
+ store.activeTabId1,
125
+ store.activeTabId2,
126
+ store.activeTabId3
127
+ ].filter(Boolean) // Remove empty strings
128
+
120
129
  const bgTabs = config.terminalBackgroundImagePath === 'index' ||
121
130
  config.terminalBackgroundImagePath === 'randomShape' ||
122
131
  config.terminalBackgroundImagePath === textTerminalBgValue
123
- ? store.getTabs()
132
+ ? store.getTabs().filter(tab => activeTabIds.includes(tab.id))
124
133
  : store.getTabs().filter(tab =>
125
- tab.terminalBackground?.terminalBackgroundImagePath
134
+ activeTabIds.includes(tab.id) && tab.terminalBackground?.terminalBackgroundImagePath
126
135
  )
127
136
  const confsCss = {
128
137
  ...Object.keys(config)
@@ -131,6 +140,7 @@ export default auto(function Index (props) {
131
140
  ...p,
132
141
  [k]: config[k]
133
142
  }), {}),
143
+ activeTabIds,
134
144
  tabs: bgTabs.map(tab => {
135
145
  return {
136
146
  tabCount: tab.tabCount,