@electerm/electerm-react 2.1.8 → 2.1.26
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/constants.js +6 -0
- package/client/common/init-setting-item.js +1 -1
- package/client/components/bookmark-form/common/fields.jsx +1 -1
- package/client/components/bookmark-form/common/init-values.js +10 -1
- package/client/components/bookmark-form/common/terminal-background.jsx +11 -2
- package/client/components/bookmark-form/config/ftp.js +3 -2
- package/client/components/bookmark-form/config/local.js +8 -2
- package/client/components/bookmark-form/config/rdp.js +3 -2
- package/client/components/bookmark-form/config/ssh.js +3 -2
- package/client/components/bookmark-form/config/telnet.js +8 -2
- package/client/components/bookmark-form/config/vnc.js +3 -2
- package/client/components/bookmark-form/form-renderer.jsx +5 -3
- package/client/components/profile/profile-form-elem.jsx +22 -3
- package/client/components/profile/profile-tabs.jsx +33 -20
- package/client/components/quick-commands/quick-commands-form-elem.jsx +7 -7
- package/client/components/setting-panel/list.jsx +14 -1
- package/client/components/setting-panel/setting-common.jsx +1 -1
- package/client/components/setting-panel/terminal-bg-config.jsx +21 -9
- package/client/components/sftp/paged-list.jsx +1 -1
- package/client/components/shortcuts/shortcut-control.jsx +8 -0
- package/client/components/shortcuts/shortcuts-defaults.js +5 -0
- package/client/components/ssh-config/ssh-config-load-notify.jsx +2 -1
- package/client/components/tabs/tab.jsx +3 -1
- package/client/components/theme/theme-list.jsx +35 -13
- package/client/components/tree-list/tree-list.jsx +4 -0
- package/client/store/common.js +9 -0
- package/client/store/store.js +14 -5
- package/package.json +1 -1
|
@@ -107,6 +107,12 @@ export const settingMap = buildConst([
|
|
|
107
107
|
'profiles'
|
|
108
108
|
])
|
|
109
109
|
|
|
110
|
+
export const staticNewItemTabs = new Set([
|
|
111
|
+
'terminalThemes',
|
|
112
|
+
'quickCommands',
|
|
113
|
+
'profiles'
|
|
114
|
+
])
|
|
115
|
+
|
|
110
116
|
export const infoTabs = buildConst([
|
|
111
117
|
'info',
|
|
112
118
|
'deps',
|
|
@@ -145,7 +145,7 @@ export function renderFormItem (item, formItemLayout, form, ctxProps, index) {
|
|
|
145
145
|
/>
|
|
146
146
|
)
|
|
147
147
|
case 'terminalBackground':
|
|
148
|
-
return <TerminalBackgroundField key={name}
|
|
148
|
+
return <TerminalBackgroundField key={name} />
|
|
149
149
|
case 'profileItem':
|
|
150
150
|
return <ProfileItem key={name} store={ctxProps.store} profileFilter={item.profileFilter} />
|
|
151
151
|
case 'quickCommands':
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Common utilities for config initValues
|
|
3
3
|
*/
|
|
4
|
-
import { newBookmarkIdPrefix } from '../../../common/constants.js'
|
|
4
|
+
import { newBookmarkIdPrefix, authTypeMap } from '../../../common/constants.js'
|
|
5
5
|
import { getColorFromCategory } from '../../../common/get-category-color.js'
|
|
6
6
|
import findBookmarkGroupId from '../../../common/find-bookmark-group-id.js'
|
|
7
7
|
import deepCopy from 'json-deep-copy'
|
|
@@ -81,3 +81,12 @@ export function getTerminalBackgroundDefaults (defaultSetting) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
export function getAuthTypeDefault (props) {
|
|
86
|
+
const r = {}
|
|
87
|
+
if (window.store.defaultProfileId) {
|
|
88
|
+
r.profile = window.store.defaultProfileId
|
|
89
|
+
r.authType = authTypeMap.profiles
|
|
90
|
+
}
|
|
91
|
+
return r
|
|
92
|
+
}
|
|
@@ -11,7 +11,7 @@ const FormItem = Form.Item
|
|
|
11
11
|
const e = window.translate
|
|
12
12
|
|
|
13
13
|
// Custom form control that implements the antd form control interface
|
|
14
|
-
const TerminalBgControl = ({ value
|
|
14
|
+
const TerminalBgControl = ({ value, onChange }) => {
|
|
15
15
|
const handleChange = (newValue, name) => {
|
|
16
16
|
const updatedValue = {
|
|
17
17
|
...value,
|
|
@@ -20,16 +20,25 @@ const TerminalBgControl = ({ value = {}, onChange }) => {
|
|
|
20
20
|
onChange(updatedValue)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
const handleBatchUpdate = (updates) => {
|
|
24
|
+
const updatedValue = {
|
|
25
|
+
...value,
|
|
26
|
+
...updates
|
|
27
|
+
}
|
|
28
|
+
onChange(updatedValue)
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
return (
|
|
24
32
|
<TerminalBackgroundConfig
|
|
25
33
|
config={value}
|
|
26
34
|
onChangeValue={handleChange}
|
|
35
|
+
batchUpdate={handleBatchUpdate}
|
|
27
36
|
name='terminalBackgroundImagePath'
|
|
28
37
|
/>
|
|
29
38
|
)
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
export default function renderTermBg (
|
|
41
|
+
export default function renderTermBg () {
|
|
33
42
|
const formProps = {
|
|
34
43
|
...formItemLayout,
|
|
35
44
|
name: 'terminalBackground',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
2
|
import { terminalFtpType } from '../../../common/constants.js'
|
|
3
|
-
import { createBaseInitValues } from '../common/init-values.js'
|
|
3
|
+
import { createBaseInitValues, getAuthTypeDefault } from '../common/init-values.js'
|
|
4
4
|
import { commonFields } from './common-fields.js'
|
|
5
5
|
import { isEmpty } from 'lodash-es'
|
|
6
6
|
|
|
@@ -14,7 +14,8 @@ const ftpConfig = {
|
|
|
14
14
|
port: 21,
|
|
15
15
|
user: '',
|
|
16
16
|
password: '',
|
|
17
|
-
secure: false
|
|
17
|
+
secure: false,
|
|
18
|
+
...getAuthTypeDefault(props)
|
|
18
19
|
})
|
|
19
20
|
},
|
|
20
21
|
layout: formItemLayout,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
2
|
import { terminalLocalType, terminalTypes } from '../../../common/constants.js'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createBaseInitValues,
|
|
5
|
+
getTerminalDefaults,
|
|
6
|
+
getSshDefaults,
|
|
7
|
+
getTerminalBackgroundDefaults
|
|
8
|
+
} from '../common/init-values.js'
|
|
4
9
|
import defaultSettings from '../../../common/default-setting.js'
|
|
5
10
|
import { commonFields } from './common-fields.js'
|
|
6
11
|
|
|
@@ -13,7 +18,8 @@ const localConfig = {
|
|
|
13
18
|
const { store } = props
|
|
14
19
|
return createBaseInitValues(props, terminalLocalType, {
|
|
15
20
|
...getTerminalDefaults(store),
|
|
16
|
-
...getSshDefaults()
|
|
21
|
+
...getSshDefaults(),
|
|
22
|
+
...getTerminalBackgroundDefaults(defaultSettings)
|
|
17
23
|
})
|
|
18
24
|
},
|
|
19
25
|
layout: formItemLayout,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
2
|
import { terminalRdpType } from '../../../common/constants.js'
|
|
3
|
-
import { createBaseInitValues } from '../common/init-values.js'
|
|
3
|
+
import { createBaseInitValues, getAuthTypeDefault } from '../common/init-values.js'
|
|
4
4
|
import { isEmpty } from 'lodash-es'
|
|
5
5
|
import { commonFields } from './common-fields.js'
|
|
6
6
|
|
|
@@ -11,7 +11,8 @@ const rdpConfig = {
|
|
|
11
11
|
type: terminalRdpType,
|
|
12
12
|
initValues: (props) => {
|
|
13
13
|
return createBaseInitValues(props, terminalRdpType, {
|
|
14
|
-
port: 3389
|
|
14
|
+
port: 3389,
|
|
15
|
+
...getAuthTypeDefault(props)
|
|
15
16
|
})
|
|
16
17
|
},
|
|
17
18
|
layout: formItemLayout,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { formItemLayout } from '../../../common/form-layout.js'
|
|
3
3
|
import { connectionMap, authTypeMap, defaultEnvLang } from '../../../common/constants.js'
|
|
4
4
|
import defaultSetting from '../../../common/default-setting.js'
|
|
5
|
-
import { createBaseInitValues, getTerminalDefaults, getSshDefaults, getTerminalBackgroundDefaults } from '../common/init-values.js'
|
|
5
|
+
import { createBaseInitValues, getTerminalDefaults, getSshDefaults, getTerminalBackgroundDefaults, getAuthTypeDefault } from '../common/init-values.js'
|
|
6
6
|
import { sshAuthFields, sshSettings, quickCommandsTab, sshTunnelTab, connectionHoppingTab } from './common-fields.js'
|
|
7
7
|
|
|
8
8
|
const e = window.translate
|
|
@@ -24,7 +24,8 @@ const sshConfig = {
|
|
|
24
24
|
cipher: [],
|
|
25
25
|
...getTerminalDefaults(store),
|
|
26
26
|
...getSshDefaults(),
|
|
27
|
-
...getTerminalBackgroundDefaults(defaultSetting)
|
|
27
|
+
...getTerminalBackgroundDefaults(defaultSetting),
|
|
28
|
+
...getAuthTypeDefault(props)
|
|
28
29
|
})
|
|
29
30
|
},
|
|
30
31
|
layout: formItemLayout,
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
2
|
import { terminalTelnetType, authTypeMap } from '../../../common/constants.js'
|
|
3
3
|
import defaultSettings from '../../../common/default-setting.js'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
createBaseInitValues,
|
|
6
|
+
getSshDefaults,
|
|
7
|
+
getTerminalBackgroundDefaults,
|
|
8
|
+
getAuthTypeDefault
|
|
9
|
+
} from '../common/init-values.js'
|
|
5
10
|
import { telnetAuthFields, terminalSettings, quickCommandsTab } from './common-fields.js'
|
|
6
11
|
|
|
7
12
|
const e = window.translate
|
|
@@ -18,7 +23,8 @@ const telnetConfig = {
|
|
|
18
23
|
authType: authTypeMap.password,
|
|
19
24
|
term: defaultSettings.terminalType,
|
|
20
25
|
...getSshDefaults(),
|
|
21
|
-
...getTerminalBackgroundDefaults(defaultSettings)
|
|
26
|
+
...getTerminalBackgroundDefaults(defaultSettings),
|
|
27
|
+
...getAuthTypeDefault(props)
|
|
22
28
|
})
|
|
23
29
|
},
|
|
24
30
|
layout: formItemLayout,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formItemLayout } from '../../../common/form-layout.js'
|
|
2
2
|
import { terminalVncType } from '../../../common/constants.js'
|
|
3
|
-
import { createBaseInitValues } from '../common/init-values.js'
|
|
3
|
+
import { createBaseInitValues, getAuthTypeDefault } from '../common/init-values.js'
|
|
4
4
|
import { isEmpty } from 'lodash-es'
|
|
5
5
|
import { commonFields, connectionHoppingTab } from './common-fields.js'
|
|
6
6
|
|
|
@@ -14,7 +14,8 @@ const vncConfig = {
|
|
|
14
14
|
port: 5900,
|
|
15
15
|
viewOnly: false,
|
|
16
16
|
scaleViewport: true,
|
|
17
|
-
connectionHoppings: []
|
|
17
|
+
connectionHoppings: [],
|
|
18
|
+
...getAuthTypeDefault(props)
|
|
18
19
|
})
|
|
19
20
|
},
|
|
20
21
|
layout: formItemLayout,
|
|
@@ -22,9 +22,10 @@ import { isValidIP } from '../../common/is-ip'
|
|
|
22
22
|
import { action as manateAction } from 'manate'
|
|
23
23
|
|
|
24
24
|
export default function FormRenderer ({ config, props }) {
|
|
25
|
+
const initialValues = config.initValues(props)
|
|
25
26
|
const [form] = Form.useForm()
|
|
26
27
|
const [ips, setIps] = useState([])
|
|
27
|
-
const [authType, setAuthType] = useState(
|
|
28
|
+
const [authType, setAuthType] = useState(initialValues.authType || authTypeMap.password)
|
|
28
29
|
const [testing, setTesting] = useState(false)
|
|
29
30
|
const action = useRef('submit')
|
|
30
31
|
|
|
@@ -156,6 +157,9 @@ export default function FormRenderer ({ config, props }) {
|
|
|
156
157
|
...props.formData,
|
|
157
158
|
...res
|
|
158
159
|
}
|
|
160
|
+
if (!obj.terminalBackground?.terminalBackgroundImagePath) {
|
|
161
|
+
delete obj.terminalBackground
|
|
162
|
+
}
|
|
159
163
|
if (isTest) {
|
|
160
164
|
return test(obj)
|
|
161
165
|
}
|
|
@@ -266,7 +270,6 @@ export default function FormRenderer ({ config, props }) {
|
|
|
266
270
|
setAuthType(newAuthType)
|
|
267
271
|
}
|
|
268
272
|
|
|
269
|
-
// Context props for specialized components
|
|
270
273
|
const ctxProps = {
|
|
271
274
|
...props,
|
|
272
275
|
form,
|
|
@@ -282,7 +285,6 @@ export default function FormRenderer ({ config, props }) {
|
|
|
282
285
|
useIp
|
|
283
286
|
}
|
|
284
287
|
|
|
285
|
-
const initialValues = config.initValues(props)
|
|
286
288
|
const tabs = typeof config.tabs === 'function' ? (config.tabs() || []) : (config.tabs || [])
|
|
287
289
|
let content = null
|
|
288
290
|
|
|
@@ -2,14 +2,16 @@ import { useState } from 'react'
|
|
|
2
2
|
import {
|
|
3
3
|
Form,
|
|
4
4
|
message,
|
|
5
|
+
Switch,
|
|
5
6
|
Button
|
|
6
7
|
} from 'antd'
|
|
7
8
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
8
9
|
import { formItemLayout } from '../../common/form-layout'
|
|
10
|
+
import HelpIcon from '../common/help-icon'
|
|
9
11
|
import {
|
|
10
12
|
settingMap
|
|
11
13
|
} from '../../common/constants'
|
|
12
|
-
|
|
14
|
+
import { action } from 'manate'
|
|
13
15
|
import ProfileTabs from './profile-tabs'
|
|
14
16
|
|
|
15
17
|
const FormItem = Form.Item
|
|
@@ -28,13 +30,15 @@ export default function ProfileFormElem (props) {
|
|
|
28
30
|
}
|
|
29
31
|
return id
|
|
30
32
|
}
|
|
31
|
-
async function
|
|
33
|
+
const handleSubmit = action(async function (res) {
|
|
32
34
|
const { formData } = props
|
|
33
35
|
const update1 = {
|
|
34
36
|
...res,
|
|
35
37
|
id: genId()
|
|
36
38
|
}
|
|
39
|
+
let defaultId = update1.id
|
|
37
40
|
if (formData.id) {
|
|
41
|
+
defaultId = formData.id
|
|
38
42
|
props.store.editItem(formData.id, res, settingMap.profiles)
|
|
39
43
|
} else {
|
|
40
44
|
props.store.addItem(update1, settingMap.profiles)
|
|
@@ -43,14 +47,21 @@ export default function ProfileFormElem (props) {
|
|
|
43
47
|
name: e('profile')
|
|
44
48
|
})
|
|
45
49
|
}
|
|
50
|
+
window.store.makeSureProfileDefault(defaultId)
|
|
46
51
|
message.success(e('saved'))
|
|
47
|
-
}
|
|
52
|
+
})
|
|
48
53
|
const tabsProps = {
|
|
49
54
|
activeTab,
|
|
50
55
|
onChangeTab: setActiveTab,
|
|
51
56
|
form,
|
|
52
57
|
store: props.store
|
|
53
58
|
}
|
|
59
|
+
const profileDefaultWikiLink = 'https://github.com/electerm/electerm/wiki/Default-Profile'
|
|
60
|
+
const defaultLabel = (
|
|
61
|
+
<span>
|
|
62
|
+
{e('default')} <HelpIcon link={profileDefaultWikiLink} />
|
|
63
|
+
</span>
|
|
64
|
+
)
|
|
54
65
|
return (
|
|
55
66
|
<Form
|
|
56
67
|
form={form}
|
|
@@ -73,6 +84,14 @@ export default function ProfileFormElem (props) {
|
|
|
73
84
|
>
|
|
74
85
|
<InputAutoFocus />
|
|
75
86
|
</FormItem>
|
|
87
|
+
<FormItem
|
|
88
|
+
{...formItemLayout}
|
|
89
|
+
label={defaultLabel}
|
|
90
|
+
name='isDefault'
|
|
91
|
+
valuePropName='checked'
|
|
92
|
+
>
|
|
93
|
+
<Switch />
|
|
94
|
+
</FormItem>
|
|
76
95
|
<ProfileTabs {...tabsProps} />
|
|
77
96
|
<FormItem>
|
|
78
97
|
<Button
|
|
@@ -5,32 +5,45 @@ import ProfileFormVnc from './profile-form-vnc'
|
|
|
5
5
|
import ProfileFormFtp from './profile-form-ftp'
|
|
6
6
|
import ProfileFormTelnet from './profile-form-telnet'
|
|
7
7
|
|
|
8
|
-
const { TabPane } = Tabs
|
|
9
|
-
|
|
10
8
|
export default function ProfileTabs (props) {
|
|
11
9
|
const { activeTab, onChangeTab, form, store } = props
|
|
12
10
|
const tabsProps = {
|
|
13
11
|
activeKey: activeTab,
|
|
14
12
|
onChange: onChangeTab
|
|
15
13
|
}
|
|
14
|
+
const items = [
|
|
15
|
+
{
|
|
16
|
+
label: 'ssh',
|
|
17
|
+
key: 'ssh',
|
|
18
|
+
forceRender: true,
|
|
19
|
+
children: <ProfileFormSsh form={form} store={store} />
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: 'telnet',
|
|
23
|
+
key: 'telnet',
|
|
24
|
+
forceRender: true,
|
|
25
|
+
children: <ProfileFormTelnet form={form} store={store} />
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'vnc',
|
|
29
|
+
key: 'vnc',
|
|
30
|
+
forceRender: true,
|
|
31
|
+
children: <ProfileFormVnc />
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
label: 'rdp',
|
|
35
|
+
key: 'rdp',
|
|
36
|
+
forceRender: true,
|
|
37
|
+
children: <ProfileFormRdp />
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: 'ftp',
|
|
41
|
+
key: 'ftp',
|
|
42
|
+
forceRender: true,
|
|
43
|
+
children: <ProfileFormFtp />
|
|
44
|
+
}
|
|
45
|
+
]
|
|
16
46
|
return (
|
|
17
|
-
<Tabs {...tabsProps}
|
|
18
|
-
<TabPane tab='ssh' key='ssh' forceRender>
|
|
19
|
-
<ProfileFormSsh form={form} store={store} />
|
|
20
|
-
</TabPane>
|
|
21
|
-
<TabPane tab='telnet' key='telnet' forceRender>
|
|
22
|
-
<ProfileFormTelnet form={form} store={store} />
|
|
23
|
-
</TabPane>
|
|
24
|
-
<TabPane tab='vnc' key='vnc' forceRender>
|
|
25
|
-
<ProfileFormVnc />
|
|
26
|
-
</TabPane>
|
|
27
|
-
<TabPane tab='rdp' key='rdp' forceRender>
|
|
28
|
-
<ProfileFormRdp />
|
|
29
|
-
</TabPane>
|
|
30
|
-
<TabPane tab='ftp' key='ftp' forceRender>
|
|
31
|
-
<ProfileFormFtp />
|
|
32
|
-
</TabPane>
|
|
33
|
-
</Tabs>
|
|
34
|
-
|
|
47
|
+
<Tabs {...tabsProps} items={items} />
|
|
35
48
|
)
|
|
36
49
|
}
|
|
@@ -138,13 +138,6 @@ export default function QuickCommandForm (props) {
|
|
|
138
138
|
const wiki = 'https://github.com/electerm/electerm/wiki/quick-command-templates'
|
|
139
139
|
return (
|
|
140
140
|
<>
|
|
141
|
-
<p>
|
|
142
|
-
<b className='mg1r'>{e('templates')}:</b>
|
|
143
|
-
<span className='mg1r'>{templatesStr}</span>
|
|
144
|
-
<HelpIcon
|
|
145
|
-
link={wiki}
|
|
146
|
-
/>
|
|
147
|
-
</p>
|
|
148
141
|
<Form
|
|
149
142
|
form={form}
|
|
150
143
|
onFinish={handleSubmit}
|
|
@@ -210,6 +203,13 @@ export default function QuickCommandForm (props) {
|
|
|
210
203
|
</Button>
|
|
211
204
|
</p>
|
|
212
205
|
</FormItem>
|
|
206
|
+
<p>
|
|
207
|
+
<b className='mg1r'>{e('templates')}:</b>
|
|
208
|
+
<span className='mg1r'>{templatesStr}</span>
|
|
209
|
+
<HelpIcon
|
|
210
|
+
link={wiki}
|
|
211
|
+
/>
|
|
212
|
+
</p>
|
|
213
213
|
</Form>
|
|
214
214
|
</>
|
|
215
215
|
)
|
|
@@ -9,7 +9,8 @@ import createName, { createTitleTag } from '../../common/create-title'
|
|
|
9
9
|
import classnames from 'classnames'
|
|
10
10
|
import { noop } from 'lodash-es'
|
|
11
11
|
import highlight from '../common/highlight'
|
|
12
|
-
import { settingSyncId, settingCommonId } from '../../common/constants'
|
|
12
|
+
import { settingSyncId, settingCommonId, staticNewItemTabs } from '../../common/constants'
|
|
13
|
+
import getInitItem from '../../common/init-setting-item'
|
|
13
14
|
import './list.styl'
|
|
14
15
|
|
|
15
16
|
const e = window.translate
|
|
@@ -95,6 +96,17 @@ export default class ItemList extends React.PureComponent {
|
|
|
95
96
|
return icon
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
renderNewItem () {
|
|
100
|
+
const { type } = this.props
|
|
101
|
+
|
|
102
|
+
if (!staticNewItemTabs.has(type)) {
|
|
103
|
+
return null
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const newItem = getInitItem([], type)
|
|
107
|
+
return this.renderItem(newItem, -1)
|
|
108
|
+
}
|
|
109
|
+
|
|
98
110
|
renderItem = (item, i) => {
|
|
99
111
|
const { onClickItem, type, activeItemId } = this.props
|
|
100
112
|
const { id } = item
|
|
@@ -175,6 +187,7 @@ export default class ItemList extends React.PureComponent {
|
|
|
175
187
|
{this.renderLabels ? this.renderLabels() : null}
|
|
176
188
|
{this.renderSearch()}
|
|
177
189
|
<div className='item-list-wrap' style={listStyle}>
|
|
190
|
+
{this.renderNewItem()}
|
|
178
191
|
{
|
|
179
192
|
list.map(this.renderItem)
|
|
180
193
|
}
|
|
@@ -20,7 +20,8 @@ export default function TerminalBackgroundConfig ({
|
|
|
20
20
|
onChangeValue,
|
|
21
21
|
name,
|
|
22
22
|
config,
|
|
23
|
-
isGlobal = false
|
|
23
|
+
isGlobal = false,
|
|
24
|
+
batchUpdate
|
|
24
25
|
}) {
|
|
25
26
|
const [showTextModal, setShowTextModal] = useState(false)
|
|
26
27
|
const value = config[name]
|
|
@@ -71,7 +72,7 @@ export default function TerminalBackgroundConfig ({
|
|
|
71
72
|
// Show helpful text when text background is selected but no text is configured
|
|
72
73
|
dataSource[2] = {
|
|
73
74
|
value: textTerminalBgValue,
|
|
74
|
-
desc:
|
|
75
|
+
desc: '📝 Click to configure text'
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -93,12 +94,24 @@ export default function TerminalBackgroundConfig ({
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
const handleTextBgModalOk = (textConfig) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
if (batchUpdate) {
|
|
98
|
+
// Use batch update if available
|
|
99
|
+
const updates = {
|
|
100
|
+
terminalBackgroundText: textConfig.text,
|
|
101
|
+
terminalBackgroundTextSize: textConfig.fontSize,
|
|
102
|
+
terminalBackgroundTextColor: textConfig.color,
|
|
103
|
+
terminalBackgroundTextFontFamily: textConfig.fontFamily,
|
|
104
|
+
[name]: textTerminalBgValue
|
|
105
|
+
}
|
|
106
|
+
batchUpdate(updates)
|
|
107
|
+
} else {
|
|
108
|
+
// Fall back to sequential updates
|
|
109
|
+
onChangeValue(textConfig.text, 'terminalBackgroundText')
|
|
110
|
+
onChangeValue(textConfig.fontSize, 'terminalBackgroundTextSize')
|
|
111
|
+
onChangeValue(textConfig.color, 'terminalBackgroundTextColor')
|
|
112
|
+
onChangeValue(textConfig.fontFamily, 'terminalBackgroundTextFontFamily')
|
|
113
|
+
onChange(textTerminalBgValue)
|
|
114
|
+
}
|
|
102
115
|
setShowTextModal(false)
|
|
103
116
|
}
|
|
104
117
|
|
|
@@ -204,7 +217,6 @@ export default function TerminalBackgroundConfig ({
|
|
|
204
217
|
label: item.desc
|
|
205
218
|
}
|
|
206
219
|
}
|
|
207
|
-
|
|
208
220
|
return (
|
|
209
221
|
<div className='pd2b'>
|
|
210
222
|
<div className='pd1b'>
|
|
@@ -144,6 +144,14 @@ class ShortcutControl extends React.PureComponent {
|
|
|
144
144
|
window.store.cloneToNextLayout()
|
|
145
145
|
}, 500)
|
|
146
146
|
|
|
147
|
+
duplicateTabShortcut = throttle((e) => {
|
|
148
|
+
e.stopPropagation()
|
|
149
|
+
const { activeTabId } = window.store
|
|
150
|
+
if (activeTabId) {
|
|
151
|
+
window.store.duplicateTab(activeTabId)
|
|
152
|
+
}
|
|
153
|
+
}, 500)
|
|
154
|
+
|
|
147
155
|
prevTabShortcut = throttle((e) => {
|
|
148
156
|
e.stopPropagation()
|
|
149
157
|
window.store.clickPrevTab()
|
|
@@ -49,7 +49,8 @@ export default function SshConfigLoadNotify (props) {
|
|
|
49
49
|
ignoreSshConfig !== 'yes' &&
|
|
50
50
|
settingTab === 'bookmarks' &&
|
|
51
51
|
showModal &&
|
|
52
|
-
sshConfigLoaded !== 'yes'
|
|
52
|
+
sshConfigLoaded !== 'yes' &&
|
|
53
|
+
window.store.hasNodePty
|
|
53
54
|
|
|
54
55
|
if (shouldShow) {
|
|
55
56
|
showNotification()
|
|
@@ -268,6 +268,7 @@ class Tab extends Component {
|
|
|
268
268
|
const reloadShortcut = this.getShortcut('app_reloadCurrentTab')
|
|
269
269
|
const closeShortcut = this.getShortcut('app_closeCurrentTab')
|
|
270
270
|
const cloneToNextShortcut = this.getShortcut('app_cloneToNextLayout')
|
|
271
|
+
const duplicateShortcut = this.getShortcut('app_duplicateTab')
|
|
271
272
|
|
|
272
273
|
const x = [
|
|
273
274
|
{
|
|
@@ -294,7 +295,8 @@ class Tab extends Component {
|
|
|
294
295
|
{
|
|
295
296
|
key: 'handleDup',
|
|
296
297
|
icon: <iconsMap.CopyOutlined />,
|
|
297
|
-
label: e('duplicate')
|
|
298
|
+
label: e('duplicate'),
|
|
299
|
+
extra: duplicateShortcut
|
|
298
300
|
},
|
|
299
301
|
{
|
|
300
302
|
key: 'cloneToNextLayout',
|
|
@@ -7,7 +7,8 @@ import { LoadingOutlined, CheckCircleOutlined } from '@ant-design/icons'
|
|
|
7
7
|
import { pick } from 'lodash-es'
|
|
8
8
|
import { Pagination } from 'antd'
|
|
9
9
|
import ThemeListItem from './theme-list-item'
|
|
10
|
-
import { defaultTheme } from '../../common/constants'
|
|
10
|
+
import { defaultTheme, settingMap } from '../../common/constants'
|
|
11
|
+
import getInitItem from '../../common/init-setting-item'
|
|
11
12
|
import './terminal-theme-list.styl'
|
|
12
13
|
|
|
13
14
|
const e = window.translate
|
|
@@ -58,13 +59,33 @@ export default class ThemeList extends List {
|
|
|
58
59
|
)
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
renderNewItem () {
|
|
63
|
+
const newThemeItem = getInitItem([], settingMap.terminalThemes)
|
|
64
|
+
const itemProps = {
|
|
65
|
+
item: newThemeItem,
|
|
66
|
+
renderDelBtn: this.renderDelBtn,
|
|
67
|
+
activeItemId: this.props.activeItemId,
|
|
68
|
+
...pick(
|
|
69
|
+
this.props,
|
|
70
|
+
[
|
|
71
|
+
'onClickItem',
|
|
72
|
+
'theme',
|
|
73
|
+
'keyword'
|
|
74
|
+
]
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
return (
|
|
78
|
+
<ThemeListItem key='new-theme' {...itemProps} />
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
filter = list => {
|
|
62
|
-
const { keyword
|
|
83
|
+
const { keyword } = this.state
|
|
63
84
|
return keyword
|
|
64
|
-
? list.
|
|
85
|
+
? list.filter(item => {
|
|
65
86
|
return item.name.toLowerCase().includes(keyword.toLowerCase())
|
|
66
87
|
})
|
|
67
|
-
: list
|
|
88
|
+
: list
|
|
68
89
|
}
|
|
69
90
|
|
|
70
91
|
paged = list => {
|
|
@@ -77,6 +98,13 @@ export default class ThemeList extends List {
|
|
|
77
98
|
|
|
78
99
|
render () {
|
|
79
100
|
const { ready, page, pageSize } = this.state
|
|
101
|
+
if (!ready) {
|
|
102
|
+
return (
|
|
103
|
+
<div className='pd3 aligncenter'>
|
|
104
|
+
<LoadingOutlined />
|
|
105
|
+
</div>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
80
108
|
let {
|
|
81
109
|
list = [],
|
|
82
110
|
type,
|
|
@@ -92,6 +120,7 @@ export default class ThemeList extends List {
|
|
|
92
120
|
{this.renderSearch()}
|
|
93
121
|
{this.renderCurrentTheme()}
|
|
94
122
|
<div className='item-list-wrap' style={listStyle}>
|
|
123
|
+
{this.renderNewItem()}
|
|
95
124
|
{
|
|
96
125
|
list.map(this.renderItem)
|
|
97
126
|
}
|
|
@@ -101,17 +130,10 @@ export default class ThemeList extends List {
|
|
|
101
130
|
total={all}
|
|
102
131
|
current={page}
|
|
103
132
|
pageSize={pageSize}
|
|
133
|
+
showLessItems
|
|
134
|
+
simple
|
|
104
135
|
onShowSizeChange={this.handlePageSizeChange}
|
|
105
136
|
/>
|
|
106
|
-
{
|
|
107
|
-
ready
|
|
108
|
-
? null
|
|
109
|
-
: (
|
|
110
|
-
<div className='pd3 aligncenter'>
|
|
111
|
-
<LoadingOutlined />
|
|
112
|
-
</div>
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
137
|
</div>
|
|
116
138
|
)
|
|
117
139
|
}
|
|
@@ -309,6 +309,10 @@ export default class ItemListTree extends Component {
|
|
|
309
309
|
store.storeAssign({
|
|
310
310
|
currentBookmarkGroupId: id
|
|
311
311
|
})
|
|
312
|
+
const func = this.props.expandedKeys.includes(id)
|
|
313
|
+
? this.onUnExpandKey
|
|
314
|
+
: this.onExpandKey
|
|
315
|
+
func({ id })
|
|
312
316
|
} else {
|
|
313
317
|
store.storeAssign({
|
|
314
318
|
currentBookmarkGroupId: findBookmarkGroupId(store.bookmarkGroups, id)
|
package/client/store/common.js
CHANGED
|
@@ -313,6 +313,15 @@ export default Store => {
|
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
Store.prototype.makeSureProfileDefault = function (defaultId) {
|
|
317
|
+
const { profiles } = window.store
|
|
318
|
+
for (const p of profiles) {
|
|
319
|
+
if (p.id !== defaultId) {
|
|
320
|
+
delete p.isDefault
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
316
325
|
Store.prototype.aiConfigMissing = function () {
|
|
317
326
|
return aiConfigsArr.slice(0, -1).some(k => !window.store.config[k])
|
|
318
327
|
}
|
package/client/store/store.js
CHANGED
|
@@ -32,7 +32,8 @@ import getBrand from '../components/ai/get-brand'
|
|
|
32
32
|
import {
|
|
33
33
|
settingMap,
|
|
34
34
|
terminalSshConfigType,
|
|
35
|
-
paneMap
|
|
35
|
+
paneMap,
|
|
36
|
+
staticNewItemTabs
|
|
36
37
|
} from '../common/constants'
|
|
37
38
|
import getInitItem from '../common/init-setting-item'
|
|
38
39
|
import createTitle from '../common/create-title'
|
|
@@ -121,6 +122,12 @@ class Store {
|
|
|
121
122
|
currentTab.pane === paneMap.terminal
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
get defaultProfileId () {
|
|
126
|
+
const { profiles } = window.store
|
|
127
|
+
const defaultProfile = profiles.find(p => p.isDefault)
|
|
128
|
+
return defaultProfile?.id || ''
|
|
129
|
+
}
|
|
130
|
+
|
|
124
131
|
get quickCommandTags () {
|
|
125
132
|
const { quickCommands } = window.store
|
|
126
133
|
return uniq(
|
|
@@ -149,10 +156,12 @@ class Store {
|
|
|
149
156
|
const initItem = getInitItem(arr, settingTab)
|
|
150
157
|
return settingTab === settingMap.history
|
|
151
158
|
? arr
|
|
152
|
-
:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
: staticNewItemTabs.has(settingTab)
|
|
160
|
+
? arr // Don't add initItem for these tabs, they will be handled separately
|
|
161
|
+
: [
|
|
162
|
+
deepCopy(initItem),
|
|
163
|
+
...arr
|
|
164
|
+
]
|
|
156
165
|
}
|
|
157
166
|
|
|
158
167
|
get terminalCommandSuggestions () {
|