@electerm/electerm-react 3.8.15 → 3.9.15
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/pre.js +0 -1
- package/client/components/bookmark-form/bookmark-from-history-modal.jsx +0 -1
- package/client/components/bookmark-form/config/rdp.js +4 -2
- package/client/components/icons/heartbeat.jsx +23 -0
- package/client/components/main/main.jsx +3 -1
- package/client/components/session/session.jsx +3 -3
- package/client/components/setting-sync/setting-sync-form.jsx +9 -1
- package/client/components/setting-sync/setting-sync.jsx +2 -1
- package/client/components/sftp/list-table-ui.jsx +33 -54
- package/client/components/sftp/paged-list.jsx +44 -44
- package/client/components/sftp/sftp-entry.jsx +5 -4
- package/client/components/sidebar/info-modal.jsx +8 -2
- package/client/components/tabs/tab.jsx +38 -19
- package/client/components/tabs/tabs.styl +8 -17
- package/client/components/terminal/attach-addon-custom.js +7 -3
- package/client/components/terminal/reconnect-overlay.jsx +2 -15
- package/client/components/terminal/terminal-command-dropdown.jsx +1 -1
- package/client/components/terminal/terminal-error-handle.jsx +43 -0
- package/client/components/terminal/terminal.jsx +40 -38
- package/client/components/terminal/terminal.styl +12 -7
- package/client/components/terminal/unix-timestamp-tooltip.jsx +85 -0
- package/client/components/text-editor/edit-with-custom-editor.jsx +22 -3
- package/client/components/text-editor/text-editor.jsx +21 -0
- package/client/components/tree-list/bookmark-toolbar.jsx +5 -5
- package/client/components/tree-list/tree-list-item.jsx +6 -12
- package/client/components/tree-list/tree-list-row.jsx +5 -0
- package/client/components/tree-list/tree-list-rows.js +3 -1
- package/client/components/widgets/widget-control.jsx +1 -0
- package/client/store/common.js +1 -1
- package/client/store/load-data.js +2 -2
- package/client/store/mcp-handler.js +83 -10
- package/client/store/sync.js +3 -2
- package/client/store/tab.js +34 -0
- package/package.json +1 -1
- package/client/components/terminal/socket-close-warning.jsx +0 -94
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
import { memo } from 'react'
|
|
2
|
-
import { Button } from 'antd'
|
|
3
|
-
import { LoadingOutlined } from '@ant-design/icons'
|
|
4
2
|
|
|
5
3
|
const e = window.translate
|
|
6
4
|
|
|
7
|
-
export default memo(function ReconnectOverlay ({ countdown
|
|
5
|
+
export default memo(function ReconnectOverlay ({ countdown }) {
|
|
8
6
|
if (countdown === null || countdown === undefined) {
|
|
9
7
|
return null
|
|
10
8
|
}
|
|
11
9
|
return (
|
|
12
10
|
<div className='terminal-reconnect-overlay'>
|
|
13
|
-
|
|
14
|
-
<LoadingOutlined className='terminal-reconnect-icon' />
|
|
15
|
-
<div className='terminal-reconnect-msg'>
|
|
16
|
-
{e('autoReconnectTerminal')}: {countdown}s
|
|
17
|
-
</div>
|
|
18
|
-
<Button
|
|
19
|
-
size='small'
|
|
20
|
-
onClick={onCancel}
|
|
21
|
-
>
|
|
22
|
-
{e('cancel')}
|
|
23
|
-
</Button>
|
|
24
|
-
</div>
|
|
11
|
+
{e('autoReconnectTerminal')}: {countdown}s
|
|
25
12
|
</div>
|
|
26
13
|
)
|
|
27
14
|
})
|
|
@@ -278,7 +278,7 @@ export default class TerminalCmdSuggestions extends Component {
|
|
|
278
278
|
id: uid(),
|
|
279
279
|
command: b.password,
|
|
280
280
|
type: 'PW',
|
|
281
|
-
hint: [b.username, b.host].filter(Boolean).join('@')
|
|
281
|
+
hint: [b.username, [b.host, b.port].filter(Boolean).join(':')].filter(Boolean).join('@')
|
|
282
282
|
})
|
|
283
283
|
}
|
|
284
284
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { memo } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Alert
|
|
5
|
+
} from 'antd'
|
|
6
|
+
|
|
7
|
+
const e = window.translate
|
|
8
|
+
|
|
9
|
+
export default memo(function TerminalErrorHandle ({
|
|
10
|
+
errorMessage,
|
|
11
|
+
showEditBookmarkButton,
|
|
12
|
+
onEditBookmark
|
|
13
|
+
}) {
|
|
14
|
+
if (!errorMessage) {
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function renderEditBookmarkButton () {
|
|
19
|
+
if (!showEditBookmarkButton) {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
return (
|
|
23
|
+
<div className='terminal-error-actions pd1y'>
|
|
24
|
+
<Button
|
|
25
|
+
onClick={onEditBookmark}
|
|
26
|
+
>
|
|
27
|
+
{e('edit')} {e('bookmarks')}
|
|
28
|
+
</Button>
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Alert
|
|
35
|
+
className='terminal-error-handle'
|
|
36
|
+
message={errorMessage}
|
|
37
|
+
type='error'
|
|
38
|
+
showIcon
|
|
39
|
+
banner
|
|
40
|
+
description={renderEditBookmarkButton()}
|
|
41
|
+
/>
|
|
42
|
+
)
|
|
43
|
+
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Component, createRef } from 'react'
|
|
2
|
-
import { handleErr } from '../../common/fetch.jsx'
|
|
3
2
|
import { isEqual, pick, debounce, throttle } from 'lodash-es'
|
|
4
3
|
import clone from '../../common/to-simple-obj.js'
|
|
5
4
|
import resolve from '../../common/resolve.js'
|
|
@@ -7,7 +6,6 @@ import {
|
|
|
7
6
|
Spin,
|
|
8
7
|
Dropdown
|
|
9
8
|
} from 'antd'
|
|
10
|
-
import { notification } from '../common/notification'
|
|
11
9
|
import message from '../common/message'
|
|
12
10
|
import Modal from '../common/modal'
|
|
13
11
|
import classnames from 'classnames'
|
|
@@ -48,8 +46,8 @@ import ExternalLink from '../common/external-link.jsx'
|
|
|
48
46
|
import createDefaultLogPath from '../../common/default-log-path.js'
|
|
49
47
|
import SearchResultBar from './terminal-search-bar'
|
|
50
48
|
import RemoteFloatControl from '../common/remote-float-control'
|
|
51
|
-
import { showSocketCloseWarning } from './socket-close-warning.jsx'
|
|
52
49
|
import ReconnectOverlay from './reconnect-overlay.jsx'
|
|
50
|
+
import TerminalErrorHandle from './terminal-error-handle.jsx'
|
|
53
51
|
import {
|
|
54
52
|
loadTerminal,
|
|
55
53
|
loadFitAddon,
|
|
@@ -78,6 +76,7 @@ class Term extends Component {
|
|
|
78
76
|
matchIndex: -1,
|
|
79
77
|
totalLines: 0,
|
|
80
78
|
reconnectCountdown: null,
|
|
79
|
+
terminalError: null,
|
|
81
80
|
dropFileModalVisible: false,
|
|
82
81
|
droppedFiles: []
|
|
83
82
|
}
|
|
@@ -169,11 +168,6 @@ class Term extends Component {
|
|
|
169
168
|
this.fitAddon = null
|
|
170
169
|
this.cmdAddon = null
|
|
171
170
|
this.imageAddon = null
|
|
172
|
-
// Clear the notification if it exists
|
|
173
|
-
if (this.socketCloseWarning) {
|
|
174
|
-
notification.destroy(this.socketCloseWarning.key)
|
|
175
|
-
this.socketCloseWarning = null
|
|
176
|
-
}
|
|
177
171
|
}
|
|
178
172
|
|
|
179
173
|
terminalConfigProps = [
|
|
@@ -836,6 +830,7 @@ class Term extends Component {
|
|
|
836
830
|
}
|
|
837
831
|
|
|
838
832
|
onPasswordPromptDetected = () => {
|
|
833
|
+
window.store.notifyTabPasswordPrompt(this.props.tab.id)
|
|
839
834
|
if (!this.props.config.showCmdSuggestions) {
|
|
840
835
|
return
|
|
841
836
|
}
|
|
@@ -848,6 +843,7 @@ class Term extends Component {
|
|
|
848
843
|
}
|
|
849
844
|
|
|
850
845
|
onPasswordPromptCancelled = () => {
|
|
846
|
+
window.store.clearTabPasswordPrompt(this.props.tab.id)
|
|
851
847
|
const suggestions = refsStatic.get('terminal-suggestions')
|
|
852
848
|
if (suggestions?.state?.passwordMode) {
|
|
853
849
|
suggestions.closeSuggestions()
|
|
@@ -958,9 +954,10 @@ class Term extends Component {
|
|
|
958
954
|
}
|
|
959
955
|
|
|
960
956
|
onSelectionChange = () => {
|
|
961
|
-
this.
|
|
962
|
-
|
|
963
|
-
})
|
|
957
|
+
const hasSelection = this.term.hasSelection()
|
|
958
|
+
const txt = hasSelection ? this.term.getSelection().trim() : ''
|
|
959
|
+
this.setState({ hasSelection })
|
|
960
|
+
refsStatic.get('unix-timestamp-tooltip')?.onSelection(txt)
|
|
964
961
|
}
|
|
965
962
|
|
|
966
963
|
// setActive = () => {
|
|
@@ -1170,7 +1167,8 @@ class Term extends Component {
|
|
|
1170
1167
|
|
|
1171
1168
|
remoteInit = async (term = this.term) => {
|
|
1172
1169
|
this.setState({
|
|
1173
|
-
loading: true
|
|
1170
|
+
loading: true,
|
|
1171
|
+
terminalError: null
|
|
1174
1172
|
})
|
|
1175
1173
|
const { cols, rows } = term
|
|
1176
1174
|
const { config } = this.props
|
|
@@ -1248,7 +1246,7 @@ class Term extends Component {
|
|
|
1248
1246
|
.catch(err => {
|
|
1249
1247
|
if (!isAutoReconnect) {
|
|
1250
1248
|
const text = err.message
|
|
1251
|
-
|
|
1249
|
+
this.handleError({ message: text, from, srcId })
|
|
1252
1250
|
}
|
|
1253
1251
|
})
|
|
1254
1252
|
if (typeof r === 'string' && r.includes('fail')) {
|
|
@@ -1304,6 +1302,29 @@ class Term extends Component {
|
|
|
1304
1302
|
)
|
|
1305
1303
|
}
|
|
1306
1304
|
|
|
1305
|
+
handleError = ({ message: errorMessage, from, srcId }) => {
|
|
1306
|
+
this.setState({
|
|
1307
|
+
terminalError: {
|
|
1308
|
+
message: errorMessage || 'Failed to create terminal session',
|
|
1309
|
+
from,
|
|
1310
|
+
srcId
|
|
1311
|
+
}
|
|
1312
|
+
})
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
handleEditBookmarkFromError = () => {
|
|
1316
|
+
const error = this.state.terminalError
|
|
1317
|
+
if (!error || error.from !== 'bookmarks' || !error.srcId) {
|
|
1318
|
+
return
|
|
1319
|
+
}
|
|
1320
|
+
const item = window.store.bookmarksMap?.get(error.srcId) ||
|
|
1321
|
+
window.store.bookmarks?.find(d => d.id === error.srcId)
|
|
1322
|
+
if (!item) {
|
|
1323
|
+
return
|
|
1324
|
+
}
|
|
1325
|
+
window.store.openBookmarkEdit(item)
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1307
1328
|
initSocketEvents = () => {
|
|
1308
1329
|
const originalSend = this.socket.send
|
|
1309
1330
|
this.socket.send = (data) => {
|
|
@@ -1369,31 +1390,8 @@ class Term extends Component {
|
|
|
1369
1390
|
return this.props.delTab(this.props.tab.id)
|
|
1370
1391
|
}
|
|
1371
1392
|
const { autoReconnectTerminal } = this.props.config
|
|
1372
|
-
const isActive = this.isActiveTerminal()
|
|
1373
|
-
const isFocused = window.focused
|
|
1374
1393
|
if (autoReconnectTerminal) {
|
|
1375
|
-
|
|
1376
|
-
this.socketCloseWarning = showSocketCloseWarning({
|
|
1377
|
-
tabId: this.props.tab.id,
|
|
1378
|
-
tab: this.props.tab,
|
|
1379
|
-
autoReconnect: true,
|
|
1380
|
-
delTab: this.props.delTab,
|
|
1381
|
-
reloadTab: this.props.reloadTab
|
|
1382
|
-
})
|
|
1383
|
-
} else {
|
|
1384
|
-
this.scheduleAutoReconnect(3000)
|
|
1385
|
-
}
|
|
1386
|
-
} else {
|
|
1387
|
-
if (!isActive || !isFocused) {
|
|
1388
|
-
return false
|
|
1389
|
-
}
|
|
1390
|
-
this.socketCloseWarning = showSocketCloseWarning({
|
|
1391
|
-
tabId: this.props.tab.id,
|
|
1392
|
-
tab: this.props.tab,
|
|
1393
|
-
autoReconnect: false,
|
|
1394
|
-
delTab: this.props.delTab,
|
|
1395
|
-
reloadTab: this.props.reloadTab
|
|
1396
|
-
})
|
|
1394
|
+
this.scheduleAutoReconnect(3000)
|
|
1397
1395
|
}
|
|
1398
1396
|
}
|
|
1399
1397
|
|
|
@@ -1547,9 +1545,13 @@ class Term extends Component {
|
|
|
1547
1545
|
<RemoteFloatControl
|
|
1548
1546
|
isFullScreen={fullscreen}
|
|
1549
1547
|
/>
|
|
1548
|
+
<TerminalErrorHandle
|
|
1549
|
+
errorMessage={this.state.terminalError?.message}
|
|
1550
|
+
showEditBookmarkButton={this.state.terminalError?.from === 'bookmarks' && !!this.state.terminalError?.srcId}
|
|
1551
|
+
onEditBookmark={this.handleEditBookmarkFromError}
|
|
1552
|
+
/>
|
|
1550
1553
|
<ReconnectOverlay
|
|
1551
1554
|
countdown={this.state.reconnectCountdown}
|
|
1552
|
-
onCancel={this.handleCancelAutoReconnect}
|
|
1553
1555
|
/>
|
|
1554
1556
|
<DropFileModal
|
|
1555
1557
|
visible={this.state.dropFileModalVisible}
|
|
@@ -153,12 +153,17 @@
|
|
|
153
153
|
|
|
154
154
|
.terminal-reconnect-overlay
|
|
155
155
|
position absolute
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
align-items center
|
|
162
|
-
justify-content center
|
|
156
|
+
bottom 6px
|
|
157
|
+
right 12px
|
|
158
|
+
font-size 11px
|
|
159
|
+
color rgba(255, 255, 255, 0.55)
|
|
160
|
+
pointer-events none
|
|
163
161
|
z-index 110
|
|
164
162
|
|
|
163
|
+
.terminal-error-handle
|
|
164
|
+
position absolute
|
|
165
|
+
left 0
|
|
166
|
+
top 0
|
|
167
|
+
z-index 100
|
|
168
|
+
background var(--main)
|
|
169
|
+
max-width calc(100% - 24px)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global tooltip that detects Unix timestamps in terminal selections
|
|
3
|
+
* and displays their human-readable date/time near the cursor.
|
|
4
|
+
* Registered via refsStatic as 'unix-timestamp-tooltip'.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Component } from 'react'
|
|
8
|
+
import { refsStatic } from '../common/ref'
|
|
9
|
+
|
|
10
|
+
export default class UnixTimestampTooltip extends Component {
|
|
11
|
+
state = {
|
|
12
|
+
visible: false,
|
|
13
|
+
x: 0,
|
|
14
|
+
y: 0,
|
|
15
|
+
text: ''
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_mouseX = 0
|
|
19
|
+
_mouseY = 0
|
|
20
|
+
|
|
21
|
+
componentDidMount () {
|
|
22
|
+
refsStatic.add('unix-timestamp-tooltip', this)
|
|
23
|
+
document.addEventListener('mousemove', this.onMouseMove)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
componentWillUnmount () {
|
|
27
|
+
refsStatic.remove('unix-timestamp-tooltip')
|
|
28
|
+
document.removeEventListener('mousemove', this.onMouseMove)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
detectUnixTimestamp (txt) {
|
|
32
|
+
if (!/^\d+$/.test(txt)) return null
|
|
33
|
+
const num = parseInt(txt, 10)
|
|
34
|
+
// seconds: 9-10 digits, year ~2001-2286
|
|
35
|
+
if ((txt.length === 9 || txt.length === 10) && num >= 946684800 && num <= 32503680000) {
|
|
36
|
+
return new Date(num * 1000).toLocaleString()
|
|
37
|
+
}
|
|
38
|
+
// milliseconds: 13 digits
|
|
39
|
+
if (txt.length === 13 && num >= 946684800000 && num <= 32503680000000) {
|
|
40
|
+
return new Date(num).toLocaleString()
|
|
41
|
+
}
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
onMouseMove = (e) => {
|
|
46
|
+
this._mouseX = e.clientX
|
|
47
|
+
this._mouseY = e.clientY
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
onSelection = (txt) => {
|
|
51
|
+
const ts = this.detectUnixTimestamp(txt)
|
|
52
|
+
if (ts) {
|
|
53
|
+
this.setState({ visible: true, x: this._mouseX, y: this._mouseY, text: ts })
|
|
54
|
+
} else {
|
|
55
|
+
this.setState({ visible: false })
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
render () {
|
|
60
|
+
const { visible, x, y, text } = this.state
|
|
61
|
+
if (!visible) {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
style={{
|
|
67
|
+
position: 'fixed',
|
|
68
|
+
left: x,
|
|
69
|
+
top: y - 36,
|
|
70
|
+
background: 'rgba(0,0,0,0.75)',
|
|
71
|
+
color: '#fff',
|
|
72
|
+
padding: '3px 8px',
|
|
73
|
+
borderRadius: 4,
|
|
74
|
+
fontSize: 12,
|
|
75
|
+
whiteSpace: 'nowrap',
|
|
76
|
+
pointerEvents: 'none',
|
|
77
|
+
transform: 'translateX(-50%)',
|
|
78
|
+
zIndex: 9999
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{text}
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -6,18 +6,30 @@ import { useState } from 'react'
|
|
|
6
6
|
import { Button, Input, Space } from 'antd'
|
|
7
7
|
import { safeGetItem, safeSetItem } from '../../common/safe-local-storage.js'
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
export const CUSTOM_EDITOR_COMMAND_LS_KEY = 'customEditorCommand'
|
|
10
|
+
export const CUSTOM_EDITOR_AUTO_OPEN_LS_KEY = 'customEditorAutoOpen'
|
|
10
11
|
const e = window.translate
|
|
11
12
|
|
|
12
13
|
export default function EditWithCustomEditor ({ loading, editWithCustom }) {
|
|
13
14
|
const [editorCommand, setEditorCommand] = useState(
|
|
14
|
-
() => safeGetItem(
|
|
15
|
+
() => safeGetItem(CUSTOM_EDITOR_COMMAND_LS_KEY) || ''
|
|
15
16
|
)
|
|
17
|
+
const [autoOpen, setAutoOpen] = useState(
|
|
18
|
+
() => safeGetItem(CUSTOM_EDITOR_AUTO_OPEN_LS_KEY) === 'true'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const autoOpenLabel = e('autoOpen')
|
|
16
22
|
|
|
17
23
|
function handleChange (ev) {
|
|
18
24
|
const val = ev.target.value
|
|
19
25
|
setEditorCommand(val)
|
|
20
|
-
safeSetItem(
|
|
26
|
+
safeSetItem(CUSTOM_EDITOR_COMMAND_LS_KEY, val)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function handleToggleAutoOpen () {
|
|
30
|
+
const next = !autoOpen
|
|
31
|
+
setAutoOpen(next)
|
|
32
|
+
safeSetItem(CUSTOM_EDITOR_AUTO_OPEN_LS_KEY, String(next))
|
|
21
33
|
}
|
|
22
34
|
|
|
23
35
|
function handleClick () {
|
|
@@ -45,6 +57,13 @@ export default function EditWithCustomEditor ({ loading, editWithCustom }) {
|
|
|
45
57
|
onChange={handleChange}
|
|
46
58
|
disabled={loading}
|
|
47
59
|
/>
|
|
60
|
+
<Button
|
|
61
|
+
type={autoOpen ? 'primary' : 'default'}
|
|
62
|
+
disabled={loading}
|
|
63
|
+
onClick={handleToggleAutoOpen}
|
|
64
|
+
>
|
|
65
|
+
{autoOpenLabel}: {autoOpen ? 'On' : 'Off'}
|
|
66
|
+
</Button>
|
|
48
67
|
</Space.Compact>
|
|
49
68
|
)
|
|
50
69
|
}
|
|
@@ -4,9 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
import { PureComponent } from 'react'
|
|
6
6
|
import TextEditorForm from './text-editor-form'
|
|
7
|
+
import {
|
|
8
|
+
CUSTOM_EDITOR_AUTO_OPEN_LS_KEY,
|
|
9
|
+
CUSTOM_EDITOR_COMMAND_LS_KEY
|
|
10
|
+
} from './edit-with-custom-editor'
|
|
7
11
|
import { Spin } from 'antd'
|
|
8
12
|
import Modal from '../common/modal'
|
|
9
13
|
import resolve from '../../common/resolve'
|
|
14
|
+
import { safeGetItem } from '../../common/safe-local-storage.js'
|
|
10
15
|
import { refsStatic, refs } from '../common/ref'
|
|
11
16
|
|
|
12
17
|
const e = window.translate
|
|
@@ -69,12 +74,28 @@ export default class TextEditor extends PureComponent {
|
|
|
69
74
|
return
|
|
70
75
|
}
|
|
71
76
|
const text = await fileRef.fetchEditorText(p, type)
|
|
77
|
+
const editorCommand = this.getAutoOpenCustomEditorCommand()
|
|
72
78
|
this.setStateProxy({
|
|
73
79
|
text,
|
|
74
80
|
loading: false
|
|
81
|
+
}, () => {
|
|
82
|
+
if (editorCommand) {
|
|
83
|
+
this.editWithCustom(editorCommand)
|
|
84
|
+
}
|
|
75
85
|
})
|
|
76
86
|
}
|
|
77
87
|
|
|
88
|
+
getAutoOpenCustomEditorCommand = () => {
|
|
89
|
+
if (window.et.isWebApp) {
|
|
90
|
+
return ''
|
|
91
|
+
}
|
|
92
|
+
const autoOpen = safeGetItem(CUSTOM_EDITOR_AUTO_OPEN_LS_KEY) === 'true'
|
|
93
|
+
if (!autoOpen) {
|
|
94
|
+
return ''
|
|
95
|
+
}
|
|
96
|
+
return safeGetItem(CUSTOM_EDITOR_COMMAND_LS_KEY).trim()
|
|
97
|
+
}
|
|
98
|
+
|
|
78
99
|
doSubmit = () => {
|
|
79
100
|
this.handleSubmit({
|
|
80
101
|
text: this.state.text
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
MenuOutlined,
|
|
8
8
|
EditOutlined
|
|
9
9
|
} from '@ant-design/icons'
|
|
10
|
-
import { Button, Space, Dropdown } from 'antd'
|
|
10
|
+
import { Button, Space, Dropdown, Flex } from 'antd'
|
|
11
11
|
import copy from 'json-deep-copy'
|
|
12
12
|
import time from '../../common/time'
|
|
13
13
|
import download from '../../common/download'
|
|
@@ -87,8 +87,8 @@ export default function BookmarkToolbar (props) {
|
|
|
87
87
|
return (
|
|
88
88
|
|
|
89
89
|
<div className='pd1b pd1r'>
|
|
90
|
-
<
|
|
91
|
-
<div
|
|
90
|
+
<Flex justify='space-between' align='center'>
|
|
91
|
+
<div>
|
|
92
92
|
<Space.Compact>
|
|
93
93
|
<Button onClick={onNewBookmark}>
|
|
94
94
|
<BookOutlined className='with-plus' />
|
|
@@ -122,12 +122,12 @@ export default function BookmarkToolbar (props) {
|
|
|
122
122
|
</Button>
|
|
123
123
|
</Space.Compact>
|
|
124
124
|
</div>
|
|
125
|
-
<div
|
|
125
|
+
<div>
|
|
126
126
|
<Dropdown {...ddProps}>
|
|
127
127
|
<MenuOutlined />
|
|
128
128
|
</Dropdown>
|
|
129
129
|
</div>
|
|
130
|
-
</
|
|
130
|
+
</Flex>
|
|
131
131
|
</div>
|
|
132
132
|
)
|
|
133
133
|
}
|
|
@@ -3,17 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { memo } from 'react'
|
|
6
|
-
import
|
|
6
|
+
import { createTitleTag } from '../../common/create-title'
|
|
7
7
|
import classnames from 'classnames'
|
|
8
8
|
import highlight from '../common/highlight'
|
|
9
9
|
import uid from '../../common/uid'
|
|
10
10
|
|
|
11
|
-
function getItemLabel (item, isGroup) {
|
|
12
|
-
return isGroup
|
|
13
|
-
? item?.title || ''
|
|
14
|
-
: createName(item)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
11
|
function areEqual (prevProps, nextProps) {
|
|
18
12
|
const prevSelected = prevProps.selectedItemId === prevProps.item.id
|
|
19
13
|
const nextSelected = nextProps.selectedItemId === nextProps.item.id
|
|
@@ -27,10 +21,10 @@ function areEqual (prevProps, nextProps) {
|
|
|
27
21
|
prevSelected === nextSelected &&
|
|
28
22
|
prevSearchSelected === nextSearchSelected &&
|
|
29
23
|
prevProps.item.id === nextProps.item.id &&
|
|
30
|
-
prevProps.
|
|
31
|
-
prevProps.
|
|
32
|
-
prevProps.
|
|
33
|
-
|
|
24
|
+
prevProps.itemLevel === nextProps.itemLevel &&
|
|
25
|
+
prevProps.itemColor === nextProps.itemColor &&
|
|
26
|
+
prevProps.itemDescription === nextProps.itemDescription &&
|
|
27
|
+
prevProps.itemLabel === nextProps.itemLabel
|
|
34
28
|
}
|
|
35
29
|
|
|
36
30
|
function TreeListItem (props) {
|
|
@@ -87,7 +81,7 @@ function TreeListItem (props) {
|
|
|
87
81
|
: null
|
|
88
82
|
const title = isGroup
|
|
89
83
|
? item.title
|
|
90
|
-
:
|
|
84
|
+
: props.itemLabel
|
|
91
85
|
const titleAll = title + (item.description ? ' - ' + item.description : '')
|
|
92
86
|
const titleHighlight = isGroup
|
|
93
87
|
? item.title || 'no title'
|
|
@@ -2,6 +2,7 @@ import TreeExpander from './tree-expander'
|
|
|
2
2
|
import TreeListItem from './tree-list-item'
|
|
3
3
|
import TreeItemOp from './tree-item-op'
|
|
4
4
|
import { treeLevelIndent } from './tree-list-layout'
|
|
5
|
+
import createName from '../../common/create-title'
|
|
5
6
|
|
|
6
7
|
export default function TreeListRow (props) {
|
|
7
8
|
const {
|
|
@@ -38,6 +39,10 @@ export default function TreeListRow (props) {
|
|
|
38
39
|
item,
|
|
39
40
|
isGroup,
|
|
40
41
|
parentId,
|
|
42
|
+
itemLabel: isGroup ? (item?.title || '') : createName(item),
|
|
43
|
+
itemColor: item?.color,
|
|
44
|
+
itemDescription: item?.description,
|
|
45
|
+
itemLevel: item?.level,
|
|
41
46
|
leftSidebarWidth,
|
|
42
47
|
staticList,
|
|
43
48
|
selectedItemId: activeItemId,
|
|
@@ -26,7 +26,9 @@ export function buildVisibleTreeRows ({
|
|
|
26
26
|
const item = bookmarksMap.get(bookmarkId)
|
|
27
27
|
const matched = Boolean(
|
|
28
28
|
item &&
|
|
29
|
-
(!lowerKeyword ||
|
|
29
|
+
(!lowerKeyword ||
|
|
30
|
+
createName(item).toLowerCase().includes(lowerKeyword) ||
|
|
31
|
+
(item.description || '').toLowerCase().includes(lowerKeyword))
|
|
30
32
|
)
|
|
31
33
|
bookmarkMatchCache.set(bookmarkId, matched)
|
|
32
34
|
return matched
|
|
@@ -55,6 +55,7 @@ export default function WidgetControl ({ formData, widgetInstancesLength }) {
|
|
|
55
55
|
showMsg(msg, 'success', result.serverInfo, 10)
|
|
56
56
|
} catch (err) {
|
|
57
57
|
console.error('Failed to run widget:', err)
|
|
58
|
+
showMsg(`Failed to run widget: ${err.message}`, 'error', null, 10)
|
|
58
59
|
} finally {
|
|
59
60
|
setLoading(false)
|
|
60
61
|
}
|
package/client/store/common.js
CHANGED
|
@@ -298,7 +298,7 @@ export default Store => {
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
Store.prototype.aiConfigMissing = function () {
|
|
301
|
-
return aiConfigsArr.
|
|
301
|
+
return aiConfigsArr.filter(k => k !== 'apiKeyAI' && k !== 'proxyAI').some(k => !window.store.config[k])
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
Store.prototype.clearHistory = function () {
|
|
@@ -100,7 +100,7 @@ export async function addTabFromCommandLine (store, opts) {
|
|
|
100
100
|
(conf.username && conf.host) ||
|
|
101
101
|
conf.fromCmdLine
|
|
102
102
|
) {
|
|
103
|
-
store.
|
|
103
|
+
store.ipcOpenTab(conf)
|
|
104
104
|
} else if (
|
|
105
105
|
options.initFolder &&
|
|
106
106
|
!(store.config.onStartSessions || []).length &&
|
|
@@ -229,7 +229,7 @@ export default (Store) => {
|
|
|
229
229
|
Store.prototype.checkPendingDeepLink = async function () {
|
|
230
230
|
const pending = await window.pre.runGlobalAsync('getPendingDeepLink')
|
|
231
231
|
if (pending) {
|
|
232
|
-
window.store.
|
|
232
|
+
window.store.ipcOpenTab(pending)
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
Store.prototype.parseQuickConnect = function (url) {
|