@electerm/electerm-react 1.37.46 → 1.37.58

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.
@@ -138,6 +138,8 @@ export const terminalTelnetType = 'telnet'
138
138
  export const terminalLocalType = 'local'
139
139
  export const openedSidebarKey = 'opened-sidebar'
140
140
  export const sidebarPinnedKey = 'sidebar-pinned'
141
+ export const leftSidebarWidthKey = 'left-sidebar-width'
142
+ export const rightSidebarWidthKey = 'right-sidebar-width'
141
143
  export const sftpDefaultSortSettingKey = 'sftp-default-sort'
142
144
  // https://github.com/tinkertrain/panda-syntax-vscode/blob/master/themes/workbench.yaml
143
145
  export const defaultTheme = {
@@ -122,13 +122,24 @@ export default class SystemMenu extends Component {
122
122
  }
123
123
 
124
124
  render () {
125
- const { tabs } = this.props.store
125
+ const { tabs, leftSidebarWidth, openedSideBar } = this.props.store
126
126
  const pane = this.props.store.currentTab?.pane
127
127
  if (pane === paneMap.fileManager || !tabs.length) {
128
128
  return null
129
129
  }
130
+ const w = 43 + leftSidebarWidth
131
+ const sideProps = openedSideBar
132
+ ? {
133
+ className: 'main-footer',
134
+ style: {
135
+ left: `${w}px`
136
+ }
137
+ }
138
+ : {
139
+ className: 'main-footer'
140
+ }
130
141
  return (
131
- <div className='main-footer'>
142
+ <div {...sideProps}>
132
143
  <div className='terminal-footer-flex'>
133
144
  {this.renderQuickCommands()}
134
145
  {this.renderBatchInputs()}
@@ -74,6 +74,7 @@ export default class SessionWrapper extends Component {
74
74
  enableSftp: false,
75
75
  splitDirection: terminalSplitDirectionMap.horizontal,
76
76
  activeSplitId,
77
+ infoPanelPinned: false,
77
78
  key: Math.random(),
78
79
  sessionOptions: null,
79
80
  sessionId: generate(),
@@ -104,6 +105,12 @@ export default class SessionWrapper extends Component {
104
105
  })
105
106
  }
106
107
 
108
+ toggleInfoPinned = () => {
109
+ this.setState({
110
+ infoPanelPinned: !this.state.infoPanelPinned
111
+ })
112
+ }
113
+
107
114
  hideInfoPanel = () => {
108
115
  this.setState({
109
116
  showInfo: false
@@ -217,7 +224,7 @@ export default class SessionWrapper extends Component {
217
224
 
218
225
  computePosition = (index) => {
219
226
  const len = this.state.terminals.length || 1
220
- const { width: windowWidth } = this.props
227
+ const windowWidth = this.getWidth()
221
228
  const { splitDirection } = this.state
222
229
  const isHori = splitDirection === terminalSplitDirectionMap.horizontal
223
230
  const heightAll = this.computeHeight()
@@ -241,6 +248,18 @@ export default class SessionWrapper extends Component {
241
248
  }
242
249
  }
243
250
 
251
+ getWidth = () => {
252
+ const {
253
+ infoPanelPinned,
254
+ showInfo
255
+ } = this.state
256
+ if (!infoPanelPinned || !showInfo) {
257
+ return this.props.width
258
+ }
259
+ const { rightSidebarWidth, width } = this.props
260
+ return width - rightSidebarWidth
261
+ }
262
+
244
263
  renderTerminals = () => {
245
264
  const {
246
265
  terminals,
@@ -256,7 +275,8 @@ export default class SessionWrapper extends Component {
256
275
  ? 'terms-box'
257
276
  : 'terms-box hide'
258
277
  const height = this.computeHeight()
259
- const { width, tab } = this.props
278
+ const { tab } = this.props
279
+ const width = this.getWidth()
260
280
  const themeConfig = copy(window.store.getThemeConfig())
261
281
  return (
262
282
  <div
@@ -467,20 +487,20 @@ export default class SessionWrapper extends Component {
467
487
  const {
468
488
  splitDirection,
469
489
  infoPanelProps,
470
- showInfo
490
+ showInfo,
491
+ infoPanelPinned
471
492
  } = this.state
472
493
  const { pane } = this.props.tab
473
494
  const infoProps = {
495
+ infoPanelPinned,
474
496
  ...pick(this.props.config, ['host', 'port', 'saveTerminalLogToFile']),
475
497
  ...infoPanelProps,
476
498
  appPath: this.props.appPath,
499
+ rightSidebarWidth: this.props.rightSidebarWidth,
477
500
  showInfo,
478
501
  tabsHeight: this.props.tabsHeight,
479
502
  topMenuHeight: this.props.topMenuHeight,
480
- // pid,
481
- // sessionId,
482
- // isRemote: this.isRemote(),
483
- // isActive: this.isActiveTerminal(),
503
+ toggleInfoPinned: this.toggleInfoPinned,
484
504
  hideInfoPanel: this.hideInfoPanel
485
505
  }
486
506
  const cls = classnames(
@@ -346,7 +346,8 @@ class Sessions extends Component {
346
346
  'pinnedQuickCommandBar',
347
347
  'tabsHeight',
348
348
  'appPath',
349
- 'topMenuHeight'
349
+ 'topMenuHeight',
350
+ 'rightSidebarWidth'
350
351
  ]),
351
352
  config,
352
353
  ...pick(this, [
@@ -407,8 +408,23 @@ class Sessions extends Component {
407
408
  }
408
409
 
409
410
  renderSessionsWrap = () => {
411
+ const { leftSidebarWidth, openedSideBar } = this.props.store
412
+ const w = leftSidebarWidth + 43
413
+ const ptp = openedSideBar
414
+ ? {
415
+ className: 'sessions',
416
+ style: {
417
+ marginLeft: `${w}px`
418
+ }
419
+ }
420
+ : {
421
+ className: 'sessions'
422
+ }
410
423
  return (
411
- <div className='sessions' key='main-sess'>
424
+ <div
425
+ {...ptp}
426
+ key='main-sess'
427
+ >
412
428
  {this.renderSessions()}
413
429
  </div>
414
430
  )
@@ -110,7 +110,7 @@ export default function SyncForm (props) {
110
110
  }
111
111
  const otherNameMapper = {
112
112
  token: 'access token',
113
- gist: 'gist id'
113
+ gistId: 'gist id'
114
114
  }
115
115
  function createLabel (name, text) {
116
116
  return (
@@ -23,6 +23,7 @@ import {
23
23
  modals
24
24
  } from '../../common/constants'
25
25
  import SideIcon from './side-icon'
26
+ import SidePanel from './side-panel'
26
27
  import './sidebar.styl'
27
28
 
28
29
  const { prefix } = window
@@ -91,7 +92,9 @@ export default class Sidebar extends Component {
91
92
  showModal,
92
93
  showInfoModal,
93
94
  settingItem,
94
- isSyncingSetting
95
+ isSyncingSetting,
96
+ leftSidebarWidth,
97
+ setLeftSidePanelWidth
95
98
  } = store
96
99
  const {
97
100
  showUpgradeModal,
@@ -106,6 +109,16 @@ export default class Sidebar extends Component {
106
109
  const themeActive = showSetting && settingTab === settingMap.terminalThemes
107
110
  const historyActive = showSetting && settingTab === settingMap.history
108
111
  const bookmarksActive = showSetting && settingTab === settingMap.bookmarks
112
+ const sideProps = openedSideBar
113
+ ? {
114
+ className: 'sidebar-list',
115
+ style: {
116
+ width: `${leftSidebarWidth}px`
117
+ }
118
+ }
119
+ : {
120
+ className: 'sidebar-list'
121
+ }
109
122
  return (
110
123
  <div
111
124
  className={`sidebar type-${openedSideBar}`}
@@ -210,8 +223,10 @@ export default class Sidebar extends Component {
210
223
  }
211
224
  </div>
212
225
  <InfoModal store={store} />
213
- <div
214
- className='sidebar-list'
226
+ <SidePanel
227
+ sideProps={sideProps}
228
+ setLeftSidePanelWidth={setLeftSidePanelWidth}
229
+ leftSidebarWidth={leftSidebarWidth}
215
230
  >
216
231
  <BookMarksWrap
217
232
  store={store}
@@ -223,7 +238,7 @@ export default class Sidebar extends Component {
223
238
  onMouseEnter={this.handleMouseEnterHistory}
224
239
  onMouseLeave={this.handleMouseLeave}
225
240
  />
226
- </div>
241
+ </SidePanel>
227
242
  </div>
228
243
  )
229
244
  }
@@ -0,0 +1,51 @@
1
+ import { PureComponent } from 'react'
2
+ export default class SidePanel extends PureComponent {
3
+ handleMousedown = (e) => {
4
+ this.dragStart = true
5
+ this.clientX = e.clientX
6
+ document.body.addEventListener('mouseup', this.handleMouseup)
7
+ document.body.addEventListener('mousemove', this.handleMousemove)
8
+ }
9
+
10
+ handleMouseup = (e) => {
11
+ this.dragStart = false
12
+ const {
13
+ clientX
14
+ } = e
15
+ let nw = clientX - this.clientX + 300
16
+ if (nw < 343) {
17
+ nw = 343
18
+ } else if (nw > 600) {
19
+ nw = 600
20
+ }
21
+ this.props.setLeftSidePanelWidth(nw)
22
+ document.body.removeEventListener('mouseup', this.handleMouseup)
23
+ document.body.removeEventListener('mousemove', this.handleMousemove)
24
+ }
25
+
26
+ handleMousemove = (e) => {
27
+ const {
28
+ clientX
29
+ } = e
30
+ const el = document.getElementById('side-panel')
31
+ const nw = clientX - this.clientX + this.props.leftSidebarWidth
32
+ el.style.width = nw + 'px'
33
+ }
34
+
35
+ render () {
36
+ return (
37
+ <div
38
+ {...this.props.sideProps}
39
+ id='side-panel'
40
+ draggable={false}
41
+ >
42
+ <div
43
+ className='drag-handle'
44
+ onMouseDown={this.handleMousedown}
45
+ draggable={false}
46
+ />
47
+ {this.props.children}
48
+ </div>
49
+ )
50
+ }
51
+ }
@@ -3,9 +3,9 @@
3
3
  animation-duration .2s
4
4
  .sidebar-panel
5
5
  position absolute
6
- left 43px
7
- top 46px
8
- bottom 36px
6
+ left 0
7
+ top 0
8
+ bottom 0
9
9
  z-index 200
10
10
  width 0
11
11
  overflow-y scroll
@@ -15,8 +15,6 @@
15
15
  .list-item-remove
16
16
  display none !important
17
17
 
18
- .pinned .sidebar-panel
19
- bottom 0
20
18
  .sidebar
21
19
  position absolute
22
20
  left 0
@@ -30,10 +28,10 @@
30
28
  padding-right 0
31
29
  .type-bookmarks
32
30
  .bookmarks-panel
33
- width 300px
31
+ width 100%
34
32
  .type-history
35
33
  .history-panel
36
- width 300px
34
+ width 100%
37
35
  .control-icon-text
38
36
  color text
39
37
  &:hover
@@ -50,11 +48,21 @@
50
48
  &:hover
51
49
  color text-light
52
50
  .sidebar-list
53
- .pinned
54
- color success
55
- &:hover
56
- color success
51
+ position absolute
52
+ left 43px
53
+ top 45px
54
+ bottom 36px
55
+ z-index 200
56
+ width 0
57
+ border-top 5px solid main
57
58
 
59
+ .pinned
60
+ .sidebar-list
61
+ bottom 0
62
+ .drag-handle
63
+ display block
64
+ .sidebar-panel .pinned
65
+ color success
58
66
  //btns
59
67
  .btns
60
68
  background main-dark
@@ -69,7 +77,15 @@
69
77
  // background transparent
70
78
  // color #aaa
71
79
  // border-color #555
72
-
80
+ .drag-handle
81
+ position absolute
82
+ right 0
83
+ top 0
84
+ width 3px
85
+ bottom 0
86
+ cursor ew-resize
87
+ display none
88
+ z-index 201
73
89
  // Hover.css (http://ianlunn.github.io/Hover/)
74
90
  // Version: 2.3.2
75
91
  // Author: Ian Lunn @IanLunn
@@ -2,27 +2,26 @@
2
2
  * info content module
3
3
  */
4
4
 
5
+ import { PureComponent } from 'react'
5
6
  import TerminalInfoBase from './base'
6
7
  import TerminalInfoUp from './up'
7
8
  import TerminalInfoNetwork from './network'
8
9
  import TerminalInfoResource from './resource'
9
10
  import TerminalInfoActivities from './activity'
10
11
  import TerminalInfoDisk from './disk'
11
- import { useState } from 'react'
12
12
  import RunCmd from './run-cmd'
13
13
  import {
14
- sidebarWidth,
15
14
  termControlHeight
16
15
  } from '../../common/constants'
17
16
  import { runCmd } from '../terminal/terminal-apis'
18
- import { CloseCircleOutlined, LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons'
17
+ import {
18
+ CloseCircleOutlined,
19
+ PushpinOutlined
20
+ } from '@ant-design/icons'
21
+ import classNames from 'classnames'
19
22
 
20
- export default function TerminalInfoContent (props) {
21
- if (!props.showInfo) {
22
- return null
23
- }
24
- const [state, setter] = useState({
25
- expand: false,
23
+ export default class TerminalInfoContent extends PureComponent {
24
+ state = {
26
25
  uptime: '',
27
26
  cpu: '',
28
27
  mem: {},
@@ -30,72 +29,119 @@ export default function TerminalInfoContent (props) {
30
29
  activities: [],
31
30
  disks: [],
32
31
  network: {}
33
- })
34
- function setState (ext) {
35
- setter(s => {
36
- return Object.assign({}, s, ext)
37
- })
38
32
  }
39
- async function killProcess (id) {
33
+
34
+ setStateRef = (...args) => {
35
+ this.setState(...args)
36
+ }
37
+
38
+ togglePin = () => {
39
+ this.props.toggleInfoPinned()
40
+ }
41
+
42
+ handleMousedown = (e) => {
43
+ this.dragStart = true
44
+ this.clientX = e.clientX
45
+ document.body.addEventListener('mouseup', this.handleMouseup)
46
+ document.body.addEventListener('mousemove', this.handleMousemove)
47
+ }
48
+
49
+ handleMouseup = (e) => {
50
+ this.dragStart = false
51
+ const {
52
+ clientX
53
+ } = e
54
+ let nw = this.clientX - clientX + this.props.rightSidebarWidth
55
+ if (nw < 400) {
56
+ nw = 400
57
+ } else if (nw > 1000) {
58
+ nw = 1000
59
+ }
60
+ window.store.setRightSidePanelWidth(nw)
61
+ document.body.removeEventListener('mouseup', this.handleMouseup)
62
+ document.body.removeEventListener('mousemove', this.handleMousemove)
63
+ }
64
+
65
+ handleMousemove = (e) => {
66
+ const {
67
+ clientX
68
+ } = e
69
+ const el = document.getElementById('info-panel-wrap')
70
+ const nw = this.clientX - clientX + this.props.rightSidebarWidth
71
+ console.log(nw, this.clientX, clientX, this.props.rightSidebarWidth)
72
+ el.style.width = nw + 'px'
73
+ }
74
+
75
+ killProcess = async (id) => {
40
76
  const {
41
77
  pid,
42
78
  sessionId
43
- } = props
79
+ } = this.props
44
80
  const cmd = `kill ${id}`
45
81
  runCmd(pid, sessionId, cmd)
46
82
  }
47
- const pops = {
48
- onClick: props.hideInfoPanel,
49
- className: 'pointer font20 hide-info-panel-wrap'
50
- }
51
- return (
52
- <div
53
- className='info-panel-wrap'
54
- style={{
55
- width: state.expand ? `calc(100% - ${sidebarWidth}px)` : '50%',
56
- top: props.topMenuHeight + props.tabsHeight + termControlHeight - 4
57
- }}
58
- >
59
- <div className='pd2t pd2x'>
60
- <CloseCircleOutlined
61
- {...pops}
62
- />
83
+
84
+ render () {
85
+ const { props, state } = this
86
+ if (!props.showInfo) {
87
+ return null
88
+ }
89
+
90
+ const pops = {
91
+ onClick: props.hideInfoPanel,
92
+ className: 'pointer font20 hide-info-panel-wrap'
93
+ }
94
+ const pops2 = {
95
+ onClick: this.togglePin,
96
+ className: 'pointer font20 toggle-info-panel-wrap mg1l'
97
+ }
98
+ const pops1 = {
99
+ className: classNames(
100
+ 'info-panel-wrap',
63
101
  {
64
- state.expand
65
- ? (
66
- <RightCircleOutlined
67
- onClick={() => setState({
68
- expand: false
69
- })}
70
- className='pointer font20 mg1l'
71
- />
72
- )
73
- : (
74
- <LeftCircleOutlined
75
- onClick={() => setState({
76
- expand: true
77
- })}
78
- className='pointer font20 mg1l'
79
- />
80
- )
102
+ 'info-panel-wrap-pin': props.infoPanelPinned
81
103
  }
82
-
83
- </div>
84
- <div className='pd2'>
85
- <TerminalInfoBase {...props} {...state} />
86
- <TerminalInfoUp {...props} {...state} />
87
- <TerminalInfoResource
88
- {...props} {...state}
89
- />
90
- <TerminalInfoActivities
91
- {...props}
92
- {...state}
93
- killProcess={killProcess}
104
+ ),
105
+ id: 'info-panel-wrap',
106
+ draggable: false,
107
+ style: {
108
+ width: props.rightSidebarWidth,
109
+ top: props.topMenuHeight + props.tabsHeight + termControlHeight - 4
110
+ }
111
+ }
112
+ return (
113
+ <div
114
+ {...pops1}
115
+ >
116
+ <div
117
+ className='drag-handle'
118
+ onMouseDown={this.handleMousedown}
119
+ draggable={false}
94
120
  />
95
- <TerminalInfoNetwork {...props} {...state} />
96
- <TerminalInfoDisk {...props} {...state} />
97
- <RunCmd {...props} setState={setState} />
121
+ <div className='pd2t pd2x'>
122
+ <CloseCircleOutlined
123
+ {...pops}
124
+ />
125
+ <PushpinOutlined
126
+ {...pops2}
127
+ />
128
+ </div>
129
+ <div className='pd2'>
130
+ <TerminalInfoBase {...props} {...state} />
131
+ <TerminalInfoUp {...props} {...state} />
132
+ <TerminalInfoResource
133
+ {...props} {...state}
134
+ />
135
+ <TerminalInfoActivities
136
+ {...props}
137
+ {...state}
138
+ killProcess={this.killProcess}
139
+ />
140
+ <TerminalInfoNetwork {...props} {...state} />
141
+ <TerminalInfoDisk {...props} {...state} />
142
+ <RunCmd {...props} setState={this.setStateRef} />
143
+ </div>
98
144
  </div>
99
- </div>
100
- )
145
+ )
146
+ }
101
147
  }
@@ -4,17 +4,20 @@
4
4
  &:hover
5
5
  color text
6
6
  .info-panel-wrap
7
- position fixed
7
+ position absolute
8
8
  right 0
9
9
  top 100px
10
10
  bottom 0
11
11
  width 500px
12
- background main
12
+ background main-light
13
13
  color text
14
- box-shadow 0px 3px 3px 3px alpha(main, .25)
15
14
  z-index 100
16
15
  overflow-y scroll
17
16
  opacity .9
17
+ .drag-handle
18
+ left 0
19
+ right auto
20
+ display block
18
21
  .terminal-info-section
19
22
  padding 10px 0
20
23
  .terminal-info-act
@@ -26,4 +29,7 @@
26
29
  .activity-item-copy
27
30
  display none
28
31
  &:hover .activity-item-copy
29
- display inline
32
+ display inline
33
+ .info-panel-wrap-pin
34
+ .toggle-info-panel-wrap
35
+ color success
@@ -8,8 +8,11 @@ import postMessage from '../common/post-msg'
8
8
  import {
9
9
  commonActions,
10
10
  tabActions,
11
- modals
11
+ modals,
12
+ leftSidebarWidthKey,
13
+ rightSidebarWidthKey
12
14
  } from '../common/constants'
15
+ import * as ls from '../common/safe-local-storage'
13
16
 
14
17
  export default Store => {
15
18
  Store.prototype.storeAssign = function (updates) {
@@ -137,4 +140,14 @@ export default Store => {
137
140
  ...update
138
141
  })
139
142
  }
143
+
144
+ Store.prototype.setLeftSidePanelWidth = function (v) {
145
+ ls.setItem(leftSidebarWidthKey, v)
146
+ window.store.leftSidebarWidth = v
147
+ }
148
+
149
+ Store.prototype.setRightSidePanelWidth = function (v) {
150
+ ls.setItem(rightSidebarWidthKey, v)
151
+ window.store.rightSidebarWidth = v
152
+ }
140
153
  }
@@ -15,7 +15,9 @@ import {
15
15
  batchInputLsKey,
16
16
  expandedKeysLsKey,
17
17
  checkedKeysLsKey,
18
- localAddrBookmarkLsKey
18
+ localAddrBookmarkLsKey,
19
+ leftSidebarWidthKey,
20
+ rightSidebarWidthKey
19
21
  } from '../common/constants'
20
22
  import { buildDefaultThemes, buildNewTheme } from '../common/terminal-theme'
21
23
  import * as ls from '../common/safe-local-storage'
@@ -141,6 +143,8 @@ export default () => {
141
143
 
142
144
  // sidebar
143
145
  openedSideBar: ls.getItem(openedSidebarKey),
146
+ leftSidebarWidth: parseInt(ls.getItem(leftSidebarWidthKey), 10) || 300,
147
+ rightSidebarWidth: parseInt(ls.getItem(rightSidebarWidthKey), 10) || 500,
144
148
  menuOpened: false,
145
149
  pinned: ls.getItem(sidebarPinnedKey) === 'true',
146
150
 
@@ -2,7 +2,7 @@
2
2
  * setting modal
3
3
  */
4
4
 
5
- import { find, isEqual, pick, without, findIndex } from 'lodash-es'
5
+ import { find, isEqual, pick, without } from 'lodash-es'
6
6
  import {
7
7
  message
8
8
  } from 'antd'
@@ -113,14 +113,8 @@ export default Store => {
113
113
  pick(j, without(keysj, 'id'))
114
114
  )
115
115
  })
116
- if (!existItem) {
117
- store.addItem(item, settingMap.history)
118
- } else {
119
- const index = findIndex(history, f => f.id === existItem.id)
120
- history.splice(index, 1)
121
- history.unshift(existItem)
122
- store.setItems('history', history)
123
- }
116
+ history.unshift(existItem)
117
+ store.setItems('history', history)
124
118
  }
125
119
 
126
120
  Store.prototype.openSetting = function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "1.37.46",
3
+ "version": "1.37.58",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",