@electerm/electerm-react 1.38.19 → 1.38.40
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/build-ssh-tunnel.js +2 -1
- package/client/common/choose-save-folder.js +22 -0
- package/client/common/constants.js +1 -1
- package/client/common/default-setting.js +9 -1
- package/client/common/download.jsx +31 -0
- package/client/common/trzsz.js +2 -18
- package/client/components/bookmark-form/render-ssh-tunnel.jsx +32 -14
- package/client/components/main/main.jsx +4 -0
- package/client/components/quick-commands/quick-commands-box.jsx +20 -5
- package/client/components/quick-commands/quick-commands-form-elem.jsx +14 -17
- package/client/components/quick-commands/quick-commands-list-form.jsx +89 -0
- package/client/components/session/session.jsx +5 -4
- package/client/components/setting-panel/list.styl +3 -0
- package/client/components/setting-panel/setting-terminal.jsx +1 -0
- package/client/components/setting-panel/tree-list.styl +4 -0
- package/client/components/sftp/file-item.jsx +27 -20
- package/client/components/sftp/sftp-entry.jsx +65 -45
- package/client/components/shortcuts/shortcuts-defaults.js +7 -7
- package/client/components/tabs/index.jsx +12 -1
- package/client/components/terminal/attach-addon-custom.js +2 -2
- package/client/components/terminal/index.jsx +18 -15
- package/client/components/terminal-info/activity.jsx +4 -4
- package/client/components/terminal-info/base.jsx +58 -2
- package/client/components/terminal-info/disk.jsx +4 -3
- package/client/components/terminal-info/network.jsx +4 -3
- package/client/components/terminal-info/resource.jsx +20 -10
- package/client/components/terminal-info/up.jsx +5 -3
- package/client/css/basic.styl +3 -0
- package/client/store/common.js +51 -0
- package/client/store/index.js +2 -2
- package/client/store/sync.js +15 -2
- package/client/store/system-menu.js +6 -16
- package/package.json +1 -1
- package/client/common/download.js +0 -16
|
@@ -562,6 +562,22 @@ export default class Sftp extends Component {
|
|
|
562
562
|
})
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
+
sftpList = (sftp, remotePath) => {
|
|
566
|
+
return sftp.list(remotePath)
|
|
567
|
+
.then(arr => {
|
|
568
|
+
return arr.map(item => {
|
|
569
|
+
const { type } = item
|
|
570
|
+
return {
|
|
571
|
+
...pick(item, ['name', 'size', 'accessTime', 'modifyTime', 'mode', 'owner', 'group']),
|
|
572
|
+
isDirectory: type === fileTypeMap.directory,
|
|
573
|
+
type: typeMap.remote,
|
|
574
|
+
path: remotePath,
|
|
575
|
+
id: generate()
|
|
576
|
+
}
|
|
577
|
+
})
|
|
578
|
+
})
|
|
579
|
+
}
|
|
580
|
+
|
|
565
581
|
remoteList = async (
|
|
566
582
|
returnList = false,
|
|
567
583
|
remotePathReal,
|
|
@@ -644,52 +660,8 @@ export default class Sftp extends Component {
|
|
|
644
660
|
}
|
|
645
661
|
}
|
|
646
662
|
|
|
647
|
-
|
|
663
|
+
const remote = await this.sftpList(sftp, remotePath)
|
|
648
664
|
this.sftp = sftp
|
|
649
|
-
const remotes = deepCopy(remote)
|
|
650
|
-
remote = []
|
|
651
|
-
for (const _r of remotes) {
|
|
652
|
-
const r = _r
|
|
653
|
-
const { type, name } = r
|
|
654
|
-
const f = {
|
|
655
|
-
...pick(r, ['name', 'size', 'accessTime', 'modifyTime', 'mode', 'owner', 'group']),
|
|
656
|
-
isDirectory: r.type === fileTypeMap.directory,
|
|
657
|
-
type: typeMap.remote,
|
|
658
|
-
path: remotePath,
|
|
659
|
-
id: generate()
|
|
660
|
-
}
|
|
661
|
-
if (type === fileTypeMap.link) {
|
|
662
|
-
const linkPath = resolve(remotePath, name)
|
|
663
|
-
let realpath = await sftp.readlink(linkPath)
|
|
664
|
-
.catch(e => {
|
|
665
|
-
console.debug(e)
|
|
666
|
-
return null
|
|
667
|
-
})
|
|
668
|
-
if (!realpath) {
|
|
669
|
-
continue
|
|
670
|
-
}
|
|
671
|
-
if (!isAbsPath(realpath)) {
|
|
672
|
-
realpath = resolve(remotePath, realpath)
|
|
673
|
-
realpath = await sftp.realpath(realpath)
|
|
674
|
-
}
|
|
675
|
-
const realFileInfo = await getRemoteFileInfo(
|
|
676
|
-
sftp,
|
|
677
|
-
realpath
|
|
678
|
-
).catch(e => {
|
|
679
|
-
log.debug('seems a bad symbolic link')
|
|
680
|
-
log.debug(e)
|
|
681
|
-
return null
|
|
682
|
-
})
|
|
683
|
-
if (!realFileInfo) {
|
|
684
|
-
continue
|
|
685
|
-
}
|
|
686
|
-
f.isSymbolicLink = true
|
|
687
|
-
f.isDirectory = realFileInfo.isDirectory
|
|
688
|
-
} else {
|
|
689
|
-
f.isSymbolicLink = false
|
|
690
|
-
}
|
|
691
|
-
remote.push(f)
|
|
692
|
-
}
|
|
693
665
|
const update = {
|
|
694
666
|
remote,
|
|
695
667
|
remoteFileTree: buildTree(remote),
|
|
@@ -712,6 +684,7 @@ export default class Sftp extends Component {
|
|
|
712
684
|
]).slice(0, maxSftpHistory)
|
|
713
685
|
}
|
|
714
686
|
this.setState(update, () => {
|
|
687
|
+
this.updateRemoteList(remote, remotePath, sftp)
|
|
715
688
|
this.props.editTab(tab.id, {
|
|
716
689
|
sftpCreated: true
|
|
717
690
|
})
|
|
@@ -731,6 +704,53 @@ export default class Sftp extends Component {
|
|
|
731
704
|
}
|
|
732
705
|
}
|
|
733
706
|
|
|
707
|
+
updateRemoteList = async (
|
|
708
|
+
remotes,
|
|
709
|
+
remotePath,
|
|
710
|
+
sftp
|
|
711
|
+
) => {
|
|
712
|
+
const remote = []
|
|
713
|
+
for (const r of remotes) {
|
|
714
|
+
const { type, name } = r
|
|
715
|
+
if (type === fileTypeMap.link) {
|
|
716
|
+
const linkPath = resolve(remotePath, name)
|
|
717
|
+
let realpath = await sftp.readlink(linkPath)
|
|
718
|
+
.catch(e => {
|
|
719
|
+
console.debug(e)
|
|
720
|
+
return null
|
|
721
|
+
})
|
|
722
|
+
if (!realpath) {
|
|
723
|
+
continue
|
|
724
|
+
}
|
|
725
|
+
if (!isAbsPath(realpath)) {
|
|
726
|
+
realpath = resolve(remotePath, realpath)
|
|
727
|
+
realpath = await sftp.realpath(realpath)
|
|
728
|
+
}
|
|
729
|
+
const realFileInfo = await getRemoteFileInfo(
|
|
730
|
+
sftp,
|
|
731
|
+
realpath
|
|
732
|
+
).catch(e => {
|
|
733
|
+
log.debug('seems a bad symbolic link')
|
|
734
|
+
log.debug(e)
|
|
735
|
+
return null
|
|
736
|
+
})
|
|
737
|
+
if (!realFileInfo) {
|
|
738
|
+
continue
|
|
739
|
+
}
|
|
740
|
+
r.isSymbolicLink = true
|
|
741
|
+
r.isDirectory = realFileInfo.isDirectory
|
|
742
|
+
} else {
|
|
743
|
+
r.isSymbolicLink = false
|
|
744
|
+
}
|
|
745
|
+
remote.push(r)
|
|
746
|
+
}
|
|
747
|
+
const update = {
|
|
748
|
+
remote,
|
|
749
|
+
remoteFileTree: buildTree(remote)
|
|
750
|
+
}
|
|
751
|
+
this.setState(update)
|
|
752
|
+
}
|
|
753
|
+
|
|
734
754
|
localList = async (returnList = false, localPathReal, oldPath) => {
|
|
735
755
|
if (!fs) return
|
|
736
756
|
if (!returnList) {
|
|
@@ -50,13 +50,13 @@ export default () => {
|
|
|
50
50
|
shortcut: 'ctrl+l,ctrl+shift+l',
|
|
51
51
|
shortcutMac: 'meta+l'
|
|
52
52
|
},
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
},
|
|
53
|
+
// {
|
|
54
|
+
// name: 'terminal_selectAll',
|
|
55
|
+
// shortcut: 'ctrl+a,ctrl+shift+a',
|
|
56
|
+
// shortcutMac: 'meta+a',
|
|
57
|
+
// skipMac: true,
|
|
58
|
+
// readonly: true
|
|
59
|
+
// },
|
|
60
60
|
{
|
|
61
61
|
name: 'terminal_copy',
|
|
62
62
|
shortcut: 'ctrl+c,ctrl+shift+c',
|
|
@@ -49,6 +49,7 @@ export default class Tabs extends React.Component {
|
|
|
49
49
|
tabsRef
|
|
50
50
|
} = this
|
|
51
51
|
tabsRef.current.addEventListener('mousedown', this.handleClickEvent)
|
|
52
|
+
tabsRef.current.addEventListener('mousewheel', this.handleWheelEvent)
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
componentDidUpdate (prevProps) {
|
|
@@ -75,7 +76,7 @@ export default class Tabs extends React.Component {
|
|
|
75
76
|
const len = tabs.length
|
|
76
77
|
const addBtnWidth = 22
|
|
77
78
|
const tabsWidth = this.tabsWidth()
|
|
78
|
-
const tabsWidthAll = tabMargin * len +
|
|
79
|
+
const tabsWidthAll = tabMargin * len + 166 + tabsWidth
|
|
79
80
|
return width < (tabsWidthAll + addBtnWidth)
|
|
80
81
|
}
|
|
81
82
|
|
|
@@ -129,6 +130,16 @@ export default class Tabs extends React.Component {
|
|
|
129
130
|
this.dom.scrollLeft = scrollLeft
|
|
130
131
|
}
|
|
131
132
|
|
|
133
|
+
handleWheelEvent = (e) => {
|
|
134
|
+
if (this.isOverflow()) {
|
|
135
|
+
if (e.deltaY < 0) {
|
|
136
|
+
this.handleScrollLeft()
|
|
137
|
+
} else {
|
|
138
|
+
this.handleScrollRight()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
132
143
|
handleClickMenu = ({ key }) => {
|
|
133
144
|
const id = key.split('##')[1]
|
|
134
145
|
this.props.onChangeTabId(id)
|
|
@@ -55,7 +55,7 @@ export default class AttachAddonCustom extends AttachAddon {
|
|
|
55
55
|
const data = ev.target.result
|
|
56
56
|
const { term } = this
|
|
57
57
|
const str = this.decoder.decode(data)
|
|
58
|
-
if (term
|
|
58
|
+
if (term?.parent?.props.sftpPathFollowSsh && term?.buffer.active.type !== 'alternate') {
|
|
59
59
|
const {
|
|
60
60
|
cwdId
|
|
61
61
|
} = term
|
|
@@ -78,7 +78,7 @@ export default class AttachAddonCustom extends AttachAddon {
|
|
|
78
78
|
}
|
|
79
79
|
term.write(nnss.join('\r'))
|
|
80
80
|
} else {
|
|
81
|
-
term
|
|
81
|
+
term?.write(str)
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -234,10 +234,10 @@ class Term extends Component {
|
|
|
234
234
|
this.onClear()
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
selectAllShortcut = (e) => {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
237
|
+
// selectAllShortcut = (e) => {
|
|
238
|
+
// e.stopPropagation()
|
|
239
|
+
// this.term.selectAll()
|
|
240
|
+
// }
|
|
241
241
|
|
|
242
242
|
copyShortcut = (e) => {
|
|
243
243
|
const sel = this.term.getSelection()
|
|
@@ -425,6 +425,9 @@ class Term extends Component {
|
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
webLinkHandler = (event, url) => {
|
|
428
|
+
if (event?.button === 2) {
|
|
429
|
+
return false
|
|
430
|
+
}
|
|
428
431
|
if (!this.props.config.ctrlOrMetaOpenTerminalLink) {
|
|
429
432
|
return window.openLink(url, '_blank')
|
|
430
433
|
}
|
|
@@ -757,9 +760,9 @@ class Term extends Component {
|
|
|
757
760
|
this.term.focus()
|
|
758
761
|
}
|
|
759
762
|
|
|
760
|
-
onSelectAll = () => {
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
+
// onSelectAll = () => {
|
|
764
|
+
// this.term.selectAll()
|
|
765
|
+
// }
|
|
763
766
|
|
|
764
767
|
onClear = () => {
|
|
765
768
|
this.term.clear()
|
|
@@ -810,7 +813,7 @@ class Term extends Component {
|
|
|
810
813
|
const copyShortcut = this.getShortcut('terminal_copy')
|
|
811
814
|
const pasteShortcut = this.getShortcut('terminal_paste')
|
|
812
815
|
const clearShortcut = this.getShortcut('terminal_clear')
|
|
813
|
-
const selectAllShortcut = this.getShortcut('terminal_selectAll')
|
|
816
|
+
// const selectAllShortcut = this.getShortcut('terminal_selectAll')
|
|
814
817
|
const searchShortcut = this.getShortcut('terminal_search')
|
|
815
818
|
return [
|
|
816
819
|
{
|
|
@@ -833,12 +836,12 @@ class Term extends Component {
|
|
|
833
836
|
text: e('clear'),
|
|
834
837
|
subText: clearShortcut
|
|
835
838
|
},
|
|
836
|
-
{
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
},
|
|
839
|
+
// {
|
|
840
|
+
// func: 'onSelectAll',
|
|
841
|
+
// icon: 'SelectOutlined',
|
|
842
|
+
// text: e('selectAll'),
|
|
843
|
+
// subText: selectAllShortcut
|
|
844
|
+
// },
|
|
842
845
|
{
|
|
843
846
|
func: 'toggleSearch',
|
|
844
847
|
icon: 'SearchOutlined',
|
|
@@ -1203,7 +1206,7 @@ class Term extends Component {
|
|
|
1203
1206
|
}
|
|
1204
1207
|
|
|
1205
1208
|
oncloseSocket = () => {
|
|
1206
|
-
if (this.onClose) {
|
|
1209
|
+
if (this.onClose || !this.props.tab.enableSsh) {
|
|
1207
1210
|
return
|
|
1208
1211
|
}
|
|
1209
1212
|
this.setStatus(
|
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import { Table, Tooltip, Popconfirm } from 'antd'
|
|
6
6
|
import { isEmpty } from 'lodash-es'
|
|
7
|
-
import { CloseCircleOutlined } from '@ant-design/icons'
|
|
7
|
+
import { CloseCircleOutlined, BarsOutlined } from '@ant-design/icons'
|
|
8
8
|
import colsParser from './data-cols-parser'
|
|
9
9
|
|
|
10
10
|
const { prefix } = window
|
|
11
11
|
const m = prefix('menu')
|
|
12
12
|
|
|
13
13
|
export default function TerminalInfoActivities (props) {
|
|
14
|
-
const { activities } = props
|
|
15
|
-
if (isEmpty(activities) || !
|
|
14
|
+
const { activities, isRemote, terminalInfos } = props
|
|
15
|
+
if (isEmpty(activities) || !isRemote || !terminalInfos.includes('activities')) {
|
|
16
16
|
return null
|
|
17
17
|
}
|
|
18
18
|
const col = colsParser(activities[0])
|
|
@@ -47,7 +47,7 @@ export default function TerminalInfoActivities (props) {
|
|
|
47
47
|
}
|
|
48
48
|
return (
|
|
49
49
|
<div className='terminal-info-section terminal-info-act'>
|
|
50
|
-
<div className='pd1y bold'
|
|
50
|
+
<div className='pd1y bold'><BarsOutlined /> Activities</div>
|
|
51
51
|
<Table {...ps} />
|
|
52
52
|
</div>
|
|
53
53
|
)
|
|
@@ -7,15 +7,28 @@ import {
|
|
|
7
7
|
commonActions
|
|
8
8
|
} from '../../common/constants'
|
|
9
9
|
import {
|
|
10
|
-
Switch
|
|
10
|
+
Switch,
|
|
11
|
+
Space,
|
|
12
|
+
Button
|
|
11
13
|
} from 'antd'
|
|
12
14
|
import ShowItem from '../common/show-item'
|
|
15
|
+
import defaults from '../../common/default-setting'
|
|
13
16
|
import postMsg from '../../common/post-msg'
|
|
14
17
|
import { toggleTerminalLog, toggleTerminalLogTimestamp } from '../terminal/terminal-apis'
|
|
18
|
+
import { ClockCircleOutlined, BorderlessTableOutlined, DatabaseOutlined, BarsOutlined, ApiOutlined, PartitionOutlined } from '@ant-design/icons'
|
|
15
19
|
|
|
16
20
|
const { prefix } = window
|
|
17
21
|
const st = prefix('setting')
|
|
18
22
|
|
|
23
|
+
const mapper = {
|
|
24
|
+
uptime: <ClockCircleOutlined />,
|
|
25
|
+
cpu: <BorderlessTableOutlined />,
|
|
26
|
+
mem: <DatabaseOutlined />,
|
|
27
|
+
activities: <BarsOutlined />,
|
|
28
|
+
network: <ApiOutlined />,
|
|
29
|
+
disks: <PartitionOutlined />
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
export default class TerminalInfoBase extends Component {
|
|
20
33
|
state = {
|
|
21
34
|
saveTerminalLogToFile: false,
|
|
@@ -54,6 +67,16 @@ export default class TerminalInfoBase extends Component {
|
|
|
54
67
|
})
|
|
55
68
|
}
|
|
56
69
|
|
|
70
|
+
toggleTerminalLogInfo = (h) => {
|
|
71
|
+
const { terminalInfos } = this.props
|
|
72
|
+
const nv = terminalInfos.includes(h)
|
|
73
|
+
? terminalInfos.filter(f => f !== h)
|
|
74
|
+
: [...terminalInfos, h]
|
|
75
|
+
window.store.setConfig({
|
|
76
|
+
terminalInfos: nv
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
57
80
|
handleToggle = () => {
|
|
58
81
|
const { saveTerminalLogToFile, addTimeStampToTermLog } = this.state
|
|
59
82
|
const {
|
|
@@ -120,10 +143,38 @@ export default class TerminalInfoBase extends Component {
|
|
|
120
143
|
unCheckedChildren={name}
|
|
121
144
|
checked={addTimeStampToTermLog}
|
|
122
145
|
onChange={this.handleToggleTimestamp}
|
|
146
|
+
className='mg1b'
|
|
123
147
|
/>
|
|
124
148
|
)
|
|
125
149
|
}
|
|
126
150
|
|
|
151
|
+
renderInfoSelection () {
|
|
152
|
+
const {
|
|
153
|
+
terminalInfos
|
|
154
|
+
} = this.props
|
|
155
|
+
return (
|
|
156
|
+
<Space.Compact block>
|
|
157
|
+
{
|
|
158
|
+
defaults.terminalInfos.map(f => {
|
|
159
|
+
const type = terminalInfos.includes(f) ? 'primary' : 'default'
|
|
160
|
+
return (
|
|
161
|
+
<Button
|
|
162
|
+
key={f + 'term-info-sel'}
|
|
163
|
+
type={type}
|
|
164
|
+
size='small'
|
|
165
|
+
onClick={() => this.toggleTerminalLogInfo(f)}
|
|
166
|
+
className='cap'
|
|
167
|
+
icon={mapper[f]}
|
|
168
|
+
>
|
|
169
|
+
{f}
|
|
170
|
+
</Button>
|
|
171
|
+
)
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
</Space.Compact>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
127
178
|
render () {
|
|
128
179
|
const {
|
|
129
180
|
id,
|
|
@@ -149,13 +200,18 @@ export default class TerminalInfoBase extends Component {
|
|
|
149
200
|
unCheckedChildren={name}
|
|
150
201
|
checked={saveTerminalLogToFile}
|
|
151
202
|
onChange={this.handleToggle}
|
|
152
|
-
className='mg1r'
|
|
203
|
+
className='mg1r mg1b'
|
|
153
204
|
/>
|
|
154
205
|
{
|
|
155
206
|
this.renderTimestamp()
|
|
156
207
|
}
|
|
157
208
|
</span>
|
|
158
209
|
</div>
|
|
210
|
+
<div className='pd2y'>
|
|
211
|
+
{
|
|
212
|
+
this.renderInfoSelection()
|
|
213
|
+
}
|
|
214
|
+
</div>
|
|
159
215
|
<p><b>log:</b> {to}</p>
|
|
160
216
|
</div>
|
|
161
217
|
)
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
import { Table } from 'antd'
|
|
6
6
|
import { isEmpty } from 'lodash-es'
|
|
7
7
|
import colsParser from './data-cols-parser'
|
|
8
|
+
import { PartitionOutlined } from '@ant-design/icons'
|
|
8
9
|
|
|
9
10
|
export default function TerminalInfoDisk (props) {
|
|
10
|
-
const { disks } = props
|
|
11
|
-
if (isEmpty(disks) || !
|
|
11
|
+
const { disks, isRemote, terminalInfos } = props
|
|
12
|
+
if (isEmpty(disks) || !isRemote || !terminalInfos.includes('disks')) {
|
|
12
13
|
return null
|
|
13
14
|
}
|
|
14
15
|
const col = colsParser(disks[0])
|
|
@@ -22,7 +23,7 @@ export default function TerminalInfoDisk (props) {
|
|
|
22
23
|
}
|
|
23
24
|
return (
|
|
24
25
|
<div className='terminal-info-section terminal-info-disk'>
|
|
25
|
-
<div className='pd1y bold'
|
|
26
|
+
<div className='pd1y bold'><PartitionOutlined /> File system</div>
|
|
26
27
|
<Table {...ps} />
|
|
27
28
|
</div>
|
|
28
29
|
)
|
|
@@ -7,10 +7,11 @@ import { isEmpty } from 'lodash-es'
|
|
|
7
7
|
import { useEffect, useState } from 'react'
|
|
8
8
|
import { formatBytes } from '../../common/byte-format'
|
|
9
9
|
import copy from 'json-deep-copy'
|
|
10
|
+
import { ApiOutlined } from '@ant-design/icons'
|
|
10
11
|
|
|
11
12
|
export default function TerminalInfoDisk (props) {
|
|
12
|
-
const { network } = props
|
|
13
|
-
if (isEmpty(network) || !
|
|
13
|
+
const { network, isRemote, terminalInfos } = props
|
|
14
|
+
if (isEmpty(network) || !isRemote || !terminalInfos.includes('network')) {
|
|
14
15
|
return null
|
|
15
16
|
}
|
|
16
17
|
const [state, setter] = useState({
|
|
@@ -107,7 +108,7 @@ export default function TerminalInfoDisk (props) {
|
|
|
107
108
|
}
|
|
108
109
|
return (
|
|
109
110
|
<div className='terminal-info-section terminal-info-network'>
|
|
110
|
-
<div className='pd1y bold'
|
|
111
|
+
<div className='pd1y bold'><ApiOutlined /> Network</div>
|
|
111
112
|
<Table {...ps} />
|
|
112
113
|
</div>
|
|
113
114
|
)
|
|
@@ -25,8 +25,13 @@ function computePercent (used, total) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export default function TerminalInfoResource (props) {
|
|
28
|
-
const { cpu, mem, swap } = props
|
|
29
|
-
if (
|
|
28
|
+
const { cpu, mem, swap, isRemote, terminalInfos } = props
|
|
29
|
+
if (
|
|
30
|
+
!isRemote ||
|
|
31
|
+
(!terminalInfos.includes('cpu') &&
|
|
32
|
+
!terminalInfos.includes('mem') &&
|
|
33
|
+
!terminalInfos.includes('swap'))
|
|
34
|
+
) {
|
|
30
35
|
return null
|
|
31
36
|
}
|
|
32
37
|
function renderItem (obj) {
|
|
@@ -56,20 +61,25 @@ export default function TerminalInfoResource (props) {
|
|
|
56
61
|
</div>
|
|
57
62
|
)
|
|
58
63
|
}
|
|
59
|
-
const data = [
|
|
60
|
-
|
|
64
|
+
const data = []
|
|
65
|
+
if (terminalInfos.includes('cpu')) {
|
|
66
|
+
data.push({
|
|
61
67
|
name: 'cpu',
|
|
62
68
|
percent: parseInt10(cpu)
|
|
63
|
-
}
|
|
64
|
-
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
if (terminalInfos.includes('mem')) {
|
|
72
|
+
data.push({
|
|
65
73
|
name: 'mem',
|
|
66
74
|
...mem
|
|
67
|
-
}
|
|
68
|
-
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
if (terminalInfos.includes('swap')) {
|
|
78
|
+
data.push({
|
|
69
79
|
name: 'swap',
|
|
70
80
|
...swap
|
|
71
|
-
}
|
|
72
|
-
|
|
81
|
+
})
|
|
82
|
+
}
|
|
73
83
|
return (
|
|
74
84
|
<div className='terminal-info-section terminal-info-resource'>
|
|
75
85
|
{
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* up time info
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { ClockCircleOutlined } from '@ant-design/icons'
|
|
6
|
+
|
|
5
7
|
export default function TerminalInfoUp (props) {
|
|
6
|
-
const { uptime } = props
|
|
7
|
-
if (!
|
|
8
|
+
const { uptime, isRemote, terminalInfos } = props
|
|
9
|
+
if (!isRemote || !terminalInfos.includes('uptime')) {
|
|
8
10
|
return null
|
|
9
11
|
}
|
|
10
12
|
return (
|
|
11
13
|
<div className='terminal-info-section terminal-info-up'>
|
|
12
|
-
<b
|
|
14
|
+
<b><ClockCircleOutlined /> uptime</b>: {uptime}
|
|
13
15
|
</div>
|
|
14
16
|
)
|
|
15
17
|
}
|
package/client/css/basic.styl
CHANGED
package/client/store/common.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import handleError from '../common/error-handler'
|
|
6
|
+
import { Modal } from 'antd'
|
|
6
7
|
import { debounce } from 'lodash-es'
|
|
7
8
|
import postMessage from '../common/post-msg'
|
|
8
9
|
import {
|
|
@@ -15,6 +16,10 @@ import {
|
|
|
15
16
|
} from '../common/constants'
|
|
16
17
|
import * as ls from '../common/safe-local-storage'
|
|
17
18
|
|
|
19
|
+
const { prefix } = window
|
|
20
|
+
const m = prefix('menu')
|
|
21
|
+
const c = prefix('common')
|
|
22
|
+
|
|
18
23
|
export default Store => {
|
|
19
24
|
Store.prototype.storeAssign = function (updates) {
|
|
20
25
|
Object.assign(this, updates)
|
|
@@ -155,4 +160,50 @@ export default Store => {
|
|
|
155
160
|
ls.setItem(dismissDelKeyTipLsKey, 'y')
|
|
156
161
|
window.store.hideDelKeyTip = true
|
|
157
162
|
}
|
|
163
|
+
Store.prototype.beforeExit = function (e) {
|
|
164
|
+
const { confirmBeforeExit } = window.store.config
|
|
165
|
+
if (
|
|
166
|
+
(confirmBeforeExit &&
|
|
167
|
+
!window.confirmExit) ||
|
|
168
|
+
window.store.isTransporting
|
|
169
|
+
) {
|
|
170
|
+
e.returnValue = false
|
|
171
|
+
let mod = null
|
|
172
|
+
mod = Modal.confirm({
|
|
173
|
+
onCancel: () => {
|
|
174
|
+
window.confirmExit = false
|
|
175
|
+
mod.destroy()
|
|
176
|
+
},
|
|
177
|
+
onOk: () => {
|
|
178
|
+
window.confirmExit = true
|
|
179
|
+
window.store[window.exitFunction]()
|
|
180
|
+
},
|
|
181
|
+
title: m('quit'),
|
|
182
|
+
okText: c('ok'),
|
|
183
|
+
cancelText: c('cancel'),
|
|
184
|
+
content: ''
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
Store.prototype.beforeExitApp = function (e, name) {
|
|
189
|
+
let mod = null
|
|
190
|
+
mod = Modal.confirm({
|
|
191
|
+
onCancel: () => {
|
|
192
|
+
window.pre.runGlobalAsync('setCloseAction', 'closeApp')
|
|
193
|
+
mod.destroy()
|
|
194
|
+
},
|
|
195
|
+
onOk: () => {
|
|
196
|
+
window.pre.runGlobalAsync(name)
|
|
197
|
+
},
|
|
198
|
+
title: m('quit'),
|
|
199
|
+
okText: c('ok'),
|
|
200
|
+
cancelText: c('cancel'),
|
|
201
|
+
content: ''
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
Store.prototype.setTerminalInfos = function (arr) {
|
|
205
|
+
window.store.setConfig({
|
|
206
|
+
terminalInfos: arr
|
|
207
|
+
})
|
|
208
|
+
}
|
|
158
209
|
}
|
package/client/store/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import loadDataExtend from './load-data'
|
|
|
8
8
|
import dbUpgradeExtend from './db-upgrade'
|
|
9
9
|
import eventExtend from './event'
|
|
10
10
|
import syncExtend from './sync'
|
|
11
|
-
import
|
|
11
|
+
import appUpgradeExtend from './app-upgrade'
|
|
12
12
|
import bookmarkGroupExtend from './bookmark-group'
|
|
13
13
|
import bookmarkExtend from './bookmark'
|
|
14
14
|
import commonExtend from './common'
|
|
@@ -288,7 +288,7 @@ loadDataExtend(Store)
|
|
|
288
288
|
eventExtend(Store)
|
|
289
289
|
dbUpgradeExtend(Store)
|
|
290
290
|
syncExtend(Store)
|
|
291
|
-
|
|
291
|
+
appUpgradeExtend(Store)
|
|
292
292
|
bookmarkGroupExtend(Store)
|
|
293
293
|
bookmarkExtend(Store)
|
|
294
294
|
commonExtend(Store)
|
package/client/store/sync.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* sync data to github gist related
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { without, get, pick, debounce } from 'lodash-es'
|
|
5
|
+
import { without, get, pick, debounce, findIndex } from 'lodash-es'
|
|
6
6
|
import copy from 'json-deep-copy'
|
|
7
7
|
import {
|
|
8
8
|
settingMap, packInfo, syncTypes
|
|
9
9
|
} from '../common/constants'
|
|
10
|
-
import { remove, dbNames, insert, update } from '../common/db'
|
|
10
|
+
import { remove, dbNames, insert, update, getData } from '../common/db'
|
|
11
11
|
import fetch from '../common/fetch-from-server'
|
|
12
12
|
import download from '../common/download'
|
|
13
13
|
import { fixBookmarks } from '../common/db-fix'
|
|
@@ -169,6 +169,10 @@ export default (Store) => {
|
|
|
169
169
|
objs[`${n}.json`] = {
|
|
170
170
|
content: str
|
|
171
171
|
}
|
|
172
|
+
const order = await getData(`${n}:order`)
|
|
173
|
+
objs[`${n}.order.json`] = {
|
|
174
|
+
content: JSON.stringify(order)
|
|
175
|
+
}
|
|
172
176
|
}
|
|
173
177
|
const res = await fetchData(type, 'update', [gistId, {
|
|
174
178
|
description: 'sync electerm data',
|
|
@@ -235,6 +239,15 @@ export default (Store) => {
|
|
|
235
239
|
} else if (n === settingMap.bookmarks) {
|
|
236
240
|
arr = fixBookmarks(arr)
|
|
237
241
|
}
|
|
242
|
+
let strOrder = get(gist, `files["${n}.order.json"].content`)
|
|
243
|
+
if (strOrder) {
|
|
244
|
+
strOrder = JSON.parse(strOrder)
|
|
245
|
+
arr.sort((a, b) => {
|
|
246
|
+
const ai = findIndex(strOrder, r => r === a.id)
|
|
247
|
+
const bi = findIndex(strOrder, r => r === b.id)
|
|
248
|
+
return ai - bi
|
|
249
|
+
})
|
|
250
|
+
}
|
|
238
251
|
toInsert.push({
|
|
239
252
|
name: n,
|
|
240
253
|
value: arr
|