@electerm/electerm-react 1.70.6 → 1.72.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/cache.js +56 -0
- package/client/common/constants.js +2 -0
- package/client/common/default-setting.js +2 -1
- package/client/common/download.jsx +5 -7
- package/client/common/setting-list.js +27 -0
- package/client/components/ai/ai-cache.jsx +36 -0
- package/client/components/ai/ai-chat-history-item.jsx +1 -1
- package/client/components/ai/ai-chat.jsx +5 -40
- package/client/components/ai/ai-config-props.js +7 -0
- package/client/components/ai/ai-config.jsx +5 -14
- package/client/components/ai/ai.styl +0 -4
- package/client/components/ai/providers.js +2 -2
- package/client/components/batch-op/batch-op-entry.jsx +1 -1
- package/client/components/batch-op/batch-op.jsx +2 -2
- package/client/components/bookmark-form/form-ssh-common.jsx +2 -3
- package/client/components/bookmark-form/form-tabs.jsx +2 -2
- package/client/components/bookmark-form/render-connection-hopping.jsx +2 -2
- package/client/components/bookmark-form/render-delayed-scripts.jsx +4 -4
- package/client/components/bookmark-form/render-ssh-tunnel.jsx +2 -2
- package/client/components/bookmark-form/sftp-enable.jsx +9 -0
- package/client/components/bookmark-form/ssh-form-ui.jsx +1 -0
- package/client/components/bookmark-form/ssh-form.jsx +3 -0
- package/client/components/bookmark-form/use-quick-commands.jsx +2 -2
- package/client/components/bookmark-form/x11.jsx +78 -9
- package/client/components/common/input-auto-focus.jsx +3 -11
- package/client/components/layout/layout.jsx +2 -1
- package/client/components/main/main.jsx +5 -0
- package/client/components/profile/profile-form-elem.jsx +1 -3
- package/client/components/quick-commands/quick-commands-form-elem.jsx +1 -3
- package/client/components/quick-commands/quick-commands-list-form.jsx +2 -2
- package/client/components/session/session.jsx +80 -19
- package/client/components/session/session.styl +10 -3
- package/client/components/session/sessions.jsx +2 -1
- package/client/components/setting-panel/keywords-form.jsx +36 -38
- package/client/components/setting-panel/setting-modal.jsx +2 -2
- package/client/components/setting-panel/setting-terminal.jsx +2 -1
- package/client/components/setting-panel/tab-settings.jsx +26 -0
- package/client/components/sftp/address-bar.jsx +9 -2
- package/client/components/sftp/address-bookmark.jsx +4 -6
- package/client/components/sftp/file-item.jsx +1 -1
- package/client/components/sftp/file-read.js +14 -19
- package/client/components/sftp/keyword-filter.jsx +63 -0
- package/client/components/sftp/list-table-ui.jsx +7 -9
- package/client/components/sftp/sftp-entry.jsx +46 -9
- package/client/components/sftp/sftp.styl +6 -1
- package/client/components/sftp/transfer-conflict-store.jsx +1 -1
- package/client/components/shortcuts/shortcut-control.jsx +20 -0
- package/client/components/shortcuts/shortcut-editor.jsx +2 -2
- package/client/components/shortcuts/shortcuts.jsx +2 -2
- package/client/components/sidebar/info-modal.jsx +2 -2
- package/client/components/sidebar/transfer-list-control.jsx +18 -20
- package/client/components/ssh-config/ssh-config-item.jsx +2 -4
- package/client/components/ssh-config/ssh-config-load-notify.jsx +2 -2
- package/client/components/sys-menu/zoom.jsx +2 -2
- package/client/components/tabs/index.jsx +1 -1
- package/client/components/tabs/tab.jsx +3 -3
- package/client/components/terminal/cmd-item.jsx +32 -0
- package/client/components/terminal/command-tracker-addon.js +3 -1
- package/client/components/terminal/term-search.jsx +5 -6
- package/client/components/terminal/terminal-command-dropdown.jsx +303 -0
- package/client/components/terminal/terminal.jsx +88 -8
- package/client/components/terminal/terminal.styl +58 -0
- package/client/components/terminal-info/terminal-info.jsx +2 -2
- package/client/components/tree-list/tree-list.jsx +1 -1
- package/client/components/web/address-bar.jsx +2 -2
- package/client/store/common.js +27 -2
- package/client/store/init-state.js +3 -3
- package/client/store/item.js +2 -1
- package/client/store/setting.js +3 -2
- package/client/store/store.js +23 -24
- package/client/store/watch.js +7 -1
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// cache class that can set(key, value), get(key), init with limit, so we only
|
|
2
|
+
// keep limit items in cache
|
|
3
|
+
// we persist cache to local storage, so we can keep cache after restart
|
|
4
|
+
|
|
5
|
+
class MapCache {
|
|
6
|
+
constructor (limit, key) {
|
|
7
|
+
this.limit = limit
|
|
8
|
+
this.key = key
|
|
9
|
+
this.cache = new Map()
|
|
10
|
+
this.load()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
load () {
|
|
14
|
+
const data = window.localStorage.getItem(this.key)
|
|
15
|
+
if (data) {
|
|
16
|
+
const arr = JSON.parse(data)
|
|
17
|
+
for (const item of arr) {
|
|
18
|
+
this.cache.set(item.key, item.value)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
save () {
|
|
24
|
+
const arr = []
|
|
25
|
+
for (const [key, value] of this.cache) {
|
|
26
|
+
arr.push({
|
|
27
|
+
key,
|
|
28
|
+
value
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
window.localStorage.setItem(this.key, JSON.stringify(arr))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
set (key, value) {
|
|
35
|
+
this.cache.set(key, value)
|
|
36
|
+
if (this.cache.size > this.limit) {
|
|
37
|
+
// Delete oldest 20 items when cache exceeds limit
|
|
38
|
+
const values = Array.from(this.cache.values())
|
|
39
|
+
for (let i = 0; i < 20 && i < values.length; i++) {
|
|
40
|
+
this.cache.delete(values[i])
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
this.save()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get (key) {
|
|
47
|
+
return this.cache.get(key)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
clear () {
|
|
51
|
+
this.cache.clear()
|
|
52
|
+
this.save()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const aiSuggestionsCache = new MapCache(100, 'ai-cmd-suggestion-cache')
|
|
@@ -218,6 +218,7 @@ export const syncTokenCreateUrls = {
|
|
|
218
218
|
export const settingSyncId = 'setting-sync'
|
|
219
219
|
export const settingTerminalId = 'setting-terminal'
|
|
220
220
|
export const settingShortcutsId = 'setting-shortcuts'
|
|
221
|
+
export const settingAiId = 'setting-ai'
|
|
221
222
|
export const settingCommonId = 'setting-common'
|
|
222
223
|
export const defaultEnvLang = 'en_US.UTF-8'
|
|
223
224
|
const defaultThemeLightConf = _get(
|
|
@@ -373,3 +374,4 @@ export const sshConfigKey = 'ignore-ssh-config'
|
|
|
373
374
|
export const connectionHoppingWarnKey = 'connectionHoppingWarnned'
|
|
374
375
|
export const aiChatHistoryKey = 'ai-chat-history'
|
|
375
376
|
export const syncServerDataKey = 'sync-server-data'
|
|
377
|
+
export const cmdHistoryKey = 'cmd-history'
|
|
@@ -19,13 +19,11 @@ export default async function download (filename, text) {
|
|
|
19
19
|
notification.success({
|
|
20
20
|
message: '',
|
|
21
21
|
description: (
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</ShowItem>
|
|
28
|
-
</div>
|
|
22
|
+
<ShowItem
|
|
23
|
+
to={filePath}
|
|
24
|
+
>
|
|
25
|
+
{filePath}
|
|
26
|
+
</ShowItem>
|
|
29
27
|
)
|
|
30
28
|
})
|
|
31
29
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
settingSyncId,
|
|
3
|
+
settingShortcutsId,
|
|
4
|
+
settingTerminalId,
|
|
5
|
+
settingAiId
|
|
6
|
+
} from '../common/constants'
|
|
7
|
+
|
|
8
|
+
const e = window.translate
|
|
9
|
+
|
|
10
|
+
export default () => ([
|
|
11
|
+
{
|
|
12
|
+
id: settingTerminalId,
|
|
13
|
+
title: e('terminal')
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: settingShortcutsId,
|
|
17
|
+
title: e('settingShortcuts')
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: settingSyncId,
|
|
21
|
+
title: e('settingSync')
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: settingAiId,
|
|
25
|
+
title: 'AI'
|
|
26
|
+
}
|
|
27
|
+
])
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { aiSuggestionsCache } from '../../common/cache'
|
|
2
|
+
import { useEffect, useState } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Alert
|
|
6
|
+
} from 'antd'
|
|
7
|
+
|
|
8
|
+
const e = window.translate
|
|
9
|
+
|
|
10
|
+
export default function AiCache () {
|
|
11
|
+
const [count, setCount] = useState(0)
|
|
12
|
+
|
|
13
|
+
function handleClick () {
|
|
14
|
+
aiSuggestionsCache.clear()
|
|
15
|
+
setCount(0)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
setCount(aiSuggestionsCache.cache.size)
|
|
20
|
+
}, [])
|
|
21
|
+
|
|
22
|
+
const msg = (
|
|
23
|
+
<>
|
|
24
|
+
<span className='mg3r'>{e('aiSuggestionsCache')}: <b>{count}</b></span>
|
|
25
|
+
<Button
|
|
26
|
+
onClick={handleClick}
|
|
27
|
+
size='small'
|
|
28
|
+
>
|
|
29
|
+
{e('clear')}
|
|
30
|
+
</Button>
|
|
31
|
+
</>
|
|
32
|
+
)
|
|
33
|
+
return (
|
|
34
|
+
<Alert message={msg} type='info' className='mg2y' />
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect } from 'react'
|
|
2
|
-
import { Flex, Input
|
|
3
|
-
import AIConfigForm from './ai-config'
|
|
2
|
+
import { Flex, Input } from 'antd'
|
|
4
3
|
import TabSelect from '../footer/tab-select'
|
|
5
4
|
import AiChatHistory from './ai-chat-history'
|
|
6
5
|
import uid from '../../common/uid'
|
|
@@ -20,13 +19,6 @@ import './ai.styl'
|
|
|
20
19
|
|
|
21
20
|
const { TextArea } = Input
|
|
22
21
|
const MAX_HISTORY = 100
|
|
23
|
-
const aiConfigsArr = [
|
|
24
|
-
'baseURLAI',
|
|
25
|
-
'modelAI',
|
|
26
|
-
'roleAI',
|
|
27
|
-
'apiKeyAI',
|
|
28
|
-
'apiPathAI'
|
|
29
|
-
]
|
|
30
22
|
|
|
31
23
|
export default function AIChat (props) {
|
|
32
24
|
const [prompt, setPrompt] = useState('')
|
|
@@ -42,7 +34,7 @@ export default function AIChat (props) {
|
|
|
42
34
|
}
|
|
43
35
|
|
|
44
36
|
const handleSubmit = useCallback(async function () {
|
|
45
|
-
if (aiConfigMissing()) {
|
|
37
|
+
if (window.store.aiConfigMissing()) {
|
|
46
38
|
window.store.toggleAIConfig()
|
|
47
39
|
}
|
|
48
40
|
if (!prompt.trim() || isLoading) return
|
|
@@ -82,30 +74,6 @@ export default function AIChat (props) {
|
|
|
82
74
|
setIsLoading(false)
|
|
83
75
|
}, [prompt, isLoading, props.config])
|
|
84
76
|
|
|
85
|
-
function handleConfigSubmit (values) {
|
|
86
|
-
window.store.updateConfig(values)
|
|
87
|
-
message.success('Saved')
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function getInitialValues () {
|
|
91
|
-
const res = pick(props.config, aiConfigsArr)
|
|
92
|
-
if (!res.languageAI) {
|
|
93
|
-
res.languageAI = window.store.getLangName()
|
|
94
|
-
}
|
|
95
|
-
return res
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const renderConfig = useCallback(() => {
|
|
99
|
-
if (!props.showAIConfig) return null
|
|
100
|
-
return (
|
|
101
|
-
<AIConfigForm
|
|
102
|
-
initialValues={getInitialValues()}
|
|
103
|
-
onSubmit={handleConfigSubmit}
|
|
104
|
-
showAIConfig={props.showAIConfig}
|
|
105
|
-
/>
|
|
106
|
-
)
|
|
107
|
-
}, [props.showAIConfig, props.config])
|
|
108
|
-
|
|
109
77
|
function renderHistory () {
|
|
110
78
|
return (
|
|
111
79
|
<AiChatHistory
|
|
@@ -122,10 +90,6 @@ export default function AIChat (props) {
|
|
|
122
90
|
window.store.aiChatHistory = []
|
|
123
91
|
}
|
|
124
92
|
|
|
125
|
-
function aiConfigMissing () {
|
|
126
|
-
return aiConfigsArr.some(k => !props.config[k])
|
|
127
|
-
}
|
|
128
|
-
|
|
129
93
|
function renderSendIcon () {
|
|
130
94
|
if (isLoading) {
|
|
131
95
|
return <LoadingOutlined />
|
|
@@ -134,6 +98,7 @@ export default function AIChat (props) {
|
|
|
134
98
|
<SendOutlined
|
|
135
99
|
onClick={handleSubmit}
|
|
136
100
|
className='mg1l pointer icon-hover'
|
|
101
|
+
title='Ctrl+Enter'
|
|
137
102
|
/>
|
|
138
103
|
)
|
|
139
104
|
}
|
|
@@ -143,7 +108,7 @@ export default function AIChat (props) {
|
|
|
143
108
|
setPrompt,
|
|
144
109
|
handleSubmit
|
|
145
110
|
})
|
|
146
|
-
if (aiConfigMissing()) {
|
|
111
|
+
if (window.store.aiConfigMissing()) {
|
|
147
112
|
window.store.toggleAIConfig()
|
|
148
113
|
}
|
|
149
114
|
return () => {
|
|
@@ -168,6 +133,7 @@ export default function AIChat (props) {
|
|
|
168
133
|
placeholder='Enter your prompt here'
|
|
169
134
|
autoSize={{ minRows: 3, maxRows: 10 }}
|
|
170
135
|
disabled={isLoading}
|
|
136
|
+
className='ai-chat-textarea'
|
|
171
137
|
/>
|
|
172
138
|
<Flex className='ai-chat-terminals' justify='space-between' align='center'>
|
|
173
139
|
<Flex align='center'>
|
|
@@ -188,7 +154,6 @@ export default function AIChat (props) {
|
|
|
188
154
|
<HelpIcon
|
|
189
155
|
link={aiConfigWikiLink}
|
|
190
156
|
/>
|
|
191
|
-
{renderConfig()}
|
|
192
157
|
</Flex>
|
|
193
158
|
{renderSendIcon()}
|
|
194
159
|
</Flex>
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
Input,
|
|
4
4
|
Button,
|
|
5
5
|
AutoComplete,
|
|
6
|
-
Modal,
|
|
7
6
|
Alert,
|
|
8
7
|
Space
|
|
9
8
|
} from 'antd'
|
|
10
9
|
import { useEffect, useState } from 'react'
|
|
11
10
|
import Link from '../common/external-link'
|
|
11
|
+
import AiCache from './ai-cache'
|
|
12
12
|
import {
|
|
13
13
|
aiConfigWikiLink
|
|
14
14
|
} from '../../common/constants'
|
|
@@ -61,10 +61,6 @@ export default function AIConfigForm ({ initialValues, onSubmit, showAIConfig })
|
|
|
61
61
|
onSubmit(values)
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
function handleCancel () {
|
|
65
|
-
window.store.toggleAIConfig()
|
|
66
|
-
}
|
|
67
|
-
|
|
68
64
|
function handleChange (v) {
|
|
69
65
|
const options = getModelOptions(v)
|
|
70
66
|
setModelOptions(options)
|
|
@@ -76,16 +72,9 @@ export default function AIConfigForm ({ initialValues, onSubmit, showAIConfig })
|
|
|
76
72
|
if (!showAIConfig) {
|
|
77
73
|
return null
|
|
78
74
|
}
|
|
79
|
-
const title = 'AI ' + e('setting')
|
|
80
75
|
const defaultLangs = window.store.getLangNames().map(l => ({ value: l }))
|
|
81
76
|
return (
|
|
82
|
-
|
|
83
|
-
title={title}
|
|
84
|
-
open
|
|
85
|
-
onCancel={handleCancel}
|
|
86
|
-
footer={null}
|
|
87
|
-
width='90%'
|
|
88
|
-
>
|
|
77
|
+
<>
|
|
89
78
|
<Alert
|
|
90
79
|
message={
|
|
91
80
|
<Link to={aiConfigWikiLink}>WIKI: {aiConfigWikiLink}</Link>
|
|
@@ -98,6 +87,7 @@ export default function AIConfigForm ({ initialValues, onSubmit, showAIConfig })
|
|
|
98
87
|
onFinish={handleSubmit}
|
|
99
88
|
initialValues={initialValues}
|
|
100
89
|
layout='vertical'
|
|
90
|
+
className='ai-config-form'
|
|
101
91
|
>
|
|
102
92
|
<Form.Item label='API URL' required>
|
|
103
93
|
<Space.Compact block>
|
|
@@ -181,6 +171,7 @@ export default function AIConfigForm ({ initialValues, onSubmit, showAIConfig })
|
|
|
181
171
|
</Button>
|
|
182
172
|
</Form.Item>
|
|
183
173
|
</Form>
|
|
184
|
-
|
|
174
|
+
<AiCache />
|
|
175
|
+
</>
|
|
185
176
|
)
|
|
186
177
|
}
|
|
@@ -3,12 +3,12 @@ export default [
|
|
|
3
3
|
label: 'OpenAI',
|
|
4
4
|
baseURL: 'https://api.openai.com/v1',
|
|
5
5
|
homepage: 'https://openai.com',
|
|
6
|
-
models: ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k']
|
|
6
|
+
models: ['gpt-4', 'gpt-3.5-turbo', 'gpt-3.5-turbo-16k', 'gpt-4.5']
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
9
|
label: 'DeepSeek',
|
|
10
10
|
baseURL: 'https://api.deepseek.com/v1',
|
|
11
11
|
homepage: 'https://deepseek.com',
|
|
12
|
-
models: ['deepseek-chat', 'deepseek-coder']
|
|
12
|
+
models: ['deepseek-chat', 'deepseek-coder', 'deepseek-reasoner']
|
|
13
13
|
}
|
|
14
14
|
]
|
|
@@ -6,7 +6,7 @@ export const BatchOp = lazy(() => import('./batch-op'))
|
|
|
6
6
|
// Wrap BatchOp with Suspense
|
|
7
7
|
export default function BatchOpEntry (props) {
|
|
8
8
|
return (
|
|
9
|
-
<Suspense fallback={
|
|
9
|
+
<Suspense fallback={<>Loading...</>}>
|
|
10
10
|
<BatchOp {...props} />
|
|
11
11
|
</Suspense>
|
|
12
12
|
)
|
|
@@ -479,7 +479,7 @@ export default class BatchOp extends PureComponent {
|
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
return (
|
|
482
|
-
|
|
482
|
+
<>
|
|
483
483
|
<div className='pd1y'>
|
|
484
484
|
<h2>
|
|
485
485
|
{e('batchOperation')}
|
|
@@ -555,7 +555,7 @@ export default class BatchOp extends PureComponent {
|
|
|
555
555
|
<div className='pd1y'>
|
|
556
556
|
{this.renderTables()}
|
|
557
557
|
</div>
|
|
558
|
-
|
|
558
|
+
</>
|
|
559
559
|
)
|
|
560
560
|
}
|
|
561
561
|
|
|
@@ -61,7 +61,7 @@ export default function renderCommon (props) {
|
|
|
61
61
|
})
|
|
62
62
|
}
|
|
63
63
|
return (
|
|
64
|
-
|
|
64
|
+
<>
|
|
65
65
|
<FormItem
|
|
66
66
|
{...formItemLayout}
|
|
67
67
|
label={e('host')}
|
|
@@ -84,7 +84,6 @@ export default function renderCommon (props) {
|
|
|
84
84
|
}
|
|
85
85
|
<FormItem noStyle name='host'>
|
|
86
86
|
<InputAutoFocus
|
|
87
|
-
selectall='yes'
|
|
88
87
|
name='host'
|
|
89
88
|
onBlur={props.onBlur}
|
|
90
89
|
onPaste={e => props.onPaste(e, form)}
|
|
@@ -223,6 +222,6 @@ export default function renderCommon (props) {
|
|
|
223
222
|
}
|
|
224
223
|
</Select>
|
|
225
224
|
</FormItem>
|
|
226
|
-
|
|
225
|
+
</>
|
|
227
226
|
)
|
|
228
227
|
}
|
|
@@ -30,12 +30,12 @@ export default function renderTabs (props) {
|
|
|
30
30
|
label: e('settings'),
|
|
31
31
|
forceRender: true,
|
|
32
32
|
children: (
|
|
33
|
-
|
|
33
|
+
<>
|
|
34
34
|
{props.renderEnableSftp()}
|
|
35
35
|
{props.uis}
|
|
36
36
|
{props.renderProxy(props)}
|
|
37
37
|
{props.renderX11()}
|
|
38
|
-
|
|
38
|
+
</>
|
|
39
39
|
)
|
|
40
40
|
},
|
|
41
41
|
{
|
|
@@ -169,7 +169,7 @@ export default function renderConnectionHopping (props) {
|
|
|
169
169
|
onSelect: handleFinish
|
|
170
170
|
}
|
|
171
171
|
return (
|
|
172
|
-
|
|
172
|
+
<>
|
|
173
173
|
<FormItem
|
|
174
174
|
name='connectionHoppings'
|
|
175
175
|
className='hide'
|
|
@@ -269,6 +269,6 @@ export default function renderConnectionHopping (props) {
|
|
|
269
269
|
</Button>
|
|
270
270
|
</FormItem>
|
|
271
271
|
</Form>
|
|
272
|
-
|
|
272
|
+
</>
|
|
273
273
|
)
|
|
274
274
|
}
|
|
@@ -15,7 +15,7 @@ const e = window.translate
|
|
|
15
15
|
export default function renderRunScripts () {
|
|
16
16
|
function renderItem (field, i, add, remove) {
|
|
17
17
|
return (
|
|
18
|
-
|
|
18
|
+
<>
|
|
19
19
|
<Space
|
|
20
20
|
align='center'
|
|
21
21
|
key={field.key}
|
|
@@ -51,7 +51,7 @@ export default function renderRunScripts () {
|
|
|
51
51
|
className='mg24b'
|
|
52
52
|
/>
|
|
53
53
|
</Space>
|
|
54
|
-
|
|
54
|
+
</>
|
|
55
55
|
)
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -63,7 +63,7 @@ export default function renderRunScripts () {
|
|
|
63
63
|
{
|
|
64
64
|
(fields, { add, remove }, { errors }) => {
|
|
65
65
|
return (
|
|
66
|
-
|
|
66
|
+
<>
|
|
67
67
|
{
|
|
68
68
|
fields.map((field, i) => {
|
|
69
69
|
return renderItem(field, i, add, remove)
|
|
@@ -79,7 +79,7 @@ export default function renderRunScripts () {
|
|
|
79
79
|
{e('loginScript')}
|
|
80
80
|
</Button>
|
|
81
81
|
</FormItem>
|
|
82
|
-
|
|
82
|
+
</>
|
|
83
83
|
)
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -197,7 +197,7 @@ export default function renderSshTunnels (props) {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
return (
|
|
200
|
-
|
|
200
|
+
<>
|
|
201
201
|
<FormItem
|
|
202
202
|
name='sshTunnels'
|
|
203
203
|
className='hide'
|
|
@@ -291,6 +291,6 @@ export default function renderSshTunnels (props) {
|
|
|
291
291
|
</Button>
|
|
292
292
|
</FormItem>
|
|
293
293
|
</Form>
|
|
294
|
-
|
|
294
|
+
</>
|
|
295
295
|
)
|
|
296
296
|
}
|
|
@@ -19,6 +19,15 @@ export default function renderEnableSftp () {
|
|
|
19
19
|
>
|
|
20
20
|
<Switch />
|
|
21
21
|
</FormItem>,
|
|
22
|
+
<FormItem
|
|
23
|
+
{...formItemLayout}
|
|
24
|
+
label='SFTP'
|
|
25
|
+
name='enableSftp'
|
|
26
|
+
key='sftp'
|
|
27
|
+
valuePropName='checked'
|
|
28
|
+
>
|
|
29
|
+
<Switch />
|
|
30
|
+
</FormItem>,
|
|
22
31
|
<FormItem
|
|
23
32
|
{...formItemLayout}
|
|
24
33
|
label={e('ignoreKeyboardInteractive')}
|
|
@@ -237,6 +237,9 @@ export default class BookmarkForm extends PureComponent {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
handleSubmit = async (evt, res, isTest = false) => {
|
|
240
|
+
if (res.enableSsh === false && res.enableSftp === false) {
|
|
241
|
+
return message.warning('SSH and SFTP all disabled')
|
|
242
|
+
}
|
|
240
243
|
const obj = {
|
|
241
244
|
...this.props.formData,
|
|
242
245
|
...res
|
|
@@ -57,7 +57,7 @@ export default function useQuickCmds (form, formData) {
|
|
|
57
57
|
{
|
|
58
58
|
(fields, { add, remove }, { errors }) => {
|
|
59
59
|
return (
|
|
60
|
-
|
|
60
|
+
<>
|
|
61
61
|
{
|
|
62
62
|
fields.map((field, i) => {
|
|
63
63
|
return renderItem(field, i, add, remove)
|
|
@@ -73,7 +73,7 @@ export default function useQuickCmds (form, formData) {
|
|
|
73
73
|
{e('newQuickCommand')}
|
|
74
74
|
</Button>
|
|
75
75
|
</FormItem>
|
|
76
|
-
|
|
76
|
+
</>
|
|
77
77
|
)
|
|
78
78
|
}
|
|
79
79
|
}
|
|
@@ -3,21 +3,90 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
5
|
Switch,
|
|
6
|
-
Form
|
|
6
|
+
Form,
|
|
7
|
+
Select
|
|
7
8
|
} from 'antd'
|
|
8
9
|
import { formItemLayout } from '../../common/form-layout'
|
|
9
10
|
|
|
10
11
|
const FormItem = Form.Item
|
|
12
|
+
const { Option } = Select
|
|
13
|
+
|
|
14
|
+
// Available cipher options from ssh2-alg.js
|
|
15
|
+
const cipherOptions = [
|
|
16
|
+
'aes128-ctr',
|
|
17
|
+
'aes192-ctr',
|
|
18
|
+
'aes256-ctr',
|
|
19
|
+
'aes128-gcm',
|
|
20
|
+
'aes128-gcm@openssh.com',
|
|
21
|
+
'aes256-gcm',
|
|
22
|
+
'aes256-gcm@openssh.com',
|
|
23
|
+
'aes256-cbc',
|
|
24
|
+
'aes192-cbc',
|
|
25
|
+
'aes128-cbc',
|
|
26
|
+
'blowfish-cbc',
|
|
27
|
+
'3des-cbc',
|
|
28
|
+
'arcfour256',
|
|
29
|
+
'arcfour128',
|
|
30
|
+
'cast128-cbc',
|
|
31
|
+
'arcfour',
|
|
32
|
+
'chacha20-poly1305@openssh.com',
|
|
33
|
+
'umac-128-etm@openssh.com',
|
|
34
|
+
'curve25519-sha256@libssh.org'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
// Available serverHostKey options from ssh2-alg.js
|
|
38
|
+
const serverHostKeyOptions = [
|
|
39
|
+
'ssh-rsa',
|
|
40
|
+
'ssh-ed25519',
|
|
41
|
+
'ecdsa-sha2-nistp256',
|
|
42
|
+
'ecdsa-sha2-nistp384',
|
|
43
|
+
'ecdsa-sha2-nistp521',
|
|
44
|
+
'ssh-dss',
|
|
45
|
+
'rsa-sha2-512',
|
|
46
|
+
'rsa-sha2-256'
|
|
47
|
+
]
|
|
11
48
|
|
|
12
49
|
export default function renderX11 () {
|
|
13
50
|
return (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
51
|
+
<>
|
|
52
|
+
<FormItem
|
|
53
|
+
{...formItemLayout}
|
|
54
|
+
label='cipher'
|
|
55
|
+
name='cipher'
|
|
56
|
+
>
|
|
57
|
+
<Select
|
|
58
|
+
mode='multiple'
|
|
59
|
+
>
|
|
60
|
+
{cipherOptions.map(cipher => (
|
|
61
|
+
<Option key={cipher} value={cipher}>
|
|
62
|
+
{cipher}
|
|
63
|
+
</Option>
|
|
64
|
+
))}
|
|
65
|
+
</Select>
|
|
66
|
+
</FormItem>
|
|
67
|
+
<FormItem
|
|
68
|
+
{...formItemLayout}
|
|
69
|
+
label='serverHostKey'
|
|
70
|
+
name='serverHostKey'
|
|
71
|
+
>
|
|
72
|
+
<Select
|
|
73
|
+
mode='multiple'
|
|
74
|
+
>
|
|
75
|
+
{serverHostKeyOptions.map(key => (
|
|
76
|
+
<Option key={key} value={key}>
|
|
77
|
+
{key}
|
|
78
|
+
</Option>
|
|
79
|
+
))}
|
|
80
|
+
</Select>
|
|
81
|
+
</FormItem>
|
|
82
|
+
<FormItem
|
|
83
|
+
{...formItemLayout}
|
|
84
|
+
label='x11'
|
|
85
|
+
name='x11'
|
|
86
|
+
valuePropName='checked'
|
|
87
|
+
>
|
|
88
|
+
<Switch />
|
|
89
|
+
</FormItem>
|
|
90
|
+
</>
|
|
22
91
|
)
|
|
23
92
|
}
|