@electerm/electerm-react 1.37.128 → 1.38.6
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 +2 -1
- package/client/common/default-setting.js +1 -1
- package/client/common/pre.js +1 -1
- package/client/components/main/main.jsx +1 -0
- package/client/components/quick-commands/quick-commands-select.jsx +1 -0
- package/client/components/session/sessions.jsx +7 -0
- package/client/components/setting-panel/setting-modal.jsx +3 -1
- package/client/components/setting-panel/setting-wrap.jsx +10 -0
- package/client/components/setting-panel/setting.styl +8 -1
- package/client/components/shortcuts/shortcut-handler.js +11 -0
- package/client/components/shortcuts/shortcuts-defaults.js +5 -0
- package/client/components/sidebar/sidebar.styl +4 -1
- package/client/components/tabs/index.jsx +9 -2
- package/client/components/tabs/tab.jsx +17 -6
- package/client/components/tabs/tabs.styl +13 -6
- package/client/components/tabs/window-control.jsx +4 -1
- package/client/components/terminal/attach-addon-custom.js +11 -2
- package/client/components/terminal/fs.js +59 -0
- package/client/components/terminal/index.jsx +245 -126
- package/client/components/terminal/xterm-zmodem.js +40 -33
- package/client/store/index.js +0 -5
- package/client/store/init-state.js +2 -1
- package/package.json +1 -1
- package/client/components/terminal/zmodem-transfer.jsx +0 -98
|
@@ -35,7 +35,7 @@ export const filePropMinWidth = 1
|
|
|
35
35
|
export const contextMenuHeight = 28
|
|
36
36
|
export const contextMenuWidth = 280
|
|
37
37
|
export const contextMenuPaddingTop = 10
|
|
38
|
-
export const sftpControlHeight = 28 + 42 + 33 +
|
|
38
|
+
export const sftpControlHeight = 28 + 42 + 33 + 36
|
|
39
39
|
export const sidebarWidth = 43
|
|
40
40
|
export const maxHistory = 50
|
|
41
41
|
export const maxTransport = 5
|
|
@@ -339,3 +339,4 @@ export const instSftpKeys = [
|
|
|
339
339
|
'writeFile'
|
|
340
340
|
]
|
|
341
341
|
export const cwdId = '=__+__'
|
|
342
|
+
export const zmodemTransferPackSize = 1024 * 1024 * 2
|
|
@@ -31,7 +31,7 @@ export default {
|
|
|
31
31
|
checkUpdateOnStart: true,
|
|
32
32
|
cursorBlink: false,
|
|
33
33
|
cursorStyle: 'block',
|
|
34
|
-
useSystemTitleBar: false,
|
|
34
|
+
useSystemTitleBar: window.pre.isLinux || window.et.isLinux || false,
|
|
35
35
|
opacity: 1,
|
|
36
36
|
defaultEditor: '',
|
|
37
37
|
terminalWordSeparator: './\\()"\'-:,.;<>~!@#$%^&*|+=[]{}`~ ?',
|
package/client/common/pre.js
CHANGED
|
@@ -29,6 +29,7 @@ export default class QuickCommandsFooter extends PureComponent {
|
|
|
29
29
|
size='small'
|
|
30
30
|
onMouseEnter={this.handleOpen}
|
|
31
31
|
onMouseLeave={this.handleMouseLeave}
|
|
32
|
+
type='ghost'
|
|
32
33
|
>
|
|
33
34
|
<span className='w500'>{e('quickCommands')}</span>
|
|
34
35
|
<span className='l500'>Q</span>
|
|
@@ -144,7 +144,8 @@ export default class SettingModalWrap extends Component {
|
|
|
144
144
|
const {
|
|
145
145
|
showModal,
|
|
146
146
|
hideSettingModal,
|
|
147
|
-
innerWidth
|
|
147
|
+
innerWidth,
|
|
148
|
+
useSystemTitleBar
|
|
148
149
|
} = this.props.store
|
|
149
150
|
const show = showModal === modals.setting
|
|
150
151
|
if (!show) {
|
|
@@ -154,6 +155,7 @@ export default class SettingModalWrap extends Component {
|
|
|
154
155
|
<SettingModal
|
|
155
156
|
onCancel={hideSettingModal}
|
|
156
157
|
visible={show}
|
|
158
|
+
useSystemTitleBar={useSystemTitleBar}
|
|
157
159
|
innerWidth={innerWidth}
|
|
158
160
|
>
|
|
159
161
|
{this.renderTabs()}
|
|
@@ -6,9 +6,16 @@ import { Component } from 'react'
|
|
|
6
6
|
import { Drawer } from 'antd'
|
|
7
7
|
import { CloseCircleOutlined } from '@ant-design/icons'
|
|
8
8
|
import { sidebarWidth } from '../../common/constants'
|
|
9
|
+
import AppDrag from '../tabs/app-drag'
|
|
9
10
|
import './setting-wrap.styl'
|
|
10
11
|
|
|
11
12
|
export default class SettingWrap extends Component {
|
|
13
|
+
renderDrag () {
|
|
14
|
+
return (
|
|
15
|
+
<AppDrag />
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
12
19
|
render () {
|
|
13
20
|
const pops = {
|
|
14
21
|
open: this.props.visible,
|
|
@@ -32,6 +39,9 @@ export default class SettingWrap extends Component {
|
|
|
32
39
|
className='close-setting-wrap'
|
|
33
40
|
onClick={this.props.onCancel}
|
|
34
41
|
/>
|
|
42
|
+
{
|
|
43
|
+
this.props.useSystemTitleBar ? null : <AppDrag />
|
|
44
|
+
}
|
|
35
45
|
{this.props.visible ? this.props.children : null}
|
|
36
46
|
</Drawer>
|
|
37
47
|
)
|
|
@@ -75,6 +75,17 @@ export function shortcutExtend (Cls) {
|
|
|
75
75
|
) {
|
|
76
76
|
return true
|
|
77
77
|
}
|
|
78
|
+
if (
|
|
79
|
+
this.term &&
|
|
80
|
+
key === 'c' &&
|
|
81
|
+
type === 'keydown' &&
|
|
82
|
+
!altKey &&
|
|
83
|
+
!shiftKey &&
|
|
84
|
+
ctrlKey &&
|
|
85
|
+
this.onZmodem
|
|
86
|
+
) {
|
|
87
|
+
this.onZmodemEnd()
|
|
88
|
+
}
|
|
78
89
|
const codeName = event instanceof window.WheelEvent
|
|
79
90
|
? (wheelDeltaY > 0 ? 'mouseWheelUp' : 'mouseWheelDown')
|
|
80
91
|
: code
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
box-shadow 0px 0px 3px 3px alpha(main, .1)
|
|
27
27
|
.item-list
|
|
28
28
|
padding-right 0
|
|
29
|
+
.not-system-ui.is-mac
|
|
30
|
+
.sidebar-bar
|
|
31
|
+
margin-top 20px
|
|
29
32
|
.type-bookmarks
|
|
30
33
|
.bookmarks-panel
|
|
31
34
|
width 100%
|
|
@@ -50,7 +53,7 @@
|
|
|
50
53
|
.sidebar-list
|
|
51
54
|
position absolute
|
|
52
55
|
left 43px
|
|
53
|
-
top
|
|
56
|
+
top 36px
|
|
54
57
|
bottom 0
|
|
55
58
|
z-index 200
|
|
56
59
|
width 0
|
|
@@ -18,7 +18,13 @@ import {
|
|
|
18
18
|
import { Dropdown, Menu, Popover } from 'antd'
|
|
19
19
|
import Tab from './tab'
|
|
20
20
|
import './tabs.styl'
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
tabWidth,
|
|
23
|
+
tabMargin,
|
|
24
|
+
extraTabWidth,
|
|
25
|
+
windowControlWidth,
|
|
26
|
+
isMacJs
|
|
27
|
+
} from '../../common/constants'
|
|
22
28
|
import findParentBySel from '../../common/find-parent'
|
|
23
29
|
import WindowControl from './window-control'
|
|
24
30
|
import BookmarksList from '../sidebar/bookmark-select'
|
|
@@ -239,8 +245,9 @@ export default class Tabs extends React.Component {
|
|
|
239
245
|
const left = overflow
|
|
240
246
|
? '100%'
|
|
241
247
|
: tabsWidthAll
|
|
248
|
+
const w1 = isMacJs ? 30 : windowControlWidth
|
|
242
249
|
const style = {
|
|
243
|
-
width: width -
|
|
250
|
+
width: width - w1 - 136
|
|
244
251
|
}
|
|
245
252
|
return (
|
|
246
253
|
<div
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* file section
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import { Component } from 'react'
|
|
6
6
|
import runIdle from '../../common/run-idle'
|
|
7
7
|
import {
|
|
8
8
|
CloseOutlined,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
terminalSshConfigType,
|
|
22
22
|
commonActions
|
|
23
23
|
} from '../../common/constants'
|
|
24
|
-
import
|
|
24
|
+
import { shortcutDescExtend } from '../shortcuts/shortcut-handler.js'
|
|
25
25
|
|
|
26
26
|
const { prefix } = window
|
|
27
27
|
const e = prefix('tabs')
|
|
@@ -29,7 +29,7 @@ const m = prefix('menu')
|
|
|
29
29
|
const onDragCls = 'ondrag-tab'
|
|
30
30
|
const onDragOverCls = 'dragover-tab'
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
class Tab extends Component {
|
|
33
33
|
constructor (props) {
|
|
34
34
|
super(props)
|
|
35
35
|
this.state = {
|
|
@@ -245,13 +245,14 @@ export default class Tab extends React.Component {
|
|
|
245
245
|
setTabs(tabs)
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
renderContext () {
|
|
248
|
+
renderContext = () => {
|
|
249
249
|
const { tabs, tab } = this.props
|
|
250
250
|
const len = tabs.length
|
|
251
251
|
const index = findIndex(tabs, t => t.id === tab.id)
|
|
252
252
|
const noRight = index >= len - 1
|
|
253
253
|
const isSshConfig = tab.type === terminalSshConfigType
|
|
254
254
|
const res = []
|
|
255
|
+
const reloadShortcut = this.getShortcut('app_reloadCurrentTab')
|
|
255
256
|
res.push({
|
|
256
257
|
func: 'handleClose',
|
|
257
258
|
icon: 'CloseOutlined',
|
|
@@ -288,7 +289,8 @@ export default class Tab extends React.Component {
|
|
|
288
289
|
res.push({
|
|
289
290
|
func: 'handleReloadTab',
|
|
290
291
|
icon: 'Loading3QuartersOutlined',
|
|
291
|
-
text: m('reload')
|
|
292
|
+
text: m('reload'),
|
|
293
|
+
subText: reloadShortcut
|
|
292
294
|
})
|
|
293
295
|
return res
|
|
294
296
|
}
|
|
@@ -379,6 +381,10 @@ export default class Tab extends React.Component {
|
|
|
379
381
|
if (isEditting) {
|
|
380
382
|
return this.renderEditting(tab, cls)
|
|
381
383
|
}
|
|
384
|
+
const { tabCount, color } = tab
|
|
385
|
+
const styleTag = color
|
|
386
|
+
? { borderTop: `1px solid ${color}` }
|
|
387
|
+
: {}
|
|
382
388
|
return (
|
|
383
389
|
<Tooltip
|
|
384
390
|
title={title}
|
|
@@ -404,6 +410,7 @@ export default class Tab extends React.Component {
|
|
|
404
410
|
className='tab-title elli pd1x'
|
|
405
411
|
onClick={this.handleClick}
|
|
406
412
|
onDoubleClick={this.handleDup}
|
|
413
|
+
style={styleTag}
|
|
407
414
|
onContextMenu={this.handleContextMenu}
|
|
408
415
|
>
|
|
409
416
|
<Loading3QuartersOutlined
|
|
@@ -411,7 +418,9 @@ export default class Tab extends React.Component {
|
|
|
411
418
|
onClick={this.handleReloadTab}
|
|
412
419
|
title={m('reload')}
|
|
413
420
|
/>
|
|
414
|
-
<
|
|
421
|
+
<span className='tab-title'>
|
|
422
|
+
{tabCount}. {title}
|
|
423
|
+
</span>
|
|
415
424
|
</div>
|
|
416
425
|
<div className={'tab-status ' + status} />
|
|
417
426
|
<div className='tab-traffic' />
|
|
@@ -424,3 +433,5 @@ export default class Tab extends React.Component {
|
|
|
424
433
|
)
|
|
425
434
|
}
|
|
426
435
|
}
|
|
436
|
+
|
|
437
|
+
export default shortcutDescExtend(Tab)
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
@require '../../css/includes/theme-default'
|
|
2
2
|
.tabs
|
|
3
3
|
position relative
|
|
4
|
-
height
|
|
4
|
+
height 36px
|
|
5
5
|
overflow hidden
|
|
6
6
|
background main-dark
|
|
7
|
-
|
|
7
|
+
::-webkit-scrollbar
|
|
8
|
+
width 0
|
|
9
|
+
display none
|
|
10
|
+
.not-system-ui.is-mac
|
|
11
|
+
.tabs-inner
|
|
12
|
+
margin-left 72px
|
|
13
|
+
.tabs-extra
|
|
14
|
+
right 0
|
|
8
15
|
.tabs-inner
|
|
9
16
|
position relative
|
|
10
17
|
z-index 2
|
|
11
18
|
padding 0
|
|
12
19
|
margin-top 0
|
|
13
20
|
display inline-block
|
|
14
|
-
height
|
|
21
|
+
height 36px
|
|
15
22
|
overflow-x scroll
|
|
16
23
|
overflow-y hidden
|
|
17
24
|
margin-left 42px
|
|
@@ -25,7 +32,7 @@
|
|
|
25
32
|
min-width 100px
|
|
26
33
|
max-width 200px
|
|
27
34
|
line-height 36px
|
|
28
|
-
margin
|
|
35
|
+
margin 0 1px 0 0
|
|
29
36
|
border-radius 3px 3px 0 0
|
|
30
37
|
background main-dark
|
|
31
38
|
text-align center
|
|
@@ -118,13 +125,13 @@
|
|
|
118
125
|
.tabs-add-btn
|
|
119
126
|
display inline-block
|
|
120
127
|
vertical-align middle
|
|
121
|
-
margin
|
|
128
|
+
margin 0 3px 0 3px
|
|
122
129
|
-webkit-app-region no-drag
|
|
123
130
|
color text
|
|
124
131
|
&.empty
|
|
125
132
|
font-size 20px
|
|
126
133
|
margin-left 20px
|
|
127
|
-
margin-top
|
|
134
|
+
margin-top 10px
|
|
128
135
|
&:hover
|
|
129
136
|
color text-light
|
|
130
137
|
.tabs-extra
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import { CloseOutlined, MinusOutlined } from '@ant-design/icons'
|
|
6
6
|
import { Component } from '../common/react-subx'
|
|
7
|
+
import {
|
|
8
|
+
isMacJs
|
|
9
|
+
} from '../../common/constants'
|
|
7
10
|
|
|
8
11
|
const { prefix } = window
|
|
9
12
|
const m = prefix('menu')
|
|
@@ -14,7 +17,7 @@ export default class WindowControl extends Component {
|
|
|
14
17
|
isMaximized,
|
|
15
18
|
config
|
|
16
19
|
} = this.props.store
|
|
17
|
-
if (config.useSystemTitleBar) {
|
|
20
|
+
if (config.useSystemTitleBar || isMacJs) {
|
|
18
21
|
return null
|
|
19
22
|
}
|
|
20
23
|
const minimize = () => {
|
|
@@ -7,12 +7,16 @@ import strip from '@electerm/strip-ansi'
|
|
|
7
7
|
export default class AttachAddonCustom extends AttachAddon {
|
|
8
8
|
constructor (term, options, encode, isWindowsShell) {
|
|
9
9
|
super(term, options)
|
|
10
|
+
this.term = term
|
|
10
11
|
this.decoder = new TextDecoder(encode)
|
|
11
12
|
this.isWindowsShell = isWindowsShell
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
activate (terminal) {
|
|
15
|
+
activate (terminal = this.term) {
|
|
15
16
|
const writeToTerminal = (data) => {
|
|
17
|
+
if (terminal.parent?.onZmodem) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
16
20
|
if (typeof data === 'string') {
|
|
17
21
|
return terminal.write(data)
|
|
18
22
|
}
|
|
@@ -79,6 +83,12 @@ export default class AttachAddonCustom extends AttachAddon {
|
|
|
79
83
|
this._disposables.push(addSocketListener(this._socket, 'close', () => this.dispose()))
|
|
80
84
|
this._disposables.push(addSocketListener(this._socket, 'error', () => this.dispose()))
|
|
81
85
|
}
|
|
86
|
+
|
|
87
|
+
dispose () {
|
|
88
|
+
this.term = null
|
|
89
|
+
this._disposables.forEach(d => d.dispose())
|
|
90
|
+
this._disposables.length = 0
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
|
|
84
94
|
function addSocketListener (socket, type, handler) {
|
|
@@ -86,7 +96,6 @@ function addSocketListener (socket, type, handler) {
|
|
|
86
96
|
return {
|
|
87
97
|
dispose: () => {
|
|
88
98
|
if (!handler) {
|
|
89
|
-
// Already disposed
|
|
90
99
|
return
|
|
91
100
|
}
|
|
92
101
|
socket.removeEventListener(type, handler)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export const open = (filePath, flag) => {
|
|
2
|
+
const fs = window.require('fs')
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
fs.open(filePath, flag, (err, fd) => {
|
|
5
|
+
if (err) {
|
|
6
|
+
return reject(err)
|
|
7
|
+
}
|
|
8
|
+
return resolve(fd)
|
|
9
|
+
})
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const close = (fd) => {
|
|
14
|
+
const fs = window.require('fs')
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
fs.close(fd, (err) => {
|
|
17
|
+
if (err) {
|
|
18
|
+
return reject(err)
|
|
19
|
+
}
|
|
20
|
+
return resolve(true)
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const exists = (filePath) => {
|
|
26
|
+
const fs = window.require('fs')
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
fs.access(filePath, (err) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
return reject(err)
|
|
31
|
+
}
|
|
32
|
+
return resolve(true)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const read = (fd, buffer, offset, length, position) => {
|
|
38
|
+
const fs = window.require('fs')
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
fs.read(fd, buffer, offset, length, position, (err, bytesRead, buffer) => {
|
|
41
|
+
if (err) {
|
|
42
|
+
return reject(err)
|
|
43
|
+
}
|
|
44
|
+
return resolve(buffer.subarray(0, bytesRead))
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const write = (fd, buffer) => {
|
|
50
|
+
const fs = window.require('fs')
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
fs.write(fd, buffer, (err, buffer) => {
|
|
53
|
+
if (err) {
|
|
54
|
+
return reject(err)
|
|
55
|
+
}
|
|
56
|
+
return resolve(buffer)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Component } from 'react'
|
|
2
|
-
import ZmodemTransfer from './zmodem-transfer'
|
|
3
2
|
import { handleErr } from '../../common/fetch'
|
|
4
3
|
import generate from '../../common/uid'
|
|
5
4
|
import { isEqual, pick, debounce, throttle } from 'lodash-es'
|
|
@@ -27,7 +26,8 @@ import {
|
|
|
27
26
|
commonActions,
|
|
28
27
|
rendererTypes,
|
|
29
28
|
cwdId,
|
|
30
|
-
isMac
|
|
29
|
+
isMac,
|
|
30
|
+
zmodemTransferPackSize
|
|
31
31
|
} from '../../common/constants'
|
|
32
32
|
import deepCopy from 'json-deep-copy'
|
|
33
33
|
import { readClipboardAsync, copy } from '../../common/clipboard'
|
|
@@ -39,7 +39,7 @@ import { CanvasAddon } from 'xterm-addon-canvas'
|
|
|
39
39
|
import { WebglAddon } from 'xterm-addon-webgl'
|
|
40
40
|
import { LigaturesAddon } from 'xterm-addon-ligatures'
|
|
41
41
|
import getProxy from '../../common/get-proxy'
|
|
42
|
-
import {
|
|
42
|
+
import { AddonZmodem } from './xterm-zmodem'
|
|
43
43
|
import { Unicode11Addon } from 'xterm-addon-unicode11'
|
|
44
44
|
import keyControlPressed from '../../common/key-control-pressed'
|
|
45
45
|
import { Terminal } from 'xterm'
|
|
@@ -47,8 +47,11 @@ import NormalBuffer from './normal-buffer'
|
|
|
47
47
|
import { createTerm, resizeTerm } from './terminal-apis'
|
|
48
48
|
import { shortcutExtend, shortcutDescExtend } from '../shortcuts/shortcut-handler.js'
|
|
49
49
|
import { KeywordHighlighterAddon } from './highlight-addon.js'
|
|
50
|
+
import { getLocalFileInfo } from '../sftp/file-read.js'
|
|
50
51
|
import { SerializeAddon } from 'xterm-addon-serialize'
|
|
51
52
|
import strip from '@electerm/strip-ansi'
|
|
53
|
+
import { formatBytes } from '../../common/byte-format.js'
|
|
54
|
+
import * as fs from './fs.js'
|
|
52
55
|
|
|
53
56
|
const { prefix } = window
|
|
54
57
|
const e = prefix('ssh')
|
|
@@ -71,7 +74,6 @@ class Term extends Component {
|
|
|
71
74
|
saveTerminalLogToFile: !!this.props.config.saveTerminalLogToFile,
|
|
72
75
|
addTimeStampToTermLog: !!this.props.config.addTimeStampToTermLog,
|
|
73
76
|
passType: 'password',
|
|
74
|
-
zmodemTransfer: null,
|
|
75
77
|
lines: []
|
|
76
78
|
}
|
|
77
79
|
}
|
|
@@ -128,6 +130,9 @@ class Term extends Component {
|
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
componentWillUnmount () {
|
|
133
|
+
if (this.zsession) {
|
|
134
|
+
this.onZmodemEnd()
|
|
135
|
+
}
|
|
131
136
|
delete this.term.parent
|
|
132
137
|
Object.keys(this.timers).forEach(k => {
|
|
133
138
|
clearTimeout(this.timers[k])
|
|
@@ -161,6 +166,21 @@ class Term extends Component {
|
|
|
161
166
|
}
|
|
162
167
|
]
|
|
163
168
|
|
|
169
|
+
initAttachAddon = (encode) => {
|
|
170
|
+
this.attachAddon = new AttachAddon(
|
|
171
|
+
this.socket,
|
|
172
|
+
undefined,
|
|
173
|
+
this.props.tab.encode,
|
|
174
|
+
isWin && !this.isRemote()
|
|
175
|
+
)
|
|
176
|
+
if (encode || this.decode) {
|
|
177
|
+
this.attachAddon.decoder = encode
|
|
178
|
+
? new TextDecoder(encode)
|
|
179
|
+
: this.decode
|
|
180
|
+
}
|
|
181
|
+
this.term.loadAddon(this.attachAddon)
|
|
182
|
+
}
|
|
183
|
+
|
|
164
184
|
getValue = (props, type, name) => {
|
|
165
185
|
return type === 'glob'
|
|
166
186
|
? props.config[name]
|
|
@@ -420,152 +440,259 @@ class Term extends Component {
|
|
|
420
440
|
log.debug('zmodemRetract')
|
|
421
441
|
}
|
|
422
442
|
|
|
423
|
-
|
|
424
|
-
// * zmodem transfer
|
|
425
|
-
// * then run rz to send from your browser or
|
|
426
|
-
// * sz <file> to send from the remote peer.
|
|
443
|
+
writeBanner = (type) => {
|
|
427
444
|
this.term.write('\r\nRecommmend use trzsz instead: https://github.com/trzsz/trzsz\r\n')
|
|
445
|
+
this.term.write(`\x1b[32mZMODEM::${type}::START\x1b[0m\r\n\r\n`)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
onReceiveZmodemSession = async () => {
|
|
449
|
+
const savePath = await this.openSaveFolderSelect()
|
|
428
450
|
this.zsession.on('offer', this.onOfferReceive)
|
|
429
451
|
this.zsession.start()
|
|
452
|
+
this.term.write('\r\n\x1b[2A\r\n')
|
|
453
|
+
if (!savePath) {
|
|
454
|
+
return this.onZmodemEnd()
|
|
455
|
+
}
|
|
456
|
+
this.writeBanner('RECEIVE')
|
|
457
|
+
this.zmodemSavePath = savePath
|
|
430
458
|
return new Promise((resolve) => {
|
|
431
459
|
this.zsession.on('session_end', resolve)
|
|
432
|
-
})
|
|
460
|
+
})
|
|
461
|
+
.then(this.onZmodemEnd)
|
|
462
|
+
.catch(this.onZmodemCatch)
|
|
433
463
|
}
|
|
434
464
|
|
|
435
|
-
|
|
436
|
-
if (this.
|
|
465
|
+
initZmodemDownload = async (name, size) => {
|
|
466
|
+
if (!this.zmodemSavePath) {
|
|
437
467
|
return
|
|
438
468
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
if (percent > 99) {
|
|
446
|
-
percent = 99
|
|
469
|
+
let pth = window.pre.resolve(
|
|
470
|
+
this.zmodemSavePath, name
|
|
471
|
+
)
|
|
472
|
+
const exist = await fs.exists(pth)
|
|
473
|
+
if (exist) {
|
|
474
|
+
pth = pth + '.' + generate()
|
|
447
475
|
}
|
|
448
|
-
this.
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
476
|
+
const fd = await fs.open(pth, 'w').catch(this.onZmodemEnd)
|
|
477
|
+
this.downloadFd = fd
|
|
478
|
+
this.downloadPath = pth
|
|
479
|
+
this.downloadCount = 0
|
|
480
|
+
this.zmodemStartTime = Date.now()
|
|
481
|
+
this.downloadSize = size
|
|
482
|
+
this.updateZmodemProgress(
|
|
483
|
+
0, pth, size, transferTypeMap.download
|
|
484
|
+
)
|
|
485
|
+
return fd
|
|
456
486
|
}
|
|
457
487
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
488
|
+
onOfferReceive = async (xfer) => {
|
|
489
|
+
const {
|
|
490
|
+
name,
|
|
491
|
+
size
|
|
492
|
+
} = xfer.get_details()
|
|
493
|
+
if (!this.downloadFd) {
|
|
494
|
+
await this.initZmodemDownload(name, size)
|
|
495
|
+
}
|
|
496
|
+
xfer.on('input', this.onZmodemDownload)
|
|
497
|
+
this.xfer = xfer
|
|
498
|
+
await xfer.accept()
|
|
499
|
+
.then(this.finishZmodemTransfer)
|
|
500
|
+
.catch(this.onZmodemEnd)
|
|
461
501
|
}
|
|
462
502
|
|
|
463
|
-
|
|
464
|
-
this.
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
this.updateProgress(xfer, transferTypeMap.download)
|
|
468
|
-
FILE_BUFFER.push(new Uint8Array(payload))
|
|
469
|
-
})
|
|
470
|
-
xfer.accept()
|
|
471
|
-
.then(
|
|
472
|
-
() => {
|
|
473
|
-
this.saveToDisk(xfer, FILE_BUFFER)
|
|
474
|
-
}
|
|
475
|
-
)
|
|
476
|
-
.catch(window.store.onError)
|
|
503
|
+
checkCache = async () => {
|
|
504
|
+
if (this.DownloadCache?.length > 0) {
|
|
505
|
+
return fs.write(this.downloadFd, new Uint8Array(this.DownloadCache))
|
|
506
|
+
}
|
|
477
507
|
}
|
|
478
508
|
|
|
479
|
-
|
|
480
|
-
if (!
|
|
481
|
-
return
|
|
509
|
+
onZmodemDownload = async payload => {
|
|
510
|
+
if (this.onCanceling || !this.downloadFd) {
|
|
511
|
+
return
|
|
482
512
|
}
|
|
483
|
-
//
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
//
|
|
491
|
-
//
|
|
492
|
-
//
|
|
493
|
-
//
|
|
494
|
-
// // return this.transferBySftp(files)
|
|
495
|
-
// // } else {
|
|
496
|
-
// const url = 'https://github.com/FGasper/zmodemjs/issues/11'
|
|
497
|
-
// const msg = (
|
|
498
|
-
// <div>
|
|
499
|
-
// <p>Currently <b>rz</b> only support upload file size less than {filesize(maxZmodemUploadSize)}, due to known issue:</p>
|
|
500
|
-
// <p><Link to={url}>{url}</Link></p>
|
|
501
|
-
// <p>You can try upload in sftp which is much faster.</p>
|
|
502
|
-
// </div>
|
|
513
|
+
// if (!this.DownloadCache) {
|
|
514
|
+
// this.DownloadCache = []
|
|
515
|
+
// }
|
|
516
|
+
// this.DownloadCache = this.DownloadCache.concat(payload)
|
|
517
|
+
// this.downloadCount += payload.length
|
|
518
|
+
// if (this.DownloadCache.length < zmodemTransferPackSize) {
|
|
519
|
+
// return this.updateZmodemProgress(
|
|
520
|
+
// this.downloadCount,
|
|
521
|
+
// this.downloadPath,
|
|
522
|
+
// this.downloadSize,
|
|
523
|
+
// transferTypeMap.download
|
|
503
524
|
// )
|
|
504
|
-
// notification.error({
|
|
505
|
-
// message: msg,
|
|
506
|
-
// duration: 8
|
|
507
|
-
// })
|
|
508
|
-
// // }
|
|
509
525
|
// }
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
on_progress (obj, xfer) {
|
|
520
|
-
th.updateProgress(xfer, transferTypeMap.upload)
|
|
521
|
-
}
|
|
522
|
-
}
|
|
526
|
+
// this.writeCache = this.DownloadCache
|
|
527
|
+
// this.DownloadCache = []
|
|
528
|
+
this.downloadCount += payload.length
|
|
529
|
+
await fs.write(this.downloadFd, new Uint8Array(payload))
|
|
530
|
+
this.updateZmodemProgress(
|
|
531
|
+
this.downloadCount,
|
|
532
|
+
this.downloadPath,
|
|
533
|
+
this.downloadSize,
|
|
534
|
+
transferTypeMap.download
|
|
523
535
|
)
|
|
524
|
-
|
|
525
|
-
.catch(th.onZmodemCatch)
|
|
536
|
+
}
|
|
526
537
|
|
|
527
|
-
|
|
538
|
+
updateZmodemProgress = throttle((start, name, size, type) => {
|
|
539
|
+
this.zmodemTransfer = {
|
|
540
|
+
type,
|
|
541
|
+
start,
|
|
542
|
+
name,
|
|
543
|
+
size
|
|
544
|
+
}
|
|
545
|
+
this.writeZmodemProgress()
|
|
546
|
+
}, 500)
|
|
547
|
+
|
|
548
|
+
finishZmodemTransfer = () => {
|
|
549
|
+
this.zmodemTransfer = {
|
|
550
|
+
...this.zmodemTransfer,
|
|
551
|
+
start: this.zmodemTransfer.size
|
|
552
|
+
}
|
|
553
|
+
this.writeZmodemProgress()
|
|
528
554
|
}
|
|
529
555
|
|
|
530
|
-
|
|
531
|
-
this.
|
|
532
|
-
return
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
556
|
+
writeZmodemProgress = () => {
|
|
557
|
+
if (this.onCanceling) {
|
|
558
|
+
return
|
|
559
|
+
}
|
|
560
|
+
const {
|
|
561
|
+
size, start, name
|
|
562
|
+
} = this.zmodemTransfer
|
|
563
|
+
const speed = size > 0 ? formatBytes(start * 1000 / 1024 / (Date.now() - this.zmodemStartTime)) : 0
|
|
564
|
+
const percent = size > 0 ? Math.floor(start * 100 / size) : 100
|
|
565
|
+
const str = `\x1b[32m${name}\x1b[0m::${percent}%,${start}/${size},${speed}/s`
|
|
566
|
+
this.term.write('\r\n\x1b[2A' + str + '\n')
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
zmodemTransferFile = async (file, filesRemaining, sizeRemaining) => {
|
|
570
|
+
const offer = {
|
|
571
|
+
obj: file,
|
|
572
|
+
name: file.name,
|
|
573
|
+
size: file.size,
|
|
574
|
+
files_remaining: filesRemaining,
|
|
575
|
+
bytes_remaining: sizeRemaining
|
|
576
|
+
}
|
|
577
|
+
const xfer = await this.zsession.send_offer(offer)
|
|
578
|
+
if (!xfer) {
|
|
579
|
+
this.onZmodemEnd()
|
|
580
|
+
return window.store.onError(new Error('Transfer cancelled, maybe file already exists'))
|
|
581
|
+
}
|
|
582
|
+
this.zmodemStartTime = Date.now()
|
|
583
|
+
const fd = await fs.open(file.filePath, 'r')
|
|
584
|
+
let start = 0
|
|
585
|
+
const { size } = file
|
|
586
|
+
let inited = false
|
|
587
|
+
while (start < size || !inited) {
|
|
588
|
+
const rest = size - start
|
|
589
|
+
const len = rest > zmodemTransferPackSize ? zmodemTransferPackSize : rest
|
|
590
|
+
const buffer = new Uint8Array(len)
|
|
591
|
+
const newArr = await fs.read(fd, buffer, 0, len, null)
|
|
592
|
+
const n = newArr.length
|
|
593
|
+
await xfer.send(newArr)
|
|
594
|
+
start = start + n
|
|
595
|
+
inited = true
|
|
596
|
+
this.updateZmodemProgress(start, file.name, size, transferTypeMap.upload)
|
|
597
|
+
if (n < zmodemTransferPackSize || start >= file.size || this.onCanceling) {
|
|
598
|
+
break
|
|
536
599
|
}
|
|
600
|
+
}
|
|
601
|
+
await fs.close(fd)
|
|
602
|
+
this.finishZmodemTransfer()
|
|
603
|
+
await xfer.end()
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
openFileSelect = async () => {
|
|
607
|
+
const properties = [
|
|
608
|
+
'openFile',
|
|
609
|
+
'multiSelections',
|
|
610
|
+
'showHiddenFiles',
|
|
611
|
+
'noResolveAliases',
|
|
612
|
+
'treatPackageAsDirectory',
|
|
613
|
+
'dontAddToRecent'
|
|
614
|
+
]
|
|
615
|
+
const files = await window.api.openDialog({
|
|
616
|
+
title: 'Choose some files to send',
|
|
617
|
+
message: 'Choose some files to send',
|
|
618
|
+
properties
|
|
537
619
|
})
|
|
620
|
+
if (!files || !files.length) {
|
|
621
|
+
return this.onZmodemEnd()
|
|
622
|
+
}
|
|
623
|
+
const r = []
|
|
624
|
+
for (const filePath of files) {
|
|
625
|
+
const stat = await getLocalFileInfo(filePath)
|
|
626
|
+
r.push({ ...stat, filePath })
|
|
627
|
+
}
|
|
628
|
+
return r
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
openSaveFolderSelect = async () => {
|
|
632
|
+
const savePaths = await window.api.openDialog({
|
|
633
|
+
title: 'Choose a folder to save file(s)',
|
|
634
|
+
message: 'Choose a folder to save file(s)',
|
|
635
|
+
properties: [
|
|
636
|
+
'openDirectory',
|
|
637
|
+
'showHiddenFiles',
|
|
638
|
+
'createDirectory',
|
|
639
|
+
'noResolveAliases',
|
|
640
|
+
'treatPackageAsDirectory',
|
|
641
|
+
'dontAddToRecent'
|
|
642
|
+
]
|
|
643
|
+
})
|
|
644
|
+
if (!savePaths || !savePaths.length) {
|
|
645
|
+
return false
|
|
646
|
+
}
|
|
647
|
+
return savePaths[0]
|
|
538
648
|
}
|
|
539
649
|
|
|
540
|
-
|
|
541
|
-
|
|
650
|
+
beforeZmodemUpload = async (files) => {
|
|
651
|
+
if (!files || !files.length) {
|
|
652
|
+
return false
|
|
653
|
+
}
|
|
654
|
+
this.writeBanner('SEND')
|
|
655
|
+
let filesRemaining = files.length
|
|
656
|
+
let sizeRemaining = files.reduce((a, b) => a + b.size, 0)
|
|
657
|
+
for (const f of files) {
|
|
658
|
+
await this.zmodemTransferFile(f, filesRemaining, sizeRemaining)
|
|
659
|
+
filesRemaining = filesRemaining - 1
|
|
660
|
+
sizeRemaining = sizeRemaining - f.size
|
|
661
|
+
}
|
|
662
|
+
this.onZmodemEnd()
|
|
542
663
|
}
|
|
543
664
|
|
|
544
|
-
|
|
545
|
-
this.
|
|
546
|
-
this.
|
|
665
|
+
onSendZmodemSession = async () => {
|
|
666
|
+
this.term.write('\r\n\x1b[2A\n')
|
|
667
|
+
const files = await this.openFileSelect()
|
|
668
|
+
this.beforeZmodemUpload(files)
|
|
547
669
|
}
|
|
548
670
|
|
|
549
|
-
onZmodemEnd = () => {
|
|
550
|
-
delete this.
|
|
671
|
+
onZmodemEnd = async () => {
|
|
672
|
+
delete this.zmodemSavePath
|
|
551
673
|
this.onCanceling = true
|
|
552
|
-
this.
|
|
553
|
-
this.
|
|
554
|
-
undefined,
|
|
555
|
-
this.props.tab.encode,
|
|
556
|
-
isWin && !this.isRemote()
|
|
557
|
-
)
|
|
558
|
-
if (this.decoder) {
|
|
559
|
-
this.attachAddon.decoder = this.decode
|
|
674
|
+
if (this.downloadFd) {
|
|
675
|
+
await fs.close(this.downloadFd)
|
|
560
676
|
}
|
|
561
|
-
this.
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
677
|
+
if (this.xfer && this.xfer.end) {
|
|
678
|
+
await this.xfer.end().catch(
|
|
679
|
+
console.error
|
|
680
|
+
)
|
|
681
|
+
}
|
|
682
|
+
delete this.xfer
|
|
683
|
+
if (this.zsession && this.zsession.close) {
|
|
684
|
+
await this.zsession.close().catch(
|
|
685
|
+
console.error
|
|
686
|
+
)
|
|
687
|
+
}
|
|
688
|
+
delete this.zsession
|
|
567
689
|
this.term.focus()
|
|
568
690
|
this.term.write('\r\n')
|
|
691
|
+
delete this.downloadFd
|
|
692
|
+
delete this.downloadPath
|
|
693
|
+
delete this.downloadCount
|
|
694
|
+
delete this.downloadSize
|
|
695
|
+
delete this.DownloadCache
|
|
569
696
|
}
|
|
570
697
|
|
|
571
698
|
onZmodemCatch = (e) => {
|
|
@@ -575,7 +702,6 @@ class Term extends Component {
|
|
|
575
702
|
|
|
576
703
|
onZmodemDetect = detection => {
|
|
577
704
|
this.onCanceling = false
|
|
578
|
-
this.attachAddon.dispose()
|
|
579
705
|
this.term.blur()
|
|
580
706
|
this.onZmodem = true
|
|
581
707
|
const zsession = detection.confirm()
|
|
@@ -1055,9 +1181,7 @@ class Term extends Component {
|
|
|
1055
1181
|
this.zmodemAddon = new AddonZmodem()
|
|
1056
1182
|
this.fitAddon.fit()
|
|
1057
1183
|
term.loadAddon(this.zmodemAddon)
|
|
1058
|
-
term.zmodemAttach(this
|
|
1059
|
-
noTerminalWriteOutsideSession: true
|
|
1060
|
-
}, this)
|
|
1184
|
+
term.zmodemAttach(this)
|
|
1061
1185
|
}
|
|
1062
1186
|
term.displayRaw = displayRaw
|
|
1063
1187
|
term.loadAddon(
|
|
@@ -1085,7 +1209,7 @@ class Term extends Component {
|
|
|
1085
1209
|
|
|
1086
1210
|
onerrorSocket = err => {
|
|
1087
1211
|
this.setStatus(statusMap.error)
|
|
1088
|
-
log.
|
|
1212
|
+
log.error('onerrorSocket', err)
|
|
1089
1213
|
}
|
|
1090
1214
|
|
|
1091
1215
|
oncloseSocket = () => {
|
|
@@ -1184,7 +1308,7 @@ class Term extends Component {
|
|
|
1184
1308
|
}
|
|
1185
1309
|
|
|
1186
1310
|
render () {
|
|
1187
|
-
const { id, loading
|
|
1311
|
+
const { id, loading } = this.state
|
|
1188
1312
|
const { height, width, left, top, position, id: pid, activeSplitId } = this.props
|
|
1189
1313
|
const cls = classnames('term-wrap', {
|
|
1190
1314
|
'not-first-term': !!position
|
|
@@ -1242,11 +1366,6 @@ class Term extends Component {
|
|
|
1242
1366
|
close={this.closeNormalBuffer}
|
|
1243
1367
|
/>
|
|
1244
1368
|
</div>
|
|
1245
|
-
<ZmodemTransfer
|
|
1246
|
-
zmodemTransfer={zmodemTransfer}
|
|
1247
|
-
cancelZmodem={this.cancelZmodem}
|
|
1248
|
-
beforeZmodemUpload={this.beforeZmodemUpload}
|
|
1249
|
-
/>
|
|
1250
1369
|
<Spin className='loading-wrapper' spinning={loading} />
|
|
1251
1370
|
</div>
|
|
1252
1371
|
)
|
|
@@ -1,48 +1,55 @@
|
|
|
1
1
|
import zmodem from 'zmodem.js/src/zmodem_browser'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function shouldWrite () {
|
|
9
|
-
return !!zsentry.get_confirmed_session() || !opts.noTerminalWriteOutsideSession
|
|
3
|
+
export class AddonZmodem {
|
|
4
|
+
_disposables = []
|
|
5
|
+
|
|
6
|
+
activate (terminal) {
|
|
7
|
+
terminal.zmodemAttach = this.zmodemAttach.bind(this)
|
|
10
8
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
sender: senderFunc,
|
|
18
|
-
on_retract: ctx.onzmodemRetract,
|
|
19
|
-
on_detect: ctx.onZmodemDetect
|
|
20
|
-
})
|
|
21
|
-
function handleWSMessage (evt) {
|
|
22
|
-
if (typeof evt.data === 'string') {
|
|
23
|
-
if (shouldWrite()) {
|
|
24
|
-
term.write(evt.data)
|
|
25
|
-
}
|
|
9
|
+
|
|
10
|
+
sendWebSocket (octets) {
|
|
11
|
+
const { socket } = this
|
|
12
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
13
|
+
return socket.send(new Uint8Array(octets))
|
|
26
14
|
} else {
|
|
27
|
-
|
|
15
|
+
console.error('WebSocket is not open')
|
|
28
16
|
}
|
|
29
17
|
}
|
|
30
|
-
ws.binaryType = 'arraybuffer'
|
|
31
|
-
ws.addEventListener('message', handleWSMessage)
|
|
32
|
-
}
|
|
33
18
|
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
zmodemAttach (ctx) {
|
|
20
|
+
this.socket = ctx.socket
|
|
21
|
+
this.term = ctx.term
|
|
22
|
+
this.ctx = ctx
|
|
23
|
+
this.zsentry = new zmodem.Sentry({
|
|
24
|
+
to_terminal: (octets) => {
|
|
25
|
+
if (ctx.onZmodem) {
|
|
26
|
+
this.term.write(String.fromCharCode.apply(String, octets))
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
sender: this.sendWebSocket.bind(this),
|
|
30
|
+
on_retract: ctx.onzmodemRetract,
|
|
31
|
+
on_detect: ctx.onZmodemDetect
|
|
32
|
+
})
|
|
33
|
+
this.socket.binaryType = 'arraybuffer'
|
|
34
|
+
this.socket.addEventListener('message', this.handleWSMessage.bind(this))
|
|
35
|
+
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
handleWSMessage (evt) {
|
|
38
|
+
if (typeof evt.data === 'string') {
|
|
39
|
+
if (this.ctx.onZmodem) {
|
|
40
|
+
this.term.write(evt.data)
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
this.zsentry.consume(evt.data)
|
|
44
|
+
}
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
dispose () {
|
|
48
|
+
this.socket && this.socket.removeEventListener('message', this.handleWSMessage)
|
|
43
49
|
this._disposables.forEach(d => d.dispose())
|
|
44
50
|
this._disposables.length = 0
|
|
51
|
+
this.term = null
|
|
52
|
+
this.zsentry = null
|
|
53
|
+
this.socket = null
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
|
-
|
|
48
|
-
export const Zmodem = zmodem
|
package/client/store/index.js
CHANGED
|
@@ -216,7 +216,6 @@ class Store {
|
|
|
216
216
|
store
|
|
217
217
|
} = window
|
|
218
218
|
return store.showModal ||
|
|
219
|
-
store.termSearchOpen ||
|
|
220
219
|
store.showInfoModal ||
|
|
221
220
|
store.showEditor ||
|
|
222
221
|
store.showFileModal
|
|
@@ -226,10 +225,6 @@ class Store {
|
|
|
226
225
|
return 0
|
|
227
226
|
}
|
|
228
227
|
|
|
229
|
-
get tabsHeight () {
|
|
230
|
-
return 45 // window.store.config.useSystemTitleBar ? 45 : 56
|
|
231
|
-
}
|
|
232
|
-
|
|
233
228
|
get langs () {
|
|
234
229
|
return JSON.parse(window.store._langs)
|
|
235
230
|
}
|
|
@@ -187,6 +187,7 @@ export default () => {
|
|
|
187
187
|
height: 500,
|
|
188
188
|
isMaximized: window.pre.runSync('isMaximized'),
|
|
189
189
|
terminalFullScreen: false,
|
|
190
|
-
hideDelKeyTip: ls.getItem(dismissDelKeyTipLsKey) === 'y'
|
|
190
|
+
hideDelKeyTip: ls.getItem(dismissDelKeyTipLsKey) === 'y',
|
|
191
|
+
tabsHeight: 36
|
|
191
192
|
}
|
|
192
193
|
}
|
package/package.json
CHANGED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* zmodem transfer UI module
|
|
3
|
-
* then run rz to send from your browser or
|
|
4
|
-
* sz <file> to send from the remote peer.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { memo } from 'react'
|
|
8
|
-
import { Progress, Button, Upload, Tag } from 'antd'
|
|
9
|
-
import { transferTypeMap } from '../../common/constants'
|
|
10
|
-
import Link from '../common/external-link'
|
|
11
|
-
import './zmodem.styl'
|
|
12
|
-
|
|
13
|
-
const { prefix } = window
|
|
14
|
-
const s = prefix('sftp')
|
|
15
|
-
const c = prefix('common')
|
|
16
|
-
|
|
17
|
-
export default memo((props) => {
|
|
18
|
-
const { zmodemTransfer, cancelZmodem, beforeZmodemUpload } = props
|
|
19
|
-
if (!zmodemTransfer) {
|
|
20
|
-
return null
|
|
21
|
-
}
|
|
22
|
-
const {
|
|
23
|
-
fileInfo,
|
|
24
|
-
type,
|
|
25
|
-
transferedSize,
|
|
26
|
-
percent
|
|
27
|
-
// options
|
|
28
|
-
} = zmodemTransfer
|
|
29
|
-
let btn = null
|
|
30
|
-
let progress = null
|
|
31
|
-
const recm = (
|
|
32
|
-
<Tag color='success'>
|
|
33
|
-
<div className='pd1y'>
|
|
34
|
-
<b className='mg1r'>Recommend Use trzsz instead:</b>
|
|
35
|
-
<Link to='https://github.com/trzsz/trzsz'>https://github.com/trzsz/trzsz</Link>
|
|
36
|
-
</div>
|
|
37
|
-
</Tag>
|
|
38
|
-
)
|
|
39
|
-
const cancelBtn = (
|
|
40
|
-
<Button
|
|
41
|
-
type='danger'
|
|
42
|
-
className='iblock mg2l'
|
|
43
|
-
onClick={cancelZmodem}
|
|
44
|
-
>{c('cancel')}
|
|
45
|
-
</Button>
|
|
46
|
-
)
|
|
47
|
-
if (type === transferTypeMap.upload) {
|
|
48
|
-
btn = (
|
|
49
|
-
<div className={fileInfo ? 'hide' : 'mg2b'}>
|
|
50
|
-
<div className='iblock'>
|
|
51
|
-
<Upload
|
|
52
|
-
showUploadList={false}
|
|
53
|
-
beforeUpload={beforeZmodemUpload}
|
|
54
|
-
className={fileInfo ? 'hide' : 'iblock'}
|
|
55
|
-
>
|
|
56
|
-
<Button>
|
|
57
|
-
{s(type)}
|
|
58
|
-
</Button>
|
|
59
|
-
</Upload>
|
|
60
|
-
</div>
|
|
61
|
-
{cancelBtn}
|
|
62
|
-
</div>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
if (fileInfo) {
|
|
66
|
-
const {
|
|
67
|
-
size,
|
|
68
|
-
name
|
|
69
|
-
} = fileInfo
|
|
70
|
-
progress = (
|
|
71
|
-
<div className='pd1b'>
|
|
72
|
-
<Progress
|
|
73
|
-
percent={percent}
|
|
74
|
-
size='small'
|
|
75
|
-
status='active'
|
|
76
|
-
format={() => {
|
|
77
|
-
return `%${percent}(${transferedSize}/${size})`
|
|
78
|
-
}}
|
|
79
|
-
/>
|
|
80
|
-
<h2 className='pd2y'>
|
|
81
|
-
<span className='iblock'>
|
|
82
|
-
{s(type)}: {name}
|
|
83
|
-
</span>
|
|
84
|
-
</h2>
|
|
85
|
-
<h4 className='pd2t pd2x'>Upload file(❯1M) may not show progress and may not end properly, but still would finish uploading in background.</h4>
|
|
86
|
-
</div>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
return (
|
|
90
|
-
<div className='zmodem-transfer'>
|
|
91
|
-
<div className='zmodem-transfer-inner'>
|
|
92
|
-
{btn}
|
|
93
|
-
{progress}
|
|
94
|
-
{recm}
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
)
|
|
98
|
-
})
|