@electerm/electerm-react 1.91.1 → 1.91.16

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.
@@ -63,6 +63,7 @@ export default {
63
63
  modelAI: 'deepseek-chat',
64
64
  roleAI: '终端专家,提供不同系统下命令,简要解释用法,用markdown格式',
65
65
  apiPathAI: '/chat/completions',
66
+ proxyAI: '',
66
67
  sessionLogPath: '',
67
68
  sshSftpSplitView: false,
68
69
  showCmdSuggestions: false,
@@ -7,17 +7,31 @@ import {
7
7
  import {
8
8
  UserOutlined,
9
9
  CopyOutlined,
10
- CloseOutlined
10
+ CloseOutlined,
11
+ CaretDownOutlined,
12
+ CaretRightOutlined
11
13
  } from '@ant-design/icons'
12
14
  import { copy } from '../../common/clipboard'
15
+ import { useState } from 'react'
13
16
 
14
17
  export default function AIChatHistoryItem ({ item }) {
18
+ const [showOutput, setShowOutput] = useState(true)
15
19
  const {
16
20
  prompt
17
21
  } = item
22
+
23
+ function toggleOutput () {
24
+ setShowOutput(!showOutput)
25
+ }
26
+
18
27
  const alertProps = {
19
28
  message: (
20
- <><UserOutlined />: {prompt}</>
29
+ <>
30
+ <span className='pointer mg1r' onClick={toggleOutput}>
31
+ {showOutput ? <CaretDownOutlined /> : <CaretRightOutlined />}
32
+ </span>
33
+ <UserOutlined />: {prompt}
34
+ </>
21
35
  ),
22
36
  type: 'info'
23
37
  }
@@ -63,7 +77,7 @@ export default function AIChatHistoryItem ({ item }) {
63
77
  <Alert {...alertProps} />
64
78
  </Tooltip>
65
79
  </div>
66
- <AIOutput item={item} />
80
+ {showOutput && <AIOutput item={item} />}
67
81
  </div>
68
82
  )
69
83
  }
@@ -46,7 +46,8 @@ export default function AIChat (props) {
46
46
  buildRole(),
47
47
  props.config.baseURLAI,
48
48
  props.config.apiPathAI,
49
- props.config.apiKeyAI
49
+ props.config.apiKeyAI,
50
+ props.config.proxyAI
50
51
  ).catch(
51
52
  window.store.onError
52
53
  )
@@ -3,5 +3,7 @@ export const aiConfigsArr = [
3
3
  'modelAI',
4
4
  'roleAI',
5
5
  'apiKeyAI',
6
- 'apiPathAI'
6
+ 'apiPathAI',
7
+ 'languageAI',
8
+ 'proxyAI'
7
9
  ]
@@ -26,6 +26,12 @@ const defaultRoles = [
26
26
  }
27
27
  ]
28
28
 
29
+ const proxyOptions = [
30
+ { value: 'socks5://127.0.0.1:1080' },
31
+ { value: 'http://127.0.0.1:8080' },
32
+ { value: 'https://proxy.example.com:3128' }
33
+ ]
34
+
29
35
  export default function AIConfigForm ({ initialValues, onSubmit, showAIConfig }) {
30
36
  const [form] = Form.useForm()
31
37
  const [modelOptions, setModelOptions] = useState([])
@@ -171,6 +177,21 @@ export default function AIConfigForm ({ initialValues, onSubmit, showAIConfig })
171
177
  </AutoComplete>
172
178
  </Form.Item>
173
179
 
180
+ <Form.Item
181
+ label={e('proxy')}
182
+ name='proxyAI'
183
+ tooltip='Proxy for AI API requests (e.g., socks5://127.0.0.1:1080)'
184
+ >
185
+ <AutoComplete
186
+ options={proxyOptions}
187
+ placeholder='Enter proxy URL (optional)'
188
+ filterOption={filter}
189
+ allowClear
190
+ >
191
+ <Input />
192
+ </AutoComplete>
193
+ </Form.Item>
194
+
174
195
  <Form.Item>
175
196
  <Button type='primary' htmlType='submit'>
176
197
  {e('save')}
@@ -1,15 +1,13 @@
1
- import { useState, useMemo } from 'react'
2
1
  import ReactMarkdown from 'react-markdown'
3
2
  import { copy } from '../../common/clipboard'
4
3
  import Link from '../common/external-link'
5
4
  import { Tag } from 'antd'
6
- import { CopyOutlined, PlayCircleOutlined, DownCircleOutlined } from '@ant-design/icons'
5
+ import { CopyOutlined, PlayCircleOutlined } from '@ant-design/icons'
7
6
  import getBrand from './get-brand'
8
7
 
9
8
  const e = window.translate
10
9
 
11
10
  export default function AIOutput ({ item }) {
12
- const [showFull, setShowFull] = useState(false)
13
11
  const {
14
12
  response,
15
13
  baseURLAI
@@ -20,18 +18,6 @@ export default function AIOutput ({ item }) {
20
18
 
21
19
  const { brand, brandUrl } = getBrand(baseURLAI)
22
20
 
23
- const truncatedResponse = useMemo(() => {
24
- if (!response) return ''
25
- const codeBlockRegex = /```[\s\S]*?```/
26
- const match = response.match(codeBlockRegex)
27
- if (match) {
28
- const index = match.index + match[0].length
29
- return response.slice(0, index) + '\n\n... ...'
30
- }
31
- // If no code block found, show first 5 lines
32
- return response.split('\n').slice(0, 5).join('\n') + '\n\n... ...'
33
- }, [response])
34
-
35
21
  const renderCode = (props) => {
36
22
  const { node, className = '', children, ...rest } = props
37
23
  const code = String(children).replace(/\n$/, '')
@@ -87,22 +73,8 @@ export default function AIOutput ({ item }) {
87
73
  )
88
74
  }
89
75
 
90
- function renderShowMore () {
91
- if (showFull) {
92
- return null
93
- }
94
- return (
95
- <span
96
- onClick={() => setShowFull(true)}
97
- className='mg1t pointer'
98
- >
99
- <DownCircleOutlined /> {e('fullContent')}
100
- </span>
101
- )
102
- }
103
-
104
76
  const mdProps = {
105
- children: showFull ? response : truncatedResponse,
77
+ children: response,
106
78
  components: {
107
79
  code: renderCode
108
80
  }
@@ -112,7 +84,6 @@ export default function AIOutput ({ item }) {
112
84
  <div className='pd1'>
113
85
  {renderBrand()}
114
86
  <ReactMarkdown {...mdProps} />
115
- {renderShowMore()}
116
87
  </div>
117
88
  )
118
89
  }
@@ -21,7 +21,8 @@ function buildTreeData (bookmarkGroups, tree) {
21
21
  const y = {
22
22
  key: x.id,
23
23
  value: x.id,
24
- title: x.title
24
+ title: x.title,
25
+ selectable: false // Make categories non-selectable
25
26
  }
26
27
  y.children = [
27
28
  ...(x.bookmarkGroupIds || []).map(buildSubCats),
@@ -49,6 +50,7 @@ function buildTreeData (bookmarkGroups, tree) {
49
50
  title: d.title,
50
51
  value: d.id,
51
52
  key: d.id,
53
+ selectable: false, // Make categories non-selectable
52
54
  children: [
53
55
  ...(d.bookmarkGroupIds || []).map(buildSubCats),
54
56
  ...(d.bookmarkIds || []).map(buildLeaf)
@@ -82,13 +84,26 @@ export default function BookmarkSelect (props) {
82
84
  props.onSelect(item)
83
85
  }
84
86
  }
87
+
88
+ // Custom filter function to only match leaf nodes
89
+ function filterTreeNode (inputValue, treeNode) {
90
+ // Skip filtering for category nodes
91
+ if (treeNode.selectable === false) {
92
+ return false
93
+ }
94
+
95
+ // Match against searchText which includes both title and host
96
+ return treeNode.title && treeNode.title.toLowerCase().includes(inputValue.toLowerCase())
97
+ }
98
+
85
99
  const treeData = buildTreeData(bookmarkGroups, tree)
86
100
  const treeProps = {
87
101
  treeData,
88
102
  onChange: onSelect,
89
103
  placeholder: e('chooseFromBookmarks'),
90
104
  showSearch: true,
91
- value: undefined
105
+ value: undefined,
106
+ filterTreeNode
92
107
  }
93
108
  return (
94
109
  <TreeSelect {...treeProps} />
@@ -27,10 +27,6 @@ class MenuBtn extends PureComponent {
27
27
  window.store.addTab()
28
28
  }
29
29
 
30
- onNewWindow = () => {
31
- window.store.onNewWindow()
32
- }
33
-
34
30
  openAbout = () => {
35
31
  window.store.openAbout()
36
32
  }
@@ -80,11 +76,6 @@ class MenuBtn extends PureComponent {
80
76
  icon: 'RightSquareFilled',
81
77
  text: e('newTab')
82
78
  },
83
- {
84
- func: 'onNewWindow',
85
- icon: 'WindowsOutlined',
86
- text: e('newWindow')
87
- },
88
79
  // {
89
80
  // type: 'hr'
90
81
  // },
@@ -77,9 +77,12 @@ export default class ContextMenu extends PureComponent {
77
77
  if (type === 'hr') {
78
78
  return <hr />
79
79
  }
80
- const baseCls = 'context-item'
80
+ let baseCls = 'context-item'
81
81
  if (module && this.modules[module]) {
82
82
  const Mod = this.modules[module]
83
+ if (module === 'Zoom') {
84
+ baseCls = 'context-item zoom-item'
85
+ }
83
86
  return (
84
87
  <div className={baseCls}>
85
88
  <Mod {...this.props} />
@@ -20,6 +20,11 @@
20
20
  color #777
21
21
  background #333
22
22
  cursor not-allowed
23
+ &.zoom-item
24
+ height 36px
25
+ line-height 36px
26
+ &:hover
27
+ background transparent
23
28
 
24
29
  .context-sub-text
25
30
  position absolute
@@ -385,6 +385,7 @@ export default class ItemListTree extends Component {
385
385
  if (tar) {
386
386
  target = tar
387
387
  }
388
+ console.log('tar', target, tar)
388
389
  const dataDragged = e.dataTransfer.getData('idDragged')
389
390
  const [idDragged, pidDrags, isGroupDragged] = dataDragged.split('@')
390
391
  const isGroupDrag = isGroupDragged === 'true'
@@ -395,7 +396,6 @@ export default class ItemListTree extends Component {
395
396
  const pidDrops = target.getAttribute('data-parent-id') || ''
396
397
  const pidDropsArr = pidDrops.split('#')
397
398
  const pidDrop = pidDropsArr[pidDropsArr.length - 1]
398
-
399
399
  // can not drag item to its own children
400
400
  if (
401
401
  (idDragged === 'default' &&
@@ -404,7 +404,8 @@ export default class ItemListTree extends Component {
404
404
  pidDrop &&
405
405
  pidDrags !== pidDrops &&
406
406
  pidDrops.includes(idDragged)
407
- )
407
+ ) ||
408
+ idDragged === idDrop
408
409
  ) {
409
410
  return
410
411
  }
@@ -314,7 +314,7 @@ export default Store => {
314
314
  }
315
315
 
316
316
  Store.prototype.aiConfigMissing = function () {
317
- return aiConfigsArr.some(k => !window.store.config[k])
317
+ return aiConfigsArr.slice(0, -1).some(k => !window.store.config[k])
318
318
  }
319
319
 
320
320
  Store.prototype.addCmdHistory = action(function (cmd) {
@@ -512,7 +512,9 @@ export default (Store) => {
512
512
  'dataSyncSelected',
513
513
  'baseURLAI',
514
514
  'modelAI',
515
- 'roleAI'
515
+ 'roleAI',
516
+ 'languageAI',
517
+ 'proxyAI'
516
518
  ]
517
519
  return pick(store.config, configSyncKeys)
518
520
  }
@@ -61,10 +61,6 @@ export default Store => {
61
61
  store.openSettingModal()
62
62
  }
63
63
 
64
- Store.prototype.onNewWindow = async function () {
65
- window.pre.runGlobalAsync('openNewInstance')
66
- }
67
-
68
64
  Store.prototype.confirmExit = function (type) {
69
65
  const { store } = window
70
66
  let mod = null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electerm/electerm-react",
3
- "version": "1.91.1",
3
+ "version": "1.91.16",
4
4
  "description": "react components src for electerm",
5
5
  "main": "./client/components/main/main.jsx",
6
6
  "license": "MIT",