Skip to content

Commit e6fce90

Browse files
committed
fix #260 and release version patch
1 parent c267f59 commit e6fce90

File tree

14 files changed

+557
-18
lines changed

14 files changed

+557
-18
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import * as React from 'react';
2+
3+
import { TreeDataSource, TreeGrid } from '@infinite-table/infinite-react';
4+
import {
5+
DataSourceApi,
6+
type InfiniteTableColumn,
7+
} from '@infinite-table/infinite-react';
8+
9+
export type FileSystemNode = {
10+
name: string;
11+
type: 'file' | 'folder';
12+
children?: FileSystemNode[] | null;
13+
sizeKB?: number;
14+
id: string;
15+
collapsed?: boolean;
16+
};
17+
18+
const nodes: FileSystemNode[] = [
19+
{
20+
name: 'Documents',
21+
type: 'folder',
22+
id: '1',
23+
children: [
24+
{
25+
name: 'report.doc',
26+
type: 'file',
27+
sizeKB: 100,
28+
id: '2',
29+
},
30+
{
31+
type: 'folder',
32+
name: 'pictures',
33+
id: '3',
34+
collapsed: true,
35+
children: [
36+
{
37+
name: 'mountain.jpg',
38+
type: 'file',
39+
sizeKB: 302,
40+
id: '5',
41+
},
42+
],
43+
},
44+
45+
{
46+
type: 'file',
47+
name: 'last.txt',
48+
id: '7',
49+
},
50+
],
51+
},
52+
];
53+
54+
const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
55+
name: {
56+
field: 'name',
57+
renderTreeIcon: true,
58+
59+
renderValue: ({ value, data }) => {
60+
return (
61+
<>
62+
{value} - {data!.id}
63+
</>
64+
);
65+
},
66+
},
67+
type: { field: 'type' },
68+
sizeKB: { field: 'sizeKB' },
69+
};
70+
export default function App() {
71+
const [dataSourceApi, setDataSourceApi] =
72+
React.useState<DataSourceApi<FileSystemNode> | null>(null);
73+
74+
const removeRowsByPrimaryKey = async () => {
75+
if (!dataSourceApi) {
76+
return;
77+
}
78+
79+
dataSourceApi.removeDataArray([{ id: '3' }, { id: '7' }]);
80+
};
81+
82+
return (
83+
<>
84+
<button type="button" onClick={removeRowsByPrimaryKey}>
85+
Click to remove children
86+
</button>
87+
<TreeDataSource<FileSystemNode>
88+
onReady={setDataSourceApi}
89+
data={nodes}
90+
primaryKey="id"
91+
nodesKey="children"
92+
>
93+
<TreeGrid<FileSystemNode>
94+
domProps={{
95+
style: {
96+
margin: '5px',
97+
height: 900,
98+
border: '1px solid gray',
99+
position: 'relative',
100+
},
101+
}}
102+
columns={columns}
103+
/>
104+
</TreeDataSource>
105+
</>
106+
);
107+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { test, expect } from '@testing';
2+
3+
export default test.describe.parallel('TreeDataSourceApi', () => {
4+
test('removeDataArray - with ids of collapsed children', async ({
5+
page,
6+
rowModel,
7+
treeModel,
8+
}) => {
9+
await page.waitForInfinite();
10+
11+
let rowCount = await rowModel.getRenderedRowCount();
12+
13+
expect(rowCount).toBe(5);
14+
15+
await treeModel.toggleParentNode(0);
16+
17+
rowCount = await rowModel.getRenderedRowCount();
18+
19+
expect(rowCount).toBe(1);
20+
21+
await page.click('button:text("Click to remove children")');
22+
await treeModel.toggleParentNode(0);
23+
24+
rowCount = await rowModel.getRenderedRowCount();
25+
26+
expect(rowCount).toBe(2);
27+
});
28+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import * as React from 'react';
2+
3+
import {
4+
DataSourcePropIsNodeExpanded,
5+
InfiniteTableColumn,
6+
TreeDataSource,
7+
TreeExpandState,
8+
TreeGrid,
9+
} from '@infinite-table/infinite-react';
10+
import { useState } from 'react';
11+
12+
export type FileSystemNode = {
13+
name: string;
14+
type: 'file' | 'folder';
15+
children?: FileSystemNode[] | null;
16+
sizeKB?: number;
17+
id: string;
18+
collapsed?: boolean;
19+
};
20+
21+
export const nodes: FileSystemNode[] = [
22+
{
23+
name: 'Documents',
24+
type: 'folder',
25+
id: '1',
26+
children: [
27+
{
28+
name: 'report.doc',
29+
type: 'file',
30+
sizeKB: 100,
31+
id: '2',
32+
},
33+
{
34+
type: 'folder',
35+
name: 'pictures',
36+
id: '3',
37+
children: [
38+
{
39+
name: 'mountain.jpg',
40+
type: 'file',
41+
sizeKB: 302,
42+
id: '5',
43+
},
44+
],
45+
},
46+
{
47+
type: 'folder',
48+
name: 'diverse',
49+
id: '4',
50+
children: [
51+
{
52+
name: 'beach.jpg',
53+
type: 'file',
54+
sizeKB: 2024,
55+
id: '6',
56+
},
57+
],
58+
},
59+
{
60+
type: 'file',
61+
name: 'last.txt',
62+
id: '7',
63+
},
64+
],
65+
},
66+
];
67+
68+
const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
69+
name: {
70+
field: 'name',
71+
renderTreeIcon: true,
72+
73+
renderValue: ({ value, data }) => {
74+
return (
75+
<>
76+
{value} - {data!.id}
77+
</>
78+
);
79+
},
80+
},
81+
type: { field: 'type' },
82+
sizeKB: { field: 'sizeKB' },
83+
};
84+
85+
export default function DataTestPage() {
86+
const [treeExpandState] = useState<TreeExpandState>(() => {
87+
return new TreeExpandState({
88+
defaultExpanded: false,
89+
expandedPaths: [['1', '4', '5'], ['1']],
90+
});
91+
});
92+
const [key, setKey] = useState(0);
93+
const isNodeExpanded = React.useCallback<
94+
DataSourcePropIsNodeExpanded<FileSystemNode>
95+
>(
96+
(rowInfo) => {
97+
return rowInfo.data.id === '3'
98+
? false
99+
: treeExpandState.isNodeExpanded(rowInfo.nodePath);
100+
},
101+
[key],
102+
);
103+
104+
return (
105+
<React.StrictMode>
106+
<button
107+
onClick={() => {
108+
treeExpandState.expandAll();
109+
setKey((k) => k + 1);
110+
}}
111+
>
112+
expand all
113+
</button>
114+
<TreeDataSource<FileSystemNode>
115+
data={nodes}
116+
primaryKey="id"
117+
nodesKey="children"
118+
treeExpandState={treeExpandState}
119+
onTreeExpandStateChange={(treeExpandStateValue) => {
120+
treeExpandState.update(treeExpandStateValue);
121+
setKey((k) => k + 1);
122+
}}
123+
isNodeExpanded={isNodeExpanded}
124+
>
125+
<TreeGrid<FileSystemNode>
126+
wrapRowsHorizontally
127+
domProps={{
128+
style: {
129+
margin: '5px',
130+
height: 900,
131+
border: '1px solid gray',
132+
position: 'relative',
133+
},
134+
}}
135+
columns={columns}
136+
/>
137+
</TreeDataSource>
138+
</React.StrictMode>
139+
);
140+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { test, expect } from '@testing';
2+
3+
export default test.describe('isNodeExpanded', () => {
4+
test('works as expected', async ({ page, rowModel, tableModel }) => {
5+
await page.waitForInfinite();
6+
7+
const cell = tableModel.withCell({
8+
rowIndex: 2,
9+
colIndex: 0,
10+
});
11+
12+
const collapsedNode = tableModel.withCell({
13+
rowIndex: 3,
14+
colIndex: 0,
15+
});
16+
17+
expect(await rowModel.getRenderedRowCount()).toBe(5);
18+
expect(await cell.isTreeIconExpanded()).toBe(false);
19+
expect(await collapsedNode.isTreeIconExpanded()).toBe(false);
20+
21+
await page.click('button:text("expand all")');
22+
23+
expect(await rowModel.getRenderedRowCount()).toBe(6);
24+
expect(await cell.isTreeIconExpanded()).toBe(false);
25+
expect(await collapsedNode.isTreeIconExpanded()).toBe(true);
26+
});
27+
});

examples/src/pages/tests/testUtils/TableTestingModel.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ export class TableTestingModel {
138138
);
139139
},
140140

141+
isTreeIconExpanded: async () => {
142+
const cellLocator = this.rowModel.getCellLocator(cellLocation);
143+
144+
const icon = cellLocator.locator('[data-name="expand-collapse-icon"]');
145+
return (await icon.getAttribute('data-state')) === 'expanded';
146+
},
147+
141148
getLocator: () => {
142149
return this.rowModel.getCellLocator(cellLocation);
143150
},

source/src/components/DataSource/TreeApi.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ export class TreeApiImpl<T> implements TreeApi<T> {
159159
return false;
160160
}
161161
if (isNodeCollapsed) {
162-
return !isNodeExpanded!(rowInfo);
162+
return !isNodeExpanded!(rowInfo, treeExpandState);
163163
}
164164
if (isNodeExpanded) {
165-
return isNodeExpanded!(rowInfo);
165+
return isNodeExpanded!(rowInfo, treeExpandState);
166166
}
167167
}
168168

source/src/components/DataSource/getDataSourceApi.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,18 +178,18 @@ class DataSourceApiImpl<T> implements DataSourceApi<T> {
178178
case 'delete':
179179
if (operation.primaryKeys) {
180180
operation.primaryKeys.forEach((key) => {
181-
const rowInfo = this.getRowInfoByPrimaryKey(key);
182-
if (rowInfo && !rowInfo.isGroupRow) {
183-
cache.delete(key, rowInfo.data, operation.metadata);
181+
const originalData = this.getDataByPrimaryKey(key);
182+
if (originalData) {
183+
cache.delete(key, originalData, operation.metadata);
184184
}
185185
});
186186
} else if (operation.nodePaths) {
187187
operation.nodePaths.forEach((nodePath) => {
188-
const rowInfo = this.getRowInfoByNodePath(nodePath);
189-
if (rowInfo && !rowInfo.isGroupRow) {
188+
const originalData = this.getDataByNodePath(nodePath);
189+
if (originalData) {
190190
cache.deleteNodePath(
191191
nodePath,
192-
rowInfo.data,
192+
originalData,
193193
operation.metadata,
194194
);
195195
}

source/src/components/DataSource/state/reducer.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -528,17 +528,22 @@ export function concludeReducer<T>(params: {
528528

529529
let isNodeExpanded:
530530
| ((rowInfo: InfiniteTable_Tree_RowInfoParentNode<T>) => boolean)
531-
| undefined = state.isNodeExpanded;
531+
| undefined;
532+
533+
if (state.isNodeExpanded) {
534+
isNodeExpanded = (rowInfo) =>
535+
state.isNodeExpanded!(rowInfo, treeExpandState!);
536+
}
532537

533538
if (state.isNodeCollapsed) {
534-
isNodeExpanded = (rowInfo) => !state.isNodeExpanded!(rowInfo);
539+
isNodeExpanded = (rowInfo) =>
540+
!state.isNodeExpanded!(rowInfo, treeExpandState!);
535541
}
536542

537543
if (!isNodeExpanded) {
538-
const defaultIsRowExpanded = (rowInfo: InfiniteTableRowInfo<T>) => {
539-
if (!rowInfo.isTreeNode || !rowInfo.isParentNode) {
540-
return false;
541-
}
544+
const defaultIsRowExpanded = (
545+
rowInfo: InfiniteTable_Tree_RowInfoParentNode<T>,
546+
) => {
542547
return treeExpandState!.isNodeExpanded(rowInfo.nodePath);
543548
};
544549

source/src/components/DataSource/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ export type DataSourcePropIsNodeSelectable<T> = (
488488

489489
export type DataSourcePropIsNodeExpanded<T> = (
490490
rowInfo: InfiniteTable_Tree_RowInfoParentNode<T>,
491+
treeExpandState: TreeExpandState,
491492
) => boolean;
492493

493494
// export type DataSourcePropIsCellSelected<T> = ( // TODO implement this

0 commit comments

Comments
 (0)