@electerm/electerm-react 1.38.65 → 1.38.70
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 +3 -2
- package/client/common/create-title.jsx +9 -1
- package/client/common/sftp.js +3 -0
- package/client/components/batch-op/batch-op.jsx +1 -6
- package/client/components/bookmark-form/bookmark-form.styl +3 -1
- package/client/components/bookmark-form/render-ssh-tunnel.jsx +210 -88
- package/client/components/bookmark-form/ssh-form-ui.jsx +1 -1
- package/client/components/main/main.jsx +14 -0
- package/client/components/sftp/{confirm-modal.jsx → confirm-modal-store.jsx} +81 -50
- package/client/components/sftp/file-item.jsx +2 -0
- package/client/components/sftp/sftp-entry.jsx +27 -37
- package/client/components/sftp/transfer-conflict-store.jsx +291 -0
- package/client/components/sftp/transport-action-store.jsx +430 -0
- package/client/components/sftp/transports-action-store.jsx +102 -0
- package/client/components/sftp/transports-ui-store.jsx +30 -0
- package/client/components/sidebar/transfer-list-control.jsx +5 -14
- package/client/components/sidebar/transport-ui.jsx +2 -12
- package/client/components/tabs/tab.jsx +43 -2
- package/client/components/tabs/tabs.styl +1 -1
- package/client/components/terminal/index.jsx +1 -0
- package/client/components/terminal/terminal-interactive.jsx +15 -0
- package/client/components/terminal-info/disk.jsx +9 -0
- package/client/store/index.js +4 -0
- package/client/store/init-state.js +2 -3
- package/client/store/sync.js +5 -2
- package/client/store/tab.js +1 -1
- package/client/store/transfer-list.js +55 -2
- package/client/store/watch.js +0 -8
- package/package.json +1 -1
- package/client/components/sftp/transfer-conflict.jsx +0 -323
- package/client/components/sftp/transport-action.jsx +0 -412
- package/client/components/sftp/transport-entry.jsx +0 -108
- package/client/components/sftp/transport-types.js +0 -8
- package/client/components/sftp/transports-action.jsx +0 -111
- package/client/components/sftp/transports-ui.jsx +0 -93
|
@@ -14,8 +14,10 @@ import {
|
|
|
14
14
|
typeMap, maxSftpHistory, paneMap,
|
|
15
15
|
eventTypes,
|
|
16
16
|
fileTypeMap,
|
|
17
|
-
terminalSshConfigType,
|
|
18
|
-
|
|
17
|
+
terminalSshConfigType,
|
|
18
|
+
terminalSerialType,
|
|
19
|
+
unexpectedPacketErrorDesc,
|
|
20
|
+
sftpRetryInterval,
|
|
19
21
|
commonActions
|
|
20
22
|
} from '../../common/constants'
|
|
21
23
|
import { hasFileInClipboardText } from '../../common/clipboard'
|
|
@@ -27,7 +29,6 @@ import ListTable from './list-table-ui'
|
|
|
27
29
|
import deepCopy from 'json-deep-copy'
|
|
28
30
|
import isValidPath from '../../common/is-valid-path'
|
|
29
31
|
import memoizeOne from 'memoize-one'
|
|
30
|
-
import TransportEntry from './transport-entry'
|
|
31
32
|
import postMessage from '../../common/post-msg'
|
|
32
33
|
import { runCmd } from '../terminal/terminal-apis'
|
|
33
34
|
import * as owner from './owner-list'
|
|
@@ -58,9 +59,6 @@ export default class Sftp extends Component {
|
|
|
58
59
|
onEditFile: false,
|
|
59
60
|
...this.defaultState(),
|
|
60
61
|
loadingSftp: false,
|
|
61
|
-
transferToConfirm: null,
|
|
62
|
-
transferList: [],
|
|
63
|
-
pauseAll: false,
|
|
64
62
|
inited: false
|
|
65
63
|
}
|
|
66
64
|
this.retryCount = 0
|
|
@@ -190,11 +188,27 @@ export default class Sftp extends Component {
|
|
|
190
188
|
}, isEqual)
|
|
191
189
|
|
|
192
190
|
initEvent () {
|
|
191
|
+
window.addEventListener('message', this.handleMsg)
|
|
193
192
|
window.addEventListener('keydown', this.handleEvent)
|
|
194
193
|
}
|
|
195
194
|
|
|
196
195
|
destroyEvent () {
|
|
197
196
|
window.removeEventListener('keydown', this.handleEvent)
|
|
197
|
+
window.removeEventListener('message', this.handleMsg)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
handleMsg = event => {
|
|
201
|
+
const {
|
|
202
|
+
action,
|
|
203
|
+
sessionId,
|
|
204
|
+
type
|
|
205
|
+
} = event?.data || {}
|
|
206
|
+
if (
|
|
207
|
+
action === commonActions.sftpList &&
|
|
208
|
+
sessionId === this.props.sessionId
|
|
209
|
+
) {
|
|
210
|
+
this[type + 'List']()
|
|
211
|
+
}
|
|
198
212
|
}
|
|
199
213
|
|
|
200
214
|
isActive () {
|
|
@@ -437,32 +451,28 @@ export default class Sftp extends Component {
|
|
|
437
451
|
}
|
|
438
452
|
const { type } = lastClickedFile
|
|
439
453
|
const { inputFocus, onDelete } = this
|
|
454
|
+
e.stopPropagation()
|
|
440
455
|
if (keyControlPressed(e) && keyPressed(e, 'keyA') && !inputFocus) {
|
|
441
|
-
e.stopPropagation()
|
|
442
456
|
this.selectAll(type, e)
|
|
443
457
|
} else if (keyPressed(e, 'arrowdown') && !inputFocus) {
|
|
444
|
-
e.stopPropagation()
|
|
445
458
|
this.selectNext(type)
|
|
446
459
|
} else if (keyPressed(e, 'arrowup') && !inputFocus) {
|
|
447
|
-
e.stopPropagation()
|
|
448
460
|
this.selectPrev(type)
|
|
449
|
-
} else if (
|
|
450
|
-
e
|
|
461
|
+
} else if (
|
|
462
|
+
keyPressed(e, 'delete') &&
|
|
463
|
+
!inputFocus &&
|
|
464
|
+
!this.state.onEditFile
|
|
465
|
+
) {
|
|
451
466
|
this.onDel(type)
|
|
452
467
|
} else if (keyPressed(e, 'enter') && !inputFocus && !onDelete) {
|
|
453
|
-
e.stopPropagation()
|
|
454
468
|
this.enter(type, e)
|
|
455
469
|
} else if (keyControlPressed(e) && keyPressed(e, 'keyC') && !inputFocus) {
|
|
456
|
-
e.stopPropagation()
|
|
457
470
|
this.doCopy(type, e)
|
|
458
471
|
} else if (keyControlPressed(e) && keyPressed(e, 'keyX') && !inputFocus) {
|
|
459
|
-
e.stopPropagation()
|
|
460
472
|
this.doCut(type, e)
|
|
461
473
|
} else if (keyControlPressed(e) && keyPressed(e, 'keyV') && !inputFocus) {
|
|
462
|
-
e.stopPropagation()
|
|
463
474
|
this.doPaste(type, e)
|
|
464
475
|
} else if (keyPressed(e, 'f5')) {
|
|
465
|
-
e.stopPropagation()
|
|
466
476
|
this.onGoto(type)
|
|
467
477
|
}
|
|
468
478
|
}
|
|
@@ -496,11 +506,7 @@ export default class Sftp extends Component {
|
|
|
496
506
|
}
|
|
497
507
|
|
|
498
508
|
addTransferList = list => {
|
|
499
|
-
|
|
500
|
-
list,
|
|
501
|
-
action: commonActions.addTransfer,
|
|
502
|
-
sessionId: this.props.sessionId
|
|
503
|
-
})
|
|
509
|
+
window.store.addTransferList(list)
|
|
504
510
|
}
|
|
505
511
|
|
|
506
512
|
computeListHeight = () => {
|
|
@@ -906,11 +912,8 @@ export default class Sftp extends Component {
|
|
|
906
912
|
typeMap.remote,
|
|
907
913
|
'lastClickedFile',
|
|
908
914
|
'lastMataKey',
|
|
909
|
-
'transferToConfirm',
|
|
910
|
-
'transferList',
|
|
911
915
|
'targetTransferType',
|
|
912
916
|
'selectedFiles',
|
|
913
|
-
'pauseAll',
|
|
914
917
|
'localGidTree',
|
|
915
918
|
'remoteUidTree',
|
|
916
919
|
'localUidTree',
|
|
@@ -1108,18 +1111,6 @@ export default class Sftp extends Component {
|
|
|
1108
1111
|
const {
|
|
1109
1112
|
id
|
|
1110
1113
|
} = this.state
|
|
1111
|
-
const prps = {
|
|
1112
|
-
localList: this.localList,
|
|
1113
|
-
remoteList: this.remoteList,
|
|
1114
|
-
sftp: this.sftp,
|
|
1115
|
-
sessionId: this.props.sessionId,
|
|
1116
|
-
host: this.props.tab.host,
|
|
1117
|
-
localListDebounce: this.localListDebounce,
|
|
1118
|
-
remoteListDebounce: this.remoteListDebounce,
|
|
1119
|
-
config: this.props.config,
|
|
1120
|
-
tab: this.props.tab,
|
|
1121
|
-
pid: this.props.pid
|
|
1122
|
-
}
|
|
1123
1114
|
const all = {
|
|
1124
1115
|
className: 'sftp-wrap overhide relative',
|
|
1125
1116
|
id: `id-${id}`,
|
|
@@ -1132,7 +1123,6 @@ export default class Sftp extends Component {
|
|
|
1132
1123
|
{
|
|
1133
1124
|
this.renderSections()
|
|
1134
1125
|
}
|
|
1135
|
-
<TransportEntry {...prps} />
|
|
1136
1126
|
</div>
|
|
1137
1127
|
)
|
|
1138
1128
|
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pass transfer list from props
|
|
3
|
+
* when list changes, do transfer and other op
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Component } from '../common/react-subx'
|
|
7
|
+
import { typeMap } from '../../common/constants'
|
|
8
|
+
import {
|
|
9
|
+
getLocalFileInfo,
|
|
10
|
+
getRemoteFileInfo,
|
|
11
|
+
getFolderFromFilePath,
|
|
12
|
+
getFileExt,
|
|
13
|
+
checkFolderSize
|
|
14
|
+
} from './file-read'
|
|
15
|
+
import { findIndex, find } from 'lodash-es'
|
|
16
|
+
import generate from '../../common/uid'
|
|
17
|
+
import resolve from '../../common/resolve'
|
|
18
|
+
|
|
19
|
+
export default class TransferConflictStore extends Component {
|
|
20
|
+
state = {
|
|
21
|
+
currentId: ''
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
componentDidMount () {
|
|
25
|
+
this.watchFile()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
componentDidUpdate (prevProps) {
|
|
29
|
+
if (
|
|
30
|
+
prevProps._fileTransfers !== this.props._fileTransfers
|
|
31
|
+
) {
|
|
32
|
+
this.watchFile()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
localCheckExist = (path) => {
|
|
37
|
+
return getLocalFileInfo(path)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
remoteCheckExist = (path, sessionId) => {
|
|
41
|
+
const sftp = window.sftps[sessionId]
|
|
42
|
+
return getRemoteFileInfo(sftp, path)
|
|
43
|
+
.then(r => r)
|
|
44
|
+
.catch(() => false)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
checkExist = (type, path, sessionId) => {
|
|
48
|
+
return this[type + 'CheckExist'](path, sessionId)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
rename = (tr, action, _renameId) => {
|
|
52
|
+
const isRemote = tr.typeTo === typeMap.remote
|
|
53
|
+
const { path, name } = getFolderFromFilePath(tr.toPath, isRemote)
|
|
54
|
+
const { base, ext } = getFileExt(name)
|
|
55
|
+
const renameId = _renameId || generate()
|
|
56
|
+
const newName = ext
|
|
57
|
+
? `${base}(rename-${renameId}).${ext}`
|
|
58
|
+
: `${base}(rename-${renameId})`
|
|
59
|
+
const res = {
|
|
60
|
+
...tr,
|
|
61
|
+
renameId,
|
|
62
|
+
newName,
|
|
63
|
+
oldName: base,
|
|
64
|
+
toPath: resolve(path, newName)
|
|
65
|
+
}
|
|
66
|
+
if (action) {
|
|
67
|
+
res.action = action
|
|
68
|
+
}
|
|
69
|
+
return res
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
updateTransferAction = (data) => {
|
|
73
|
+
const {
|
|
74
|
+
id,
|
|
75
|
+
action,
|
|
76
|
+
transfer
|
|
77
|
+
} = data
|
|
78
|
+
const {
|
|
79
|
+
fromFile
|
|
80
|
+
} = transfer
|
|
81
|
+
this.clear()
|
|
82
|
+
const { store } = this.props
|
|
83
|
+
let {
|
|
84
|
+
fileTransfers
|
|
85
|
+
} = store
|
|
86
|
+
const index = findIndex(fileTransfers, d => d.id === id)
|
|
87
|
+
if (index < 0) {
|
|
88
|
+
return store.setFileTransfers(fileTransfers)
|
|
89
|
+
}
|
|
90
|
+
fileTransfers[index].fromFile = fromFile
|
|
91
|
+
fileTransfers[index].action = action
|
|
92
|
+
if (action === 'skip') {
|
|
93
|
+
fileTransfers.splice(index, 1)
|
|
94
|
+
} else if (action === 'cancel') {
|
|
95
|
+
fileTransfers = fileTransfers.slice(0, index)
|
|
96
|
+
}
|
|
97
|
+
if (action.includes('All')) {
|
|
98
|
+
fileTransfers = fileTransfers.map((t, i) => {
|
|
99
|
+
if (i < index) {
|
|
100
|
+
return t
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...t,
|
|
104
|
+
action: action.replace('All', '')
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
if (action.includes('rename')) {
|
|
109
|
+
fileTransfers[index] = this.rename(fileTransfers[index])
|
|
110
|
+
} else if (action === 'skipAll') {
|
|
111
|
+
fileTransfers.splice(index, 1)
|
|
112
|
+
}
|
|
113
|
+
store.setFileTransfers(fileTransfers)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
tagTransferError = (id, errorMsg) => {
|
|
117
|
+
const { store } = this.props
|
|
118
|
+
const {
|
|
119
|
+
fileTransfers
|
|
120
|
+
} = store
|
|
121
|
+
const tr = find(fileTransfers, d => d.id === id)
|
|
122
|
+
if (!tr) {
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
window.store.addTransferHistory({
|
|
126
|
+
...tr,
|
|
127
|
+
host: tr.host,
|
|
128
|
+
error: errorMsg,
|
|
129
|
+
finishTime: Date.now()
|
|
130
|
+
})
|
|
131
|
+
const index = findIndex(fileTransfers, d => d.id === id)
|
|
132
|
+
if (index >= 0) {
|
|
133
|
+
fileTransfers.splice(index, 1)
|
|
134
|
+
}
|
|
135
|
+
store.setFileTransfers(fileTransfers)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
setConflict (tr) {
|
|
139
|
+
if (window.store.transferToConfirm.id) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
window.store.setState(
|
|
143
|
+
'transferToConfirm', tr
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onDecision = (event) => {
|
|
148
|
+
if (
|
|
149
|
+
event &&
|
|
150
|
+
event.data &&
|
|
151
|
+
event.data.id === this.currentId
|
|
152
|
+
) {
|
|
153
|
+
this.currentId = ''
|
|
154
|
+
this.updateTransferAction(event.data)
|
|
155
|
+
this.onConfirm = false
|
|
156
|
+
window.removeEventListener('message', this.onDecision)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
waitForSignal = () => {
|
|
161
|
+
window.addEventListener('message', this.onDecision)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
setCanTransfer = (fromFile, tr) => {
|
|
165
|
+
this.clear()
|
|
166
|
+
const {
|
|
167
|
+
store
|
|
168
|
+
} = this.props
|
|
169
|
+
const {
|
|
170
|
+
fileTransfers
|
|
171
|
+
} = store
|
|
172
|
+
const index = findIndex(fileTransfers, t => {
|
|
173
|
+
return t.id === tr.id
|
|
174
|
+
})
|
|
175
|
+
if (index >= 0) {
|
|
176
|
+
const up = {
|
|
177
|
+
action: 'transfer',
|
|
178
|
+
fromFile
|
|
179
|
+
}
|
|
180
|
+
Object.assign(fileTransfers[index], up)
|
|
181
|
+
} else {
|
|
182
|
+
fileTransfers[0].r = Math.random()
|
|
183
|
+
}
|
|
184
|
+
store.setFileTransfers(fileTransfers)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
clear = () => {
|
|
188
|
+
this.currentId = ''
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
watchFile = async () => {
|
|
192
|
+
const { store } = this.props
|
|
193
|
+
const {
|
|
194
|
+
fileTransfers
|
|
195
|
+
} = store
|
|
196
|
+
if (!fileTransfers.length && this.currentId) {
|
|
197
|
+
return this.clear()
|
|
198
|
+
}
|
|
199
|
+
const tr = fileTransfers
|
|
200
|
+
.filter(t => {
|
|
201
|
+
return (
|
|
202
|
+
!t.action ||
|
|
203
|
+
!t.fromFile ||
|
|
204
|
+
t.fromFile.isDirectory
|
|
205
|
+
)
|
|
206
|
+
})[0]
|
|
207
|
+
if (!tr) {
|
|
208
|
+
this.onConfirm = false
|
|
209
|
+
return this.clear()
|
|
210
|
+
}
|
|
211
|
+
if (this.currentId) {
|
|
212
|
+
// fileTransfers[0].r = Math.random()
|
|
213
|
+
return store.setFileTransfers(fileTransfers)
|
|
214
|
+
}
|
|
215
|
+
this.currentId = tr.id
|
|
216
|
+
const {
|
|
217
|
+
typeFrom,
|
|
218
|
+
typeTo,
|
|
219
|
+
fromPath,
|
|
220
|
+
toPath,
|
|
221
|
+
id,
|
|
222
|
+
action,
|
|
223
|
+
renameId,
|
|
224
|
+
parentId,
|
|
225
|
+
skipConfirm,
|
|
226
|
+
sessionId
|
|
227
|
+
} = tr
|
|
228
|
+
const fromFile = tr.fromFile
|
|
229
|
+
? tr.fromFile
|
|
230
|
+
: await this.checkExist(typeFrom, fromPath, sessionId)
|
|
231
|
+
if (!fromFile) {
|
|
232
|
+
this.currentId = ''
|
|
233
|
+
return this.tagTransferError(id, 'file not exist')
|
|
234
|
+
}
|
|
235
|
+
let toFile = false
|
|
236
|
+
if (renameId || parentId) {
|
|
237
|
+
toFile = false
|
|
238
|
+
} else if (fromPath === toPath && typeFrom === typeTo) {
|
|
239
|
+
toFile = true
|
|
240
|
+
} else {
|
|
241
|
+
toFile = await this.checkExist(typeTo, toPath, sessionId)
|
|
242
|
+
}
|
|
243
|
+
if (fromFile.isDirectory) {
|
|
244
|
+
const props = {
|
|
245
|
+
sftp: window.sftps[sessionId]
|
|
246
|
+
}
|
|
247
|
+
const skip = await checkFolderSize(props, fromFile)
|
|
248
|
+
.then(d => d && typeFrom !== typeTo)
|
|
249
|
+
if (!skip) {
|
|
250
|
+
return this.tagTransferError(id, 'folder too big or too many files in folder')
|
|
251
|
+
}
|
|
252
|
+
tr.zip = true
|
|
253
|
+
tr.skipExpand = true
|
|
254
|
+
}
|
|
255
|
+
if (fromPath === toPath && typeFrom === typeTo) {
|
|
256
|
+
return this.updateTransferAction({
|
|
257
|
+
id,
|
|
258
|
+
action: 'rename',
|
|
259
|
+
transfer: {
|
|
260
|
+
...tr,
|
|
261
|
+
operation: 'cp',
|
|
262
|
+
fromFile
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
} else if (toFile && !action && !skipConfirm) {
|
|
266
|
+
this.waitForSignal(id)
|
|
267
|
+
if (!this.onConfirm) {
|
|
268
|
+
this.onConfirm = true
|
|
269
|
+
return this.setConflict({
|
|
270
|
+
...tr,
|
|
271
|
+
fromFile,
|
|
272
|
+
toFile
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
} else if (toFile && !tr.fromFile && action) {
|
|
276
|
+
return this.updateTransferAction({
|
|
277
|
+
id,
|
|
278
|
+
action,
|
|
279
|
+
transfer: {
|
|
280
|
+
...tr,
|
|
281
|
+
fromFile
|
|
282
|
+
}
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
this.setCanTransfer(fromFile, tr)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
render () {
|
|
289
|
+
return null
|
|
290
|
+
}
|
|
291
|
+
}
|