@electerm/electerm-react 1.100.20 → 1.100.46

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 (33) hide show
  1. package/client/common/constants.js +2 -1
  2. package/client/common/default-setting.js +6 -1
  3. package/client/common/get-category-color.js +19 -0
  4. package/client/components/ai/ai-chat-history.jsx +1 -1
  5. package/client/components/ai/ai-chat.jsx +108 -22
  6. package/client/components/ai/ai-output.jsx +8 -8
  7. package/client/components/ai/ai.styl +6 -6
  8. package/client/components/bg/css-overwrite.jsx +52 -4
  9. package/client/components/bookmark-form/bookmark-category-select.jsx +80 -0
  10. package/client/components/bookmark-form/form-ssh-common.jsx +6 -14
  11. package/client/components/bookmark-form/ftp-form-ui.jsx +7 -16
  12. package/client/components/bookmark-form/local-form-ui.jsx +7 -16
  13. package/client/components/bookmark-form/rdp-form-ui.jsx +7 -16
  14. package/client/components/bookmark-form/serial-form-ui.jsx +9 -17
  15. package/client/components/bookmark-form/ssh-form-ui.jsx +7 -3
  16. package/client/components/bookmark-form/telnet-form-ui.jsx +2 -2
  17. package/client/components/bookmark-form/vnc-form-ui.jsx +7 -16
  18. package/client/components/bookmark-form/web-form-ui.jsx +7 -16
  19. package/client/components/main/main.jsx +4 -2
  20. package/client/components/main/term-fullscreen.styl +18 -7
  21. package/client/components/session/session.jsx +3 -1
  22. package/client/components/setting-panel/setting-common.jsx +1 -0
  23. package/client/components/setting-panel/terminal-bg-config.jsx +82 -5
  24. package/client/components/setting-panel/text-bg-modal.jsx +131 -0
  25. package/client/components/sftp/sftp-entry.jsx +8 -3
  26. package/client/components/terminal/terminal.jsx +4 -4
  27. package/client/components/tree-list/category-color-picker.jsx +11 -0
  28. package/client/components/tree-list/tree-list-item.jsx +11 -1
  29. package/client/components/tree-list/tree-list.jsx +54 -7
  30. package/client/components/tree-list/tree-list.styl +10 -1
  31. package/client/store/init-state.js +3 -1
  32. package/client/store/sync.js +6 -1
  33. package/package.json +1 -1
@@ -11,8 +11,7 @@ import {
11
11
  Select,
12
12
  Switch,
13
13
  AutoComplete,
14
- Form,
15
- TreeSelect
14
+ Form
16
15
  } from 'antd'
17
16
  import { formItemLayout } from '../../common/form-layout'
18
17
  import parseInt10 from '../../common/parse-int10'
@@ -24,7 +23,6 @@ import {
24
23
  terminalSerialType,
25
24
  newBookmarkIdPrefix
26
25
  } from '../../common/constants'
27
- import formatBookmarkGroups from './bookmark-group-tree-format'
28
26
  import defaultSettings from '../../common/default-setting'
29
27
  import findBookmarkGroupId from '../../common/find-bookmark-group-id'
30
28
  import useSubmit from './use-submit'
@@ -33,8 +31,9 @@ import useQm from './use-quick-commands'
33
31
  import copy from 'json-deep-copy'
34
32
  import renderTermBg from './render-bg'
35
33
  import { defaults } from 'lodash-es'
36
- import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
34
+ import { getColorFromCategory } from '../../common/get-category-color.js'
37
35
  import { ColorPickerItem } from './color-picker-item.jsx'
36
+ import BookmarkCategorySelect from './bookmark-category-select.jsx'
38
37
 
39
38
  const FormItem = Form.Item
40
39
  const { Option } = Select
@@ -67,7 +66,7 @@ export default function SerialFormUi (props) {
67
66
  : currentBookmarkGroupId
68
67
  let initialValues = copy(props.formData)
69
68
  const defaultValues = {
70
- color: getRandomDefaultColor(),
69
+ color: getColorFromCategory(bookmarkGroups, currentBookmarkGroupId),
71
70
  baudRate: 9600,
72
71
  dataBits: 8,
73
72
  lock: true,
@@ -91,7 +90,6 @@ export default function SerialFormUi (props) {
91
90
  serials = [],
92
91
  loaddingSerials
93
92
  } = props
94
- const tree = formatBookmarkGroups(bookmarkGroups)
95
93
  return (
96
94
  <div className='pd1x'>
97
95
  <FormItem
@@ -257,17 +255,11 @@ export default function SerialFormUi (props) {
257
255
  >
258
256
  <Input />
259
257
  </FormItem>
260
- <FormItem
261
- {...formItemLayout}
262
- label={e('bookmarkCategory')}
263
- name='category'
264
- >
265
- <TreeSelect
266
- treeData={tree}
267
- treeDefaultExpandAll
268
- showSearch
269
- />
270
- </FormItem>
258
+ <BookmarkCategorySelect
259
+ bookmarkGroups={bookmarkGroups}
260
+ form={form}
261
+ formItemLayout={formItemLayout}
262
+ />
271
263
  </div>
272
264
  )
273
265
  }
@@ -26,7 +26,7 @@ import renderAuth from './render-auth-ssh'
26
26
  import renderTermBg from './render-bg'
27
27
  import renderSshTunnel from './render-ssh-tunnel'
28
28
  import renderConnectionHopping from './render-connection-hopping'
29
- import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
29
+ import { getColorFromCategory } from '../../common/get-category-color.js'
30
30
  import defaultSetting from '../../common/default-setting'
31
31
  import './bookmark-form.styl'
32
32
 
@@ -61,7 +61,7 @@ export default function BookmarkFormUI (props) {
61
61
  port: 22,
62
62
  authType: authTypeMap.password,
63
63
  id: '',
64
- color: getRandomDefaultColor(),
64
+ color: getColorFromCategory(bookmarkGroups, currentBookmarkGroupId),
65
65
  term: props.store.config.terminalType,
66
66
  displayRaw: false,
67
67
  encode: encodes[0],
@@ -80,7 +80,11 @@ export default function BookmarkFormUI (props) {
80
80
  'terminalBackgroundFilterBlur',
81
81
  'terminalBackgroundFilterBrightness',
82
82
  'terminalBackgroundFilterGrayscale',
83
- 'terminalBackgroundFilterContrast'
83
+ 'terminalBackgroundFilterContrast',
84
+ 'terminalBackgroundText',
85
+ 'terminalBackgroundTextSize',
86
+ 'terminalBackgroundTextColor',
87
+ 'terminalBackgroundTextFontFamily'
84
88
  ])
85
89
  }
86
90
  initialValues = defaultsDeep(initialValues, defaultValues)
@@ -21,7 +21,7 @@ import useUI from './use-ui'
21
21
  import useQm from './use-quick-commands'
22
22
  import renderCommon from './form-ssh-common'
23
23
  import renderTermBg from './render-bg'
24
- import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
24
+ import { getColorFromCategory } from '../../common/get-category-color.js'
25
25
  import copy from 'json-deep-copy'
26
26
  import { defaultsDeep, isEmpty } from 'lodash-es'
27
27
  import renderAuth from './render-auth-ssh'
@@ -65,7 +65,7 @@ export default function TelnetFormUI (props) {
65
65
  id: '',
66
66
  username: 'root',
67
67
  password: 'guest',
68
- color: getRandomDefaultColor(),
68
+ color: getColorFromCategory(bookmarkGroups, currentBookmarkGroupId),
69
69
  runScripts: [{}],
70
70
  term: defaultSettings.terminalType,
71
71
  displayRaw: false,
@@ -7,7 +7,6 @@ import {
7
7
  Input,
8
8
  Form,
9
9
  InputNumber,
10
- TreeSelect,
11
10
  Switch,
12
11
  Tabs
13
12
  } from 'antd'
@@ -20,12 +19,12 @@ import useSubmit from './use-submit'
20
19
  import copy from 'json-deep-copy'
21
20
  import { defaults, isEmpty } from 'lodash-es'
22
21
  import { ColorPickerItem } from './color-picker-item.jsx'
23
- import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
24
- import formatBookmarkGroups from './bookmark-group-tree-format'
22
+ import { getColorFromCategory } from '../../common/get-category-color.js'
25
23
  import findBookmarkGroupId from '../../common/find-bookmark-group-id'
26
24
  import renderProxy from './proxy'
27
25
  import ConnectionHopping from './render-connection-hopping.jsx'
28
26
  import ProfileItem from './profile-form-item'
27
+ import BookmarkCategorySelect from './bookmark-category-select.jsx'
29
28
 
30
29
  const FormItem = Form.Item
31
30
  const e = window.translate
@@ -58,7 +57,7 @@ export default function VncFormUi (props) {
58
57
  type: terminalVncType,
59
58
  port: 5900,
60
59
  category: initBookmarkGroupId,
61
- color: getRandomDefaultColor(),
60
+ color: getColorFromCategory(bookmarkGroups, currentBookmarkGroupId),
62
61
  viewOnly: false,
63
62
  scaleViewport: true,
64
63
  connectionHoppings: []
@@ -100,7 +99,6 @@ export default function VncFormUi (props) {
100
99
  const {
101
100
  bookmarkGroups = []
102
101
  } = props
103
- const tree = formatBookmarkGroups(bookmarkGroups)
104
102
  return (
105
103
  <div className='pd1x'>
106
104
  <FormItem
@@ -181,17 +179,10 @@ export default function VncFormUi (props) {
181
179
  >
182
180
  <Input.TextArea autoSize={{ minRows: 1 }} />
183
181
  </FormItem>
184
- <FormItem
185
- {...formItemLayout}
186
- label={e('bookmarkCategory')}
187
- name='category'
188
- >
189
- <TreeSelect
190
- treeData={tree}
191
- treeDefaultExpandAll
192
- showSearch
193
- />
194
- </FormItem>
182
+ <BookmarkCategorySelect
183
+ bookmarkGroups={bookmarkGroups}
184
+ form={form}
185
+ />
195
186
  {
196
187
  renderProxy(props)
197
188
  }
@@ -6,7 +6,6 @@ import { useEffect } from 'react'
6
6
  import {
7
7
  Input,
8
8
  Form,
9
- TreeSelect,
10
9
  Switch
11
10
  } from 'antd'
12
11
  import { formItemLayout } from '../../common/form-layout'
@@ -18,9 +17,9 @@ import useSubmit from './use-submit'
18
17
  import copy from 'json-deep-copy'
19
18
  import { defaults } from 'lodash-es'
20
19
  import { ColorPickerItem } from './color-picker-item.jsx'
21
- import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
22
- import formatBookmarkGroups from './bookmark-group-tree-format'
20
+ import { getColorFromCategory } from '../../common/get-category-color.js'
23
21
  import findBookmarkGroupId from '../../common/find-bookmark-group-id'
22
+ import BookmarkCategorySelect from './bookmark-category-select.jsx'
24
23
 
25
24
  const FormItem = Form.Item
26
25
  const e = window.translate
@@ -52,14 +51,13 @@ export default function LocalFormUi (props) {
52
51
  const defaultValues = {
53
52
  type: terminalWebType,
54
53
  category: initBookmarkGroupId,
55
- color: getRandomDefaultColor()
54
+ color: getColorFromCategory(bookmarkGroups, currentBookmarkGroupId)
56
55
  }
57
56
  initialValues = defaults(initialValues, defaultValues)
58
57
  function renderCommon () {
59
58
  const {
60
59
  bookmarkGroups = []
61
60
  } = props
62
- const tree = formatBookmarkGroups(bookmarkGroups)
63
61
  return (
64
62
  <div className='pd1x'>
65
63
  <FormItem
@@ -100,17 +98,10 @@ export default function LocalFormUi (props) {
100
98
  >
101
99
  <Input.TextArea autoSize={{ minRows: 1 }} />
102
100
  </FormItem>
103
- <FormItem
104
- {...formItemLayout}
105
- label={e('bookmarkCategory')}
106
- name='category'
107
- >
108
- <TreeSelect
109
- treeData={tree}
110
- treeDefaultExpandAll
111
- showSearch
112
- />
113
- </FormItem>
101
+ <BookmarkCategorySelect
102
+ bookmarkGroups={bookmarkGroups}
103
+ form={form}
104
+ />
114
105
  <FormItem
115
106
  {...formItemLayout}
116
107
  label={e('useragent')}
@@ -18,7 +18,7 @@ import TerminalCmdSuggestions from '../terminal/terminal-command-dropdown'
18
18
  import TransportsActionStore from '../file-transfer/transports-action-store.jsx'
19
19
  import classnames from 'classnames'
20
20
  import ShortcutControl from '../shortcuts/shortcut-control.jsx'
21
- import { isMac, isWin } from '../../common/constants'
21
+ import { isMac, isWin, textTerminalBgValue } from '../../common/constants'
22
22
  import TermFullscreenControl from './term-fullscreen-control'
23
23
  import TerminalInfo from '../terminal-info/terminal-info'
24
24
  import { ConfigProvider, notification, message } from 'antd'
@@ -117,7 +117,9 @@ export default auto(function Index (props) {
117
117
  const ext1 = {
118
118
  className: cls
119
119
  }
120
- const bgTabs = config.terminalBackgroundImagePath === 'index' || config.terminalBackgroundImagePath === 'randomShape'
120
+ const bgTabs = config.terminalBackgroundImagePath === 'index' ||
121
+ config.terminalBackgroundImagePath === 'randomShape' ||
122
+ config.terminalBackgroundImagePath === textTerminalBgValue
121
123
  ? store.getTabs()
122
124
  : store.getTabs().filter(tab =>
123
125
  tab.terminalBackground?.terminalBackgroundImagePath
@@ -14,17 +14,28 @@
14
14
  position fixed
15
15
  z-index 100
16
16
  background rgba(45, 245, 108, 0.8)
17
- .term-wrap
18
- .session-v-wrap
17
+ // Hide all sessions first
18
+ .session-wrap
19
+ display none
20
+ // Only show the session that matches the fullscreen tab ID
21
+ .session-wrap.session-current
22
+ display block !important
19
23
  position fixed
20
24
  left 0 !important
21
25
  top 0 !important
22
26
  height 100% !important
23
27
  width 100% !important
24
- .term-wrap-1
25
- left 10px !important
26
- top 10px !important
27
- right 10px !important
28
- bottom 10px !important
28
+ .term-wrap
29
+ .session-v-wrap
30
+ position fixed
31
+ left 0 !important
32
+ top 0 !important
33
+ height 100% !important
34
+ width 100% !important
35
+ .term-wrap-1
36
+ left 10px !important
37
+ top 10px !important
38
+ right 10px !important
39
+ bottom 10px !important
29
40
  .term-fullscreen-control
30
41
  display none
@@ -465,7 +465,9 @@ export default class SessionWrapper extends Component {
465
465
  }
466
466
 
467
467
  handleFullscreen = () => {
468
- window.store.toggleTermFullscreen(true)
468
+ // Make this tab the active tab before fullscreening
469
+ window.store.activeTabId = this.props.tab.id
470
+ window.store.toggleTermFullscreen(true, this.props.tab.id)
469
471
  }
470
472
 
471
473
  toggleBroadcastInput = () => {
@@ -670,6 +670,7 @@ export default class SettingCommon extends Component {
670
670
  'confirmBeforeExit',
671
671
  'hideIP',
672
672
  'allowMultiInstance',
673
+ 'disableDeveloperTool',
673
674
  'debug'
674
675
  ].map(this.renderToggle)
675
676
  }
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { useState } from 'react'
2
2
  import {
3
3
  AutoComplete,
4
4
  Upload,
@@ -6,10 +6,12 @@ import {
6
6
  Input
7
7
  } from 'antd'
8
8
  import {
9
- noTerminalBgValue
9
+ noTerminalBgValue,
10
+ textTerminalBgValue
10
11
  } from '../../common/constants'
11
12
  import defaultSettings from '../../common/default-setting'
12
13
  import NumberConfig from './number-config'
14
+ import TextBgModal from './text-bg-modal.jsx'
13
15
 
14
16
  const e = window.translate
15
17
 
@@ -19,6 +21,7 @@ export default function TerminalBackgroundConfig ({
19
21
  config,
20
22
  isGlobal = false
21
23
  }) {
24
+ const [showTextModal, setShowTextModal] = useState(false)
22
25
  const value = config[name]
23
26
  const defaultValue = defaultSettings[name]
24
27
  const onChange = (v) => onChangeValue(v, name)
@@ -33,6 +36,7 @@ export default function TerminalBackgroundConfig ({
33
36
  <span>{e('chooseFile')}</span>
34
37
  </Upload>
35
38
  )
39
+
36
40
  const dataSource = [
37
41
  {
38
42
  value: '',
@@ -41,8 +45,34 @@ export default function TerminalBackgroundConfig ({
41
45
  {
42
46
  value: noTerminalBgValue,
43
47
  desc: e('noTerminalBg')
48
+ },
49
+ {
50
+ value: textTerminalBgValue,
51
+ desc: `📝 ${e('textBackground')}`
44
52
  }
45
53
  ]
54
+
55
+ // Add custom text background option if text is configured
56
+ if (value === textTerminalBgValue && config.terminalBackgroundText) {
57
+ const text = config.terminalBackgroundText
58
+ // Clean up the text for display: remove line breaks, trim whitespace
59
+ const cleanText = text.replace(/\s+/g, ' ').trim()
60
+ // Create a more user-friendly truncation
61
+ const truncatedText = cleanText.length > 25
62
+ ? cleanText.substring(0, 25) + '...'
63
+ : cleanText
64
+ dataSource[2] = {
65
+ value: textTerminalBgValue,
66
+ desc: `📝 "${truncatedText}"`
67
+ }
68
+ } else if (value === textTerminalBgValue) {
69
+ // Show helpful text when text background is selected but no text is configured
70
+ dataSource[2] = {
71
+ value: textTerminalBgValue,
72
+ desc: `📝 ${e('clickToConfigureText') || 'Click to configure text'}`
73
+ }
74
+ }
75
+
46
76
  if (isGlobal) {
47
77
  dataSource.push(
48
78
  {
@@ -51,10 +81,45 @@ export default function TerminalBackgroundConfig ({
51
81
  },
52
82
  {
53
83
  value: 'randomShape',
54
- desc: e('randomShape')
84
+ desc: `🎨 ${e('randomShape')}`
55
85
  }
56
86
  )
57
87
  }
88
+
89
+ const handleTextBgClick = () => {
90
+ setShowTextModal(true)
91
+ }
92
+
93
+ const handleTextBgModalOk = (textConfig) => {
94
+ // Store text configuration in the config
95
+ onChangeValue(textConfig.text, 'terminalBackgroundText')
96
+ onChangeValue(textConfig.fontSize, 'terminalBackgroundTextSize')
97
+ onChangeValue(textConfig.color, 'terminalBackgroundTextColor')
98
+ onChangeValue(textConfig.fontFamily, 'terminalBackgroundTextFontFamily')
99
+ onChange(textTerminalBgValue)
100
+ setShowTextModal(false)
101
+ }
102
+
103
+ const handleTextBgModalCancel = () => {
104
+ setShowTextModal(false)
105
+ }
106
+
107
+ const handleAutocompleteSelect = (v) => {
108
+ if (v === textTerminalBgValue) {
109
+ handleTextBgClick()
110
+ } else {
111
+ onChange(v)
112
+ }
113
+ }
114
+
115
+ const handleAutocompleteChange = (v) => {
116
+ if (v === textTerminalBgValue) {
117
+ handleTextBgClick()
118
+ } else {
119
+ onChange(v)
120
+ }
121
+ }
122
+
58
123
  const numberOpts = { step: 0.05, min: 0, max: 1, cls: 'bg-img-setting' }
59
124
 
60
125
  function renderNumber (name, options, title = '', width = 136) {
@@ -88,7 +153,7 @@ export default function TerminalBackgroundConfig ({
88
153
  }
89
154
 
90
155
  const renderFilter = () => {
91
- if (config[name] === noTerminalBgValue || config[name] === 'index') return
156
+ if (config[name] === noTerminalBgValue || config[name] === 'index' || config[name] === textTerminalBgValue) return
92
157
 
93
158
  return (
94
159
  <div>
@@ -137,6 +202,7 @@ export default function TerminalBackgroundConfig ({
137
202
  label: item.desc
138
203
  }
139
204
  }
205
+
140
206
  return (
141
207
  <div className='pd2b'>
142
208
  <div className='pd1b'>
@@ -145,7 +211,8 @@ export default function TerminalBackgroundConfig ({
145
211
  >
146
212
  <AutoComplete
147
213
  value={value}
148
- onChange={onChange}
214
+ onChange={handleAutocompleteChange}
215
+ onSelect={handleAutocompleteSelect}
149
216
  placeholder={defaultValue}
150
217
  className='width-100'
151
218
  options={dataSource.map(renderBgOption)}
@@ -160,6 +227,16 @@ export default function TerminalBackgroundConfig ({
160
227
  {
161
228
  renderFilter()
162
229
  }
230
+
231
+ <TextBgModal
232
+ visible={showTextModal}
233
+ onOk={handleTextBgModalOk}
234
+ onCancel={handleTextBgModalCancel}
235
+ initialText={config.terminalBackgroundText || ''}
236
+ initialSize={config.terminalBackgroundTextSize || 48}
237
+ initialColor={config.terminalBackgroundTextColor || '#ffffff'}
238
+ initialFontFamily={config.terminalBackgroundTextFontFamily || 'monospace'}
239
+ />
163
240
  </div>
164
241
  )
165
242
  }
@@ -0,0 +1,131 @@
1
+ import React, { useState } from 'react'
2
+ import {
3
+ Modal,
4
+ Input,
5
+ InputNumber,
6
+ Space,
7
+ Typography,
8
+ Select
9
+ } from 'antd'
10
+ import { ColorPicker } from '../bookmark-form/color-picker.jsx'
11
+
12
+ const { TextArea } = Input
13
+ const { Title } = Typography
14
+ const e = window.translate
15
+
16
+ export default function TextBgModal ({
17
+ visible,
18
+ onOk,
19
+ onCancel,
20
+ initialText = '',
21
+ initialSize = 48,
22
+ initialColor = '#ffffff',
23
+ initialFontFamily = 'Maple Mono'
24
+ }) {
25
+ const [text, setText] = useState(initialText)
26
+ const [fontSize, setFontSize] = useState(initialSize)
27
+ const [color, setColor] = useState(initialColor)
28
+ const [fontFamily, setFontFamily] = useState(initialFontFamily)
29
+
30
+ const { fonts = [] } = window.et || {}
31
+
32
+ const handleOk = () => {
33
+ onOk({
34
+ text,
35
+ fontSize,
36
+ color,
37
+ fontFamily
38
+ })
39
+ }
40
+
41
+ const handleCancel = () => {
42
+ onCancel()
43
+ // Reset to initial values
44
+ setText(initialText)
45
+ setFontSize(initialSize)
46
+ setColor(initialColor)
47
+ setFontFamily(initialFontFamily)
48
+ }
49
+
50
+ return (
51
+ <Modal
52
+ title={e('terminalBackgroundText')}
53
+ open={visible}
54
+ onOk={handleOk}
55
+ onCancel={handleCancel}
56
+ width={500}
57
+ destroyOnClose
58
+ >
59
+ <div className='pd1'>
60
+ <Space direction='vertical' size='large' style={{ width: '100%' }}>
61
+ <div>
62
+ <Title level={5}>{e('text')}</Title>
63
+ <TextArea
64
+ value={text}
65
+ onChange={(e) => setText(e.target.value)}
66
+ placeholder={e('enterTextForBackground')}
67
+ rows={4}
68
+ maxLength={500}
69
+ />
70
+ </div>
71
+
72
+ <div>
73
+ <Title level={5}>{e('fontSize')}</Title>
74
+ <InputNumber
75
+ value={fontSize}
76
+ onChange={setFontSize}
77
+ min={12}
78
+ max={200}
79
+ style={{ width: '100%' }}
80
+ placeholder={e('fontSize')}
81
+ />
82
+ </div>
83
+
84
+ <div>
85
+ <Title level={5}>{e('textColor')}</Title>
86
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
87
+ <ColorPicker
88
+ value={color}
89
+ onChange={setColor}
90
+ />
91
+ <Input
92
+ value={color}
93
+ onChange={(e) => setColor(e.target.value)}
94
+ placeholder={e('colorValue')}
95
+ style={{ flex: 1 }}
96
+ />
97
+ </div>
98
+ </div>
99
+
100
+ <div>
101
+ <Title level={5}>{e('fontFamily')}</Title>
102
+ <Select
103
+ value={fontFamily}
104
+ onChange={setFontFamily}
105
+ style={{ width: '100%' }}
106
+ placeholder={e('selectFontFamily')}
107
+ showSearch
108
+ >
109
+ {
110
+ fonts.map(f => {
111
+ return (
112
+ <Select.Option value={f} key={f}>
113
+ <span
114
+ className='font-option'
115
+ style={{
116
+ fontFamily: f
117
+ }}
118
+ >
119
+ {f}
120
+ </span>
121
+ </Select.Option>
122
+ )
123
+ })
124
+ }
125
+ </Select>
126
+ </div>
127
+ </Space>
128
+ </div>
129
+ </Modal>
130
+ )
131
+ }
@@ -526,9 +526,14 @@ export default class Sftp extends Component {
526
526
  if (updates.remotePath !== undefined) {
527
527
  updates.remoteKeyword = ''
528
528
  }
529
+
530
+ // For selectedFiles updates, call setState immediately for better responsiveness
531
+ if (updates.selectedFiles !== undefined) {
532
+ return this.setState(...args)
533
+ }
529
534
  }
530
535
 
531
- // Call setState with the modified arguments
536
+ // For other updates, use runIdle to avoid blocking the UI
532
537
  runIdle(() => this.setState(...args))
533
538
  }
534
539
 
@@ -1156,12 +1161,12 @@ export default class Sftp extends Component {
1156
1161
  {
1157
1162
  type === typeMap.remote
1158
1163
  ? (
1159
- <div className='pd1t pd1b pd1x alignright'>
1164
+ <div className='sftp-panel-title pd1t pd1b pd1x alignright'>
1160
1165
  {e('remote')}: {username}@{host}
1161
1166
  </div>
1162
1167
  )
1163
1168
  : (
1164
- <div className='pd1t pd1b pd1x'>
1169
+ <div className='sftp-panel-title pd1t pd1b pd1x'>
1165
1170
  {e('local')}
1166
1171
  </div>
1167
1172
  )
@@ -151,7 +151,7 @@ class Term extends Component {
151
151
  this.attachAddon._sendData(PS1_SETUP_CMD)
152
152
  this.term.cwdId = cwdId
153
153
  } else {
154
- log.warn('Term or attachAddon not ready for PS1_SETUP_CMD in componentDidUpdate')
154
+ console.warn('Term or attachAddon not ready for PS1_SETUP_CMD in componentDidUpdate')
155
155
  }
156
156
  } else {
157
157
  if (this.attachAddon) {
@@ -895,7 +895,7 @@ class Term extends Component {
895
895
  if (this.attachAddon) {
896
896
  this.attachAddon._sendData(PS1_SETUP_CMD)
897
897
  } else {
898
- log.warn('attachAddon not ready for PS1_SETUP_CMD in getCwd fallback')
898
+ console.warn('attachAddon not ready for PS1_SETUP_CMD in getCwd fallback')
899
899
  }
900
900
  }
901
901
  }
@@ -1065,7 +1065,7 @@ class Term extends Component {
1065
1065
  const cmd = `cd "${startFolder}"\r`
1066
1066
  this.attachAddon._sendData(cmd)
1067
1067
  } else {
1068
- log.warn('attachAddon not ready for cd command in runInitScript')
1068
+ console.warn('attachAddon not ready for cd command in runInitScript')
1069
1069
  }
1070
1070
  }
1071
1071
 
@@ -1074,7 +1074,7 @@ class Term extends Component {
1074
1074
  this.attachAddon._sendData(PS1_SETUP_CMD)
1075
1075
  this.term.cwdId = cwdId
1076
1076
  } else {
1077
- log.warn('Term or attachAddon not ready for PS1_SETUP_CMD in runInitScript')
1077
+ console.warn('Term or attachAddon not ready for PS1_SETUP_CMD in runInitScript')
1078
1078
  }
1079
1079
  }
1080
1080
 
@@ -0,0 +1,11 @@
1
+ import React from 'react'
2
+ import { ColorPicker } from '../bookmark-form/color-picker.jsx'
3
+
4
+ export function CategoryColorPicker ({ value, onChange }) {
5
+ return (
6
+ <ColorPicker
7
+ value={value}
8
+ onChange={onChange}
9
+ />
10
+ )
11
+ }