Skip to content

Commit eff999f

Browse files
Merge pull request #2783 from RedisInsight/fe/feature/RI-5131-5170_tree_view
#RI-5131-5170 - update tree view
2 parents 5ce49ba + 9643326 commit eff999f

File tree

8 files changed

+112
-32
lines changed

8 files changed

+112
-32
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ const BrowserPage = () => {
190190
}
191191

192192
const selectKey = ({ rowData }: { rowData: any }) => {
193-
if (!isEqualBuffers(rowData.name, selectedKey)) {
193+
if (!isEqualBuffers(rowData.name, selectedKeyRef.current)) {
194194
dispatch(toggleBrowserFullScreen(false))
195195

196196
dispatch(setInitialStateByType(prevSelectedType.current))

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ const KeyTree = forwardRef((props: Props, ref) => {
126126
openSelectedKey(selectedKeyName)
127127
}
128128

129-
const handleStatusOpen = (name: string, value:boolean) => {
129+
const handleStatusOpen = (name: string, value: boolean) => {
130130
setStatusOpen((prevState) => {
131131
const newState = { ...prevState }
132132
// add or remove opened node

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

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,36 @@ const mockedItems = [
1515
},
1616
]
1717

18-
export const mockVirtualTreeResult = [{
19-
children: [{
18+
export const mockVirtualTreeResult = [
19+
{
20+
children: [{
21+
children: [],
22+
fullName: 'car:110:',
23+
id: '0.snc1rc3zwgo',
24+
keyApproximate: 0.01,
25+
keyCount: 1,
26+
name: '110',
27+
}],
28+
fullName: 'car:',
29+
id: '0.sz1ie1koqi8',
30+
keyApproximate: 47.18,
31+
keyCount: 4718,
32+
name: 'car',
33+
},
34+
{
2035
children: [],
21-
fullName: 'car:110:',
22-
id: '0.snc1rc3zwgo',
36+
fullName: 'test',
37+
id: '0.snc1rc3zwg1o',
2338
keyApproximate: 0.01,
2439
keyCount: 1,
25-
name: '110',
26-
}],
27-
fullName: 'car:',
28-
id: '0.sz1ie1koqi8',
29-
keyApproximate: 47.18,
30-
keyCount: 4718,
31-
name: 'car',
32-
},
33-
{
34-
children: [],
35-
fullName: 'test',
36-
id: '0.snc1rc3zwg1o',
37-
keyApproximate: 0.01,
38-
keyCount: 1,
39-
name: 'test',
40-
}]
40+
name: 'test',
41+
}
42+
]
4143

4244
jest.mock('uiSrc/services', () => ({
45+
__esModule: true,
4346
...jest.requireActual('uiSrc/services'),
44-
useDisposableWebworker: () => ({ result: mockVirtualTreeResult, run: jest.fn() }),
47+
useDisposableWebworker: () => ({ result: mockVirtualTreeResult, run: jest.fn() })
4548
}))
4649

4750
describe('VirtualTree', () => {
@@ -74,4 +77,19 @@ describe('VirtualTree', () => {
7477

7578
expect(queryByTestId('node-item_test')).toBeInTheDocument()
7679
})
80+
81+
it('should not call onStatusOpen if more than one folder is exist', () => {
82+
const mockFn = jest.fn()
83+
const mockOnStatusOpen = jest.fn()
84+
85+
render(
86+
<VirtualTree
87+
{...instance(mockedProps)}
88+
onStatusOpen={mockOnStatusOpen}
89+
setConstructingTree={mockFn}
90+
/>
91+
)
92+
93+
expect(mockOnStatusOpen).not.toHaveBeenCalled()
94+
})
7795
})

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const VirtualTree = (props: Props) => {
6363
onStatusOpen,
6464
onStatusSelected,
6565
setConstructingTree,
66-
webworkerFn = () => {},
66+
webworkerFn = () => { },
6767
onDeleteClicked,
6868
onDeleteLeaf,
6969
} = props
@@ -94,6 +94,8 @@ const VirtualTree = (props: Props) => {
9494
nodes.current = result
9595
rerender({})
9696
setConstructingTree?.(false)
97+
98+
openSingleFolderNode(nodes.current)
9799
}, [result])
98100

99101
useEffect(() => {
@@ -205,6 +207,15 @@ const VirtualTree = (props: Props) => {
205207
node,
206208
})
207209

210+
const openSingleFolderNode = useCallback((treeNodes?: TreeNode[]) => {
211+
let nodes = treeNodes
212+
while (nodes?.length === 1) {
213+
const singleNode = nodes[0]
214+
onStatusOpen?.(singleNode.fullName, true)
215+
nodes = singleNode.children
216+
}
217+
}, [onStatusOpen])
218+
208219
// The `treeWalker` function runs only on tree re-build which is performed
209220
// whenever the `treeWalker` prop is changed.
210221
const treeWalker = useCallback(

redisinsight/ui/src/pages/browser/components/virtual-tree/components/Node/Node.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const Node = ({
6666
}, [])
6767

6868
const handleClick = () => {
69-
if (isLeaf && !isSelected) {
69+
if (isLeaf) {
7070
updateStatusSelected?.(nameBuffer)
7171
}
7272

@@ -154,7 +154,7 @@ const Node = ({
154154
onKeyDown={handleKeyDown}
155155
tabIndex={0}
156156
onFocus={() => {}}
157-
data-testid={`node-item_${fullName}`}
157+
data-testid={`node-item_${fullName}${isOpen && !isLeaf ? '--expanded' : ''}`}
158158
>
159159
{!isLeaf && <Folder />}
160160
{isLeaf && <Leaf />}

tests/e2e/common-actions/browser-actions.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export class BrowserActions {
8787
* @param name node name
8888
*/
8989
getNodeSelector(name: string): Selector {
90-
return Selector(`[data-testid="node-item_${name}"]`);
90+
return Selector(`[data-testid^="node-item_${name}"]`);
9191
}
9292

9393
/**
@@ -108,7 +108,10 @@ export class BrowserActions {
108108
for (let j = 0; j < innerFoldersNumber; j++) {
109109
const nodeName = this.getNodeName(prevNodeSelector, folders[i][j], delimiter);
110110
const node = this.getNodeSelector(nodeName);
111-
await t.click(node);
111+
const fullTestIdSelector = await node.getAttribute('data-testid');
112+
if (!fullTestIdSelector?.includes('expanded')) {
113+
await t.click(node);
114+
}
112115
prevNodeSelector = nodeName;
113116
}
114117

tests/e2e/pageObjects/components/browser/tree-view.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ export class TreeView {
7171
await t.click(this.treeViewSettingsBtn);
7272
await t.click(this.sortingBtn);
7373
order === 'ASC'
74-
? await t.click(this.sortingASCoption)
75-
: await t.click(this.sortingDESCoption)
74+
? await t.click(this.sortingASCoption)
75+
: await t.click(this.sortingDESCoption);
7676

7777
// Click on save button
7878
await t.click(this.treeViewDelimiterValueSave);
@@ -93,11 +93,11 @@ export class TreeView {
9393
*/
9494
async openTreeFolders(names: string[]): Promise<void> {
9595
let base = `node-item_${names[0]}:`;
96-
await t.click(Selector(`[data-testid="${base}"]`));
96+
await this.clickElementIfNotExpanded(base);
9797
if (names.length > 1) {
9898
for (let i = 1; i < names.length; i++) {
9999
base = `${base }${names[i]}:`;
100-
await t.click(Selector(`[data-testid="${base}"]`));
100+
await this.clickElementIfNotExpanded(base);
101101
}
102102
}
103103
}
@@ -120,4 +120,16 @@ export class TreeView {
120120

121121
return textArray;
122122
}
123+
124+
/**
125+
* click on the folder element if it is not expanded
126+
* @param base the base element
127+
*/
128+
private async clickElementIfNotExpanded(base: string): Promise<void> {
129+
const baseSelector = Selector(`[data-testid^="${base}"]`);
130+
const elementSelector = await baseSelector.getAttribute('data-testid');
131+
if (!elementSelector?.includes('expanded')) {
132+
await t.click(Selector(`[data-testid^="${base}"]`));
133+
}
134+
}
123135
}

tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { BrowserPage, WorkbenchPage } from '../../../../pageObjects';
33
import {
44
commonUrl,
55
ossStandaloneBigConfig,
6+
ossStandaloneConfig,
67
ossStandaloneConfigEmpty,
78
ossStandaloneRedisearch
89
} from '../../../../helpers/conf';
910
import { KeyTypesTexts, rte } from '../../../../helpers/constants';
1011
import { DatabaseAPIRequests } from '../../../../helpers/api/api-database';
1112
import { APIKeyRequests } from '../../../../helpers/api/api-keys';
1213
import { Common } from '../../../../helpers/common';
14+
import { verifyKeysDisplayingInTheList } from '../../../../helpers/keys';
1315

1416
const browserPage = new BrowserPage();
1517
const workbenchPage = new WorkbenchPage();
@@ -145,3 +147,37 @@ test
145147
actualItemsArray = await browserPage.TreeView.getAllItemsArray();
146148
await t.expect(actualItemsArray).eql(expectedSortedByDESC);
147149
});
150+
151+
https://redislabs.atlassian.net/browse/RI-5131
152+
test
153+
.before(async() => {
154+
await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig);
155+
})
156+
.after(async() => {
157+
await browserPage.Cli.sendCommandInCli('flushdb');
158+
await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig);
159+
})('Verify that if filtering results has only 1 folder, the folder will be expanded', async t => {
160+
const name = Common.generateWord(10);
161+
const additionalCharacter = Common.generateWord(1);
162+
const keyName1 = Common.generateWord(3);
163+
const keyName2 = Common.generateWord(3);
164+
keyNames = [`${name}${additionalCharacter}:${keyName1}`, `${name}${additionalCharacter}:${keyName2}`, name];
165+
166+
const commands = [
167+
'flushdb',
168+
`HSET ${keyNames[0]} field value`,
169+
`HSET ${keyNames[1]} field value`,
170+
`HSET ${keyNames[2]} field value`
171+
];
172+
await browserPage.Cli.sendCommandsInCli(commands);
173+
await t.click(browserPage.treeViewButton);
174+
175+
// Verify if there is only folder, a user can see keys inside
176+
await browserPage.searchByKeyName(`${name}${additionalCharacter}*`);
177+
await verifyKeysDisplayingInTheList([keyName1, keyName2], true);
178+
179+
// Verify if there are folder and key, a user can't see keys inside the folder
180+
await browserPage.searchByKeyName(`${name}*`);
181+
await verifyKeysDisplayingInTheList([keyName1, keyName2], false);
182+
});
183+

0 commit comments

Comments
 (0)