@electerm/electerm-react 5.0.8 → 5.1.7
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 +2 -1
- package/client/common/constants.js +2 -0
- package/client/common/default-setting.js +10 -1
- package/client/common/left-sidebar-icon-defs.js +36 -0
- package/client/common/parse-json-safe.js +7 -3
- package/client/components/ai/ai-config-props.js +8 -0
- package/client/components/bookmark-form/common/fields.jsx +3 -2
- package/client/components/bookmark-form/common/ssh-agent.jsx +3 -2
- package/client/components/bookmark-form/common/x11.jsx +2 -2
- package/client/components/common/switch.jsx +63 -0
- package/client/components/common/switch.styl +7 -0
- package/client/components/footer/cmd-history.jsx +4 -8
- package/client/components/layout/layout.jsx +8 -5
- package/client/components/main/main.jsx +7 -2
- package/client/components/profile/profile-form-elem.jsx +2 -2
- package/client/components/quick-commands/quick-commands-form-elem.jsx +2 -2
- package/client/components/rdp/rdp-session.jsx +3 -4
- package/client/components/setting-panel/setting-common.jsx +9 -5
- package/client/components/setting-panel/setting-left-sidebar-icons.jsx +54 -0
- package/client/components/setting-panel/setting-terminal.jsx +3 -4
- package/client/components/setting-sync/data-import.jsx +3 -4
- package/client/components/setting-sync/setting-sync-form.jsx +3 -2
- package/client/components/sftp/file-compare-modal.jsx +1 -1
- package/client/components/sidebar/history.jsx +3 -8
- package/client/components/sidebar/index.jsx +22 -71
- package/client/components/sidebar/left-sidebar-icons.jsx +148 -0
- package/client/components/sidebar/transfer-list.jsx +1 -1
- package/client/components/spice/spice-session.jsx +4 -5
- package/client/components/terminal/shortcut-bar-defs.js +131 -0
- package/client/components/terminal/shortcut-bar-edit.jsx +205 -0
- package/client/components/terminal/shortcut-bar-entry.jsx +34 -0
- package/client/components/terminal/shortcut-bar.jsx +150 -0
- package/client/components/terminal/shortcut-bar.styl +186 -0
- package/client/components/terminal/terminal-color-query.mjs +47 -0
- package/client/components/terminal/terminal.jsx +39 -1
- package/client/components/terminal/terminal.styl +8 -0
- package/client/components/terminal-info/base.jsx +5 -7
- package/client/components/widgets/widget-form.jsx +3 -2
- package/client/store/init-state.js +3 -0
- package/client/store/mcp-handler.js +29 -1
- package/package.json +1 -1
package/client/common/cache.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// we persist cache to local storage, so we can keep cache after restart
|
|
4
4
|
|
|
5
5
|
import { safeGetItem, safeSetItem } from './safe-local-storage.js'
|
|
6
|
+
import safeParse from './parse-json-safe.js'
|
|
6
7
|
|
|
7
8
|
class MapCache {
|
|
8
9
|
constructor (limit, key) {
|
|
@@ -15,7 +16,7 @@ class MapCache {
|
|
|
15
16
|
load () {
|
|
16
17
|
const data = safeGetItem(this.key)
|
|
17
18
|
if (data) {
|
|
18
|
-
const arr =
|
|
19
|
+
const arr = safeParse(data, [])
|
|
19
20
|
for (const item of arr) {
|
|
20
21
|
this.cache.set(item.key, item.value)
|
|
21
22
|
}
|
|
@@ -79,6 +79,8 @@ export const authTypeMap = buildConst([
|
|
|
79
79
|
|
|
80
80
|
export const footerHeight = 36
|
|
81
81
|
export const quickCommandBoxHeight = 180
|
|
82
|
+
export const shortcutBarHeight = 44
|
|
83
|
+
export const shortcutBarLsKey = 'shortcut-bar-buttons'
|
|
82
84
|
export const isWin = typeof window.et.isWin === 'undefined' ? window.pre.isWin : window.et.isWin
|
|
83
85
|
export const isMac = typeof window.et.isMac === 'undefined' ? window.pre.isMac : window.et.isMac
|
|
84
86
|
export const isMacJs = /Macintosh|Mac|Mac OS|MacIntel|MacPPC|Mac68K/gi.test(window.navigator.userAgent)
|
|
@@ -79,5 +79,14 @@ export default {
|
|
|
79
79
|
allowMultiInstance: false,
|
|
80
80
|
disableDeveloperTool: false,
|
|
81
81
|
dragDropBehavior: 'ask',
|
|
82
|
-
switchTabOnHover: false
|
|
82
|
+
switchTabOnHover: false,
|
|
83
|
+
leftSideBarIcons: [
|
|
84
|
+
'newBookmark',
|
|
85
|
+
'quickConnect',
|
|
86
|
+
'bookmarks',
|
|
87
|
+
'terminalThemes',
|
|
88
|
+
'setting',
|
|
89
|
+
'settingSync',
|
|
90
|
+
'widgets'
|
|
91
|
+
]
|
|
83
92
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* customizable icons for the far-left sidebar.
|
|
3
|
+
*
|
|
4
|
+
* `text` is a locale key passed to window.translate. The "about",
|
|
5
|
+
* "hide sidebar" and "file transfer" icons are intentionally excluded —
|
|
6
|
+
* they are always visible / conditionally rendered and not part of the
|
|
7
|
+
* customizable set.
|
|
8
|
+
*
|
|
9
|
+
* order of `leftSidebarIconOptions` is the default order shown in the sidebar.
|
|
10
|
+
*/
|
|
11
|
+
export const leftSidebarIconOptions = [
|
|
12
|
+
{ id: 'newBookmark', text: 'newBookmark' },
|
|
13
|
+
{ id: 'quickConnect', text: 'quickConnect' },
|
|
14
|
+
{ id: 'bookmarks', text: 'bookmarks' },
|
|
15
|
+
{ id: 'terminalThemes', text: 'terminalThemes' },
|
|
16
|
+
{ id: 'setting', text: 'setting' },
|
|
17
|
+
{ id: 'settingSync', text: 'settingSync' },
|
|
18
|
+
{ id: 'widgets', text: 'widgets' }
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
// default ordered list of icon ids — mirrors the order above
|
|
22
|
+
export const defaultLeftSideBarIcons = leftSidebarIconOptions.map(o => o.id)
|
|
23
|
+
|
|
24
|
+
// valid ids, for sanitizing persisted/synced config
|
|
25
|
+
export const leftSidebarIconIds = new Set(leftSidebarIconOptions.map(o => o.id))
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* returns a clean, ordered list of icon ids from a possibly-untrusted value:
|
|
29
|
+
* unknown ids dropped, missing default ids left to the user's choice.
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeLeftSideBarIcons (value) {
|
|
32
|
+
if (!Array.isArray(value)) {
|
|
33
|
+
return [...defaultLeftSideBarIcons]
|
|
34
|
+
}
|
|
35
|
+
return value.filter(id => leftSidebarIconIds.has(id))
|
|
36
|
+
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* safe parse json
|
|
3
|
+
* @param {string} str
|
|
4
|
+
* @param defaultValue value returned when parse fails or str is empty/null.
|
|
5
|
+
* Falls back to the original str when not provided.
|
|
3
6
|
*/
|
|
4
|
-
export default str => {
|
|
7
|
+
export default (str, defaultValue) => {
|
|
8
|
+
const hasDefault = defaultValue !== undefined
|
|
5
9
|
if (str === '' || str == null) {
|
|
6
|
-
return str
|
|
10
|
+
return hasDefault ? defaultValue : str
|
|
7
11
|
}
|
|
8
12
|
try {
|
|
9
13
|
return JSON.parse(str)
|
|
10
14
|
} catch (e) {
|
|
11
15
|
console.error('JSON.parse fails', e.stack)
|
|
12
|
-
return str
|
|
16
|
+
return hasDefault ? defaultValue : str
|
|
13
17
|
}
|
|
14
18
|
}
|
|
@@ -19,6 +19,14 @@ export const defaultAIPresets = [
|
|
|
19
19
|
modelAI: 'deepseek-ai/deepseek-v4-flash',
|
|
20
20
|
authHeaderNameAI: 'Authorization: Bearer'
|
|
21
21
|
},
|
|
22
|
+
{
|
|
23
|
+
id: 'ApiSmart',
|
|
24
|
+
nameAI: 'ApiSmart',
|
|
25
|
+
baseURLAI: 'https://api.apismart.ai/v1',
|
|
26
|
+
apiPathAI: '/chat/completions',
|
|
27
|
+
modelAI: 'DEEPSEEK_V4_FLASH',
|
|
28
|
+
authHeaderNameAI: 'Authorization: Bearer'
|
|
29
|
+
},
|
|
22
30
|
{
|
|
23
31
|
id: 'deepseek',
|
|
24
32
|
nameAI: 'DeepSeek',
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
* Maps field types to React components
|
|
4
4
|
*/
|
|
5
5
|
import React from 'react'
|
|
6
|
-
import { Form, Input, InputNumber,
|
|
6
|
+
import { Form, Input, InputNumber, Select, AutoComplete, Alert, Radio } from 'antd'
|
|
7
7
|
import { ColorPickerItem } from './color-picker-item.jsx'
|
|
8
8
|
import Password from '../../common/password.jsx'
|
|
9
|
+
import SwitchLabel from '../../common/switch.jsx'
|
|
9
10
|
import InputAutoFocus from '../../common/input-auto-focus.jsx'
|
|
10
11
|
import ProxyField from './proxy.jsx'
|
|
11
12
|
import X11Field from './x11.jsx'
|
|
@@ -66,7 +67,7 @@ export function renderFormItem (item, formItemLayout, form, ctxProps, index) {
|
|
|
66
67
|
control = <InputNumber min={1} max={65535} step={1} {...item.props} />
|
|
67
68
|
break
|
|
68
69
|
case 'switch':
|
|
69
|
-
control = <
|
|
70
|
+
control = <SwitchLabel {...item.props} />
|
|
70
71
|
break
|
|
71
72
|
case 'select':
|
|
72
73
|
control = <Select options={item.options} {...item.props} />
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { Form, Input,
|
|
2
|
+
import { Form, Input, Space } from 'antd'
|
|
3
|
+
import SwitchLabel from '../../common/switch'
|
|
3
4
|
import HelpIcon from '../../common/help-icon'
|
|
4
5
|
import { formItemLayout } from '../../../common/form-layout'
|
|
5
6
|
|
|
@@ -18,7 +19,7 @@ export default function SshAgent () {
|
|
|
18
19
|
valuePropName='checked'
|
|
19
20
|
noStyle
|
|
20
21
|
>
|
|
21
|
-
<
|
|
22
|
+
<SwitchLabel />
|
|
22
23
|
</FormItem>
|
|
23
24
|
<FormItem
|
|
24
25
|
name='sshAgent'
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* bookmark form
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
-
Switch,
|
|
6
5
|
Form,
|
|
7
6
|
Button,
|
|
8
7
|
Select
|
|
9
8
|
} from 'antd'
|
|
9
|
+
import SwitchLabel from '../../common/switch'
|
|
10
10
|
import { formItemLayout } from '../../../common/form-layout'
|
|
11
11
|
|
|
12
12
|
const FormItem = Form.Item
|
|
@@ -153,7 +153,7 @@ export default function renderX11 ({ form }) {
|
|
|
153
153
|
name='x11'
|
|
154
154
|
valuePropName='checked'
|
|
155
155
|
>
|
|
156
|
-
<
|
|
156
|
+
<SwitchLabel />
|
|
157
157
|
</FormItem>
|
|
158
158
|
</>
|
|
159
159
|
)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* antd Switch wrapper.
|
|
3
|
+
*
|
|
4
|
+
* `checkedChildren` / `unCheckedChildren` cram the label text inside the
|
|
5
|
+
* toggle, which renders poorly on small / touch screens. This wrapper drops
|
|
6
|
+
* those props and renders an optional text label as a sibling `<span>`
|
|
7
|
+
* instead. Clicking the label toggles the switch by default.
|
|
8
|
+
*
|
|
9
|
+
* Passes every other prop (checked, onChange, size, disabled, ref, ...) through
|
|
10
|
+
* to the underlying antd Switch, so it is a drop-in replacement and is safe
|
|
11
|
+
* inside antd Form.Item (`valuePropName='checked'`).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { memo } from 'react'
|
|
15
|
+
import { Switch } from 'antd'
|
|
16
|
+
import './switch.styl'
|
|
17
|
+
|
|
18
|
+
function SwitchLabel (props) {
|
|
19
|
+
const {
|
|
20
|
+
label,
|
|
21
|
+
labelPosition = 'after',
|
|
22
|
+
labelClickToggle = true,
|
|
23
|
+
className = '',
|
|
24
|
+
labelClassName = '',
|
|
25
|
+
checked,
|
|
26
|
+
onChange,
|
|
27
|
+
ref,
|
|
28
|
+
...rest
|
|
29
|
+
} = props
|
|
30
|
+
const hasLabel = label !== undefined && label !== null && label !== ''
|
|
31
|
+
const onLabelClick = labelClickToggle && onChange
|
|
32
|
+
? () => onChange(!checked)
|
|
33
|
+
: undefined
|
|
34
|
+
const labelEl = hasLabel
|
|
35
|
+
? (
|
|
36
|
+
<span
|
|
37
|
+
className={
|
|
38
|
+
'switch-label-text' +
|
|
39
|
+
(labelPosition === 'before' ? ' mg1r' : ' mg1l') +
|
|
40
|
+
(labelClickToggle ? ' pointer' : '') +
|
|
41
|
+
(labelClassName ? ' ' + labelClassName : '')
|
|
42
|
+
}
|
|
43
|
+
onClick={onLabelClick}
|
|
44
|
+
>
|
|
45
|
+
{label}
|
|
46
|
+
</span>
|
|
47
|
+
)
|
|
48
|
+
: null
|
|
49
|
+
return (
|
|
50
|
+
<span className={'switch-label-wrap' + (className ? ' ' + className : '')}>
|
|
51
|
+
{labelPosition === 'before' ? labelEl : null}
|
|
52
|
+
<Switch
|
|
53
|
+
checked={checked}
|
|
54
|
+
onChange={onChange}
|
|
55
|
+
ref={ref}
|
|
56
|
+
{...rest}
|
|
57
|
+
/>
|
|
58
|
+
{labelPosition === 'after' ? labelEl : null}
|
|
59
|
+
</span>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default memo(SwitchLabel)
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { useState, useEffect } from 'react'
|
|
6
|
-
import { Button, Empty, Popover
|
|
6
|
+
import { Button, Empty, Popover } from 'antd'
|
|
7
7
|
import { auto } from 'manate/react'
|
|
8
|
+
import SwitchLabel from '../common/switch'
|
|
8
9
|
import { copy } from '../../common/clipboard'
|
|
9
10
|
import { HistoryOutlined, DeleteOutlined, CopyOutlined, UnorderedListOutlined } from '@ant-design/icons'
|
|
10
11
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
@@ -112,17 +113,12 @@ export default auto(function CmdHistory (props) {
|
|
|
112
113
|
return (
|
|
113
114
|
<div className='cmd-history-header pd2b'>
|
|
114
115
|
<div className='cmd-history-sort'>
|
|
115
|
-
<
|
|
116
|
+
<SwitchLabel
|
|
116
117
|
checked={sortByFrequency}
|
|
117
118
|
onChange={handleSortByFrequencyChange}
|
|
118
119
|
size='small'
|
|
120
|
+
label={e('sortByFrequency')}
|
|
119
121
|
/>
|
|
120
|
-
<span
|
|
121
|
-
className='cmd-history-sort-label pointer'
|
|
122
|
-
onClick={() => handleSortByFrequencyChange(!sortByFrequency)}
|
|
123
|
-
>
|
|
124
|
-
{e('sortByFrequency')}
|
|
125
|
-
</span>
|
|
126
122
|
</div>
|
|
127
123
|
<UnorderedListOutlined
|
|
128
124
|
className='cmd-history-clear-icon pointer clear-ai-icon icon-hover'
|
|
@@ -4,7 +4,8 @@ import TabsWrap from '../tabs/index'
|
|
|
4
4
|
import {
|
|
5
5
|
splitConfig,
|
|
6
6
|
quickCommandBoxHeight,
|
|
7
|
-
footerHeight
|
|
7
|
+
footerHeight,
|
|
8
|
+
shortcutBarHeight
|
|
8
9
|
} from '../../common/constants'
|
|
9
10
|
import layoutAlg from './layout-alg'
|
|
10
11
|
import calcSessionSize from './session-size-alg'
|
|
@@ -41,9 +42,10 @@ export default auto(function Layout (props) {
|
|
|
41
42
|
rightPanelPinned,
|
|
42
43
|
rightPanelWidth,
|
|
43
44
|
resizeTrigger,
|
|
44
|
-
inActiveTerminal
|
|
45
|
+
inActiveTerminal,
|
|
46
|
+
shortcutBarVisible
|
|
45
47
|
} = props.store
|
|
46
|
-
const h = height - footerHeight - (inActiveTerminal && pinnedQuickCommandBar ? quickCommandBoxHeight : 0) + resizeTrigger
|
|
48
|
+
const h = height - footerHeight - (inActiveTerminal && pinnedQuickCommandBar ? quickCommandBoxHeight : 0) - (shortcutBarVisible ? shortcutBarHeight : 0) + resizeTrigger
|
|
47
49
|
const l = pinned ? leftSideBarWidth + leftSidePanelWidth : leftSideBarWidth
|
|
48
50
|
const r = rightPanelVisible && rightPanelPinned ? rightPanelWidth : 0
|
|
49
51
|
return {
|
|
@@ -65,14 +67,15 @@ export default auto(function Layout (props) {
|
|
|
65
67
|
rightPanelVisible,
|
|
66
68
|
rightPanelPinned,
|
|
67
69
|
rightPanelWidth,
|
|
68
|
-
pinned
|
|
70
|
+
pinned,
|
|
71
|
+
shortcutBarVisible
|
|
69
72
|
} = props.store
|
|
70
73
|
const l = pinned ? leftSidePanelWidth : 0
|
|
71
74
|
const r = rightPanelPinned && rightPanelVisible ? rightPanelWidth : 0
|
|
72
75
|
// account for the far-left icon bar (sidebarWidth - 1px border on desktop;
|
|
73
76
|
// 0 when the bar is hidden on mobile)
|
|
74
77
|
const w = width - l - r - (leftSideBarWidth > 0 ? leftSideBarWidth - 1 : 0)
|
|
75
|
-
const h = height - footerHeight - (pinnedQuickCommandBar ? quickCommandBoxHeight : 0)
|
|
78
|
+
const h = height - footerHeight - (pinnedQuickCommandBar ? quickCommandBoxHeight : 0) - (shortcutBarVisible ? shortcutBarHeight : 0)
|
|
76
79
|
return layoutAlg(layout, w, h)
|
|
77
80
|
}
|
|
78
81
|
const layoutSize = calcLayoutStyle()
|
|
@@ -42,6 +42,7 @@ import { pick } from 'lodash-es'
|
|
|
42
42
|
import deepCopy from 'json-deep-copy'
|
|
43
43
|
import './wrapper.styl'
|
|
44
44
|
import TerminalInfo from '../terminal-info/terminal-info-entry'
|
|
45
|
+
import ShortcutBarEntry from '../terminal/shortcut-bar-entry'
|
|
45
46
|
import '../../common/fs.js'
|
|
46
47
|
import './term-fullscreen.styl'
|
|
47
48
|
|
|
@@ -99,7 +100,8 @@ export default auto(function Index (props) {
|
|
|
99
100
|
transferToConfirm,
|
|
100
101
|
openResolutionEdit,
|
|
101
102
|
rightPanelTitle,
|
|
102
|
-
rightPanelTab
|
|
103
|
+
rightPanelTab,
|
|
104
|
+
widgetInstances
|
|
103
105
|
} = store
|
|
104
106
|
const upgradeInfo = deepCopy(store.upgradeInfo)
|
|
105
107
|
const cls = classnames({
|
|
@@ -181,7 +183,9 @@ export default auto(function Index (props) {
|
|
|
181
183
|
fileTransfers: copiedTransfer,
|
|
182
184
|
transferHistory: copiedHistory,
|
|
183
185
|
upgradeInfo,
|
|
184
|
-
pinned
|
|
186
|
+
pinned,
|
|
187
|
+
leftSideBarIcons: config.leftSideBarIcons,
|
|
188
|
+
widgetInstancesLength: widgetInstances.length
|
|
185
189
|
}
|
|
186
190
|
|
|
187
191
|
const infoModalProps = {
|
|
@@ -311,6 +315,7 @@ export default auto(function Index (props) {
|
|
|
311
315
|
<BookmarkFromHistoryModal />
|
|
312
316
|
<NotificationContainer />
|
|
313
317
|
<BatchOpRunner />
|
|
318
|
+
<ShortcutBarEntry store={store} />
|
|
314
319
|
{!isAIDisabled() && <AIConfigModal store={store} />}
|
|
315
320
|
<UnixTimestampTooltip />
|
|
316
321
|
</div>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
Form,
|
|
4
|
-
Switch,
|
|
5
4
|
Button
|
|
6
5
|
} from 'antd'
|
|
7
6
|
import message from '../common/message'
|
|
7
|
+
import SwitchLabel from '../common/switch'
|
|
8
8
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
9
9
|
import { formItemLayout } from '../../common/form-layout'
|
|
10
10
|
import HelpIcon from '../common/help-icon'
|
|
@@ -90,7 +90,7 @@ export default function ProfileFormElem (props) {
|
|
|
90
90
|
name='isDefault'
|
|
91
91
|
valuePropName='checked'
|
|
92
92
|
>
|
|
93
|
-
<
|
|
93
|
+
<SwitchLabel />
|
|
94
94
|
</FormItem>
|
|
95
95
|
<ProfileTabs {...tabsProps} />
|
|
96
96
|
<FormItem>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Button,
|
|
3
|
-
Switch,
|
|
4
3
|
Form,
|
|
5
4
|
Select,
|
|
6
5
|
Input
|
|
7
6
|
} from 'antd'
|
|
8
7
|
import message from '../common/message'
|
|
8
|
+
import SwitchLabel from '../common/switch'
|
|
9
9
|
import { useState } from 'react'
|
|
10
10
|
import generate from '../../common/uid'
|
|
11
11
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
@@ -162,7 +162,7 @@ export default function QuickCommandForm (props) {
|
|
|
162
162
|
name='inputOnly'
|
|
163
163
|
valuePropName='checked'
|
|
164
164
|
>
|
|
165
|
-
<
|
|
165
|
+
<SwitchLabel />
|
|
166
166
|
</FormItem>
|
|
167
167
|
<FormItem>
|
|
168
168
|
<p>
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
import {
|
|
16
16
|
Spin,
|
|
17
17
|
Select,
|
|
18
|
-
Switch,
|
|
19
18
|
Tooltip
|
|
20
19
|
} from 'antd'
|
|
21
20
|
import * as ls from '../../common/safe-local-storage'
|
|
@@ -23,6 +22,7 @@ import scanCode from './code-scan'
|
|
|
23
22
|
import resolutions from './resolutions'
|
|
24
23
|
import { readClipboardAsync } from '../../common/clipboard'
|
|
25
24
|
import RemoteFloatControl from '../common/remote-float-control'
|
|
25
|
+
import SwitchLabel from '../common/switch'
|
|
26
26
|
import HelpIcon from '../common/help-icon'
|
|
27
27
|
import { FileTransferManager, createFileLogger } from './file-transfer'
|
|
28
28
|
import { notification } from '../common/notification'
|
|
@@ -634,8 +634,7 @@ export default class RdpSession extends PureComponent {
|
|
|
634
634
|
const scaleProps = {
|
|
635
635
|
checked: this.state.scaleViewport,
|
|
636
636
|
onChange: this.handleScaleViewChange,
|
|
637
|
-
|
|
638
|
-
checkedChildren: window.translate('scaleViewport'),
|
|
637
|
+
label: window.translate('scaleViewport'),
|
|
639
638
|
className: 'mg1l'
|
|
640
639
|
}
|
|
641
640
|
const uploadTitle = window.translate('upload') || 'Upload files to remote'
|
|
@@ -671,7 +670,7 @@ export default class RdpSession extends PureComponent {
|
|
|
671
670
|
className='mg2r mg1l pointer'
|
|
672
671
|
/>
|
|
673
672
|
{this.renderInfo()}
|
|
674
|
-
<
|
|
673
|
+
<SwitchLabel
|
|
675
674
|
{...scaleProps}
|
|
676
675
|
/>
|
|
677
676
|
<Tooltip title={uploadTitle}>
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
} from '@ant-design/icons'
|
|
8
8
|
import message from '../common/message'
|
|
9
9
|
import { notification } from '../common/notification'
|
|
10
|
+
import SwitchLabel from '../common/switch'
|
|
10
11
|
import {
|
|
11
12
|
Select,
|
|
12
|
-
Switch,
|
|
13
13
|
Button,
|
|
14
14
|
Table,
|
|
15
15
|
Space,
|
|
@@ -34,6 +34,7 @@ import delay from '../../common/wait.js'
|
|
|
34
34
|
import isColorDark from '../../common/is-color-dark'
|
|
35
35
|
import DeepLinkControl from './deep-link-control'
|
|
36
36
|
import HotkeySetting from './hotkey'
|
|
37
|
+
import SettingLeftSidebarIcons from './setting-left-sidebar-icons'
|
|
37
38
|
import './setting.styl'
|
|
38
39
|
|
|
39
40
|
const { Option } = Select
|
|
@@ -192,10 +193,9 @@ export default class SettingCommon extends Component {
|
|
|
192
193
|
const checked = !!this.props.config[name]
|
|
193
194
|
return (
|
|
194
195
|
<div className='pd2b' key={'rt' + name}>
|
|
195
|
-
<
|
|
196
|
+
<SwitchLabel
|
|
196
197
|
checked={checked}
|
|
197
|
-
|
|
198
|
-
unCheckedChildren={e(name)}
|
|
198
|
+
label={e(name)}
|
|
199
199
|
onChange={v => this.onChangeValue(v, name)}
|
|
200
200
|
/>
|
|
201
201
|
{isNumber(extra) ? null : extra}
|
|
@@ -372,7 +372,7 @@ export default class SettingCommon extends Component {
|
|
|
372
372
|
style={{ body: { style } }}
|
|
373
373
|
/>
|
|
374
374
|
</span>
|
|
375
|
-
<
|
|
375
|
+
<SwitchLabel
|
|
376
376
|
checked={enableGlobalProxy}
|
|
377
377
|
onChange={v => {
|
|
378
378
|
this.onChangeValue(v, 'enableGlobalProxy')
|
|
@@ -471,6 +471,10 @@ export default class SettingCommon extends Component {
|
|
|
471
471
|
return (
|
|
472
472
|
<div className='form-wrap pd1y pd2x'>
|
|
473
473
|
<h2>{e('settings')}</h2>
|
|
474
|
+
<SettingLeftSidebarIcons
|
|
475
|
+
config={props.config}
|
|
476
|
+
store={props.store}
|
|
477
|
+
/>
|
|
474
478
|
<HotkeySetting
|
|
475
479
|
{...hotkeyProps}
|
|
476
480
|
/>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* editor (embedded in the common settings page) for the customizable
|
|
3
|
+
* far-left sidebar icons. The select takes effect immediately — order of the
|
|
4
|
+
* selected ids is the order shown in the sidebar.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Select } from 'antd'
|
|
8
|
+
import {
|
|
9
|
+
leftSidebarIconOptions,
|
|
10
|
+
defaultLeftSideBarIcons
|
|
11
|
+
} from '../../common/left-sidebar-icon-defs'
|
|
12
|
+
|
|
13
|
+
const { Option } = Select
|
|
14
|
+
const e = window.translate
|
|
15
|
+
|
|
16
|
+
export default function SettingLeftSidebarIcons (props) {
|
|
17
|
+
const { config, store } = props
|
|
18
|
+
const value = Array.isArray(config.leftSideBarIcons) && config.leftSideBarIcons.length
|
|
19
|
+
? config.leftSideBarIcons
|
|
20
|
+
: [...defaultLeftSideBarIcons]
|
|
21
|
+
|
|
22
|
+
const handleChange = (v) => {
|
|
23
|
+
store.updateConfig({
|
|
24
|
+
leftSideBarIcons: v
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div className='pd2b'>
|
|
30
|
+
<div className='pd1b'>{e('leftSideBarIcons')}</div>
|
|
31
|
+
<Select
|
|
32
|
+
mode='multiple'
|
|
33
|
+
value={value}
|
|
34
|
+
onChange={handleChange}
|
|
35
|
+
popupMatchSelectWidth={false}
|
|
36
|
+
style={{ minWidth: 320, width: '100%' }}
|
|
37
|
+
placeholder={e('leftSideBarIcons')}
|
|
38
|
+
>
|
|
39
|
+
{
|
|
40
|
+
leftSidebarIconOptions.map(opt => {
|
|
41
|
+
return (
|
|
42
|
+
<Option
|
|
43
|
+
key={opt.id}
|
|
44
|
+
value={opt.id}
|
|
45
|
+
>
|
|
46
|
+
{e(opt.text)}
|
|
47
|
+
</Option>
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
</Select>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
LoadingOutlined
|
|
5
5
|
} from '@ant-design/icons'
|
|
6
6
|
import message from '../common/message'
|
|
7
|
+
import SwitchLabel from '../common/switch'
|
|
7
8
|
import {
|
|
8
9
|
Select,
|
|
9
|
-
Switch,
|
|
10
10
|
Button,
|
|
11
11
|
AutoComplete,
|
|
12
12
|
Tooltip,
|
|
@@ -123,10 +123,9 @@ export default class SettingTerminal extends Component {
|
|
|
123
123
|
const txt = label || e(name)
|
|
124
124
|
return (
|
|
125
125
|
<div className={cls} key={'rt' + name}>
|
|
126
|
-
<
|
|
126
|
+
<SwitchLabel
|
|
127
127
|
checked={checked}
|
|
128
|
-
|
|
129
|
-
unCheckedChildren={txt}
|
|
128
|
+
label={txt}
|
|
130
129
|
onChange={v => this.onChangeValue(v, name)}
|
|
131
130
|
/>
|
|
132
131
|
</div>
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
Button,
|
|
7
|
-
Switch,
|
|
8
7
|
Select,
|
|
9
8
|
Space
|
|
10
9
|
} from 'antd'
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
ExportOutlined
|
|
14
13
|
} from '@ant-design/icons'
|
|
15
14
|
import Upload from '../common/upload'
|
|
15
|
+
import SwitchLabel from '../common/switch'
|
|
16
16
|
import HelpIcon from '../common/help-icon'
|
|
17
17
|
|
|
18
18
|
const e = window.translate
|
|
@@ -87,11 +87,10 @@ export default function DataTransport (props) {
|
|
|
87
87
|
</Upload>
|
|
88
88
|
</div>
|
|
89
89
|
<div className='fright'>
|
|
90
|
-
<
|
|
90
|
+
<SwitchLabel
|
|
91
91
|
checked={autoSyncEnabled}
|
|
92
|
-
|
|
92
|
+
label={txt}
|
|
93
93
|
onChange={handleAutoSync}
|
|
94
|
-
unCheckedChildren={txt}
|
|
95
94
|
className='mg3l mg1r'
|
|
96
95
|
/>
|
|
97
96
|
{autoSyncEnabled && (
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { useEffect, useRef } from 'react'
|
|
9
9
|
import { ArrowDownOutlined, ArrowUpOutlined, SaveOutlined, ClearOutlined } from '@ant-design/icons'
|
|
10
|
-
import { Button, Input, Form, Alert
|
|
10
|
+
import { Button, Input, Form, Alert } from 'antd'
|
|
11
11
|
import { notification } from '../common/notification'
|
|
12
|
+
import SwitchLabel from '../common/switch'
|
|
12
13
|
import Link from '../common/external-link'
|
|
13
14
|
import dayjs from 'dayjs'
|
|
14
15
|
import eq from 'fast-deep-equal'
|
|
@@ -253,7 +254,7 @@ export default function SyncForm (props) {
|
|
|
253
254
|
name='skipVerify'
|
|
254
255
|
valuePropName='checked'
|
|
255
256
|
>
|
|
256
|
-
<
|
|
257
|
+
<SwitchLabel />
|
|
257
258
|
</FormItem>
|
|
258
259
|
<FormItem
|
|
259
260
|
label={createLabel(e('password'))}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import React, { useState, useEffect } from 'react'
|
|
6
6
|
import { auto } from 'manate/react'
|
|
7
|
-
import { Switch } from 'antd'
|
|
8
7
|
import { UnorderedListOutlined } from '@ant-design/icons'
|
|
8
|
+
import SwitchLabel from '../common/switch'
|
|
9
9
|
import HistoryItem from './history-item'
|
|
10
10
|
import { getItemJSON, setItemJSON } from '../../common/safe-local-storage.js'
|
|
11
11
|
import '../setting-panel/list.styl'
|
|
@@ -45,17 +45,12 @@ export default auto(function HistoryPanel (props) {
|
|
|
45
45
|
return (
|
|
46
46
|
<div className='history-header pd2x pd2b'>
|
|
47
47
|
<div className='history-sort'>
|
|
48
|
-
<
|
|
48
|
+
<SwitchLabel
|
|
49
49
|
checked={sortByFrequency}
|
|
50
50
|
onChange={handleSortByFrequencyChange}
|
|
51
51
|
size='small'
|
|
52
|
+
label={e('sortByFrequency')}
|
|
52
53
|
/>
|
|
53
|
-
<span
|
|
54
|
-
className='history-sort-label pointer'
|
|
55
|
-
onClick={() => handleSortByFrequencyChange(!sortByFrequency)}
|
|
56
|
-
>
|
|
57
|
-
{e('sortByFrequency')}
|
|
58
|
-
</span>
|
|
59
54
|
</div>
|
|
60
55
|
<UnorderedListOutlined
|
|
61
56
|
{...clearIconProps}
|