@electerm/electerm-react 3.1.26 → 3.3.8
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 +1 -3
- package/client/common/db.js +4 -2
- package/client/components/ai/ai-history.jsx +4 -4
- package/client/components/batch-op/batch-op-alert.jsx +42 -0
- package/client/components/batch-op/batch-op-editor.jsx +202 -0
- package/client/components/batch-op/batch-op-logs.jsx +53 -0
- package/client/components/batch-op/batch-op-runner.jsx +315 -0
- package/client/components/bookmark-form/ai-bookmark-form.jsx +2 -1
- package/client/components/bookmark-form/bookmark-from-history-modal.jsx +2 -1
- package/client/components/bookmark-form/common/bookmark-select.jsx +18 -2
- package/client/components/bookmark-form/common/connection-hopping-form.jsx +153 -0
- package/client/components/bookmark-form/common/connection-hopping.jsx +136 -129
- package/client/components/common/auto-check-update.jsx +31 -0
- package/client/components/common/notification.styl +1 -1
- package/client/components/file-transfer/conflict-resolve.jsx +3 -0
- package/client/components/footer/batch-input.jsx +10 -7
- package/client/components/main/error-wrapper.jsx +18 -7
- package/client/components/main/main.jsx +6 -7
- package/client/components/quick-commands/qm.styl +0 -2
- package/client/components/quick-commands/quick-commands-list-form.jsx +1 -1
- package/client/components/setting-panel/hotkey.jsx +9 -1
- package/client/components/setting-panel/list.jsx +0 -1
- package/client/components/setting-panel/list.styl +4 -0
- package/client/components/setting-panel/setting-modal.jsx +53 -47
- package/client/components/setting-sync/auto-sync.jsx +53 -0
- package/client/components/setting-sync/data-import.jsx +69 -8
- package/client/components/sftp/address-bar.jsx +7 -1
- package/client/components/shortcuts/shortcut-editor.jsx +4 -2
- package/client/components/sidebar/bookmark-select.jsx +3 -2
- package/client/components/sidebar/history-item.jsx +3 -1
- package/client/components/sidebar/history.jsx +1 -0
- package/client/components/sidebar/index.jsx +0 -9
- package/client/components/tabs/add-btn-menu.jsx +1 -1
- package/client/components/tabs/add-btn.jsx +9 -15
- package/client/components/tabs/quick-connect.jsx +6 -10
- package/client/components/terminal/attach-addon-custom.js +86 -0
- package/client/components/terminal/cmd-item.jsx +13 -3
- package/client/components/terminal/drop-file-modal.jsx +57 -0
- package/client/components/terminal/terminal-command-dropdown.jsx +91 -13
- package/client/components/terminal/terminal.jsx +107 -10
- package/client/components/terminal/terminal.styl +9 -0
- package/client/components/tree-list/tree-list-item.jsx +0 -1
- package/client/components/tree-list/tree-list.jsx +115 -10
- package/client/components/tree-list/tree-list.styl +3 -0
- package/client/components/tree-list/tree-search.jsx +9 -1
- package/client/components/vnc/vnc-session.jsx +2 -0
- package/client/components/widgets/widget-control.jsx +3 -0
- package/client/components/widgets/widget-form.jsx +6 -0
- package/client/components/widgets/widget-instance.jsx +26 -7
- package/client/css/includes/box.styl +3 -0
- package/client/store/common.js +0 -28
- package/client/store/init-state.js +2 -1
- package/client/store/load-data.js +6 -4
- package/client/store/mcp-handler.js +20 -2
- package/client/store/sync.js +25 -1
- package/client/store/tab.js +1 -1
- package/client/store/watch.js +10 -18
- package/client/store/widgets.js +54 -0
- package/client/views/index.pug +1 -2
- package/package.json +1 -1
- package/client/components/batch-op/batch-op.jsx +0 -694
|
@@ -6,7 +6,6 @@ import UpdateCheck from './upgrade'
|
|
|
6
6
|
import SettingModal from '../setting-panel/setting-modal'
|
|
7
7
|
import TextEditor from '../text-editor/text-editor'
|
|
8
8
|
import Sidebar from '../sidebar'
|
|
9
|
-
import BatchOp from '../batch-op/batch-op'
|
|
10
9
|
import CssOverwrite from '../bg/css-overwrite'
|
|
11
10
|
import UiTheme from './ui-theme'
|
|
12
11
|
import CustomCss from '../bg/custom-css.jsx'
|
|
@@ -34,6 +33,9 @@ import MoveItemModal from '../tree-list/move-item-modal'
|
|
|
34
33
|
import InputContextMenu from '../common/input-context-menu'
|
|
35
34
|
import WorkspaceSaveModal from '../tabs/workspace-save-modal'
|
|
36
35
|
import BookmarkFromHistoryModal from '../bookmark-form/bookmark-from-history-modal'
|
|
36
|
+
import AutoSync from '../setting-sync/auto-sync'
|
|
37
|
+
import AutoCheckUpdate from '../common/auto-check-update'
|
|
38
|
+
import BatchOpRunner from '../batch-op/batch-op-runner'
|
|
37
39
|
import { pick } from 'lodash-es'
|
|
38
40
|
import deepCopy from 'json-deep-copy'
|
|
39
41
|
import './wrapper.styl'
|
|
@@ -184,11 +186,6 @@ export default auto(function Index (props) {
|
|
|
184
186
|
fileTransferChanged: JSON.stringify(copiedTransfer),
|
|
185
187
|
fileTransfers: copiedTransfer
|
|
186
188
|
}
|
|
187
|
-
const batchOpProps = {
|
|
188
|
-
transferHistory,
|
|
189
|
-
showModal: store.showModal,
|
|
190
|
-
innerWidth: store.innerWidth
|
|
191
|
-
}
|
|
192
189
|
const resProps = {
|
|
193
190
|
resolutions: deepCopy(store.resolutions),
|
|
194
191
|
openResolutionEdit
|
|
@@ -263,7 +260,6 @@ export default auto(function Index (props) {
|
|
|
263
260
|
/>
|
|
264
261
|
<FileInfoModal />
|
|
265
262
|
<SettingModal store={store} />
|
|
266
|
-
<BatchOp {...batchOpProps} />
|
|
267
263
|
<MoveItemModal store={store} />
|
|
268
264
|
<div
|
|
269
265
|
id='outside-context'
|
|
@@ -295,9 +291,12 @@ export default auto(function Index (props) {
|
|
|
295
291
|
<ConnectionHoppingWarning {...warningProps} />
|
|
296
292
|
<TerminalCmdSuggestions {...cmdSuggestionsProps} />
|
|
297
293
|
<TransferQueue />
|
|
294
|
+
<AutoSync config={config} />
|
|
295
|
+
<AutoCheckUpdate config={config} />
|
|
298
296
|
<WorkspaceSaveModal store={store} />
|
|
299
297
|
<BookmarkFromHistoryModal />
|
|
300
298
|
<NotificationContainer />
|
|
299
|
+
<BatchOpRunner />
|
|
301
300
|
</div>
|
|
302
301
|
</ConfigProvider>
|
|
303
302
|
)
|
|
@@ -76,7 +76,7 @@ export default function renderQm (form) {
|
|
|
76
76
|
onDrop={(e) => handleDrop(e, i, form)}
|
|
77
77
|
onDragEnd={handleDragEnd}
|
|
78
78
|
>
|
|
79
|
-
<HolderOutlined className='mg1r
|
|
79
|
+
<HolderOutlined className='mg1r drag' />
|
|
80
80
|
|
|
81
81
|
<Space.Addon>{e('delay')}</Space.Addon>
|
|
82
82
|
<FormItem
|
|
@@ -51,6 +51,12 @@ export default class HotkeySetting extends Component {
|
|
|
51
51
|
})
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
handleClear = () => {
|
|
55
|
+
return this.props.onSaveConfig({
|
|
56
|
+
hotkey: ''
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
54
60
|
convertToElectronAccelerator = (shortcut) => {
|
|
55
61
|
if (!shortcut) return shortcut
|
|
56
62
|
|
|
@@ -117,7 +123,9 @@ export default class HotkeySetting extends Component {
|
|
|
117
123
|
index: 0
|
|
118
124
|
},
|
|
119
125
|
updateConfig: this.onChangeHotkey,
|
|
120
|
-
keysTaken: this.getKeysTaken(hotkey)
|
|
126
|
+
keysTaken: this.getKeysTaken(hotkey),
|
|
127
|
+
handleClear: this.handleClear,
|
|
128
|
+
renderClear: true
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
return (
|
|
@@ -11,7 +11,6 @@ import { noop } from 'lodash-es'
|
|
|
11
11
|
import highlight from '../common/highlight'
|
|
12
12
|
import { settingSyncId, settingCommonId, staticNewItemTabs } from '../../common/constants'
|
|
13
13
|
import getInitItem from '../../common/init-setting-item'
|
|
14
|
-
import './list.styl'
|
|
15
14
|
|
|
16
15
|
const e = window.translate
|
|
17
16
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
.list-item-remove
|
|
9
9
|
.list-item-bookmark
|
|
10
10
|
.list-item-duplicate
|
|
11
|
+
.list-item-autorun
|
|
11
12
|
display none
|
|
12
13
|
width 24px
|
|
13
14
|
line-height 35px
|
|
@@ -15,6 +16,8 @@
|
|
|
15
16
|
position absolute
|
|
16
17
|
right 0
|
|
17
18
|
top 0
|
|
19
|
+
.list-item-autorun
|
|
20
|
+
right 24px
|
|
18
21
|
|
|
19
22
|
.list-item-title
|
|
20
23
|
flex-grow: 1
|
|
@@ -37,6 +40,7 @@
|
|
|
37
40
|
.list-item-remove
|
|
38
41
|
.list-item-bookmark
|
|
39
42
|
.list-item-duplicate
|
|
43
|
+
.list-item-autorun
|
|
40
44
|
display block
|
|
41
45
|
.theme-item:hover
|
|
42
46
|
.list-item-remove
|
|
@@ -4,18 +4,22 @@
|
|
|
4
4
|
|
|
5
5
|
import { auto } from 'manate/react'
|
|
6
6
|
import { pick } from 'lodash-es'
|
|
7
|
-
import { Tabs } from 'antd'
|
|
7
|
+
import { Tabs, Spin } from 'antd'
|
|
8
|
+
import { lazy, Suspense } from 'react'
|
|
8
9
|
import SettingModal from './setting-wrap'
|
|
9
10
|
import {
|
|
10
11
|
settingMap,
|
|
11
12
|
modals
|
|
12
13
|
} from '../../common/constants'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
|
|
15
|
+
const TabBookmarks = lazy(() => import('./tab-bookmarks'))
|
|
16
|
+
const TabQuickCommands = lazy(() => import('./tab-quick-commands'))
|
|
17
|
+
const TabSettings = lazy(() => import('./tab-settings'))
|
|
18
|
+
const TabThemes = lazy(() => import('./tab-themes'))
|
|
19
|
+
const TabProfiles = lazy(() => import('./tab-profiles'))
|
|
20
|
+
const TabWidgets = lazy(() => import('./tab-widgets'))
|
|
21
|
+
|
|
22
|
+
const Loading = () => <div style={{ padding: 20, textAlign: 'center' }}><Spin /></div>
|
|
19
23
|
|
|
20
24
|
const e = window.translate
|
|
21
25
|
|
|
@@ -115,46 +119,48 @@ export default auto(function SettingModalWrap (props) {
|
|
|
115
119
|
<Tabs
|
|
116
120
|
{...tabsProps}
|
|
117
121
|
/>
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
122
|
+
<Suspense fallback={<Loading />}>
|
|
123
|
+
<TabQuickCommands
|
|
124
|
+
listProps={props0}
|
|
125
|
+
settingItem={settingItem}
|
|
126
|
+
formProps={formProps}
|
|
127
|
+
store={store}
|
|
128
|
+
settingTab={settingTab}
|
|
129
|
+
/>
|
|
130
|
+
<TabBookmarks
|
|
131
|
+
treeProps={treeProps}
|
|
132
|
+
settingItem={settingItem}
|
|
133
|
+
formProps={formProps}
|
|
134
|
+
settingTab={settingTab}
|
|
135
|
+
/>
|
|
136
|
+
<TabSettings
|
|
137
|
+
listProps={props0}
|
|
138
|
+
settingItem={settingItem}
|
|
139
|
+
settingTab={settingTab}
|
|
140
|
+
store={store}
|
|
141
|
+
/>
|
|
142
|
+
<TabThemes
|
|
143
|
+
listProps={props0}
|
|
144
|
+
settingItem={settingItem}
|
|
145
|
+
formProps={formProps}
|
|
146
|
+
store={store}
|
|
147
|
+
settingTab={settingTab}
|
|
148
|
+
/>
|
|
149
|
+
<TabProfiles
|
|
150
|
+
listProps={props0}
|
|
151
|
+
settingItem={settingItem}
|
|
152
|
+
formProps={formProps}
|
|
153
|
+
store={store}
|
|
154
|
+
settingTab={settingTab}
|
|
155
|
+
/>
|
|
156
|
+
<TabWidgets
|
|
157
|
+
listProps={props0}
|
|
158
|
+
settingItem={settingItem}
|
|
159
|
+
formProps={formProps}
|
|
160
|
+
store={store}
|
|
161
|
+
settingTab={settingTab}
|
|
162
|
+
/>
|
|
163
|
+
</Suspense>
|
|
158
164
|
</>
|
|
159
165
|
)
|
|
160
166
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
export default function AutoSync ({ config }) {
|
|
4
|
+
const lastSyncTimeRef = useRef(0)
|
|
5
|
+
const intervalIdRef = useRef(null)
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (
|
|
9
|
+
!config.syncSetting?.autoSync || config.syncSetting?.autoSyncInterval <= 0
|
|
10
|
+
) {
|
|
11
|
+
clearInterval(intervalIdRef.current)
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
const checkAndSync = async () => {
|
|
15
|
+
const syncSetting = config.syncSetting || {}
|
|
16
|
+
const { autoSync, autoSyncInterval = 0, autoSyncDirection = 'upload' } = syncSetting
|
|
17
|
+
|
|
18
|
+
if (!autoSync) {
|
|
19
|
+
return
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (autoSyncInterval <= 0) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const now = Date.now()
|
|
27
|
+
const intervalMs = autoSyncInterval * 60 * 1000
|
|
28
|
+
if (now - lastSyncTimeRef.current >= intervalMs) {
|
|
29
|
+
const { store } = window
|
|
30
|
+
if (autoSyncDirection === 'download') {
|
|
31
|
+
await store.downloadSettingAll()
|
|
32
|
+
} else {
|
|
33
|
+
await store.uploadSettingAll()
|
|
34
|
+
}
|
|
35
|
+
lastSyncTimeRef.current = now
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
intervalIdRef.current = setInterval(checkAndSync, 10000)
|
|
40
|
+
|
|
41
|
+
return () => {
|
|
42
|
+
if (intervalIdRef.current) {
|
|
43
|
+
clearInterval(intervalIdRef.current)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, [
|
|
47
|
+
config.syncSetting?.autoSync,
|
|
48
|
+
config.syncSetting?.autoSyncInterval,
|
|
49
|
+
config.syncSetting?.autoSyncDirection
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
@@ -5,22 +5,65 @@
|
|
|
5
5
|
import {
|
|
6
6
|
Button,
|
|
7
7
|
Switch,
|
|
8
|
-
|
|
8
|
+
Select,
|
|
9
|
+
Space
|
|
9
10
|
} from 'antd'
|
|
10
11
|
import {
|
|
11
12
|
ImportOutlined,
|
|
12
|
-
ExportOutlined
|
|
13
|
-
InfoCircleOutlined
|
|
13
|
+
ExportOutlined
|
|
14
14
|
} from '@ant-design/icons'
|
|
15
15
|
import Upload from '../common/upload'
|
|
16
|
+
import HelpIcon from '../common/help-icon'
|
|
16
17
|
|
|
17
18
|
const e = window.translate
|
|
18
19
|
|
|
20
|
+
const intervalOptions = [
|
|
21
|
+
{ value: 0, label: e('autoSyncOnChange') },
|
|
22
|
+
{ value: 5, label: '5 ' + e('minutes') },
|
|
23
|
+
{ value: 10, label: '10 ' + e('minutes') },
|
|
24
|
+
{ value: 15, label: '15 ' + e('minutes') },
|
|
25
|
+
{ value: 30, label: '30 ' + e('minutes') },
|
|
26
|
+
{ value: 60, label: '1 ' + e('hours') },
|
|
27
|
+
{ value: 120, label: '2 ' + e('hours') },
|
|
28
|
+
{ value: 360, label: '6 ' + e('hours') },
|
|
29
|
+
{ value: 720, label: '12 ' + e('hours') },
|
|
30
|
+
{ value: 1440, label: '24 ' + e('hours') }
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const directionOptions = [
|
|
34
|
+
{ value: 'upload', label: e('uploadSettings') },
|
|
35
|
+
{ value: 'download', label: e('downloadSettings') }
|
|
36
|
+
]
|
|
37
|
+
|
|
19
38
|
export default function DataTransport (props) {
|
|
20
39
|
const txt = e('autoSync')
|
|
21
40
|
const {
|
|
22
41
|
store
|
|
23
42
|
} = window
|
|
43
|
+
|
|
44
|
+
const syncSetting = props.config.syncSetting || {}
|
|
45
|
+
const autoSyncEnabled = syncSetting.autoSync || false
|
|
46
|
+
const autoSyncInterval = syncSetting.autoSyncInterval || 0
|
|
47
|
+
const autoSyncDirection = syncSetting.autoSyncDirection || 'upload'
|
|
48
|
+
|
|
49
|
+
function handleAutoSync (checked) {
|
|
50
|
+
store.updateSyncSetting({
|
|
51
|
+
autoSync: checked
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function handleIntervalChange (value) {
|
|
56
|
+
store.updateSyncSetting({
|
|
57
|
+
autoSyncInterval: value
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function handleDirectionChange (value) {
|
|
62
|
+
store.updateSyncSetting({
|
|
63
|
+
autoSyncDirection: value
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
24
67
|
return (
|
|
25
68
|
<div className='pd2 fix'>
|
|
26
69
|
<div className='fleft'>
|
|
@@ -45,15 +88,33 @@ export default function DataTransport (props) {
|
|
|
45
88
|
</div>
|
|
46
89
|
<div className='fright'>
|
|
47
90
|
<Switch
|
|
48
|
-
checked={
|
|
91
|
+
checked={autoSyncEnabled}
|
|
49
92
|
checkedChildren={txt}
|
|
50
|
-
onChange={
|
|
93
|
+
onChange={handleAutoSync}
|
|
51
94
|
unCheckedChildren={txt}
|
|
52
95
|
className='mg3l mg1r'
|
|
53
96
|
/>
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
97
|
+
{autoSyncEnabled && (
|
|
98
|
+
<Space className='mg1l' size='small'>
|
|
99
|
+
<Select
|
|
100
|
+
value={autoSyncInterval}
|
|
101
|
+
onChange={handleIntervalChange}
|
|
102
|
+
options={intervalOptions}
|
|
103
|
+
style={{ width: 120 }}
|
|
104
|
+
popupMatchSelectWidth={false}
|
|
105
|
+
/>
|
|
106
|
+
<Select
|
|
107
|
+
value={autoSyncDirection}
|
|
108
|
+
onChange={handleDirectionChange}
|
|
109
|
+
options={directionOptions}
|
|
110
|
+
style={{ width: 100 }}
|
|
111
|
+
popupMatchSelectWidth={false}
|
|
112
|
+
/>
|
|
113
|
+
</Space>
|
|
114
|
+
)}
|
|
115
|
+
<HelpIcon
|
|
116
|
+
link='https://github.com/electerm/electerm/wiki/Auto-data-Sync'
|
|
117
|
+
/>
|
|
57
118
|
</div>
|
|
58
119
|
</div>
|
|
59
120
|
)
|
|
@@ -74,9 +74,15 @@ function renderAddonBefore (props, realPath) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
function renderAddonAfter (isLoadingRemote, onGoto, GoIcon, type) {
|
|
77
|
+
const handleClick = (e) => {
|
|
78
|
+
e.stopPropagation()
|
|
79
|
+
if (!isLoadingRemote) {
|
|
80
|
+
onGoto(type)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
77
83
|
return (
|
|
78
84
|
<GoIcon
|
|
79
|
-
onClick={
|
|
85
|
+
onClick={handleClick}
|
|
80
86
|
/>
|
|
81
87
|
)
|
|
82
88
|
}
|
|
@@ -135,11 +135,13 @@ export default class ShortcutEdit extends PureComponent {
|
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
renderClear () {
|
|
138
|
-
|
|
138
|
+
const { renderClear, handleClear, data } = this.props
|
|
139
|
+
const hasShortcut = data && data.shortcut
|
|
140
|
+
if (renderClear && hasShortcut && handleClear) {
|
|
139
141
|
return (
|
|
140
142
|
<CloseOutlined
|
|
141
143
|
className='pointer mg1l'
|
|
142
|
-
onClick={
|
|
144
|
+
onClick={handleClear}
|
|
143
145
|
/>
|
|
144
146
|
)
|
|
145
147
|
}
|
|
@@ -6,7 +6,7 @@ import { auto } from 'manate/react'
|
|
|
6
6
|
import TreeList from '../tree-list/tree-list'
|
|
7
7
|
|
|
8
8
|
export default auto(function BookmarkSelect (props) {
|
|
9
|
-
const { store, from } = props
|
|
9
|
+
const { store, from, autoFocus } = props
|
|
10
10
|
const {
|
|
11
11
|
listStyle,
|
|
12
12
|
openedSideBar,
|
|
@@ -38,7 +38,8 @@ export default auto(function BookmarkSelect (props) {
|
|
|
38
38
|
bookmarkGroups: store.getBookmarkGroupsTotal(),
|
|
39
39
|
expandedKeys,
|
|
40
40
|
leftSidebarWidth,
|
|
41
|
-
bookmarkGroupTree: store.bookmarkGroupTree
|
|
41
|
+
bookmarkGroupTree: store.bookmarkGroupTree,
|
|
42
|
+
autoFocus
|
|
42
43
|
}
|
|
43
44
|
return (
|
|
44
45
|
<TreeList
|
|
@@ -40,7 +40,9 @@ export default function HistoryItem (props) {
|
|
|
40
40
|
e.stopPropagation()
|
|
41
41
|
refsStatic.get('bookmark-from-history-modal')?.show(item.tab)
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
if (!item.tab) {
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
44
46
|
const title = createTitleWithTag(item.tab)
|
|
45
47
|
const tt = createTitle(item.tab)
|
|
46
48
|
return (
|
|
@@ -8,6 +8,7 @@ import { Switch } from 'antd'
|
|
|
8
8
|
import { UnorderedListOutlined } from '@ant-design/icons'
|
|
9
9
|
import HistoryItem from './history-item'
|
|
10
10
|
import { getItemJSON, setItemJSON } from '../../common/safe-local-storage.js'
|
|
11
|
+
import '../setting-panel/list.styl'
|
|
11
12
|
|
|
12
13
|
const SORT_BY_FREQ_KEY = 'electerm-history-sort-by-frequency'
|
|
13
14
|
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
PlusCircleOutlined,
|
|
7
7
|
SettingOutlined,
|
|
8
8
|
UpCircleOutlined,
|
|
9
|
-
BarsOutlined,
|
|
10
9
|
AppstoreOutlined,
|
|
11
10
|
ThunderboltOutlined
|
|
12
11
|
} from '@ant-design/icons'
|
|
@@ -92,7 +91,6 @@ export default function Sidebar (props) {
|
|
|
92
91
|
openAbout,
|
|
93
92
|
openSettingSync,
|
|
94
93
|
openTerminalThemes,
|
|
95
|
-
toggleBatchOp,
|
|
96
94
|
setLeftSidePanelWidth
|
|
97
95
|
} = store
|
|
98
96
|
const {
|
|
@@ -102,7 +100,6 @@ export default function Sidebar (props) {
|
|
|
102
100
|
shouldUpgrade
|
|
103
101
|
} = upgradeInfo
|
|
104
102
|
const showSetting = showModal === modals.setting
|
|
105
|
-
const showBatchOp = showModal === modals.batchOps
|
|
106
103
|
const settingActive = showSetting && settingTab === settingMap.setting && settingItem.id === 'setting-common'
|
|
107
104
|
const syncActive = showSetting && settingTab === settingMap.setting && settingItem.id === 'setting-sync'
|
|
108
105
|
const themeActive = showSetting && settingTab === settingMap.terminalThemes
|
|
@@ -190,12 +187,6 @@ export default function Sidebar (props) {
|
|
|
190
187
|
spin={isSyncingSetting}
|
|
191
188
|
/>
|
|
192
189
|
</SideIcon>
|
|
193
|
-
<SideIcon
|
|
194
|
-
title={e('batchOp')}
|
|
195
|
-
active={showBatchOp}
|
|
196
|
-
>
|
|
197
|
-
<BarsOutlined className='iblock font20 control-icon' onClick={toggleBatchOp} />
|
|
198
|
-
</SideIcon>
|
|
199
190
|
<SideIcon
|
|
200
191
|
title={e('widgets')}
|
|
201
192
|
active={widgetsActive}
|
|
@@ -75,7 +75,7 @@ export default function AddBtnMenu ({
|
|
|
75
75
|
|
|
76
76
|
let listContent
|
|
77
77
|
if (activeTab === 'bookmarks') {
|
|
78
|
-
listContent = <BookmarksList store={window.store} />
|
|
78
|
+
listContent = <BookmarksList store={window.store} autoFocus />
|
|
79
79
|
} else {
|
|
80
80
|
listContent = <History store={window.store} />
|
|
81
81
|
}
|
|
@@ -40,15 +40,18 @@ export default class AddBtn extends Component {
|
|
|
40
40
|
componentWillUnmount () {
|
|
41
41
|
if (this.state.open) {
|
|
42
42
|
document.removeEventListener('click', this.handleDocumentClick)
|
|
43
|
+
document.removeEventListener('keydown', this.handleKeyDown)
|
|
43
44
|
}
|
|
44
45
|
// Clean up portal container
|
|
45
46
|
if (this.portalContainer) {
|
|
46
47
|
document.body.removeChild(this.portalContainer)
|
|
47
48
|
this.portalContainer = null
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
handleKeyDown = (e) => {
|
|
53
|
+
if (e.key === 'Escape') {
|
|
54
|
+
this.setState({ open: false })
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
57
|
|
|
@@ -56,8 +59,10 @@ export default class AddBtn extends Component {
|
|
|
56
59
|
// Attach or detach document click listener only when menu open state changes
|
|
57
60
|
if (this.state.open && !prevState.open) {
|
|
58
61
|
document.addEventListener('click', this.handleDocumentClick)
|
|
62
|
+
document.addEventListener('keydown', this.handleKeyDown)
|
|
59
63
|
} else if (!this.state.open && prevState.open) {
|
|
60
64
|
document.removeEventListener('click', this.handleDocumentClick)
|
|
65
|
+
document.removeEventListener('keydown', this.handleKeyDown)
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
|
|
@@ -115,17 +120,6 @@ export default class AddBtn extends Component {
|
|
|
115
120
|
)
|
|
116
121
|
}
|
|
117
122
|
|
|
118
|
-
focusSearchInput = () => {
|
|
119
|
-
// Focus the search input after the menu renders
|
|
120
|
-
this.focusTimeout = setTimeout(() => {
|
|
121
|
-
const searchInput = this.menuRef.current?.querySelector('.add-menu-list .ant-input')
|
|
122
|
-
if (searchInput) {
|
|
123
|
-
searchInput.focus()
|
|
124
|
-
searchInput.select()
|
|
125
|
-
}
|
|
126
|
-
}, 500)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
123
|
handleAddBtnClick = () => {
|
|
130
124
|
if (this.state.open) {
|
|
131
125
|
this.setState({ open: false })
|
|
@@ -172,7 +166,7 @@ export default class AddBtn extends Component {
|
|
|
172
166
|
menuPosition,
|
|
173
167
|
menuTop,
|
|
174
168
|
menuLeft
|
|
175
|
-
}
|
|
169
|
+
})
|
|
176
170
|
|
|
177
171
|
window.openTabBatch = this.props.batch
|
|
178
172
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useEffect } from 'react'
|
|
2
|
-
import { Button, Space } from 'antd'
|
|
2
|
+
import { Button, Space, Input } from 'antd'
|
|
3
3
|
import { ArrowRightOutlined, ThunderboltOutlined } from '@ant-design/icons'
|
|
4
4
|
import message from '../common/message'
|
|
5
5
|
import InputAutoFocus from '../common/input-auto-focus'
|
|
@@ -29,18 +29,14 @@ export default function QuickConnect ({ batch, inputOnly }) {
|
|
|
29
29
|
const [inputValue, setInputValue] = useState('')
|
|
30
30
|
const inputRef = useRef(null)
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
if (showInput && inputRef.current) {
|
|
34
|
-
inputRef.current.focus()
|
|
35
|
-
}
|
|
36
|
-
}, [showInput])
|
|
37
|
-
|
|
38
|
-
// When inputOnly is true, always show the input
|
|
32
|
+
// When inputOnly is true, always show the input (without auto-focus)
|
|
39
33
|
useEffect(() => {
|
|
40
34
|
if (inputOnly) {
|
|
41
35
|
setShowInput(true)
|
|
36
|
+
} else if (showInput && inputRef.current) {
|
|
37
|
+
inputRef.current.focus()
|
|
42
38
|
}
|
|
43
|
-
}, [inputOnly])
|
|
39
|
+
}, [inputOnly, showInput])
|
|
44
40
|
|
|
45
41
|
const handleToggle = () => {
|
|
46
42
|
setShowInput(!showInput)
|
|
@@ -94,7 +90,7 @@ export default function QuickConnect ({ batch, inputOnly }) {
|
|
|
94
90
|
<Button
|
|
95
91
|
{...iconsProps1}
|
|
96
92
|
/>
|
|
97
|
-
<InputAutoFocus {...inputProps} />
|
|
93
|
+
{inputOnly ? <Input {...inputProps} /> : <InputAutoFocus {...inputProps} />}
|
|
98
94
|
<Button
|
|
99
95
|
{...iconProps}
|
|
100
96
|
/>
|