@electerm/electerm-react 1.60.16 → 1.60.29
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 -14
- package/client/common/constants.js +0 -43
- package/client/common/data-compare.js +55 -0
- package/client/common/default-setting.js +2 -10
- package/client/common/resolve.js +18 -22
- package/client/common/sftp.js +0 -3
- package/client/components/ai/ai-chat.jsx +30 -6
- package/client/components/ai/ai-config.jsx +17 -6
- package/client/components/batch-op/batch-op.jsx +3 -24
- package/client/components/bookmark-form/bookmark-group-tree-format.js +7 -9
- package/client/components/bookmark-form/form-ssh-common.jsx +0 -2
- package/client/components/bookmark-form/ssh-form.jsx +8 -41
- package/client/components/bookmark-form/tree-delete.jsx +6 -15
- package/client/components/common/animate-text.jsx +3 -4
- package/client/components/common/drag-handle.jsx +59 -45
- package/client/components/common/drag-handle.styl +2 -1
- package/client/components/common/input-auto-focus.jsx +29 -63
- package/client/components/common/ref.js +24 -0
- package/client/components/footer/batch-input.jsx +1 -6
- package/client/components/footer/footer-entry.jsx +13 -16
- package/client/components/footer/footer.styl +0 -5
- package/client/components/icons/ai-icon.jsx +17 -0
- package/client/components/icons/ai-icon.styl +3 -0
- package/client/components/layout/layout-item.jsx +14 -0
- package/client/components/main/main.jsx +8 -19
- package/client/components/main/upgrade.jsx +13 -25
- package/client/components/profile/profile-form-elem.jsx +1 -2
- package/client/components/quick-commands/on-drop.js +1 -12
- package/client/components/quick-commands/quick-command-transport-mod.jsx +3 -13
- package/client/components/quick-commands/quick-commands-form-elem.jsx +1 -2
- package/client/components/rdp/rdp-session.jsx +4 -4
- package/client/components/session/session.jsx +9 -11
- package/client/components/setting-panel/on-tree-drop.js +4 -35
- package/client/components/setting-panel/setting-common.jsx +4 -1
- package/client/components/setting-panel/setting-modal.jsx +7 -5
- package/client/components/setting-panel/tab-settings.jsx +0 -1
- package/client/components/setting-sync/setting-sync.jsx +0 -1
- package/client/components/sftp/address-bookmark-item.jsx +1 -15
- package/client/components/sftp/confirm-modal-store.jsx +2 -2
- package/client/components/sftp/{file-mode-modal.jsx → file-info-modal.jsx} +137 -37
- package/client/components/sftp/file-item.jsx +156 -192
- package/client/components/sftp/file-table-header.jsx +98 -0
- package/client/components/sftp/list-table-ui.jsx +125 -416
- package/client/components/sftp/sftp-entry.jsx +102 -128
- package/client/components/sftp/sftp.styl +6 -22
- package/client/components/sftp/transfer-conflict-store.jsx +8 -12
- package/client/components/sftp/transport-action-store.jsx +7 -15
- package/client/components/shortcuts/shortcut-control.jsx +72 -3
- package/client/components/shortcuts/shortcut-handler.js +0 -1
- package/client/components/side-panel-r/side-panel-r.jsx +7 -4
- package/client/components/sidebar/history.jsx +3 -0
- package/client/components/sidebar/index.jsx +1 -1
- package/client/components/sidebar/info-modal.jsx +3 -0
- package/client/components/sidebar/side-panel.jsx +7 -4
- package/client/components/sidebar/sidebar-panel.jsx +1 -1
- package/client/components/sidebar/sidebar.styl +3 -3
- package/client/components/sys-menu/icons-map.jsx +52 -0
- package/client/components/{context-menu → sys-menu}/menu-btn.jsx +33 -45
- package/client/components/sys-menu/sys-menu.jsx +163 -0
- package/client/components/{context-menu/context-menu.styl → sys-menu/sys-menu.styl} +2 -11
- package/client/components/tabs/index.jsx +5 -97
- package/client/components/tabs/tab.jsx +121 -73
- package/client/components/tabs/tabs.styl +4 -1
- package/client/components/terminal/term-search.jsx +16 -28
- package/client/components/terminal/terminal-interactive.jsx +0 -2
- package/client/components/terminal/{index.jsx → terminal.jsx} +126 -248
- package/client/components/terminal-info/base.jsx +21 -46
- package/client/components/terminal-info/terminal-info.jsx +3 -0
- package/client/components/text-editor/text-editor.jsx +38 -53
- package/client/components/theme/theme-form.jsx +0 -2
- package/client/components/tree-list/bookmark-toolbar.jsx +23 -47
- package/client/components/tree-list/bookmark-transport.jsx +2 -90
- package/client/components/tree-list/move-item-modal.jsx +101 -0
- package/client/components/tree-list/tree-list-item.jsx +6 -8
- package/client/components/tree-list/tree-list.jsx +48 -273
- package/client/components/vnc/vnc-session.jsx +5 -3
- package/client/store/app-upgrade.js +2 -5
- package/client/store/bookmark-group.js +74 -28
- package/client/store/common.js +36 -54
- package/client/store/event.js +4 -37
- package/client/store/init-state.js +9 -12
- package/client/store/item.js +34 -39
- package/client/store/load-data.js +5 -1
- package/client/store/quick-command.js +2 -12
- package/client/store/session.js +6 -7
- package/client/store/setting.js +3 -7
- package/client/store/sidebar.js +2 -8
- package/client/store/store.js +0 -20
- package/client/store/system-menu.js +1 -2
- package/client/store/tab.js +29 -1
- package/client/store/terminal-theme.js +0 -4
- package/client/store/watch.js +26 -4
- package/package.json +1 -1
- package/client/common/post-msg.js +0 -3
- package/client/components/common/native-input.jsx +0 -30
- package/client/components/context-menu/context-menu.jsx +0 -339
- package/client/components/sftp/file-props-modal.jsx +0 -210
- package/client/store/context-menu.js +0 -23
- /package/client/components/{context-menu → sys-menu}/boomarks.jsx +0 -0
- /package/client/components/{context-menu → sys-menu}/history.jsx +0 -0
- /package/client/components/{context-menu → sys-menu}/icon-holder.jsx +0 -0
- /package/client/components/{context-menu → sys-menu}/sub-tab-menu.jsx +0 -0
- /package/client/components/{context-menu → sys-menu}/tabs.jsx +0 -0
- /package/client/components/{context-menu → sys-menu}/zoom.jsx +0 -0
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
import { Component } from 'react'
|
|
2
|
+
import { refs } from '../common/ref'
|
|
2
3
|
import generate from '../../common/uid'
|
|
3
4
|
import runIdle from '../../common/run-idle'
|
|
4
5
|
import { Spin, Modal, notification } from 'antd'
|
|
5
|
-
import {
|
|
6
|
+
import { isEqual, last, isNumber, some, isArray, pick, uniq, debounce } from 'lodash-es'
|
|
6
7
|
import FileSection from './file-item'
|
|
7
8
|
import resolve from '../../common/resolve'
|
|
8
9
|
import wait from '../../common/wait'
|
|
9
10
|
import isAbsPath from '../../common/is-absolute-path'
|
|
10
11
|
import classnames from 'classnames'
|
|
11
12
|
import sorterIndex from '../../common/index-sorter'
|
|
12
|
-
import { getLocalFileInfo, getRemoteFileInfo } from './file-read'
|
|
13
|
+
import { getLocalFileInfo, getRemoteFileInfo, getFolderFromFilePath } from './file-read'
|
|
13
14
|
import {
|
|
14
15
|
typeMap, maxSftpHistory, paneMap,
|
|
15
|
-
eventTypes,
|
|
16
16
|
fileTypeMap,
|
|
17
17
|
terminalSerialType,
|
|
18
18
|
unexpectedPacketErrorDesc,
|
|
19
|
-
sftpRetryInterval
|
|
20
|
-
commonActions
|
|
19
|
+
sftpRetryInterval
|
|
21
20
|
} from '../../common/constants'
|
|
22
21
|
import { hasFileInClipboardText } from '../../common/clipboard'
|
|
23
22
|
import Client from '../../common/sftp'
|
|
24
23
|
import fs from '../../common/fs'
|
|
25
|
-
import keyControlPressed from '../../common/key-control-pressed'
|
|
26
|
-
import keyPressed from '../../common/key-pressed'
|
|
27
24
|
import ListTable from './list-table-ui'
|
|
28
25
|
import deepCopy from 'json-deep-copy'
|
|
29
26
|
import isValidPath from '../../common/is-valid-path'
|
|
30
27
|
import memoizeOne from 'memoize-one'
|
|
31
|
-
import postMessage from '../../common/post-msg'
|
|
32
28
|
import * as owner from './owner-list'
|
|
33
29
|
import AddressBar from './address-bar'
|
|
34
30
|
import getProxy from '../../common/get-proxy'
|
|
@@ -36,15 +32,6 @@ import './sftp.styl'
|
|
|
36
32
|
|
|
37
33
|
const e = window.translate
|
|
38
34
|
|
|
39
|
-
const buildTree = arr => {
|
|
40
|
-
return arr.reduce((prev, curr) => {
|
|
41
|
-
return {
|
|
42
|
-
...prev,
|
|
43
|
-
[curr.id]: curr
|
|
44
|
-
}
|
|
45
|
-
}, {})
|
|
46
|
-
}
|
|
47
|
-
|
|
48
35
|
export default class Sftp extends Component {
|
|
49
36
|
constructor (props) {
|
|
50
37
|
super(props)
|
|
@@ -60,10 +47,12 @@ export default class Sftp extends Component {
|
|
|
60
47
|
this.retryCount = 0
|
|
61
48
|
}
|
|
62
49
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
componentDidMount () {
|
|
51
|
+
this.id = 'sftp-' + this.props.sessionId
|
|
52
|
+
this.tid = 'sftp-' + this.props.tab.id
|
|
53
|
+
refs.add(this.id, this)
|
|
54
|
+
refs.add(this.tid, this)
|
|
55
|
+
}
|
|
67
56
|
|
|
68
57
|
componentDidUpdate (prevProps, prevState) {
|
|
69
58
|
if (
|
|
@@ -78,7 +67,6 @@ export default class Sftp extends Component {
|
|
|
78
67
|
this.props.enableSftp !== false
|
|
79
68
|
)
|
|
80
69
|
) {
|
|
81
|
-
this.initEvent()
|
|
82
70
|
this.initData(true)
|
|
83
71
|
}
|
|
84
72
|
if (
|
|
@@ -114,7 +102,8 @@ export default class Sftp extends Component {
|
|
|
114
102
|
}
|
|
115
103
|
|
|
116
104
|
componentWillUnmount () {
|
|
117
|
-
this.
|
|
105
|
+
refs.remove(this.id)
|
|
106
|
+
refs.remove(this.tid)
|
|
118
107
|
this.sftp && this.sftp.destroy()
|
|
119
108
|
this.sftp = null
|
|
120
109
|
clearTimeout(this.timer4)
|
|
@@ -157,58 +146,41 @@ export default class Sftp extends Component {
|
|
|
157
146
|
sortDirection,
|
|
158
147
|
sortProp
|
|
159
148
|
) => {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const l2 = list.filter(g => g.id && !g.isDirectory)
|
|
163
|
-
const sorter = (a, b) => {
|
|
164
|
-
let va = a[sortProp]
|
|
165
|
-
let vb = b[sortProp]
|
|
166
|
-
if (isString(va)) {
|
|
167
|
-
va = va.toLowerCase()
|
|
168
|
-
vb = vb.toLowerCase()
|
|
169
|
-
}
|
|
170
|
-
if (sortDirection === 'desc') {
|
|
171
|
-
if (isString(va)) {
|
|
172
|
-
return va.localeCompare(vb, { sensitivity: 'base' })
|
|
173
|
-
}
|
|
174
|
-
return va > vb ? -1 : 1
|
|
175
|
-
} else {
|
|
176
|
-
if (isString(va)) {
|
|
177
|
-
return -va.localeCompare(vb, { sensitivity: 'base' })
|
|
178
|
-
}
|
|
179
|
-
return va > vb ? 1 : -1
|
|
180
|
-
}
|
|
149
|
+
if (!list || !list.length) {
|
|
150
|
+
return []
|
|
181
151
|
}
|
|
182
|
-
return [
|
|
183
|
-
l0,
|
|
184
|
-
...l1.sort(sorter),
|
|
185
|
-
...l2.sort(sorter)
|
|
186
|
-
].filter(d => d)
|
|
187
|
-
}, isEqual)
|
|
188
152
|
|
|
189
|
-
|
|
190
|
-
window.addEventListener('message', this.handleMsg)
|
|
191
|
-
window.addEventListener('keydown', this.handleEvent)
|
|
192
|
-
}
|
|
153
|
+
const isDesc = sortDirection === 'desc'
|
|
193
154
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
155
|
+
return list.slice().sort((a, b) => {
|
|
156
|
+
// Handle items with no id first
|
|
157
|
+
if (!a.id && b.id) return -1
|
|
158
|
+
if (a.id && !b.id) return 1
|
|
159
|
+
if (!a.id && !b.id) return 0
|
|
198
160
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
161
|
+
// Sort directories before files
|
|
162
|
+
if (a.isDirectory !== b.isDirectory) {
|
|
163
|
+
return a.isDirectory ? -1 : 1
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Sort by the specified property
|
|
167
|
+
let aValue = a[sortProp]
|
|
168
|
+
let bValue = b[sortProp]
|
|
169
|
+
|
|
170
|
+
if (typeof aValue === 'string') {
|
|
171
|
+
aValue = aValue.toLowerCase()
|
|
172
|
+
bValue = bValue.toLowerCase()
|
|
173
|
+
return isDesc
|
|
174
|
+
? bValue.localeCompare(aValue, { sensitivity: 'base' })
|
|
175
|
+
: aValue.localeCompare(bValue, { sensitivity: 'base' })
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// For non-string values, use simple comparison
|
|
179
|
+
if (aValue < bValue) return isDesc ? 1 : -1
|
|
180
|
+
if (aValue > bValue) return isDesc ? -1 : 1
|
|
181
|
+
return 0
|
|
182
|
+
})
|
|
183
|
+
}, isEqual)
|
|
212
184
|
|
|
213
185
|
isActive () {
|
|
214
186
|
return this.props.enableSftp && this.props.currentBatchTabId === this.props.tab.id &&
|
|
@@ -266,15 +238,6 @@ export default class Sftp extends Component {
|
|
|
266
238
|
return this.getFileList(type).findIndex(f => f.id === file.id)
|
|
267
239
|
}
|
|
268
240
|
|
|
269
|
-
onResizeDragEnd = () => {
|
|
270
|
-
postMessage({
|
|
271
|
-
type: eventTypes.resetFileListTable,
|
|
272
|
-
data: {
|
|
273
|
-
id: this.state.id
|
|
274
|
-
}
|
|
275
|
-
})
|
|
276
|
-
}
|
|
277
|
-
|
|
278
241
|
selectAll = (type, e) => {
|
|
279
242
|
e && e.preventDefault && e.preventDefault()
|
|
280
243
|
this.setState({
|
|
@@ -344,8 +307,25 @@ export default class Sftp extends Component {
|
|
|
344
307
|
await func(p).catch(window.store.onError)
|
|
345
308
|
}
|
|
346
309
|
|
|
310
|
+
confirmDelete = (files) => {
|
|
311
|
+
return new Promise((resolve) => {
|
|
312
|
+
Modal.confirm({
|
|
313
|
+
title: this.renderDelConfirmTitle(files),
|
|
314
|
+
okText: e('ok'),
|
|
315
|
+
cancelText: e('cancel'),
|
|
316
|
+
onOk: () => resolve(true),
|
|
317
|
+
onCancel: () => resolve(false)
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
|
|
347
322
|
delFiles = async (_type, files = this.state.selectedFiles) => {
|
|
323
|
+
this.onDelete = true
|
|
324
|
+
const confirm = await this.confirmDelete(files)
|
|
348
325
|
this.onDelete = false
|
|
326
|
+
if (!confirm) {
|
|
327
|
+
return
|
|
328
|
+
}
|
|
349
329
|
const type = files[0].type || _type
|
|
350
330
|
const func = this[type + 'Del']
|
|
351
331
|
for (const f of files) {
|
|
@@ -380,16 +360,6 @@ export default class Sftp extends Component {
|
|
|
380
360
|
)
|
|
381
361
|
}
|
|
382
362
|
|
|
383
|
-
onDel = (type, files) => {
|
|
384
|
-
this.onDelete = true
|
|
385
|
-
Modal.confirm({
|
|
386
|
-
cancelText: e('cancel'),
|
|
387
|
-
okText: e('ok'),
|
|
388
|
-
title: this.renderDelConfirmTitle(files),
|
|
389
|
-
onOk: () => this.delFiles(type, files)
|
|
390
|
-
})
|
|
391
|
-
}
|
|
392
|
-
|
|
393
363
|
enter = (type, e) => {
|
|
394
364
|
const { selectedFiles, onEditFile } = this.state
|
|
395
365
|
if (onEditFile || selectedFiles.length !== 1) {
|
|
@@ -437,41 +407,6 @@ export default class Sftp extends Component {
|
|
|
437
407
|
this[type + 'Dom'].onPaste()
|
|
438
408
|
}
|
|
439
409
|
|
|
440
|
-
handleEvent = (e) => {
|
|
441
|
-
if (!this.isActive() || window.store.onOperation) {
|
|
442
|
-
return
|
|
443
|
-
}
|
|
444
|
-
const lastClickedFile = this.state.lastClickedFile || {
|
|
445
|
-
type: typeMap.local
|
|
446
|
-
}
|
|
447
|
-
const { type } = lastClickedFile
|
|
448
|
-
const { inputFocus, onDelete } = this
|
|
449
|
-
e.stopPropagation()
|
|
450
|
-
if (keyControlPressed(e) && keyPressed(e, 'keyA') && !inputFocus) {
|
|
451
|
-
this.selectAll(type, e)
|
|
452
|
-
} else if (keyPressed(e, 'arrowdown') && !inputFocus) {
|
|
453
|
-
this.selectNext(type)
|
|
454
|
-
} else if (keyPressed(e, 'arrowup') && !inputFocus) {
|
|
455
|
-
this.selectPrev(type)
|
|
456
|
-
} else if (
|
|
457
|
-
keyPressed(e, 'delete') &&
|
|
458
|
-
!inputFocus &&
|
|
459
|
-
!this.state.onEditFile
|
|
460
|
-
) {
|
|
461
|
-
this.onDel(type)
|
|
462
|
-
} else if (keyPressed(e, 'enter') && !inputFocus && !onDelete) {
|
|
463
|
-
this.enter(type, e)
|
|
464
|
-
} else if (keyControlPressed(e) && keyPressed(e, 'keyC') && !inputFocus) {
|
|
465
|
-
this.doCopy(type, e)
|
|
466
|
-
} else if (keyControlPressed(e) && keyPressed(e, 'keyX') && !inputFocus) {
|
|
467
|
-
this.doCut(type, e)
|
|
468
|
-
} else if (keyControlPressed(e) && keyPressed(e, 'keyV') && !inputFocus) {
|
|
469
|
-
this.doPaste(type, e)
|
|
470
|
-
} else if (keyPressed(e, 'f5')) {
|
|
471
|
-
this.onGoto(type)
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
410
|
initData = async () => {
|
|
476
411
|
if (this.shouldRenderRemote()) {
|
|
477
412
|
this.initRemoteAll()
|
|
@@ -537,6 +472,18 @@ export default class Sftp extends Component {
|
|
|
537
472
|
})
|
|
538
473
|
}
|
|
539
474
|
|
|
475
|
+
buildTree = (arr, type) => {
|
|
476
|
+
const parent = this.renderParentItem(type)
|
|
477
|
+
const treeMap = new Map(arr.map(d => [d.id, d]))
|
|
478
|
+
|
|
479
|
+
// Only add parent if it exists
|
|
480
|
+
if (parent) {
|
|
481
|
+
treeMap.set(parent.id, parent)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return treeMap
|
|
485
|
+
}
|
|
486
|
+
|
|
540
487
|
remoteListOwner = async () => {
|
|
541
488
|
const remoteUidTree = await owner.remoteListUsers(
|
|
542
489
|
this.props.pid,
|
|
@@ -666,7 +613,7 @@ export default class Sftp extends Component {
|
|
|
666
613
|
this.sftp = sftp
|
|
667
614
|
const update = {
|
|
668
615
|
remote,
|
|
669
|
-
remoteFileTree: buildTree(remote),
|
|
616
|
+
remoteFileTree: this.buildTree(remote, typeMap.remote),
|
|
670
617
|
inited: true,
|
|
671
618
|
remoteLoading: false
|
|
672
619
|
}
|
|
@@ -748,7 +695,7 @@ export default class Sftp extends Component {
|
|
|
748
695
|
}
|
|
749
696
|
const update = {
|
|
750
697
|
remote,
|
|
751
|
-
remoteFileTree: buildTree(remote)
|
|
698
|
+
remoteFileTree: this.buildTree(remote, typeMap.remote)
|
|
752
699
|
}
|
|
753
700
|
this.setState(update)
|
|
754
701
|
}
|
|
@@ -781,7 +728,7 @@ export default class Sftp extends Component {
|
|
|
781
728
|
const update = {
|
|
782
729
|
local,
|
|
783
730
|
inited: true,
|
|
784
|
-
localFileTree: buildTree(local),
|
|
731
|
+
localFileTree: this.buildTree(local, typeMap.local),
|
|
785
732
|
localLoading: false
|
|
786
733
|
}
|
|
787
734
|
if (!noPathInit) {
|
|
@@ -953,6 +900,32 @@ export default class Sftp extends Component {
|
|
|
953
900
|
)
|
|
954
901
|
}
|
|
955
902
|
|
|
903
|
+
renderParentItem = (type) => {
|
|
904
|
+
const currentPath = this.state[`${type}Path`]
|
|
905
|
+
const parentPath = resolve(currentPath, '..')
|
|
906
|
+
// Don't render parent item if we're at the root
|
|
907
|
+
if (parentPath === currentPath) {
|
|
908
|
+
return null
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const { id } = this.props.tab
|
|
912
|
+
const uniqueId = `parent-${parentPath}-${id}-${type}`
|
|
913
|
+
|
|
914
|
+
return {
|
|
915
|
+
type,
|
|
916
|
+
isDirectory: true,
|
|
917
|
+
...getFolderFromFilePath(parentPath, type === typeMap.remote),
|
|
918
|
+
id: uniqueId,
|
|
919
|
+
size: 0,
|
|
920
|
+
modifyTime: 0,
|
|
921
|
+
accessTime: 0,
|
|
922
|
+
mode: 0,
|
|
923
|
+
owner: '',
|
|
924
|
+
group: '',
|
|
925
|
+
isParent: true
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
956
929
|
renderHistory = (type) => {
|
|
957
930
|
const currentPath = this.state[type + 'Path']
|
|
958
931
|
const options = this.state[type + 'PathHistory']
|
|
@@ -999,6 +972,7 @@ export default class Sftp extends Component {
|
|
|
999
972
|
store: window.store,
|
|
1000
973
|
id,
|
|
1001
974
|
type,
|
|
975
|
+
parentItem: this.renderParentItem(type),
|
|
1002
976
|
...this.props,
|
|
1003
977
|
...pick(
|
|
1004
978
|
this,
|
|
@@ -78,9 +78,11 @@
|
|
|
78
78
|
left 10px
|
|
79
79
|
top 10px
|
|
80
80
|
font-size 50px
|
|
81
|
+
.file-props-div
|
|
82
|
+
display flex
|
|
83
|
+
width 100%
|
|
81
84
|
.file-props
|
|
82
85
|
margin-left 70px
|
|
83
|
-
|
|
84
86
|
.opacity-loop
|
|
85
87
|
opacity 0.3
|
|
86
88
|
animation blinker 5s linear infinite
|
|
@@ -97,11 +99,9 @@
|
|
|
97
99
|
|
|
98
100
|
//list table
|
|
99
101
|
.sftp-file-prop
|
|
102
|
+
flex 0 0 auto
|
|
100
103
|
height 32px
|
|
101
104
|
line-height 30px
|
|
102
|
-
position absolute
|
|
103
|
-
left 0
|
|
104
|
-
width 100px
|
|
105
105
|
padding 0 5px
|
|
106
106
|
background main
|
|
107
107
|
overflow hidden
|
|
@@ -109,11 +109,8 @@
|
|
|
109
109
|
text-overflow ellipsis
|
|
110
110
|
pointer-events none
|
|
111
111
|
cursor default
|
|
112
|
-
z-index 4
|
|
113
112
|
color text
|
|
114
|
-
|
|
115
|
-
right 0 !important
|
|
116
|
-
width auto !important
|
|
113
|
+
|
|
117
114
|
.file-bg
|
|
118
115
|
position absolute
|
|
119
116
|
left 0
|
|
@@ -125,26 +122,13 @@
|
|
|
125
122
|
.sftp-header-item
|
|
126
123
|
height 28px
|
|
127
124
|
line-height 25px
|
|
128
|
-
position absolute
|
|
129
|
-
left 0
|
|
130
|
-
width 100px
|
|
131
|
-
border 1px solid main
|
|
132
|
-
border-right none
|
|
133
125
|
padding 0 5px
|
|
134
126
|
background main
|
|
135
127
|
overflow hidden
|
|
136
128
|
white-space nowrap
|
|
137
129
|
text-overflow ellipsis
|
|
138
130
|
color text
|
|
139
|
-
|
|
140
|
-
border-right 1px solid main
|
|
141
|
-
right 0 !important
|
|
142
|
-
width auto !important
|
|
143
|
-
.sftp-header-handle
|
|
144
|
-
z-index 20
|
|
145
|
-
cursor ew-resize
|
|
146
|
-
border none
|
|
147
|
-
background none
|
|
131
|
+
|
|
148
132
|
.sftp-file-table-header
|
|
149
133
|
height 30px
|
|
150
134
|
.sftp-table
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getFileExt,
|
|
13
13
|
checkFolderSize
|
|
14
14
|
} from './file-read'
|
|
15
|
+
import { refsStatic, refs } from '../common/ref'
|
|
15
16
|
import generate from '../../common/uid'
|
|
16
17
|
import resolve from '../../common/resolve'
|
|
17
18
|
import deepCopy from 'json-deep-copy'
|
|
@@ -24,6 +25,8 @@ export default class TransferConflictStore extends PureComponent {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
componentDidMount () {
|
|
28
|
+
this.id = 'transfer-conflict'
|
|
29
|
+
refsStatic.add(this.id, this)
|
|
27
30
|
this.watchFile()
|
|
28
31
|
}
|
|
29
32
|
|
|
@@ -40,7 +43,7 @@ export default class TransferConflictStore extends PureComponent {
|
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
remoteCheckExist = (path, sessionId) => {
|
|
43
|
-
const sftp =
|
|
46
|
+
const sftp = refs.get('sftp-' + sessionId).sftp
|
|
44
47
|
return getRemoteFileInfo(sftp, path)
|
|
45
48
|
.then(r => r)
|
|
46
49
|
.catch(() => false)
|
|
@@ -131,23 +134,17 @@ export default class TransferConflictStore extends PureComponent {
|
|
|
131
134
|
window.store.transferToConfirm = tr
|
|
132
135
|
}
|
|
133
136
|
|
|
134
|
-
onDecision = (
|
|
137
|
+
onDecision = (data) => {
|
|
135
138
|
if (
|
|
136
|
-
|
|
137
|
-
event.data &&
|
|
138
|
-
event.data.id === this.currentId
|
|
139
|
+
data.id === this.currentId
|
|
139
140
|
) {
|
|
140
141
|
this.currentId = ''
|
|
141
|
-
this.updateTransferAction(
|
|
142
|
+
this.updateTransferAction(data)
|
|
142
143
|
this.onConfirm = false
|
|
143
144
|
window.removeEventListener('message', this.onDecision)
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
waitForSignal = () => {
|
|
148
|
-
window.addEventListener('message', this.onDecision)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
148
|
updateData = () => {
|
|
152
149
|
const {
|
|
153
150
|
store
|
|
@@ -239,7 +236,7 @@ export default class TransferConflictStore extends PureComponent {
|
|
|
239
236
|
}
|
|
240
237
|
if (fromFile.isDirectory && typeFrom !== typeTo) {
|
|
241
238
|
const props = {
|
|
242
|
-
sftp:
|
|
239
|
+
sftp: refs.get('sftp-' + sessionId).sftp
|
|
243
240
|
}
|
|
244
241
|
const skip = await checkFolderSize(props, fromFile)
|
|
245
242
|
.then(d => d && typeFrom !== typeTo)
|
|
@@ -260,7 +257,6 @@ export default class TransferConflictStore extends PureComponent {
|
|
|
260
257
|
transfer: tr
|
|
261
258
|
})
|
|
262
259
|
} else if (toFile && !action && !skipConfirm) {
|
|
263
|
-
this.waitForSignal(id)
|
|
264
260
|
if (!this.onConfirm) {
|
|
265
261
|
this.onConfirm = true
|
|
266
262
|
assign(tr, {
|
|
@@ -2,7 +2,7 @@ import { Component } from 'react'
|
|
|
2
2
|
import copy from 'json-deep-copy'
|
|
3
3
|
import { isFunction } from 'lodash-es'
|
|
4
4
|
import generate from '../../common/uid'
|
|
5
|
-
import { typeMap, transferTypeMap
|
|
5
|
+
import { typeMap, transferTypeMap } from '../../common/constants'
|
|
6
6
|
import fs from '../../common/fs'
|
|
7
7
|
import format, { computeLeftTime, computePassedTime } from './transfer-speed-format'
|
|
8
8
|
import {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from './file-read'
|
|
11
11
|
import resolve from '../../common/resolve'
|
|
12
12
|
import delay from '../../common/wait'
|
|
13
|
-
import
|
|
13
|
+
import { refs } from '../common/ref'
|
|
14
14
|
import { zipCmd, unzipCmd, rmCmd, mvCmd, mkdirCmd } from './zip'
|
|
15
15
|
import './transfer.styl'
|
|
16
16
|
|
|
@@ -71,19 +71,11 @@ export default class TransportAction extends Component {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
remoteList = () => {
|
|
74
|
-
|
|
75
|
-
action: commonActions.sftpList,
|
|
76
|
-
sessionId: this.sessionId,
|
|
77
|
-
type: typeMap.remote
|
|
78
|
-
})
|
|
74
|
+
window.store.remoteList(this.sessionId)
|
|
79
75
|
}
|
|
80
76
|
|
|
81
77
|
localList = () => {
|
|
82
|
-
|
|
83
|
-
action: commonActions.sftpList,
|
|
84
|
-
sessionId: this.sessionId,
|
|
85
|
-
type: typeMap.local
|
|
86
|
-
})
|
|
78
|
+
window.store.localList(this.sessionId)
|
|
87
79
|
}
|
|
88
80
|
|
|
89
81
|
onEnd = (update = {}) => {
|
|
@@ -200,7 +192,7 @@ export default class TransportAction extends Component {
|
|
|
200
192
|
this.onError(e)
|
|
201
193
|
})
|
|
202
194
|
}
|
|
203
|
-
const sftp =
|
|
195
|
+
const sftp = refs.get('sftp-' + sessionId).sftp
|
|
204
196
|
return sftp[operation](fromPath, toPath)
|
|
205
197
|
.then(this.onEnd)
|
|
206
198
|
.catch(e => {
|
|
@@ -342,7 +334,7 @@ export default class TransportAction extends Component {
|
|
|
342
334
|
? fromPath
|
|
343
335
|
: toPath
|
|
344
336
|
const mode = toFile.mode || fromMode
|
|
345
|
-
const sftp =
|
|
337
|
+
const sftp = refs.get('sftp-' + this.sessionId).sftp
|
|
346
338
|
this.transport = await sftp[transferType]({
|
|
347
339
|
remotePath,
|
|
348
340
|
localPath,
|
|
@@ -419,7 +411,7 @@ export default class TransportAction extends Component {
|
|
|
419
411
|
return fs.mkdir(toPath)
|
|
420
412
|
.catch(this.onError)
|
|
421
413
|
}
|
|
422
|
-
const sftp =
|
|
414
|
+
const sftp = refs.get('sftp-' + sessionId).sftp
|
|
423
415
|
return sftp.mkdir(toPath)
|
|
424
416
|
.catch(this.onError)
|
|
425
417
|
}
|
|
@@ -6,15 +6,84 @@
|
|
|
6
6
|
import React from 'react'
|
|
7
7
|
import { shortcutExtend } from './shortcut-handler.js'
|
|
8
8
|
import { throttle } from 'lodash-es'
|
|
9
|
+
import {
|
|
10
|
+
typeMap
|
|
11
|
+
} from '../../common/constants'
|
|
12
|
+
import { refs, refsStatic } from '../common/ref'
|
|
13
|
+
import keyControlPressed from '../../common/key-control-pressed'
|
|
14
|
+
import keyPressed from '../../common/key-pressed'
|
|
9
15
|
|
|
10
16
|
class ShortcutControl extends React.PureComponent {
|
|
11
17
|
componentDidMount () {
|
|
12
18
|
const onEvent = this.handleKeyboardEvent.bind(this)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
document.addEventListener('keydown', this.onEvent, true)
|
|
20
|
+
document.addEventListener('mousedown', onEvent)
|
|
21
|
+
document.addEventListener('mousewheel', onEvent)
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
onEvent = (e) => {
|
|
25
|
+
// First check SFTP shortcuts
|
|
26
|
+
this.handleSftpKeyboardEvent(e)
|
|
27
|
+
// Then handle extended shortcuts
|
|
28
|
+
this.handleKeyboardEvent(e)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getActiveSftp = () => {
|
|
32
|
+
const { activeTabId } = window.store
|
|
33
|
+
if (!activeTabId) return null
|
|
34
|
+
const ref = refs.get('sftp-' + activeTabId)
|
|
35
|
+
if (!ref || !ref.isActive()) return null
|
|
36
|
+
return ref
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// SFTP shortcuts handler
|
|
40
|
+
handleSftpKeyboardEvent = (e) => {
|
|
41
|
+
const activeSftp = this.getActiveSftp()
|
|
42
|
+
if (!activeSftp || activeSftp.state.onDelete) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const lastClickedFile = activeSftp.state.lastClickedFile || {
|
|
47
|
+
type: typeMap.local
|
|
48
|
+
}
|
|
49
|
+
const { type } = lastClickedFile
|
|
50
|
+
const { inputFocus } = activeSftp
|
|
51
|
+
|
|
52
|
+
if (keyControlPressed(e) && keyPressed(e, 'keyA') && !inputFocus) {
|
|
53
|
+
e.stopPropagation()
|
|
54
|
+
activeSftp.selectAll(type, e)
|
|
55
|
+
} else if (keyPressed(e, 'arrowdown') && !inputFocus) {
|
|
56
|
+
e.stopPropagation()
|
|
57
|
+
activeSftp.selectNext(type)
|
|
58
|
+
} else if (keyPressed(e, 'arrowup') && !inputFocus) {
|
|
59
|
+
e.stopPropagation()
|
|
60
|
+
activeSftp.selectPrev(type)
|
|
61
|
+
} else if (keyPressed(e, 'delete') && !inputFocus && !activeSftp.state.onEditFile) {
|
|
62
|
+
e.stopPropagation()
|
|
63
|
+
activeSftp.delFiles(type)
|
|
64
|
+
} else if (keyPressed(e, 'enter') && !inputFocus && !activeSftp.onDelete) {
|
|
65
|
+
e.stopPropagation()
|
|
66
|
+
activeSftp.enter(type, e)
|
|
67
|
+
} else if (keyControlPressed(e) && keyPressed(e, 'keyC') && !inputFocus) {
|
|
68
|
+
e.stopPropagation()
|
|
69
|
+
activeSftp.doCopy(type, e)
|
|
70
|
+
} else if (keyControlPressed(e) && keyPressed(e, 'keyX') && !inputFocus) {
|
|
71
|
+
e.stopPropagation()
|
|
72
|
+
activeSftp.doCut(type, e)
|
|
73
|
+
} else if (keyControlPressed(e) && keyPressed(e, 'keyV') && !inputFocus) {
|
|
74
|
+
e.stopPropagation()
|
|
75
|
+
activeSftp.doPaste(type, e)
|
|
76
|
+
} else if (keyPressed(e, 'f5')) {
|
|
77
|
+
e.stopPropagation()
|
|
78
|
+
activeSftp.onGoto(type)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
searchShortcut = throttle((e) => {
|
|
83
|
+
e.stopPropagation()
|
|
84
|
+
refsStatic.get('term-search')?.toggleSearch()
|
|
85
|
+
}, 500)
|
|
86
|
+
|
|
18
87
|
closeCurrentTabShortcut = throttle((e) => {
|
|
19
88
|
e.stopPropagation()
|
|
20
89
|
const { activeTabId } = window.store
|
|
@@ -68,7 +68,6 @@ export function shortcutExtend (Cls) {
|
|
|
68
68
|
!altKey &&
|
|
69
69
|
!ctrlKey
|
|
70
70
|
) {
|
|
71
|
-
console.log('handleKeyboardEvent: Handling Backspace key')
|
|
72
71
|
this.props.onDelKeyPressed()
|
|
73
72
|
const delKey = this.props.config.backspaceMode === '^?' ? 8 : 127
|
|
74
73
|
const altDelDelKey = delKey === 8 ? 127 : 8
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { memo } from 'react'
|
|
1
|
+
import React, { memo, useRef } from 'react'
|
|
2
2
|
import DragHandle from '../common/drag-handle'
|
|
3
3
|
import './right-side-panel.styl'
|
|
4
4
|
import {
|
|
@@ -22,6 +22,8 @@ export default memo(function RightSidePanel (
|
|
|
22
22
|
rightPanelTab
|
|
23
23
|
}
|
|
24
24
|
) {
|
|
25
|
+
const panelRef = useRef(null)
|
|
26
|
+
|
|
25
27
|
if (!rightPanelVisible) {
|
|
26
28
|
return null
|
|
27
29
|
}
|
|
@@ -34,8 +36,9 @@ export default memo(function RightSidePanel (
|
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
function onDragMove (nw) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
if (panelRef.current) {
|
|
40
|
+
panelRef.current.style.width = nw + 'px'
|
|
41
|
+
}
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
function onClose () {
|
|
@@ -48,7 +51,7 @@ export default memo(function RightSidePanel (
|
|
|
48
51
|
|
|
49
52
|
const panelProps = {
|
|
50
53
|
className: 'right-side-panel animate-fast' + (rightPanelPinned ? ' right-side-panel-pinned' : ''),
|
|
51
|
-
|
|
54
|
+
ref: panelRef,
|
|
52
55
|
style: {
|
|
53
56
|
width: `${rightPanelWidth}px`
|
|
54
57
|
}
|