@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.
Files changed (35) hide show
  1. package/client/common/constants.js +3 -2
  2. package/client/common/create-title.jsx +9 -1
  3. package/client/common/sftp.js +3 -0
  4. package/client/components/batch-op/batch-op.jsx +1 -6
  5. package/client/components/bookmark-form/bookmark-form.styl +3 -1
  6. package/client/components/bookmark-form/render-ssh-tunnel.jsx +210 -88
  7. package/client/components/bookmark-form/ssh-form-ui.jsx +1 -1
  8. package/client/components/main/main.jsx +14 -0
  9. package/client/components/sftp/{confirm-modal.jsx → confirm-modal-store.jsx} +81 -50
  10. package/client/components/sftp/file-item.jsx +2 -0
  11. package/client/components/sftp/sftp-entry.jsx +27 -37
  12. package/client/components/sftp/transfer-conflict-store.jsx +291 -0
  13. package/client/components/sftp/transport-action-store.jsx +430 -0
  14. package/client/components/sftp/transports-action-store.jsx +102 -0
  15. package/client/components/sftp/transports-ui-store.jsx +30 -0
  16. package/client/components/sidebar/transfer-list-control.jsx +5 -14
  17. package/client/components/sidebar/transport-ui.jsx +2 -12
  18. package/client/components/tabs/tab.jsx +43 -2
  19. package/client/components/tabs/tabs.styl +1 -1
  20. package/client/components/terminal/index.jsx +1 -0
  21. package/client/components/terminal/terminal-interactive.jsx +15 -0
  22. package/client/components/terminal-info/disk.jsx +9 -0
  23. package/client/store/index.js +4 -0
  24. package/client/store/init-state.js +2 -3
  25. package/client/store/sync.js +5 -2
  26. package/client/store/tab.js +1 -1
  27. package/client/store/transfer-list.js +55 -2
  28. package/client/store/watch.js +0 -8
  29. package/package.json +1 -1
  30. package/client/components/sftp/transfer-conflict.jsx +0 -323
  31. package/client/components/sftp/transport-action.jsx +0 -412
  32. package/client/components/sftp/transport-entry.jsx +0 -108
  33. package/client/components/sftp/transport-types.js +0 -8
  34. package/client/components/sftp/transports-action.jsx +0 -111
  35. package/client/components/sftp/transports-ui.jsx +0 -93
@@ -151,7 +151,7 @@
151
151
  position absolute
152
152
  right 0
153
153
  top 0
154
- z-index 200
154
+ z-index 900
155
155
  border-radius 0 0 3px 3px
156
156
  padding 0
157
157
  background main-light
@@ -1110,6 +1110,7 @@ class Term extends Component {
1110
1110
  ]),
1111
1111
  sessionId,
1112
1112
  tabId: id,
1113
+ srcTabId: tab.id,
1113
1114
  terminalIndex,
1114
1115
  termType,
1115
1116
  readyTimeout: config.sshReadyTimeout,
@@ -5,7 +5,9 @@
5
5
  import { useEffect, useState } from 'react'
6
6
  import { Modal, Form, Button } from 'antd'
7
7
  import InputAutoFocus from '../common/input-auto-focus'
8
+ import { tabActions } from '../../common/constants'
8
9
  import wait from '../../common/wait'
10
+ import postMsg from '../../common/post-msg'
9
11
 
10
12
  const { prefix } = window
11
13
  const e = prefix('sftp')
@@ -16,6 +18,13 @@ export default function TermInteractive () {
16
18
  const [trigger] = useState(0)
17
19
  const [opts, setter] = useState(null)
18
20
  const [form] = Form.useForm()
21
+ function updateTab (data) {
22
+ postMsg({
23
+ action: tabActions.updateTabs,
24
+ id: data.tabId,
25
+ update: data.update
26
+ })
27
+ }
19
28
  function onMsg (e) {
20
29
  if (
21
30
  e &&
@@ -24,6 +33,12 @@ export default function TermInteractive () {
24
33
  e.data.includes('session-interactive')
25
34
  ) {
26
35
  setter(JSON.parse(e.data))
36
+ } else if (
37
+ e &&
38
+ e.data &&
39
+ e.data.includes('ssh-tunnel-result')
40
+ ) {
41
+ updateTab(JSON.parse(e.data))
27
42
  }
28
43
  }
29
44
  function clear () {
@@ -13,6 +13,15 @@ export default function TerminalInfoDisk (props) {
13
13
  return null
14
14
  }
15
15
  const col = colsParser(disks[0])
16
+ disks.sort((a, b) => {
17
+ if (a.filesystem.startsWith('/') && !b.filesystem.startsWith('/')) {
18
+ return -1
19
+ }
20
+ if (!a.filesystem.startsWith('/') && b.filesystem.startsWith('/')) {
21
+ return 1
22
+ }
23
+ return 0
24
+ })
16
25
  const ps = {
17
26
  rowKey: (rec) => `${rec.mount}_${rec.filesystem}`,
18
27
  dataSource: disks,
@@ -233,6 +233,10 @@ class Store {
233
233
  return JSON.parse(window.store._upgradeInfo)
234
234
  }
235
235
 
236
+ get transferToConfirm () {
237
+ return JSON.parse(window.store._transferToConfirm)
238
+ }
239
+
236
240
  get settingItem () {
237
241
  return JSON.parse(window.store._settingItem)
238
242
  }
@@ -92,9 +92,11 @@ export default () => {
92
92
 
93
93
  // sftp
94
94
  fileOperation: fileOperationsMap.cp, // cp or mv
95
+ pauseAllTransfer: false,
95
96
  transferTab: 'transfer',
96
97
  _transferHistory: '[]',
97
98
  _fileTransfers: '[]',
99
+ _transferToConfirm: '{}',
98
100
  _sftpSortSetting: ls.getItem(sftpDefaultSortSettingKey) || JSON.stringify({
99
101
  local: {
100
102
  prop: 'modifyTime',
@@ -169,9 +171,6 @@ export default () => {
169
171
  _serials: '[]',
170
172
  loaddingSerials: false,
171
173
 
172
- // transfer list
173
- transports: [],
174
-
175
174
  _sshConfigItems: '[]',
176
175
 
177
176
  appPath: '',
@@ -12,6 +12,7 @@ import fetch from '../common/fetch-from-server'
12
12
  import download from '../common/download'
13
13
  import { fixBookmarks } from '../common/db-fix'
14
14
  import dayjs from 'dayjs'
15
+ import parseJsonSafe from '../common/parse-json-safe'
15
16
 
16
17
  const names = without(dbNames, settingMap.history)
17
18
  const {
@@ -262,10 +263,12 @@ export default (Store) => {
262
263
  })
263
264
  store.setItems(n, arr)
264
265
  }
265
- const userConfig = JSON.parse(
266
+ const userConfig = parseJsonSafe(
266
267
  get(gist, 'files["userConfig.json"].content')
267
268
  )
268
- store.setTheme(userConfig.theme)
269
+ if (userConfig && userConfig.theme) {
270
+ store.setTheme(userConfig.theme)
271
+ }
269
272
  const up = {
270
273
  [type + 'LastSyncTime']: Date.now()
271
274
  }
@@ -11,7 +11,7 @@ import postMsg from '../common/post-msg'
11
11
  export default Store => {
12
12
  Store.prototype.updateTabsStatus = function () {
13
13
  const tabIds = uniq(
14
- window.store.getTransfers().map(d => d.tabId)
14
+ window.store.fileTransfers.map(d => d.tabId)
15
15
  )
16
16
  postMsg({
17
17
  action: tabActions.updateTabsStatus,
@@ -4,10 +4,9 @@ export default Store => {
4
4
  window.store.transferTab = tab
5
5
  }
6
6
 
7
- // should update any item with same id in oldList from list array, should add any new item from list array to oldList, should remove any item with same id and sessionId in oldList but not in list array
8
7
  Store.prototype.setTransfers = function (list, _sessId) {
9
8
  const { store } = window
10
- let oldList = store.getTransfers()
9
+ let oldList = store.fileTransfers
11
10
  const sessId = _sessId || list[0].sessionId
12
11
  const arr2 = oldList.filter(t => {
13
12
  return t.sessionId === sessId
@@ -48,4 +47,58 @@ export default Store => {
48
47
  Store.prototype.addTransfers = function (objs) {
49
48
  return window.store.addItems(objs, 'fileTransfers')
50
49
  }
50
+ Store.prototype.setFileTransfers = function (objs) {
51
+ return window.store.setState('fileTransfers', objs)
52
+ }
53
+ Store.prototype.addTransferList = function (objs) {
54
+ const { store } = window
55
+ store.setFileTransfers([
56
+ ...store.fileTransfers,
57
+ ...objs
58
+ ])
59
+ }
60
+ Store.prototype.toggleTransfer = function (itemId) {
61
+ const { store } = window
62
+ const { fileTransfers } = store
63
+ const index = findIndex(fileTransfers, t => t.id === itemId)
64
+ if (index < 0) {
65
+ return
66
+ }
67
+ fileTransfers[index].pausing = !fileTransfers[index].pausing
68
+ store.setFileTransfers(fileTransfers)
69
+ }
70
+
71
+ Store.prototype.pauseAll = function () {
72
+ const { store } = window
73
+ store.pauseAllTransfer = true
74
+ store.setFileTransfers(store.fileTransfers.map(t => {
75
+ t.pausing = true
76
+ return t
77
+ }))
78
+ }
79
+ Store.prototype.resumeAll = function () {
80
+ const { store } = window
81
+ store.pauseAllTransfer = false
82
+ store.setFileTransfers(store.fileTransfers.map(t => {
83
+ t.pausing = false
84
+ return t
85
+ }))
86
+ }
87
+ Store.prototype.cancelAll = function () {
88
+ const { store } = window
89
+ store.setFileTransfers(store.fileTransfers.map(t => {
90
+ t.cancel = true
91
+ return t
92
+ }))
93
+ }
94
+ Store.prototype.cancelTransfer = function (itemId) {
95
+ const { store } = window
96
+ const { fileTransfers } = store
97
+ const index = findIndex(fileTransfers, t => t.id === itemId)
98
+ if (index < 0) {
99
+ return
100
+ }
101
+ fileTransfers[index].cancel = true
102
+ store.setFileTransfers(fileTransfers)
103
+ }
51
104
  }
@@ -33,14 +33,6 @@ export default store => {
33
33
  // return store.menuOpened
34
34
  // })
35
35
 
36
- // autoRun(store, () => {
37
- // const v = store.getItems('tabs').map(t => {
38
- // delete t.isTransporting
39
- // return t
40
- // })
41
- // update('sessions', v)
42
- // return store._tabs
43
- // }, func => debounce(func, 100))
44
36
  for (const name of dbNamesForWatch) {
45
37
  autoRun(store, async () => {
46
38
  await update(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "1.38.65",
3
+ "version": "1.38.70",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",
@@ -1,323 +0,0 @@
1
- /**
2
- * pass transfer list from props
3
- * when list changes, do transfer and other op
4
- */
5
-
6
- import { useRef } from 'react'
7
- import { useDelta, useConditionalEffect } from 'react-delta'
8
- import { maxTransport, typeMap } from '../../common/constants'
9
- import {
10
- getLocalFileInfo,
11
- getRemoteFileInfo,
12
- getFolderFromFilePath,
13
- getFileExt,
14
- checkFolderSize
15
- } from './file-read'
16
- import copy from 'json-deep-copy'
17
- import { findIndex, find } from 'lodash-es'
18
- import generate from '../../common/uid'
19
- import resolve from '../../common/resolve'
20
- import eq from 'fast-deep-equal'
21
- import { createTransferProps } from './transfer-common'
22
-
23
- export default (props) => {
24
- const { transferList, sessionId } = props
25
- const delta = useDelta(transferList)
26
- const currentId = useRef('')
27
- const timer = useRef(null)
28
- const onConfirm = useRef(false)
29
- const ref = {}
30
-
31
- ref.localCheckExist = (path) => {
32
- return getLocalFileInfo(path)
33
- }
34
-
35
- ref.remoteCheckExist = (path) => {
36
- const { sftp } = props
37
- return getRemoteFileInfo(sftp, path)
38
- .then(r => r)
39
- .catch(() => false)
40
- }
41
-
42
- const checkExist = (type, path) => {
43
- return ref[type + 'CheckExist'](path)
44
- }
45
-
46
- function rename (tr, action, _renameId) {
47
- const isRemote = tr.typeTo === typeMap.remote
48
- const { path, name } = getFolderFromFilePath(tr.toPath, isRemote)
49
- const { base, ext } = getFileExt(name)
50
- const renameId = _renameId || generate()
51
- const newName = ext
52
- ? `${base}(rename-${renameId}).${ext}`
53
- : `${base}(rename-${renameId})`
54
- const res = {
55
- ...tr,
56
- renameId,
57
- newName,
58
- oldName: base,
59
- toPath: resolve(path, newName)
60
- }
61
- if (action) {
62
- res.action = action
63
- }
64
- return res
65
- }
66
-
67
- function updateTransferAction (data) {
68
- const {
69
- id,
70
- action,
71
- transfer
72
- } = data
73
- const {
74
- fromFile
75
- } = transfer
76
- clear()
77
- props.modifier((old) => {
78
- let transferList = copy(old.transferList)
79
- const index = findIndex(transferList, d => d.id === id)
80
- if (index < 0) {
81
- return {
82
- transferList
83
- }
84
- }
85
- transferList[index].fromFile = fromFile
86
- transferList[index].action = action
87
- if (action === 'skip') {
88
- transferList.splice(index, 1)
89
- } else if (action === 'cancel') {
90
- transferList = transferList.slice(0, index)
91
- }
92
- if (action.includes('All')) {
93
- transferList = transferList.map((t, i) => {
94
- if (i < index) {
95
- return t
96
- }
97
- return {
98
- ...t,
99
- action: action.replace('All', '')
100
- }
101
- })
102
- }
103
- if (action.includes('rename')) {
104
- transferList[index] = rename(transferList[index])
105
- } else if (action === 'skipAll') {
106
- transferList.splice(index, 1)
107
- }
108
- window.store.setTransfers(transferList, sessionId)
109
- return {
110
- transferList
111
- }
112
- })
113
- }
114
-
115
- function tagTransferError (id, errorMsg) {
116
- const tr = find(transferList, d => d.id === id)
117
- window.store.addTransferHistory({
118
- ...tr,
119
- host: props.host,
120
- error: errorMsg,
121
- finishTime: Date.now()
122
- })
123
- props.modifier(old => {
124
- const transferList = copy(old.transferList)
125
- const index = findIndex(transferList, d => d.id === id)
126
- if (index >= 0) {
127
- transferList.splice(index, 1)
128
- }
129
- window.store.setTransfers(transferList, sessionId)
130
- return {
131
- transferList
132
- }
133
- })
134
- }
135
-
136
- function setConflict (tr) {
137
- if (props.transferToConfirm) {
138
- return
139
- }
140
- props.modifier({
141
- transferToConfirm: tr
142
- })
143
- }
144
-
145
- function onDecision (event) {
146
- if (event && event.data && event.data.id === currentId.current) {
147
- // const {
148
- // transferGroupId,
149
- // fileId,
150
- // id,
151
- // action
152
- // } = event.data
153
- currentId.current = ''
154
- updateTransferAction(event.data)
155
- onConfirm.current = false
156
- window.removeEventListener('message', onDecision)
157
- }
158
- }
159
-
160
- function waitForSignal () {
161
- window.addEventListener('message', onDecision)
162
- }
163
-
164
- function setCanTransfer (fromFile, tr) {
165
- clear()
166
- props.modifier((old) => {
167
- const transferList = copy(old.transferList)
168
- const index = findIndex(transferList, t => {
169
- return t.id === tr.id
170
- })
171
- if (index >= 0) {
172
- const up = {
173
- action: 'transfer',
174
- fromFile
175
- }
176
- Object.assign(transferList[index], up)
177
- }
178
- window.store.setTransfers(transferList, sessionId)
179
- return {
180
- transferList
181
- }
182
- })
183
- }
184
-
185
- async function expand (fromFile, tr) {
186
- let list = []
187
- if (!tr.skipExpand) {
188
- const { type } = fromFile
189
- list = await props[type + 'List'](
190
- true, tr.fromPath
191
- )
192
- list = list.map(t => {
193
- return {
194
- typeFrom: tr.typeFrom,
195
- typeTo: tr.typeTo,
196
- fromPath: resolve(t.path, t.name),
197
- toPath: resolve(tr.toPath, t.name),
198
- id: generate(),
199
- ...createTransferProps(props),
200
- parentId: tr.id
201
- }
202
- })
203
- }
204
- clear()
205
- props.modifier((old) => {
206
- const transferList = copy(old.transferList)
207
- const index = findIndex(transferList, t => {
208
- return t.id === tr.id
209
- })
210
- transferList.splice(index + 1, 0, ...list)
211
- if (transferList[index]) {
212
- transferList[index].expanded = true
213
- }
214
- window.store.setTransfers(transferList, sessionId)
215
- return {
216
- transferList
217
- }
218
- })
219
- }
220
-
221
- function clear () {
222
- currentId.current = ''
223
- }
224
- async function watchFile () {
225
- if (!transferList.length && currentId.current) {
226
- return clear()
227
- }
228
- const tr = transferList
229
- .filter(t => {
230
- return (
231
- !t.action ||
232
- !t.fromFile ||
233
- (t.fromFile.isDirectory && !t.expanded)
234
- )
235
- })[0]
236
- if (!tr) {
237
- onConfirm.current = false
238
- return clear()
239
- }
240
- if (currentId.current) {
241
- return null
242
- }
243
- currentId.current = tr.id
244
- const {
245
- typeFrom,
246
- typeTo,
247
- fromPath,
248
- toPath,
249
- id,
250
- action,
251
- expanded,
252
- renameId,
253
- parentId,
254
- skipConfirm
255
- } = tr
256
- const fromFile = tr.fromFile
257
- ? tr.fromFile
258
- : await checkExist(typeFrom, fromPath)
259
- if (!fromFile) {
260
- currentId.current = ''
261
- return tagTransferError(id, 'file not exist')
262
- }
263
- let toFile = false
264
- if (renameId || parentId) {
265
- toFile = false
266
- } else if (fromPath === toPath && typeFrom === typeTo) {
267
- toFile = true
268
- } else {
269
- toFile = await checkExist(typeTo, toPath)
270
- }
271
- if (fromFile.isDirectory) {
272
- const skip = await checkFolderSize(props, fromFile)
273
- .then(d => d && typeFrom !== typeTo)
274
- tr.zip = skip
275
- tr.skipExpand = skip
276
- }
277
- if (fromPath === toPath && typeFrom === typeTo) {
278
- return updateTransferAction({
279
- id,
280
- action: 'rename',
281
- transfer: {
282
- ...tr,
283
- operation: 'cp',
284
- fromFile
285
- }
286
- })
287
- } else if (toFile && !action && !skipConfirm) {
288
- waitForSignal(id)
289
- if (!onConfirm.current) {
290
- onConfirm.current = true
291
- return setConflict({
292
- ...tr,
293
- fromFile,
294
- toFile
295
- })
296
- }
297
- } else if (toFile && !tr.fromFile && action) {
298
- return updateTransferAction({
299
- id,
300
- action,
301
- transfer: {
302
- ...tr,
303
- fromFile
304
- }
305
- })
306
- } else if (
307
- fromFile.isDirectory &&
308
- !expanded &&
309
- typeFrom !== typeTo &&
310
- transferList.filter(t => t.fromFile).length < maxTransport
311
- ) {
312
- return expand(fromFile, tr)
313
- }
314
- setCanTransfer(fromFile, tr)
315
- }
316
- useConditionalEffect(() => {
317
- watchFile()
318
- return () => {
319
- clearTimeout(timer.current)
320
- }
321
- }, delta && delta.prev && !eq(delta.prev, delta.curr))
322
- return null
323
- }