@electerm/electerm-react 2.3.191 → 2.4.16
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/clipboard.js +1 -1
- package/client/common/constants.js +2 -2
- package/client/common/download.jsx +3 -2
- package/client/common/error-handler.jsx +5 -9
- package/client/common/fetch-from-server.js +1 -1
- package/client/common/fetch.jsx +5 -5
- package/client/common/icon-helpers.jsx +16 -0
- package/client/common/parse-json-safe.js +1 -1
- package/client/common/pre.js +0 -7
- package/client/common/sftp.js +1 -1
- package/client/common/terminal-theme.js +1 -1
- package/client/common/transfer.js +2 -2
- package/client/common/upgrade.js +2 -2
- package/client/components/ai/ai-chat.jsx +10 -1
- package/client/components/auth/login.jsx +1 -1
- package/client/components/bg/css-overwrite.jsx +1 -1
- package/client/components/bookmark-form/common/fields.jsx +3 -0
- package/client/components/bookmark-form/common/ssh-agent.jsx +33 -0
- package/client/components/bookmark-form/config/common-fields.js +2 -4
- package/client/components/bookmark-form/config/serial.js +1 -1
- package/client/components/bookmark-form/config/ssh.js +1 -0
- package/client/components/bookmark-form/form-renderer.jsx +3 -2
- package/client/components/common/input-auto-focus.jsx +1 -1
- package/client/components/common/message.jsx +131 -0
- package/client/components/common/message.styl +58 -0
- package/client/components/common/modal.jsx +176 -0
- package/client/components/common/modal.styl +22 -0
- package/client/components/common/notification-with-details.jsx +1 -1
- package/client/components/common/notification.jsx +94 -0
- package/client/components/common/notification.styl +51 -0
- package/client/components/main/connection-hopping-warnning.jsx +1 -3
- package/client/components/main/error-wrapper.jsx +3 -2
- package/client/components/main/main.jsx +4 -11
- package/client/components/main/upgrade.jsx +6 -4
- package/client/components/profile/profile-form-elem.jsx +1 -1
- package/client/components/quick-commands/quick-commands-box.jsx +5 -2
- package/client/components/quick-commands/quick-commands-form-elem.jsx +1 -1
- package/client/components/rdp/rdp-session.jsx +2 -2
- package/client/components/session/session.jsx +4 -9
- package/client/components/setting-panel/deep-link-control.jsx +4 -3
- package/client/components/setting-panel/keyword-input.jsx +60 -0
- package/client/components/setting-panel/keywords-form.jsx +2 -7
- package/client/components/setting-panel/setting-common.jsx +1 -1
- package/client/components/setting-panel/setting-terminal.jsx +1 -1
- package/client/components/setting-panel/tab-settings.jsx +1 -1
- package/client/components/setting-sync/setting-sync-form.jsx +53 -3
- package/client/components/setting-sync/setting-sync.jsx +2 -1
- package/client/components/sftp/owner-list.js +6 -6
- package/client/components/sftp/sftp-entry.jsx +6 -4
- package/client/components/shortcuts/shortcut-editor.jsx +2 -2
- package/client/components/ssh-config/ssh-config-load-notify.jsx +3 -2
- package/client/components/tabs/tab.jsx +1 -1
- package/client/components/tabs/workspace-save-modal.jsx +2 -1
- package/client/components/terminal/attach-addon-custom.js +142 -26
- package/client/components/terminal/command-tracker-addon.js +164 -53
- package/client/components/terminal/highlight-addon.js +84 -43
- package/client/components/terminal/shell.js +138 -0
- package/client/components/terminal/term-search.styl +1 -0
- package/client/components/terminal/terminal-command-dropdown.jsx +3 -0
- package/client/components/terminal/terminal.jsx +166 -104
- package/client/components/theme/theme-form.jsx +2 -1
- package/client/components/tree-list/bookmark-transport.jsx +27 -5
- package/client/components/vnc/vnc-session.jsx +1 -1
- package/client/components/widgets/widget-notification-with-details.jsx +1 -1
- package/client/store/common.js +5 -2
- package/client/store/db-upgrade.js +1 -1
- package/client/store/init-state.js +2 -1
- package/client/store/load-data.js +2 -2
- package/client/store/mcp-handler.js +9 -56
- package/client/store/setting.js +1 -3
- package/client/store/store.js +2 -1
- package/client/store/sync.js +14 -8
- package/client/store/system-menu.js +2 -1
- package/client/store/tab.js +1 -1
- package/client/store/widgets.js +1 -3
- package/package.json +1 -1
- package/client/common/track.js +0 -7
- package/client/components/batch-op/batch-op-entry.jsx +0 -13
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { CloseOutlined } from '@ant-design/icons'
|
|
7
7
|
import classnames from 'classnames'
|
|
8
|
+
import React, { useEffect } from 'react'
|
|
9
|
+
import { createRoot } from 'react-dom/client'
|
|
8
10
|
import './modal.styl'
|
|
9
11
|
|
|
10
12
|
export default function Modal (props) {
|
|
@@ -51,6 +53,36 @@ export default function Modal (props) {
|
|
|
51
53
|
className
|
|
52
54
|
)
|
|
53
55
|
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!open) return
|
|
58
|
+
|
|
59
|
+
const handleKeyDown = (e) => {
|
|
60
|
+
const isConfirm = !!document.querySelector('.custom-modal-cancel-btn')
|
|
61
|
+
if (e.key === 'Escape') {
|
|
62
|
+
if (onCancel) {
|
|
63
|
+
onCancel()
|
|
64
|
+
e.preventDefault()
|
|
65
|
+
}
|
|
66
|
+
} else if ((e.key === 'Enter' || e.key === ' ') && !isConfirm) {
|
|
67
|
+
// For info, Enter/Space closes
|
|
68
|
+
if (onCancel) {
|
|
69
|
+
onCancel()
|
|
70
|
+
e.preventDefault()
|
|
71
|
+
}
|
|
72
|
+
} else if ((e.key === 'Enter' || e.key === ' ') && isConfirm) {
|
|
73
|
+
// For confirm, Enter/Space confirms
|
|
74
|
+
const okBtn = document.querySelector('.custom-modal-ok-btn')
|
|
75
|
+
if (okBtn) {
|
|
76
|
+
okBtn.click()
|
|
77
|
+
e.preventDefault()
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
document.addEventListener('keydown', handleKeyDown)
|
|
83
|
+
return () => document.removeEventListener('keydown', handleKeyDown)
|
|
84
|
+
}, [open, onCancel])
|
|
85
|
+
|
|
54
86
|
return (
|
|
55
87
|
<div className={cls} style={modalStyle}>
|
|
56
88
|
<div
|
|
@@ -87,3 +119,147 @@ export default function Modal (props) {
|
|
|
87
119
|
</div>
|
|
88
120
|
)
|
|
89
121
|
}
|
|
122
|
+
|
|
123
|
+
function createModalInstance (type, options) {
|
|
124
|
+
const {
|
|
125
|
+
title,
|
|
126
|
+
content,
|
|
127
|
+
okText = 'OK',
|
|
128
|
+
cancelText = 'Cancel',
|
|
129
|
+
onOk,
|
|
130
|
+
onCancel,
|
|
131
|
+
...rest
|
|
132
|
+
} = options
|
|
133
|
+
|
|
134
|
+
const container = document.createElement('div')
|
|
135
|
+
document.body.appendChild(container)
|
|
136
|
+
|
|
137
|
+
const root = createRoot(container)
|
|
138
|
+
|
|
139
|
+
const destroy = () => {
|
|
140
|
+
if (root && container && container.parentNode) {
|
|
141
|
+
root.unmount()
|
|
142
|
+
document.body.removeChild(container)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const handleOk = () => {
|
|
147
|
+
if (onOk) {
|
|
148
|
+
onOk()
|
|
149
|
+
}
|
|
150
|
+
destroy()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const handleCancel = () => {
|
|
154
|
+
if (onCancel) {
|
|
155
|
+
onCancel()
|
|
156
|
+
}
|
|
157
|
+
destroy()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const hasCancel = type === 'confirm'
|
|
161
|
+
|
|
162
|
+
const footer = (
|
|
163
|
+
<div className='custom-modal-footer-buttons'>
|
|
164
|
+
{hasCancel && (
|
|
165
|
+
<button
|
|
166
|
+
type='button'
|
|
167
|
+
className='custom-modal-cancel-btn'
|
|
168
|
+
onClick={handleCancel}
|
|
169
|
+
>
|
|
170
|
+
{cancelText}
|
|
171
|
+
</button>
|
|
172
|
+
)}
|
|
173
|
+
<button
|
|
174
|
+
type='button'
|
|
175
|
+
className='custom-modal-ok-btn'
|
|
176
|
+
onClick={handleOk}
|
|
177
|
+
>
|
|
178
|
+
{okText}
|
|
179
|
+
</button>
|
|
180
|
+
</div>
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
const modalProps = {
|
|
184
|
+
...rest,
|
|
185
|
+
title,
|
|
186
|
+
open: true,
|
|
187
|
+
onCancel: hasCancel ? handleCancel : destroy,
|
|
188
|
+
footer,
|
|
189
|
+
children: content
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
root.render(<Modal {...modalProps} />)
|
|
193
|
+
|
|
194
|
+
const update = (newOptions) => {
|
|
195
|
+
const updatedOptions = { ...options, ...newOptions }
|
|
196
|
+
const {
|
|
197
|
+
title: newTitle,
|
|
198
|
+
content: newContent,
|
|
199
|
+
okText: newOkText = 'OK',
|
|
200
|
+
cancelText: newCancelText = 'Cancel',
|
|
201
|
+
onOk: newOnOk,
|
|
202
|
+
onCancel: newOnCancel,
|
|
203
|
+
...newRest
|
|
204
|
+
} = updatedOptions
|
|
205
|
+
|
|
206
|
+
const newHandleOk = () => {
|
|
207
|
+
if (newOnOk) {
|
|
208
|
+
newOnOk()
|
|
209
|
+
}
|
|
210
|
+
destroy()
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const newHandleCancel = () => {
|
|
214
|
+
if (newOnCancel) {
|
|
215
|
+
newOnCancel()
|
|
216
|
+
}
|
|
217
|
+
destroy()
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const newFooter = (
|
|
221
|
+
<div className='custom-modal-footer-buttons'>
|
|
222
|
+
{hasCancel && (
|
|
223
|
+
<button
|
|
224
|
+
type='button'
|
|
225
|
+
className='custom-modal-cancel-btn'
|
|
226
|
+
onClick={newHandleCancel}
|
|
227
|
+
>
|
|
228
|
+
{newCancelText}
|
|
229
|
+
</button>
|
|
230
|
+
)}
|
|
231
|
+
<button
|
|
232
|
+
type='button'
|
|
233
|
+
className='custom-modal-ok-btn'
|
|
234
|
+
onClick={newHandleOk}
|
|
235
|
+
>
|
|
236
|
+
{newOkText}
|
|
237
|
+
</button>
|
|
238
|
+
</div>
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
const newModalProps = {
|
|
242
|
+
...newRest,
|
|
243
|
+
title: newTitle,
|
|
244
|
+
open: true,
|
|
245
|
+
onCancel: hasCancel ? newHandleCancel : destroy,
|
|
246
|
+
footer: newFooter,
|
|
247
|
+
children: newContent
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
root.render(<Modal {...newModalProps} />)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
destroy,
|
|
255
|
+
update
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
Modal.info = (options) => {
|
|
260
|
+
return createModalInstance('info', options)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
Modal.confirm = (options) => {
|
|
264
|
+
return createModalInstance('confirm', options)
|
|
265
|
+
}
|
|
@@ -75,3 +75,25 @@
|
|
|
75
75
|
padding 12px 24px
|
|
76
76
|
border-top 1px solid var(--main-darker)
|
|
77
77
|
text-align right
|
|
78
|
+
|
|
79
|
+
.custom-modal-footer-buttons
|
|
80
|
+
display flex
|
|
81
|
+
justify-content flex-end
|
|
82
|
+
gap 8px
|
|
83
|
+
|
|
84
|
+
.custom-modal-ok-btn,
|
|
85
|
+
.custom-modal-cancel-btn
|
|
86
|
+
padding 6px 16px
|
|
87
|
+
border none
|
|
88
|
+
border-radius 4px
|
|
89
|
+
cursor pointer
|
|
90
|
+
font-size 14px
|
|
91
|
+
transition background-color 0.2s
|
|
92
|
+
|
|
93
|
+
.custom-modal-ok-btn
|
|
94
|
+
background var(--primary)
|
|
95
|
+
color var(--primary-contrast)
|
|
96
|
+
|
|
97
|
+
.custom-modal-cancel-btn
|
|
98
|
+
background var(--main)
|
|
99
|
+
color var(--text)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react'
|
|
2
|
+
import { CloseOutlined } from '@ant-design/icons'
|
|
3
|
+
import classnames from 'classnames'
|
|
4
|
+
import generateId from '../../common/uid'
|
|
5
|
+
import { messageIcons } from '../../common/icon-helpers.jsx'
|
|
6
|
+
import './notification.styl'
|
|
7
|
+
|
|
8
|
+
const notifications = []
|
|
9
|
+
const NOTIFICATION_EVENT = 'notification-update'
|
|
10
|
+
|
|
11
|
+
function addNotification (notif) {
|
|
12
|
+
notifications.push(notif)
|
|
13
|
+
window.dispatchEvent(new CustomEvent(NOTIFICATION_EVENT))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function removeNotification (key) {
|
|
17
|
+
const index = notifications.findIndex(n => n.key === key)
|
|
18
|
+
if (index > -1) {
|
|
19
|
+
notifications.splice(index, 1)
|
|
20
|
+
window.dispatchEvent(new CustomEvent(NOTIFICATION_EVENT))
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const notification = {
|
|
25
|
+
success: (options) => {
|
|
26
|
+
addNotification({ ...options, type: 'success', key: options.key || generateId() })
|
|
27
|
+
},
|
|
28
|
+
error: (options) => {
|
|
29
|
+
addNotification({ ...options, type: 'error', key: options.key || generateId() })
|
|
30
|
+
},
|
|
31
|
+
warning: (options) => {
|
|
32
|
+
addNotification({ ...options, type: 'warning', key: options.key || generateId() })
|
|
33
|
+
},
|
|
34
|
+
info: (options) => {
|
|
35
|
+
addNotification({ ...options, type: 'info', key: options.key || generateId() })
|
|
36
|
+
},
|
|
37
|
+
destroy: (key) => {
|
|
38
|
+
if (key) {
|
|
39
|
+
removeNotification(key)
|
|
40
|
+
} else {
|
|
41
|
+
notifications.length = 0
|
|
42
|
+
window.dispatchEvent(new CustomEvent(NOTIFICATION_EVENT))
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function NotificationContainer () {
|
|
48
|
+
const [nots, setNots] = useState([...notifications])
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const handler = () => setNots([...notifications])
|
|
52
|
+
window.addEventListener(NOTIFICATION_EVENT, handler)
|
|
53
|
+
return () => window.removeEventListener(NOTIFICATION_EVENT, handler)
|
|
54
|
+
}, [])
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className='notification-container'>
|
|
58
|
+
{nots.map(notif => (
|
|
59
|
+
<NotificationItem
|
|
60
|
+
key={notif.key}
|
|
61
|
+
message={notif.message}
|
|
62
|
+
description={notif.description}
|
|
63
|
+
type={notif.type}
|
|
64
|
+
duration={notif.duration}
|
|
65
|
+
onClose={() => removeNotification(notif.key)}
|
|
66
|
+
/>
|
|
67
|
+
))}
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function NotificationItem ({ message, description, type, onClose, duration = 18.5 }) {
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (duration > 0) {
|
|
75
|
+
const timer = setTimeout(onClose, duration * 1000)
|
|
76
|
+
return () => clearTimeout(timer)
|
|
77
|
+
}
|
|
78
|
+
}, [duration, onClose])
|
|
79
|
+
|
|
80
|
+
const className = classnames('notification', type)
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div className={className}>
|
|
84
|
+
<div className='notification-content'>
|
|
85
|
+
<div className='notification-message'>
|
|
86
|
+
<div className='notification-icon'>{messageIcons[type]}</div>
|
|
87
|
+
<div className='notification-title' title={message}>{message}</div>
|
|
88
|
+
</div>
|
|
89
|
+
{description && <div className='notification-description'>{description}</div>}
|
|
90
|
+
</div>
|
|
91
|
+
<CloseOutlined className='notification-close' onClick={onClose} />
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.notification-container
|
|
2
|
+
position fixed
|
|
3
|
+
bottom 20px
|
|
4
|
+
right 20px
|
|
5
|
+
z-index 1000
|
|
6
|
+
|
|
7
|
+
.notification
|
|
8
|
+
background var(--main-lighter)
|
|
9
|
+
color var(--text)
|
|
10
|
+
border-radius 4px
|
|
11
|
+
margin-bottom 10px
|
|
12
|
+
padding 12px 16px
|
|
13
|
+
box-shadow 0 4px 12px rgba(0, 0, 0, 0.15)
|
|
14
|
+
width 400px
|
|
15
|
+
position relative
|
|
16
|
+
|
|
17
|
+
.notification-content
|
|
18
|
+
width 100%
|
|
19
|
+
|
|
20
|
+
.notification-message
|
|
21
|
+
font-weight bold
|
|
22
|
+
margin-bottom 10px
|
|
23
|
+
.notification-title
|
|
24
|
+
overflow hidden
|
|
25
|
+
text-overflow ellipsis
|
|
26
|
+
white-space nowrap
|
|
27
|
+
padding 0 30px 0 20px
|
|
28
|
+
|
|
29
|
+
.notification-icon
|
|
30
|
+
font-size 16px
|
|
31
|
+
position absolute
|
|
32
|
+
left 12px
|
|
33
|
+
top 10px
|
|
34
|
+
|
|
35
|
+
.notification-description
|
|
36
|
+
word-wrap break-all
|
|
37
|
+
max-height 200px
|
|
38
|
+
overflow auto
|
|
39
|
+
|
|
40
|
+
.notification-close
|
|
41
|
+
position absolute
|
|
42
|
+
top 12px
|
|
43
|
+
right 12px
|
|
44
|
+
background none
|
|
45
|
+
border none
|
|
46
|
+
color var(--text-dark)
|
|
47
|
+
font-size 18px
|
|
48
|
+
cursor pointer
|
|
49
|
+
padding 0
|
|
50
|
+
&:hover
|
|
51
|
+
color var(--text)
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { useEffect } from 'react'
|
|
2
2
|
import ConnectionHoppingWarningText from '../common/connection-hopping-warning-text'
|
|
3
|
-
import {
|
|
4
|
-
notification
|
|
5
|
-
} from 'antd'
|
|
3
|
+
import { notification } from '../common/notification'
|
|
6
4
|
import * as ls from '../../common/safe-local-storage'
|
|
7
5
|
import {
|
|
8
6
|
connectionHoppingWarnKey
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
import { FrownOutlined, ReloadOutlined } from '@ant-design/icons'
|
|
3
|
-
import { Button
|
|
3
|
+
import { Button } from 'antd'
|
|
4
|
+
import message from '../common/message'
|
|
4
5
|
import {
|
|
5
6
|
logoPath1,
|
|
6
7
|
packInfo,
|
|
@@ -41,7 +42,7 @@ export default class ErrorBoundary extends React.PureComponent {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
componentDidCatch (error) {
|
|
44
|
-
|
|
45
|
+
console.error(error)
|
|
45
46
|
this.setState({
|
|
46
47
|
hasError: true,
|
|
47
48
|
error
|
|
@@ -6,7 +6,7 @@ import UpdateCheck from './upgrade'
|
|
|
6
6
|
import SettingModal from '../setting-panel/setting-modal'
|
|
7
7
|
import TextEditor from '../text-editor/text-editor'
|
|
8
8
|
import Sidebar from '../sidebar'
|
|
9
|
-
import BatchOp from '../batch-op/batch-op
|
|
9
|
+
import BatchOp from '../batch-op/batch-op'
|
|
10
10
|
import CssOverwrite from '../bg/css-overwrite'
|
|
11
11
|
import UiTheme from './ui-theme'
|
|
12
12
|
import CustomCss from '../bg/custom-css.jsx'
|
|
@@ -21,7 +21,8 @@ import ShortcutControl from '../shortcuts/shortcut-control.jsx'
|
|
|
21
21
|
import { isMac, isWin, textTerminalBgValue } from '../../common/constants'
|
|
22
22
|
import TermFullscreenControl from './term-fullscreen-control'
|
|
23
23
|
import TerminalInfo from '../terminal-info/terminal-info'
|
|
24
|
-
import { ConfigProvider
|
|
24
|
+
import { ConfigProvider } from 'antd'
|
|
25
|
+
import { NotificationContainer } from '../common/notification'
|
|
25
26
|
import InfoModal from '../sidebar/info-modal.jsx'
|
|
26
27
|
import RightSidePanel from '../side-panel-r/side-panel-r'
|
|
27
28
|
import ConnectionHoppingWarning from './connection-hopping-warnning'
|
|
@@ -37,19 +38,10 @@ import deepCopy from 'json-deep-copy'
|
|
|
37
38
|
import './wrapper.styl'
|
|
38
39
|
|
|
39
40
|
function setupGlobalMessageDismiss () {
|
|
40
|
-
document.addEventListener('click', (event) => {
|
|
41
|
-
const messageElement = event.target.closest('.ant-message-notice')
|
|
42
|
-
if (messageElement) {
|
|
43
|
-
message.destroy()
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
41
|
}
|
|
47
42
|
|
|
48
43
|
export default auto(function Index (props) {
|
|
49
44
|
useEffect(() => {
|
|
50
|
-
notification.config({
|
|
51
|
-
placement: 'bottomRight'
|
|
52
|
-
})
|
|
53
45
|
setupGlobalMessageDismiss()
|
|
54
46
|
const { store } = props
|
|
55
47
|
window.addEventListener('resize', store.onResize)
|
|
@@ -307,6 +299,7 @@ export default auto(function Index (props) {
|
|
|
307
299
|
<TerminalCmdSuggestions {...cmdSuggestionsProps} />
|
|
308
300
|
<TransferQueue />
|
|
309
301
|
<WorkspaceSaveModal store={store} />
|
|
302
|
+
<NotificationContainer />
|
|
310
303
|
</div>
|
|
311
304
|
</ConfigProvider>
|
|
312
305
|
)
|
|
@@ -37,9 +37,6 @@ export default class Upgrade extends PureComponent {
|
|
|
37
37
|
if (window.et.isWebApp) {
|
|
38
38
|
return
|
|
39
39
|
}
|
|
40
|
-
setTimeout(() => {
|
|
41
|
-
getLatestReleaseVersion(1)
|
|
42
|
-
}, 5000)
|
|
43
40
|
this.id = 'upgrade'
|
|
44
41
|
refsStatic.add(this.id, this)
|
|
45
42
|
}
|
|
@@ -119,7 +116,12 @@ export default class Upgrade extends PureComponent {
|
|
|
119
116
|
return window.store.addTab(
|
|
120
117
|
{
|
|
121
118
|
...newTerm(undefined, true),
|
|
122
|
-
|
|
119
|
+
runScripts: [
|
|
120
|
+
{
|
|
121
|
+
script: 'npm install -g electerm',
|
|
122
|
+
delay: 500
|
|
123
|
+
}
|
|
124
|
+
]
|
|
123
125
|
}
|
|
124
126
|
)
|
|
125
127
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
Form,
|
|
4
|
-
message,
|
|
5
4
|
Switch,
|
|
6
5
|
Button
|
|
7
6
|
} from 'antd'
|
|
7
|
+
import message from '../common/message'
|
|
8
8
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
9
9
|
import { formItemLayout } from '../../common/form-layout'
|
|
10
10
|
import HelpIcon from '../common/help-icon'
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { useState, useRef } from 'react'
|
|
6
|
-
import { quickCommandLabelsLsKey } from '../../common/constants'
|
|
6
|
+
import { quickCommandLabelsLsKey, pinnedQuickCommandBarKey } from '../../common/constants'
|
|
7
7
|
import { sortBy } from 'lodash-es'
|
|
8
8
|
import { Button, Input, Select, Space, Flex } from 'antd'
|
|
9
9
|
import * as ls from '../../common/safe-local-storage'
|
|
@@ -41,7 +41,9 @@ export default function QuickCommandsFooterBox (props) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
function handleTogglePinned () {
|
|
44
|
-
|
|
44
|
+
const current = !window.store.pinnedQuickCommandBar
|
|
45
|
+
ls.setItem(pinnedQuickCommandBarKey, current ? 'y' : 'n')
|
|
46
|
+
window.store.pinnedQuickCommandBar = current
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
async function handleSelect (id) {
|
|
@@ -56,6 +58,7 @@ export default function QuickCommandsFooterBox (props) {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
function handleClose () {
|
|
61
|
+
ls.setItem(pinnedQuickCommandBarKey, 'n')
|
|
59
62
|
window.store.pinnedQuickCommandBar = false
|
|
60
63
|
window.store.openQuickCommandBar = false
|
|
61
64
|
}
|
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
Button,
|
|
3
3
|
Switch,
|
|
4
4
|
Form,
|
|
5
|
-
message,
|
|
6
5
|
Select,
|
|
7
6
|
Input
|
|
8
7
|
} from 'antd'
|
|
8
|
+
import message from '../common/message'
|
|
9
9
|
import { useState } from 'react'
|
|
10
10
|
import generate from '../../common/uid'
|
|
11
11
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
statusMap
|
|
8
8
|
} from '../../common/constants'
|
|
9
9
|
import {
|
|
10
|
-
notification,
|
|
11
10
|
Spin,
|
|
12
11
|
// Button,
|
|
13
12
|
Select
|
|
14
13
|
} from 'antd'
|
|
14
|
+
import { notification } from '../common/notification'
|
|
15
15
|
import {
|
|
16
16
|
ReloadOutlined,
|
|
17
17
|
EditOutlined
|
|
@@ -246,7 +246,7 @@ export default class RdpSession extends PureComponent {
|
|
|
246
246
|
|
|
247
247
|
onerrorSocket = err => {
|
|
248
248
|
this.setStatus(statusMap.error)
|
|
249
|
-
|
|
249
|
+
console.error('socket error', err)
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
closeMsg = () => {
|
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
} from '@ant-design/icons'
|
|
18
18
|
import {
|
|
19
19
|
Tooltip,
|
|
20
|
-
message,
|
|
21
20
|
Splitter
|
|
22
21
|
} from 'antd'
|
|
23
22
|
import { pick } from 'lodash-es'
|
|
@@ -206,13 +205,9 @@ export default class SessionWrapper extends Component {
|
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
toggleCheckSftpPathFollowSsh = () => {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
this.setState({
|
|
214
|
-
sftpPathFollowSsh: nv
|
|
215
|
-
})
|
|
208
|
+
this.setState(prevState => ({
|
|
209
|
+
sftpPathFollowSsh: !prevState.sftpPathFollowSsh
|
|
210
|
+
}))
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
editTab = (up) => {
|
|
@@ -660,7 +655,7 @@ export default class SessionWrapper extends Component {
|
|
|
660
655
|
const termType = tab?.type
|
|
661
656
|
const isSsh = tab.authType
|
|
662
657
|
const isLocal = !isSsh && (termType === connectionMap.local || !termType)
|
|
663
|
-
const checkTxt = e('sftpPathFollowSsh')
|
|
658
|
+
const checkTxt = e('sftpPathFollowSsh')
|
|
664
659
|
const checkProps = {
|
|
665
660
|
onClick: this.toggleCheckSftpPathFollowSsh,
|
|
666
661
|
className: classnames(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react'
|
|
2
|
-
import { Button,
|
|
2
|
+
import { Button, Tooltip, Tag, Space } from 'antd'
|
|
3
|
+
import message from '../common/message'
|
|
3
4
|
import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons'
|
|
4
5
|
|
|
5
6
|
const e = window.translate
|
|
@@ -64,12 +65,12 @@ export default function DeepLinkControl () {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
const renderTooltipContent = () => {
|
|
67
|
-
const protocols = ['ssh', 'telnet'
|
|
68
|
+
const protocols = ['ssh', 'telnet']
|
|
68
69
|
|
|
69
70
|
return (
|
|
70
71
|
<div>
|
|
71
72
|
<div className='pd1b'>
|
|
72
|
-
Register electerm to handle protocol URLs (ssh://, telnet
|
|
73
|
+
Register electerm to handle protocol URLs (ssh://, telnet://)
|
|
73
74
|
</div>
|
|
74
75
|
|
|
75
76
|
{registrationStatus && (
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Input } from 'antd'
|
|
2
|
+
import { CheckOutlined, CloseOutlined } from '@ant-design/icons'
|
|
3
|
+
import { useState, useEffect } from 'react'
|
|
4
|
+
|
|
5
|
+
export default function KeywordInput (props) {
|
|
6
|
+
const { value, onChange, addonBefore, ...rest } = props
|
|
7
|
+
const [localValue, setLocalValue] = useState(value || '')
|
|
8
|
+
const [isEditing, setIsEditing] = useState(false)
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setLocalValue(value || '')
|
|
12
|
+
}, [value])
|
|
13
|
+
|
|
14
|
+
function handleChange (e) {
|
|
15
|
+
const newValue = e.target.value
|
|
16
|
+
setLocalValue(newValue)
|
|
17
|
+
setIsEditing(true)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function handleConfirm () {
|
|
21
|
+
onChange(localValue)
|
|
22
|
+
setIsEditing(false)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function handleCancel () {
|
|
26
|
+
setLocalValue(value || '')
|
|
27
|
+
setIsEditing(false)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function handleBlur () {
|
|
31
|
+
// Optionally hide icons on blur, but since user might click icons, maybe not
|
|
32
|
+
// setIsEditing(false)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const addonAfter = isEditing
|
|
36
|
+
? (
|
|
37
|
+
<div>
|
|
38
|
+
<CheckOutlined
|
|
39
|
+
onClick={handleConfirm}
|
|
40
|
+
className='mg1r pointer'
|
|
41
|
+
/>
|
|
42
|
+
<CloseOutlined
|
|
43
|
+
onClick={handleCancel}
|
|
44
|
+
className='pointer'
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
: null
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Input
|
|
52
|
+
value={localValue}
|
|
53
|
+
onChange={handleChange}
|
|
54
|
+
onBlur={handleBlur}
|
|
55
|
+
addonBefore={addonBefore}
|
|
56
|
+
addonAfter={addonAfter}
|
|
57
|
+
{...rest}
|
|
58
|
+
/>
|
|
59
|
+
)
|
|
60
|
+
}
|