@electerm/electerm-react 1.72.48 → 1.80.2
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 -1
- package/client/common/sftp.js +3 -1
- package/client/components/ai/ai-config.jsx +7 -1
- package/client/components/batch-op/batch-op.jsx +4 -5
- package/client/components/bg/css-overwrite.jsx +179 -0
- package/client/components/bg/shapes.js +501 -0
- package/client/components/bookmark-form/form-tabs.jsx +1 -0
- package/client/components/bookmark-form/local-form-ui.jsx +7 -1
- package/client/components/bookmark-form/render-bg.jsx +43 -0
- package/client/components/bookmark-form/serial-form-ui.jsx +7 -1
- package/client/components/bookmark-form/ssh-form-ui.jsx +14 -3
- package/client/components/bookmark-form/telnet-form-ui.jsx +7 -1
- package/client/components/bookmark-form/use-ui.jsx +68 -72
- package/client/components/common/ref.js +2 -0
- package/client/components/{sftp/confirm-modal-store.jsx → file-transfer/conflict-resolve.jsx} +86 -48
- package/client/components/file-transfer/transfer-queue.jsx +151 -0
- package/client/components/file-transfer/transfer.jsx +582 -0
- package/client/components/{sftp → file-transfer}/transports-action-store.jsx +35 -32
- package/client/components/{sftp → file-transfer}/transports-ui-store.jsx +2 -2
- package/client/components/main/main.jsx +25 -18
- package/client/components/main/wrapper.styl +16 -0
- package/client/components/profile/profile-list.jsx +1 -1
- package/client/components/quick-commands/qm.styl +4 -1
- package/client/components/quick-commands/quick-commands-list.jsx +16 -4
- package/client/components/setting-panel/list.jsx +1 -1
- package/client/components/setting-panel/setting-terminal.jsx +2 -1
- package/client/components/setting-panel/terminal-bg-config.jsx +15 -2
- package/client/components/sftp/file-info-modal.jsx +3 -0
- package/client/components/sftp/file-item.jsx +25 -23
- package/client/components/sftp/file-read.js +1 -27
- package/client/components/sftp/list-table-ui.jsx +2 -2
- package/client/components/sidebar/transfer-history-modal.jsx +1 -1
- package/client/components/sidebar/transfer-list-control.jsx +1 -1
- package/client/components/sidebar/transport-ui.jsx +16 -9
- package/client/components/terminal/terminal.jsx +23 -1
- package/client/components/text-editor/simple-editor.jsx +164 -0
- package/client/components/text-editor/text-editor-form.jsx +6 -9
- package/client/css/includes/box.styl +2 -2
- package/client/store/tab.js +5 -1
- package/client/store/transfer-list.js +10 -51
- package/package.json +1 -1
- package/client/components/main/css-overwrite.jsx +0 -91
- package/client/components/sftp/transfer-conflict-store.jsx +0 -284
- package/client/components/sftp/transport-action-store.jsx +0 -422
- package/client/components/sftp/zip.js +0 -42
- /package/client/components/{main → bg}/custom-css.jsx +0 -0
- /package/client/components/{sftp → file-transfer}/transfer-speed-format.js +0 -0
- /package/client/components/{sftp → file-transfer}/transfer.styl +0 -0
|
@@ -26,76 +26,72 @@ export default function useBookmarkFormUI (props) {
|
|
|
26
26
|
fontFamily: defaultFontFamily,
|
|
27
27
|
fontSize: defaultFontSize
|
|
28
28
|
} = defaultSettings
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
step={1000}
|
|
98
|
-
/>
|
|
99
|
-
</FormItem>
|
|
100
|
-
]
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
<FormItem
|
|
32
|
+
{...formItemLayout}
|
|
33
|
+
label='ENV:LANG'
|
|
34
|
+
rules={[{
|
|
35
|
+
max: 130, message: '130 chars max'
|
|
36
|
+
}]}
|
|
37
|
+
name='envLang'
|
|
38
|
+
>
|
|
39
|
+
<Input placeholder={defaultEnvLang} />
|
|
40
|
+
</FormItem>,
|
|
41
|
+
<FormItem
|
|
42
|
+
{...formItemLayout}
|
|
43
|
+
label={e('terminalType')}
|
|
44
|
+
rules={[{
|
|
45
|
+
required: true, message: 'terminal type required'
|
|
46
|
+
}]}
|
|
47
|
+
normalize={props.trim}
|
|
48
|
+
name='term'
|
|
49
|
+
>
|
|
50
|
+
<AutoComplete
|
|
51
|
+
options={terminalTypes.map(mapper)}
|
|
52
|
+
/>
|
|
53
|
+
</FormItem>,
|
|
54
|
+
<FormItem
|
|
55
|
+
{...formItemLayout}
|
|
56
|
+
label={e('displayRaw')}
|
|
57
|
+
name='displayRaw'
|
|
58
|
+
valuePropName='checked'
|
|
59
|
+
>
|
|
60
|
+
<Switch />
|
|
61
|
+
</FormItem>,
|
|
62
|
+
<FormItem
|
|
63
|
+
{...formItemLayout}
|
|
64
|
+
label={e('fontFamily')}
|
|
65
|
+
name='fontFamily'
|
|
66
|
+
rules={[{
|
|
67
|
+
max: 130, message: '130 chars max'
|
|
68
|
+
}]}
|
|
69
|
+
>
|
|
70
|
+
<Input placeholder={defaultFontFamily + ''} />
|
|
71
|
+
</FormItem>,
|
|
72
|
+
<FormItem
|
|
73
|
+
{...formItemLayout}
|
|
74
|
+
label={e('fontSize')}
|
|
75
|
+
name='fontSize'
|
|
76
|
+
>
|
|
77
|
+
<InputNumber
|
|
78
|
+
min={9}
|
|
79
|
+
max={65535}
|
|
80
|
+
step={1}
|
|
81
|
+
placeholder={defaultFontSize}
|
|
82
|
+
/>
|
|
83
|
+
</FormItem>,
|
|
84
|
+
<FormItem
|
|
85
|
+
{...formItemLayout}
|
|
86
|
+
label={e('keepaliveIntervalDesc')}
|
|
87
|
+
name='keepaliveInterval'
|
|
88
|
+
>
|
|
89
|
+
<InputNumber
|
|
90
|
+
min={0}
|
|
91
|
+
max={20000000}
|
|
92
|
+
step={1000}
|
|
93
|
+
/>
|
|
94
|
+
</FormItem>
|
|
95
|
+
</>
|
|
96
|
+
)
|
|
101
97
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// components instance reference holder
|
|
2
2
|
window.refs = new Map()
|
|
3
3
|
window.refsStatic = new Map()
|
|
4
|
+
window.refsTransfers = new Map()
|
|
4
5
|
|
|
5
6
|
class Ref {
|
|
6
7
|
constructor (key) {
|
|
@@ -21,4 +22,5 @@ class Ref {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export const refs = new Ref('refs')
|
|
25
|
+
export const refsTransfers = new Ref('refsTransfers')
|
|
24
26
|
export const refsStatic = new Ref('refsStatic')
|
package/client/components/{sftp/confirm-modal-store.jsx → file-transfer/conflict-resolve.jsx}
RENAMED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { Component } from 'react'
|
|
6
7
|
import { Modal, Button } from 'antd'
|
|
7
8
|
import { isString } from 'lodash-es'
|
|
8
9
|
import AnimateText from '../common/animate-text'
|
|
@@ -11,8 +12,7 @@ import { FolderOutlined, FileOutlined } from '@ant-design/icons'
|
|
|
11
12
|
import {
|
|
12
13
|
fileActions
|
|
13
14
|
} from '../../common/constants'
|
|
14
|
-
import
|
|
15
|
-
import { refsStatic } from '../common/ref'
|
|
15
|
+
import { refsStatic, refsTransfers } from '../common/ref'
|
|
16
16
|
|
|
17
17
|
const e = window.translate
|
|
18
18
|
|
|
@@ -23,30 +23,66 @@ function formatTimeAuto (strOrDigit) {
|
|
|
23
23
|
return formatTime(strOrDigit * 1000)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export default
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
export default class ConfirmModalStore extends Component {
|
|
27
|
+
constructor (props) {
|
|
28
|
+
super(props)
|
|
29
|
+
this.state = {
|
|
30
|
+
transferToConfirm: null
|
|
31
|
+
}
|
|
32
|
+
this.queue = []
|
|
33
|
+
this.id = 'transfer-conflict'
|
|
34
|
+
refsStatic.add(this.id, this)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
addConflict = (transfer) => {
|
|
38
|
+
this.queue.push(transfer)
|
|
39
|
+
if (!this.state.transferToConfirm) {
|
|
40
|
+
this.showNext()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
showNext = () => {
|
|
45
|
+
const next = this.queue.shift()
|
|
46
|
+
this.setState({
|
|
47
|
+
transferToConfirm: next
|
|
43
48
|
})
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
act = (action) => {
|
|
52
|
+
const { id, transferBatch } = this.state.transferToConfirm
|
|
53
|
+
const toAll = action.includes('All')
|
|
54
|
+
const policy = toAll ? action.replace('All', '') : action
|
|
55
|
+
const trid = `tr-${transferBatch}-${id}`
|
|
56
|
+
const doFilter = toAll && transferBatch
|
|
57
|
+
|
|
58
|
+
// For "All" actions, update all existing transfers in the same batch
|
|
59
|
+
if (doFilter) {
|
|
60
|
+
// Update all existing transfers with same batch ID in DOM
|
|
61
|
+
const prefix = `tr-${transferBatch}-`
|
|
62
|
+
for (const [key, r] of window.refsTransfers.entries()) {
|
|
63
|
+
if (key.startsWith(prefix)) {
|
|
64
|
+
if (key !== trid) {
|
|
65
|
+
r.resolvePolicy = policy
|
|
66
|
+
r.onDecision(policy)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
this.queue = this.queue.filter(d => d.transferBatch !== transferBatch)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Resolve current conflict
|
|
74
|
+
refsTransfers.get(trid)?.onDecision(policy)
|
|
75
|
+
|
|
76
|
+
// Move to the next item
|
|
77
|
+
this.setState({
|
|
78
|
+
transferToConfirm: null
|
|
79
|
+
}, this.showNext)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
renderContent () {
|
|
47
83
|
const {
|
|
48
84
|
transferToConfirm
|
|
49
|
-
} =
|
|
85
|
+
} = this.state
|
|
50
86
|
const {
|
|
51
87
|
fromPath,
|
|
52
88
|
toPath,
|
|
@@ -100,10 +136,10 @@ export default function ConfirmModalStore (props) {
|
|
|
100
136
|
)
|
|
101
137
|
}
|
|
102
138
|
|
|
103
|
-
|
|
139
|
+
renderFooter () {
|
|
104
140
|
const {
|
|
105
141
|
transferToConfirm
|
|
106
|
-
} =
|
|
142
|
+
} = this.state
|
|
107
143
|
if (!transferToConfirm) {
|
|
108
144
|
return null
|
|
109
145
|
}
|
|
@@ -117,14 +153,14 @@ export default function ConfirmModalStore (props) {
|
|
|
117
153
|
<Button
|
|
118
154
|
type='dashed'
|
|
119
155
|
className='mg1l'
|
|
120
|
-
onClick={() => act(fileActions.cancel)}
|
|
156
|
+
onClick={() => this.act(fileActions.cancel)}
|
|
121
157
|
>
|
|
122
158
|
{e('cancel')}
|
|
123
159
|
</Button>
|
|
124
160
|
<Button
|
|
125
161
|
type='dashed'
|
|
126
162
|
className='mg1l'
|
|
127
|
-
onClick={() => act(fileActions.skip)}
|
|
163
|
+
onClick={() => this.act(fileActions.skip)}
|
|
128
164
|
>
|
|
129
165
|
{e('skip')}
|
|
130
166
|
</Button>
|
|
@@ -132,7 +168,7 @@ export default function ConfirmModalStore (props) {
|
|
|
132
168
|
danger
|
|
133
169
|
className='mg1l'
|
|
134
170
|
onClick={
|
|
135
|
-
() => act(fileActions.mergeOrOverwrite)
|
|
171
|
+
() => this.act(fileActions.mergeOrOverwrite)
|
|
136
172
|
}
|
|
137
173
|
>
|
|
138
174
|
{isDirectory ? e('merge') : e('overwrite')}
|
|
@@ -141,7 +177,7 @@ export default function ConfirmModalStore (props) {
|
|
|
141
177
|
type='primary'
|
|
142
178
|
className='mg1l'
|
|
143
179
|
onClick={
|
|
144
|
-
() => act(fileActions.rename)
|
|
180
|
+
() => this.act(fileActions.rename)
|
|
145
181
|
}
|
|
146
182
|
>
|
|
147
183
|
{e('rename')}
|
|
@@ -157,7 +193,7 @@ export default function ConfirmModalStore (props) {
|
|
|
157
193
|
: e('overwriteDesc')
|
|
158
194
|
}
|
|
159
195
|
onClick={
|
|
160
|
-
() => act(fileActions.mergeOrOverwriteAll)
|
|
196
|
+
() => this.act(fileActions.mergeOrOverwriteAll)
|
|
161
197
|
}
|
|
162
198
|
>
|
|
163
199
|
{isDirectory ? e('mergeAll') : e('overwriteAll')}
|
|
@@ -167,7 +203,7 @@ export default function ConfirmModalStore (props) {
|
|
|
167
203
|
className='mg1l'
|
|
168
204
|
title={e('renameDesc')}
|
|
169
205
|
onClick={
|
|
170
|
-
() => act(fileActions.renameAll)
|
|
206
|
+
() => this.act(fileActions.renameAll)
|
|
171
207
|
}
|
|
172
208
|
>
|
|
173
209
|
{e('renameAll')}
|
|
@@ -177,24 +213,26 @@ export default function ConfirmModalStore (props) {
|
|
|
177
213
|
)
|
|
178
214
|
}
|
|
179
215
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
216
|
+
render () {
|
|
217
|
+
const {
|
|
218
|
+
transferToConfirm
|
|
219
|
+
} = this.state
|
|
220
|
+
if (!transferToConfirm?.id) {
|
|
221
|
+
return null
|
|
222
|
+
}
|
|
223
|
+
const modalProps = {
|
|
224
|
+
open: true,
|
|
225
|
+
width: 500,
|
|
226
|
+
title: e('fileConflict'),
|
|
227
|
+
footer: this.renderFooter(),
|
|
228
|
+
onCancel: () => this.act(fileActions.cancel)
|
|
229
|
+
}
|
|
230
|
+
return (
|
|
231
|
+
<Modal
|
|
232
|
+
{...modalProps}
|
|
233
|
+
>
|
|
234
|
+
{this.renderContent()}
|
|
235
|
+
</Modal>
|
|
236
|
+
)
|
|
192
237
|
}
|
|
193
|
-
return (
|
|
194
|
-
<Modal
|
|
195
|
-
{...modalProps}
|
|
196
|
-
>
|
|
197
|
-
{renderContent()}
|
|
198
|
-
</Modal>
|
|
199
|
-
)
|
|
200
238
|
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Component } from 'react'
|
|
2
|
+
import { autoRun, action } from 'manate'
|
|
3
|
+
import { refsStatic } from '../common/ref'
|
|
4
|
+
|
|
5
|
+
export default class Queue extends Component {
|
|
6
|
+
constructor (props) {
|
|
7
|
+
super(props)
|
|
8
|
+
this.queue = []
|
|
9
|
+
this.currentRun = null
|
|
10
|
+
this.id = 'transfer-queue'
|
|
11
|
+
refsStatic.add(this.id, this)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
componentWillUnmount () {
|
|
15
|
+
if (this.currentRun) {
|
|
16
|
+
this.currentRun.stop()
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
addToQueue = (operation, ...args) => {
|
|
21
|
+
this.queue.push({ operation, args })
|
|
22
|
+
this.processQueue()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
processQueue = async () => {
|
|
26
|
+
if (this.queue.length === 0 || this.processing === true) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
this.processing = true
|
|
30
|
+
const { operation, args } = this.queue.shift()
|
|
31
|
+
|
|
32
|
+
await this.executeOperation(operation, ...args)
|
|
33
|
+
.catch((error) => {
|
|
34
|
+
console.error('Error processing operation:', error)
|
|
35
|
+
})
|
|
36
|
+
this.processing = false
|
|
37
|
+
this.processQueue()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
executeOperation = (operation, ...args) => {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const { fileTransfers } = window.store
|
|
43
|
+
const [id, updateObj] = args
|
|
44
|
+
const end = () => {
|
|
45
|
+
this.currentRun && this.currentRun.stop()
|
|
46
|
+
resolve()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Determine if this is a simple operation (same-side cp) vs a file transfer
|
|
50
|
+
const isTransferInit = updateObj && updateObj.inited === true
|
|
51
|
+
|
|
52
|
+
// For file transfers, set up autoRun before modifying data
|
|
53
|
+
if (isTransferInit) {
|
|
54
|
+
this.currentRun = autoRun(() => {
|
|
55
|
+
checkCompletion()
|
|
56
|
+
})
|
|
57
|
+
this.currentRun.start()
|
|
58
|
+
|
|
59
|
+
// Use setTimeout for transfer operations to give autoRun time to initialize
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
applyChanges()
|
|
62
|
+
}, 1)
|
|
63
|
+
} else {
|
|
64
|
+
// For same-side operations, just apply changes immediately
|
|
65
|
+
applyChanges()
|
|
66
|
+
|
|
67
|
+
// Still set up autoRun as a safety net, but we won't need it usually
|
|
68
|
+
this.currentRun = autoRun(() => {
|
|
69
|
+
checkCompletion()
|
|
70
|
+
})
|
|
71
|
+
this.currentRun.start()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function applyChanges () {
|
|
75
|
+
if (operation === 'update') {
|
|
76
|
+
const index = fileTransfers.findIndex(t => t.id === id)
|
|
77
|
+
if (index < 0) {
|
|
78
|
+
return end()
|
|
79
|
+
}
|
|
80
|
+
Object.assign(fileTransfers[index], updateObj)
|
|
81
|
+
} else if (operation === 'delete') {
|
|
82
|
+
const index = fileTransfers.findIndex(t => t.id === id)
|
|
83
|
+
if (index < 0) {
|
|
84
|
+
return end()
|
|
85
|
+
}
|
|
86
|
+
fileTransfers.splice(index, 1)
|
|
87
|
+
} else if (operation === 'insert') {
|
|
88
|
+
fileTransfers.push(id)
|
|
89
|
+
} else if (operation === 'moveTop') {
|
|
90
|
+
// New moveTop operation - wrapped with action
|
|
91
|
+
action(() => {
|
|
92
|
+
const index = fileTransfers.findIndex(t => t.id === id)
|
|
93
|
+
if (index < 0 || index === 0) {
|
|
94
|
+
return end() // Already at top or doesn't exist
|
|
95
|
+
}
|
|
96
|
+
const transfer = fileTransfers[index]
|
|
97
|
+
fileTransfers.splice(index, 1) // Remove from current position
|
|
98
|
+
fileTransfers.unshift(transfer) // Add to the beginning
|
|
99
|
+
})()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// For non-transfer operations, check immediately
|
|
103
|
+
// if (!isTransferInit) {
|
|
104
|
+
// checkCompletion()
|
|
105
|
+
// }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function checkCompletion () {
|
|
109
|
+
if (operation === 'update') {
|
|
110
|
+
const index = window.store.fileTransfers.findIndex(t => t.id === id)
|
|
111
|
+
const updatedTransfer = index >= 0 ? window.store.fileTransfers[index] : null
|
|
112
|
+
|
|
113
|
+
if (updatedTransfer && updateObj) {
|
|
114
|
+
const allUpdated = Object.keys(updateObj).every(key => {
|
|
115
|
+
const updatedValue = updatedTransfer[key]
|
|
116
|
+
const expectedValue = updateObj[key]
|
|
117
|
+
|
|
118
|
+
if (expectedValue && typeof expectedValue === 'object') {
|
|
119
|
+
return updatedValue !== undefined
|
|
120
|
+
}
|
|
121
|
+
return updatedValue === expectedValue
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
if (allUpdated) {
|
|
125
|
+
end()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} else if (operation === 'delete') {
|
|
129
|
+
const stillExists = window.store.fileTransfers.some(t => t.id === id)
|
|
130
|
+
if (!stillExists) {
|
|
131
|
+
end()
|
|
132
|
+
}
|
|
133
|
+
} else if (operation === 'insert') {
|
|
134
|
+
const exists = window.store.fileTransfers.some(t => t.id === id)
|
|
135
|
+
if (exists) {
|
|
136
|
+
end()
|
|
137
|
+
}
|
|
138
|
+
} else if (operation === 'moveTop') {
|
|
139
|
+
const index = window.store.fileTransfers.findIndex(t => t.id === id)
|
|
140
|
+
if (index === 0) {
|
|
141
|
+
end()
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
render () {
|
|
149
|
+
return null // This component doesn't render anything
|
|
150
|
+
}
|
|
151
|
+
}
|