@electerm/electerm-react 3.7.18 → 3.8.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/components/file-transfer/transfer.jsx +17 -6
- package/client/components/sftp/file-item.jsx +7 -7
- package/client/components/tree-list/tree-expander.jsx +9 -20
- package/client/components/tree-list/tree-item-op.jsx +156 -0
- package/client/components/tree-list/tree-list-editor-overlay.jsx +47 -0
- package/client/components/tree-list/tree-list-item.jsx +6 -170
- package/client/components/tree-list/tree-list-layout.js +3 -0
- package/client/components/tree-list/tree-list-row.jsx +111 -0
- package/client/components/tree-list/tree-list-rows.js +107 -0
- package/client/components/tree-list/tree-list.jsx +226 -314
- package/client/components/tree-list/tree-list.styl +49 -6
- package/client/components/tree-list/virtual-tree-list.jsx +112 -0
- package/package.json +1 -1
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import React from 'react'
|
|
6
6
|
import { Component } from 'manate/react/class-components'
|
|
7
|
-
import {
|
|
8
|
-
CheckOutlined,
|
|
9
|
-
CloseOutlined,
|
|
10
|
-
LoadingOutlined
|
|
11
|
-
} from '@ant-design/icons'
|
|
12
|
-
import createName from '../../common/create-title'
|
|
13
|
-
import InputAutoFocus from '../common/input-auto-focus'
|
|
7
|
+
import { LoadingOutlined } from '@ant-design/icons'
|
|
14
8
|
import { uniq, filter, pick } from 'lodash-es'
|
|
15
9
|
import {
|
|
16
10
|
maxBookmarkGroupTitleLength,
|
|
@@ -25,11 +19,17 @@ import getInitItem from '../../common/init-setting-item'
|
|
|
25
19
|
import uid from '../../common/uid'
|
|
26
20
|
import { action } from 'manate'
|
|
27
21
|
import './tree-list.styl'
|
|
28
|
-
import
|
|
29
|
-
import
|
|
22
|
+
import TreeListRow from './tree-list-row'
|
|
23
|
+
import TreeListEditorOverlay from './tree-list-editor-overlay.jsx'
|
|
30
24
|
import TreeSearch from './tree-search'
|
|
31
|
-
import
|
|
25
|
+
import VirtualTreeList from './virtual-tree-list'
|
|
26
|
+
import { buildVisibleTreeRows } from './tree-list-rows'
|
|
32
27
|
import { getRandomDefaultColor } from '../../common/rand-hex-color.js'
|
|
28
|
+
import {
|
|
29
|
+
treeEditorRowHeight,
|
|
30
|
+
treeLevelIndent,
|
|
31
|
+
treeRowHeight
|
|
32
|
+
} from './tree-list-layout'
|
|
33
33
|
|
|
34
34
|
export default class ItemListTree extends Component {
|
|
35
35
|
constructor (props) {
|
|
@@ -43,9 +43,10 @@ export default class ItemListTree extends Component {
|
|
|
43
43
|
bookmarkGroupColor: '',
|
|
44
44
|
categoryTitle: '',
|
|
45
45
|
categoryColor: '',
|
|
46
|
-
categoryId: ''
|
|
46
|
+
categoryId: '',
|
|
47
|
+
searchSelectedRowKey: ''
|
|
47
48
|
}
|
|
48
|
-
this.
|
|
49
|
+
this.listRef = React.createRef()
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
onSubmit = false
|
|
@@ -64,6 +65,13 @@ export default class ItemListTree extends Component {
|
|
|
64
65
|
clearTimeout(this.timer)
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
scrollTreeToTop = () => {
|
|
69
|
+
const listWrap = this.listRef.current
|
|
70
|
+
if (listWrap) {
|
|
71
|
+
listWrap.scrollTop = 0
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
onCancelMoveItem = () => {
|
|
68
76
|
this.setState({
|
|
69
77
|
openMoveModal: false,
|
|
@@ -72,15 +80,6 @@ export default class ItemListTree extends Component {
|
|
|
72
80
|
})
|
|
73
81
|
}
|
|
74
82
|
|
|
75
|
-
filter = (list) => {
|
|
76
|
-
const { keyword } = this.state
|
|
77
|
-
return keyword
|
|
78
|
-
? list.filter(item => {
|
|
79
|
-
return createName(item).toLowerCase().includes(keyword.toLowerCase())
|
|
80
|
-
})
|
|
81
|
-
: list
|
|
82
|
-
}
|
|
83
|
-
|
|
84
83
|
onExpandKey = group => {
|
|
85
84
|
const {
|
|
86
85
|
expandedKeys
|
|
@@ -104,57 +103,88 @@ export default class ItemListTree extends Component {
|
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
handleChange = keyword => {
|
|
107
|
-
this.setState({
|
|
106
|
+
this.setState({
|
|
107
|
+
keyword,
|
|
108
|
+
searchSelectedRowKey: ''
|
|
109
|
+
})
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
handleKeyDown = (e) => {
|
|
111
113
|
const { keyword } = this.state
|
|
112
114
|
if (!keyword) return
|
|
115
|
+
this.handleVirtualTreeKeyDown(e)
|
|
116
|
+
}
|
|
113
117
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const matchedItems = Array.from(allItems).filter(item => {
|
|
119
|
-
const isGroup = item.getAttribute('data-is-group') === 'true'
|
|
120
|
-
if (isGroup) return false
|
|
121
|
-
const title = item.querySelector('.tree-item-title')
|
|
122
|
-
if (!title) return false
|
|
123
|
-
const text = title.textContent || ''
|
|
124
|
-
return text.toLowerCase().includes(keyword.toLowerCase())
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
if (matchedItems.length === 0) return
|
|
128
|
-
|
|
129
|
-
const currentSelected = treeContainer.querySelector('.tree-item.search-selected')
|
|
130
|
-
let currentIndex = -1
|
|
131
|
-
if (currentSelected) {
|
|
132
|
-
currentSelected.classList.remove('search-selected')
|
|
133
|
-
currentIndex = matchedItems.indexOf(currentSelected)
|
|
118
|
+
handleVirtualTreeKeyDown = (e) => {
|
|
119
|
+
const { matchedRowKeys, rows } = this.getVisibleTreeData()
|
|
120
|
+
if (!matchedRowKeys.length) {
|
|
121
|
+
return
|
|
134
122
|
}
|
|
135
123
|
|
|
124
|
+
const { searchSelectedRowKey } = this.state
|
|
125
|
+
const currentIndex = matchedRowKeys.indexOf(searchSelectedRowKey)
|
|
126
|
+
|
|
136
127
|
if (e.key === 'ArrowDown') {
|
|
137
128
|
e.preventDefault()
|
|
138
|
-
const nextIndex = (currentIndex + 1) %
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
129
|
+
const nextIndex = (currentIndex + 1) % matchedRowKeys.length
|
|
130
|
+
const rowKey = matchedRowKeys[nextIndex]
|
|
131
|
+
this.setState({ searchSelectedRowKey: rowKey })
|
|
132
|
+
this.scrollRowIntoView(rows, rowKey)
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (e.key === 'ArrowUp') {
|
|
142
137
|
e.preventDefault()
|
|
143
|
-
const nextIndex = currentIndex <= 0 ?
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
138
|
+
const nextIndex = currentIndex <= 0 ? matchedRowKeys.length - 1 : currentIndex - 1
|
|
139
|
+
const rowKey = matchedRowKeys[nextIndex]
|
|
140
|
+
this.setState({ searchSelectedRowKey: rowKey })
|
|
141
|
+
this.scrollRowIntoView(rows, rowKey)
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (e.key === 'Enter') {
|
|
147
146
|
e.preventDefault()
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
const rowKey = currentIndex >= 0
|
|
148
|
+
? matchedRowKeys[currentIndex]
|
|
149
|
+
: matchedRowKeys[0]
|
|
150
|
+
const row = rows.find(item => item.key === rowKey)
|
|
151
|
+
if (row?.item?.id) {
|
|
152
|
+
this.selectBookmarkById(row.item.id)
|
|
154
153
|
}
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
156
|
|
|
157
|
+
scrollRowIntoView = (rows, rowKey) => {
|
|
158
|
+
const listWrap = this.listRef.current
|
|
159
|
+
if (!listWrap) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
const rowIndex = rows.findIndex(row => row.key === rowKey)
|
|
163
|
+
if (rowIndex < 0) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
const rowTop = rowIndex * treeRowHeight
|
|
167
|
+
const rowBottom = rowTop + treeRowHeight
|
|
168
|
+
const viewportTop = listWrap.scrollTop
|
|
169
|
+
const viewportBottom = viewportTop + listWrap.clientHeight
|
|
170
|
+
|
|
171
|
+
if (rowTop < viewportTop) {
|
|
172
|
+
listWrap.scrollTop = rowTop
|
|
173
|
+
} else if (rowBottom > viewportBottom) {
|
|
174
|
+
listWrap.scrollTop = rowBottom - listWrap.clientHeight
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
getVisibleTreeData = () => {
|
|
179
|
+
return buildVisibleTreeRows({
|
|
180
|
+
bookmarkGroups: this.props.bookmarkGroups,
|
|
181
|
+
bookmarkGroupTree: this.props.bookmarkGroupTree,
|
|
182
|
+
bookmarksMap: this.props.bookmarksMap,
|
|
183
|
+
expandedKeys: this.props.expandedKeys,
|
|
184
|
+
keyword: this.state.keyword
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
|
|
158
188
|
handleCancelNew = () => {
|
|
159
189
|
this.setState({
|
|
160
190
|
showNewBookmarkGroupForm: false,
|
|
@@ -319,7 +349,7 @@ export default class ItemListTree extends Component {
|
|
|
319
349
|
bookmarkGroupTitle: '',
|
|
320
350
|
bookmarkGroupColor: getRandomDefaultColor(),
|
|
321
351
|
parentId: ''
|
|
322
|
-
})
|
|
352
|
+
}, this.scrollTreeToTop)
|
|
323
353
|
}
|
|
324
354
|
|
|
325
355
|
del = (item, e) => {
|
|
@@ -358,16 +388,21 @@ export default class ItemListTree extends Component {
|
|
|
358
388
|
: this.onExpandKey
|
|
359
389
|
func({ id })
|
|
360
390
|
} else {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
391
|
+
this.selectBookmarkById(id)
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
selectBookmarkById = (id) => {
|
|
396
|
+
const { store } = window
|
|
397
|
+
store.storeAssign({
|
|
398
|
+
currentBookmarkGroupId: findBookmarkGroupId(store.bookmarkGroups, id)
|
|
399
|
+
})
|
|
400
|
+
const { bookmarks } = this.props
|
|
401
|
+
const bookmark = bookmarks.find(
|
|
402
|
+
d => d.id === id
|
|
403
|
+
)
|
|
404
|
+
if (bookmark) {
|
|
405
|
+
this.props.onClickItem(bookmark)
|
|
371
406
|
}
|
|
372
407
|
}
|
|
373
408
|
|
|
@@ -610,34 +645,6 @@ export default class ItemListTree extends Component {
|
|
|
610
645
|
}
|
|
611
646
|
})
|
|
612
647
|
|
|
613
|
-
editCategory = () => {
|
|
614
|
-
const {
|
|
615
|
-
categoryTitle,
|
|
616
|
-
categoryColor
|
|
617
|
-
} = this.state
|
|
618
|
-
const confirm = (
|
|
619
|
-
<span>
|
|
620
|
-
<CheckOutlined className='pointer' onClick={this.handleSubmitEdit} />
|
|
621
|
-
<CloseOutlined className='mg1l pointer' onClick={this.handleCancelEdit} />
|
|
622
|
-
</span>
|
|
623
|
-
)
|
|
624
|
-
const colorPicker = (
|
|
625
|
-
<CategoryColorPicker
|
|
626
|
-
value={categoryColor || getRandomDefaultColor()}
|
|
627
|
-
onChange={this.handleChangeCategoryColor}
|
|
628
|
-
/>
|
|
629
|
-
)
|
|
630
|
-
return (
|
|
631
|
-
<InputAutoFocus
|
|
632
|
-
value={categoryTitle}
|
|
633
|
-
onChange={this.handleChangeEdit}
|
|
634
|
-
onPressEnter={this.handleSubmitEdit}
|
|
635
|
-
prefix={colorPicker}
|
|
636
|
-
suffix={confirm}
|
|
637
|
-
/>
|
|
638
|
-
)
|
|
639
|
-
}
|
|
640
|
-
|
|
641
648
|
duplicateItem = (e, item) => {
|
|
642
649
|
e.stopPropagation()
|
|
643
650
|
const { addItem } = window.store
|
|
@@ -701,222 +708,148 @@ export default class ItemListTree extends Component {
|
|
|
701
708
|
})
|
|
702
709
|
}
|
|
703
710
|
|
|
704
|
-
|
|
705
|
-
if (isGroup && item.id === this.state.categoryId) {
|
|
706
|
-
return this.editCategory(item)
|
|
707
|
-
}
|
|
708
|
-
const itemProps = {
|
|
709
|
-
item,
|
|
710
|
-
isGroup,
|
|
711
|
-
parentId,
|
|
712
|
-
leftSidebarWidth: this.props.leftSidebarWidth,
|
|
713
|
-
staticList: this.props.staticList,
|
|
714
|
-
selectedItemId: this.props.activeItemId,
|
|
715
|
-
...pick(
|
|
716
|
-
this,
|
|
717
|
-
[
|
|
718
|
-
'del',
|
|
719
|
-
'openAll',
|
|
720
|
-
'openMoveModal',
|
|
721
|
-
'editItem',
|
|
722
|
-
'addSubCat',
|
|
723
|
-
'onSelect',
|
|
724
|
-
'duplicateItem',
|
|
725
|
-
'onDragStart',
|
|
726
|
-
'onDrop',
|
|
727
|
-
'onDragEnter',
|
|
728
|
-
'onDragLeave',
|
|
729
|
-
'onDragOver'
|
|
730
|
-
]
|
|
731
|
-
),
|
|
732
|
-
...pick(
|
|
733
|
-
this.state,
|
|
734
|
-
[
|
|
735
|
-
'keyword'
|
|
736
|
-
]
|
|
737
|
-
)
|
|
738
|
-
}
|
|
739
|
-
return (
|
|
740
|
-
<TreeListItem
|
|
741
|
-
{...itemProps}
|
|
742
|
-
/>
|
|
743
|
-
)
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
handleExport = () => {
|
|
747
|
-
document.querySelector('.download-bookmark-icon')?.click()
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
handleSshConfigs = () => {
|
|
751
|
-
window.store.showSshConfigModal = true
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
renderNewButtons = () => {
|
|
711
|
+
renderVirtualRow = (row, editor) => {
|
|
755
712
|
return (
|
|
756
|
-
<
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
713
|
+
<TreeListRow
|
|
714
|
+
row={row}
|
|
715
|
+
keyword={this.state.keyword}
|
|
716
|
+
expandedKeys={this.props.expandedKeys}
|
|
717
|
+
activeItemId={this.props.activeItemId}
|
|
718
|
+
searchSelectedRowKey={this.state.searchSelectedRowKey}
|
|
719
|
+
staticList={this.props.staticList}
|
|
720
|
+
leftSidebarWidth={this.props.leftSidebarWidth}
|
|
721
|
+
{...pick(
|
|
722
|
+
this,
|
|
723
|
+
[
|
|
724
|
+
'del',
|
|
725
|
+
'openAll',
|
|
726
|
+
'openMoveModal',
|
|
727
|
+
'editItem',
|
|
728
|
+
'addSubCat',
|
|
729
|
+
'onSelect',
|
|
730
|
+
'duplicateItem',
|
|
731
|
+
'onDragStart',
|
|
732
|
+
'onDrop',
|
|
733
|
+
'onDragEnter',
|
|
734
|
+
'onDragLeave',
|
|
735
|
+
'onDragOver'
|
|
736
|
+
]
|
|
737
|
+
)}
|
|
738
|
+
handleExpand={this.onExpandKey}
|
|
739
|
+
handleUnExpand={this.onUnExpandKey}
|
|
740
|
+
isHidden={editor?.hideRowKey === row.key}
|
|
763
741
|
/>
|
|
764
742
|
)
|
|
765
743
|
}
|
|
766
744
|
|
|
767
|
-
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
745
|
+
getEditorOverlayState = (rows) => {
|
|
746
|
+
const {
|
|
747
|
+
categoryColor,
|
|
748
|
+
categoryId,
|
|
749
|
+
categoryTitle,
|
|
750
|
+
bookmarkGroupColor,
|
|
751
|
+
bookmarkGroupTitle,
|
|
752
|
+
parentId,
|
|
753
|
+
showNewBookmarkGroupForm
|
|
754
|
+
} = this.state
|
|
771
755
|
|
|
772
|
-
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
756
|
+
if (categoryId) {
|
|
757
|
+
const rowIndex = rows.findIndex(row => row.isGroup && row.item.id === categoryId)
|
|
758
|
+
if (rowIndex < 0) {
|
|
759
|
+
return null
|
|
760
|
+
}
|
|
761
|
+
const row = rows[rowIndex]
|
|
762
|
+
return {
|
|
763
|
+
top: rowIndex * treeRowHeight,
|
|
764
|
+
left: Math.max(0, (row.depth - 1) * treeLevelIndent),
|
|
765
|
+
title: categoryTitle,
|
|
766
|
+
color: categoryColor,
|
|
767
|
+
handleTitleChange: this.handleChangeEdit,
|
|
768
|
+
handleColorChange: this.handleChangeCategoryColor,
|
|
769
|
+
handleSubmit: this.handleSubmitEdit,
|
|
770
|
+
handleCancel: this.handleCancelEdit,
|
|
771
|
+
selectall: true,
|
|
772
|
+
hideRowKey: row.key
|
|
773
|
+
}
|
|
779
774
|
}
|
|
780
775
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
const bgSubIds = bg.bookmarkGroupIds || []
|
|
784
|
-
if (hasMatchedItems(bgIds)) return true
|
|
785
|
-
return bgSubIds.some(sgid => {
|
|
786
|
-
const subBg = window.store.bookmarkGroupTree[sgid]
|
|
787
|
-
return subBg && hasMatchedSubGroup(subBg)
|
|
788
|
-
})
|
|
776
|
+
if (!showNewBookmarkGroupForm) {
|
|
777
|
+
return null
|
|
789
778
|
}
|
|
790
779
|
|
|
791
|
-
if (
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
780
|
+
if (!parentId) {
|
|
781
|
+
return {
|
|
782
|
+
top: 0,
|
|
783
|
+
left: 0,
|
|
784
|
+
title: bookmarkGroupTitle,
|
|
785
|
+
color: bookmarkGroupColor,
|
|
786
|
+
handleTitleChange: this.handleChangeBookmarkGroupTitle,
|
|
787
|
+
handleColorChange: this.handleChangeBookmarkGroupColor,
|
|
788
|
+
handleSubmit: this.handleSubmit,
|
|
789
|
+
handleCancel: this.handleCancelNew,
|
|
790
|
+
insertionGap: {
|
|
791
|
+
index: 0,
|
|
792
|
+
height: treeEditorRowHeight
|
|
793
|
+
}
|
|
797
794
|
}
|
|
798
795
|
}
|
|
799
|
-
return (
|
|
800
|
-
<div key={group.id} className='group-container'>
|
|
801
|
-
{
|
|
802
|
-
this.renderExpander(group, pid)
|
|
803
|
-
}
|
|
804
|
-
{
|
|
805
|
-
this.renderGroupTitle(group, pids)
|
|
806
|
-
}
|
|
807
|
-
<div className='group-container-sub'>
|
|
808
|
-
{
|
|
809
|
-
this.renderNewCat(group, pid)
|
|
810
|
-
}
|
|
811
|
-
{
|
|
812
|
-
this.renderGroupChildren(group, pid)
|
|
813
|
-
}
|
|
814
|
-
</div>
|
|
815
|
-
</div>
|
|
816
|
-
)
|
|
817
|
-
}
|
|
818
796
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
bookmarkGroupTitle,
|
|
822
|
-
bookmarkGroupColor,
|
|
823
|
-
parentId,
|
|
824
|
-
showNewBookmarkGroupForm
|
|
825
|
-
} = this.state
|
|
826
|
-
if (!showNewBookmarkGroupForm || group.id !== parentId) {
|
|
797
|
+
const parentIndex = rows.findIndex(row => row.isGroup && row.item.id === parentId)
|
|
798
|
+
if (parentIndex < 0) {
|
|
827
799
|
return null
|
|
828
800
|
}
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
value={bookmarkGroupTitle}
|
|
845
|
-
onPressEnter={this.handleSubmit}
|
|
846
|
-
onChange={this.handleChangeBookmarkGroupTitle}
|
|
847
|
-
prefix={colorPicker}
|
|
848
|
-
suffix={confirm}
|
|
849
|
-
onBlur={this.handleBlurBookmarkGroupTitle}
|
|
850
|
-
/>
|
|
851
|
-
</div>
|
|
852
|
-
)
|
|
801
|
+
const parentRow = rows[parentIndex]
|
|
802
|
+
return {
|
|
803
|
+
top: (parentIndex + 1) * treeRowHeight,
|
|
804
|
+
left: parentRow.depth * treeLevelIndent,
|
|
805
|
+
title: bookmarkGroupTitle,
|
|
806
|
+
color: bookmarkGroupColor,
|
|
807
|
+
handleTitleChange: this.handleChangeBookmarkGroupTitle,
|
|
808
|
+
handleColorChange: this.handleChangeBookmarkGroupColor,
|
|
809
|
+
handleSubmit: this.handleSubmit,
|
|
810
|
+
handleCancel: this.handleCancelNew,
|
|
811
|
+
insertionGap: {
|
|
812
|
+
index: parentIndex + 1,
|
|
813
|
+
height: treeEditorRowHeight
|
|
814
|
+
}
|
|
815
|
+
}
|
|
853
816
|
}
|
|
854
817
|
|
|
855
|
-
|
|
856
|
-
const expProps = {
|
|
857
|
-
level,
|
|
858
|
-
group,
|
|
859
|
-
keyword: this.state.keyword,
|
|
860
|
-
expandedKeys: this.props.expandedKeys,
|
|
861
|
-
onExpand: this.onExpandKey,
|
|
862
|
-
onUnExpand: this.onUnExpandKey
|
|
863
|
-
}
|
|
818
|
+
renderVirtualTreeContent = (rows, editor) => {
|
|
864
819
|
return (
|
|
865
|
-
<
|
|
866
|
-
{
|
|
820
|
+
<VirtualTreeList
|
|
821
|
+
items={rows}
|
|
822
|
+
rowHeight={treeRowHeight}
|
|
823
|
+
containerRef={this.listRef}
|
|
824
|
+
insertionGap={editor?.insertionGap}
|
|
825
|
+
renderItem={row => this.renderVirtualRow(row, editor)}
|
|
867
826
|
/>
|
|
868
827
|
)
|
|
869
828
|
}
|
|
870
829
|
|
|
871
|
-
|
|
872
|
-
return
|
|
830
|
+
renderEditorOverlay = (editor) => {
|
|
831
|
+
return <TreeListEditorOverlay editor={editor} />
|
|
873
832
|
}
|
|
874
833
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
bookmarkIds = [],
|
|
878
|
-
bookmarkGroupIds = [],
|
|
879
|
-
id
|
|
880
|
-
} = group
|
|
881
|
-
const shouldRender = this.state.keyword || this.props.expandedKeys.includes(id)
|
|
882
|
-
if (!shouldRender) {
|
|
883
|
-
return null
|
|
884
|
-
}
|
|
885
|
-
const subGroups = this.renderSubGroup(bookmarkGroupIds, parentId)
|
|
886
|
-
const childs = this.renderChilds(bookmarkIds, parentId)
|
|
887
|
-
if (this.state.keyword && subGroups.length === 0 && childs.length === 0) {
|
|
888
|
-
return null
|
|
889
|
-
}
|
|
890
|
-
return [
|
|
891
|
-
...subGroups,
|
|
892
|
-
...childs
|
|
893
|
-
]
|
|
834
|
+
handleExport = () => {
|
|
835
|
+
document.querySelector('.download-bookmark-icon')?.click()
|
|
894
836
|
}
|
|
895
837
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
return window.store.bookmarkGroupTree[id]
|
|
899
|
-
}).filter(d => d)
|
|
900
|
-
return bookmarkGroups.map((node, i) => {
|
|
901
|
-
return this.renderGroup(node, i, parentId)
|
|
902
|
-
})
|
|
838
|
+
handleSshConfigs = () => {
|
|
839
|
+
window.store.showSshConfigModal = true
|
|
903
840
|
}
|
|
904
841
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
}).filter(d => d)
|
|
917
|
-
return bookmarks.map((node) => {
|
|
918
|
-
return this.renderItemTitle(node, false, pid)
|
|
919
|
-
})
|
|
842
|
+
renderNewButtons = () => {
|
|
843
|
+
return (
|
|
844
|
+
<NewButtonsGroup
|
|
845
|
+
onNewBookmark={this.handleNewBookmark}
|
|
846
|
+
onNewBookmarkGroup={this.handleNewBookmarkGroup}
|
|
847
|
+
onExport={this.handleExport}
|
|
848
|
+
onSshConfigs={this.handleSshConfigs}
|
|
849
|
+
bookmarkGroups={this.props.bookmarkGroups}
|
|
850
|
+
bookmarks={this.props.bookmarks}
|
|
851
|
+
/>
|
|
852
|
+
)
|
|
920
853
|
}
|
|
921
854
|
|
|
922
855
|
render () {
|
|
@@ -929,39 +862,14 @@ export default class ItemListTree extends Component {
|
|
|
929
862
|
)
|
|
930
863
|
}
|
|
931
864
|
const {
|
|
932
|
-
bookmarkGroups,
|
|
933
865
|
type,
|
|
934
866
|
staticList,
|
|
935
867
|
listStyle = {}
|
|
936
868
|
} = this.props
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
if (!d.level || d.level < 2) {
|
|
940
|
-
if (this.state.keyword) {
|
|
941
|
-
const hasMatchedItemsRecursive = (bg) => {
|
|
942
|
-
const ids = bg.bookmarkIds || []
|
|
943
|
-
const subIds = bg.bookmarkGroupIds || []
|
|
944
|
-
const tree = this.props.bookmarksMap
|
|
945
|
-
const { keyword } = this.state
|
|
946
|
-
const hasMatch = ids.some(id => {
|
|
947
|
-
const item = tree.get(id)
|
|
948
|
-
return item && createName(item).toLowerCase().includes(keyword.toLowerCase())
|
|
949
|
-
})
|
|
950
|
-
if (hasMatch) return true
|
|
951
|
-
return subIds.some(sgid => {
|
|
952
|
-
const subBg = window.store.bookmarkGroupTree[sgid]
|
|
953
|
-
return subBg && hasMatchedItemsRecursive(subBg)
|
|
954
|
-
})
|
|
955
|
-
}
|
|
956
|
-
return hasMatchedItemsRecursive(d)
|
|
957
|
-
}
|
|
958
|
-
return true
|
|
959
|
-
}
|
|
960
|
-
return false
|
|
961
|
-
})
|
|
962
|
-
: []
|
|
869
|
+
const { rows } = this.getVisibleTreeData()
|
|
870
|
+
const editor = this.getEditorOverlayState(rows)
|
|
963
871
|
return (
|
|
964
|
-
<div className={`tree-list item-type-${type}`}
|
|
872
|
+
<div className={`tree-list item-type-${type}`}>
|
|
965
873
|
<div className='tree-list-header'>
|
|
966
874
|
{
|
|
967
875
|
staticList
|
|
@@ -972,9 +880,13 @@ export default class ItemListTree extends Component {
|
|
|
972
880
|
this.renderSearch()
|
|
973
881
|
}
|
|
974
882
|
</div>
|
|
975
|
-
<div
|
|
976
|
-
|
|
977
|
-
{
|
|
883
|
+
<div
|
|
884
|
+
className='item-list-wrap'
|
|
885
|
+
style={listStyle}
|
|
886
|
+
ref={this.listRef}
|
|
887
|
+
>
|
|
888
|
+
{this.renderVirtualTreeContent(rows, editor)}
|
|
889
|
+
{this.renderEditorOverlay(editor)}
|
|
978
890
|
</div>
|
|
979
891
|
</div>
|
|
980
892
|
)
|