@electerm/electerm-react 1.39.5 → 1.39.31

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 (45) hide show
  1. package/client/common/constants.js +7 -3
  2. package/client/common/create-title.jsx +12 -2
  3. package/client/common/default-setting.js +5 -0
  4. package/client/common/init-setting-item.js +6 -0
  5. package/client/components/bookmark-form/form-ssh-common.jsx +1 -1
  6. package/client/components/bookmark-form/index.jsx +6 -2
  7. package/client/components/bookmark-form/rdp-form-ui.jsx +1 -1
  8. package/client/components/bookmark-form/rdp-form.jsx +1 -1
  9. package/client/components/bookmark-form/render-auth-ssh.jsx +27 -1
  10. package/client/components/bookmark-form/render-ssh-tunnel.jsx +60 -31
  11. package/client/components/bookmark-form/use-ui.jsx +12 -0
  12. package/client/components/bookmark-form/vnc-form-ui.jsx +179 -0
  13. package/client/components/bookmark-form/vnc-form.jsx +16 -0
  14. package/client/components/footer/footer-entry.jsx +13 -6
  15. package/client/components/main/term-fullscreen.styl +4 -1
  16. package/client/components/profile/profile-form-elem.jsx +87 -0
  17. package/client/components/profile/profile-form.jsx +33 -0
  18. package/client/components/profile/profile-list.jsx +79 -0
  19. package/client/components/profile/profile-transport-mod.jsx +5 -0
  20. package/client/components/profile/profile-transport.jsx +12 -0
  21. package/client/components/quick-commands/quick-command-transport-mod.jsx +13 -14
  22. package/client/components/quick-commands/quick-commands-list-form.jsx +54 -3
  23. package/client/components/rdp/rdp-session.jsx +53 -36
  24. package/client/components/session/session.jsx +14 -3
  25. package/client/components/session/session.styl +7 -2
  26. package/client/components/setting-panel/setting-modal.jsx +23 -6
  27. package/client/components/setting-panel/setting-terminal.jsx +1 -1
  28. package/client/components/setting-panel/setting-wrap.jsx +5 -1
  29. package/client/components/setting-panel/setting-wrap.styl +5 -3
  30. package/client/components/setting-panel/tab-profiles.jsx +38 -0
  31. package/client/components/sftp/list-table-ui.jsx +99 -46
  32. package/client/components/sftp/sftp-entry.jsx +1 -0
  33. package/client/components/sftp/sftp.styl +4 -1
  34. package/client/components/sftp/transfer-common.js +1 -1
  35. package/client/components/tabs/index.jsx +1 -1
  36. package/client/components/tabs/tab.jsx +9 -4
  37. package/client/components/terminal/index.jsx +5 -5
  38. package/client/components/vnc/vnc-form.jsx +66 -0
  39. package/client/components/vnc/vnc-session.jsx +297 -0
  40. package/client/store/common.js +21 -0
  41. package/client/store/index.js +1 -0
  42. package/client/store/init-state.js +4 -23
  43. package/client/store/load-data.js +9 -2
  44. package/client/store/sync.js +7 -3
  45. package/package.json +1 -1
@@ -68,12 +68,14 @@ export const connectionMap = buildConst([
68
68
  'serial',
69
69
  'local',
70
70
  'web',
71
- 'rdp'
71
+ 'rdp',
72
+ 'vnc'
72
73
  ])
73
74
 
74
75
  export const authTypeMap = buildConst([
75
76
  'password',
76
- 'privateKey'
77
+ 'privateKey',
78
+ 'profiles'
77
79
  ])
78
80
 
79
81
  export const footerHeight = 36
@@ -101,7 +103,8 @@ export const settingMap = buildConst([
101
103
  'terminalThemes',
102
104
  'bookmarkGroups',
103
105
  'quickCommands',
104
- 'addressBookmarks'
106
+ 'addressBookmarks',
107
+ 'profiles'
105
108
  ])
106
109
 
107
110
  export const infoTabs = buildConst([
@@ -135,6 +138,7 @@ export const terminalSplitDirectionMap = buildConst([
135
138
  export const terminalSshConfigType = 'ssh-config'
136
139
  export const terminalWebType = 'web'
137
140
  export const terminalRdpType = 'rdp'
141
+ export const terminalVncType = 'vnc'
138
142
  export const terminalSerialType = 'serial'
139
143
  export const terminalTelnetType = 'telnet'
140
144
  export const terminalLocalType = 'local'
@@ -9,7 +9,16 @@ import {
9
9
  const { prefix } = window
10
10
  const p = prefix('sftp')
11
11
 
12
- export default function createTitle (res) {
12
+ function maskHost (hostOrIp = '') {
13
+ if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostOrIp)) {
14
+ const arr = hostOrIp.split('.')
15
+ return arr.slice(0, arr.length - 2).join('.') + '.*.*'
16
+ } else {
17
+ return hostOrIp.replace(/^.{3}/, '***')
18
+ }
19
+ }
20
+
21
+ export default function createTitle (res, hide = true) {
13
22
  if (!res) {
14
23
  return ''
15
24
  }
@@ -17,7 +26,8 @@ export default function createTitle (res) {
17
26
  host, port, username, title, type,
18
27
  path, connectionHoppings, sshTunnels
19
28
  } = res
20
- const fixTitle = `${username || ''}@${host}:${port}`
29
+ const h = hide ? maskHost(host) : host
30
+ const fixTitle = `${username || ''}@${h}:${port}`
21
31
  const extra = host || path ? (path || fixTitle) : ''
22
32
  let f = title
23
33
  ? `${title}` + (extra ? ` - ${extra}` : '')
@@ -52,5 +52,10 @@ export default {
52
52
  'activities',
53
53
  'network',
54
54
  'disks'
55
+ ],
56
+ filePropsEnabled: [
57
+ 'name',
58
+ 'size',
59
+ 'modifyTime'
55
60
  ]
56
61
  }
@@ -13,6 +13,7 @@ const { prefix } = window
13
13
  const e = prefix('control')
14
14
  const newQuickCommand = 'newQuickCommand'
15
15
  const q = prefix('quickCommands')
16
+ const f = prefix('form')
16
17
 
17
18
  export default (arr, tab) => {
18
19
  if (tab === settingMap.history) {
@@ -28,5 +29,10 @@ export default (arr, tab) => {
28
29
  id: '',
29
30
  name: q(newQuickCommand)
30
31
  }
32
+ } else if (tab === settingMap.profiles) {
33
+ return {
34
+ id: '',
35
+ name: f(settingMap.profiles)
36
+ }
31
37
  }
32
38
  }
@@ -209,7 +209,7 @@ export default function renderCommon (props) {
209
209
  value={k}
210
210
  key={k}
211
211
  >
212
- {k}
212
+ {k.toUpperCase()}
213
213
  </Option>
214
214
  )
215
215
  })
@@ -11,6 +11,7 @@ import {
11
11
  terminalSerialType,
12
12
  terminalWebType,
13
13
  terminalRdpType,
14
+ terminalVncType,
14
15
  terminalLocalType,
15
16
  terminalTelnetType,
16
17
  newBookmarkIdPrefix
@@ -21,6 +22,7 @@ import LocalForm from './local-form'
21
22
  import TelnetForm from './telnet-form'
22
23
  import WebForm from './web-form'
23
24
  import RdpForm from './rdp-form'
25
+ import VncForm from './vnc-form'
24
26
  import { createTitleWithTag } from '../../common/create-title'
25
27
  import {
26
28
  LoadingOutlined,
@@ -43,7 +45,8 @@ export default class BookmarkIndex extends Component {
43
45
  terminalWebType,
44
46
  terminalLocalType,
45
47
  terminalSerialType,
46
- terminalRdpType
48
+ terminalRdpType,
49
+ terminalVncType
47
50
  ].includes(initType)
48
51
  ) {
49
52
  initType = connectionMap.ssh
@@ -72,7 +75,8 @@ export default class BookmarkIndex extends Component {
72
75
  [connectionMap.serial]: SerialForm,
73
76
  [connectionMap.local]: LocalForm,
74
77
  [connectionMap.web]: WebForm,
75
- [connectionMap.rdp]: RdpForm
78
+ [connectionMap.rdp]: RdpForm,
79
+ [connectionMap.vnc]: VncForm
76
80
  }
77
81
 
78
82
  handleChange = (e) => {
@@ -29,7 +29,7 @@ const { prefix } = window
29
29
  const e = prefix('form')
30
30
  const c = prefix('common')
31
31
 
32
- export default function LocalFormUi (props) {
32
+ export default function RdpFormUi (props) {
33
33
  const [
34
34
  form,
35
35
  handleFinish,
@@ -4,7 +4,7 @@
4
4
  import BookmarkForm from './ssh-form'
5
5
  import RdpFormUi from './rdp-form-ui'
6
6
 
7
- export default class WebForm extends BookmarkForm {
7
+ export default class RdpForm extends BookmarkForm {
8
8
  render () {
9
9
  return (
10
10
  <RdpFormUi
@@ -6,7 +6,8 @@ import {
6
6
  Input,
7
7
  Upload,
8
8
  AutoComplete,
9
- Form
9
+ Form,
10
+ Select
10
11
  } from 'antd'
11
12
  import { formItemLayout } from '../../common/form-layout'
12
13
  import { uniqBy } from 'lodash-es'
@@ -57,6 +58,31 @@ export default function renderAuth (props) {
57
58
  </FormItem>
58
59
  )
59
60
  }
61
+ if (authType === 'profiles') {
62
+ const opts = {
63
+ options: store.profiles
64
+ .map(d => {
65
+ return {
66
+ label: d.name,
67
+ value: d.id
68
+ }
69
+ }),
70
+ placeholder: e('profiles'),
71
+ allowClear: false
72
+ }
73
+ return (
74
+ <FormItem
75
+ {...formItemLayout}
76
+ label={e('profiles')}
77
+ name='profile'
78
+ hasFeedback
79
+ >
80
+ <Select
81
+ {...opts}
82
+ />
83
+ </FormItem>
84
+ )
85
+ }
60
86
  return [
61
87
  <FormItem
62
88
  {...formItemLayout}
@@ -35,10 +35,14 @@ export default function renderSshTunnels (props) {
35
35
  sshTunnelRemotePort: 12300,
36
36
  sshTunnelRemoteHost: '127.0.0.1'
37
37
  })
38
+ const [isDynamic, setter] = useState(formData.sshTunnel === 'dynamicForward')
38
39
  const [list, setList] = useState(formData.sshTunnels || [])
39
40
  function onSubmit () {
40
41
  formChild.submit()
41
42
  }
43
+ function onChange (e) {
44
+ setter(e.target.value === 'dynamicForward')
45
+ }
42
46
  function handleFinish (data) {
43
47
  const nd = {
44
48
  ...data,
@@ -80,7 +84,7 @@ export default function renderSshTunnels (props) {
80
84
  title: e('sshTunnel'),
81
85
  key: 'sshTunnel',
82
86
  render: (k, item) => {
83
- // sshTunnel is forwardRemoteToLocal or forwardLocalToRemote
87
+ // sshTunnel is forwardRemoteToLocal or forwardLocalToRemote or dynamicForward
84
88
  const {
85
89
  sshTunnel,
86
90
  sshTunnelRemoteHost = '127.0.0.1',
@@ -89,6 +93,9 @@ export default function renderSshTunnels (props) {
89
93
  sshTunnelLocalPort,
90
94
  name
91
95
  } = item
96
+ if (sshTunnel === 'dynamicForward') {
97
+ return `socks5://${sshTunnelLocalHost}:${sshTunnelLocalPort}`
98
+ }
92
99
  const to = sshTunnel === 'forwardRemoteToLocal'
93
100
  ? `${s('local')}:${sshTunnelLocalHost}:${sshTunnelLocalPort}`
94
101
  : `${s('remote')}:${sshTunnelRemoteHost}:${sshTunnelRemotePort}`
@@ -148,6 +155,49 @@ export default function renderSshTunnels (props) {
148
155
  )
149
156
  }
150
157
 
158
+ function renderDynamicForward () {
159
+ return (
160
+ <p><UserOutlined /> → socks proxy → url</p>
161
+ )
162
+ }
163
+
164
+ function renderRemote () {
165
+ if (isDynamic) {
166
+ return null
167
+ }
168
+ return (
169
+ <FormItem
170
+ label={s('remote')}
171
+ {...formItemLayout}
172
+ required
173
+ className='ssh-tunnels-host'
174
+ >
175
+ <Space.Compact>
176
+ <FormItem
177
+ name='sshTunnelRemoteHost'
178
+ label=''
179
+ required
180
+ >
181
+ <Input
182
+ placeholder={e('host')}
183
+ />
184
+ </FormItem>
185
+ <FormItem
186
+ label=''
187
+ name='sshTunnelRemotePort'
188
+ required
189
+ >
190
+ <InputNumber
191
+ min={1}
192
+ max={65535}
193
+ placeholder={e('port')}
194
+ />
195
+ </FormItem>
196
+ </Space.Compact>
197
+ </FormItem>
198
+ )
199
+ }
200
+
151
201
  return (
152
202
  <div>
153
203
  <FormItem
@@ -168,7 +218,7 @@ export default function renderSshTunnels (props) {
168
218
  {...formItemLayout}
169
219
  required
170
220
  >
171
- <RadioGroup>
221
+ <RadioGroup onChange={onChange}>
172
222
  <RadioButton
173
223
  value='forwardRemoteToLocal'
174
224
  >
@@ -183,37 +233,16 @@ export default function renderSshTunnels (props) {
183
233
  <span>L→R <QuestionCircleOutlined /></span>
184
234
  </Tooltip>
185
235
  </RadioButton>
186
- </RadioGroup>
187
- </FormItem>
188
- <FormItem
189
- label={s('remote')}
190
- {...formItemLayout}
191
- required
192
- className='ssh-tunnels-host'
193
- >
194
- <Space.Compact>
195
- <FormItem
196
- name='sshTunnelRemoteHost'
197
- label=''
198
- required
199
- >
200
- <Input
201
- placeholder={e('host')}
202
- />
203
- </FormItem>
204
- <FormItem
205
- label=''
206
- name='sshTunnelRemotePort'
207
- required
236
+ <RadioButton
237
+ value='dynamicForward'
208
238
  >
209
- <InputNumber
210
- min={1}
211
- max={65535}
212
- placeholder={e('port')}
213
- />
214
- </FormItem>
215
- </Space.Compact>
239
+ <Tooltip title={renderDynamicForward()}>
240
+ <span>{e('dynamicForward')}(socks proxy) <QuestionCircleOutlined /></span>
241
+ </Tooltip>
242
+ </RadioButton>
243
+ </RadioGroup>
216
244
  </FormItem>
245
+ {renderRemote()}
217
246
  <FormItem
218
247
  label={s('local')}
219
248
  {...formItemLayout}
@@ -87,6 +87,18 @@ export default function useBookmarkFormUI (props) {
87
87
  step={1}
88
88
  placeholder={defaultFontSize}
89
89
  />
90
+ </FormItem>,
91
+ <FormItem
92
+ key='keepaliveInterval'
93
+ {...formItemLayout}
94
+ label={s('keepaliveIntervalDesc')}
95
+ name='keepaliveInterval'
96
+ >
97
+ <InputNumber
98
+ min={0}
99
+ max={20000000}
100
+ step={1000}
101
+ />
90
102
  </FormItem>
91
103
  ]
92
104
  }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * web form
3
+ */
4
+
5
+ import { useEffect } from 'react'
6
+ import {
7
+ Input,
8
+ Form,
9
+ InputNumber,
10
+ TreeSelect,
11
+ Switch
12
+ } from 'antd'
13
+ import { formItemLayout } from '../../common/form-layout'
14
+ import {
15
+ newBookmarkIdPrefix,
16
+ terminalVncType
17
+ } from '../../common/constants'
18
+ import useSubmit from './use-submit'
19
+ import copy from 'json-deep-copy'
20
+ import { defaults } from 'lodash-es'
21
+ import { ColorPickerItem } from './color-picker-item.jsx'
22
+ import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
23
+ import formatBookmarkGroups from './bookmark-group-tree-format'
24
+ import findBookmarkGroupId from '../../common/find-bookmark-group-id'
25
+
26
+ const FormItem = Form.Item
27
+ const { prefix } = window
28
+ const e = prefix('form')
29
+ const c = prefix('common')
30
+
31
+ export default function VncFormUi (props) {
32
+ const [
33
+ form,
34
+ handleFinish,
35
+ submitUi
36
+ ] = useSubmit(props)
37
+ useEffect(() => {
38
+ if (props.formData.id.startsWith(newBookmarkIdPrefix)) {
39
+ form.setFieldsValue({
40
+ category: props.currentBookmarkGroupId
41
+ })
42
+ }
43
+ }, [props.currentBookmarkGroupId])
44
+ const {
45
+ id = ''
46
+ } = props.formData
47
+ const {
48
+ bookmarkGroups = [],
49
+ currentBookmarkGroupId
50
+ } = props
51
+ let initialValues = copy(props.formData)
52
+ const initBookmarkGroupId = !id.startsWith(newBookmarkIdPrefix)
53
+ ? findBookmarkGroupId(bookmarkGroups, id)
54
+ : currentBookmarkGroupId
55
+ const defaultValues = {
56
+ type: terminalVncType,
57
+ port: 5900,
58
+ category: initBookmarkGroupId,
59
+ color: getRandomDefaultColor(),
60
+ viewOnly: false,
61
+ scaleViewport: true
62
+ }
63
+ initialValues = defaults(initialValues, defaultValues)
64
+ function renderCommon () {
65
+ const {
66
+ bookmarkGroups = []
67
+ } = props
68
+ const tree = formatBookmarkGroups(bookmarkGroups)
69
+ return (
70
+ <div className='pd1x'>
71
+ <FormItem
72
+ {...formItemLayout}
73
+ label={e('title')}
74
+ hasFeedback
75
+ >
76
+ <FormItem noStyle name='title'>
77
+ <Input addonBefore={<ColorPickerItem />} />
78
+ </FormItem>
79
+ </FormItem>
80
+ <FormItem
81
+ {...formItemLayout}
82
+ label={e('host')}
83
+ hasFeedback
84
+ name='host'
85
+ required
86
+ >
87
+ <Input />
88
+ </FormItem>
89
+ <FormItem
90
+ {...formItemLayout}
91
+ label={e('port')}
92
+ hasFeedback
93
+ name='port'
94
+ rules={[{
95
+ required: true, message: 'port required'
96
+ }]}
97
+ >
98
+ <InputNumber
99
+ placeholder={e('port')}
100
+ min={1}
101
+ max={65535}
102
+ step={1}
103
+ />
104
+ </FormItem>
105
+ <FormItem
106
+ {...formItemLayout}
107
+ label={e('viewOnly')}
108
+ name='viewOnly'
109
+ valuePropName='checked'
110
+ >
111
+ <Switch />
112
+ </FormItem>
113
+ <FormItem
114
+ {...formItemLayout}
115
+ label={e('scaleViewport')}
116
+ name='scaleViewport'
117
+ valuePropName='checked'
118
+ >
119
+ <Switch />
120
+ </FormItem>
121
+ <FormItem
122
+ {...formItemLayout}
123
+ label={e('username')}
124
+ hasFeedback
125
+ name='username'
126
+ >
127
+ <Input />
128
+ </FormItem>
129
+ <FormItem
130
+ {...formItemLayout}
131
+ label={e('password')}
132
+ hasFeedback
133
+ name='password'
134
+ >
135
+ <Input.Password />
136
+ </FormItem>
137
+ <FormItem
138
+ {...formItemLayout}
139
+ label={e('description')}
140
+ name='description'
141
+ hasFeedback
142
+ >
143
+ <Input.TextArea rows={1} />
144
+ </FormItem>
145
+ <FormItem
146
+ {...formItemLayout}
147
+ label={c('bookmarkCategory')}
148
+ name='category'
149
+ >
150
+ <TreeSelect
151
+ treeData={tree}
152
+ treeDefaultExpandAll
153
+ showSearch
154
+ />
155
+ </FormItem>
156
+ <FormItem
157
+ {...formItemLayout}
158
+ label='type'
159
+ name='type'
160
+ className='hide'
161
+ >
162
+ <Input />
163
+ </FormItem>
164
+ </div>
165
+ )
166
+ }
167
+
168
+ return (
169
+ <Form
170
+ form={form}
171
+ onFinish={handleFinish}
172
+ initialValues={initialValues}
173
+ name='vnc-form'
174
+ >
175
+ {renderCommon()}
176
+ {submitUi}
177
+ </Form>
178
+ )
179
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * bookmark form
3
+ */
4
+ import BookmarkForm from './ssh-form'
5
+ import VncFormUi from './vnc-form-ui'
6
+
7
+ export default class VncForm extends BookmarkForm {
8
+ render () {
9
+ return (
10
+ <VncFormUi
11
+ {...this.props}
12
+ {...this.getProps()}
13
+ />
14
+ )
15
+ }
16
+ }
@@ -76,21 +76,27 @@ export default class SystemMenu extends Component {
76
76
  }
77
77
 
78
78
  renderEncodingInfo () {
79
+ const selectProps = {
80
+ style: {
81
+ minWidth: 30
82
+ },
83
+ placeholder: f('encode'),
84
+ defaultValue: this.props.currentTab?.encode,
85
+ onSelect: this.handleSwitchEncoding,
86
+ size: 'small',
87
+ popupMatchSelectWidth: false
88
+ }
79
89
  return (
80
90
  <div className='terminal-footer-unit terminal-footer-info'>
81
91
  <div className='fleft relative'>
82
92
  <Select
83
- style={{ minWidth: 30 }}
84
- placeholder={f('encode')}
85
- defaultValue={this.props.currentTab?.encode}
86
- onSelect={this.handleSwitchEncoding}
87
- size='small'
93
+ {...selectProps}
88
94
  >
89
95
  {
90
96
  encodes.map(k => {
91
97
  return (
92
98
  <Option key={k} value={k}>
93
- {k}
99
+ {k.toUpperCase()}
94
100
  </Option>
95
101
  )
96
102
  })
@@ -123,6 +129,7 @@ export default class SystemMenu extends Component {
123
129
  if (
124
130
  type === 'rdp' ||
125
131
  type === 'web' ||
132
+ type === 'vnc' ||
126
133
  pane === paneMap.fileManager ||
127
134
  !tabs.length
128
135
  ) {
@@ -5,6 +5,7 @@
5
5
  .terminal-control
6
6
  .qm-wrap-tooltip
7
7
  .main-footer
8
+ .session-v-info
8
9
  display none
9
10
  .term-fullscreen-control
10
11
  display block
@@ -12,7 +13,9 @@
12
13
  top 10px
13
14
  position fixed
14
15
  z-index 100
16
+ background rgba(45, 245, 108, 0.8)
15
17
  .term-wrap
18
+ .session-v-wrap
16
19
  position fixed
17
20
  left 0 !important
18
21
  top 0 !important
@@ -24,4 +27,4 @@
24
27
  right 10px !important
25
28
  bottom 10px !important
26
29
  .term-fullscreen-control
27
- display none
30
+ display none