@electerm/electerm-react 3.15.46 → 3.15.50

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.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Retry wrapper for dynamic import() calls
3
+ * Handles transient "Failed to fetch" errors that can occur
4
+ * when the app starts and chunks are fetched before the
5
+ * network/server is fully ready
6
+ */
7
+
8
+ const MAX_RETRIES = 3
9
+ const RETRY_DELAY = 500
10
+
11
+ function sleep (ms) {
12
+ return new Promise(resolve => setTimeout(resolve, ms))
13
+ }
14
+
15
+ export default function importRetry (factory, retries = MAX_RETRIES) {
16
+ return factory().catch(async (err) => {
17
+ if (retries <= 0) {
18
+ throw err
19
+ }
20
+ await sleep(RETRY_DELAY)
21
+ return importRetry(factory, retries - 1)
22
+ })
23
+ }
@@ -1,6 +1,7 @@
1
1
  import { lazy, Suspense } from 'react'
2
+ import importRetry from '../../common/import-retry'
2
3
 
3
- const AIChat = lazy(() => import('./ai-chat'))
4
+ const AIChat = lazy(() => importRetry(() => import('./ai-chat')))
4
5
 
5
6
  export default function AIChatEntry (props) {
6
7
  return (
@@ -28,6 +28,7 @@ import { FileTransferManager, createFileLogger } from './file-transfer'
28
28
  import { notification } from '../common/notification'
29
29
  import message from '../common/message'
30
30
  import ShowItem from '../common/show-item'
31
+ import importRetry from '../../common/import-retry'
31
32
  import './rdp.styl'
32
33
 
33
34
  const { Option } = Select
@@ -35,7 +36,7 @@ const { Option } = Select
35
36
  async function loadWasmModule () {
36
37
  if (window.ironRdp) return
37
38
  console.debug('[RDP-CLIENT] Loading IronRDP WASM module...')
38
- const mod = await import('ironrdp-wasm')
39
+ const mod = await importRetry(() => import('ironrdp-wasm'))
39
40
  window.ironRdp = {
40
41
  wasmInit: mod.default,
41
42
  wasmSetup: mod.setup,
@@ -11,13 +11,14 @@ import {
11
11
  settingMap,
12
12
  modals
13
13
  } from '../../common/constants'
14
+ import importRetry from '../../common/import-retry'
14
15
 
15
- const TabBookmarks = lazy(() => import('./tab-bookmarks'))
16
- const TabQuickCommands = lazy(() => import('./tab-quick-commands'))
17
- const TabSettings = lazy(() => import('./tab-settings'))
18
- const TabThemes = lazy(() => import('./tab-themes'))
19
- const TabProfiles = lazy(() => import('./tab-profiles'))
20
- const TabWidgets = lazy(() => import('./tab-widgets'))
16
+ const TabBookmarks = lazy(() => importRetry(() => import('./tab-bookmarks')))
17
+ const TabQuickCommands = lazy(() => importRetry(() => import('./tab-quick-commands')))
18
+ const TabSettings = lazy(() => importRetry(() => import('./tab-settings')))
19
+ const TabThemes = lazy(() => importRetry(() => import('./tab-themes')))
20
+ const TabProfiles = lazy(() => importRetry(() => import('./tab-profiles')))
21
+ const TabWidgets = lazy(() => importRetry(() => import('./tab-widgets')))
21
22
 
22
23
  const Loading = () => <div style={{ padding: 20, textAlign: 'center' }}><Spin /></div>
23
24
 
@@ -15,11 +15,12 @@ import {
15
15
  } from 'antd'
16
16
  import * as ls from '../../common/safe-local-storage'
17
17
  import RemoteFloatControl from '../common/remote-float-control'
18
+ import importRetry from '../../common/import-retry'
18
19
  import './spice.styl'
19
20
 
20
21
  async function loadSpiceModule () {
21
22
  if (window.spiceHtml5) return
22
- const mod = await import('spice-client')
23
+ const mod = await importRetry(() => import('spice-client'))
23
24
  window.spiceHtml5 = {
24
25
  SpiceMainConn: mod.SpiceMainConn,
25
26
  sendCtrlAltDel: mod.sendCtrlAltDel
@@ -1,3 +1,5 @@
1
+ import importRetry from '../../common/import-retry'
2
+
1
3
  window.xtermAddons = window.xtermAddons || {}
2
4
 
3
5
  let xtermCssLoaded = false
@@ -5,76 +7,76 @@ let xtermCssLoaded = false
5
7
  function loadXtermCss () {
6
8
  if (xtermCssLoaded) return
7
9
  xtermCssLoaded = true
8
- import('@xterm/xterm/css/xterm.css')
10
+ importRetry(() => import('@xterm/xterm/css/xterm.css'))
9
11
  }
10
12
 
11
13
  export async function loadTerminal () {
12
14
  if (window.xtermAddons.Terminal) return window.xtermAddons.Terminal
13
15
  loadXtermCss()
14
- const mod = await import('@xterm/xterm')
16
+ const mod = await importRetry(() => import('@xterm/xterm'))
15
17
  window.xtermAddons.Terminal = mod.Terminal
16
18
  return window.xtermAddons.Terminal
17
19
  }
18
20
 
19
21
  export async function loadFitAddon () {
20
22
  if (window.xtermAddons.FitAddon) return window.xtermAddons.FitAddon
21
- const mod = await import('@xterm/addon-fit')
23
+ const mod = await importRetry(() => import('@xterm/addon-fit'))
22
24
  window.xtermAddons.FitAddon = mod.FitAddon
23
25
  return window.xtermAddons.FitAddon
24
26
  }
25
27
 
26
28
  export async function loadAttachAddon () {
27
29
  if (window.xtermAddons.AttachAddon) return window.xtermAddons.AttachAddon
28
- const mod = await import('@xterm/addon-attach')
30
+ const mod = await importRetry(() => import('@xterm/addon-attach'))
29
31
  window.xtermAddons.AttachAddon = mod.AttachAddon
30
32
  return window.xtermAddons.AttachAddon
31
33
  }
32
34
 
33
35
  export async function loadWebLinksAddon () {
34
36
  if (window.xtermAddons.WebLinksAddon) return window.xtermAddons.WebLinksAddon
35
- const mod = await import('@xterm/addon-web-links')
37
+ const mod = await importRetry(() => import('@xterm/addon-web-links'))
36
38
  window.xtermAddons.WebLinksAddon = mod.WebLinksAddon
37
39
  return window.xtermAddons.WebLinksAddon
38
40
  }
39
41
 
40
42
  export async function loadCanvasAddon () {
41
43
  if (window.xtermAddons.CanvasAddon) return window.xtermAddons.CanvasAddon
42
- const mod = await import('@xterm/addon-canvas')
44
+ const mod = await importRetry(() => import('@xterm/addon-canvas'))
43
45
  window.xtermAddons.CanvasAddon = mod.CanvasAddon
44
46
  return window.xtermAddons.CanvasAddon
45
47
  }
46
48
 
47
49
  export async function loadWebglAddon () {
48
50
  if (window.xtermAddons.WebglAddon) return window.xtermAddons.WebglAddon
49
- const mod = await import('@xterm/addon-webgl')
51
+ const mod = await importRetry(() => import('@xterm/addon-webgl'))
50
52
  window.xtermAddons.WebglAddon = mod.WebglAddon
51
53
  return window.xtermAddons.WebglAddon
52
54
  }
53
55
 
54
56
  export async function loadSearchAddon () {
55
57
  if (window.xtermAddons.SearchAddon) return window.xtermAddons.SearchAddon
56
- const mod = await import('@xterm/addon-search')
58
+ const mod = await importRetry(() => import('@xterm/addon-search'))
57
59
  window.xtermAddons.SearchAddon = mod.SearchAddon
58
60
  return window.xtermAddons.SearchAddon
59
61
  }
60
62
 
61
63
  export async function loadLigaturesAddon () {
62
64
  if (window.xtermAddons.LigaturesAddon) return window.xtermAddons.LigaturesAddon
63
- const mod = await import('@xterm/addon-ligatures')
65
+ const mod = await importRetry(() => import('@xterm/addon-ligatures'))
64
66
  window.xtermAddons.LigaturesAddon = mod.LigaturesAddon
65
67
  return window.xtermAddons.LigaturesAddon
66
68
  }
67
69
 
68
70
  export async function loadUnicode11Addon () {
69
71
  if (window.xtermAddons.Unicode11Addon) return window.xtermAddons.Unicode11Addon
70
- const mod = await import('@xterm/addon-unicode11')
72
+ const mod = await importRetry(() => import('@xterm/addon-unicode11'))
71
73
  window.xtermAddons.Unicode11Addon = mod.Unicode11Addon
72
74
  return window.xtermAddons.Unicode11Addon
73
75
  }
74
76
 
75
77
  export async function loadImageAddon () {
76
78
  if (window.xtermAddons.ImageAddon) return window.xtermAddons.ImageAddon
77
- const mod = await import('@xterm/addon-image')
79
+ const mod = await importRetry(() => import('@xterm/addon-image'))
78
80
  window.xtermAddons.ImageAddon = mod.ImageAddon
79
81
  return window.xtermAddons.ImageAddon
80
82
  }
@@ -1,6 +1,7 @@
1
1
  import { lazy, Suspense } from 'react'
2
+ import importRetry from '../../common/import-retry'
2
3
 
3
- const TerminalInfo = lazy(() => import('./terminal-info'))
4
+ const TerminalInfo = lazy(() => importRetry(() => import('./terminal-info')))
4
5
 
5
6
  export default function TerminalInfoEntry (props) {
6
7
  return (
@@ -1,6 +1,7 @@
1
1
  import { lazy, Suspense } from 'react'
2
+ import importRetry from '../../common/import-retry'
2
3
 
3
- const TextEditor = lazy(() => import('./text-editor'))
4
+ const TextEditor = lazy(() => importRetry(() => import('./text-editor')))
4
5
 
5
6
  export default function TextEditorEntry (props) {
6
7
  return (
@@ -18,13 +18,14 @@ import Modal from '../common/modal'
18
18
  import { copy } from '../../common/clipboard'
19
19
  import VncForm from './vnc-form'
20
20
  import RemoteFloatControl from '../common/remote-float-control'
21
+ import importRetry from '../../common/import-retry'
21
22
  import './vnc.styl'
22
23
 
23
24
  // noVNC module imports — loaded dynamically
24
25
  async function loadVncModule () {
25
26
  if (window.novnc) return
26
27
  console.debug('[VNC-CLIENT] Loading noVNC module...')
27
- const mod = await import('@novnc/novnc/core/rfb')
28
+ const mod = await importRetry(() => import('@novnc/novnc/core/rfb'))
28
29
  window.novnc = {
29
30
  RFB: mod.default
30
31
  }
@@ -21,51 +21,45 @@ import dataCompare from '../common/data-compare'
21
21
 
22
22
  export default store => {
23
23
  for (const name of dbNamesForWatch) {
24
- window[`watch${name}Running`] = false
25
24
  window[`watch${name}`] = autoRun(async () => {
26
25
  const n = store.getItems(name)
27
- if (window.migrating || window[`watch${name}Running`]) {
26
+ if (window.migrating) {
28
27
  return
29
28
  }
30
- window[`watch${name}Running`] = true
31
- try {
32
- const old = refsStatic.get('oldState-' + name)
33
- const { updated, added, removed } = dataCompare(
34
- old,
35
- n
29
+ const old = refsStatic.get('oldState-' + name)
30
+ const { updated, added, removed } = dataCompare(
31
+ old,
32
+ n
33
+ )
34
+ await Promise.all([
35
+ ...removed.map(item => remove(name, item.id)),
36
+ ...updated.map(item => update(item.id, item, name, false)),
37
+ added.length ? insert(name, added) : Promise.resolve()
38
+ ])
39
+ const newOrder = (n || []).map(d => d.id)
40
+ await update(
41
+ `${name}:order`,
42
+ newOrder
43
+ )
44
+ refsStatic.add('oldState-' + name, deepCopy(n) || [])
45
+ if (name === 'bookmarks') {
46
+ store.bookmarksMap = new Map(
47
+ n.map(d => [d.id, d])
36
48
  )
37
- await Promise.all([
38
- ...removed.map(item => remove(name, item.id)),
39
- ...updated.map(item => update(item.id, item, name, false)),
40
- added.length ? insert(name, added) : Promise.resolve()
41
- ])
42
- const newOrder = (n || []).map(d => d.id)
43
- await update(
44
- `${name}:order`,
45
- newOrder
46
- )
47
- refsStatic.add('oldState-' + name, deepCopy(n) || [])
48
- if (name === 'bookmarks') {
49
- store.bookmarksMap = new Map(
50
- n.map(d => [d.id, d])
51
- )
52
- }
53
- await store.updateLastDataUpdateTime()
54
- if (dbNamesForSync.includes(name)) {
55
- const syncSetting = store.config.syncSetting || {}
56
- const { autoSync, autoSyncInterval, autoSyncDirection } = syncSetting
57
- if (autoSync && autoSyncInterval === 0) {
58
- if (autoSyncDirection === 'download') {
59
- await store.downloadSettingAll()
60
- } else {
61
- await store.uploadSettingAll()
62
- }
49
+ }
50
+ await store.updateLastDataUpdateTime()
51
+ if (dbNamesForSync.includes(name)) {
52
+ const syncSetting = store.config.syncSetting || {}
53
+ const { autoSync, autoSyncInterval, autoSyncDirection } = syncSetting
54
+ if (autoSync && autoSyncInterval === 0) {
55
+ if (autoSyncDirection === 'download') {
56
+ await store.downloadSettingAll()
57
+ } else {
58
+ await store.uploadSettingAll()
63
59
  }
64
60
  }
65
- return store[name]
66
- } finally {
67
- window[`watch${name}Running`] = false
68
61
  }
62
+ return store[name]
69
63
  })
70
64
  window[`watch${name}`].start()
71
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "3.15.46",
3
+ "version": "3.15.50",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",