@electerm/electerm-react 1.39.109 → 1.39.119
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/components/bookmark-form/bookmark-select.jsx +96 -0
- package/client/components/bookmark-form/render-connection-hopping.jsx +15 -1
- package/client/components/quick-commands/on-drop.js +19 -0
- package/client/components/quick-commands/quick-commands-box.jsx +2 -17
- package/client/components/quick-commands/quick-commands-list.jsx +4 -19
- package/client/components/setting-panel/keywords-form.jsx +5 -0
- package/client/components/setting-panel/keywords-transport.jsx +32 -0
- package/client/components/setting-panel/setting-terminal.jsx +16 -1
- package/client/components/sftp/file-item.jsx +2 -2
- package/client/components/terminal/attach-addon-custom.js +1 -0
- package/client/components/terminal/index.jsx +3 -3
- package/client/store/sync.js +4 -1
- package/package.json +1 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// bookmark select tree
|
|
2
|
+
import createTitle from '../../common/create-title'
|
|
3
|
+
import { TreeSelect } from 'antd'
|
|
4
|
+
|
|
5
|
+
const e = window.translate
|
|
6
|
+
|
|
7
|
+
function buildTreeData (bookmarkGroups, tree) {
|
|
8
|
+
const cats = bookmarkGroups
|
|
9
|
+
const btree = cats
|
|
10
|
+
.reduce((p, k) => {
|
|
11
|
+
return {
|
|
12
|
+
...p,
|
|
13
|
+
[k.id]: k
|
|
14
|
+
}
|
|
15
|
+
}, {})
|
|
16
|
+
function buildSubCats (id) {
|
|
17
|
+
const x = btree[id]
|
|
18
|
+
if (!x) {
|
|
19
|
+
return ''
|
|
20
|
+
}
|
|
21
|
+
const y = {
|
|
22
|
+
key: x.id,
|
|
23
|
+
value: x.id,
|
|
24
|
+
title: x.title
|
|
25
|
+
}
|
|
26
|
+
y.children = [
|
|
27
|
+
...(x.bookmarkGroupIds || []).map(buildSubCats),
|
|
28
|
+
...(x.bookmarkIds || []).map(buildLeaf)
|
|
29
|
+
].filter(d => d)
|
|
30
|
+
if (y.children && !y.children.length) {
|
|
31
|
+
delete y.children
|
|
32
|
+
}
|
|
33
|
+
return y
|
|
34
|
+
}
|
|
35
|
+
function buildLeaf (id) {
|
|
36
|
+
const x = tree[id]
|
|
37
|
+
if (!x) {
|
|
38
|
+
return ''
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
value: x.id,
|
|
42
|
+
key: x.id,
|
|
43
|
+
title: createTitle(x)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const level1 = cats.filter(d => d.level !== 2)
|
|
47
|
+
.map(d => {
|
|
48
|
+
const r = {
|
|
49
|
+
title: d.title,
|
|
50
|
+
value: d.id,
|
|
51
|
+
key: d.id,
|
|
52
|
+
children: [
|
|
53
|
+
...(d.bookmarkGroupIds || []).map(buildSubCats),
|
|
54
|
+
...(d.bookmarkIds || []).map(buildLeaf)
|
|
55
|
+
].filter(d => d)
|
|
56
|
+
}
|
|
57
|
+
if (!r.children.length) {
|
|
58
|
+
return ''
|
|
59
|
+
}
|
|
60
|
+
return r
|
|
61
|
+
}).filter(d => d)
|
|
62
|
+
return level1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default function BookmarkSelect (props) {
|
|
66
|
+
const {
|
|
67
|
+
bookmarks,
|
|
68
|
+
bookmarkGroups
|
|
69
|
+
} = props
|
|
70
|
+
const tree = bookmarks
|
|
71
|
+
.reduce((p, k) => {
|
|
72
|
+
return {
|
|
73
|
+
...p,
|
|
74
|
+
[k.id]: k
|
|
75
|
+
}
|
|
76
|
+
}, {})
|
|
77
|
+
|
|
78
|
+
function onSelect (id) {
|
|
79
|
+
const item = tree[id]
|
|
80
|
+
if (item) {
|
|
81
|
+
item.bookmarkId = item.id
|
|
82
|
+
props.onSelect(item)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const treeData = buildTreeData(bookmarkGroups, tree)
|
|
86
|
+
const treeProps = {
|
|
87
|
+
treeData,
|
|
88
|
+
onChange: onSelect,
|
|
89
|
+
placeholder: e('chooseFromBookmarks'),
|
|
90
|
+
showSearch: true,
|
|
91
|
+
value: undefined
|
|
92
|
+
}
|
|
93
|
+
return (
|
|
94
|
+
<TreeSelect {...treeProps} />
|
|
95
|
+
)
|
|
96
|
+
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
authTypeMap
|
|
18
18
|
} from '../../common/constants'
|
|
19
19
|
import { useState } from 'react'
|
|
20
|
+
import BookmarkSelect from './bookmark-select'
|
|
20
21
|
|
|
21
22
|
const FormItem = Form.Item
|
|
22
23
|
const RadioButton = Radio.Button
|
|
@@ -129,7 +130,13 @@ export default function renderConnectionHopping (props) {
|
|
|
129
130
|
</FormItem>
|
|
130
131
|
)
|
|
131
132
|
}
|
|
132
|
-
|
|
133
|
+
const treeProps = {
|
|
134
|
+
bookmarks: store.bookmarks.filter(d => {
|
|
135
|
+
return d.host && d.port && d.username
|
|
136
|
+
}),
|
|
137
|
+
bookmarkGroups: store.bookmarkGroups,
|
|
138
|
+
onSelect: handleFinish
|
|
139
|
+
}
|
|
133
140
|
return (
|
|
134
141
|
<div>
|
|
135
142
|
<FormItem
|
|
@@ -144,6 +151,13 @@ export default function renderConnectionHopping (props) {
|
|
|
144
151
|
initialValues={initialValues}
|
|
145
152
|
>
|
|
146
153
|
{renderList()}
|
|
154
|
+
<FormItem
|
|
155
|
+
{...formItemLayout}
|
|
156
|
+
label={e('chooseFromBookmarks')}
|
|
157
|
+
className='mg60b'
|
|
158
|
+
>
|
|
159
|
+
<BookmarkSelect {...treeProps} />
|
|
160
|
+
</FormItem>
|
|
147
161
|
<FormItem
|
|
148
162
|
{...formItemLayout}
|
|
149
163
|
label={e('host')}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default function onDrop (e, cls) {
|
|
2
|
+
e.preventDefault()
|
|
3
|
+
const { store } = window
|
|
4
|
+
const { quickCommands } = store
|
|
5
|
+
const idDragged = e.dataTransfer.getData('idDragged')
|
|
6
|
+
const tar = cls ? e.target.closest(cls) : e.target
|
|
7
|
+
const idDrop = tar.getAttribute('data-id')
|
|
8
|
+
const idDraggedIndex = quickCommands.findIndex(
|
|
9
|
+
({ id }) => id === idDragged
|
|
10
|
+
)
|
|
11
|
+
const targetIndex = quickCommands.findIndex(
|
|
12
|
+
({ id }) => id === idDrop
|
|
13
|
+
)
|
|
14
|
+
if (idDraggedIndex !== targetIndex) {
|
|
15
|
+
const [removed] = quickCommands.splice(idDraggedIndex, 1)
|
|
16
|
+
quickCommands.splice(targetIndex, 0, removed)
|
|
17
|
+
store.setItems('quickCommands', quickCommands)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
PushpinOutlined
|
|
15
15
|
} from '@ant-design/icons'
|
|
16
16
|
import classNames from 'classnames'
|
|
17
|
+
import onDrop from './on-drop'
|
|
17
18
|
import './qm.styl'
|
|
18
19
|
|
|
19
20
|
const e = window.translate
|
|
@@ -90,23 +91,7 @@ export default class QuickCommandsFooterBox extends Component {
|
|
|
90
91
|
|
|
91
92
|
// sort quick commands array when drop, so that the dragged item will be placed at the right position, e.target.getAttribute('data-id') would target item id, e.dataTransfer.getData('idDragged') would target dragged item id, then set window.store.quickCommands use window.store.setItems
|
|
92
93
|
onDrop = e => {
|
|
93
|
-
e.
|
|
94
|
-
const { store } = window
|
|
95
|
-
const { quickCommands } = store
|
|
96
|
-
const idDragged = e.dataTransfer.getData('idDragged')
|
|
97
|
-
const idDrop = e.target.getAttribute('data-id')
|
|
98
|
-
const idDraggedIndex = quickCommands.findIndex(
|
|
99
|
-
({ id }) => id === idDragged
|
|
100
|
-
)
|
|
101
|
-
const targetIndex = quickCommands.findIndex(
|
|
102
|
-
({ id }) => id === idDrop
|
|
103
|
-
)
|
|
104
|
-
if (idDraggedIndex < targetIndex) {
|
|
105
|
-
quickCommands.splice(targetIndex, 0, quickCommands.splice(idDraggedIndex, 1)[0])
|
|
106
|
-
} else {
|
|
107
|
-
quickCommands.splice(targetIndex + 1, 0, quickCommands.splice(idDraggedIndex, 1)[0])
|
|
108
|
-
}
|
|
109
|
-
store.setItems('quickCommands', quickCommands)
|
|
94
|
+
onDrop(e, '.qm-item')
|
|
110
95
|
}
|
|
111
96
|
|
|
112
97
|
renderNoCmd = () => {
|
|
@@ -8,6 +8,7 @@ import { Select } from 'antd'
|
|
|
8
8
|
import classnames from 'classnames'
|
|
9
9
|
import highlight from '../common/highlight'
|
|
10
10
|
import QmTransport from './quick-command-transport'
|
|
11
|
+
import onDrop from './on-drop'
|
|
11
12
|
|
|
12
13
|
const { Option } = Select
|
|
13
14
|
const e = window.translate
|
|
@@ -22,7 +23,7 @@ export default class QuickCommandsList extends List {
|
|
|
22
23
|
this.props.onClickItem(item)
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
handleChangeLabel = v => {
|
|
26
27
|
this.setState({
|
|
27
28
|
labels: v
|
|
28
29
|
})
|
|
@@ -42,23 +43,7 @@ export default class QuickCommandsList extends List {
|
|
|
42
43
|
|
|
43
44
|
// adjust window.store.quickCommands array order when drop, so that the dragged item will be placed at the right position, e.target.getAttribute('data-id') would target item id, e.dataTransfer.getData('idDragged') would target dragged item id
|
|
44
45
|
handleDrop = e => {
|
|
45
|
-
e
|
|
46
|
-
const { store } = window
|
|
47
|
-
const { quickCommands } = store
|
|
48
|
-
const idDragged = e.dataTransfer.getData('idDragged')
|
|
49
|
-
const idDrop = e.target.getAttribute('data-id')
|
|
50
|
-
const idDraggedIndex = quickCommands.findIndex(
|
|
51
|
-
({ id }) => id === idDragged
|
|
52
|
-
)
|
|
53
|
-
const targetIndex = quickCommands.findIndex(
|
|
54
|
-
({ id }) => id === idDrop
|
|
55
|
-
)
|
|
56
|
-
if (idDraggedIndex < targetIndex) {
|
|
57
|
-
quickCommands.splice(targetIndex, 0, quickCommands.splice(idDraggedIndex, 1)[0])
|
|
58
|
-
} else {
|
|
59
|
-
quickCommands.splice(targetIndex + 1, 0, quickCommands.splice(idDraggedIndex, 1)[0])
|
|
60
|
-
}
|
|
61
|
-
store.setItems('quickCommands', quickCommands)
|
|
46
|
+
onDrop(e)
|
|
62
47
|
}
|
|
63
48
|
|
|
64
49
|
renderItem = (item, i) => {
|
|
@@ -116,7 +101,7 @@ export default class QuickCommandsList extends List {
|
|
|
116
101
|
placeholder: e('labels'),
|
|
117
102
|
mode: 'multiple',
|
|
118
103
|
value: this.state.labels,
|
|
119
|
-
onChange: this.
|
|
104
|
+
onChange: this.handleChangeLabel,
|
|
120
105
|
style: {
|
|
121
106
|
width: '100%'
|
|
122
107
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
MinusCircleOutlined,
|
|
11
11
|
PlusOutlined
|
|
12
12
|
} from '@ant-design/icons'
|
|
13
|
+
import { useEffect } from 'react'
|
|
13
14
|
|
|
14
15
|
const FormItem = Form.Item
|
|
15
16
|
const FormList = Form.List
|
|
@@ -101,6 +102,10 @@ export default function KeywordForm (props) {
|
|
|
101
102
|
)
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
formChild.resetFields()
|
|
107
|
+
}, [props.keywordFormReset])
|
|
108
|
+
|
|
104
109
|
return (
|
|
105
110
|
<div>
|
|
106
111
|
<Form
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import BookmarkTransport from '../tree-list/bookmark-transport'
|
|
2
|
+
import download from '../../common/download'
|
|
3
|
+
import time from '../../common/time'
|
|
4
|
+
|
|
5
|
+
export default class KeywordsTransport extends BookmarkTransport {
|
|
6
|
+
name = 'keywords-highlight'
|
|
7
|
+
beforeUpload = async (file) => {
|
|
8
|
+
const { store } = this.props
|
|
9
|
+
const txt = await window.fs.readFile(file.path)
|
|
10
|
+
try {
|
|
11
|
+
store.setConfig({
|
|
12
|
+
keywords: JSON.parse(txt)
|
|
13
|
+
})
|
|
14
|
+
} catch (e) {
|
|
15
|
+
store.onError(e)
|
|
16
|
+
}
|
|
17
|
+
setTimeout(this.props.resetKeywordForm, 100)
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
renderEdit () {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
handleDownload = () => {
|
|
26
|
+
const { store } = this.props
|
|
27
|
+
const arr = store.config.keywords || []
|
|
28
|
+
const txt = JSON.stringify(arr, null, 2)
|
|
29
|
+
const stamp = time(undefined, 'YYYY-MM-DD-HH-mm-ss')
|
|
30
|
+
download('electerm-' + this.name + '-' + stamp + '.json', txt)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -28,6 +28,7 @@ import mapper from '../../common/auto-complete-data-mapper'
|
|
|
28
28
|
import KeywordForm from './keywords-form'
|
|
29
29
|
import Link from '../common/external-link'
|
|
30
30
|
import HelpIcon from '../common/help-icon'
|
|
31
|
+
import KeywordsTransport from './keywords-transport'
|
|
31
32
|
import './setting.styl'
|
|
32
33
|
|
|
33
34
|
const { Option } = Select
|
|
@@ -35,7 +36,8 @@ const e = window.translate
|
|
|
35
36
|
|
|
36
37
|
export default class SettingTerminal extends Component {
|
|
37
38
|
state = {
|
|
38
|
-
ready: false
|
|
39
|
+
ready: false,
|
|
40
|
+
keywordFormReset: 1
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
componentDidMount () {
|
|
@@ -50,6 +52,12 @@ export default class SettingTerminal extends Component {
|
|
|
50
52
|
clearTimeout(this.timer)
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
resetKeywordForm = () => {
|
|
56
|
+
this.setState({
|
|
57
|
+
keywordFormReset: Date.now()
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
handleResetAll = () => {
|
|
54
62
|
this.saveConfig(
|
|
55
63
|
deepCopy(defaultSettings)
|
|
@@ -411,6 +419,7 @@ export default class SettingTerminal extends Component {
|
|
|
411
419
|
formData: {
|
|
412
420
|
keywords
|
|
413
421
|
},
|
|
422
|
+
keywordFormReset: this.state.keywordFormReset,
|
|
414
423
|
submit: this.handleSubmitKeywords,
|
|
415
424
|
themeConfig: getThemeConfig()
|
|
416
425
|
}
|
|
@@ -469,6 +478,12 @@ export default class SettingTerminal extends Component {
|
|
|
469
478
|
<HelpIcon
|
|
470
479
|
title={tip}
|
|
471
480
|
/>
|
|
481
|
+
<span className='mg1l'>
|
|
482
|
+
<KeywordsTransport
|
|
483
|
+
store={this.props.store}
|
|
484
|
+
resetKeywordForm={this.resetKeywordForm}
|
|
485
|
+
/>
|
|
486
|
+
</span>
|
|
472
487
|
</div>
|
|
473
488
|
<KeywordForm
|
|
474
489
|
{...ps}
|
|
@@ -722,12 +722,12 @@ export default class FileSection extends React.Component {
|
|
|
722
722
|
path,
|
|
723
723
|
text,
|
|
724
724
|
mode
|
|
725
|
-
)
|
|
725
|
+
).catch(window.store.onError)
|
|
726
726
|
: await fs.writeFile(
|
|
727
727
|
path,
|
|
728
728
|
text,
|
|
729
729
|
mode
|
|
730
|
-
)
|
|
730
|
+
).catch(window.store.onError)
|
|
731
731
|
const data = {
|
|
732
732
|
loading: false
|
|
733
733
|
}
|
|
@@ -54,6 +54,7 @@ export default class AttachAddonCustom extends AttachAddon {
|
|
|
54
54
|
onRead = (ev) => {
|
|
55
55
|
const data = ev.target.result
|
|
56
56
|
const { term } = this
|
|
57
|
+
term?.parent?.notifyOnData()
|
|
57
58
|
const str = this.decoder.decode(data)
|
|
58
59
|
if (term?.parent?.props.sftpPathFollowSsh && term?.buffer.active.type !== 'alternate') {
|
|
59
60
|
const {
|
|
@@ -4,7 +4,7 @@ import generate from '../../common/uid'
|
|
|
4
4
|
import { isEqual, pick, debounce, throttle } from 'lodash-es'
|
|
5
5
|
import postMessage from '../../common/post-msg'
|
|
6
6
|
import clone from '../../common/to-simple-obj'
|
|
7
|
-
import runIdle from '../../common/run-idle'
|
|
7
|
+
// import runIdle from '../../common/run-idle'
|
|
8
8
|
import {
|
|
9
9
|
ReloadOutlined
|
|
10
10
|
} from '@ant-design/icons'
|
|
@@ -783,7 +783,7 @@ class Term extends Component {
|
|
|
783
783
|
onClear = () => {
|
|
784
784
|
this.term.clear()
|
|
785
785
|
this.term.focus()
|
|
786
|
-
this.notifyOnData('')
|
|
786
|
+
// this.notifyOnData('')
|
|
787
787
|
}
|
|
788
788
|
|
|
789
789
|
isRemote = () => {
|
|
@@ -921,7 +921,7 @@ class Term extends Component {
|
|
|
921
921
|
}
|
|
922
922
|
|
|
923
923
|
onData = (d) => {
|
|
924
|
-
runIdle(this.notifyOnData)
|
|
924
|
+
// runIdle(this.notifyOnData)
|
|
925
925
|
if (!d.includes('\r')) {
|
|
926
926
|
delete this.userTypeExit
|
|
927
927
|
} else {
|
package/client/store/sync.js
CHANGED
|
@@ -190,7 +190,10 @@ export default (Store) => {
|
|
|
190
190
|
})
|
|
191
191
|
}
|
|
192
192
|
str = JSON.stringify(str)
|
|
193
|
-
if (
|
|
193
|
+
if (
|
|
194
|
+
(n === settingMap.bookmarks || n === settingMap.profiles) &&
|
|
195
|
+
pass
|
|
196
|
+
) {
|
|
194
197
|
str = await window.pre.runGlobalAsync('encryptAsync', str, pass)
|
|
195
198
|
}
|
|
196
199
|
objs[`${n}.json`] = {
|