@electerm/electerm-react 5.1.25 → 5.2.0

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.
Files changed (32) hide show
  1. package/client/common/build-map.js +12 -0
  2. package/client/common/db.js +7 -5
  3. package/client/common/import-task.js +174 -0
  4. package/client/components/bookmark-form/ai-bookmark-form.jsx +18 -15
  5. package/client/components/bookmark-form/common/bookmark-select.jsx +6 -5
  6. package/client/components/bookmark-form/common/fields.jsx +1 -1
  7. package/client/components/bookmark-form/common/profile-item.jsx +12 -2
  8. package/client/components/bookmark-form/config/rdp.js +1 -1
  9. package/client/components/bookmark-form/tree-select.jsx +5 -16
  10. package/client/components/common/import-progress.jsx +90 -0
  11. package/client/components/main/main.jsx +2 -0
  12. package/client/components/profile/profile-form-rdp.jsx +1 -1
  13. package/client/components/quick-commands/quick-command-transport-mod.jsx +24 -18
  14. package/client/components/rdp/rdp-cred-form.jsx +55 -0
  15. package/client/components/rdp/rdp-session.jsx +97 -6
  16. package/client/components/setting-panel/keywords-transport.jsx +1 -4
  17. package/client/components/setting-panel/setting-modal.jsx +8 -2
  18. package/client/components/setting-panel/start-session-select.jsx +5 -16
  19. package/client/components/spice/spice-session.jsx +40 -0
  20. package/client/components/terminal/terminal-color-query.mjs +32 -27
  21. package/client/components/terminal/terminal.jsx +13 -9
  22. package/client/components/tree-list/bookmark-transport.jsx +2 -1
  23. package/client/components/tree-list/bookmark-upload.js +56 -41
  24. package/client/components/tree-list/tree-list-row.jsx +11 -4
  25. package/client/components/tree-list/tree-list-rows.js +6 -3
  26. package/client/components/tree-list/tree-list.jsx +4 -2
  27. package/client/store/common.js +19 -1
  28. package/client/store/load-data.js +6 -1
  29. package/client/store/store.js +3 -12
  30. package/client/store/sync.js +31 -2
  31. package/client/store/watch.js +10 -1
  32. package/package.json +1 -1
@@ -193,7 +193,13 @@ export default Store => {
193
193
  type,
194
194
  authType
195
195
  } = tab
196
- if (!profile || authType !== 'profiles') {
196
+ // SSH picks auth type explicitly (password/privateKey/profiles radio),
197
+ // other types only have the profile dropdown, so a selected profile
198
+ // always means profile auth for them
199
+ const useProfile = type === connectionMap.ssh
200
+ ? authType === 'profiles'
201
+ : true
202
+ if (!profile || !useProfile) {
197
203
  return tab
198
204
  }
199
205
  let p = window.store.profiles.find(x => x.id === profile)
@@ -224,10 +230,17 @@ export default Store => {
224
230
  ...tab,
225
231
  ...filtered
226
232
  }
233
+ } else if (type === connectionMap.ftp) {
234
+ const filtered = pickBy(p.ftp, (value) => value !== undefined && value !== '')
235
+ return {
236
+ ...tab,
237
+ ...filtered
238
+ }
227
239
  }
228
240
  delete p.rdp
229
241
  delete p.vnc
230
242
  delete p.telnet
243
+ delete p.ftp
231
244
  const filtered = pickBy(p, (value) => value !== undefined && value !== '')
232
245
  return {
233
246
  ...tab,
@@ -455,6 +468,11 @@ export default Store => {
455
468
  let i = len - 1
456
469
  for (;i >= 0; i--) {
457
470
  const f = profiles[i]
471
+ // migrate old rdp profile key userName -> username
472
+ if (f.rdp?.userName !== undefined) {
473
+ f.rdp.username = f.rdp.userName
474
+ delete f.rdp.userName
475
+ }
458
476
  if (f.name) {
459
477
  continue
460
478
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import { dbNames, getData, fetchInitData } from '../common/db'
6
+ import deepCopy from 'json-deep-copy'
6
7
  import parseInt10 from '../common/parse-int10'
7
8
  import { infoTabs, statusMap, defaultEnvLang } from '../common/constants'
8
9
  import generate from '../common/id-with-stamp'
@@ -237,7 +238,11 @@ export default (Store) => {
237
238
  .then(arr => {
238
239
  for (const { name, data } of arr) {
239
240
  const dt = JSON.parse(data || '[]')
240
- refsStatic.add('oldState-' + name, dt)
241
+ // seed the watcher snapshot with a *copy* - manate wraps the exact
242
+ // array assigned into the store, so seeding with `dt` itself would
243
+ // alias snapshot and store to one backing array; the watcher's
244
+ // no-change early-return would then skip DB writes forever
245
+ refsStatic.add('oldState-' + name, deepCopy(dt))
241
246
  if (name === 'bookmarks') {
242
247
  ext.bookmarksMap = new Map(
243
248
  dt.map(d => [d.id, d])
@@ -42,6 +42,7 @@ import {
42
42
  } from '../common/constants'
43
43
  import getInitItem from '../common/init-setting-item'
44
44
  import createTitle from '../common/create-title'
45
+ import buildMap from '../common/build-map'
45
46
  import {
46
47
  theme
47
48
  } from 'antd'
@@ -278,12 +279,7 @@ class Store {
278
279
  const {
279
280
  bookmarks
280
281
  } = window.store
281
- return bookmarks.reduce((p, v) => {
282
- return {
283
- ...p,
284
- [v.id]: v
285
- }
286
- }, {})
282
+ return buildMap(bookmarks)
287
283
  }
288
284
 
289
285
  hasSshConfig () {
@@ -296,12 +292,7 @@ class Store {
296
292
  const {
297
293
  bookmarkGroups
298
294
  } = window.store
299
- return bookmarkGroups.reduce((p, v) => {
300
- return {
301
- ...p,
302
- [v.id]: v
303
- }
304
- }, {})
295
+ return buildMap(bookmarkGroups)
305
296
  }
306
297
 
307
298
  get hasOldConnectionHoppingBookmark () {
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { get, pick, debounce } from 'lodash-es'
6
6
  import copy from 'json-deep-copy'
7
+ import { action } from 'manate'
7
8
  import {
8
9
  settingMap, packInfo, syncTypes, syncDataMaps
9
10
  } from '../common/constants'
@@ -13,6 +14,9 @@ import download from '../common/download'
13
14
  import { fixBookmarks } from '../common/db-fix'
14
15
  import dayjs from 'dayjs'
15
16
  import parseJsonSafe from '../common/parse-json-safe'
17
+ import { runImportTask } from '../common/import-task'
18
+
19
+ const e = window.translate
16
20
 
17
21
  const {
18
22
  version: packVer
@@ -694,15 +698,40 @@ export default (Store) => {
694
698
  const { store } = window
695
699
  const objs = JSON.parse(txt)
696
700
  const { names } = store.getDataSyncNames(true)
701
+ const fixed = {}
697
702
  for (const n of names) {
698
- let arr = objs[n]
703
+ let arr = objs[n] || []
699
704
  if (n === settingMap.terminalThemes) {
700
705
  arr = store.fixThemes(arr)
701
706
  } else if (n === settingMap.bookmarks) {
702
707
  arr = fixBookmarks(arr)
703
708
  }
704
- store.setItems(n, objs[n])
709
+ fixed[n] = arr
705
710
  }
711
+ // clear all targets first - importAll replaces data sets, not appends.
712
+ // watchers are stopped inside runImportTask, so this is silent until restart
713
+ action(() => {
714
+ for (const n of names) {
715
+ store.setItems(n, [])
716
+ }
717
+ })()
718
+ await runImportTask({
719
+ title: e('import'),
720
+ batch: 200,
721
+ stopWatchers: names,
722
+ // one chunked step per data set (bookmarks, groups, themes, ...),
723
+ // so the progress bar advances per batch instead of per data set
724
+ steps: names.map((n) => {
725
+ const arr = fixed[n]
726
+ return {
727
+ label: n,
728
+ items: arr,
729
+ process: (chunk) => {
730
+ store[n].push(...chunk)
731
+ }
732
+ }
733
+ })
734
+ })
706
735
  store.updateConfig(stripServerManagedKeys(objs.config))
707
736
  if (objs.config?.theme) {
708
737
  store.setTheme(objs.config.theme)
@@ -31,6 +31,16 @@ export default store => {
31
31
  old,
32
32
  n
33
33
  )
34
+ const newOrder = (n || []).map(d => d.id)
35
+ // with large collections (thousands of bookmarks) this autoRun fires
36
+ // often; when neither content nor order changed, skip the deep-copy
37
+ // snapshot and the DB writes entirely
38
+ const orderChanged = !old ||
39
+ old.length !== (n || []).length ||
40
+ old.some((d, i) => d.id !== newOrder[i])
41
+ if (!updated.length && !added.length && !removed.length && !orderChanged) {
42
+ return store[name]
43
+ }
34
44
  // Update snapshot immediately before async DB writes to prevent
35
45
  // race conditions: a second autoRun firing before the first
36
46
  // completes would see stale oldState and re-insert the same items,
@@ -41,7 +51,6 @@ export default store => {
41
51
  ...updated.map(item => update(item.id, item, name, false)),
42
52
  added.length ? insert(name, added) : Promise.resolve()
43
53
  ])
44
- const newOrder = (n || []).map(d => d.id)
45
54
  await update(
46
55
  `${name}:order`,
47
56
  newOrder
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "5.1.25",
3
+ "version": "5.2.0",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",