@electerm/electerm-react 2.3.198 → 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/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 +2 -1
- 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/terminal-command-dropdown.jsx +3 -0
- package/client/components/terminal/terminal.jsx +165 -103
- 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 -50
- 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
|
@@ -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
|
|
@@ -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
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Form,
|
|
3
|
-
Input,
|
|
4
3
|
Select,
|
|
5
4
|
Space,
|
|
6
5
|
Button
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
PlusOutlined
|
|
12
11
|
} from '@ant-design/icons'
|
|
13
12
|
import { useEffect } from 'react'
|
|
13
|
+
import KeywordInput from './keyword-input'
|
|
14
14
|
|
|
15
15
|
const FormItem = Form.Item
|
|
16
16
|
const FormList = Form.List
|
|
@@ -26,10 +26,6 @@ export default function KeywordForm (props) {
|
|
|
26
26
|
formChild.submit()
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
function handleChange (e) {
|
|
30
|
-
formChild.submit()
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
function handleFinish (data) {
|
|
34
30
|
props.submit(data)
|
|
35
31
|
}
|
|
@@ -59,9 +55,8 @@ export default function KeywordForm (props) {
|
|
|
59
55
|
name={[field.name, 'keyword']}
|
|
60
56
|
rules={[{ validator: checker }]}
|
|
61
57
|
>
|
|
62
|
-
<
|
|
58
|
+
<KeywordInput
|
|
63
59
|
addonBefore={renderBefore(field.name)}
|
|
64
|
-
onChange={handleChange}
|
|
65
60
|
/>
|
|
66
61
|
</FormItem>
|
|
67
62
|
</FormItem>
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { useDelta, useConditionalEffect } from 'react-delta-hooks'
|
|
9
9
|
import { ArrowDownOutlined, ArrowUpOutlined, SaveOutlined, ClearOutlined } from '@ant-design/icons'
|
|
10
|
-
import { Button, Input,
|
|
10
|
+
import { Button, Input, Form, Alert } from 'antd'
|
|
11
|
+
import { notification } from '../common/notification'
|
|
11
12
|
import Link from '../common/external-link'
|
|
12
13
|
import dayjs from 'dayjs'
|
|
13
14
|
import eq from 'fast-deep-equal'
|
|
@@ -15,6 +16,7 @@ import { syncTokenCreateUrls, syncTypes } from '../../common/constants'
|
|
|
15
16
|
import HelpIcon from '../common/help-icon'
|
|
16
17
|
import ServerDataStatus from './server-data-status'
|
|
17
18
|
import Password from '../common/password'
|
|
19
|
+
import { isError } from 'lodash-es'
|
|
18
20
|
|
|
19
21
|
const FormItem = Form.Item
|
|
20
22
|
const e = window.translate
|
|
@@ -58,11 +60,17 @@ export default function SyncForm (props) {
|
|
|
58
60
|
up[syncType + 'ApiUrl'] = 'https://electerm-cloud.html5beta.com/api/sync'
|
|
59
61
|
// up[syncType + 'ApiUrl'] = 'http://127.0.0.1:5678/api/sync'
|
|
60
62
|
}
|
|
63
|
+
if (res.proxy) {
|
|
64
|
+
up[syncType + 'Proxy'] = res.proxy
|
|
65
|
+
} else {
|
|
66
|
+
up[syncType + 'Proxy'] = ''
|
|
67
|
+
}
|
|
61
68
|
window.store.updateSyncSetting(up)
|
|
62
69
|
const test = await window.store.testSyncToken(syncType, res.gistId)
|
|
63
|
-
if (
|
|
70
|
+
if (isError(test)) {
|
|
64
71
|
return notification.error({
|
|
65
|
-
|
|
72
|
+
message: test.message || 'Request failed',
|
|
73
|
+
description: test.stack || 'Request failed'
|
|
66
74
|
})
|
|
67
75
|
}
|
|
68
76
|
if (!res.gistId && syncType !== syncTypes.custom && syncType !== syncTypes.cloud) {
|
|
@@ -136,6 +144,27 @@ export default function SyncForm (props) {
|
|
|
136
144
|
function createId (name) {
|
|
137
145
|
return 'sync-input-' + name + '-' + syncType
|
|
138
146
|
}
|
|
147
|
+
function renderWarning () {
|
|
148
|
+
if (syncType === syncTypes.gitee) {
|
|
149
|
+
return (
|
|
150
|
+
<Alert
|
|
151
|
+
message={
|
|
152
|
+
<span>
|
|
153
|
+
Gitee data sync is not recommended. For more information, please refer to the
|
|
154
|
+
<Link to='https://github.com/electerm/electerm/wiki/gitee-data-sync-warning' className='mg1l'>
|
|
155
|
+
wiki
|
|
156
|
+
</Link>
|
|
157
|
+
.
|
|
158
|
+
</span>
|
|
159
|
+
}
|
|
160
|
+
type='warning'
|
|
161
|
+
showIcon
|
|
162
|
+
className='mg1b'
|
|
163
|
+
/>
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
139
168
|
function createUrlItem () {
|
|
140
169
|
if (syncType === syncTypes.cloud) {
|
|
141
170
|
return (
|
|
@@ -215,6 +244,23 @@ export default function SyncForm (props) {
|
|
|
215
244
|
</FormItem>
|
|
216
245
|
)
|
|
217
246
|
}
|
|
247
|
+
function createProxyItem () {
|
|
248
|
+
return (
|
|
249
|
+
<FormItem
|
|
250
|
+
label='Proxy'
|
|
251
|
+
name='proxy'
|
|
252
|
+
normalize={trim}
|
|
253
|
+
rules={[{
|
|
254
|
+
max: 200, message: '200 chars max'
|
|
255
|
+
}]}
|
|
256
|
+
>
|
|
257
|
+
<Input
|
|
258
|
+
placeholder='socks5://127.0.0.1:1080'
|
|
259
|
+
id={createId('proxy')}
|
|
260
|
+
/>
|
|
261
|
+
</FormItem>
|
|
262
|
+
)
|
|
263
|
+
}
|
|
218
264
|
const sprops = {
|
|
219
265
|
type: syncType,
|
|
220
266
|
status: props.serverStatus
|
|
@@ -228,6 +274,7 @@ export default function SyncForm (props) {
|
|
|
228
274
|
layout='vertical'
|
|
229
275
|
initialValues={props.formData}
|
|
230
276
|
>
|
|
277
|
+
{renderWarning()}
|
|
231
278
|
{createUrlItem()}
|
|
232
279
|
<FormItem
|
|
233
280
|
label={tokenLabel}
|
|
@@ -251,6 +298,9 @@ export default function SyncForm (props) {
|
|
|
251
298
|
{
|
|
252
299
|
createPasswordItem()
|
|
253
300
|
}
|
|
301
|
+
{
|
|
302
|
+
createProxyItem()
|
|
303
|
+
}
|
|
254
304
|
<FormItem>
|
|
255
305
|
<p>
|
|
256
306
|
<Button
|
|
@@ -43,7 +43,8 @@ export default auto(function SyncSettingEntry (props) {
|
|
|
43
43
|
url: syncSetting[type + 'Url'],
|
|
44
44
|
apiUrl: syncSetting[type + 'ApiUrl'],
|
|
45
45
|
lastSyncTime: syncSetting[type + 'LastSyncTime'],
|
|
46
|
-
syncPassword: syncSetting[type + 'SyncPassword']
|
|
46
|
+
syncPassword: syncSetting[type + 'SyncPassword'],
|
|
47
|
+
proxy: syncSetting[type + 'Proxy']
|
|
47
48
|
}
|
|
48
49
|
return (
|
|
49
50
|
<SyncForm
|