@electerm/electerm-react 1.34.30

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 (273) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/client/common/auto-complete-data-mapper.js +6 -0
  4. package/client/common/byte-format.js +14 -0
  5. package/client/common/class.js +52 -0
  6. package/client/common/clipboard.js +49 -0
  7. package/client/common/constants.js +308 -0
  8. package/client/common/create-lang-edit-link.js +7 -0
  9. package/client/common/create-title.js +29 -0
  10. package/client/common/db-fix.js +24 -0
  11. package/client/common/db.js +155 -0
  12. package/client/common/download-mirrors.js +10 -0
  13. package/client/common/download.js +16 -0
  14. package/client/common/error-handler.jsx +27 -0
  15. package/client/common/fetch-from-server.js +47 -0
  16. package/client/common/fetch.jsx +71 -0
  17. package/client/common/find-bookmark-group-id.js +15 -0
  18. package/client/common/find-parent.js +30 -0
  19. package/client/common/form-layout.js +27 -0
  20. package/client/common/fs.js +21 -0
  21. package/client/common/get-proxy.js +8 -0
  22. package/client/common/id-with-stamp.js +10 -0
  23. package/client/common/index-sorter.js +4 -0
  24. package/client/common/init-setting-item.js +32 -0
  25. package/client/common/is-absolute-path.js +3 -0
  26. package/client/common/is-ip.js +16 -0
  27. package/client/common/is-valid-path.js +7 -0
  28. package/client/common/key-control-pressed.js +13 -0
  29. package/client/common/key-pressed.js +13 -0
  30. package/client/common/key-shift-pressed.js +7 -0
  31. package/client/common/mode2permission.js +81 -0
  32. package/client/common/new-terminal.js +31 -0
  33. package/client/common/parse-int10.js +3 -0
  34. package/client/common/parse-json-safe.js +11 -0
  35. package/client/common/pass-enc.js +25 -0
  36. package/client/common/post-msg.js +3 -0
  37. package/client/common/pre.js +156 -0
  38. package/client/common/promise-timeout.js +27 -0
  39. package/client/common/resolve.js +31 -0
  40. package/client/common/run-idle.js +1 -0
  41. package/client/common/safe-local-storage.js +35 -0
  42. package/client/common/safe-name.js +19 -0
  43. package/client/common/sftp.js +74 -0
  44. package/client/common/terminal-theme.js +158 -0
  45. package/client/common/test-connection.js +12 -0
  46. package/client/common/time.js +30 -0
  47. package/client/common/to-simple-obj.js +5 -0
  48. package/client/common/track.js +7 -0
  49. package/client/common/transfer.js +76 -0
  50. package/client/common/trzsz.js +62 -0
  51. package/client/common/ui-theme.js +44 -0
  52. package/client/common/uid.js +5 -0
  53. package/client/common/update-check.js +79 -0
  54. package/client/common/upgrade.js +68 -0
  55. package/client/common/wait.js +8 -0
  56. package/client/common/ws.js +161 -0
  57. package/client/components/batch-op/batch-op.jsx +650 -0
  58. package/client/components/bookmark-form/bookmark-form.styl +8 -0
  59. package/client/components/bookmark-form/bookmark-group-tree-format.js +39 -0
  60. package/client/components/bookmark-form/encodes.js +44 -0
  61. package/client/components/bookmark-form/form-ssh-common.jsx +208 -0
  62. package/client/components/bookmark-form/form-tabs.jsx +69 -0
  63. package/client/components/bookmark-form/index.jsx +159 -0
  64. package/client/components/bookmark-form/local-form-ui.jsx +152 -0
  65. package/client/components/bookmark-form/local-form.jsx +16 -0
  66. package/client/components/bookmark-form/proxy.jsx +49 -0
  67. package/client/components/bookmark-form/quick-command-list.jsx +31 -0
  68. package/client/components/bookmark-form/quick-command.jsx +228 -0
  69. package/client/components/bookmark-form/render-auth-ssh.jsx +104 -0
  70. package/client/components/bookmark-form/render-connection-hopping.jsx +229 -0
  71. package/client/components/bookmark-form/render-delayed-scripts.jsx +88 -0
  72. package/client/components/bookmark-form/render-ssh-tunnel.jsx +116 -0
  73. package/client/components/bookmark-form/serial-form-ui.jsx +311 -0
  74. package/client/components/bookmark-form/serial-form.jsx +20 -0
  75. package/client/components/bookmark-form/sftp-enable.jsx +33 -0
  76. package/client/components/bookmark-form/ssh-form-ui.jsx +100 -0
  77. package/client/components/bookmark-form/ssh-form.jsx +348 -0
  78. package/client/components/bookmark-form/telnet-form-ui.jsx +154 -0
  79. package/client/components/bookmark-form/telnet-form.jsx +16 -0
  80. package/client/components/bookmark-form/tree-delete.jsx +87 -0
  81. package/client/components/bookmark-form/use-form-funcs.jsx +50 -0
  82. package/client/components/bookmark-form/use-quick-commands.jsx +83 -0
  83. package/client/components/bookmark-form/use-submit.jsx +77 -0
  84. package/client/components/bookmark-form/use-ui.jsx +82 -0
  85. package/client/components/bookmark-form/x11.jsx +23 -0
  86. package/client/components/common/animate-text.jsx +37 -0
  87. package/client/components/common/animate-text.styl +54 -0
  88. package/client/components/common/external-link.jsx +28 -0
  89. package/client/components/common/help-icon.jsx +25 -0
  90. package/client/components/common/highlight.jsx +23 -0
  91. package/client/components/common/highlight.styl +3 -0
  92. package/client/components/common/input-auto-focus.jsx +68 -0
  93. package/client/components/common/input-confirm.jsx +66 -0
  94. package/client/components/common/logo-elem.jsx +22 -0
  95. package/client/components/common/markdown.jsx +27 -0
  96. package/client/components/common/react-subx.jsx +1 -0
  97. package/client/components/common/resize-wrap.jsx +222 -0
  98. package/client/components/common/resize-wrap.styl +9 -0
  99. package/client/components/common/search.jsx +9 -0
  100. package/client/components/common/show-item.jsx +27 -0
  101. package/client/components/context-menu/boomarks.jsx +15 -0
  102. package/client/components/context-menu/context-menu.jsx +340 -0
  103. package/client/components/context-menu/context-menu.styl +90 -0
  104. package/client/components/context-menu/history.jsx +27 -0
  105. package/client/components/context-menu/icon-holder.jsx +5 -0
  106. package/client/components/context-menu/menu-btn.jsx +224 -0
  107. package/client/components/context-menu/sub-tab-menu.jsx +23 -0
  108. package/client/components/context-menu/tabs.jsx +22 -0
  109. package/client/components/context-menu/zoom.jsx +40 -0
  110. package/client/components/footer/batch-input.jsx +177 -0
  111. package/client/components/footer/footer-entry.jsx +141 -0
  112. package/client/components/footer/footer.styl +47 -0
  113. package/client/components/icons/match-case.jsx +10 -0
  114. package/client/components/icons/match-whole-word.jsx +13 -0
  115. package/client/components/icons/regular-exp.jsx +10 -0
  116. package/client/components/main/css-overwrite.jsx +92 -0
  117. package/client/components/main/error-wrapper.jsx +59 -0
  118. package/client/components/main/index.jsx +11 -0
  119. package/client/components/main/loading.jsx +25 -0
  120. package/client/components/main/main.jsx +149 -0
  121. package/client/components/main/term-fullscreen-control.jsx +21 -0
  122. package/client/components/main/term-fullscreen.styl +27 -0
  123. package/client/components/main/ui-theme.jsx +31 -0
  124. package/client/components/main/upgrade.jsx +351 -0
  125. package/client/components/main/upgrade.styl +27 -0
  126. package/client/components/main/wrapper.styl +41 -0
  127. package/client/components/quick-commands/qm.styl +29 -0
  128. package/client/components/quick-commands/quick-command-item.jsx +36 -0
  129. package/client/components/quick-commands/quick-command-transport-mod.jsx +54 -0
  130. package/client/components/quick-commands/quick-command-transport.jsx +12 -0
  131. package/client/components/quick-commands/quick-commands-box.jsx +233 -0
  132. package/client/components/quick-commands/quick-commands-form-elem.jsx +119 -0
  133. package/client/components/quick-commands/quick-commands-form.jsx +33 -0
  134. package/client/components/quick-commands/quick-commands-list.jsx +128 -0
  135. package/client/components/quick-commands/quick-commands-select.jsx +38 -0
  136. package/client/components/session/session.jsx +533 -0
  137. package/client/components/session/session.styl +53 -0
  138. package/client/components/session/sessions.jsx +445 -0
  139. package/client/components/setting-panel/bookmark-transport.jsx +148 -0
  140. package/client/components/setting-panel/bookmark-tree-list.jsx +14 -0
  141. package/client/components/setting-panel/col.jsx +18 -0
  142. package/client/components/setting-panel/list.jsx +186 -0
  143. package/client/components/setting-panel/list.styl +33 -0
  144. package/client/components/setting-panel/on-tree-drop.js +222 -0
  145. package/client/components/setting-panel/setting-modal.jsx +163 -0
  146. package/client/components/setting-panel/setting-wrap.jsx +37 -0
  147. package/client/components/setting-panel/setting-wrap.styl +52 -0
  148. package/client/components/setting-panel/setting.jsx +858 -0
  149. package/client/components/setting-panel/setting.styl +4 -0
  150. package/client/components/setting-panel/start-session-select.jsx +91 -0
  151. package/client/components/setting-panel/tab-bookmarks.jsx +37 -0
  152. package/client/components/setting-panel/tab-history.jsx +44 -0
  153. package/client/components/setting-panel/tab-quick-commands.jsx +38 -0
  154. package/client/components/setting-panel/tab-settings.jsx +42 -0
  155. package/client/components/setting-panel/tab-themes.jsx +34 -0
  156. package/client/components/setting-panel/tree-list.jsx +978 -0
  157. package/client/components/setting-panel/tree-list.styl +57 -0
  158. package/client/components/setting-sync/data-import.jsx +65 -0
  159. package/client/components/setting-sync/setting-sync-form.jsx +271 -0
  160. package/client/components/setting-sync/setting-sync.jsx +81 -0
  161. package/client/components/setting-sync/sync.styl +7 -0
  162. package/client/components/sftp/address-bar.jsx +139 -0
  163. package/client/components/sftp/address-bookmark-item.jsx +47 -0
  164. package/client/components/sftp/address-bookmark.jsx +81 -0
  165. package/client/components/sftp/address-bookmark.styl +8 -0
  166. package/client/components/sftp/confirm-modal.jsx +184 -0
  167. package/client/components/sftp/file-icon.jsx +22 -0
  168. package/client/components/sftp/file-item.jsx +1226 -0
  169. package/client/components/sftp/file-mode-modal.jsx +205 -0
  170. package/client/components/sftp/file-props-modal.jsx +211 -0
  171. package/client/components/sftp/file-read.js +81 -0
  172. package/client/components/sftp/list-table-ui.jsx +547 -0
  173. package/client/components/sftp/owner-list.js +97 -0
  174. package/client/components/sftp/paged-list.jsx +60 -0
  175. package/client/components/sftp/permission-render.jsx +42 -0
  176. package/client/components/sftp/sftp-entry.jsx +1069 -0
  177. package/client/components/sftp/sftp.styl +217 -0
  178. package/client/components/sftp/transfer-common.js +9 -0
  179. package/client/components/sftp/transfer-conflict.jsx +315 -0
  180. package/client/components/sftp/transfer-speed-format.js +60 -0
  181. package/client/components/sftp/transfer-tag.jsx +40 -0
  182. package/client/components/sftp/transfer-tag.styl +11 -0
  183. package/client/components/sftp/transfer.styl +55 -0
  184. package/client/components/sftp/transport-action.jsx +410 -0
  185. package/client/components/sftp/transport-entry.jsx +108 -0
  186. package/client/components/sftp/transport-types.js +8 -0
  187. package/client/components/sftp/transports-action.jsx +111 -0
  188. package/client/components/sftp/transports-ui.jsx +93 -0
  189. package/client/components/sftp/zip.js +42 -0
  190. package/client/components/sidebar/bookmark-select.jsx +48 -0
  191. package/client/components/sidebar/bookmark.jsx +82 -0
  192. package/client/components/sidebar/history.jsx +66 -0
  193. package/client/components/sidebar/index.jsx +230 -0
  194. package/client/components/sidebar/info-modal.jsx +250 -0
  195. package/client/components/sidebar/info.styl +27 -0
  196. package/client/components/sidebar/side-icon.jsx +25 -0
  197. package/client/components/sidebar/sidebar.styl +128 -0
  198. package/client/components/sidebar/transfer-history-modal.jsx +110 -0
  199. package/client/components/sidebar/transfer-history.styl +3 -0
  200. package/client/components/sidebar/transfer-list-control.jsx +205 -0
  201. package/client/components/sidebar/transfer-list.jsx +55 -0
  202. package/client/components/sidebar/transfer-modal.jsx +76 -0
  203. package/client/components/sidebar/transfer.styl +8 -0
  204. package/client/components/sidebar/transport-ui.jsx +109 -0
  205. package/client/components/tabs/index.jsx +320 -0
  206. package/client/components/tabs/tab.jsx +427 -0
  207. package/client/components/tabs/tabs.styl +220 -0
  208. package/client/components/tabs/window-control.jsx +55 -0
  209. package/client/components/terminal/attach-addon-custom.js +70 -0
  210. package/client/components/terminal/build-ls-term-id.js +5 -0
  211. package/client/components/terminal/index.jsx +1358 -0
  212. package/client/components/terminal/normal-buffer.jsx +33 -0
  213. package/client/components/terminal/term-search.jsx +224 -0
  214. package/client/components/terminal/term-search.styl +15 -0
  215. package/client/components/terminal/terminal-apis.js +31 -0
  216. package/client/components/terminal/terminal-interactive.jsx +148 -0
  217. package/client/components/terminal/terminal.styl +96 -0
  218. package/client/components/terminal/xterm-zmodem.js +48 -0
  219. package/client/components/terminal/zmodem-transfer.jsx +98 -0
  220. package/client/components/terminal/zmodem.styl +14 -0
  221. package/client/components/terminal-info/activity.jsx +54 -0
  222. package/client/components/terminal-info/base.jsx +25 -0
  223. package/client/components/terminal-info/content.jsx +101 -0
  224. package/client/components/terminal-info/data-cols-parser.jsx +50 -0
  225. package/client/components/terminal-info/disk.jsx +29 -0
  226. package/client/components/terminal-info/index.jsx +25 -0
  227. package/client/components/terminal-info/network.jsx +114 -0
  228. package/client/components/terminal-info/resource.jsx +80 -0
  229. package/client/components/terminal-info/run-cmd.jsx +273 -0
  230. package/client/components/terminal-info/terminal-info.styl +29 -0
  231. package/client/components/terminal-info/up.jsx +15 -0
  232. package/client/components/terminal-theme/index.jsx +264 -0
  233. package/client/components/terminal-theme/terminal-theme-list.styl +3 -0
  234. package/client/components/terminal-theme/theme-list.jsx +146 -0
  235. package/client/components/text-editor/text-editor-form.jsx +97 -0
  236. package/client/components/text-editor/text-editor.jsx +182 -0
  237. package/client/css/antd-overwrite.styl +14 -0
  238. package/client/css/basic.styl +38 -0
  239. package/client/css/includes/box.styl +154 -0
  240. package/client/css/includes/font-size.styl +6 -0
  241. package/client/css/includes/index.styl +3 -0
  242. package/client/css/includes/text.styl +31 -0
  243. package/client/css/includes/theme-default.styl +20 -0
  244. package/client/entry/basic.js +58 -0
  245. package/client/entry/index.jsx +15 -0
  246. package/client/entry/worker.js +137 -0
  247. package/client/store/address-bookmark.js +25 -0
  248. package/client/store/app-upgrade.js +23 -0
  249. package/client/store/batch-input-history.js +26 -0
  250. package/client/store/bookmark-group.js +128 -0
  251. package/client/store/bookmark.js +22 -0
  252. package/client/store/common.js +140 -0
  253. package/client/store/context-menu.js +23 -0
  254. package/client/store/db-upgrade.js +43 -0
  255. package/client/store/event.js +70 -0
  256. package/client/store/index.js +335 -0
  257. package/client/store/init-state.js +191 -0
  258. package/client/store/item.js +120 -0
  259. package/client/store/load-data.js +198 -0
  260. package/client/store/quick-command.js +43 -0
  261. package/client/store/session.js +54 -0
  262. package/client/store/setting.js +208 -0
  263. package/client/store/sidebar.js +48 -0
  264. package/client/store/sync.js +390 -0
  265. package/client/store/system-menu.js +120 -0
  266. package/client/store/tab.js +74 -0
  267. package/client/store/terminal-theme.js +116 -0
  268. package/client/store/transfer-history.js +27 -0
  269. package/client/store/transfer-list.js +20 -0
  270. package/client/store/ui-theme.js +71 -0
  271. package/client/store/watch.js +116 -0
  272. package/client/views/index.pug +58 -0
  273. package/package.json +34 -0
@@ -0,0 +1,1069 @@
1
+ import { Component } from 'react'
2
+ import generate from '../../common/uid'
3
+ import runIdle from '../../common/run-idle'
4
+ import { Spin, Modal, notification } from 'antd'
5
+ import { find, isString, findIndex, isEqual, last, isNumber, some, isArray, pick, uniq, debounce } from 'lodash-es'
6
+ import FileSection from './file-item'
7
+ import resolve from '../../common/resolve'
8
+ import wait from '../../common/wait'
9
+ import isAbsPath from '../../common/is-absolute-path'
10
+ import classnames from 'classnames'
11
+ import sorterIndex from '../../common/index-sorter'
12
+ import { getLocalFileInfo, getRemoteFileInfo } from './file-read'
13
+ import {
14
+ typeMap, maxSftpHistory, paneMap,
15
+ eventTypes,
16
+ fileTypeMap,
17
+ terminalSshConfigType, terminalSerialType,
18
+ unexpectedPacketErrorDesc, sftpRetryInterval,
19
+ commonActions
20
+ } from '../../common/constants'
21
+ import { hasFileInClipboardText } from '../../common/clipboard'
22
+ import Client from '../../common/sftp'
23
+ import fs from '../../common/fs'
24
+ import keyControlPressed from '../../common/key-control-pressed'
25
+ import keyPressed from '../../common/key-pressed'
26
+ import ListTable from './list-table-ui'
27
+ import deepCopy from 'json-deep-copy'
28
+ import isValidPath from '../../common/is-valid-path'
29
+ import memoizeOne from 'memoize-one'
30
+ import TransportEntry from './transport-entry'
31
+ import postMessage from '../../common/post-msg'
32
+ import { runCmd } from '../terminal/terminal-apis'
33
+ import * as owner from './owner-list'
34
+ import AddressBar from './address-bar'
35
+ import getProxy from '../../common/get-proxy'
36
+ import './sftp.styl'
37
+
38
+ const { prefix } = window
39
+ const e = prefix('sftp')
40
+ const c = prefix('common')
41
+
42
+ const buildTree = arr => {
43
+ return arr.reduce((prev, curr) => {
44
+ return {
45
+ ...prev,
46
+ [curr.id]: curr
47
+ }
48
+ }, {})
49
+ }
50
+
51
+ export default class Sftp extends Component {
52
+ constructor (props) {
53
+ super(props)
54
+ this.state = {
55
+ id: props.id || generate(),
56
+ selectedFiles: [],
57
+ lastClickedFile: null,
58
+ onEditFile: false,
59
+ ...this.defaultState(),
60
+ loadingSftp: false,
61
+ transferToConfirm: null,
62
+ transferList: [],
63
+ pauseAll: false,
64
+ inited: false
65
+ }
66
+ this.retryCount = 0
67
+ }
68
+
69
+ // componentDidMount () {
70
+ // // this.initData()
71
+ // // this.initEvent()
72
+ // }
73
+
74
+ componentDidUpdate (prevProps, prevState) {
75
+ if (
76
+ (
77
+ prevProps.enableSftp !== false &&
78
+ !prevProps.pid &&
79
+ this.props.pid
80
+ ) ||
81
+ (
82
+ prevProps.pid &&
83
+ prevProps.enableSftp === false &&
84
+ this.props.enableSftp !== false
85
+ )
86
+ ) {
87
+ this.initEvent()
88
+ this.initData(true)
89
+ }
90
+ if (
91
+ this.props.config.autoRefreshWhenSwitchToSftp &&
92
+ prevProps.pane !== this.props.pane &&
93
+ (this.props.pane === paneMap.fileManager || this.props.pane.sftp) &&
94
+ this.state.inited
95
+ ) {
96
+ this.onGoto(typeMap.local)
97
+ this.onGoto(typeMap.remote)
98
+ }
99
+ if (
100
+ prevState.remotePath !== this.state.remotePath &&
101
+ this.state.selectedFiles.some(f => f.type === typeMap.remote)
102
+ ) {
103
+ this.setState({
104
+ selectedFiles: []
105
+ })
106
+ } else if (
107
+ prevState.localPath !== this.state.localPath &&
108
+ this.state.selectedFiles.some(f => f.type === typeMap.local)
109
+ ) {
110
+ this.setState({
111
+ selectedFiles: []
112
+ })
113
+ }
114
+ }
115
+
116
+ componentWillUnmount () {
117
+ this.destroyEvent()
118
+ this.sftp && this.sftp.destroy()
119
+ clearTimeout(this.timer4)
120
+ }
121
+
122
+ directions = [
123
+ 'desc',
124
+ 'asc'
125
+ ]
126
+
127
+ defaultDirection = (i = 0) => {
128
+ return this.directions[i]
129
+ }
130
+
131
+ defaultState = () => {
132
+ return Object.keys(typeMap).reduce((prev, k, i) => {
133
+ Object.assign(prev, {
134
+ [`sortProp.${k}`]: window.store.sftpSortSetting[k].prop,
135
+ [`sortDirection.${k}`]: window.store.sftpSortSetting[k].direction,
136
+ [k]: [],
137
+ [`${k}FileTree`]: {},
138
+ [`${k}Loading`]: false,
139
+ [`${k}InputFocus`]: false,
140
+ [`${k}ShowHiddenFile`]: false,
141
+ [`${k}Path`]: '',
142
+ [`${k}PathTemp`]: '',
143
+ [`${k}PathHistory`]: [],
144
+ [`${k}GidTree`]: {},
145
+ [`${k}UidTree`]: {}
146
+ })
147
+ return prev
148
+ }, {})
149
+ }
150
+
151
+ sort = memoizeOne((
152
+ list,
153
+ type,
154
+ sortDirection,
155
+ sortProp
156
+ ) => {
157
+ const l0 = find(list, g => !g.id)
158
+ const l1 = list.filter(g => g.id && g.isDirectory)
159
+ const l2 = list.filter(g => g.id && !g.isDirectory)
160
+ const sorter = (a, b) => {
161
+ let va = a[sortProp]
162
+ let vb = b[sortProp]
163
+ if (isString(va)) {
164
+ va = va.toLowerCase()
165
+ vb = vb.toLowerCase()
166
+ }
167
+ if (sortDirection === 'desc') {
168
+ if (isString(va)) {
169
+ return va.localeCompare(vb, { sensitivity: 'base' })
170
+ }
171
+ return va > vb ? -1 : 1
172
+ } else {
173
+ if (isString(va)) {
174
+ return -va.localeCompare(vb, { sensitivity: 'base' })
175
+ }
176
+ return va > vb ? 1 : -1
177
+ }
178
+ }
179
+ return [
180
+ l0,
181
+ ...l1.sort(sorter),
182
+ ...l2.sort(sorter)
183
+ ].filter(d => d)
184
+ }, isEqual)
185
+
186
+ initEvent () {
187
+ window.addEventListener('keydown', this.handleEvent)
188
+ }
189
+
190
+ destroyEvent () {
191
+ window.removeEventListener('keydown', this.handleEvent)
192
+ }
193
+
194
+ isActive () {
195
+ return this.props.enableSftp && this.props.currentTabId === this.props.tab.id &&
196
+ this.props.pane === paneMap.fileManager
197
+ }
198
+
199
+ getPwd = async (username) => {
200
+ const home = await runCmd(
201
+ this.props.pid,
202
+ this.props.sessionId,
203
+ 'pwd'
204
+ ).catch(window.store.onError)
205
+ if (home) {
206
+ return home.trim()
207
+ } else {
208
+ return username === 'root'
209
+ ? '/root'
210
+ : `/home/${this.props.tab.username}`
211
+ }
212
+ }
213
+
214
+ getIndex = (file) => {
215
+ const { type } = file
216
+ return findIndex(this.getFileList(type), f => f.id === file.id)
217
+ }
218
+
219
+ onResizeDragEnd = () => {
220
+ postMessage({
221
+ type: eventTypes.resetFileListTable,
222
+ data: {
223
+ id: this.state.id
224
+ }
225
+ })
226
+ }
227
+
228
+ selectAll = (type, e) => {
229
+ e && e.preventDefault && e.preventDefault()
230
+ this.setState({
231
+ selectedFiles: this.getFileList(type)
232
+ })
233
+ }
234
+
235
+ selectNext = type => {
236
+ const { selectedFiles } = this.state
237
+ const sorted = selectedFiles.map(f => this.getIndex(f))
238
+ .sort(sorterIndex)
239
+ const lastOne = last(sorted)
240
+ const list = this.getFileList(type)
241
+ if (!list.length) {
242
+ return
243
+ }
244
+ let next = 0
245
+ if (isNumber(lastOne)) {
246
+ next = (lastOne + 1) % list.length
247
+ }
248
+ const nextFile = list[next]
249
+ if (nextFile) {
250
+ this.setState({
251
+ selectedFiles: [nextFile]
252
+ })
253
+ }
254
+ }
255
+
256
+ selectPrev = type => {
257
+ const { selectedFiles } = this.state
258
+ const sorted = selectedFiles.map(f => this.getIndex(f))
259
+ .sort(sorterIndex)
260
+ const lastOne = sorted[0]
261
+ const list = this.getFileList(type)
262
+ if (!list.length) {
263
+ return
264
+ }
265
+ let next = 0
266
+ const len = list.length
267
+ if (isNumber(lastOne)) {
268
+ next = (lastOne - 1 + len) % len
269
+ }
270
+ const nextFile = list[next]
271
+ if (nextFile) {
272
+ this.setState({
273
+ selectedFiles: [nextFile]
274
+ })
275
+ }
276
+ }
277
+
278
+ localDel = async (file) => {
279
+ const { name, isDirectory, path } = file
280
+ const func = !isDirectory
281
+ ? fs.unlink
282
+ : fs.rmrf
283
+ const p = resolve(path, name)
284
+ await func(p).catch(window.store.onError)
285
+ }
286
+
287
+ remoteDel = async (file) => {
288
+ const { name, isDirectory, path } = file
289
+ const { sftp } = this
290
+ const func = isDirectory
291
+ ? sftp.rmdir
292
+ : sftp.rm
293
+ const p = resolve(path, name)
294
+ await func(p).catch(window.store.onError)
295
+ }
296
+
297
+ delFiles = async (_type, files = this.state.selectedFiles) => {
298
+ this.onDelete = false
299
+ const type = files[0].type || _type
300
+ const func = this[type + 'Del']
301
+ for (const f of files) {
302
+ await func(f)
303
+ }
304
+ if (type === typeMap.remote) {
305
+ await wait(500)
306
+ }
307
+ this[type + 'List']()
308
+ }
309
+
310
+ renderDelConfirmTitle (files = this.state.selectedFiles, pureText) {
311
+ const hasDirectory = some(files, f => f.isDirectory)
312
+ const names = hasDirectory ? e('filesAndFolders') : e('files')
313
+ if (pureText) {
314
+ const t1 = hasDirectory
315
+ ? e('delTip1')
316
+ : ''
317
+ return `${e('delTip')} ${names} ${t1} (${files.length})`
318
+ }
319
+ return (
320
+ <div className='wordbreak'>
321
+ {e('delTip')}
322
+ {names}
323
+ {
324
+ hasDirectory
325
+ ? e('delTip1')
326
+ : ''
327
+ }
328
+ (<b className='mg1x'>{files.length}</b>)
329
+ </div>
330
+ )
331
+ }
332
+
333
+ onDel = (type, files) => {
334
+ this.onDelete = true
335
+ Modal.confirm({
336
+ cancelText: c('cancel'),
337
+ okText: c('ok'),
338
+ title: this.renderDelConfirmTitle(files),
339
+ onOk: () => this.delFiles(type, files)
340
+ })
341
+ }
342
+
343
+ enter = (type, e) => {
344
+ const { selectedFiles, onEditFile } = this.state
345
+ if (onEditFile || selectedFiles.length !== 1) {
346
+ return
347
+ }
348
+ const file = selectedFiles[0]
349
+ const { isDirectory } = file
350
+ if (isDirectory) {
351
+ this[type + 'Dom'].enterDirectory(e, file)
352
+ } else {
353
+ this.setState({
354
+ filesToConfirm: [file]
355
+ })
356
+ }
357
+ }
358
+
359
+ onInputFocus = (type) => {
360
+ this.setState({
361
+ [type + 'InputFocus']: true
362
+ })
363
+ this.inputFocus = true
364
+ }
365
+
366
+ onInputBlur = (type) => {
367
+ this.inputFocus = false
368
+ this.timer4 = setTimeout(() => {
369
+ this.setState({
370
+ [type + 'InputFocus']: false
371
+ })
372
+ }, 200)
373
+ }
374
+
375
+ doCopy = (type, e) => {
376
+ this[type + 'Dom'].onCopy(e, this.state.selectedFiles)
377
+ }
378
+
379
+ doCut = (type, e) => {
380
+ this[type + 'Dom'].onCut(e, this.state.selectedFiles)
381
+ }
382
+
383
+ doPaste = (type) => {
384
+ if (!hasFileInClipboardText()) {
385
+ return
386
+ }
387
+ this[type + 'Dom'].onPaste()
388
+ }
389
+
390
+ handleEvent = (e) => {
391
+ if (!this.isActive() || window.store.onOperation) {
392
+ return
393
+ }
394
+ const lastClickedFile = this.state.lastClickedFile || {
395
+ type: typeMap.local
396
+ }
397
+ const { type } = lastClickedFile
398
+ const { inputFocus, onDelete } = this
399
+ if (keyControlPressed(e) && keyPressed(e, 'a') && !inputFocus) {
400
+ e.stopPropagation()
401
+ this.selectAll(type, e)
402
+ } else if (keyPressed(e, 'arrowdown') && !inputFocus) {
403
+ e.stopPropagation()
404
+ this.selectNext(type)
405
+ } else if (keyPressed(e, 'arrowup') && !inputFocus) {
406
+ e.stopPropagation()
407
+ this.selectPrev(type)
408
+ } else if (keyPressed(e, 'delete') && !inputFocus) {
409
+ e.stopPropagation()
410
+ this.onDel(type)
411
+ } else if (keyPressed(e, 'enter') && !inputFocus && !onDelete) {
412
+ e.stopPropagation()
413
+ this.enter(type, e)
414
+ } else if (keyControlPressed(e) && keyPressed(e, 'c') && !inputFocus) {
415
+ e.stopPropagation()
416
+ this.doCopy(type, e)
417
+ } else if (keyControlPressed(e) && keyPressed(e, 'x') && !inputFocus) {
418
+ e.stopPropagation()
419
+ this.doCut(type, e)
420
+ } else if (keyControlPressed(e) && keyPressed(e, 'v') && !inputFocus) {
421
+ e.stopPropagation()
422
+ this.doPaste(type, e)
423
+ } else if (keyPressed(e, 'f5')) {
424
+ e.stopPropagation()
425
+ this.onGoto(type)
426
+ }
427
+ }
428
+
429
+ initData = async () => {
430
+ const { props } = this
431
+ const host = props.tab?.host &&
432
+ props.tab?.type !== terminalSshConfigType &&
433
+ props.tab?.type !== terminalSerialType
434
+ if (host) {
435
+ this.initRemoteAll()
436
+ }
437
+ this.initLocalAll()
438
+ }
439
+
440
+ initLocalAll = () => {
441
+ this.localListOwner()
442
+ this.localList()
443
+ }
444
+
445
+ initRemoteAll = async () => {
446
+ await this.remoteList()
447
+ this.remoteListOwner()
448
+ }
449
+
450
+ modifier = (...args) => {
451
+ runIdle(() => this.setState(...args))
452
+ }
453
+
454
+ addTransferList = list => {
455
+ postMessage({
456
+ list,
457
+ action: commonActions.addTransfer,
458
+ sessionId: this.props.sessionId
459
+ })
460
+ }
461
+
462
+ computeListHeight = () => {
463
+ const hasTransports = this.state.transports.length
464
+ return this.props.height - 15 - (hasTransports ? 300 : 0)
465
+ }
466
+
467
+ onError = e => {
468
+ window.store.onError(e)
469
+ this.setState({
470
+ remoteLoading: false
471
+ })
472
+ }
473
+
474
+ getFileList = type => {
475
+ const showHide = this.state[`${type}ShowHiddenFile`]
476
+ let list = this.state[type]
477
+ list = isArray(list) ? list : []
478
+ if (!showHide) {
479
+ list = list.filter(f => !/^\./.test(f.name))
480
+ }
481
+ return this.sort(
482
+ list,
483
+ type,
484
+ this.state[`sortDirection.${type}`],
485
+ this.state[`sortProp.${type}`]
486
+ )
487
+ }
488
+
489
+ toggleShowHiddenFile = type => {
490
+ const prop = `${type}ShowHiddenFile`
491
+ const b = this.state[prop]
492
+ this.setState({
493
+ [prop]: !b
494
+ })
495
+ }
496
+
497
+ remoteListOwner = async () => {
498
+ const remoteUidTree = await owner.remoteListUsers(
499
+ this.props.pid,
500
+ this.props.sessionId
501
+ )
502
+ const remoteGidTree = await owner.remoteListGroups(
503
+ this.props.pid,
504
+ this.props.sessionId
505
+ )
506
+ this.setState({
507
+ remoteGidTree,
508
+ remoteUidTree
509
+ })
510
+ }
511
+
512
+ localListOwner = async () => {
513
+ const localUidTree = await owner.localListUsers()
514
+ const localGidTree = await owner.localListGroups()
515
+ this.setState({
516
+ localGidTree,
517
+ localUidTree
518
+ })
519
+ }
520
+
521
+ remoteList = async (
522
+ returnList = false,
523
+ remotePathReal,
524
+ oldPath
525
+ ) => {
526
+ const { tab, sessionOptions, sessionId } = this.props
527
+ const { username, startDirectory } = tab
528
+ let remotePath
529
+ const noPathInit = remotePathReal || this.state.remotePath
530
+ if (noPathInit) {
531
+ remotePath = noPathInit
532
+ }
533
+ if (!returnList) {
534
+ this.setState({
535
+ remoteLoading: true
536
+ })
537
+ }
538
+ const oldRemote = deepCopy(
539
+ this.state.remote
540
+ )
541
+ let sftp = this.sftp
542
+ try {
543
+ if (!this.sftp) {
544
+ sftp = await Client(sessionId)
545
+ if (!sftp) {
546
+ return
547
+ }
548
+ const config = deepCopy(
549
+ this.props.config
550
+ )
551
+ this.setState({
552
+ loadingSftp: true
553
+ })
554
+ const opts = deepCopy({
555
+ ...tab,
556
+ readyTimeout: config.sshReadyTimeout,
557
+ sessionId,
558
+ keepaliveInterval: config.keepaliveInterval,
559
+ proxy: getProxy(tab, config),
560
+ ...sessionOptions
561
+ })
562
+ delete opts.terminals
563
+ const r = await sftp.connect(opts)
564
+ .catch(e => {
565
+ if (
566
+ e &&
567
+ e.message.includes(unexpectedPacketErrorDesc) && this.retryCount
568
+ ) {
569
+ this.retryHandler = setTimeout(
570
+ () => this.initData(
571
+ true
572
+ ),
573
+ sftpRetryInterval
574
+ )
575
+ this.retryCount++
576
+ } else {
577
+ throw e
578
+ }
579
+ })
580
+ this.setState(() => {
581
+ return {
582
+ loadingSftp: false
583
+ }
584
+ })
585
+ if (!r) {
586
+ sftp.destroy()
587
+ return this.props.editTab(tab.id, {
588
+ sftpCreated: false
589
+ })
590
+ } else {
591
+ this.sftp = sftp
592
+ }
593
+ }
594
+
595
+ if (!remotePath) {
596
+ if (startDirectory) {
597
+ remotePath = startDirectory
598
+ } else {
599
+ remotePath = await this.getPwd(username)
600
+ }
601
+ }
602
+
603
+ let remote = await sftp.list(remotePath)
604
+ this.sftp = sftp
605
+ const remotes = deepCopy(remote)
606
+ remote = []
607
+ for (const _r of remotes) {
608
+ const r = _r
609
+ const { type, name } = r
610
+ const f = {
611
+ ...pick(r, ['name', 'size', 'accessTime', 'modifyTime', 'mode', 'owner', 'group']),
612
+ isDirectory: r.type === fileTypeMap.directory,
613
+ type: typeMap.remote,
614
+ path: remotePath,
615
+ id: generate()
616
+ }
617
+ if (type === fileTypeMap.link) {
618
+ const linkPath = resolve(remotePath, name)
619
+ let realpath = await sftp.readlink(linkPath)
620
+ .catch(e => {
621
+ console.debug(e)
622
+ return null
623
+ })
624
+ if (!realpath) {
625
+ continue
626
+ }
627
+ if (!isAbsPath(realpath)) {
628
+ realpath = resolve(remotePath, realpath)
629
+ realpath = await sftp.realpath(realpath)
630
+ }
631
+ const realFileInfo = await getRemoteFileInfo(
632
+ sftp,
633
+ realpath
634
+ ).catch(e => {
635
+ log.debug('seems a bad symbolic link')
636
+ log.debug(e)
637
+ return null
638
+ })
639
+ if (!realFileInfo) {
640
+ continue
641
+ }
642
+ f.isSymbolicLink = true
643
+ f.isDirectory = realFileInfo.isDirectory
644
+ } else {
645
+ f.isSymbolicLink = false
646
+ }
647
+ remote.push(f)
648
+ }
649
+ const update = {
650
+ remote,
651
+ remoteFileTree: buildTree(remote),
652
+ inited: true,
653
+ remoteLoading: false
654
+ }
655
+ if (!noPathInit) {
656
+ update.remotePath = remotePath
657
+ update.remotePathTemp = remotePath
658
+ }
659
+ if (returnList) {
660
+ return remote
661
+ } else {
662
+ update.onEditFile = false
663
+ }
664
+ if (oldPath) {
665
+ update.remotePathHistory = uniq([
666
+ oldPath,
667
+ ...this.state.remotePathHistory
668
+ ]).slice(0, maxSftpHistory)
669
+ }
670
+ this.setState(update, () => {
671
+ this.props.editTab(tab.id, {
672
+ sftpCreated: true
673
+ })
674
+ })
675
+ } catch (e) {
676
+ const update = {
677
+ remoteLoading: false,
678
+ remote: oldRemote,
679
+ loadingSftp: false
680
+ }
681
+ if (oldPath) {
682
+ update.remotePath = oldPath
683
+ update.remotePathTemp = oldPath
684
+ }
685
+ this.setState(update)
686
+ this.onError(e)
687
+ }
688
+ }
689
+
690
+ localList = async (returnList = false, localPathReal, oldPath) => {
691
+ if (!fs) return
692
+ if (!returnList) {
693
+ this.setState({
694
+ localLoading: true
695
+ })
696
+ }
697
+ const oldLocal = deepCopy(
698
+ this.state.local
699
+ )
700
+ try {
701
+ const noPathInit = localPathReal || this.state.localPath
702
+ const localPath = noPathInit || this.props.tab.startDirectoryLocal || window.pre.homeOrtmp
703
+ const locals = await fs.readdirAsync(localPath)
704
+ const local = []
705
+ for (const name of locals) {
706
+ const p = resolve(localPath, name)
707
+ const fileObj = await getLocalFileInfo(p)
708
+ if (fileObj) {
709
+ local.push(fileObj)
710
+ }
711
+ }
712
+ const update = {
713
+ local,
714
+ inited: true,
715
+ localFileTree: buildTree(local),
716
+ localLoading: false
717
+ }
718
+ if (!noPathInit) {
719
+ update.localPath = localPath
720
+ update.localPathTemp = localPath
721
+ }
722
+ if (returnList) {
723
+ return local
724
+ } else {
725
+ update.onEditFile = false
726
+ }
727
+ if (oldPath) {
728
+ update.localPathHistory = uniq([
729
+ oldPath,
730
+ ...this.state.localPathHistory
731
+ ]).slice(0, maxSftpHistory)
732
+ }
733
+ this.setState(update)
734
+ } catch (e) {
735
+ const update = {
736
+ localLoading: false,
737
+ local: oldLocal
738
+ }
739
+ if (oldPath) {
740
+ update.localPath = oldPath
741
+ update.localPathTemp = oldPath
742
+ }
743
+ this.setState(update)
744
+ this.onError(e)
745
+ }
746
+ }
747
+
748
+ remoteListDebounce = debounce(this.remoteList, 1000)
749
+
750
+ localListDebounce = debounce(this.localList, 1000)
751
+
752
+ timers = {}
753
+
754
+ onChange = (e, prop) => {
755
+ this.setState({
756
+ [prop]: e.target.value
757
+ })
758
+ }
759
+
760
+ onClickHistory = (type, path) => {
761
+ const n = `${type}Path`
762
+ const oldPath = this.state[type + 'Path']
763
+ this.setState({
764
+ [n]: path,
765
+ [`${n}Temp`]: path
766
+ }, () => this[`${type}List`](undefined, undefined, oldPath))
767
+ }
768
+
769
+ onGoto = (type, e) => {
770
+ e && e.preventDefault()
771
+ if (type === typeMap.remote && !this.sftp) {
772
+ return this.initData(true)
773
+ }
774
+ const n = `${type}Path`
775
+ const nt = n + 'Temp'
776
+ const oldPath = this.state[type + 'Path']
777
+ const np = this.state[nt]
778
+ if (!isValidPath(np)) {
779
+ return notification.warning({
780
+ message: 'path not valid'
781
+ })
782
+ }
783
+ this.setState({
784
+ [n]: this.state[nt]
785
+ }, () => this[`${type}List`](undefined, undefined, oldPath))
786
+ }
787
+
788
+ goParent = (type) => {
789
+ const n = `${type}Path`
790
+ const p = this.state[n]
791
+ const np = resolve(p, '..')
792
+ const op = this.state[n]
793
+ if (np !== p) {
794
+ this.setState({
795
+ [n]: np,
796
+ [n + 'Temp']: np
797
+ }, () => this[`${type}List`](
798
+ undefined,
799
+ undefined,
800
+ op
801
+ ))
802
+ }
803
+ }
804
+
805
+ getFileProps = (file, type) => {
806
+ return {
807
+ ...this.props,
808
+ file,
809
+ type,
810
+ ...pick(this, [
811
+ 'sftp',
812
+ 'modifier',
813
+ 'localList',
814
+ 'remoteList',
815
+ 'localDel',
816
+ 'remoteDel',
817
+ 'delFiles',
818
+ 'getIndex',
819
+ 'selectAll',
820
+ 'getFileList',
821
+ 'onGoto',
822
+ 'addTransferList',
823
+ 'renderDelConfirmTitle'
824
+ ]),
825
+ ...pick(this.state, [
826
+ 'id',
827
+ 'localPath',
828
+ 'remotePath',
829
+ 'localFileTree',
830
+ 'remoteFileTree',
831
+ 'localOrder',
832
+ 'remoteOrder',
833
+ 'sortData',
834
+ typeMap.local,
835
+ typeMap.remote,
836
+ 'lastClickedFile',
837
+ 'lastMataKey',
838
+ 'transferToConfirm',
839
+ 'transferList',
840
+ 'targetTransferType',
841
+ 'selectedFiles',
842
+ 'pauseAll',
843
+ 'localGidTree',
844
+ 'remoteUidTree',
845
+ 'localUidTree',
846
+ 'remoteGidTree'
847
+ ])
848
+ }
849
+ }
850
+
851
+ renderEmptyFile = (type) => {
852
+ const item = {
853
+ type,
854
+ name: '',
855
+ isDirectory: true
856
+ }
857
+ return (
858
+ <div
859
+ className={`virtual-file virtual-file-${type}`}
860
+ >
861
+ <FileSection
862
+ {...this.getFileProps(item, type)}
863
+ ref={ref => {
864
+ this[type + 'Dom'] = ref
865
+ }}
866
+ draggable={false}
867
+ cls='virtual-file-unit'
868
+ key={'empty' + type}
869
+ />
870
+ </div>
871
+ )
872
+ }
873
+
874
+ renderHistory = (type) => {
875
+ const currentPath = this.state[type + 'Path']
876
+ const options = this.state[type + 'PathHistory']
877
+ .filter(o => o !== currentPath)
878
+ const focused = this.state[type + 'InputFocus']
879
+ if (!options.length) {
880
+ return null
881
+ }
882
+ const cls = classnames(
883
+ 'sftp-history',
884
+ 'animated',
885
+ `sftp-history-${type}`,
886
+ { focused }
887
+ )
888
+ return (
889
+ <div
890
+ className={cls}
891
+ >
892
+ {
893
+ options.map(o => {
894
+ return (
895
+ <div
896
+ key={o}
897
+ className='sftp-history-item'
898
+ onClick={() => this.onClickHistory(type, o)}
899
+ >
900
+ {o}
901
+ </div>
902
+ )
903
+ })
904
+ }
905
+ </div>
906
+ )
907
+ }
908
+
909
+ renderSection (type, style, width) {
910
+ const {
911
+ id
912
+ } = this.state
913
+ const arr = this.getFileList(type)
914
+ const loading = this.state[`${type}Loading`]
915
+ const { host, username } = this.props.tab
916
+ const listProps = {
917
+ id,
918
+ type,
919
+ ...this.props,
920
+ ...pick(
921
+ this,
922
+ [
923
+ 'directions',
924
+ 'renderEmptyFile',
925
+ 'getFileProps',
926
+ 'defaultDirection',
927
+ 'modifier',
928
+ 'sort'
929
+ ]
930
+ ),
931
+ sortProp: this.state[`sortProp.${type}`],
932
+ sortDirection: this.state[`sortDirection.${type}`],
933
+ width,
934
+ fileList: arr
935
+ }
936
+ const addrProps = {
937
+ host,
938
+ type,
939
+ ...pick(
940
+ this,
941
+ [
942
+ 'onChange',
943
+ 'onGoto',
944
+ 'onInputFocus',
945
+ 'onInputBlur',
946
+ 'toggleShowHiddenFile',
947
+ 'goParent',
948
+ 'onClickHistory'
949
+ ]
950
+ ),
951
+ ...pick(
952
+ this.state,
953
+ [
954
+ `${type}ShowHiddenFile`,
955
+ 'onGoto',
956
+ `${type}PathTemp`,
957
+ `${type}Path`,
958
+ `${type}PathHistory`,
959
+ `${type}InputFocus`,
960
+ 'loadingSftp'
961
+ ]
962
+ )
963
+ }
964
+ return (
965
+ <div
966
+ className={`sftp-section sftp-${type}-section tw-${type}`}
967
+ style={style}
968
+ key={type}
969
+ {...style}
970
+ >
971
+ <Spin spinning={loading}>
972
+ <div className='pd1 sftp-panel'>
973
+ {
974
+ type === typeMap.remote
975
+ ? (
976
+ <div className='pd1t pd1b pd1x alignright'>
977
+ {e('remote')}: {username}@{host}
978
+ </div>
979
+ )
980
+ : (
981
+ <div className='pd1t pd1b pd1x'>
982
+ {e('local')}
983
+ </div>
984
+ )
985
+ }
986
+ <AddressBar
987
+ {...addrProps}
988
+ />
989
+ <div
990
+ className={`file-list ${type} relative`}
991
+ >
992
+ <ListTable
993
+ {...listProps}
994
+ />
995
+ </div>
996
+ </div>
997
+ </Spin>
998
+ </div>
999
+ )
1000
+ }
1001
+
1002
+ renderSections () {
1003
+ if (!this.isActive()) {
1004
+ return null
1005
+ }
1006
+ const arr = [
1007
+ typeMap.local,
1008
+ typeMap.remote
1009
+ ]
1010
+ const {
1011
+ height, width
1012
+ } = this.props
1013
+ const shouldRenderRemote = this.props.tab?.authType &&
1014
+ this.props.tab?.enableSftp !== false
1015
+ if (!shouldRenderRemote) {
1016
+ return (
1017
+ this.renderSection(arr[0], {
1018
+ width,
1019
+ left: 0,
1020
+ top: 0,
1021
+ height
1022
+ }, width)
1023
+ )
1024
+ }
1025
+ return arr.map((t, i) => {
1026
+ const style = {
1027
+ width: width / 2,
1028
+ left: i * width / 2,
1029
+ top: 0,
1030
+ height
1031
+ }
1032
+ return this.renderSection(t, style, width / 2)
1033
+ })
1034
+ }
1035
+
1036
+ render () {
1037
+ const { height } = this.props
1038
+ const {
1039
+ id
1040
+ } = this.state
1041
+ const prps = {
1042
+ localList: this.localList,
1043
+ remoteList: this.remoteList,
1044
+ sftp: this.sftp,
1045
+ sessionId: this.props.sessionId,
1046
+ host: this.props.tab.host,
1047
+ localListDebounce: this.localListDebounce,
1048
+ remoteListDebounce: this.remoteListDebounce,
1049
+ config: this.props.config,
1050
+ tab: this.props.tab,
1051
+ pid: this.props.pid
1052
+ }
1053
+ const all = {
1054
+ className: 'sftp-wrap overhide relative',
1055
+ id: `id-${id}`,
1056
+ style: { height }
1057
+ }
1058
+ return (
1059
+ <div
1060
+ {...all}
1061
+ >
1062
+ {
1063
+ this.renderSections()
1064
+ }
1065
+ <TransportEntry {...prps} />
1066
+ </div>
1067
+ )
1068
+ }
1069
+ }