@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.
Files changed (84) hide show
  1. package/client/common/check-skip-src.js +16 -0
  2. package/client/components/bookmark-form/{bookmark-select.jsx → common/bookmark-select.jsx} +11 -44
  3. package/client/components/bookmark-form/{bookmark-category-select.jsx → common/category-select.jsx} +10 -4
  4. package/client/components/bookmark-form/{color-picker-item.jsx → common/color-picker-item.jsx} +2 -3
  5. package/client/components/bookmark-form/{color-picker.jsx → common/color-picker.jsx} +10 -46
  6. package/client/components/bookmark-form/{render-connection-hopping.jsx → common/connection-hopping.jsx} +7 -7
  7. package/client/components/bookmark-form/common/fields.jsx +202 -0
  8. package/client/components/bookmark-form/common/hex-input.jsx +22 -0
  9. package/client/components/bookmark-form/common/init-values.js +83 -0
  10. package/client/components/bookmark-form/common/profile-item.jsx +34 -0
  11. package/client/components/bookmark-form/{proxy.jsx → common/proxy.jsx} +1 -1
  12. package/client/components/bookmark-form/{use-quick-commands.jsx → common/quick-commands.jsx} +1 -1
  13. package/client/components/bookmark-form/common/rdp-alert.jsx +13 -0
  14. package/client/components/bookmark-form/common/render-auth-ssh.jsx +119 -0
  15. package/client/components/bookmark-form/{render-delayed-scripts.jsx → common/run-scripts.jsx} +6 -2
  16. package/client/components/bookmark-form/common/serial-path-selector.jsx +39 -0
  17. package/client/components/bookmark-form/{render-auth-ssh.jsx → common/ssh-auth-selector.jsx} +3 -4
  18. package/client/components/bookmark-form/common/ssh-auth-type-selector.jsx +38 -0
  19. package/client/components/bookmark-form/common/ssh-host-selector.jsx +61 -0
  20. package/client/components/bookmark-form/{render-ssh-tunnel.jsx → common/ssh-tunnels.jsx} +4 -4
  21. package/client/components/bookmark-form/common/submit-buttons.jsx +42 -0
  22. package/client/components/bookmark-form/{render-bg.jsx → common/terminal-background.jsx} +2 -2
  23. package/client/components/bookmark-form/{x11.jsx → common/x11.jsx} +2 -2
  24. package/client/components/bookmark-form/config/common-fields.js +305 -0
  25. package/client/components/bookmark-form/config/ftp.js +40 -0
  26. package/client/components/bookmark-form/config/local.js +96 -0
  27. package/client/components/bookmark-form/config/rdp.js +39 -0
  28. package/client/components/bookmark-form/config/serial.js +69 -0
  29. package/client/components/bookmark-form/config/session-config.js +23 -0
  30. package/client/components/bookmark-form/config/ssh.js +47 -0
  31. package/client/components/bookmark-form/config/telnet.js +40 -0
  32. package/client/components/bookmark-form/config/vnc.js +44 -0
  33. package/client/components/bookmark-form/config/web.js +45 -0
  34. package/client/components/bookmark-form/form-renderer.jsx +328 -0
  35. package/client/components/bookmark-form/index.jsx +32 -91
  36. package/client/components/bookmark-form/render-form.jsx +11 -0
  37. package/client/components/common/password.jsx +21 -12
  38. package/client/components/footer/footer-entry.jsx +1 -1
  39. package/client/components/main/main.jsx +12 -2
  40. package/client/components/main/upgrade.jsx +3 -3
  41. package/client/components/profile/profile-form-ftp.jsx +35 -0
  42. package/client/components/profile/profile-form-ssh.jsx +3 -3
  43. package/client/components/profile/profile-form-telnet.jsx +1 -1
  44. package/client/components/profile/profile-tabs.jsx +4 -0
  45. package/client/components/setting-panel/setting-modal.jsx +1 -1
  46. package/client/components/setting-panel/setting-wrap.jsx +1 -1
  47. package/client/components/setting-panel/text-bg-modal.jsx +2 -2
  48. package/client/components/sidebar/info-modal.jsx +3 -3
  49. package/client/components/theme/theme-edit-slot.jsx +1 -1
  50. package/client/components/tree-list/category-color-picker.jsx +1 -1
  51. package/client/components/tree-list/move-item-modal.jsx +1 -1
  52. package/client/entry/basic.js +6 -1
  53. package/client/store/load-data.js +1 -1
  54. package/package.json +1 -1
  55. package/client/components/bookmark-form/form-ssh-common.jsx +0 -219
  56. package/client/components/bookmark-form/form-tabs.jsx +0 -66
  57. package/client/components/bookmark-form/ftp-form-ui.jsx +0 -160
  58. package/client/components/bookmark-form/ftp-form.jsx +0 -16
  59. package/client/components/bookmark-form/hex-input.jsx +0 -39
  60. package/client/components/bookmark-form/local-form-ui.jsx +0 -151
  61. package/client/components/bookmark-form/local-form.jsx +0 -16
  62. package/client/components/bookmark-form/profile-form-item.jsx +0 -43
  63. package/client/components/bookmark-form/quick-command-list.jsx +0 -31
  64. package/client/components/bookmark-form/quick-command.jsx +0 -227
  65. package/client/components/bookmark-form/rdp-form-ui.jsx +0 -179
  66. package/client/components/bookmark-form/rdp-form.jsx +0 -16
  67. package/client/components/bookmark-form/render-profile-item.jsx +0 -0
  68. package/client/components/bookmark-form/serial-form-ui.jsx +0 -309
  69. package/client/components/bookmark-form/serial-form.jsx +0 -20
  70. package/client/components/bookmark-form/sftp-enable.jsx +0 -41
  71. package/client/components/bookmark-form/ssh-form-ui.jsx +0 -121
  72. package/client/components/bookmark-form/ssh-form.jsx +0 -292
  73. package/client/components/bookmark-form/telnet-form-ui.jsx +0 -140
  74. package/client/components/bookmark-form/telnet-form.jsx +0 -16
  75. package/client/components/bookmark-form/use-form-funcs.jsx +0 -50
  76. package/client/components/bookmark-form/use-submit.jsx +0 -67
  77. package/client/components/bookmark-form/use-ui.jsx +0 -97
  78. package/client/components/bookmark-form/vnc-form-ui.jsx +0 -213
  79. package/client/components/bookmark-form/vnc-form.jsx +0 -16
  80. package/client/components/bookmark-form/web-form-ui.jsx +0 -143
  81. package/client/components/bookmark-form/web-form.jsx +0 -16
  82. /package/client/components/bookmark-form/{bookmark-group-tree-format.js → common/bookmark-group-tree-format.js} +0 -0
  83. /package/client/components/bookmark-form/{color-picker.styl → common/color-picker.styl} +0 -0
  84. /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 '../../common/create-title'
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
- return ''
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
- bookmarks,
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
- // Skip filtering for category nodes
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
 
@@ -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
- {...formItemLayout}
74
+ {...layout}
69
75
  label={e('bookmarkCategory')}
70
76
  name={name}
71
77
  >
@@ -1,6 +1,5 @@
1
- import {
2
- Form
3
- } from 'antd'
1
+ import React from 'react'
2
+ import { Form } from 'antd'
4
3
  import { ColorPicker } from './color-picker.jsx'
5
4
 
6
5
  const FormItem = Form.Item
@@ -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 '../../common/rand-hex-color.js'
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 '../../common/form-layout'
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 '../../common/uid'
18
+ import uid from '../../../common/uid'
19
19
  import {
20
20
  authTypeMap,
21
21
  connectionHoppingWarnKey
22
- } from '../../common/constants'
22
+ } from '../../../common/constants'
23
23
  import { useState } from 'react'
24
- import ConnectionHoppingWarningText from '../common/connection-hopping-warning-text'
24
+ import ConnectionHoppingWarningText from '../../common/connection-hopping-warning-text'
25
25
  import BookmarkSelect from './bookmark-select'
26
- import * as ls from '../../common/safe-local-storage'
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
+ }
@@ -3,7 +3,7 @@ import {
3
3
  Form,
4
4
  AutoComplete
5
5
  } from 'antd'
6
- import { formItemLayout } from '../../common/form-layout'
6
+ import { formItemLayout } from '../../../common/form-layout'
7
7
 
8
8
  const FormItem = Form.Item
9
9
  const e = window.translate
@@ -13,7 +13,7 @@ import {
13
13
  Space,
14
14
  Button
15
15
  } from 'antd'
16
- import { formItemLayout } from '../../common/form-layout'
16
+ import { formItemLayout } from '../../../common/form-layout'
17
17
  import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'
18
18
 
19
19
  const FormItem = Form.Item