@electerm/electerm-react 1.60.29 → 1.60.36

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.
@@ -265,6 +265,7 @@ export const proxyHelpLink = 'https://github.com/electerm/electerm/wiki/proxy-fo
265
265
  export const regexHelpLink = 'https://github.com/electerm/electerm/wiki/Terminal-keywords-highlight-regular-expression-exmaples'
266
266
  export const connectionHoppingWikiLink = 'https://github.com/electerm/electerm/wiki/Connection-Hopping-Behavior-Change-in-electerm-since-v1.50.65'
267
267
  export const aiConfigWikiLink = 'https://github.com/electerm/electerm/wiki/AI-model-config-guide'
268
+ export const rdpWikiLink = 'https://github.com/electerm/electerm/wiki/RDP-session-known-issues'
268
269
  export const modals = {
269
270
  hide: 0,
270
271
  setting: 1,
@@ -7,12 +7,14 @@ import {
7
7
  Input,
8
8
  Form,
9
9
  InputNumber,
10
- TreeSelect
10
+ TreeSelect,
11
+ Alert
11
12
  } from 'antd'
12
13
  import { formItemLayout } from '../../common/form-layout'
13
14
  import {
14
15
  newBookmarkIdPrefix,
15
- terminalRdpType
16
+ terminalRdpType,
17
+ rdpWikiLink
16
18
  } from '../../common/constants'
17
19
  import useSubmit from './use-submit'
18
20
  import copy from 'json-deep-copy'
@@ -22,6 +24,7 @@ import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
22
24
  import formatBookmarkGroups from './bookmark-group-tree-format'
23
25
  import findBookmarkGroupId from '../../common/find-bookmark-group-id'
24
26
  import ProfileItem from './profile-form-item'
27
+ import Link from '../common/external-link'
25
28
 
26
29
  const FormItem = Form.Item
27
30
  const e = window.translate
@@ -63,8 +66,18 @@ export default function RdpFormUi (props) {
63
66
  bookmarkGroups = []
64
67
  } = props
65
68
  const tree = formatBookmarkGroups(bookmarkGroups)
69
+ const alertProps = {
70
+ message: (
71
+ <Link to={rdpWikiLink}>WIKI: {rdpWikiLink}</Link>
72
+ ),
73
+ type: 'warning',
74
+ className: 'mg2y'
75
+ }
66
76
  return (
67
77
  <div className='pd1x'>
78
+ <Alert
79
+ {...alertProps}
80
+ />
68
81
  <FormItem
69
82
  {...formItemLayout}
70
83
  label={e('title')}
@@ -5,7 +5,6 @@ import {
5
5
  } from 'antd'
6
6
  import { defaultBookmarkGroupId, settingMap } from '../../common/constants'
7
7
  import deepCopy from 'json-deep-copy'
8
- import { action } from 'manate'
9
8
 
10
9
  const e = window.translate
11
10
 
@@ -24,10 +23,8 @@ export default class BookmarkTreeDelete extends StartSessionSelect {
24
23
  checkedKeys
25
24
  } = this.props
26
25
  const arr = checkedKeys.filter(d => d !== defaultBookmarkGroupId)
27
- action(() => {
28
- store.delItems(arr, settingMap.bookmarks)
29
- store.delItems(arr, settingMap.bookmarkGroups)
30
- })
26
+ store.delItems(arr, settingMap.bookmarks)
27
+ store.delItems(arr, settingMap.bookmarkGroups)
31
28
  store.checkedKeys = []
32
29
  }
33
30
 
@@ -0,0 +1,42 @@
1
+ import React from 'react'
2
+ import writeEmitter from 'manate/events/write-emitter'
3
+ import { run } from 'manate/utils'
4
+
5
+ export class Component extends React.Component {
6
+ constructor (props) {
7
+ super(props)
8
+ this.isTrigger = null
9
+ this.originalRender = this.render
10
+ this.render = this.autoRender
11
+
12
+ const originalDidMount = this.componentDidMount
13
+ this.componentDidMount = () => {
14
+ writeEmitter.on(this.handleWrite)
15
+ if (originalDidMount) {
16
+ originalDidMount.call(this)
17
+ }
18
+ }
19
+
20
+ const originalWillUnmount = this.componentWillUnmount
21
+ this.componentWillUnmount = () => {
22
+ writeEmitter.off(this.handleWrite)
23
+ if (originalWillUnmount) {
24
+ originalWillUnmount.call(this)
25
+ }
26
+ }
27
+ }
28
+
29
+ handleWrite = (writeLog) => {
30
+ if (this.isTrigger && this.isTrigger(writeLog)) {
31
+ this.forceUpdate()
32
+ }
33
+ }
34
+
35
+ autoRender = () => {
36
+ const [element, isTrigger] = run(() => {
37
+ return this.originalRender()
38
+ })
39
+ this.isTrigger = isTrigger
40
+ return element
41
+ }
42
+ }
@@ -11,7 +11,7 @@ export default function InputAutoFocus (props) {
11
11
  if (inputRef.current) {
12
12
  const { value } = props
13
13
  if (value && selectall) {
14
- inputRef.current.setSelectionRange(0, value.length)
14
+ inputRef.current.focus()
15
15
  } else {
16
16
  inputRef.current.focus()
17
17
  }
@@ -13,7 +13,6 @@ import Footer from '../footer/footer-entry'
13
13
  import SessionsWrap from '../session/sessions'
14
14
  import QuickCommandsFooterBox from '../quick-commands/quick-commands-box'
15
15
  import pixed from './pixed'
16
- import copy from 'json-deep-copy'
17
16
  import { pick } from 'lodash-es'
18
17
  import './layout.styl'
19
18
 
@@ -181,7 +180,7 @@ export default auto(function Layout (props) {
181
180
  'openedSideBar',
182
181
  'config'
183
182
  ]),
184
- tabs: copy(store.tabs)
183
+ tabs: store.tabs
185
184
  }
186
185
  return [
187
186
  <Layouts {...layoutProps} key='layouts'>
@@ -1,11 +1,10 @@
1
- import { memo } from 'react'
2
1
  import {
3
2
  splitConfig
4
3
  } from '../../common/constants'
5
4
  import LayoutItem from './layout-item'
6
5
  import pixed from './pixed'
7
6
 
8
- export default memo(function LayoutWrap (props) {
7
+ export default function LayoutWrap (props) {
9
8
  const {
10
9
  children,
11
10
  layout,
@@ -61,4 +60,4 @@ export default memo(function LayoutWrap (props) {
61
60
  }
62
61
  </div>
63
62
  )
64
- })
63
+ }
@@ -165,7 +165,7 @@ export default auto(function Index (props) {
165
165
  'commandLineHelp'
166
166
  ]),
167
167
  installSrc,
168
- upgradeInfo
168
+ upgradeInfo: store.upgradeInfo
169
169
  }
170
170
  const conflictStoreProps = {
171
171
  fileTransferChanged: JSON.stringify(copiedTransfer),
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * terminal/sftp wrapper
3
3
  */
4
- import { Component, createRef } from 'react'
4
+ import { createRef } from 'react'
5
+ import { Component } from '../common/component'
5
6
  import Term from '../terminal/terminal.jsx'
6
7
  import Sftp from '../sftp/sftp-entry'
7
8
  import RdpSession from '../rdp/rdp-session'
@@ -1,4 +1,4 @@
1
- import { Component } from 'react'
1
+ import { Component } from '../common/component'
2
2
  import Session from './session.jsx'
3
3
 
4
4
  import { pick } from 'lodash-es'
@@ -15,7 +15,6 @@ import TabQuickCommands from './tab-quick-commands'
15
15
  import TabSettings from './tab-settings'
16
16
  import TabThemes from './tab-themes'
17
17
  import TabProfiles from './tab-profiles'
18
- import deepCopy from 'json-deep-copy'
19
18
 
20
19
  const e = window.translate
21
20
 
@@ -39,8 +38,7 @@ export default auto(function SettingModalWrap (props) {
39
38
  shouldConfirmDel: tabsShouldConfirmDel.includes(settingTab),
40
39
  list: settingSidebarList
41
40
  }
42
- const bookmarks = deepCopy(store.bookmarks)
43
- const bookmarkGroups = deepCopy(store.bookmarkGroups)
41
+ const { bookmarks, bookmarkGroups } = store
44
42
  const formProps = {
45
43
  store,
46
44
  formData: settingItem,
@@ -11,7 +11,8 @@ export default auto(function BookmarkSelect (props) {
11
11
  listStyle,
12
12
  openedSideBar,
13
13
  leftSidebarWidth,
14
- expandedKeys
14
+ expandedKeys,
15
+ bookmarks
15
16
  } = store
16
17
  if (from === 'sidebar' && openedSideBar !== 'bookmarks') {
17
18
  return null
@@ -23,7 +24,7 @@ export default auto(function BookmarkSelect (props) {
23
24
  store.onSelectBookmark(item.id)
24
25
  }
25
26
  const base = {
26
- bookmarks: store.bookmarks || [],
27
+ bookmarks: bookmarks || [],
27
28
  type: 'bookmarks',
28
29
  onClickItem,
29
30
  listStyle,
@@ -1,4 +1,3 @@
1
- import { memo } from 'react'
2
1
  import {
3
2
  GithubOutlined,
4
3
  GlobalOutlined,
@@ -16,6 +15,7 @@ import { Modal, Tabs, Button } from 'antd'
16
15
  import Link from '../common/external-link'
17
16
  import LogoElem from '../common/logo-elem'
18
17
  import RunningTime from './app-running-time'
18
+ import { auto } from 'manate/react'
19
19
 
20
20
  import {
21
21
  packInfo,
@@ -26,7 +26,7 @@ import './info.styl'
26
26
 
27
27
  const e = window.translate
28
28
 
29
- export default memo(function InfoModal (props) {
29
+ export default auto(function InfoModal (props) {
30
30
  const handleChangeTab = key => {
31
31
  window.store.infoModalTab = key
32
32
  }
@@ -2,6 +2,7 @@
2
2
  * session tabs component
3
3
  */
4
4
 
5
+ import { Component } from '../common/component'
5
6
  import React from 'react'
6
7
  import runIdle from '../../common/run-idle'
7
8
  import { throttle } from 'lodash-es'
@@ -43,7 +44,7 @@ import classNames from 'classnames'
43
44
 
44
45
  const e = window.translate
45
46
 
46
- export default class Tabs extends React.Component {
47
+ export default class Tabs extends Component {
47
48
  constructor (props) {
48
49
  super(props)
49
50
  this.tabsRef = React.createRef()
@@ -2,7 +2,8 @@
2
2
  * file section
3
3
  */
4
4
 
5
- import { Component, createRef } from 'react'
5
+ import { createRef } from 'react'
6
+ import { Component } from '../common/component'
6
7
  import { refs } from '../common/ref'
7
8
  import {
8
9
  CloseOutlined,
@@ -2,9 +2,8 @@ import {
2
2
  CaretDownOutlined,
3
3
  CaretRightOutlined
4
4
  } from '@ant-design/icons'
5
- import { memo } from 'react'
6
5
 
7
- export default memo(function TreeExpander (props) {
6
+ export default function TreeExpander (props) {
8
7
  function onExpand () {
9
8
  props.onExpand(group)
10
9
  }
@@ -33,4 +32,4 @@ export default memo(function TreeExpander (props) {
33
32
  <Icon />
34
33
  </div>
35
34
  )
36
- })
35
+ }
@@ -21,12 +21,11 @@ import {
21
21
  } from '../../common/constants'
22
22
  import highlight from '../common/highlight'
23
23
  import uid from '../../common/uid'
24
- import { memo } from 'react'
25
24
  import './tree-list.styl'
26
25
 
27
26
  const e = window.translate
28
27
 
29
- export default memo(function TreeListItem (props) {
28
+ export default function TreeListItem (props) {
30
29
  const handleDel = (e) => {
31
30
  props.del(props.item, e)
32
31
  }
@@ -254,4 +253,4 @@ export default memo(function TreeListItem (props) {
254
253
  {renderEditBtn()}
255
254
  </div>
256
255
  )
257
- })
256
+ }
@@ -2,7 +2,7 @@
2
2
  * tree list for bookmarks
3
3
  */
4
4
 
5
- import { Component } from 'react'
5
+ import { Component } from '../common/component'
6
6
  import {
7
7
  CheckOutlined,
8
8
  CloseOutlined,
@@ -22,6 +22,7 @@ import NewButtonsGroup from './bookmark-toolbar'
22
22
  import findBookmarkGroupId from '../../common/find-bookmark-group-id'
23
23
  import getInitItem from '../../common/init-setting-item'
24
24
  import uid from '../../common/uid'
25
+ import { action } from 'manate'
25
26
  import deepEqual from 'fast-deep-equal'
26
27
  import './tree-list.styl'
27
28
  import TreeExpander from './tree-expander'
@@ -223,34 +224,37 @@ export default class ItemListTree extends Component {
223
224
  return
224
225
  }
225
226
  this.onSubmit = true
226
- const id = this.state.parentId
227
+ this.parentId = this.state.parentId
227
228
  this.setState({
228
229
  showNewBookmarkGroupForm: false,
229
230
  parentId: ''
230
- }, () => {
231
- this.onSubmit = false
232
- const { bookmarkGroups } = window.store
233
- const newCat = {
234
- id: uid(),
235
- title: this.state.bookmarkGroupTitle,
236
- level: 2,
237
- bookmarkIds: []
238
- }
239
- bookmarkGroups.unshift(newCat)
240
- const cat = find(
241
- bookmarkGroups,
242
- d => d.id === id
243
- )
244
- if (!cat) {
245
- return
246
- }
247
- cat.bookmarkGroupIds = [
248
- ...(cat.bookmarkGroupIds || []),
249
- newCat.id
250
- ]
251
- })
231
+ }, this.afterSubmitSub)
252
232
  }
253
233
 
234
+ afterSubmitSub = action(() => {
235
+ const id = this.parentId
236
+ this.onSubmit = false
237
+ const { bookmarkGroups } = window.store
238
+ const newCat = {
239
+ id: uid(),
240
+ title: this.state.bookmarkGroupTitle,
241
+ level: 2,
242
+ bookmarkIds: []
243
+ }
244
+ bookmarkGroups.unshift(newCat)
245
+ const cat = find(
246
+ bookmarkGroups,
247
+ d => d.id === id
248
+ )
249
+ if (!cat) {
250
+ return
251
+ }
252
+ cat.bookmarkGroupIds = [
253
+ ...(cat.bookmarkGroupIds || []),
254
+ newCat.id
255
+ ]
256
+ })
257
+
254
258
  handleNewBookmarkGroup = () => {
255
259
  this.setState({
256
260
  showNewBookmarkGroupForm: true,
@@ -391,7 +395,7 @@ export default class ItemListTree extends Component {
391
395
  target.classList.add('item-dragover')
392
396
  }
393
397
 
394
- onDrop = e => {
398
+ onDrop = action(e => {
395
399
  e.preventDefault()
396
400
  const elems = document.querySelectorAll('.tree-item.item-dragover')
397
401
  elems.forEach(elem => {
@@ -533,7 +537,7 @@ export default class ItemListTree extends Component {
533
537
  item.level = 2
534
538
  }
535
539
  }
536
- }
540
+ })
537
541
 
538
542
  editCategory = () => {
539
543
  const {
@@ -47,44 +47,63 @@ export default Store => {
47
47
 
48
48
  Store.prototype.delBookmarkGroup = action(function ({ id }) {
49
49
  const { store } = window
50
+
51
+ // Cannot delete default group
50
52
  if (id === defaultBookmarkGroupId) {
51
53
  return
52
54
  }
53
- let { bookmarkGroups } = store
54
- const tobeDel = find(bookmarkGroups, bg => bg.id === id)
55
- if (!tobeDel) {
55
+
56
+ const { bookmarkGroups } = store
57
+ const index = bookmarkGroups.findIndex(bg => bg.id === id)
58
+
59
+ // If group not found, return
60
+ if (index === -1) {
56
61
  return
57
62
  }
58
- const groups = [tobeDel]
59
- if (
60
- tobeDel.level !== 2 &&
61
- tobeDel.bookmarkGroupIds &&
62
- tobeDel.bookmarkGroupIds.length > 0
63
- ) {
64
- const childs = bookmarkGroups.filter(
65
- bg => tobeDel.bookmarkGroupIds.includes(bg.id)
63
+
64
+ const tobeDel = bookmarkGroups[index]
65
+
66
+ // Find parent group
67
+ let parentGroup = null
68
+ if (tobeDel.level === 2) {
69
+ parentGroup = bookmarkGroups.find(bg =>
70
+ (bg.bookmarkGroupIds || []).includes(tobeDel.id)
66
71
  )
67
- groups.push(...childs)
68
72
  }
69
- const groupIds = groups.map(g => g.id)
70
- const defaultCatIndex = tobeDel.level !== 2
71
- ? bookmarkGroups.findIndex(
72
- g => g.id === defaultBookmarkGroupId
73
- )
74
- : bookmarkGroups.findIndex(
75
- g => (g.bookmarkGroupIds || []).includes(tobeDel.id)
76
- )
77
- for (const g of groups) {
78
- if (g.bookmarkIds.length) {
79
- const def = bookmarkGroups[defaultCatIndex]
80
- def.bookmarkIds.push(...g.bookmarkIds)
81
- }
73
+
74
+ // If no parent found, use default group
75
+ if (!parentGroup) {
76
+ parentGroup = bookmarkGroups.find(bg => bg.id === defaultBookmarkGroupId)
77
+ }
78
+
79
+ // Ensure parent group has bookmarkIds and bookmarkGroupIds arrays
80
+ if (!parentGroup.bookmarkIds) {
81
+ parentGroup.bookmarkIds = []
82
+ }
83
+ if (!parentGroup.bookmarkGroupIds) {
84
+ parentGroup.bookmarkGroupIds = []
85
+ }
86
+
87
+ // Transfer bookmarkIds to parent
88
+ if (tobeDel.bookmarkIds && tobeDel.bookmarkIds.length) {
89
+ parentGroup.bookmarkIds = [
90
+ ...new Set([...parentGroup.bookmarkIds, ...tobeDel.bookmarkIds])
91
+ ]
82
92
  }
83
- bookmarkGroups = bookmarkGroups.filter(t => {
84
- return !groupIds.includes(t.id)
85
- })
93
+
94
+ // Transfer child groups to parent
95
+ if (tobeDel.bookmarkGroupIds && tobeDel.bookmarkGroupIds.length) {
96
+ parentGroup.bookmarkGroupIds = [
97
+ ...new Set([...parentGroup.bookmarkGroupIds, ...tobeDel.bookmarkGroupIds])
98
+ ]
99
+ }
100
+
101
+ // Remove the group from bookmarkGroups
102
+ bookmarkGroups.splice(index, 1)
103
+
104
+ // Reset current group if it was deleted
86
105
  if (id === store.currentBookmarkGroupId) {
87
- store.currentBookmarkGroupId = ''
106
+ store.currentBookmarkGroupId = parentGroup.id
88
107
  }
89
108
  })
90
109
 
@@ -15,6 +15,7 @@ import {
15
15
  import * as ls from '../common/safe-local-storage'
16
16
  import { refs, refsStatic } from '../components/common/ref'
17
17
  import { action } from 'manate'
18
+ import deepCopy from 'json-deep-copy'
18
19
 
19
20
  const e = window.translate
20
21
  const { assign } = Object
@@ -192,10 +193,11 @@ export default Store => {
192
193
  if (!profile || authType !== 'profiles') {
193
194
  return tab
194
195
  }
195
- const p = window.store.profiles.find(x => x.id === profile)
196
+ let p = window.store.profiles.find(x => x.id === profile)
196
197
  if (!p) {
197
198
  return tab
198
199
  }
200
+ p = deepCopy(p)
199
201
  // delete tab.password
200
202
  // delete tab.privateKey
201
203
  // delete tab.passphrase
@@ -279,4 +281,26 @@ export default Store => {
279
281
  Store.prototype.getLangNames = function () {
280
282
  return window.et.langs.map(d => d.name)
281
283
  }
284
+
285
+ Store.prototype.fixProfiles = function () {
286
+ const { profiles } = window.store
287
+ const len = profiles.length
288
+ let i = len - 1
289
+ for (;i >= 0; i--) {
290
+ const f = profiles[i]
291
+ if (f.name) {
292
+ continue
293
+ }
294
+ let count = 0
295
+ let id = 'PROFILE' + i
296
+ while (profiles.find(d => d.id === id)) {
297
+ count = count + 1
298
+ id = 'PROFILE' + count
299
+ }
300
+ const np = deepCopy(f)
301
+ np.id = id
302
+ np.name = id
303
+ profiles[i] = np
304
+ }
305
+ }
282
306
  }
@@ -194,6 +194,7 @@ export default (Store) => {
194
194
  ext.lastDataUpdateTime = await getData('lastDataUpdateTime') || 0
195
195
  Object.assign(store, ext)
196
196
  await store.fixBookmarkGroups()
197
+ await store.fixProfiles()
197
198
 
198
199
  store.checkDefaultTheme()
199
200
  store.loadFontList()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "1.60.29",
3
+ "version": "1.60.36",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",