@electerm/electerm-react 1.38.60 → 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/quick-commands/quick-commands-box.jsx +5 -4
- 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 +34 -40
- 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
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { Component } from '../common/react-subx'
|
|
6
7
|
import { Modal, Button } from 'antd'
|
|
7
8
|
import { isString } from 'lodash-es'
|
|
8
9
|
import AnimateText from '../common/animate-text'
|
|
@@ -23,42 +24,51 @@ function formatTimeAuto (strOrDigit) {
|
|
|
23
24
|
return formatTime(strOrDigit * 1000)
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
export default
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
modifyTime: modifyTimeTo,
|
|
43
|
-
size: sizeTo,
|
|
44
|
-
type: typeTo
|
|
45
|
-
},
|
|
46
|
-
id,
|
|
47
|
-
transferGroupId
|
|
48
|
-
} = props.transferToConfirm
|
|
49
|
-
function act (action) {
|
|
50
|
-
props.modifier({
|
|
51
|
-
transferToConfirm: null
|
|
52
|
-
})
|
|
27
|
+
export default class ConfirmModalStore extends Component {
|
|
28
|
+
act (action) {
|
|
29
|
+
const { store } = this.props
|
|
30
|
+
const {
|
|
31
|
+
transferToConfirm
|
|
32
|
+
} = store
|
|
33
|
+
store.setState(
|
|
34
|
+
'transferToConfirm', {}
|
|
35
|
+
)
|
|
36
|
+
const {
|
|
37
|
+
fromFile: {
|
|
38
|
+
id: fileId
|
|
39
|
+
},
|
|
40
|
+
id,
|
|
41
|
+
transferGroupId
|
|
42
|
+
} = transferToConfirm
|
|
53
43
|
postMessage({
|
|
54
44
|
transferGroupId,
|
|
55
45
|
fileId,
|
|
56
46
|
id,
|
|
57
|
-
transfer:
|
|
47
|
+
transfer: transferToConfirm,
|
|
58
48
|
action
|
|
59
49
|
})
|
|
60
50
|
}
|
|
61
|
-
|
|
51
|
+
|
|
52
|
+
renderContent () {
|
|
53
|
+
const {
|
|
54
|
+
transferToConfirm
|
|
55
|
+
} = this.props.store
|
|
56
|
+
const {
|
|
57
|
+
fromPath,
|
|
58
|
+
toPath,
|
|
59
|
+
fromFile: {
|
|
60
|
+
isDirectory,
|
|
61
|
+
name,
|
|
62
|
+
modifyTime: modifyTimeFrom,
|
|
63
|
+
size: sizeFrom,
|
|
64
|
+
type: typeFrom
|
|
65
|
+
},
|
|
66
|
+
toFile: {
|
|
67
|
+
modifyTime: modifyTimeTo,
|
|
68
|
+
size: sizeTo,
|
|
69
|
+
type: typeTo
|
|
70
|
+
}
|
|
71
|
+
} = transferToConfirm
|
|
62
72
|
const action = isDirectory ? e('merge') : e('replace')
|
|
63
73
|
const typeTxt = isDirectory ? e('folder') : e('file')
|
|
64
74
|
const Icon = isDirectory ? FolderOutlined : FileOutlined
|
|
@@ -95,27 +105,39 @@ export default (props) => {
|
|
|
95
105
|
</div>
|
|
96
106
|
)
|
|
97
107
|
}
|
|
98
|
-
|
|
108
|
+
|
|
109
|
+
renderFooter () {
|
|
110
|
+
const {
|
|
111
|
+
transferToConfirm
|
|
112
|
+
} = this.props.store
|
|
113
|
+
if (!transferToConfirm) {
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
const {
|
|
117
|
+
fromFile: {
|
|
118
|
+
isDirectory
|
|
119
|
+
}
|
|
120
|
+
} = transferToConfirm
|
|
99
121
|
return (
|
|
100
122
|
<div className='mgq1t pd1y alignright'>
|
|
101
123
|
<Button
|
|
102
124
|
type='dashed'
|
|
103
125
|
className='mg1l'
|
|
104
|
-
onClick={() => act(fileActions.cancel)}
|
|
126
|
+
onClick={() => this.act(fileActions.cancel)}
|
|
105
127
|
>
|
|
106
128
|
{e('cancel')}
|
|
107
129
|
</Button>
|
|
108
130
|
<Button
|
|
109
131
|
type='dashed'
|
|
110
132
|
className='mg1l'
|
|
111
|
-
onClick={() => act(fileActions.skip)}
|
|
133
|
+
onClick={() => this.act(fileActions.skip)}
|
|
112
134
|
>
|
|
113
135
|
{e('skip')}
|
|
114
136
|
</Button>
|
|
115
137
|
<Button
|
|
116
138
|
type='dashed'
|
|
117
139
|
className='mg1l'
|
|
118
|
-
onClick={() => act(fileActions.skipAll)}
|
|
140
|
+
onClick={() => this.act(fileActions.skipAll)}
|
|
119
141
|
>
|
|
120
142
|
{e('skipAll')}
|
|
121
143
|
</Button>
|
|
@@ -123,7 +145,7 @@ export default (props) => {
|
|
|
123
145
|
danger
|
|
124
146
|
className='mg1l'
|
|
125
147
|
onClick={
|
|
126
|
-
() => act(fileActions.mergeOrOverwrite)
|
|
148
|
+
() => this.act(fileActions.mergeOrOverwrite)
|
|
127
149
|
}
|
|
128
150
|
>
|
|
129
151
|
{isDirectory ? e('merge') : e('overwrite')}
|
|
@@ -132,7 +154,7 @@ export default (props) => {
|
|
|
132
154
|
type='primary'
|
|
133
155
|
className='mg1l'
|
|
134
156
|
onClick={
|
|
135
|
-
() => act(fileActions.rename)
|
|
157
|
+
() => this.act(fileActions.rename)
|
|
136
158
|
}
|
|
137
159
|
>
|
|
138
160
|
{e('rename')}
|
|
@@ -148,7 +170,7 @@ export default (props) => {
|
|
|
148
170
|
: e('overwriteDesc')
|
|
149
171
|
}
|
|
150
172
|
onClick={
|
|
151
|
-
() => act(fileActions.mergeOrOverwriteAll)
|
|
173
|
+
() => this.act(fileActions.mergeOrOverwriteAll)
|
|
152
174
|
}
|
|
153
175
|
>
|
|
154
176
|
{isDirectory ? e('mergeAll') : e('overwriteAll')}
|
|
@@ -158,7 +180,7 @@ export default (props) => {
|
|
|
158
180
|
className='mg1l'
|
|
159
181
|
title={e('renameDesc')}
|
|
160
182
|
onClick={
|
|
161
|
-
() => act(fileActions.renameAll)
|
|
183
|
+
() => this.act(fileActions.renameAll)
|
|
162
184
|
}
|
|
163
185
|
>
|
|
164
186
|
{e('renameAll')}
|
|
@@ -167,18 +189,27 @@ export default (props) => {
|
|
|
167
189
|
</div>
|
|
168
190
|
)
|
|
169
191
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
192
|
+
|
|
193
|
+
render () {
|
|
194
|
+
const {
|
|
195
|
+
transferToConfirm
|
|
196
|
+
} = this.props.store
|
|
197
|
+
if (!transferToConfirm.id) {
|
|
198
|
+
return null
|
|
199
|
+
}
|
|
200
|
+
const modalProps = {
|
|
201
|
+
open: true,
|
|
202
|
+
width: 500,
|
|
203
|
+
title: e('fileConflict'),
|
|
204
|
+
footer: this.renderFooter(),
|
|
205
|
+
onCancel: () => this.act(fileActions.cancel)
|
|
206
|
+
}
|
|
207
|
+
return (
|
|
208
|
+
<Modal
|
|
209
|
+
{...modalProps}
|
|
210
|
+
>
|
|
211
|
+
{this.renderContent()}
|
|
212
|
+
</Modal>
|
|
213
|
+
)
|
|
176
214
|
}
|
|
177
|
-
return (
|
|
178
|
-
<Modal
|
|
179
|
-
{...modalProps}
|
|
180
|
-
>
|
|
181
|
-
{renderContent()}
|
|
182
|
-
</Modal>
|
|
183
|
-
)
|
|
184
215
|
}
|
|
@@ -168,6 +168,7 @@ export default class FileSection extends React.Component {
|
|
|
168
168
|
fromPath,
|
|
169
169
|
toPath,
|
|
170
170
|
id: generate(),
|
|
171
|
+
host: this.props.tab?.host,
|
|
171
172
|
...createTransferProps(this.props),
|
|
172
173
|
operation
|
|
173
174
|
})
|
|
@@ -804,6 +805,7 @@ export default class FileSection extends React.Component {
|
|
|
804
805
|
}
|
|
805
806
|
toPath = resolve(toPath, name)
|
|
806
807
|
const obj = {
|
|
808
|
+
host: this.props.tab?.host,
|
|
807
809
|
typeFrom: type,
|
|
808
810
|
typeTo,
|
|
809
811
|
fromPath: resolve(path, name),
|
|
@@ -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 = () => {
|
|
@@ -568,10 +574,14 @@ export default class Sftp extends Component {
|
|
|
568
574
|
return arr.map(item => {
|
|
569
575
|
const { type } = item
|
|
570
576
|
return {
|
|
571
|
-
...pick(
|
|
577
|
+
...pick(
|
|
578
|
+
item,
|
|
579
|
+
['name', 'size', 'accessTime', 'modifyTime', 'mode', 'owner', 'group']
|
|
580
|
+
),
|
|
572
581
|
isDirectory: type === fileTypeMap.directory,
|
|
573
582
|
type: typeMap.remote,
|
|
574
583
|
path: remotePath,
|
|
584
|
+
isSymbol: type === fileTypeMap.link,
|
|
575
585
|
id: generate()
|
|
576
586
|
}
|
|
577
587
|
})
|
|
@@ -711,8 +721,8 @@ export default class Sftp extends Component {
|
|
|
711
721
|
) => {
|
|
712
722
|
const remote = []
|
|
713
723
|
for (const r of remotes) {
|
|
714
|
-
const {
|
|
715
|
-
if (
|
|
724
|
+
const { name } = r
|
|
725
|
+
if (r.isSymbol) {
|
|
716
726
|
const linkPath = resolve(remotePath, name)
|
|
717
727
|
let realpath = await sftp.readlink(linkPath)
|
|
718
728
|
.catch(e => {
|
|
@@ -902,11 +912,8 @@ export default class Sftp extends Component {
|
|
|
902
912
|
typeMap.remote,
|
|
903
913
|
'lastClickedFile',
|
|
904
914
|
'lastMataKey',
|
|
905
|
-
'transferToConfirm',
|
|
906
|
-
'transferList',
|
|
907
915
|
'targetTransferType',
|
|
908
916
|
'selectedFiles',
|
|
909
|
-
'pauseAll',
|
|
910
917
|
'localGidTree',
|
|
911
918
|
'remoteUidTree',
|
|
912
919
|
'localUidTree',
|
|
@@ -1104,18 +1111,6 @@ export default class Sftp extends Component {
|
|
|
1104
1111
|
const {
|
|
1105
1112
|
id
|
|
1106
1113
|
} = this.state
|
|
1107
|
-
const prps = {
|
|
1108
|
-
localList: this.localList,
|
|
1109
|
-
remoteList: this.remoteList,
|
|
1110
|
-
sftp: this.sftp,
|
|
1111
|
-
sessionId: this.props.sessionId,
|
|
1112
|
-
host: this.props.tab.host,
|
|
1113
|
-
localListDebounce: this.localListDebounce,
|
|
1114
|
-
remoteListDebounce: this.remoteListDebounce,
|
|
1115
|
-
config: this.props.config,
|
|
1116
|
-
tab: this.props.tab,
|
|
1117
|
-
pid: this.props.pid
|
|
1118
|
-
}
|
|
1119
1114
|
const all = {
|
|
1120
1115
|
className: 'sftp-wrap overhide relative',
|
|
1121
1116
|
id: `id-${id}`,
|
|
@@ -1128,7 +1123,6 @@ export default class Sftp extends Component {
|
|
|
1128
1123
|
{
|
|
1129
1124
|
this.renderSections()
|
|
1130
1125
|
}
|
|
1131
|
-
<TransportEntry {...prps} />
|
|
1132
1126
|
</div>
|
|
1133
1127
|
)
|
|
1134
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
|
+
}
|