@electerm/electerm-react 2.2.0 → 2.3.6

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.
@@ -30,7 +30,7 @@ export default function SerialPathSelector ({
30
30
  />
31
31
  </FormItem>
32
32
  <Spin spinning={loaddingSerials}>
33
- <span onClick={store.handleGetSerials}>
33
+ <span onClick={store.handleGetSerials} className='pointer'>
34
34
  <ReloadOutlined /> {e('reload')} serials
35
35
  </span>
36
36
  </Spin>
@@ -0,0 +1,66 @@
1
+ import { useEffect } from 'react'
2
+ import { useDelta, useConditionalEffect } from 'react-delta-hooks'
3
+ import eq from 'fast-deep-equal'
4
+
5
+ const opacityDomId = 'opacity-style'
6
+
7
+ /**
8
+ * Opacity component
9
+ * Handles conditional CSS rendering based on opacity setting
10
+ * @param {Object} props
11
+ * @param {number} props.opacity - Opacity value from store.config
12
+ * @returns {null}
13
+ */
14
+ export default function Opacity ({ opacity }) {
15
+ // Default to 1 if opacity is not provided
16
+ const currentOpacity = opacity !== undefined ? opacity : 1
17
+ const delta = useDelta(currentOpacity)
18
+
19
+ function applyOpacity () {
20
+ let styleElement = document.getElementById(opacityDomId)
21
+
22
+ // Create style element if it doesn't exist
23
+ if (!styleElement) {
24
+ styleElement = document.createElement('style')
25
+ styleElement.id = opacityDomId
26
+ document.head.appendChild(styleElement)
27
+ }
28
+
29
+ // Update style content based on opacity value
30
+ if (currentOpacity === 1) {
31
+ styleElement.innerHTML = ''
32
+ window.pre.runGlobalAsync('setBackgroundColor', '#333333')
33
+ } else {
34
+ window.pre.runGlobalAsync('setBackgroundColor', '#33333300')
35
+ styleElement.innerHTML = `
36
+ html {
37
+ background: transparent !important;
38
+ }
39
+ body {
40
+ background: transparent !important;
41
+ }
42
+ #outside-context {
43
+ opacity: ${currentOpacity} !important;
44
+ }
45
+ `
46
+ }
47
+ }
48
+
49
+ useEffect(() => {
50
+ applyOpacity()
51
+
52
+ // Cleanup function
53
+ return () => {
54
+ const styleElement = document.getElementById(opacityDomId)
55
+ if (styleElement) {
56
+ document.head.removeChild(styleElement)
57
+ }
58
+ }
59
+ }, [])
60
+
61
+ useConditionalEffect(() => {
62
+ applyOpacity()
63
+ }, delta && !eq(delta.prev, delta.curr))
64
+
65
+ return null
66
+ }
@@ -17,7 +17,7 @@
17
17
  overflow-y scroll
18
18
  z-index 11
19
19
  background main
20
- box-shadow 0px 0px 3px 3px alpha(main, .5)
20
+
21
21
  .transports-wrap
22
22
  .transports-dd
23
23
  display none
@@ -28,6 +28,7 @@ import ConnectionHoppingWarning from './connection-hopping-warnning'
28
28
  import SshConfigLoadNotify from '../ssh-config/ssh-config-load-notify'
29
29
  import LoadSshConfigs from '../ssh-config/load-ssh-configs'
30
30
  import AIChat from '../ai/ai-chat'
31
+ import Opacity from '../common/opacity'
31
32
  import { pick } from 'lodash-es'
32
33
  import deepCopy from 'json-deep-copy'
33
34
  import './wrapper.styl'
@@ -152,11 +153,6 @@ export default auto(function Index (props) {
152
153
  const themeProps = {
153
154
  themeConfig: store.getUiThemeConfig()
154
155
  }
155
- const outerProps = {
156
- style: {
157
- opacity: config.opacity
158
- }
159
- }
160
156
  const copiedTransfer = deepCopy(fileTransfers)
161
157
  const copiedHistory = deepCopy(transferHistory)
162
158
  const sidebarProps = {
@@ -260,6 +256,7 @@ export default auto(function Index (props) {
260
256
  {...confsCss}
261
257
  wsInited={wsInited}
262
258
  />
259
+ <Opacity opacity={config.opacity} />
263
260
  <TerminalInteractive />
264
261
  <UiTheme
265
262
  {...themeProps}
@@ -277,7 +274,6 @@ export default auto(function Index (props) {
277
274
  <BatchOp {...batchOpProps} />
278
275
  <div
279
276
  id='outside-context'
280
- {...outerProps}
281
277
  >
282
278
  <Sidebar {...sidebarProps} />
283
279
  <Layout
@@ -13,7 +13,7 @@
13
13
  top 10px
14
14
  position fixed
15
15
  z-index 100
16
- background rgba(45, 245, 108, 0.8)
16
+ background #2df56c
17
17
  // Hide all sessions first
18
18
  .session-wrap
19
19
  display none
@@ -42,7 +42,7 @@
42
42
  &::before
43
43
  font-size 30vmin
44
44
  font-weight bold
45
- color alpha(text, 0.15)
45
+ color lighten(text, 15%)
46
46
  display flex
47
47
  justify-content center
48
48
  align-items center
@@ -21,12 +21,11 @@
21
21
  .fil-keyword
22
22
  .fil-label
23
23
  .qm-item
24
- opacity .4
24
+ color lighten(text, 30%)
25
25
  .qm-item
26
26
  &.name-match
27
27
  &.label-match
28
28
  font-weight bold
29
- opacity 1
30
29
  @media (max-width: 500px)
31
30
  .qm-search-input
32
31
  width 100px
@@ -55,7 +55,7 @@
55
55
  overflow hidden
56
56
  z-index 3
57
57
  padding-top 36px
58
- box-shadow 0px 0px 1px 1px alpha(main, .3)
58
+ box-shadow 0px 0px 1px 1px lighten(main, 20%)
59
59
  &.session-batch-active
60
60
  display block
61
61
 
@@ -27,7 +27,7 @@ import fs from '../../common/fs'
27
27
  import ListTable from './list-table-ui'
28
28
  import deepCopy from 'json-deep-copy'
29
29
  import isValidPath from '../../common/is-valid-path'
30
- import memoizeOne from 'memoize-one'
30
+
31
31
  import * as owner from './owner-list'
32
32
  import AddressBar from './address-bar'
33
33
  import getProxy from '../../common/get-proxy'
@@ -101,6 +101,9 @@ export default class Sftp extends Component {
101
101
  this.timer4 = null
102
102
  clearTimeout(this.timer5)
103
103
  this.timer5 = null
104
+ // Clear sort cache to prevent memory leaks
105
+ this._sortCache?.clear()
106
+ this._lastSortArgs = null
104
107
  }
105
108
 
106
109
  initFtpData = async () => {
@@ -167,19 +170,36 @@ export default class Sftp extends Component {
167
170
  }, {})
168
171
  }
169
172
 
170
- sort = memoizeOne((
171
- list,
172
- type,
173
- sortDirection,
174
- sortProp
175
- ) => {
173
+ // Cache for memoized sort results
174
+ _sortCache = new Map()
175
+ _lastSortArgs = null
176
+
177
+ sort = (list, type, sortDirection, sortProp) => {
178
+ // Create a cache key from the arguments
179
+ const cacheKey = JSON.stringify({
180
+ listLength: list?.length || 0,
181
+ listHash: this._hashList(list),
182
+ type,
183
+ sortDirection,
184
+ sortProp
185
+ })
186
+
187
+ // Check if we have a cached result and if args haven't changed
188
+ if (this._lastSortArgs && isEqual(this._lastSortArgs, [list, type, sortDirection, sortProp])) {
189
+ const cached = this._sortCache.get(cacheKey)
190
+ if (cached) {
191
+ return cached
192
+ }
193
+ }
194
+
195
+ // Compute the result
176
196
  if (!list || !list.length) {
177
197
  return []
178
198
  }
179
199
 
180
200
  const isDesc = sortDirection === 'desc'
181
201
 
182
- return list.slice().sort((a, b) => {
202
+ const result = list.slice().sort((a, b) => {
183
203
  // Handle items with no id first
184
204
  if (!a.id && b.id) return -1
185
205
  if (a.id && !b.id) return 1
@@ -207,7 +227,28 @@ export default class Sftp extends Component {
207
227
  if (aValue > bValue) return isDesc ? -1 : 1
208
228
  return 0
209
229
  })
210
- }, isEqual)
230
+
231
+ // Cache the result
232
+ this._lastSortArgs = [list, type, sortDirection, sortProp]
233
+ this._sortCache.set(cacheKey, result)
234
+
235
+ // Limit cache size to prevent memory leaks
236
+ if (this._sortCache.size > 10) {
237
+ const firstKey = this._sortCache.keys().next().value
238
+ this._sortCache.delete(firstKey)
239
+ }
240
+
241
+ return result
242
+ }
243
+
244
+ // Helper method to create a simple hash of the list for cache key
245
+ _hashList = (list) => {
246
+ if (!list || !list.length) return 0
247
+ return list.reduce((hash, item, index) => {
248
+ const str = `${item.id || ''}${item.name || ''}${item.modifyTime || ''}${index}`
249
+ return hash + str.length
250
+ }, 0)
251
+ }
211
252
 
212
253
  isActive () {
213
254
  const { currentBatchTabId, pane, sshSftpSplitView } = this.props
@@ -41,7 +41,7 @@
41
41
  &.focused
42
42
  height auto
43
43
  border 1px solid main-dark
44
- box-shadow 0px 0px 3px 3px alpha(main, .05)
44
+ box-shadow 0px 0px 3px 3px lighten(main, 5%)
45
45
 
46
46
  .sftp-history-item
47
47
  padding 5px 10px
@@ -72,7 +72,6 @@
72
72
  top 0
73
73
  z-index 1
74
74
  height 100%
75
- opacity 0
76
75
  padding 0
77
76
  margin 0
78
77
 
@@ -86,13 +85,6 @@
86
85
  width 100%
87
86
  .file-props
88
87
  margin-left 70px
89
- .opacity-loop
90
- opacity 0.3
91
- animation blinker 5s linear infinite
92
-
93
- @keyframes blinker
94
- 50%
95
- opacity .8
96
88
 
97
89
  .sftp-sort-btn
98
90
  color text
@@ -2,23 +2,22 @@
2
2
 
3
3
  // from https://freefrontend.com/css-border-animations/
4
4
  .morph-shape
5
- background linear-gradient(45deg, primary 0%, success 100%)
6
- animation morph 8s ease-in-out infinite
5
+ background linear-gradient(45deg, #08c 0%, #09c 100%)
7
6
  border-radius 60% 40% 30% 70% / 60% 30% 70% 40%
8
7
  transition all 1s ease-in-out
9
8
  z-index 5
10
9
 
11
- @keyframes morph
12
- 0%
13
- border-radius 60% 40% 30% 70% / 60% 30% 70% 40%
14
- background linear-gradient(45deg, primary 0%, success 100%)
15
- 50%
16
- border-radius 30% 60% 70% 40% / 50% 60% 30% 60%
17
- background linear-gradient(45deg, main 0%, success 100%)
10
+ // @keyframes morph
11
+ // 0%
12
+ // border-radius 60% 40% 30% 70% / 60% 30% 70% 40%
13
+ // background linear-gradient(45deg, primary 0%, success 100%)
14
+ // 50%
15
+ // border-radius 30% 60% 70% 40% / 50% 60% 30% 60%
16
+ // background linear-gradient(45deg, main 0%, success 100%)
18
17
 
19
- 100%
20
- border-radius 60% 40% 30% 70% / 60% 30% 70% 40%
21
- background linear-gradient(45deg, primary 0%, success 100%)
18
+ // 100%
19
+ // border-radius 60% 40% 30% 70% / 60% 30% 70% 40%
20
+ // background linear-gradient(45deg, primary 0%, success 100%)
22
21
  .info-modal
23
22
  .ant-modal-header
24
23
  border none
@@ -23,7 +23,7 @@
23
23
  z-index 100
24
24
  bottom 0
25
25
  background main-dark
26
- box-shadow 0px 0px 3px 3px alpha(main, .1)
26
+
27
27
  .item-list
28
28
  padding-right 0
29
29
  .sidebar-pin-top
@@ -73,7 +73,6 @@
73
73
  bottom 0
74
74
  z-index 200
75
75
  width 0
76
- border-right 1px solid darken(main, 30%)
77
76
 
78
77
  .pinned
79
78
  .sidebar-list
@@ -15,7 +15,7 @@
15
15
  color #eee
16
16
  cursor pointer
17
17
  &.disabled
18
- color alpha(text, .85)
18
+ color lighten(text, 15%)
19
19
  &:hover
20
20
  color #777
21
21
  background #333
@@ -30,7 +30,7 @@
30
30
  position absolute
31
31
  right 16px
32
32
  top 0
33
- opacity .65
33
+ color lighten(text, 20%)
34
34
 
35
35
  .context-menu
36
36
  hr
@@ -44,7 +44,7 @@
44
44
  left 100%
45
45
  top 0
46
46
  background main
47
- box-shadow 0px 0px 3px 3px alpha(main, .35)
47
+ box-shadow 0px 0px 3px 3px lighten(main, 35%)
48
48
  max-height 300px
49
49
  overflow-y scroll
50
50
  .with-sub-menu
@@ -68,15 +68,14 @@
68
68
  width 28px
69
69
  height 28px
70
70
  border-radius 30px
71
- color text
71
+ color lighten(text, 20%)
72
72
  font-size 16px
73
73
  text-align center
74
74
  display inline-block
75
75
  line-height 28px
76
76
  cursor pointer
77
- opacity .6
78
77
  &:hover
79
- opacity 1
78
+ color text
80
79
  .is-main
81
80
  .menu-control
82
81
  img
@@ -71,11 +71,11 @@
71
71
  color text-light
72
72
  @keyframes blink
73
73
  0%
74
- opacity 0.3
74
+ background-color #e0e0e0
75
75
  50%
76
- opacity 1
76
+ background-color #ffffff
77
77
  100%
78
- opacity 0.3
78
+ background-color #e0e0e0
79
79
 
80
80
  .tab-terminal-feed
81
81
  .tab-traffic
@@ -96,6 +96,7 @@
96
96
  .is-transporting .tab-traffic
97
97
  display block
98
98
  animation blink 2s infinite
99
+ /* Remove opacity animation, use background-color */
99
100
  .tab-traffic
100
101
  display none
101
102
  left 10px
@@ -105,6 +106,7 @@
105
106
  .is-terminal-active .tab-terminal-feed
106
107
  display block
107
108
  animation blink 2s infinite
109
+ /* Remove opacity animation, use background-color */
108
110
  .tab-terminal-feed
109
111
  display none
110
112
  left 20px
@@ -217,7 +219,7 @@
217
219
  margin-right 5px
218
220
  font-size 14px
219
221
  .no-sessions
220
- background main-dark
222
+ background main
221
223
  text-align center
222
224
  padding 50px 0
223
225
  position absolute
@@ -231,7 +233,6 @@
231
233
  padding 0 4px
232
234
  height 20px
233
235
  line-height 21px
234
- opacity 0.8
235
236
  .no-session-history
236
237
  position absolute
237
238
  top 280px
@@ -26,7 +26,7 @@ export default function SearchResultBar ({
26
26
  ctx.clearRect(0, 0, canvas.width, canvas.height)
27
27
  matches.forEach((match, index) => {
28
28
  const y = (match / totalLines) * containerHeight
29
- ctx.fillStyle = index === matchIndex ? 'rgba(243, 67, 9, 0.5)' : 'rgba(243, 196, 9, 0.5)'
29
+ ctx.fillStyle = index === matchIndex ? '#f34309' : '#f3c409'
30
30
  ctx.fillRect(0, y, 16, 2)
31
31
  })
32
32
  }
@@ -41,11 +41,7 @@
41
41
  height 100%
42
42
  background-repeat no-repeat
43
43
  background-position center
44
- background-color: transparent !important
45
-
46
-
47
- .terminal-not-active .xterm-text-layer
48
- opacity .74
44
+ background-color transparent !important
49
45
 
50
46
  .terminal-normal-buffer
51
47
  position absolute
@@ -54,7 +50,7 @@
54
50
  width 100%
55
51
  background main
56
52
  color text
57
- box-shadow 0px 3px 3px 0px alpha(text, .25)
53
+ box-shadow 0px 3px 3px 0px lighten(main, 25%)
58
54
  z-index 66
59
55
  padding-bottom 32px
60
56
  .terminal-normal-buffer-body
@@ -73,7 +69,7 @@
73
69
  width 100%
74
70
  height 32px
75
71
  line-height 32px
76
- box-shadow 0px -3px 3px 0px alpha(text, .25)
72
+ box-shadow 0px -3px 3px 0px lighten(main, 25%)
77
73
  background main-light
78
74
  .batch-input-wrap
79
75
  width calc(100% - 80px)
@@ -128,9 +124,9 @@
128
124
  .suggestion-type
129
125
  margin-left 5px
130
126
  font-size 0.8em
131
- opacity .8
127
+ color lighten(text, 20%)
132
128
  &:hover
133
- opacity 1
129
+ color text
134
130
 
135
131
  .suggestion-delete
136
132
  margin-left 5px
@@ -16,7 +16,7 @@
16
16
  color text
17
17
  z-index 100
18
18
  overflow-y scroll
19
- opacity .9
19
+
20
20
  .drag-handle
21
21
  left 0
22
22
  right auto
@@ -75,5 +75,5 @@
75
75
  height 12px
76
76
  margin-right 6px
77
77
  border-radius 2px
78
- border 1px solid rgba(0,0,0,0.1)
78
+ border 1px solid #1a1a1a
79
79
  vertical-align middle
@@ -2,20 +2,17 @@
2
2
  @require './antd-overwrite'
3
3
  @require './includes/theme-default'
4
4
 
5
- html
6
- background rgba(0,0,0,.01)
7
-
8
5
  body
9
6
  color text
10
7
  overflow hidden
11
- background alpha(main, .3)
8
+ background main
12
9
  font-size 12px
13
10
  line-height 1.5715
14
11
  font-family -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'
15
12
  font-variant: tabular-nums
16
13
 
17
14
  ::-webkit-scrollbar
18
- background alpha(main, .5)
15
+ background transparent
19
16
  width 7px
20
17
 
21
18
  .term-wrap:hover
@@ -16,7 +16,6 @@ html
16
16
  top: 0;
17
17
  width: 100%;
18
18
  height: 100%;
19
- background: #141314 50% 50% no-repeat url("./images/electerm-watermark.png");
20
19
  display: flex;
21
20
  flex-direction: column;
22
21
  justify-content: center;
@@ -25,6 +24,14 @@ html
25
24
  .electerm-logo-bg {
26
25
  background: transparent 50% 50% no-repeat url("./images/electerm-watermark.png");
27
26
  }
27
+ .morph-shape {
28
+ background: linear-gradient(45deg, #08c 0%, #09c 100%);
29
+ animation: morph 8s ease-in-out infinite;
30
+ border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%;
31
+ transition: all 1s ease-in-out;
32
+ z-index: 5;
33
+ }
34
+
28
35
  - if (!isDev)
29
36
  link(rel='stylesheet', href='css/' + version + '-basic.css')
30
37
  link(rel='stylesheet', href='css/' + version + '-electerm.css')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "2.2.0",
3
+ "version": "2.3.6",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",
@@ -1,14 +0,0 @@
1
- @require '../../css/includes/theme-default'
2
- .zmodem-transfer
3
- position absolute
4
- left 0
5
- right 0
6
- height 100%
7
- width 100%
8
- background alpha(main-dark, .95)
9
- display flex
10
- flex-direction column
11
- align-items center
12
- justify-content center
13
- z-index 20
14
- padding 20px 180px 20px 20px