@electerm/electerm-react 1.60.56 → 1.70.0
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 +1 -0
- package/client/common/default-log-path.js +5 -0
- package/client/common/default-setting.js +3 -1
- package/client/common/find-bookmark-group-id.js +1 -2
- package/client/components/batch-op/batch-op-entry.jsx +13 -0
- package/client/components/bookmark-form/index.jsx +1 -1
- package/client/components/footer/footer-entry.jsx +9 -16
- package/client/components/icons/split-view.jsx +14 -0
- package/client/components/main/main.jsx +9 -10
- package/client/components/session/session.jsx +285 -70
- package/client/components/session/session.styl +2 -0
- package/client/components/setting-panel/on-tree-drop.js +10 -19
- package/client/components/setting-panel/setting-terminal.jsx +94 -20
- package/client/components/setting-panel/tab-settings.jsx +2 -1
- package/client/components/setting-sync/server-data-status.jsx +81 -0
- package/client/components/setting-sync/setting-sync-form.jsx +6 -0
- package/client/components/setting-sync/setting-sync.jsx +8 -5
- package/client/components/sftp/list-table-ui.jsx +13 -15
- package/client/components/sftp/sftp-entry.jsx +4 -22
- package/client/components/shortcuts/shortcut-control.jsx +10 -1
- package/client/components/tabs/tab.jsx +7 -8
- package/client/components/tabs/tabs.styl +3 -0
- package/client/components/terminal/term-search.jsx +2 -1
- package/client/components/terminal/terminal.jsx +26 -8
- package/client/components/terminal-info/base.jsx +9 -4
- package/client/components/tree-list/bookmark-toolbar.jsx +2 -3
- package/client/components/tree-list/tree-list.jsx +4 -7
- package/client/components/tree-list/tree-search.jsx +1 -0
- package/client/store/bookmark-group.js +1 -2
- package/client/store/init-state.js +3 -0
- package/client/store/item.js +1 -2
- package/client/store/load-data.js +1 -1
- package/client/store/setting.js +1 -2
- package/client/store/store.js +13 -15
- package/client/store/sync.js +42 -7
- package/client/store/terminal-theme.js +4 -4
- package/client/store/ui-theme.js +3 -10
- package/client/store/watch.js +6 -0
- package/package.json +1 -1
- package/client/components/main/loading.jsx +0 -25
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import {
|
|
6
6
|
defaultBookmarkGroupId
|
|
7
7
|
} from '../../common/constants'
|
|
8
|
-
import { isEqual,
|
|
8
|
+
import { isEqual, last, remove } from 'lodash-es'
|
|
9
9
|
import copy from 'json-deep-copy'
|
|
10
10
|
import { action } from 'manate'
|
|
11
11
|
|
|
@@ -25,19 +25,15 @@ export default action((info, props) => {
|
|
|
25
25
|
const isSameLevel = fromPosesLevel.length === toPosesLevel.length
|
|
26
26
|
const isSameCat = isEqual(fromPosesLevel, toPosesLevel) && dropToGap
|
|
27
27
|
const { bookmarks, bookmarkGroups } = window.store
|
|
28
|
-
let from = find(
|
|
29
|
-
bookmarks,
|
|
28
|
+
let from = bookmarks.find(
|
|
30
29
|
d => d.id === fromId
|
|
31
|
-
) || find(
|
|
32
|
-
bookmarkGroups,
|
|
30
|
+
) || bookmarkGroups.find(
|
|
33
31
|
d => d.id === fromId
|
|
34
32
|
)
|
|
35
33
|
const fromLeaf = !!from && !from.bookmarkIds
|
|
36
|
-
let to = find(
|
|
37
|
-
bookmarks,
|
|
34
|
+
let to = bookmarks.find(
|
|
38
35
|
d => d.id === toId
|
|
39
|
-
) || find(
|
|
40
|
-
bookmarkGroups,
|
|
36
|
+
) || bookmarkGroups.find(
|
|
41
37
|
d => d.id === toId
|
|
42
38
|
)
|
|
43
39
|
const toLeaf = !!to && !to.bookmarkIds
|
|
@@ -87,12 +83,10 @@ export default action((info, props) => {
|
|
|
87
83
|
let fromGroup = null
|
|
88
84
|
if (fromPoses.length > 2) {
|
|
89
85
|
fromGroup = fromLeaf
|
|
90
|
-
? find(
|
|
91
|
-
bookmarkGroups,
|
|
86
|
+
? bookmarkGroups.find(
|
|
92
87
|
d => (d.bookmarkIds || []).includes(fromId)
|
|
93
88
|
)
|
|
94
|
-
: find(
|
|
95
|
-
bookmarkGroups,
|
|
89
|
+
: bookmarkGroups.find(
|
|
96
90
|
d => (d.bookmarkGroupIds || []).includes(fromId)
|
|
97
91
|
)
|
|
98
92
|
}
|
|
@@ -100,8 +94,7 @@ export default action((info, props) => {
|
|
|
100
94
|
const toFirstLevel = toPoses.length === 2 && dropToGap
|
|
101
95
|
if (!toFirstLevel) {
|
|
102
96
|
toGroup = dropToGap
|
|
103
|
-
? find(
|
|
104
|
-
bookmarkGroups,
|
|
97
|
+
? bookmarkGroups.find(
|
|
105
98
|
d => {
|
|
106
99
|
const arr = toLeaf
|
|
107
100
|
? d.bookmarkIds
|
|
@@ -111,12 +104,10 @@ export default action((info, props) => {
|
|
|
111
104
|
)
|
|
112
105
|
: (
|
|
113
106
|
toLeaf
|
|
114
|
-
? find(
|
|
115
|
-
bookmarkGroups,
|
|
107
|
+
? bookmarkGroups.find(
|
|
116
108
|
d => (d.bookmarkIds || []).includes(toId)
|
|
117
109
|
)
|
|
118
|
-
: find(
|
|
119
|
-
bookmarkGroups,
|
|
110
|
+
: bookmarkGroups.find(
|
|
120
111
|
d => d.id === toId
|
|
121
112
|
)
|
|
122
113
|
)
|
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
InputNumber,
|
|
13
13
|
Button,
|
|
14
14
|
AutoComplete,
|
|
15
|
-
Tooltip
|
|
15
|
+
Tooltip,
|
|
16
|
+
Flex
|
|
16
17
|
} from 'antd'
|
|
17
18
|
import deepCopy from 'json-deep-copy'
|
|
18
19
|
import {
|
|
@@ -24,12 +25,16 @@ import {
|
|
|
24
25
|
import defaultSettings from '../../common/default-setting'
|
|
25
26
|
import ShowItem from '../common/show-item'
|
|
26
27
|
import { osResolve } from '../../common/resolve'
|
|
28
|
+
import { chooseSaveDirectory } from '../../common/choose-save-folder'
|
|
27
29
|
import { isNumber, isNaN } from 'lodash-es'
|
|
28
30
|
import mapper from '../../common/auto-complete-data-mapper'
|
|
29
31
|
import KeywordForm from './keywords-form'
|
|
30
32
|
import Link from '../common/external-link'
|
|
31
33
|
import HelpIcon from '../common/help-icon'
|
|
32
34
|
import KeywordsTransport from './keywords-transport'
|
|
35
|
+
import fs from '../../common/fs'
|
|
36
|
+
import uid from '../../common/uid'
|
|
37
|
+
import createDefaultSessionLogPath from '../../common/default-log-path'
|
|
33
38
|
import './setting.styl'
|
|
34
39
|
|
|
35
40
|
const { Option } = Select
|
|
@@ -111,18 +116,87 @@ export default class SettingTerminal extends Component {
|
|
|
111
116
|
return this.saveConfig(data)
|
|
112
117
|
}
|
|
113
118
|
|
|
114
|
-
renderToggle = (name,
|
|
119
|
+
renderToggle = (name, cls = 'pd2b') => {
|
|
115
120
|
const checked = !!this.props.config[name]
|
|
116
121
|
const txt = e(name)
|
|
117
122
|
return (
|
|
118
|
-
<div className=
|
|
123
|
+
<div className={cls} key={'rt' + name}>
|
|
119
124
|
<Switch
|
|
120
125
|
checked={checked}
|
|
121
126
|
checkedChildren={txt}
|
|
122
127
|
unCheckedChildren={txt}
|
|
123
128
|
onChange={v => this.onChangeValue(v, name)}
|
|
124
129
|
/>
|
|
125
|
-
|
|
130
|
+
</div>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
testFolderPathCanSaveLog = async (path) => {
|
|
135
|
+
try {
|
|
136
|
+
const st = await fs.statCustom(path)
|
|
137
|
+
if (!st.isD) {
|
|
138
|
+
message.error('invalid log folder')
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
const testFile = osResolve(path, uid + '.test.log')
|
|
142
|
+
await fs.touch(testFile)
|
|
143
|
+
await fs.unlink(testFile)
|
|
144
|
+
return true
|
|
145
|
+
} catch (err) {
|
|
146
|
+
message.error('invalid log folder')
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
handleLogChange = (v) => {
|
|
152
|
+
if (v && !this.testFolderPathCanSaveLog(v)) {
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
this.onChangeValue(v, 'sessionLogPath')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
handleChooseFolder = async () => {
|
|
159
|
+
const path = await chooseSaveDirectory()
|
|
160
|
+
if (path) {
|
|
161
|
+
this.handleLogChange(path)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
renderLogPathControl = () => {
|
|
166
|
+
const { config } = this.props
|
|
167
|
+
const { sessionLogPath } = config
|
|
168
|
+
const path = sessionLogPath || createDefaultSessionLogPath()
|
|
169
|
+
const inputProps = {
|
|
170
|
+
value: sessionLogPath,
|
|
171
|
+
placeholder: path,
|
|
172
|
+
onChange: (e) => this.handleLogChange(e.target.value),
|
|
173
|
+
addonAfter: (
|
|
174
|
+
<>
|
|
175
|
+
<Button
|
|
176
|
+
onClick={this.handleChooseFolder}
|
|
177
|
+
className='mg1r'
|
|
178
|
+
size='small'
|
|
179
|
+
>
|
|
180
|
+
{e('chooseFolder')}
|
|
181
|
+
</Button>
|
|
182
|
+
<Button
|
|
183
|
+
size='small'
|
|
184
|
+
onClick={() => this.handleLogChange('')}
|
|
185
|
+
>
|
|
186
|
+
{e('reset')}
|
|
187
|
+
</Button>
|
|
188
|
+
</>
|
|
189
|
+
),
|
|
190
|
+
addonBefore: (
|
|
191
|
+
<>
|
|
192
|
+
<span className='mg1r'>{e('terminalLogPath')}</span>
|
|
193
|
+
<ShowItem to={path} />
|
|
194
|
+
</>
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
return (
|
|
198
|
+
<div className='pd2b'>
|
|
199
|
+
<Input {...inputProps} />
|
|
126
200
|
</div>
|
|
127
201
|
)
|
|
128
202
|
}
|
|
@@ -346,7 +420,7 @@ export default class SettingTerminal extends Component {
|
|
|
346
420
|
}
|
|
347
421
|
}
|
|
348
422
|
return (
|
|
349
|
-
<div className='
|
|
423
|
+
<div className='pd2b'>
|
|
350
424
|
<span className='inline-title mg1r'>{e('cursorStyle')}</span>
|
|
351
425
|
<Select
|
|
352
426
|
{...props}
|
|
@@ -371,9 +445,9 @@ export default class SettingTerminal extends Component {
|
|
|
371
445
|
const { fontFamily } = this.props.config
|
|
372
446
|
const props = {
|
|
373
447
|
mode: 'multiple',
|
|
374
|
-
className: 'font-sel',
|
|
375
448
|
onChange: this.handleChangeFont,
|
|
376
|
-
value: fontFamily.split(/, */g).filter(d => d.trim())
|
|
449
|
+
value: fontFamily.split(/, */g).filter(d => d.trim()),
|
|
450
|
+
style: { width: '100%' }
|
|
377
451
|
}
|
|
378
452
|
return (
|
|
379
453
|
<Select
|
|
@@ -415,7 +489,6 @@ export default class SettingTerminal extends Component {
|
|
|
415
489
|
keywords = [{ color: 'red' }]
|
|
416
490
|
} = this.props.config
|
|
417
491
|
const {
|
|
418
|
-
appPath,
|
|
419
492
|
getThemeConfig
|
|
420
493
|
} = this.props.store
|
|
421
494
|
const ps = {
|
|
@@ -426,9 +499,6 @@ export default class SettingTerminal extends Component {
|
|
|
426
499
|
submit: this.handleSubmitKeywords,
|
|
427
500
|
themeConfig: getThemeConfig()
|
|
428
501
|
}
|
|
429
|
-
const terminalLogPath = appPath
|
|
430
|
-
? osResolve(appPath, 'electerm', 'session_logs')
|
|
431
|
-
: window.et.sessionLogPath
|
|
432
502
|
const tip = (
|
|
433
503
|
<div>
|
|
434
504
|
<span className='mg1r'>{e('supportRegexp')}</span>
|
|
@@ -470,10 +540,10 @@ export default class SettingTerminal extends Component {
|
|
|
470
540
|
}, `${e('default')} ${e('fontSize')}`, 400)
|
|
471
541
|
}
|
|
472
542
|
<div className='pd2b'>
|
|
473
|
-
<
|
|
474
|
-
|
|
475
|
-
this.renderFontFamily()
|
|
476
|
-
|
|
543
|
+
<Flex align='center' gap='middle'>
|
|
544
|
+
<Flex><div className='inline-title'>{e('default')} {e('fontFamily')}</div></Flex>
|
|
545
|
+
<Flex flex='auto'>{this.renderFontFamily()}</Flex>
|
|
546
|
+
</Flex>
|
|
477
547
|
</div>
|
|
478
548
|
<div className='pd2b'>
|
|
479
549
|
<div className='pd1b'>
|
|
@@ -509,9 +579,12 @@ export default class SettingTerminal extends Component {
|
|
|
509
579
|
{
|
|
510
580
|
this.renderCursorStyleSelect()
|
|
511
581
|
}
|
|
512
|
-
{
|
|
513
|
-
|
|
514
|
-
|
|
582
|
+
{
|
|
583
|
+
this.renderLogPathControl()
|
|
584
|
+
}
|
|
585
|
+
{
|
|
586
|
+
this.renderToggle('saveTerminalLogToFile')
|
|
587
|
+
}
|
|
515
588
|
{this.renderToggle('addTimeStampToTermLog')}
|
|
516
589
|
{
|
|
517
590
|
[
|
|
@@ -520,8 +593,9 @@ export default class SettingTerminal extends Component {
|
|
|
520
593
|
'pasteWhenContextMenu',
|
|
521
594
|
'copyWhenSelect',
|
|
522
595
|
'ctrlOrMetaOpenTerminalLink',
|
|
523
|
-
'sftpPathFollowSsh'
|
|
524
|
-
|
|
596
|
+
'sftpPathFollowSsh',
|
|
597
|
+
'sshSftpSplitView'
|
|
598
|
+
].map(d => this.renderToggle(d))
|
|
525
599
|
}
|
|
526
600
|
<div className='pd1b'>{e('terminalBackSpaceMode')}</div>
|
|
527
601
|
<Select
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { LoadingOutlined, ReloadOutlined } from '@ant-design/icons'
|
|
3
|
+
import dayjs from 'dayjs'
|
|
4
|
+
|
|
5
|
+
const e = window.translate
|
|
6
|
+
|
|
7
|
+
export default function ServerDataStatus (props) {
|
|
8
|
+
const { store } = window
|
|
9
|
+
const { type, status } = props
|
|
10
|
+
const [loading, setLoading] = useState(false)
|
|
11
|
+
const token = store.getSyncToken(type)
|
|
12
|
+
const gistId = store.getSyncGistId(type)
|
|
13
|
+
const canSync = token && (gistId || type === 'custom' || type === 'cloud')
|
|
14
|
+
|
|
15
|
+
async function handleReload () {
|
|
16
|
+
setLoading(true)
|
|
17
|
+
await store.previewServerData(type)
|
|
18
|
+
.catch(store.onError)
|
|
19
|
+
setLoading(false)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function renderReloadButton () {
|
|
23
|
+
if (loading) {
|
|
24
|
+
return (
|
|
25
|
+
<LoadingOutlined className='mg1l' />
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
return (
|
|
29
|
+
<ReloadOutlined
|
|
30
|
+
className='pointer mg1l hover-black'
|
|
31
|
+
onClick={handleReload}
|
|
32
|
+
/>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function renderNoCredentials () {
|
|
37
|
+
return (
|
|
38
|
+
<p>
|
|
39
|
+
<span>{e('syncServerDataStatus')}: -</span>
|
|
40
|
+
</p>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function renderNoData () {
|
|
45
|
+
return (
|
|
46
|
+
<p>
|
|
47
|
+
<span>{e('syncServerDataStatus')}: -</span>
|
|
48
|
+
{renderReloadButton()}
|
|
49
|
+
</p>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function renderStatus () {
|
|
54
|
+
const {
|
|
55
|
+
lastSyncTime,
|
|
56
|
+
electermVersion,
|
|
57
|
+
deviceName = 'unknown'
|
|
58
|
+
} = status
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<p>
|
|
62
|
+
<span className='mg1r'>{e('syncServerDataStatus')}:</span>
|
|
63
|
+
<b className='mg1r'>{dayjs(lastSyncTime).format('YYYY-MM-DD HH:mm:ss')}</b>
|
|
64
|
+
<span className='mg1r'>{e('from')}:</span>
|
|
65
|
+
<b className='mg1r'>{deviceName}</b>
|
|
66
|
+
<b className='mg1r'>(v{electermVersion})</b>
|
|
67
|
+
{renderReloadButton()}
|
|
68
|
+
</p>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!canSync) {
|
|
73
|
+
return renderNoCredentials()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!status) {
|
|
77
|
+
return renderNoData()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return renderStatus()
|
|
81
|
+
}
|
|
@@ -14,6 +14,7 @@ import eq from 'fast-deep-equal'
|
|
|
14
14
|
import { syncTokenCreateUrls, syncTypes } from '../../common/constants'
|
|
15
15
|
import './sync.styl'
|
|
16
16
|
import HelpIcon from '../common/help-icon'
|
|
17
|
+
import ServerDataStatus from './server-data-status'
|
|
17
18
|
|
|
18
19
|
const FormItem = Form.Item
|
|
19
20
|
const e = window.translate
|
|
@@ -207,6 +208,10 @@ export default function SyncForm (props) {
|
|
|
207
208
|
</FormItem>
|
|
208
209
|
)
|
|
209
210
|
}
|
|
211
|
+
const sprops = {
|
|
212
|
+
type: syncType,
|
|
213
|
+
status: props.serverStatus
|
|
214
|
+
}
|
|
210
215
|
return (
|
|
211
216
|
<Form
|
|
212
217
|
onFinish={save}
|
|
@@ -280,6 +285,7 @@ export default function SyncForm (props) {
|
|
|
280
285
|
>{e('clear')}
|
|
281
286
|
</Button>
|
|
282
287
|
</p>
|
|
288
|
+
<ServerDataStatus {...sprops} />
|
|
283
289
|
<p>
|
|
284
290
|
{e('lastSyncTime')}: {timeFormatted}
|
|
285
291
|
</p>
|
|
@@ -8,8 +8,10 @@ import { syncTypes, syncDataMaps } from '../../common/constants'
|
|
|
8
8
|
import DataTransport from './data-import'
|
|
9
9
|
import DataSelect from './data-select'
|
|
10
10
|
import { pick } from 'lodash-es'
|
|
11
|
+
import { auto } from 'manate/react'
|
|
12
|
+
import deepCopy from 'json-deep-copy'
|
|
11
13
|
|
|
12
|
-
export default function SyncSettingEntry (props) {
|
|
14
|
+
export default auto(function SyncSettingEntry (props) {
|
|
13
15
|
const handleChange = (key) => {
|
|
14
16
|
window.store.syncType = key
|
|
15
17
|
}
|
|
@@ -29,8 +31,10 @@ export default function SyncSettingEntry (props) {
|
|
|
29
31
|
'isSyncingSetting',
|
|
30
32
|
'isSyncDownload',
|
|
31
33
|
'isSyncUpload',
|
|
32
|
-
'syncType'
|
|
33
|
-
|
|
34
|
+
'syncType',
|
|
35
|
+
'serverStatus'
|
|
36
|
+
]),
|
|
37
|
+
serverStatus: deepCopy(store.syncServerStatus[props.syncType])
|
|
34
38
|
}
|
|
35
39
|
const type = props.syncType
|
|
36
40
|
const formData = {
|
|
@@ -44,7 +48,6 @@ export default function SyncSettingEntry (props) {
|
|
|
44
48
|
return (
|
|
45
49
|
<SyncForm
|
|
46
50
|
{...syncProps}
|
|
47
|
-
syncType={type}
|
|
48
51
|
encrypt={syncSetting.syncEncrypt}
|
|
49
52
|
formData={formData}
|
|
50
53
|
/>
|
|
@@ -86,4 +89,4 @@ export default function SyncSettingEntry (props) {
|
|
|
86
89
|
</Spin>
|
|
87
90
|
</div>
|
|
88
91
|
)
|
|
89
|
-
}
|
|
92
|
+
})
|
|
@@ -4,10 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { Component } from 'react'
|
|
6
6
|
import classnames from 'classnames'
|
|
7
|
-
import { find } from 'lodash-es'
|
|
8
|
-
import {
|
|
9
|
-
sftpControlHeight
|
|
10
|
-
} from '../../common/constants'
|
|
11
7
|
import FileSection from './file-item'
|
|
12
8
|
import PagedList from './paged-list'
|
|
13
9
|
import FileListTableHeader from './file-table-header'
|
|
@@ -125,8 +121,7 @@ export default class FileListTable extends Component {
|
|
|
125
121
|
onClickName = (e) => {
|
|
126
122
|
const id = e.target.getAttribute('data-id')
|
|
127
123
|
const { properties } = this.state
|
|
128
|
-
const propObj = find(
|
|
129
|
-
properties,
|
|
124
|
+
const propObj = properties.find(
|
|
130
125
|
p => p.id === id
|
|
131
126
|
)
|
|
132
127
|
if (!propObj) {
|
|
@@ -280,11 +275,12 @@ export default class FileListTable extends Component {
|
|
|
280
275
|
|
|
281
276
|
render () {
|
|
282
277
|
const { fileList, height, type } = this.props
|
|
283
|
-
const tableHeaderHeight = 30
|
|
278
|
+
// const tableHeaderHeight = 30
|
|
279
|
+
// const sh = sshSftpSplitView ? 0 : 32
|
|
284
280
|
const props = {
|
|
285
281
|
className: 'sftp-table-content overscroll-y relative',
|
|
286
282
|
style: {
|
|
287
|
-
height: height -
|
|
283
|
+
height: height - 42 - 30 - 32 - 90
|
|
288
284
|
},
|
|
289
285
|
draggable: false
|
|
290
286
|
}
|
|
@@ -302,13 +298,15 @@ export default class FileListTable extends Component {
|
|
|
302
298
|
<div
|
|
303
299
|
{...props}
|
|
304
300
|
>
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
301
|
+
<div>
|
|
302
|
+
{this.props.renderEmptyFile(type)}
|
|
303
|
+
{this.renderParent(type)}
|
|
304
|
+
<PagedList
|
|
305
|
+
list={fileList}
|
|
306
|
+
renderItem={this.renderItem}
|
|
307
|
+
hasPager={hasPager}
|
|
308
|
+
/>
|
|
309
|
+
</div>
|
|
312
310
|
</div>
|
|
313
311
|
</div>
|
|
314
312
|
)
|
|
@@ -55,20 +55,6 @@ export default class Sftp extends Component {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
componentDidUpdate (prevProps, prevState) {
|
|
58
|
-
if (
|
|
59
|
-
(
|
|
60
|
-
prevProps.enableSftp !== false &&
|
|
61
|
-
!prevProps.pid &&
|
|
62
|
-
this.props.pid
|
|
63
|
-
) ||
|
|
64
|
-
(
|
|
65
|
-
prevProps.pid &&
|
|
66
|
-
prevProps.enableSftp === false &&
|
|
67
|
-
this.props.enableSftp !== false
|
|
68
|
-
)
|
|
69
|
-
) {
|
|
70
|
-
this.initData(true)
|
|
71
|
-
}
|
|
72
58
|
if (
|
|
73
59
|
this.props.config.autoRefreshWhenSwitchToSftp &&
|
|
74
60
|
prevProps.pane !== this.props.pane &&
|
|
@@ -183,8 +169,9 @@ export default class Sftp extends Component {
|
|
|
183
169
|
}, isEqual)
|
|
184
170
|
|
|
185
171
|
isActive () {
|
|
186
|
-
return this.props.
|
|
187
|
-
this.props.pane === paneMap.fileManager
|
|
172
|
+
return this.props.currentBatchTabId === this.props.tab.id &&
|
|
173
|
+
(this.props.pane === paneMap.fileManager ||
|
|
174
|
+
this.props.pane === paneMap.sftp || this.props.sshSftpSplitView)
|
|
188
175
|
}
|
|
189
176
|
|
|
190
177
|
getCwdLocal = () => {
|
|
@@ -407,7 +394,7 @@ export default class Sftp extends Component {
|
|
|
407
394
|
this[type + 'Dom'].onPaste()
|
|
408
395
|
}
|
|
409
396
|
|
|
410
|
-
initData =
|
|
397
|
+
initData = () => {
|
|
411
398
|
if (this.shouldRenderRemote()) {
|
|
412
399
|
this.initRemoteAll()
|
|
413
400
|
}
|
|
@@ -437,11 +424,6 @@ export default class Sftp extends Component {
|
|
|
437
424
|
window.store.addTransferList(list)
|
|
438
425
|
}
|
|
439
426
|
|
|
440
|
-
computeListHeight = () => {
|
|
441
|
-
const hasTransports = this.state.transports.length
|
|
442
|
-
return this.props.height - 15 - (hasTransports ? 300 : 0)
|
|
443
|
-
}
|
|
444
|
-
|
|
445
427
|
onError = e => {
|
|
446
428
|
window.store.onError(e)
|
|
447
429
|
this.setState({
|
|
@@ -13,6 +13,15 @@ import { refs, refsStatic } from '../common/ref'
|
|
|
13
13
|
import keyControlPressed from '../../common/key-control-pressed'
|
|
14
14
|
import keyPressed from '../../common/key-pressed'
|
|
15
15
|
|
|
16
|
+
function isInputActive () {
|
|
17
|
+
const activeElement = document.activeElement
|
|
18
|
+
return activeElement && (
|
|
19
|
+
activeElement.tagName === 'INPUT' ||
|
|
20
|
+
activeElement.tagName === 'TEXTAREA' ||
|
|
21
|
+
activeElement.isContentEditable
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
class ShortcutControl extends React.PureComponent {
|
|
17
26
|
componentDidMount () {
|
|
18
27
|
const onEvent = this.handleKeyboardEvent.bind(this)
|
|
@@ -39,7 +48,7 @@ class ShortcutControl extends React.PureComponent {
|
|
|
39
48
|
// SFTP shortcuts handler
|
|
40
49
|
handleSftpKeyboardEvent = (e) => {
|
|
41
50
|
const activeSftp = this.getActiveSftp()
|
|
42
|
-
if (!activeSftp || activeSftp.state.onDelete) {
|
|
51
|
+
if (!activeSftp || activeSftp.state.onDelete || isInputActive()) {
|
|
43
52
|
return
|
|
44
53
|
}
|
|
45
54
|
|
|
@@ -30,18 +30,17 @@ const onDragCls = 'ondrag-tab'
|
|
|
30
30
|
const onDragOverCls = 'dragover-tab'
|
|
31
31
|
|
|
32
32
|
class Tab extends Component {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
componentDidMount () {
|
|
33
|
+
constructor (props) {
|
|
34
|
+
super(props)
|
|
35
|
+
this.state = {
|
|
36
|
+
terminalOnData: false
|
|
37
|
+
}
|
|
40
38
|
this.id = 'tab-' + this.props.tab.id
|
|
41
39
|
refs.add(this.id, this)
|
|
42
|
-
window.addEventListener('message', this.onEvent)
|
|
43
40
|
}
|
|
44
41
|
|
|
42
|
+
tabRef = createRef()
|
|
43
|
+
|
|
45
44
|
componentDidUpdate (prevProps) {
|
|
46
45
|
if (this.props.openContextMenu && !prevProps.openContextMenu) {
|
|
47
46
|
this.handleContextMenu()
|
|
@@ -52,6 +52,8 @@
|
|
|
52
52
|
&.active
|
|
53
53
|
color text
|
|
54
54
|
background main
|
|
55
|
+
.tab-count
|
|
56
|
+
opacity 1
|
|
55
57
|
&:hover
|
|
56
58
|
.tab-close
|
|
57
59
|
display block
|
|
@@ -229,6 +231,7 @@
|
|
|
229
231
|
padding 0 4px
|
|
230
232
|
height 20px
|
|
231
233
|
line-height 21px
|
|
234
|
+
opacity 0.8
|
|
232
235
|
.no-session-history
|
|
233
236
|
position absolute
|
|
234
237
|
top 280px
|
|
@@ -191,7 +191,8 @@ export default class TermSearch extends PureComponent {
|
|
|
191
191
|
if (
|
|
192
192
|
!termSearchOpen ||
|
|
193
193
|
!currentTab ||
|
|
194
|
-
currentTab.pane === paneMap.fileManager
|
|
194
|
+
currentTab.pane === paneMap.fileManager ||
|
|
195
|
+
currentTab.pane === paneMap.sftp
|
|
195
196
|
) {
|
|
196
197
|
return null
|
|
197
198
|
}
|