@electerm/electerm-react 1.39.18 → 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.
- package/client/common/constants.js +7 -3
- package/client/common/create-title.jsx +12 -2
- package/client/common/default-setting.js +5 -0
- package/client/common/init-setting-item.js +6 -0
- package/client/components/bookmark-form/index.jsx +6 -2
- package/client/components/bookmark-form/rdp-form-ui.jsx +1 -1
- package/client/components/bookmark-form/rdp-form.jsx +1 -1
- package/client/components/bookmark-form/render-auth-ssh.jsx +27 -1
- package/client/components/bookmark-form/vnc-form-ui.jsx +179 -0
- package/client/components/bookmark-form/vnc-form.jsx +16 -0
- package/client/components/footer/footer-entry.jsx +1 -0
- package/client/components/main/term-fullscreen.styl +4 -1
- package/client/components/profile/profile-form-elem.jsx +87 -0
- package/client/components/profile/profile-form.jsx +33 -0
- package/client/components/profile/profile-list.jsx +79 -0
- package/client/components/profile/profile-transport-mod.jsx +5 -0
- package/client/components/profile/profile-transport.jsx +12 -0
- package/client/components/quick-commands/quick-command-transport-mod.jsx +13 -14
- package/client/components/rdp/rdp-session.jsx +53 -36
- package/client/components/session/session.jsx +14 -3
- package/client/components/session/session.styl +7 -2
- package/client/components/setting-panel/setting-modal.jsx +14 -0
- package/client/components/setting-panel/setting-terminal.jsx +1 -1
- package/client/components/setting-panel/tab-profiles.jsx +38 -0
- package/client/components/sftp/list-table-ui.jsx +99 -46
- package/client/components/sftp/sftp-entry.jsx +1 -0
- package/client/components/sftp/sftp.styl +4 -1
- package/client/components/sftp/transfer-common.js +1 -1
- package/client/components/terminal/index.jsx +2 -4
- package/client/components/vnc/vnc-form.jsx +66 -0
- package/client/components/vnc/vnc-session.jsx +297 -0
- package/client/store/common.js +21 -0
- package/client/store/index.js +1 -0
- package/client/store/init-state.js +4 -23
- package/client/store/load-data.js +1 -2
- package/package.json +1 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* web form
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
Input,
|
|
7
|
+
Form,
|
|
8
|
+
Button
|
|
9
|
+
} from 'antd'
|
|
10
|
+
import { formItemLayout, tailFormItemLayout } from '../../common/form-layout'
|
|
11
|
+
|
|
12
|
+
const FormItem = Form.Item
|
|
13
|
+
const { prefix } = window
|
|
14
|
+
const e = prefix('form')
|
|
15
|
+
const s = prefix('sftp')
|
|
16
|
+
|
|
17
|
+
export default function VncForm (props) {
|
|
18
|
+
const [form] = Form.useForm()
|
|
19
|
+
|
|
20
|
+
const initialValues = props.types.reduce((acc, cur) => {
|
|
21
|
+
acc[cur] = ''
|
|
22
|
+
return acc
|
|
23
|
+
}, {})
|
|
24
|
+
function renderCommon () {
|
|
25
|
+
const {
|
|
26
|
+
types
|
|
27
|
+
} = props
|
|
28
|
+
return types.map((type, index) => {
|
|
29
|
+
const Elem = type === 'password' ? Input.Password : Input
|
|
30
|
+
return (
|
|
31
|
+
<FormItem
|
|
32
|
+
{...formItemLayout}
|
|
33
|
+
label={e(type)}
|
|
34
|
+
name={type}
|
|
35
|
+
key={type}
|
|
36
|
+
autoFocus={index === 0}
|
|
37
|
+
>
|
|
38
|
+
<Elem />
|
|
39
|
+
</FormItem>
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<Form
|
|
46
|
+
form={form}
|
|
47
|
+
onFinish={props.handleFinish}
|
|
48
|
+
initialValues={initialValues}
|
|
49
|
+
name='vnc-form'
|
|
50
|
+
>
|
|
51
|
+
<div className='pd3t pd1b'>
|
|
52
|
+
{renderCommon()}
|
|
53
|
+
<FormItem
|
|
54
|
+
{...tailFormItemLayout}
|
|
55
|
+
>
|
|
56
|
+
<Button
|
|
57
|
+
type='primary'
|
|
58
|
+
htmlType='submit'
|
|
59
|
+
>
|
|
60
|
+
{s('submit')}
|
|
61
|
+
</Button>
|
|
62
|
+
</FormItem>
|
|
63
|
+
</div>
|
|
64
|
+
</Form>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import RdpSession from '../rdp/rdp-session'
|
|
2
|
+
import { createTerm } from '../terminal/terminal-apis'
|
|
3
|
+
import deepCopy from 'json-deep-copy'
|
|
4
|
+
import clone from '../../common/to-simple-obj'
|
|
5
|
+
import { handleErr } from '../../common/fetch'
|
|
6
|
+
import {
|
|
7
|
+
statusMap
|
|
8
|
+
} from '../../common/constants'
|
|
9
|
+
import {
|
|
10
|
+
Spin,
|
|
11
|
+
message,
|
|
12
|
+
Modal,
|
|
13
|
+
Tag
|
|
14
|
+
} from 'antd'
|
|
15
|
+
import * as ls from '../../common/safe-local-storage'
|
|
16
|
+
import { copy } from '../../common/clipboard'
|
|
17
|
+
import resolutions from '../rdp/resolutions'
|
|
18
|
+
import RFB from '@novnc/novnc/core/rfb'
|
|
19
|
+
import VncForm from './vnc-form'
|
|
20
|
+
|
|
21
|
+
const { prefix } = window
|
|
22
|
+
const e = prefix('form')
|
|
23
|
+
|
|
24
|
+
export default class VncSession extends RdpSession {
|
|
25
|
+
constructor (props) {
|
|
26
|
+
const id = `vnc-reso-${props.tab.host}`
|
|
27
|
+
const resObj = ls.getItemJSON(id, resolutions[0])
|
|
28
|
+
super(props)
|
|
29
|
+
this.state = {
|
|
30
|
+
types: [],
|
|
31
|
+
showConfirm: false,
|
|
32
|
+
loading: false,
|
|
33
|
+
aspectRatio: 4 / 3,
|
|
34
|
+
name: '',
|
|
35
|
+
...resObj
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
componentDidMount () {
|
|
40
|
+
this.remoteInit()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
componentWillUnmount () {
|
|
44
|
+
this.rfb && this.rfb.disconnect()
|
|
45
|
+
delete this.rfb
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// computeProps = () => {
|
|
49
|
+
// const {
|
|
50
|
+
// height,
|
|
51
|
+
// width,
|
|
52
|
+
// tabsHeight,
|
|
53
|
+
// leftSidebarWidth,
|
|
54
|
+
// pinned,
|
|
55
|
+
// openedSideBar
|
|
56
|
+
// } = this.props
|
|
57
|
+
// return {
|
|
58
|
+
// width: width - (pinned && openedSideBar ? leftSidebarWidth : 0),
|
|
59
|
+
// height: height - tabsHeight
|
|
60
|
+
// }
|
|
61
|
+
// }
|
|
62
|
+
|
|
63
|
+
remoteInit = async (term = this.term) => {
|
|
64
|
+
this.setState({
|
|
65
|
+
loading: true
|
|
66
|
+
})
|
|
67
|
+
const { config } = this.props
|
|
68
|
+
const {
|
|
69
|
+
host,
|
|
70
|
+
port,
|
|
71
|
+
tokenElecterm,
|
|
72
|
+
server = ''
|
|
73
|
+
} = config
|
|
74
|
+
const { sessionId, id } = this.props
|
|
75
|
+
const tab = deepCopy(this.props.tab || {})
|
|
76
|
+
const {
|
|
77
|
+
type,
|
|
78
|
+
term: terminalType,
|
|
79
|
+
viewOnly = false,
|
|
80
|
+
scaleViewport = true,
|
|
81
|
+
username,
|
|
82
|
+
password
|
|
83
|
+
} = tab
|
|
84
|
+
const opts = clone({
|
|
85
|
+
term: terminalType || config.terminalType,
|
|
86
|
+
sessionId,
|
|
87
|
+
tabId: id,
|
|
88
|
+
srcTabId: tab.id,
|
|
89
|
+
termType: type,
|
|
90
|
+
...tab
|
|
91
|
+
})
|
|
92
|
+
let pid = await createTerm(opts)
|
|
93
|
+
.catch(err => {
|
|
94
|
+
const text = err.message
|
|
95
|
+
handleErr({ message: text })
|
|
96
|
+
})
|
|
97
|
+
pid = pid || ''
|
|
98
|
+
this.setState({
|
|
99
|
+
loading: false
|
|
100
|
+
})
|
|
101
|
+
if (!pid) {
|
|
102
|
+
this.setStatus(statusMap.error)
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
this.setStatus(statusMap.success)
|
|
106
|
+
this.pid = pid
|
|
107
|
+
const hs = server
|
|
108
|
+
? server.replace(/https?:\/\//, '')
|
|
109
|
+
: `${host}:${port}`
|
|
110
|
+
const pre = server.startsWith('https') ? 'wss' : 'ws'
|
|
111
|
+
const { width, height } = this.state
|
|
112
|
+
const wsUrl = `${pre}://${hs}/vnc/${pid}?sessionId=${sessionId}&token=${tokenElecterm}&width=${width}&height=${height}`
|
|
113
|
+
const vncOpts = {
|
|
114
|
+
scaleViewport,
|
|
115
|
+
viewOnly,
|
|
116
|
+
style: {
|
|
117
|
+
width: width + 'px',
|
|
118
|
+
height: height + 'px',
|
|
119
|
+
overflow: 'scroll'
|
|
120
|
+
},
|
|
121
|
+
credentials: {}
|
|
122
|
+
}
|
|
123
|
+
if (username) {
|
|
124
|
+
vncOpts.credentials.username = username
|
|
125
|
+
}
|
|
126
|
+
if (password) {
|
|
127
|
+
vncOpts.credentials.password = password
|
|
128
|
+
}
|
|
129
|
+
const rfb = new RFB(
|
|
130
|
+
this.getDom(),
|
|
131
|
+
wsUrl,
|
|
132
|
+
vncOpts
|
|
133
|
+
)
|
|
134
|
+
const events = [
|
|
135
|
+
'connect',
|
|
136
|
+
'disconnect',
|
|
137
|
+
'credentialsrequired',
|
|
138
|
+
'securityfailure',
|
|
139
|
+
'clipboard',
|
|
140
|
+
'bell',
|
|
141
|
+
'desktopname',
|
|
142
|
+
'capabilities'
|
|
143
|
+
]
|
|
144
|
+
for (const event of events) {
|
|
145
|
+
rfb.addEventListener(event, this[`on${window.capitalizeFirstLetter(event)}`])
|
|
146
|
+
}
|
|
147
|
+
this.rfb = rfb
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
onConnect = (event) => {
|
|
151
|
+
// console.log('onConnect', event)
|
|
152
|
+
this.setStatus(statusMap.success)
|
|
153
|
+
this.setState({
|
|
154
|
+
loading: false
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
onDisconnect = () => {
|
|
159
|
+
this.setStatus(statusMap.error)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
onSecurityfailure = (event) => {
|
|
163
|
+
// console.log('onSecurityFailure', event)
|
|
164
|
+
message.error('Security Failure: ' + event.detail?.reason)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
onOk = (res) => {
|
|
168
|
+
this.setState({
|
|
169
|
+
showConfirm: false
|
|
170
|
+
})
|
|
171
|
+
this.rfb?.sendCredentials(res)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
onCredentialsrequired = (event) => {
|
|
175
|
+
this.setState({
|
|
176
|
+
types: event.detail?.types || [],
|
|
177
|
+
showConfirm: true
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
renderForm (types = this.state.types) {
|
|
182
|
+
return (
|
|
183
|
+
<VncForm
|
|
184
|
+
types={types}
|
|
185
|
+
handleFinish={this.onOk}
|
|
186
|
+
/>
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
onClipboard = (event) => {
|
|
191
|
+
// console.log('onClipboard', event)
|
|
192
|
+
copy(event.detail.text)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
onBell = (event) => {
|
|
196
|
+
// console.log('Bell', event)
|
|
197
|
+
message.warning('Bell')
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
onDesktopname = (event) => {
|
|
201
|
+
this.setState({
|
|
202
|
+
name: event?.detail?.name || ''
|
|
203
|
+
})
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
onCapabilities = (capabilities) => {
|
|
207
|
+
console.log('onCapabilities', capabilities)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
getDom = () => {
|
|
211
|
+
const id = 'canvas_' + this.props.tab.id
|
|
212
|
+
return document.getElementById(id)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
handleReInit = () => {
|
|
216
|
+
this.rfb?.disconnect()
|
|
217
|
+
delete this.rfb
|
|
218
|
+
this.remoteInit()
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
renderInfo () {
|
|
222
|
+
const {
|
|
223
|
+
name
|
|
224
|
+
} = this.state
|
|
225
|
+
const {
|
|
226
|
+
host,
|
|
227
|
+
port,
|
|
228
|
+
username
|
|
229
|
+
} = this.props.tab
|
|
230
|
+
return (
|
|
231
|
+
<span className='mg2l mg2r'>
|
|
232
|
+
<b>{name}</b> {username}@{host}:{port}
|
|
233
|
+
</span>
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
renderHelp = () => {
|
|
238
|
+
return (
|
|
239
|
+
<Tag color='red' className='mg1l'>Beta</Tag>
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
renderConfirm () {
|
|
244
|
+
const {
|
|
245
|
+
showConfirm
|
|
246
|
+
} = this.state
|
|
247
|
+
if (!showConfirm) {
|
|
248
|
+
return null
|
|
249
|
+
}
|
|
250
|
+
const confirmProps = {
|
|
251
|
+
title: e('credentialsRequired'),
|
|
252
|
+
content: this.renderForm(['password']),
|
|
253
|
+
footer: null,
|
|
254
|
+
visible: true
|
|
255
|
+
}
|
|
256
|
+
return (
|
|
257
|
+
<Modal
|
|
258
|
+
{...confirmProps}
|
|
259
|
+
>
|
|
260
|
+
{this.renderForm()}
|
|
261
|
+
</Modal>
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
render () {
|
|
266
|
+
const { width: w, height: h } = this.computeProps()
|
|
267
|
+
const vncProps = {
|
|
268
|
+
style: {
|
|
269
|
+
width: w + 'px',
|
|
270
|
+
height: h + 'px'
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const { width, height, loading } = this.state
|
|
274
|
+
const divProps = {
|
|
275
|
+
style: {
|
|
276
|
+
width: width + 'px',
|
|
277
|
+
height: height + 'px'
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return (
|
|
281
|
+
<Spin spinning={loading}>
|
|
282
|
+
<div
|
|
283
|
+
{...vncProps}
|
|
284
|
+
className='rdp-session-wrap pd1'
|
|
285
|
+
>
|
|
286
|
+
{this.renderControl()}
|
|
287
|
+
<div
|
|
288
|
+
{...divProps}
|
|
289
|
+
className='vnc-session-wrap session-v-wrap'
|
|
290
|
+
id={'canvas_' + this.props.tab.id}
|
|
291
|
+
/>
|
|
292
|
+
{this.renderConfirm()}
|
|
293
|
+
</div>
|
|
294
|
+
</Spin>
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
}
|
package/client/store/common.js
CHANGED
|
@@ -211,4 +211,25 @@ export default Store => {
|
|
|
211
211
|
terminalInfos: arr
|
|
212
212
|
})
|
|
213
213
|
}
|
|
214
|
+
|
|
215
|
+
Store.prototype.applyProfile = function (tab) {
|
|
216
|
+
const {
|
|
217
|
+
authType,
|
|
218
|
+
profile
|
|
219
|
+
} = tab
|
|
220
|
+
if (authType !== 'profiles') {
|
|
221
|
+
return tab
|
|
222
|
+
}
|
|
223
|
+
const p = window.store.profiles.find(x => x.id === profile)
|
|
224
|
+
if (!p) {
|
|
225
|
+
return tab
|
|
226
|
+
}
|
|
227
|
+
// delete tab.password
|
|
228
|
+
// delete tab.privateKey
|
|
229
|
+
// delete tab.passphrase
|
|
230
|
+
return {
|
|
231
|
+
...tab,
|
|
232
|
+
...p
|
|
233
|
+
}
|
|
234
|
+
}
|
|
214
235
|
}
|
package/client/store/index.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
import {
|
|
6
6
|
settingMap,
|
|
7
7
|
defaultBookmarkGroupId,
|
|
8
|
-
newBookmarkIdPrefix,
|
|
9
8
|
fileOperationsMap,
|
|
10
9
|
syncTypes,
|
|
11
10
|
infoTabs,
|
|
@@ -22,14 +21,12 @@ import {
|
|
|
22
21
|
qmSortByFrequencyKey,
|
|
23
22
|
resolutionsLsKey
|
|
24
23
|
} from '../common/constants'
|
|
25
|
-
import { buildDefaultThemes
|
|
24
|
+
import { buildDefaultThemes } from '../common/terminal-theme'
|
|
26
25
|
import * as ls from '../common/safe-local-storage'
|
|
26
|
+
import initSettingItem from '../common/init-setting-item'
|
|
27
27
|
|
|
28
28
|
const { prefix } = window
|
|
29
29
|
const t = prefix('terminalThemes')
|
|
30
|
-
const e = prefix('common')
|
|
31
|
-
const newQuickCommand = 'newQuickCommand'
|
|
32
|
-
const q = prefix('quickCommands')
|
|
33
30
|
|
|
34
31
|
function getDefaultBookmarkGroups (bookmarks) {
|
|
35
32
|
return [
|
|
@@ -41,23 +38,6 @@ function getDefaultBookmarkGroups (bookmarks) {
|
|
|
41
38
|
]
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
export const getInitItem = (arr, tab) => {
|
|
45
|
-
if (tab === settingMap.history) {
|
|
46
|
-
return arr[0] || {}
|
|
47
|
-
} else if (tab === settingMap.bookmarks) {
|
|
48
|
-
return { id: newBookmarkIdPrefix + ':' + (Date.now()), title: '' }
|
|
49
|
-
} else if (tab === settingMap.setting) {
|
|
50
|
-
return { id: '', title: e('common') }
|
|
51
|
-
} else if (tab === settingMap.terminalThemes) {
|
|
52
|
-
return buildNewTheme()
|
|
53
|
-
} else if (tab === settingMap.quickCommands) {
|
|
54
|
-
return {
|
|
55
|
-
id: '',
|
|
56
|
-
name: q(newQuickCommand)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
41
|
export default () => {
|
|
62
42
|
return {
|
|
63
43
|
// common
|
|
@@ -70,6 +50,7 @@ export default () => {
|
|
|
70
50
|
termFocused: false,
|
|
71
51
|
_history: '[]',
|
|
72
52
|
_bookmarks: '[]',
|
|
53
|
+
_profiles: '[]',
|
|
73
54
|
_bookmarkGroups: JSON.stringify(
|
|
74
55
|
getDefaultBookmarkGroups([])
|
|
75
56
|
),
|
|
@@ -113,7 +94,7 @@ export default () => {
|
|
|
113
94
|
|
|
114
95
|
// for settings related
|
|
115
96
|
_setting: '',
|
|
116
|
-
_settingItem: JSON.stringify(
|
|
97
|
+
_settingItem: JSON.stringify(initSettingItem([], settingMap.bookmarks)),
|
|
117
98
|
settingTab: settingMap.bookmarks, // setting tab
|
|
118
99
|
autofocustrigger: Date.now(),
|
|
119
100
|
bookmarkId: undefined,
|
|
@@ -80,7 +80,6 @@ export async function addTabFromCommandLine (store, opts) {
|
|
|
80
80
|
conf.privateKey = await fs.readFile(options.privateKeyPath)
|
|
81
81
|
}
|
|
82
82
|
log.debug('command line opts', conf)
|
|
83
|
-
console.log(options.initFolder, !(store.config.onStartSessions || []).length, store.config.initDefaultTabOnStart)
|
|
84
83
|
if (conf.username && conf.host) {
|
|
85
84
|
store.addTab(conf)
|
|
86
85
|
} else if (
|
|
@@ -178,7 +177,7 @@ export default (Store) => {
|
|
|
178
177
|
await Promise.all(all)
|
|
179
178
|
.then(arr => {
|
|
180
179
|
for (const { name, data } of arr) {
|
|
181
|
-
ext['_' + name] = data
|
|
180
|
+
ext['_' + name] = data || '[]'
|
|
182
181
|
}
|
|
183
182
|
})
|
|
184
183
|
ext.lastDataUpdateTime = await getData('lastDataUpdateTime') || 0
|