@electerm/electerm-react 2.3.75 → 2.3.100
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/components/bookmark-form/config/common-fields.js +16 -0
- package/client/components/bookmark-form/form-renderer.jsx +1 -1
- package/client/components/sidebar/transfer-history-modal.jsx +8 -2
- package/client/components/sidebar/transfer.styl +8 -1
- package/client/components/tabs/tab.jsx +4 -2
- package/client/components/tabs/tabs.styl +5 -0
- package/client/components/terminal/terminal.jsx +3 -1
- package/client/components/text-editor/simple-editor.jsx +17 -11
- package/client/components/tree-list/bookmark-transport.jsx +4 -4
- package/client/components/tree-list/tree-list-item.jsx +2 -5
- package/client/components/tree-list/tree-list.styl +4 -2
- package/client/store/tab.js +6 -2
- package/package.json +1 -1
|
@@ -43,6 +43,20 @@ export const commonFields = {
|
|
|
43
43
|
label: e('password')
|
|
44
44
|
},
|
|
45
45
|
|
|
46
|
+
loginPrompt: {
|
|
47
|
+
type: 'input',
|
|
48
|
+
name: 'loginPrompt',
|
|
49
|
+
label: e('loginPrompt'),
|
|
50
|
+
props: { placeholder: '/login[: ]*$/i' }
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
passwordPrompt: {
|
|
54
|
+
type: 'input',
|
|
55
|
+
name: 'passwordPrompt',
|
|
56
|
+
label: e('passwordPrompt'),
|
|
57
|
+
props: { placeholder: '/password[: ]*$/i' }
|
|
58
|
+
},
|
|
59
|
+
|
|
46
60
|
port: {
|
|
47
61
|
type: 'number',
|
|
48
62
|
name: 'port',
|
|
@@ -274,6 +288,8 @@ export const telnetAuthFields = [
|
|
|
274
288
|
commonFields.host,
|
|
275
289
|
commonFields.username,
|
|
276
290
|
commonFields.password,
|
|
291
|
+
commonFields.loginPrompt,
|
|
292
|
+
commonFields.passwordPrompt,
|
|
277
293
|
{ type: 'profileItem', name: '__profile__', label: '', profileFilter: d => !isEmpty(d.telnet) },
|
|
278
294
|
commonFields.port,
|
|
279
295
|
commonFields.runScripts,
|
|
@@ -61,7 +61,10 @@ export default memo(function TransferHistoryModal (props) {
|
|
|
61
61
|
dataIndex: 'fromPath',
|
|
62
62
|
key: 'fromPath',
|
|
63
63
|
render: (txt, inst) => {
|
|
64
|
-
|
|
64
|
+
const t = inst.fromPathReal || txt
|
|
65
|
+
return (
|
|
66
|
+
<div className='sftp-file history-file' title={t}>{t}</div>
|
|
67
|
+
)
|
|
65
68
|
},
|
|
66
69
|
sorter: sorterFactory('fromPath')
|
|
67
70
|
}, {
|
|
@@ -69,7 +72,10 @@ export default memo(function TransferHistoryModal (props) {
|
|
|
69
72
|
dataIndex: 'toPath',
|
|
70
73
|
key: 'toPath',
|
|
71
74
|
render: (txt, inst) => {
|
|
72
|
-
|
|
75
|
+
const t = inst.toPathReal || txt
|
|
76
|
+
return (
|
|
77
|
+
<div className='sftp-file history-file' title={t}>{t}</div>
|
|
78
|
+
)
|
|
73
79
|
},
|
|
74
80
|
sorter: sorterFactory('toPath')
|
|
75
81
|
}, {
|
|
@@ -4,4 +4,11 @@
|
|
|
4
4
|
.ant-badge-multiple-words
|
|
5
5
|
padding 0 3px
|
|
6
6
|
.transfer-list-card
|
|
7
|
-
width calc(
|
|
7
|
+
width calc(100vw - 48px)
|
|
8
|
+
.sftp-file
|
|
9
|
+
max-width calc(50vw - 250px)
|
|
10
|
+
overflow hidden
|
|
11
|
+
text-overflow ellipsis
|
|
12
|
+
white-space nowrap
|
|
13
|
+
&.history-file
|
|
14
|
+
max-width calc(50vw - 440px)
|
|
@@ -367,12 +367,14 @@ class Tab extends Component {
|
|
|
367
367
|
if (name) {
|
|
368
368
|
tunnel = `[${name}] ${tunnel}`
|
|
369
369
|
}
|
|
370
|
-
return <div key={tunnel}>{tunnel}</div>
|
|
370
|
+
return <div key={tunnel + '-' + i} className='ssh-tunnel-item'>{tunnel}</div>
|
|
371
371
|
})
|
|
372
372
|
return (
|
|
373
373
|
<>
|
|
374
374
|
<div>{title}</div>
|
|
375
|
-
|
|
375
|
+
<div className='ssh-tunnel-list-wrapper'>
|
|
376
|
+
{list}
|
|
377
|
+
</div>
|
|
376
378
|
</>
|
|
377
379
|
)
|
|
378
380
|
}
|
|
@@ -20,24 +20,32 @@ export default function SimpleEditor (props) {
|
|
|
20
20
|
if (currentMatch >= 0 && occurrences.length > 0) {
|
|
21
21
|
const match = occurrences[currentMatch]
|
|
22
22
|
if (editorRef.current) {
|
|
23
|
+
const textarea = editorRef.current.resizableTextArea.textArea
|
|
24
|
+
|
|
23
25
|
// Set selection range to select the matched text
|
|
24
|
-
|
|
26
|
+
textarea.setSelectionRange(match.start, match.end)
|
|
25
27
|
|
|
26
28
|
// Only focus the textarea when explicitly navigating between matches
|
|
27
29
|
if (isNavigating) {
|
|
28
|
-
|
|
30
|
+
textarea.focus()
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
// Scroll to the selection position
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
// Use setTimeout to ensure the selection is rendered before scrolling
|
|
35
|
+
setTimeout(() => {
|
|
36
|
+
const textBeforeSelection = props.value.substring(0, match.start)
|
|
37
|
+
const lineBreaks = textBeforeSelection.split('\n').length - 1
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
// Estimate the scroll position
|
|
40
|
+
const lineHeight = parseInt(window.getComputedStyle(textarea).lineHeight) || 20
|
|
41
|
+
const scrollPosition = lineHeight * lineBreaks
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
// Scroll to center the match, but ensure we can scroll to the bottom
|
|
44
|
+
const targetScroll = scrollPosition - textarea.clientHeight / 2
|
|
45
|
+
const maxScroll = textarea.scrollHeight - textarea.clientHeight
|
|
46
|
+
|
|
47
|
+
textarea.scrollTop = Math.max(0, Math.min(targetScroll, maxScroll))
|
|
48
|
+
}, 0)
|
|
41
49
|
}
|
|
42
50
|
}
|
|
43
51
|
// Reset navigating flag after using it
|
|
@@ -89,8 +97,6 @@ export default function SimpleEditor (props) {
|
|
|
89
97
|
|
|
90
98
|
function handleChange (e) {
|
|
91
99
|
setSearchKeyword(e.target.value)
|
|
92
|
-
findMatches()
|
|
93
|
-
goToNextMatch()
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
// Navigate to next match
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { PureComponent } from 'react'
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
ExportOutlined,
|
|
8
|
+
ImportOutlined,
|
|
9
9
|
EditOutlined
|
|
10
10
|
} from '@ant-design/icons'
|
|
11
11
|
import { Upload, Button } from 'antd'
|
|
@@ -36,7 +36,7 @@ export default class BookmarkTransport extends PureComponent {
|
|
|
36
36
|
return [
|
|
37
37
|
this.renderEdit(),
|
|
38
38
|
<Button
|
|
39
|
-
icon={<
|
|
39
|
+
icon={<ExportOutlined />}
|
|
40
40
|
onClick={this.handleDownload}
|
|
41
41
|
title={e('export')}
|
|
42
42
|
className='download-bookmark-icon'
|
|
@@ -49,7 +49,7 @@ export default class BookmarkTransport extends PureComponent {
|
|
|
49
49
|
key='Upload'
|
|
50
50
|
>
|
|
51
51
|
<Button
|
|
52
|
-
icon={<
|
|
52
|
+
icon={<ImportOutlined />}
|
|
53
53
|
title={e('importFromFile')}
|
|
54
54
|
/>
|
|
55
55
|
</Upload>
|
|
@@ -188,7 +188,7 @@ export default function TreeListItem (props) {
|
|
|
188
188
|
{
|
|
189
189
|
selected: selectedItemId === item.id
|
|
190
190
|
},
|
|
191
|
-
'tree-item
|
|
191
|
+
'tree-item',
|
|
192
192
|
{
|
|
193
193
|
'is-category': isGroup,
|
|
194
194
|
level2: item.level === 2
|
|
@@ -232,10 +232,7 @@ export default function TreeListItem (props) {
|
|
|
232
232
|
onClick: onSelect,
|
|
233
233
|
'data-item-id': item.id,
|
|
234
234
|
'data-is-group': isGroup ? 'true' : 'false',
|
|
235
|
-
'data-parent-id': props.parentId
|
|
236
|
-
style: props.staticList
|
|
237
|
-
? { maxWidth: (props.leftSidebarWidth - 110) + 'px' }
|
|
238
|
-
: undefined
|
|
235
|
+
'data-parent-id': props.parentId
|
|
239
236
|
}
|
|
240
237
|
const key = item.id || uid()
|
|
241
238
|
return (
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
line-height 26px
|
|
12
12
|
padding-left 5px
|
|
13
13
|
border-radius 3px
|
|
14
|
+
overflow hidden
|
|
15
|
+
white-space nowrap
|
|
16
|
+
text-overflow ellipsis
|
|
14
17
|
&.is-category
|
|
15
18
|
.tree-item-title
|
|
16
19
|
font-weight bold
|
|
@@ -30,13 +33,12 @@
|
|
|
30
33
|
.tree-item-title
|
|
31
34
|
flex-grow 1
|
|
32
35
|
line-height 26px
|
|
33
|
-
max-width 300px
|
|
34
36
|
overflow hidden
|
|
35
37
|
white-space nowrap
|
|
36
38
|
text-overflow ellipsis
|
|
37
39
|
|
|
38
40
|
.sidebar-panel .tree-item-title
|
|
39
|
-
|
|
41
|
+
max-width 100%
|
|
40
42
|
.with-plus
|
|
41
43
|
&:after
|
|
42
44
|
content '+'
|
package/client/store/tab.js
CHANGED
|
@@ -227,9 +227,13 @@ export default Store => {
|
|
|
227
227
|
const removedSet = new Set(removedIds)
|
|
228
228
|
const batchFirstTabs = {}
|
|
229
229
|
const currentIdNeedFix = removedSet.has(store.activeTabId)
|
|
230
|
-
|
|
230
|
+
const copiedTabs = remainingTabs.map(t => ({
|
|
231
|
+
id: t.id,
|
|
232
|
+
batch: t.batch,
|
|
233
|
+
tabCount: t.tabCount
|
|
234
|
+
})).sort((a, b) => b.tabCount - a.tabCount)
|
|
231
235
|
// Get first valid tab for each batch
|
|
232
|
-
for (const tab of
|
|
236
|
+
for (const tab of copiedTabs) {
|
|
233
237
|
if (!batchFirstTabs[tab.batch]) {
|
|
234
238
|
batchFirstTabs[tab.batch] = tab.id
|
|
235
239
|
}
|