@electerm/electerm-react 1.34.49 → 1.34.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.
@@ -34,6 +34,7 @@ export default {
34
34
  useSystemTitleBar: false,
35
35
  opacity: 1,
36
36
  defaultEditor: '',
37
+ terminalWordSeparator: './\\()"\'-:,.;<>~!@#$%^&*|+=[]{}`~?',
37
38
  confirmBeforeExit: false,
38
39
  initDefaultTabOnStart: true,
39
40
  screenReaderMode: false,
@@ -16,7 +16,7 @@ export function updateCount (tab) {
16
16
  window.et.tabCount++
17
17
  }
18
18
 
19
- export default (removeTitle) => {
19
+ export default (removeTitle, noUpdateCount) => {
20
20
  const res = {
21
21
  id: generate(),
22
22
  status: 'processing',
@@ -26,6 +26,8 @@ export default (removeTitle) => {
26
26
  if (removeTitle) {
27
27
  delete res.title
28
28
  }
29
- updateCount(res)
29
+ if (!noUpdateCount) {
30
+ updateCount(res)
31
+ }
30
32
  return res
31
33
  }
@@ -46,6 +46,7 @@ window.log = {
46
46
  }
47
47
 
48
48
  window.pre = {
49
+ requireAuth: runSync('shouldAuth'),
49
50
  readClipboard: () => {
50
51
  return runSync('readClipboard')
51
52
  },
@@ -0,0 +1,127 @@
1
+ import { Component } from '../common/react-subx'
2
+ import LogoElem from '../common/logo-elem.jsx'
3
+ import store from '../../store'
4
+ import {
5
+ Input,
6
+ message,
7
+ Spin
8
+ } from 'antd'
9
+ import {
10
+ ArrowRightOutlined
11
+ } from '@ant-design/icons'
12
+ import Main from '../main/main.jsx'
13
+ import './login.styl'
14
+
15
+ const { prefix } = window
16
+ const f = prefix('form')
17
+
18
+ export default class Login extends Component {
19
+ state = {
20
+ pass: '',
21
+ logined: !window.pre.requireAuth,
22
+ loading: false
23
+ }
24
+
25
+ componentDidMount () {
26
+ this.init()
27
+ }
28
+
29
+ init = async () => {
30
+ if (!window.pre.requireAuth) {
31
+ return
32
+ }
33
+ const globs = await window.pre.runGlobalAsync('init')
34
+ window.et.globs = globs
35
+ }
36
+
37
+ handlePassChange = e => {
38
+ this.setState({
39
+ pass: e.target.value
40
+ })
41
+ }
42
+
43
+ handleSubmit = () => {
44
+ const {
45
+ pass
46
+ } = this.state
47
+ if (!pass) {
48
+ return message.warning('password required')
49
+ } else if (
50
+ this.submitting
51
+ ) {
52
+ return
53
+ }
54
+ this.login(
55
+ this.state.pass
56
+ )
57
+ }
58
+
59
+ login = async (pass) => {
60
+ this.submitting = true
61
+ const r = await window.pre.runGlobalAsync('checkPassword', pass)
62
+ if (r) {
63
+ this.setState({
64
+ logined: true,
65
+ loading: false
66
+ })
67
+ } else {
68
+ message.error('Login failed')
69
+ this.setState({
70
+ loading: false
71
+ })
72
+ }
73
+ this.submitting = false
74
+ }
75
+
76
+ renderAfter = () => {
77
+ return (
78
+ <ArrowRightOutlined
79
+ className='mg1x pointer'
80
+ onClick={this.handleSubmit}
81
+ />
82
+ )
83
+ }
84
+
85
+ renderLogin () {
86
+ const {
87
+ pass,
88
+ loading
89
+ } = this.state
90
+ return (
91
+ <div className='login-wrap'>
92
+ <div className='pd3 aligncenter'>
93
+ <LogoElem />
94
+ <div className='pd3 aligncenter'>
95
+ <Input.Password
96
+ value={pass}
97
+ readOnly={loading}
98
+ onChange={this.handlePassChange}
99
+ placeholder={f('password')}
100
+ addonAfter={this.renderAfter()}
101
+ onPressEnter={this.handleSubmit}
102
+ />
103
+ </div>
104
+ <div className='aligncenter'>
105
+ <Spin
106
+ spinning={loading}
107
+ />
108
+ </div>
109
+ </div>
110
+ </div>
111
+ )
112
+ }
113
+
114
+ render () {
115
+ const {
116
+ logined
117
+ } = this.state
118
+ if (!logined) {
119
+ return this.renderLogin()
120
+ }
121
+ return (
122
+ <Main
123
+ store={store}
124
+ />
125
+ )
126
+ }
127
+ }
@@ -0,0 +1,7 @@
1
+ .login-wrap
2
+ position fixed
3
+ left 0
4
+ top 0
5
+ width 100%
6
+ height 100%
7
+ background #fff
@@ -303,7 +303,7 @@ export default class BookmarkForm extends PureComponent {
303
303
  if (evt !== 'save' && evt !== 'saveAndCreateNew') {
304
304
  this.props.store.addTab({
305
305
  ...copy(obj),
306
- ...newTerm(true)
306
+ ...newTerm(true, true)
307
307
  })
308
308
  this.props.hide()
309
309
  }
@@ -1,11 +1,10 @@
1
1
  import ErrorBoundary from './error-wrapper'
2
- import Main from './main'
3
- import store from '../../store'
2
+ import Login from '../auth/login'
4
3
 
5
4
  export default function MainEntry () {
6
5
  return (
7
6
  <ErrorBoundary>
8
- <Main store={store} />
7
+ <Login />
9
8
  </ErrorBoundary>
10
9
  )
11
10
  }
@@ -134,7 +134,7 @@ export default class Upgrade extends PureComponent {
134
134
  if (!isMac && !isWin && installSrc === 'npm') {
135
135
  return window.store.addTab(
136
136
  {
137
- ...newTerm(),
137
+ ...newTerm(undefined, true),
138
138
  loginScript: 'npm i -g electerm'
139
139
  }
140
140
  )
@@ -6,7 +6,7 @@ import copy from 'json-deep-copy'
6
6
  export default class QmTransport extends BookmarkTransport {
7
7
  beforeUpload = async (file) => {
8
8
  const { store } = this.props
9
- const txt = await window.fs.readFileSync(file.path)
9
+ const txt = await window.fs.readFile(file.path)
10
10
  try {
11
11
  const quickCommands = JSON.parse(txt)
12
12
  const quickCommandsOld = copy(store.quickCommands)
@@ -80,7 +80,7 @@ export default class SessionWrapper extends Component {
80
80
  key: Math.random(),
81
81
  sessionOptions: null,
82
82
  sessionId: generate(),
83
- terminals,
83
+ terminals: terminals.slice(0, 1),
84
84
  showInfo: false,
85
85
  infoPanelProps: {}
86
86
  }
@@ -437,8 +437,10 @@ export default class SessionWrapper extends Component {
437
437
  key={type + '_' + i}
438
438
  onClick={() => this.onChangePane(types[i])}
439
439
  >
440
- {e(type)}
441
- <span className='type-tab-line' />
440
+ <span className='type-tab-txt'>
441
+ {e(type)}
442
+ <span className='type-tab-line' />
443
+ </span>
442
444
  </span>
443
445
  )
444
446
  })
@@ -12,14 +12,17 @@
12
12
  height 1px
13
13
  background text-dark
14
14
  display none
15
+ .type-tab-txt
16
+ position relative
17
+ display inline-block
15
18
 
16
19
  .type-tab
17
- position relative
18
20
  display inline-block
19
21
  vertical-align middle
20
22
  line-height 30px
21
23
  color text-dark
22
- margin-right 20px
24
+ padding 0 20px 0 0
25
+ margin-right 0px
23
26
  font-size 14px
24
27
  cursor pointer
25
28
  &:hover
@@ -1,5 +1,9 @@
1
1
  import React, { Component } from 'react'
2
- import { CodeOutlined, LoadingOutlined } from '@ant-design/icons'
2
+ import {
3
+ CodeOutlined,
4
+ ArrowRightOutlined,
5
+ LoadingOutlined
6
+ } from '@ant-design/icons'
3
7
  import {
4
8
  message,
5
9
  Select,
@@ -57,7 +61,12 @@ const keys = [
57
61
  export default class Setting extends Component {
58
62
  state = {
59
63
  ready: false,
60
- languageChanged: false
64
+ languageChanged: false,
65
+ passwordChanged: false,
66
+ submittingPass: false,
67
+ passInputFocused: false,
68
+ placeholderLogin: window.pre.requireAuth ? '********' : f('notSet'),
69
+ loginPass: ''
61
70
  }
62
71
 
63
72
  componentDidMount () {
@@ -70,6 +79,61 @@ export default class Setting extends Component {
70
79
 
71
80
  componentWillUnmount () {
72
81
  clearTimeout(this.timer)
82
+ clearTimeout(this.timer1)
83
+ }
84
+
85
+ handleLoginSubmit = async () => {
86
+ if (this.submitting) {
87
+ return
88
+ }
89
+ this.setState({
90
+ submittingPass: true
91
+ })
92
+ this.submitting = true
93
+ const pass = this.state.loginPass
94
+ const r = await window.pre.runGlobalAsync(
95
+ 'setPassword',
96
+ pass
97
+ )
98
+ if (r === true) {
99
+ window.pre.requireAuth = !!pass
100
+ this.setState({
101
+ loginPass: pass ? '********' : '',
102
+ submittingPass: false,
103
+ passwordChanged: true,
104
+ placeholderLogin: pass ? '********' : f('notSet')
105
+ })
106
+ message.success('OK')
107
+ } else {
108
+ this.setState({
109
+ submittingPass: false
110
+ })
111
+ }
112
+ this.submitting = false
113
+ }
114
+
115
+ handleLoginPassFocus = () => {
116
+ this.setState({
117
+ passInputFocused: true
118
+ })
119
+ }
120
+
121
+ blurPassInput = () => {
122
+ this.setState({
123
+ passInputFocused: false
124
+ })
125
+ }
126
+
127
+ handleLoginPassBlur = () => {
128
+ this.timer1 = setTimeout(
129
+ this.blurPassInput, 300
130
+ )
131
+ }
132
+
133
+ handleChangeLoginPass = e => {
134
+ this.setState({
135
+ loginPass: e.target.value
136
+ })
73
137
  }
74
138
 
75
139
  handleRestart = () => {
@@ -182,8 +246,8 @@ export default class Setting extends Component {
182
246
  )
183
247
  }
184
248
 
185
- renderLanguageChangeTip = () => {
186
- if (!this.state.languageChanged) {
249
+ renderRestart = (name) => {
250
+ if (!this.state[name]) {
187
251
  return null
188
252
  }
189
253
  return (
@@ -617,6 +681,57 @@ export default class Setting extends Component {
617
681
  }
618
682
  }
619
683
 
684
+ renderLoginPassAfter () {
685
+ const {
686
+ loginPass,
687
+ submittingPass,
688
+ passInputFocused
689
+ } = this.state
690
+ if (!loginPass && !passInputFocused) {
691
+ return null
692
+ } else if (
693
+ submittingPass
694
+ ) {
695
+ return <LoadingOutlined />
696
+ }
697
+ return (
698
+ <ArrowRightOutlined
699
+ className='pointer'
700
+ onClick={this.handleLoginSubmit}
701
+ />
702
+ )
703
+ }
704
+
705
+ renderLoginPass () {
706
+ if (window.et.isWebApp) {
707
+ return null
708
+ }
709
+ const {
710
+ loginPass,
711
+ submittingPass,
712
+ placeholderLogin
713
+ } = this.state
714
+ const props = {
715
+ value: loginPass,
716
+ disabled: submittingPass,
717
+ onFocus: this.handleLoginPassFocus,
718
+ onBlur: this.handleLoginPassBlur,
719
+ onChange: this.handleChangeLoginPass,
720
+ addonAfter: this.renderLoginPassAfter(),
721
+ placeholder: placeholderLogin
722
+ }
723
+ return (
724
+ <div>
725
+ <div className='pd1b'>{f('loginPassword')}</div>
726
+ <div className='pd2b'>
727
+ <Input.Password
728
+ {...props}
729
+ />
730
+ </div>
731
+ </div>
732
+ )
733
+ }
734
+
620
735
  render () {
621
736
  const { ready } = this.state
622
737
  if (!ready) {
@@ -746,7 +861,7 @@ export default class Setting extends Component {
746
861
  </Select>
747
862
  <Link className='mg1l' to={createEditLangLink(language)}>{p('edit')}</Link>
748
863
  </div>
749
- {this.renderLanguageChangeTip()}
864
+ {this.renderRestart('languageChanged')}
750
865
  <div className='pd1y font16 bold'>
751
866
  <CodeOutlined className='mg1r' />
752
867
  {s('terminal')} {e('settings')}
@@ -789,9 +904,9 @@ export default class Setting extends Component {
789
904
  {
790
905
  this.renderTerminalBgSelect('terminalBackgroundImagePath')
791
906
  }
792
- <div className='pd1b'>{t('default')} {e('editorTip')}</div>
907
+ <div className='pd1b'>{e('terminalWordSeparator')}</div>
793
908
  {
794
- this.renderText('defaultEditor', e('editorTip'))
909
+ this.renderText('terminalWordSeparator', e('terminalWordSeparator'))
795
910
  }
796
911
  <div className='pd1b'>{t('default')} {e('execWindows')}</div>
797
912
  {
@@ -829,6 +944,8 @@ export default class Setting extends Component {
829
944
  {this.renderToggle('saveTerminalLogToFile', (
830
945
  <ShowItem to={terminalLogPath} className='mg1l'>{p('open')}</ShowItem>
831
946
  ))}
947
+
948
+ {this.renderLoginPass()}
832
949
  {this.renderReset()}
833
950
  </div>
834
951
  )
@@ -808,6 +808,7 @@ export default class Term extends Component {
808
808
  theme: themeConfig,
809
809
  allowTransparency: true,
810
810
  // lineHeight: 1.2,
811
+ wordSeparator: config.terminalWordSeparator,
811
812
  cursorStyle: config.cursorStyle,
812
813
  cursorBlink: config.cursorBlink,
813
814
  fontSize: tab.fontSize || config.fontSize,
@@ -9,6 +9,6 @@
9
9
  .ant-tree-indent-unit
10
10
  width 5px
11
11
  .ant-tree .ant-tree-switcher.ant-tree-switcher-noop
12
- width 18px
12
+ width 0px
13
13
  td.ant-table-column-sort
14
14
  background none
@@ -2,7 +2,7 @@ import { render } from 'react-dom'
2
2
  import 'antd/dist/reset.css'
3
3
  import 'xterm/css/xterm.css'
4
4
  import '../common/trzsz'
5
- import Main from '../components/main'
5
+ import Main from '../components/main/index.jsx'
6
6
  import { notification } from 'antd'
7
7
  notification.config({
8
8
  placement: 'bottomRight'
@@ -83,8 +83,8 @@ export default Store => {
83
83
 
84
84
  Store.prototype.runBatchOp = function (path) {
85
85
  window.store.showModal = modals.batchOps
86
- function updateText () {
87
- const text = window.pre.readFileSync(path).toString()
86
+ async function updateText () {
87
+ const text = await window.fs.readFile(path)
88
88
  postMessage({
89
89
  action: commonActions.batchOp,
90
90
  batchOp: {
@@ -142,7 +142,7 @@ export default (Store) => {
142
142
  }
143
143
  Store.prototype.initApp = async function () {
144
144
  const { store } = window
145
- const globs = await window.pre.runGlobalAsync('init')
145
+ const globs = window.et.globs || await window.pre.runGlobalAsync('init')
146
146
  window.langMap = globs.langMap
147
147
  store.installSrc = globs.installSrc
148
148
  store.appPath = globs.appPath
@@ -79,7 +79,7 @@ export default Store => {
79
79
  ...copy(item),
80
80
  from: 'history',
81
81
  srcId: item.id,
82
- ...newTerm(true)
82
+ ...newTerm(true, true)
83
83
  })
84
84
  }
85
85
 
@@ -98,7 +98,7 @@ export default Store => {
98
98
  ...item,
99
99
  from: 'bookmarks',
100
100
  srcId: item.id,
101
- ...newTerm(true)
101
+ ...newTerm(true, true)
102
102
  })
103
103
  item.id = generate()
104
104
  if (store.config.disableSshHistory) {
@@ -356,7 +356,7 @@ export default (Store) => {
356
356
 
357
357
  Store.prototype.importAll = async function (file) {
358
358
  const txt = await window.fs
359
- .readFileSync(file.path)
359
+ .readFile(file.path)
360
360
  const { store } = window
361
361
  const objs = JSON.parse(txt)
362
362
  const toInsert = []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "1.34.49",
3
+ "version": "1.34.58",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",