Skip to content

Commit e94f1d1

Browse files
authored
Merge pull request #1467 from RedisInsight/feature/RI-3355_Tree_view_improvments
Feature/ri 3355 tree view improvments
2 parents a8fe335 + 7041463 commit e94f1d1

File tree

15 files changed

+787
-32
lines changed

15 files changed

+787
-32
lines changed

redisinsight/ui/src/components/virtual-tree/VirtualTree.tsx

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import {
77
FixedSizeTree as Tree,
88
} from 'react-vtree'
99
import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui'
10+
import { useDispatch } from 'react-redux'
1011

11-
import { getTreeLeafField, Maybe } from 'uiSrc/utils'
12+
import { findTreeNode, getTreeLeafField, Maybe } from 'uiSrc/utils'
1213
import { useDisposableWebworker } from 'uiSrc/services'
1314
import { IKeyPropTypes } from 'uiSrc/constants/prop-types/keys'
1415
import { ThemeContext } from 'uiSrc/contexts/themeContext'
1516
import { DEFAULT_DELIMITER, Theme } from 'uiSrc/constants'
1617
import KeyLightSVG from 'uiSrc/assets/img/sidebar/browser.svg'
1718
import KeyDarkSVG from 'uiSrc/assets/img/sidebar/browser_active.svg'
19+
import { resetBrowserTree } from 'uiSrc/slices/app/context'
1820

1921
import { Node } from './components/Node'
2022
import { NodeMeta, TreeData, TreeNode } from './interfaces'
@@ -43,6 +45,8 @@ export interface Props {
4345
setConstructingTree: (status: boolean) => void
4446
}
4547

48+
export const KEYS = 'keys'
49+
4650
const VirtualTree = (props: Props) => {
4751
const {
4852
items,
@@ -64,6 +68,8 @@ const VirtualTree = (props: Props) => {
6468
const [nodes, setNodes] = useState<TreeNode[]>([])
6569
const { result, run: runWebworker } = useDisposableWebworker(webworkerFn)
6670

71+
const dispatch = useDispatch()
72+
6773
useEffect(() =>
6874
() => setNodes([]),
6975
[])
@@ -85,13 +91,40 @@ const VirtualTree = (props: Props) => {
8591
}
8692

8793
if (isArray(nodes) && isEmpty(statusSelected)) {
88-
const rootLeaf: Maybe<TreeNode> = nodes?.find(({ children = [] }) => children.length === 0)
94+
let selectedLeaf: Maybe<TreeNode> = nodes?.find(({ children = [] }) => children.length === 0)
95+
96+
// if Keys folder not exists - first folder should be opened
97+
if (!selectedLeaf && nodes.length) {
98+
selectedLeaf = nodes?.[0]
99+
100+
onStatusOpen?.(selectedLeaf?.fullName ?? '', true)
101+
onStatusSelected?.(
102+
`${selectedLeaf?.fullName + KEYS + delimiter + KEYS + delimiter}` ?? '',
103+
selectedLeaf?.keys ?? selectedLeaf?.children?.[0]?.keys
104+
)
105+
} else {
106+
// if Keys folder exist - open it
107+
onStatusSelected?.(selectedLeaf?.fullName ?? '', selectedLeaf?.keys)
108+
}
109+
89110
disableSelectDefaultLeaf?.()
90-
onStatusSelected?.(rootLeaf?.fullName ?? '', rootLeaf?.keys)
91-
onSelectLeaf?.(rootLeaf?.keys ?? [])
111+
onSelectLeaf?.(selectedLeaf?.keys ?? selectedLeaf?.children?.[0]?.keys ?? [])
92112
}
93113
}, [nodes, loading, selectDefaultLeaf])
94114

115+
useEffect(() => {
116+
if (isEmpty(statusSelected) || !nodes.length) {
117+
return
118+
}
119+
120+
// if selected Keys folder is not exists (after a new search) needs reset Browser state
121+
const selectedLeafExists = !!findTreeNode(nodes, Object.keys(statusSelected)?.[0], 'fullName')
122+
123+
if (!selectedLeafExists) {
124+
dispatch(resetBrowserTree())
125+
}
126+
}, [nodes])
127+
95128
useEffect(() => {
96129
if (!items?.length) {
97130
setNodes([])

redisinsight/ui/src/pages/browser/components/filter-key-type/FilterKeyType.spec.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
import { loadKeys, setFilter } from 'uiSrc/slices/browser/keys'
1212
import { connectedInstanceOverviewSelector } from 'uiSrc/slices/instances/instances'
1313
import { KeyTypes } from 'uiSrc/constants'
14-
import { resetBrowserTree } from 'uiSrc/slices/app/context'
1514
import FilterKeyType from './FilterKeyType'
1615

1716
let store: typeof mockedStore
@@ -64,7 +63,6 @@ describe('FilterKeyType', () => {
6463
const expectedActions = [
6564
setFilter(KeyTypes.Hash),
6665
loadKeys(),
67-
resetBrowserTree()
6866
]
6967
expect(clearStoreActions(store.getActions())).toEqual(
7068
clearStoreActions(expectedActions)

redisinsight/ui/src/pages/browser/components/filter-key-type/FilterKeyType.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { connectedInstanceOverviewSelector } from 'uiSrc/slices/instances/instan
1515
import { fetchKeys, keysSelector, setFilter } from 'uiSrc/slices/browser/keys'
1616
import { isVersionHigherOrEquals } from 'uiSrc/utils'
1717
import HelpTexts from 'uiSrc/constants/help-texts'
18-
import { resetBrowserTree } from 'uiSrc/slices/app/context'
1918
import { KeyViewType } from 'uiSrc/slices/interfaces/keys'
2019
import { FILTER_KEY_TYPE_OPTIONS } from './constants'
2120

@@ -82,9 +81,6 @@ const FilterKeyType = () => {
8281
'0',
8382
viewType === KeyViewType.Browser ? SCAN_COUNT_DEFAULT : SCAN_TREE_COUNT_DEFAULT,
8483
))
85-
86-
// reset browser tree context
87-
dispatch(resetBrowserTree())
8884
}
8985

9086
const UnsupportedInfo = () => (

redisinsight/ui/src/pages/browser/components/key-tree/KeyTree.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useStat
22
import cx from 'classnames'
33
import { EuiResizableContainer } from '@elastic/eui'
44
import { useDispatch, useSelector } from 'react-redux'
5+
import { isEmpty } from 'lodash'
56

67
import {
78
appContextBrowserTree,
9+
resetBrowserTree,
810
appContextDbConfig,
911
setBrowserTreeNodesOpen,
1012
setBrowserTreeSelectedLeaf
@@ -34,6 +36,10 @@ export interface Props {
3436
export const firstPanelId = 'tree'
3537
export const secondPanelId = 'keys'
3638

39+
const parseKeyNames = (keys: GetKeyInfoResponse[]) =>
40+
keys.map((item) =>
41+
({ ...item, nameString: item.nameString ?? bufferToString(item.name) }))
42+
3743
const KeyTree = forwardRef((props: Props, ref) => {
3844
const { selectKey, loadMoreItems, loading, keysState } = props
3945

@@ -50,8 +56,8 @@ const KeyTree = forwardRef((props: Props, ref) => {
5056
const [sizes, setSizes] = useState(panelSizes)
5157
const [keyListState, setKeyListState] = useState<KeysStoreData>(keysState)
5258
const [constructingTree, setConstructingTree] = useState(false)
53-
const [selectDefaultLeaf, setSelectDefaultLeaf] = useState(true)
54-
const [items, setItems] = useState<IKeyPropTypes[]>(keysState.keys ?? [])
59+
const [selectDefaultLeaf, setSelectDefaultLeaf] = useState(isEmpty(selectedLeaf))
60+
const [items, setItems] = useState<IKeyPropTypes[]>(parseKeyNames(keysState.keys ?? []))
5561

5662
const dispatch = useDispatch()
5763

@@ -70,21 +76,22 @@ const KeyTree = forwardRef((props: Props, ref) => {
7076
}, [openNodes])
7177

7278
useEffect(() => {
73-
if (selectedLeaf) {
74-
setStatusSelected(selectedLeaf)
75-
updateKeysList(Object.values(selectedLeaf)[0])
76-
}
79+
setStatusSelected(selectedLeaf)
80+
updateKeysList(Object.values(selectedLeaf)?.[0])
81+
82+
setSelectDefaultLeaf(isEmpty(selectedLeaf))
7783
}, [selectedLeaf])
7884

7985
useEffect(() => {
8086
setItems(parseKeyNames(keysState.keys))
87+
8188
if (keysState.keys?.length === 0) {
82-
dispatch(setBrowserTreeSelectedLeaf({}))
89+
updateSelectedKeys()
8390
}
8491
}, [keysState.keys])
8592

8693
useEffect(() => {
87-
updateSelectedKeys()
94+
setItems(parseKeyNames(keysState.keys))
8895
}, [delimiter, keysState.lastRefreshTime])
8996

9097
const onLoadMoreItems = (props: { startIndex: number, stopIndex: number }) => {
@@ -94,7 +101,8 @@ const KeyTree = forwardRef((props: Props, ref) => {
94101

95102
// select default leaf "Keys" after each change delimiter, filter or search
96103
const updateSelectedKeys = () => {
97-
setItems(parseKeyNames(keysState.keys))
104+
dispatch(resetBrowserTree())
105+
98106
setTimeout(() => {
99107
startTransition(() => {
100108
setStatusSelected({})
@@ -103,10 +111,6 @@ const KeyTree = forwardRef((props: Props, ref) => {
103111
}, 0)
104112
}
105113

106-
const parseKeyNames = (keys: GetKeyInfoResponse[]) =>
107-
keys.map((item) =>
108-
({ ...item, nameString: item.nameString ?? bufferToString(item.name) }))
109-
110114
const updateKeysList = (items:any = {}) => {
111115
startTransition(() => {
112116
const newState:KeysStoreData = {

redisinsight/ui/src/pages/browser/components/key-tree/KeyTreeDelimiter/KeyTreeDelimiter.spec.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { cloneDeep } from 'lodash'
22
import React from 'react'
33
import { instance, mock } from 'ts-mockito'
44
import { DEFAULT_DELIMITER } from 'uiSrc/constants'
5-
import { setBrowserTreeDelimiter } from 'uiSrc/slices/app/context'
5+
import { resetBrowserTree, setBrowserTreeDelimiter } from 'uiSrc/slices/app/context'
66
import {
77
cleanup,
88
clearStoreActions,
@@ -72,6 +72,7 @@ describe('KeyTreeDelimiter', () => {
7272

7373
const expectedActions = [
7474
setBrowserTreeDelimiter(value),
75+
resetBrowserTree(),
7576
]
7677

7778
expect(clearStoreActions(store.getActions())).toEqual(
@@ -95,6 +96,7 @@ describe('KeyTreeDelimiter', () => {
9596

9697
const expectedActions = [
9798
setBrowserTreeDelimiter(DEFAULT_DELIMITER),
99+
resetBrowserTree(),
98100
]
99101

100102
expect(clearStoreActions(store.getActions())).toEqual(

redisinsight/ui/src/pages/browser/components/key-tree/KeyTreeDelimiter/KeyTreeDelimiter.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { replaceSpaces } from 'uiSrc/utils'
88
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
99
import InlineItemEditor from 'uiSrc/components/inline-item-editor'
1010
import { DEFAULT_DELIMITER } from 'uiSrc/constants'
11-
import { appContextDbConfig, setBrowserTreeDelimiter } from 'uiSrc/slices/app/context'
11+
import { appContextDbConfig, resetBrowserTree, setBrowserTreeDelimiter } from 'uiSrc/slices/app/context'
1212

1313
import styles from './styles.module.scss'
1414

@@ -51,6 +51,8 @@ const KeyTreeDelimiter = ({ loading }: Props) => {
5151
})
5252
closePopover()
5353
dispatch(setBrowserTreeDelimiter(value || DEFAULT_DELIMITER))
54+
55+
dispatch(resetBrowserTree())
5456
}
5557

5658
return (

redisinsight/ui/src/pages/browser/components/keys-header/KeysHeader.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ const KeysHeader = (props: Props) => {
259259

260260
dispatch(changeSearchMode(mode))
261261

262+
if (viewType === KeyViewType.Tree) {
263+
dispatch(resetBrowserTree())
264+
}
265+
262266
localStorageService.set(BrowserStorageItem.browserSearchMode, mode)
263267
}
264268

redisinsight/ui/src/pages/browser/components/search-key-list/SearchKeyList.spec.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
screen,
1111
} from 'uiSrc/utils/test-utils'
1212
import { loadKeys, setPatternSearchMatch } from 'uiSrc/slices/browser/keys'
13-
import { resetBrowserTree } from 'uiSrc/slices/app/context'
1413
import SearchKeyList from './SearchKeyList'
1514

1615
let store: typeof mockedStore
@@ -38,7 +37,7 @@ describe('SearchKeyList', () => {
3837

3938
fireEvent.keyDown(screen.getByTestId('search-key'), { key: keys.ENTER })
4039

41-
const expectedActions = [setPatternSearchMatch(searchTerm), resetBrowserTree(), loadKeys()]
40+
const expectedActions = [setPatternSearchMatch(searchTerm), loadKeys()]
4241

4342
expect(clearStoreActions(store.getActions())).toEqual(
4443
clearStoreActions(expectedActions)

redisinsight/ui/src/pages/browser/components/search-key-list/SearchKeyList.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ const SearchKeyList = () => {
3636

3737
const handleApply = (match = value) => {
3838
dispatch(setSearchMatch(match, searchMode))
39-
// reset browser tree context
40-
dispatch(resetBrowserTree())
4139

4240
dispatch(fetchKeys(
4341
searchMode,

0 commit comments

Comments
 (0)