@electerm/electerm-react 1.51.21 → 1.60.6
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 -0
- package/client/common/default-setting.js +12 -1
- package/client/components/ai/ai-chat-history-item.jsx +69 -0
- package/client/components/ai/ai-chat-history.jsx +31 -0
- package/client/components/ai/ai-chat.jsx +164 -0
- package/client/components/ai/ai-config.jsx +133 -0
- package/client/components/ai/ai-output.jsx +123 -0
- package/client/components/ai/ai.styl +69 -0
- package/client/components/ai/providers.js +14 -0
- package/client/components/footer/batch-input.jsx +13 -67
- package/client/components/footer/footer-entry.jsx +19 -3
- package/client/components/footer/footer.styl +4 -0
- package/client/components/footer/tab-select.jsx +9 -3
- package/client/components/layout/layout.jsx +5 -4
- package/client/components/main/main.jsx +14 -2
- package/client/components/shortcuts/shortcut-control.jsx +17 -2
- package/client/components/shortcuts/shortcut-handler.js +24 -8
- package/client/components/shortcuts/shortcuts-defaults.js +6 -0
- package/client/components/sidebar/app-running-time.jsx +35 -0
- package/client/components/sidebar/info-modal.jsx +2 -0
- package/client/components/tabs/app-drag.jsx +1 -1
- package/client/components/tabs/index.jsx +8 -17
- package/client/store/common.js +37 -2
- package/client/store/index.js +2 -290
- package/client/store/init-state.js +7 -1
- package/client/store/store.js +298 -0
- package/client/store/tab.js +54 -1
- package/client/store/watch.js +9 -2
- package/package.json +1 -1
|
@@ -26,37 +26,23 @@ export default class BatchInput extends Component {
|
|
|
26
26
|
super(props)
|
|
27
27
|
this.state = {
|
|
28
28
|
cmd: '',
|
|
29
|
-
selectedTabIds: [props.activeTabId],
|
|
30
29
|
open: false,
|
|
31
30
|
enter: false
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
componentDidUpdate (prevProps) {
|
|
36
|
-
if (prevProps.activeTabId !== this.props.activeTabId) {
|
|
37
|
-
this.setState(prevState => {
|
|
38
|
-
const newSelectedTabIds = prevState.selectedTabIds.filter(
|
|
39
|
-
id => id !== this.props.activeTabId
|
|
40
|
-
)
|
|
41
|
-
newSelectedTabIds.unshift(this.props.activeTabId)
|
|
42
|
-
return {
|
|
43
|
-
selectedTabIds: newSelectedTabIds
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
34
|
componentWillUnmount () {
|
|
50
35
|
clearTimeout(this.timer)
|
|
51
36
|
}
|
|
52
37
|
|
|
53
38
|
handleEnter = (e) => {
|
|
54
|
-
const {
|
|
39
|
+
const { batchInputSelectedTabIds } = window.store
|
|
40
|
+
const { cmd } = this.state
|
|
55
41
|
if (!cmd.trim()) {
|
|
56
42
|
return
|
|
57
43
|
}
|
|
58
44
|
window.store.addBatchInput(cmd)
|
|
59
|
-
this.props.input(cmd,
|
|
45
|
+
this.props.input(cmd, Array.from(batchInputSelectedTabIds))
|
|
60
46
|
this.setState({
|
|
61
47
|
cmd: '',
|
|
62
48
|
open: false
|
|
@@ -64,43 +50,6 @@ export default class BatchInput extends Component {
|
|
|
64
50
|
e.stopPropagation()
|
|
65
51
|
}
|
|
66
52
|
|
|
67
|
-
onSelectAll = () => {
|
|
68
|
-
this.setState({
|
|
69
|
-
selectedTabIds: this.getTabs().map(tab => tab.id)
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
onSelectNone = () => {
|
|
74
|
-
this.setState({
|
|
75
|
-
selectedTabIds: [this.props.activeTabId]
|
|
76
|
-
})
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
filterValidTabIds = (tabIds) => {
|
|
80
|
-
return tabIds.filter(id => {
|
|
81
|
-
return this.props.tabs.some(tab => tab.id === id)
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
onSelect = (id) => {
|
|
86
|
-
this.setState(prevState => {
|
|
87
|
-
const selectedTabIds = prevState.selectedTabIds.includes(id)
|
|
88
|
-
? prevState.selectedTabIds.filter(tabId => tabId !== id)
|
|
89
|
-
: [...prevState.selectedTabIds, id]
|
|
90
|
-
|
|
91
|
-
// Ensure at least the current tab is selected
|
|
92
|
-
if (selectedTabIds.length === 0) {
|
|
93
|
-
return {
|
|
94
|
-
selectedTabIds: [this.props.activeTabId]
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
selectedTabIds
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
53
|
handleChange = (v = '') => {
|
|
105
54
|
let vv = v.replace(/^\d+:/, '').replace(/\n$/, '')
|
|
106
55
|
if (vv === batchInputLsKey) {
|
|
@@ -118,15 +67,9 @@ export default class BatchInput extends Component {
|
|
|
118
67
|
|
|
119
68
|
handleClick = () => {
|
|
120
69
|
this.setState({
|
|
121
|
-
open: true
|
|
122
|
-
selectedTabIds: this.filterValidTabIds(this.state.selectedTabIds)
|
|
123
|
-
})
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
handleChangeAll = toAll => {
|
|
127
|
-
this.setState({
|
|
128
|
-
toAll
|
|
70
|
+
open: true
|
|
129
71
|
})
|
|
72
|
+
window.store.filterBatchInputSelectedTabIds()
|
|
130
73
|
}
|
|
131
74
|
|
|
132
75
|
handleBlur = () => {
|
|
@@ -192,7 +135,10 @@ export default class BatchInput extends Component {
|
|
|
192
135
|
}
|
|
193
136
|
|
|
194
137
|
render () {
|
|
195
|
-
const { cmd, open,
|
|
138
|
+
const { cmd, open, enter } = this.state
|
|
139
|
+
const {
|
|
140
|
+
batchInputSelectedTabIds
|
|
141
|
+
} = this.props
|
|
196
142
|
const opts = {
|
|
197
143
|
options: this.buildOptions(),
|
|
198
144
|
placeholder: e('batchInput'),
|
|
@@ -217,10 +163,10 @@ export default class BatchInput extends Component {
|
|
|
217
163
|
const tabSelectProps = {
|
|
218
164
|
activeTabId: this.props.activeTabId,
|
|
219
165
|
tabs: this.getTabs(),
|
|
220
|
-
selectedTabIds,
|
|
221
|
-
onSelectAll:
|
|
222
|
-
onSelectNone:
|
|
223
|
-
onSelect:
|
|
166
|
+
selectedTabIds: batchInputSelectedTabIds,
|
|
167
|
+
onSelectAll: window.store.selectAllBatchInputTabs,
|
|
168
|
+
onSelectNone: window.store.selectNoneBatchInputTabs,
|
|
169
|
+
onSelect: window.store.onSelectBatchInputSelectedTabId
|
|
224
170
|
}
|
|
225
171
|
return (
|
|
226
172
|
<span
|
|
@@ -49,11 +49,13 @@ export default auto(function FooterEntry (props) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
function renderBatchInputs () {
|
|
52
|
+
const { store } = props
|
|
52
53
|
const batchProps = {
|
|
53
54
|
input: batchInput,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
tabs: store.tabs,
|
|
56
|
+
batchInputs: store.batchInputs,
|
|
57
|
+
batchInputSelectedTabIds: store.batchInputSelectedTabIds,
|
|
58
|
+
activeTabId: store.activeTabId
|
|
57
59
|
}
|
|
58
60
|
return (
|
|
59
61
|
<div className='terminal-footer-unit terminal-footer-center'>
|
|
@@ -72,6 +74,19 @@ export default auto(function FooterEntry (props) {
|
|
|
72
74
|
)
|
|
73
75
|
}
|
|
74
76
|
|
|
77
|
+
function renderAIIcon () {
|
|
78
|
+
return (
|
|
79
|
+
<div className='terminal-footer-unit terminal-footer-ai'>
|
|
80
|
+
<span
|
|
81
|
+
className='ai-icon'
|
|
82
|
+
onClick={window.store.handleOpenAIPanel}
|
|
83
|
+
>
|
|
84
|
+
AI
|
|
85
|
+
</span>
|
|
86
|
+
</div>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
function renderEncodingInfo () {
|
|
76
91
|
const selectProps = {
|
|
77
92
|
style: {
|
|
@@ -148,6 +163,7 @@ export default auto(function FooterEntry (props) {
|
|
|
148
163
|
return (
|
|
149
164
|
<div {...sideProps}>
|
|
150
165
|
<div className='terminal-footer-flex'>
|
|
166
|
+
{renderAIIcon()}
|
|
151
167
|
{renderQuickCommands()}
|
|
152
168
|
{renderBatchInputs()}
|
|
153
169
|
{renderEncodingInfo()}
|
|
@@ -14,7 +14,7 @@ export default function TabSelect (props) {
|
|
|
14
14
|
const itemProps = {
|
|
15
15
|
tab,
|
|
16
16
|
selected,
|
|
17
|
-
onSelect:
|
|
17
|
+
onSelect: window.store.onSelectBatchInputSelectedTabId,
|
|
18
18
|
id: tab.id,
|
|
19
19
|
isCurrent: tab.id === activeTabId
|
|
20
20
|
}
|
|
@@ -26,18 +26,24 @@ export default function TabSelect (props) {
|
|
|
26
26
|
)
|
|
27
27
|
})
|
|
28
28
|
}
|
|
29
|
+
function onSelectAll () {
|
|
30
|
+
window.store.selectAllBatchInputTabs()
|
|
31
|
+
}
|
|
32
|
+
function onSelectNone () {
|
|
33
|
+
window.store.selectNoneBatchInputTabs()
|
|
34
|
+
}
|
|
29
35
|
function renderBtns () {
|
|
30
36
|
return (
|
|
31
37
|
<div className='pd1t pd2b font12'>
|
|
32
38
|
<span
|
|
33
39
|
className='mg1r pointer'
|
|
34
|
-
onClick={
|
|
40
|
+
onClick={onSelectAll}
|
|
35
41
|
>
|
|
36
42
|
All
|
|
37
43
|
</span>
|
|
38
44
|
<span
|
|
39
45
|
className='pointer'
|
|
40
|
-
onClick={
|
|
46
|
+
onClick={onSelectNone}
|
|
41
47
|
>
|
|
42
48
|
None
|
|
43
49
|
</span>
|
|
@@ -61,12 +61,13 @@ export default auto(function Layout (props) {
|
|
|
61
61
|
width,
|
|
62
62
|
pinnedQuickCommandBar,
|
|
63
63
|
leftSidebarWidth,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
rightPanelVisible,
|
|
65
|
+
rightPanelPinned,
|
|
66
|
+
rightPanelWidth,
|
|
67
|
+
pinned
|
|
67
68
|
} = props.store
|
|
68
69
|
const l = pinned ? leftSidebarWidth : 0
|
|
69
|
-
const r =
|
|
70
|
+
const r = rightPanelPinned && rightPanelVisible ? rightPanelWidth : 0
|
|
70
71
|
const w = width - l - r - 42
|
|
71
72
|
const h = height - footerHeight - (pinnedQuickCommandBar ? quickCommandBoxHeight : 0)
|
|
72
73
|
return layoutAlg(layout, w, h)
|
|
@@ -29,6 +29,7 @@ import RightSidePanel from '../side-panel-r/side-panel-r'
|
|
|
29
29
|
import ConnectionHoppingWarning from './connection-hopping-warnning'
|
|
30
30
|
import SshConfigLoadNotify from '../ssh-config/ssh-config-load-notify'
|
|
31
31
|
import LoadSshConfigs from '../ssh-config/load-ssh-configs'
|
|
32
|
+
import AIChat from '../ai/ai-chat'
|
|
32
33
|
import { pick } from 'lodash-es'
|
|
33
34
|
import deepCopy from 'json-deep-copy'
|
|
34
35
|
import './wrapper.styl'
|
|
@@ -81,7 +82,7 @@ export default auto(function Index (props) {
|
|
|
81
82
|
store.isSecondInstance = window.pre.runSync('isSecondInstance')
|
|
82
83
|
store.initData()
|
|
83
84
|
store.checkForDbUpgrade()
|
|
84
|
-
window.pre.runGlobalAsync('registerDeepLink')
|
|
85
|
+
// window.pre.runGlobalAsync('registerDeepLink')
|
|
85
86
|
}, [])
|
|
86
87
|
|
|
87
88
|
const { store } = props
|
|
@@ -213,6 +214,17 @@ export default auto(function Index (props) {
|
|
|
213
214
|
hasOldConnectionHoppingBookmark: store.hasOldConnectionHoppingBookmark,
|
|
214
215
|
configLoaded
|
|
215
216
|
}
|
|
217
|
+
const aiChatProps = {
|
|
218
|
+
aiChatHistory: store.aiChatHistory,
|
|
219
|
+
config,
|
|
220
|
+
selectedTabIds: store.batchInputSelectedTabIds,
|
|
221
|
+
tabs: store.getTabs(),
|
|
222
|
+
activeTabId: store.activeTabId,
|
|
223
|
+
showAIConfig: store.showAIConfig
|
|
224
|
+
}
|
|
225
|
+
const rightPanelContent = store.rightPanelTab === 'ai'
|
|
226
|
+
? <AIChat {...aiChatProps} />
|
|
227
|
+
: <TerminalInfo {...terminalInfoProps} />
|
|
216
228
|
return (
|
|
217
229
|
<ConfigProvider
|
|
218
230
|
theme={uiThemeConfig}
|
|
@@ -269,7 +281,7 @@ export default auto(function Index (props) {
|
|
|
269
281
|
<Resolutions {...resProps} />
|
|
270
282
|
<InfoModal {...infoModalProps} />
|
|
271
283
|
<RightSidePanel {...rightPanelProps}>
|
|
272
|
-
|
|
284
|
+
{rightPanelContent}
|
|
273
285
|
</RightSidePanel>
|
|
274
286
|
<SshConfigLoadNotify {...sshConfigProps} />
|
|
275
287
|
<LoadSshConfigs
|
|
@@ -9,8 +9,10 @@ import { throttle } from 'lodash-es'
|
|
|
9
9
|
|
|
10
10
|
class ShortcutControl extends React.PureComponent {
|
|
11
11
|
componentDidMount () {
|
|
12
|
-
|
|
13
|
-
window.addEventListener('
|
|
12
|
+
const onEvent = this.handleKeyboardEvent.bind(this)
|
|
13
|
+
window.addEventListener('keydown', onEvent)
|
|
14
|
+
window.addEventListener('mousedown', onEvent)
|
|
15
|
+
window.addEventListener('mousewheel', onEvent)
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
closeCurrentTabShortcut = throttle((e) => {
|
|
@@ -21,6 +23,19 @@ class ShortcutControl extends React.PureComponent {
|
|
|
21
23
|
}
|
|
22
24
|
}, 500)
|
|
23
25
|
|
|
26
|
+
mouseWheelDownCloseTabShortcut = throttle((e) => {
|
|
27
|
+
e.stopPropagation()
|
|
28
|
+
|
|
29
|
+
// Check if the event target is within a .tab element
|
|
30
|
+
const tabElement = e.target.closest('.tab')
|
|
31
|
+
if (tabElement) {
|
|
32
|
+
const tabId = tabElement.getAttribute('data-id')
|
|
33
|
+
if (tabId) {
|
|
34
|
+
window.store.delTab(tabId)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, 500)
|
|
38
|
+
|
|
24
39
|
reloadCurrentTabShortcut = throttle((e) => {
|
|
25
40
|
e.stopPropagation()
|
|
26
41
|
window.store.reloadTab()
|
|
@@ -53,12 +53,14 @@ export function shortcutExtend (Cls) {
|
|
|
53
53
|
metaKey,
|
|
54
54
|
altKey,
|
|
55
55
|
wheelDeltaY,
|
|
56
|
+
button,
|
|
56
57
|
type,
|
|
57
58
|
key
|
|
58
59
|
} = event
|
|
59
60
|
if (this.cmdAddon) {
|
|
60
61
|
this.cmdAddon.handleKey(event)
|
|
61
62
|
}
|
|
63
|
+
|
|
62
64
|
if (
|
|
63
65
|
this.term &&
|
|
64
66
|
key === 'Backspace' &&
|
|
@@ -66,6 +68,7 @@ export function shortcutExtend (Cls) {
|
|
|
66
68
|
!altKey &&
|
|
67
69
|
!ctrlKey
|
|
68
70
|
) {
|
|
71
|
+
console.log('handleKeyboardEvent: Handling Backspace key')
|
|
69
72
|
this.props.onDelKeyPressed()
|
|
70
73
|
const delKey = this.props.config.backspaceMode === '^?' ? 8 : 127
|
|
71
74
|
const altDelDelKey = delKey === 8 ? 127 : 8
|
|
@@ -78,6 +81,7 @@ export function shortcutExtend (Cls) {
|
|
|
78
81
|
) {
|
|
79
82
|
return true
|
|
80
83
|
}
|
|
84
|
+
|
|
81
85
|
if (
|
|
82
86
|
this.term &&
|
|
83
87
|
key === 'c' &&
|
|
@@ -89,31 +93,42 @@ export function shortcutExtend (Cls) {
|
|
|
89
93
|
) {
|
|
90
94
|
this.onZmodemEnd()
|
|
91
95
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
|
|
97
|
+
let codeName
|
|
98
|
+
if (type === 'mousedown' && button === 1) {
|
|
99
|
+
codeName = 'mouseWheel'
|
|
100
|
+
} else {
|
|
101
|
+
codeName = event instanceof window.WheelEvent
|
|
102
|
+
? (wheelDeltaY > 0 ? 'mouseWheelUp' : 'mouseWheelDown')
|
|
103
|
+
: code
|
|
104
|
+
}
|
|
105
|
+
|
|
95
106
|
const codeK = getKeyCharacter(codeName)
|
|
96
|
-
|
|
107
|
+
|
|
108
|
+
const noControlKey = type !== 'mousedown' && !ctrlKey && !shiftKey && !metaKey && !altKey
|
|
97
109
|
if (noControlKey) {
|
|
98
110
|
return
|
|
99
111
|
}
|
|
100
|
-
const r =
|
|
112
|
+
const r = codeName === 'mouseWheel'
|
|
113
|
+
? 'mouseWheel'
|
|
114
|
+
: (ctrlKey ? 'ctrl+' : '') +
|
|
101
115
|
(metaKey ? 'meta+' : '') +
|
|
102
116
|
(shiftKey ? 'shift+' : '') +
|
|
103
117
|
(altKey ? 'alt+' : '') +
|
|
104
118
|
codeK.toLowerCase()
|
|
119
|
+
|
|
105
120
|
const shortcutsConfig = buildConfig(this.props.config, d => !d.hidden)
|
|
106
121
|
const keys = Object.keys(shortcutsConfig)
|
|
107
122
|
const len = keys.length
|
|
123
|
+
|
|
108
124
|
if (this.term) {
|
|
109
125
|
const qmMatch = window.store.quickCommands.find(d => d.shortcut === r)
|
|
110
126
|
if (qmMatch) {
|
|
111
|
-
window.store.runQuickCommandItem(
|
|
112
|
-
qmMatch.id
|
|
113
|
-
)
|
|
127
|
+
window.store.runQuickCommandItem(qmMatch.id)
|
|
114
128
|
return false
|
|
115
129
|
}
|
|
116
130
|
}
|
|
131
|
+
|
|
117
132
|
for (let i = 0; i < len; i++) {
|
|
118
133
|
const k = keys[i]
|
|
119
134
|
const conf = shortcutsConfig[k]
|
|
@@ -128,6 +143,7 @@ export function shortcutExtend (Cls) {
|
|
|
128
143
|
}
|
|
129
144
|
}
|
|
130
145
|
}
|
|
146
|
+
|
|
131
147
|
return !!this.term
|
|
132
148
|
}
|
|
133
149
|
return Cls
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
ClockCircleOutlined
|
|
4
|
+
} from '@ant-design/icons'
|
|
5
|
+
import dayjs from 'dayjs'
|
|
6
|
+
import duration from 'dayjs/plugin/duration'
|
|
7
|
+
|
|
8
|
+
dayjs.extend(duration)
|
|
9
|
+
|
|
10
|
+
const e = window.translate
|
|
11
|
+
|
|
12
|
+
export default function RunningTime () {
|
|
13
|
+
const [runningTime, setRunningTime] = useState(0)
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const startTime = window.pre.runSync('getInitTime')
|
|
17
|
+
|
|
18
|
+
const timer = setInterval(() => {
|
|
19
|
+
const currentTime = Date.now()
|
|
20
|
+
const diff = Math.floor((currentTime - startTime) / 1000)
|
|
21
|
+
setRunningTime(diff)
|
|
22
|
+
}, 1000)
|
|
23
|
+
|
|
24
|
+
return () => clearInterval(timer)
|
|
25
|
+
}, [])
|
|
26
|
+
const formatRunningTime = (seconds) => {
|
|
27
|
+
return dayjs.duration(seconds, 'seconds').format('HH:mm:ss')
|
|
28
|
+
}
|
|
29
|
+
return (
|
|
30
|
+
<p className='mg2b'>
|
|
31
|
+
<ClockCircleOutlined /> <b>{e('runningTime')} ➾</b>
|
|
32
|
+
<span className='mg1l'>{formatRunningTime(runningTime)}</span>
|
|
33
|
+
</p>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { Modal, Tabs, Button } from 'antd'
|
|
16
16
|
import Link from '../common/external-link'
|
|
17
17
|
import LogoElem from '../common/logo-elem'
|
|
18
|
+
import RunningTime from './app-running-time'
|
|
18
19
|
|
|
19
20
|
import {
|
|
20
21
|
packInfo,
|
|
@@ -121,6 +122,7 @@ export default memo(function InfoModal (props) {
|
|
|
121
122
|
<div>
|
|
122
123
|
<LogoElem />
|
|
123
124
|
<p className='mg2b'>{e('desc')}</p>
|
|
125
|
+
<RunningTime />
|
|
124
126
|
<p className='mg1b'>
|
|
125
127
|
<UserOutlined /> <b className='mg1r'>{e('author')} ➾</b>
|
|
126
128
|
<Link to={authorUrl} className='mg1l'>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react'
|
|
6
6
|
import runIdle from '../../common/run-idle'
|
|
7
|
-
import {
|
|
7
|
+
import { throttle } from 'lodash-es'
|
|
8
8
|
import TabTitle from './tab-title'
|
|
9
9
|
import {
|
|
10
10
|
CodeFilled,
|
|
@@ -49,6 +49,7 @@ export default class Tabs extends React.Component {
|
|
|
49
49
|
constructor (props) {
|
|
50
50
|
super(props)
|
|
51
51
|
this.tabsRef = React.createRef()
|
|
52
|
+
this.domRef = React.createRef()
|
|
52
53
|
this.state = {
|
|
53
54
|
overflow: false,
|
|
54
55
|
receiveDataTabId: '',
|
|
@@ -60,13 +61,13 @@ export default class Tabs extends React.Component {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
componentDidMount () {
|
|
63
|
-
this.domRef = React.createRef()
|
|
64
64
|
const {
|
|
65
65
|
tabsRef
|
|
66
66
|
} = this
|
|
67
67
|
window.addEventListener('message', this.onEvent)
|
|
68
|
-
tabsRef.current.addEventListener('
|
|
69
|
-
|
|
68
|
+
tabsRef.current.addEventListener('wheel', this.handleWheelEvent, {
|
|
69
|
+
passive: false
|
|
70
|
+
})
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
componentDidUpdate (prevProps) {
|
|
@@ -198,16 +199,6 @@ export default class Tabs extends React.Component {
|
|
|
198
199
|
return inner ? inner.clientWidth : 0
|
|
199
200
|
}
|
|
200
201
|
|
|
201
|
-
handleClickEvent = (e) => {
|
|
202
|
-
if (e.button === 1) {
|
|
203
|
-
const p = findParentBySel(e.target, '.tab')
|
|
204
|
-
if (p) {
|
|
205
|
-
const id = p.dataset.id
|
|
206
|
-
this.props.delTab(id)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
202
|
handleAdd = e => {
|
|
212
203
|
if (!e.target.className.includes('tabs-wrapper')) {
|
|
213
204
|
return
|
|
@@ -230,7 +221,7 @@ export default class Tabs extends React.Component {
|
|
|
230
221
|
const index = tabs.findIndex(t => t.id === currentBatchTabId)
|
|
231
222
|
const tabsDomWith = Array.from(
|
|
232
223
|
document.querySelectorAll(`.v${batch + 1} .tab`)
|
|
233
|
-
).slice(0, index +
|
|
224
|
+
).slice(0, index + 2).reduce((prev, c) => {
|
|
234
225
|
return prev + c.clientWidth
|
|
235
226
|
}, 0)
|
|
236
227
|
const w = (index + 1) * tabMargin + tabsDomWith
|
|
@@ -262,7 +253,7 @@ export default class Tabs extends React.Component {
|
|
|
262
253
|
this.domRef.current.scrollTo({ left: scrollLeft, behavior: 'smooth' })
|
|
263
254
|
}
|
|
264
255
|
|
|
265
|
-
handleWheelEvent =
|
|
256
|
+
handleWheelEvent = throttle((e) => {
|
|
266
257
|
if (this.isOverflow()) {
|
|
267
258
|
if (e.deltaY < 0) {
|
|
268
259
|
this.handleScrollLeft()
|
|
@@ -270,7 +261,7 @@ export default class Tabs extends React.Component {
|
|
|
270
261
|
this.handleScrollRight()
|
|
271
262
|
}
|
|
272
263
|
}
|
|
273
|
-
}, 100)
|
|
264
|
+
}, 100, { leading: true, trailing: true })
|
|
274
265
|
|
|
275
266
|
handleClickMenu = ({ key }) => {
|
|
276
267
|
const id = key.split('##')[1]
|
package/client/store/common.js
CHANGED
|
@@ -16,12 +16,14 @@ import {
|
|
|
16
16
|
terminalActions
|
|
17
17
|
} from '../common/constants'
|
|
18
18
|
import * as ls from '../common/safe-local-storage'
|
|
19
|
+
import { action } from 'manate'
|
|
19
20
|
|
|
20
21
|
const e = window.translate
|
|
22
|
+
const { assign } = Object
|
|
21
23
|
|
|
22
24
|
export default Store => {
|
|
23
25
|
Store.prototype.storeAssign = function (updates) {
|
|
24
|
-
|
|
26
|
+
assign(window.store, updates)
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
Store.prototype.onError = function (e) {
|
|
@@ -47,13 +49,23 @@ export default Store => {
|
|
|
47
49
|
})
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
Store.prototype.openInfoPanel = function () {
|
|
52
|
+
Store.prototype.openInfoPanel = action(function () {
|
|
51
53
|
const { store } = window
|
|
52
54
|
store.rightPanelVisible = true
|
|
55
|
+
store.rightPanelTab = 'info'
|
|
56
|
+
store.openInfoPanelAction()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
Store.prototype.openInfoPanelAction = action(function () {
|
|
60
|
+
const { store } = window
|
|
53
61
|
postMessage({
|
|
54
62
|
action: terminalActions.showInfoPanel,
|
|
55
63
|
activeTabId: store.activeTabId
|
|
56
64
|
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
Store.prototype.toggleAIConfig = function () {
|
|
68
|
+
window.store.showAIConfig = !window.store.showAIConfig
|
|
57
69
|
}
|
|
58
70
|
|
|
59
71
|
Store.prototype.onResize = debounce(async function () {
|
|
@@ -262,4 +274,27 @@ export default Store => {
|
|
|
262
274
|
}
|
|
263
275
|
return window.store.applyProfile(tab)
|
|
264
276
|
}
|
|
277
|
+
|
|
278
|
+
Store.prototype.handleOpenAIPanel = function () {
|
|
279
|
+
const { store } = window
|
|
280
|
+
store.rightPanelVisible = true
|
|
281
|
+
store.rightPanelTab = 'ai'
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
Store.prototype.runCommandInTerminal = function (cmd) {
|
|
285
|
+
postMessage({
|
|
286
|
+
action: terminalActions.quickCommand,
|
|
287
|
+
cmd,
|
|
288
|
+
selectedTabIds: window.store.batchInputSelectedTabIds
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
Store.prototype.removeAiHistory = function (id) {
|
|
293
|
+
const { store } = window
|
|
294
|
+
const index = store.aiChatHistory.findIndex(d => d.id === id)
|
|
295
|
+
if (index === -1) {
|
|
296
|
+
return
|
|
297
|
+
}
|
|
298
|
+
window.store.aiChatHistory.splice(index, 1)
|
|
299
|
+
}
|
|
265
300
|
}
|