Skip to content

Commit 82f3ee1

Browse files
Merge pull request #469 from RedisInsight/bugfix/RI-2577_Tree_view_rename_key
#RI-2577 - Selected renamed key is displayed in tree view with old name
2 parents 2ec601b + 5348be8 commit 82f3ee1

File tree

11 files changed

+257
-96
lines changed

11 files changed

+257
-96
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ describe('VirtualTree', () => {
7777
/>
7878
)
7979

80-
expect(queryByTestId('test')).toBeInTheDocument()
80+
expect(queryByTestId('node-item_test')).toBeInTheDocument()
8181
})
8282

8383
it('should select first leaf "Keys" by default', async () => {

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable no-console */
21
import React, { useCallback, useContext, useEffect, useState } from 'react'
32
import AutoSizer from 'react-virtualized-auto-sizer'
43
import { isArray, isEmpty } from 'lodash'
@@ -18,7 +17,7 @@ import KeyLightSVG from 'uiSrc/assets/img/sidebar/browser.svg'
1817
import KeyDarkSVG from 'uiSrc/assets/img/sidebar/browser_active.svg'
1918

2019
import { Node } from './components/Node'
21-
import { NodeMeta, TreeData, TreeNode } from './interfaces'
20+
import { NodeMeta, TreeData, TreeNode, TREE_LEAF_FIELD } from './interfaces'
2221

2322
import styles from './styles.module.scss'
2423

@@ -42,7 +41,6 @@ export interface Props {
4241
setConstructingTree: (status: boolean) => void
4342
}
4443

45-
const timeLabel = 'Time for construct a Tree'
4644
const VirtualTree = (props: Props) => {
4745
const {
4846
items,
@@ -73,8 +71,6 @@ const VirtualTree = (props: Props) => {
7371
if (!result) {
7472
return
7573
}
76-
// [ToDo] remove after tests
77-
console.timeEnd(timeLabel)
7874

7975
setNodes(result)
8076
setConstructingTree?.(false)
@@ -100,8 +96,6 @@ const VirtualTree = (props: Props) => {
10096
return
10197
}
10298

103-
// [ToDo] remove after tests
104-
console.time(timeLabel)
10599
setConstructingTree(true)
106100
runWebworker?.({ items, separator })
107101
}, [items])
@@ -137,7 +131,7 @@ const VirtualTree = (props: Props) => {
137131
updateStatusOpen: handleUpdateOpen,
138132
leafIcon: theme === Theme.Dark ? KeyDarkSVG : KeyLightSVG,
139133
keyApproximate: node.keyApproximate,
140-
keys: node.keys || node?.['keys:keys'],
134+
keys: node.keys || node?.[TREE_LEAF_FIELD],
141135
isSelected: Object.keys(statusSelected)[0] === node.fullName,
142136
isOpenByDefault: statusOpen[node.fullName],
143137
},

redisinsight/ui/src/components/virtual-tree/components/Node/Node.spec.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { render, screen } from 'uiSrc/utils/test-utils'
55
import KeyDarkSVG from 'uiSrc/assets/img/sidebar/browser_active.svg'
66
import Node from './Node'
77
import { TreeData } from '../../interfaces'
8-
import { mockLeafKeys } from '../../VirtualTree.spec'
8+
import { mockLeafKeys, mockVirtualTreeResult } from '../../VirtualTree.spec'
99

1010
const mockedProps = mock<NodePublicState<TreeData>>()
1111
const mockedPropsData = mock<TreeData>()
@@ -16,6 +16,11 @@ const mockedData: TreeData = {
1616
}
1717
const mockDataFullName = 'test'
1818

19+
jest.mock('uiSrc/services', () => ({
20+
...jest.requireActual('uiSrc/services'),
21+
useDisposableWebworker: () => ({ result: mockVirtualTreeResult, run: jest.fn() }),
22+
}))
23+
1924
describe('Node', () => {
2025
it('should render', () => {
2126
expect(render(<Node {...instance(mockedProps)} data={mockedData} />)).toBeTruthy()
@@ -69,7 +74,7 @@ describe('Node', () => {
6974
data={mockData}
7075
/>)
7176

72-
screen.getByTestId(mockDataFullName).click()
77+
screen.getByTestId(`node-item_${mockDataFullName}`).click()
7378

7479
expect(mockSetItems).toBeCalledWith(mockLeafKeys)
7580
expect(mockUpdateStatusSelected).toBeCalledWith(mockDataFullName, mockLeafKeys)
@@ -101,7 +106,7 @@ describe('Node', () => {
101106
data={mockData}
102107
/>)
103108

104-
screen.getByTestId(mockDataFullName).click()
109+
screen.getByTestId(`node-item_${mockDataFullName}`).click()
105110

106111
expect(mockSetItems).not.toBeCalled()
107112
expect(mockUpdateStatusSelected).not.toBeCalled()

redisinsight/ui/src/components/virtual-tree/interfaces.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { FixedSizeNodeData } from 'react-vtree'
22
import { IKeyPropTypes } from 'uiSrc/constants/prop-types/keys'
33

4+
export const TREE_LEAF_FIELD = 'keys:keys'
5+
46
export interface TreeNode {
57
children: TreeNode[]
68
id: number
@@ -9,7 +11,7 @@ export interface TreeNode {
911
fullName: string
1012
name: string
1113
keys: any[]
12-
'keys:keys'?: any
14+
[TREE_LEAF_FIELD]?: any
1315
}
1416

1517
export interface NodeMeta {

redisinsight/ui/src/helpers/tests/constructKeysToTreeMockResult.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { TREE_LEAF_FIELD } from 'uiSrc/components/virtual-tree'
2+
13
export const constructKeysToTreeMockResult = [
24
{
3-
name: 'keys:keys',
5+
name: TREE_LEAF_FIELD,
46
children: [],
57
keys: {
68
keys2: {
@@ -29,14 +31,14 @@ export const constructKeysToTreeMockResult = [
2931
}
3032
},
3133
keyCount: 4,
32-
fullName: 'keys:keys:',
34+
fullName: `${TREE_LEAF_FIELD}:`,
3335
keyApproximate: 40,
3436
},
3537
{
3638
name: 'keys',
3739
children: [
3840
{
39-
name: 'keys:keys',
41+
name: TREE_LEAF_FIELD,
4042
children: [],
4143
keys: {
4244
'keys:1': {
@@ -59,14 +61,14 @@ export const constructKeysToTreeMockResult = [
5961
}
6062
},
6163
keyCount: 3,
62-
fullName: 'keys:keys:keys:',
64+
fullName: `keys:${TREE_LEAF_FIELD}:`,
6365
keyApproximate: 30,
6466
},
6567
{
6668
name: '1',
6769
children: [
6870
{
69-
name: 'keys:keys',
71+
name: TREE_LEAF_FIELD,
7072
children: [],
7173
keys: {
7274
'keys:1:2': {
@@ -83,7 +85,7 @@ export const constructKeysToTreeMockResult = [
8385
}
8486
},
8587
keyCount: 2,
86-
fullName: 'keys:1:keys:keys:',
88+
fullName: `keys:1:${TREE_LEAF_FIELD}:`,
8789
keyApproximate: 20,
8890
}
8991
],
@@ -103,7 +105,7 @@ export const constructKeysToTreeMockResult = [
103105
name: '',
104106
children: [
105107
{
106-
name: 'keys:keys',
108+
name: TREE_LEAF_FIELD,
107109
children: [],
108110
keys: {
109111
'empty::test': {
@@ -114,7 +116,7 @@ export const constructKeysToTreeMockResult = [
114116
}
115117
},
116118
keyCount: 1,
117-
fullName: 'empty::keys:keys:',
119+
fullName: `empty::${TREE_LEAF_FIELD}:`,
118120
keyApproximate: 10,
119121
}
120122
],

redisinsight/ui/src/pages/browser/BrowserPage.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
appContextBrowser,
2525
setBrowserPanelSizes,
2626
setLastPageContext,
27+
updateBrowserTreeSelectedLeaf,
2728
} from 'uiSrc/slices/app/context'
2829
import { appAnalyticsInfoSelector } from 'uiSrc/slices/app/info'
2930
import { resetErrors } from 'uiSrc/slices/app/notifications'
@@ -158,6 +159,14 @@ const BrowserPage = () => {
158159
}
159160
}
160161

162+
const handleEditKey = (key: string, newKey: string) => {
163+
setSelectedKey(newKey)
164+
165+
if (viewType === KeyViewType.Tree) {
166+
dispatch(updateBrowserTreeSelectedLeaf({ key, newKey }))
167+
}
168+
}
169+
161170
return (
162171
<div className={`browserPage ${styles.container}`}>
163172
<InstanceHeader />
@@ -238,7 +247,7 @@ const BrowserPage = () => {
238247
<KeyDetailsWrapper
239248
keyProp={selectedKey}
240249
onCloseKey={closeKey}
241-
onEditKey={(newKey: string) => setSelectedKey(newKey)}
250+
onEditKey={(key: string, newKey: string) => handleEditKey(key, newKey)}
242251
onDeleteKey={() => setSelectedKey(null)}
243252
/>
244253
)}

redisinsight/ui/src/pages/browser/components/key-details/KeyDetailsWrapper.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import KeyDetails from './KeyDetails/KeyDetails'
1818

1919
export interface Props {
2020
onCloseKey: () => void;
21-
onEditKey: (newKey: string) => void;
21+
onEditKey: (key: string, newKey: string) => void;
2222
onDeleteKey: () => void;
2323
keyProp: string | null;
2424
}
@@ -79,7 +79,7 @@ const KeyDetailsWrapper = ({ onCloseKey, onEditKey, onDeleteKey, keyProp }: Prop
7979
dispatch(editKeyTTL(key, ttl))
8080
}
8181
const handleEditKey = (oldKey: string, newKey: string, onFailure?: () => void) => {
82-
dispatch(editKey(oldKey, newKey, () => onEditKey(newKey), onFailure))
82+
dispatch(editKey(oldKey, newKey, () => onEditKey(oldKey, newKey), onFailure))
8383
}
8484

8585
const handleClose = () => {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe('KeyTree', () => {
109109
it('"setBrowserTreeNodesOpen" should be called for Open a node', () => {
110110
render(<KeyTree {...propsMock} />)
111111

112-
fireEvent.click(screen.getByTestId(mockVirtualTreeResult?.[0]?.fullName))
112+
fireEvent.click(screen.getByTestId(`node-item_${mockVirtualTreeResult?.[0]?.fullName}`))
113113

114114
const expectedActions = [setBrowserTreeSelectedLeaf({}), setBrowserTreeNodesOpen({})]
115115

redisinsight/ui/src/slices/app/context.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { createSlice } from '@reduxjs/toolkit'
2+
import { first } from 'lodash'
23
import { Nullable } from 'uiSrc/utils'
4+
import { TREE_LEAF_FIELD } from 'uiSrc/components/virtual-tree'
35
import { RootState } from '../store'
46
import { StateAppContext } from '../interfaces'
57

@@ -14,6 +16,7 @@ export const initialState: StateAppContext = {
1416
},
1517
panelSizes: {},
1618
tree: {
19+
separator: ':',
1720
panelSizes: {},
1821
openNodes: {},
1922
selectedLeaf: {},
@@ -56,6 +59,29 @@ const appContextSlice = createSlice({
5659
setBrowserTreeSelectedLeaf: (state, { payload }: { payload: any }) => {
5760
state.browser.tree.selectedLeaf = payload
5861
},
62+
updateBrowserTreeSelectedLeaf: (state, { payload }) => {
63+
const { selectedLeaf, separator } = state.browser.tree
64+
const [[selectedLeafField = '', keys = {}]] = Object.entries(selectedLeaf)
65+
const [pattern] = selectedLeafField.split(TREE_LEAF_FIELD)
66+
67+
if (payload.key in keys) {
68+
const isFitNewKey = payload.newKey?.startsWith?.(pattern)
69+
&& (pattern.split(separator)?.length === payload.newKey.split(separator)?.length)
70+
71+
if (!isFitNewKey) {
72+
delete keys[payload.key]
73+
return
74+
}
75+
76+
keys[payload.newKey] = {
77+
...keys[payload.key],
78+
name: payload.newKey
79+
}
80+
delete keys[payload.key]
81+
}
82+
83+
state.browser.tree.selectedLeaf[selectedLeafField] = keys
84+
},
5985
setBrowserTreeNodesOpen: (state, { payload }: { payload: { [key: string]: boolean; } }) => {
6086
state.browser.tree.openNodes = payload
6187
},
@@ -102,6 +128,7 @@ export const {
102128
setBrowserPanelSizes,
103129
setBrowserTreeSelectedLeaf,
104130
setBrowserTreeNodesOpen,
131+
updateBrowserTreeSelectedLeaf,
105132
resetBrowserTree,
106133
setBrowserTreePanelSizes,
107134
setWorkbenchScript,

0 commit comments

Comments
 (0)