@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.
- package/client/common/default-setting.js +1 -0
- package/client/components/ai/ai-chat-history-item.jsx +17 -3
- package/client/components/ai/ai-chat.jsx +2 -1
- package/client/components/ai/ai-config-props.js +3 -1
- package/client/components/ai/ai-config.jsx +21 -0
- package/client/components/ai/ai-output.jsx +2 -31
- package/client/components/bookmark-form/bookmark-select.jsx +17 -2
- package/client/components/sys-menu/menu-btn.jsx +0 -9
- package/client/components/sys-menu/sys-menu.jsx +4 -1
- package/client/components/sys-menu/sys-menu.styl +5 -0
- package/client/components/tree-list/tree-list.jsx +3 -2
- package/client/store/common.js +1 -1
- package/client/store/sync.js +3 -1
- package/client/store/system-menu.js +0 -4
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -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
|
|
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:
|
|
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
|
-
|
|
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} />
|
|
@@ -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
|
}
|
package/client/store/common.js
CHANGED
|
@@ -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) {
|
package/client/store/sync.js
CHANGED
|
@@ -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
|