Skip to content

Commit

Permalink
fix tree selection bug and release version patch fixes #255
Browse files Browse the repository at this point in the history
  • Loading branch information
radubrehar committed Oct 29, 2024
1 parent 0c4b459 commit 39af92e
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 3 deletions.
182 changes: 182 additions & 0 deletions examples/src/pages/tests/table/treegrid/selection2.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import {
DataSourceApi,
InfiniteTableColumn,
TreeDataSource,
TreeGrid,
TreeSelectionValue,
} from '@infinite-table/infinite-react';
import { useState } from 'react';

type FileSystemNode = {
id: string;
name: string;
type: 'folder' | 'file';
extension?: string;
mimeType?: string;
sizeInKB: number;
children?: FileSystemNode[];
};

const columns: Record<string, InfiniteTableColumn<FileSystemNode>> = {
name: {
field: 'name',
header: 'Name',
defaultWidth: 500,
renderValue: ({ value, rowInfo }) => {
return (
<div style={{ color: 'red', display: 'inline-block' }}>
{rowInfo.id} - {value}
</div>
);
},
renderTreeIcon: true,
renderSelectionCheckBox: true,
},
type: { field: 'type', header: 'Type' },
extension: { field: 'extension', header: 'Extension' },
mimeType: { field: 'mimeType', header: 'Mime Type' },
size: { field: 'sizeInKB', type: 'number', header: 'Size (KB)' },
};

const defaultTreeSelection: TreeSelectionValue = {
defaultSelection: true,
deselectedPaths: [
['1', '10'],
['3', '31'],
],
selectedPaths: [['3']],
};

export default function App() {
const [dataSourceApi, setDataSourceApi] =
useState<DataSourceApi<FileSystemNode> | null>();

return (
<>
<TreeDataSource
onReady={setDataSourceApi}
nodesKey="children"
primaryKey="id"
data={dataSource}
defaultTreeSelection={defaultTreeSelection}
>
<div
style={{
color: 'var(--infinite-cell-color)',
padding: 10,
display: 'flex',
gap: 10,
}}
>
<button
onClick={() => {
dataSourceApi!.treeApi.selectAll();
}}
>
Select all
</button>
<button
onClick={() => {
dataSourceApi!.treeApi.deselectAll();
}}
>
Deselect all
</button>
</div>

<TreeGrid columns={columns} domProps={{ style: { height: '100%' } }} />
</TreeDataSource>
</>
);
}

const dataSource = () => {
const nodes: FileSystemNode[] = [
{
id: '1',
name: 'Documents',
sizeInKB: 1200,
type: 'folder',
children: [
{
id: '10',
name: 'Private',
sizeInKB: 100,
type: 'folder',
children: [
{
id: '100',
name: 'Report.docx',
sizeInKB: 210,
type: 'file',
extension: 'docx',
mimeType: 'application/msword',
},
{
id: '101',
name: 'Vacation.docx',
sizeInKB: 120,
type: 'file',
extension: 'docx',
mimeType: 'application/msword',
},
{
id: '102',
name: 'CV.pdf',
sizeInKB: 108,
type: 'file',
extension: 'pdf',
mimeType: 'application/pdf',
},
],
},
],
},
{
id: '2',
name: 'Desktop',
sizeInKB: 1000,
type: 'folder',
children: [
{
id: '20',
name: 'unknown.txt',
sizeInKB: 100,
type: 'file',
},
],
},
{
id: '3',
name: 'Media',
sizeInKB: 1000,
type: 'folder',
children: [
{
id: '30',
name: 'Music - empty',
sizeInKB: 0,
type: 'folder',
children: [],
},
{
id: '31',
name: 'Videos',
sizeInKB: 5400,
type: 'folder',
children: [
{
id: '310',
name: 'Vacation.mp4',
sizeInKB: 108,
type: 'file',
extension: 'mp4',
mimeType: 'video/mp4',
},
],
},
],
},
];
return Promise.resolve(nodes);
};
21 changes: 21 additions & 0 deletions examples/src/pages/tests/table/treegrid/selection2.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test, expect } from '@testing';

export default test.describe('TreeSelectionProp', () => {
test('when defined, makes selectionMode default to multi-row', async ({
page,
}) => {
await page.waitForInfinite();

const headerCheckbox = await page.locator(
'.InfiniteHeader input[type="checkbox"]',
);
expect(
await headerCheckbox?.evaluate((el) => {
return {
checked: (el as HTMLInputElement).checked,
indeterminate: (el as HTMLInputElement).indeterminate,
};
}),
).toEqual({ checked: false, indeterminate: true });
});
});
58 changes: 58 additions & 0 deletions examples/src/pages/tests/table/utils/DeepMap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,64 @@ export default test.describe('DeepMap', () => {
]);
});

test('getUnnestedKeysStartingWith should work correctly - 1', () => {
let map = new DeepMap<string | number, boolean>();

map.set(['3', '31'], true);
map.set(['1'], true);
map.set(['1', '10'], true);
map.set(['3'], true);

expect(map.getUnnestedKeysStartingWith([], true)).toEqual([['1'], ['3']]);
expect(map.getKeysStartingWith([], true)).toEqual([
['3'],
['3', '31'],
['1'],
['1', '10'],
]);

map = new DeepMap<string | number, boolean>();

map.set(['3', '31'], true);

map.set(['1', '10'], true);
map.set(['3'], true);
map.set(['1'], true);

expect(map.getUnnestedKeysStartingWith([], true)).toEqual([['3'], ['1']]);
});

test.only('getUnnestedKeysStartingWith should work correctly - 2', () => {
let map = new DeepMap<string | number, boolean>();

map.set(['3', '31', '300'], true);

map.set(['1', '10'], true);
map.set(['3', '30'], true);
map.set(['3', '31', '400'], true);
map.set(['3', '31', '400', '200'], true);
map.set(['1'], true);
map.set(['1', '100'], true);

const expected = [
['3', '31', '300'],
['3', '30'],
['3', '31', '400'],
['1'],
];
expect(map.getUnnestedKeysStartingWith([], true)).toEqual(expected);

map.set([], true);

expect(map.getUnnestedKeysStartingWith([])).toEqual([[]]);
expect(map.getUnnestedKeysStartingWith([], true)).toEqual(expected);
expect(map.getUnnestedKeysStartingWith([], true, 1)).toEqual([['1']]);
expect(map.getUnnestedKeysStartingWith([], true, 2)).toEqual([
['3', '30'],
['1'],
]);
});

test('visit depth first, with index', () => {
const map = new DeepMap<string | number, number>();

Expand Down
3 changes: 2 additions & 1 deletion source/src/components/DataSource/TreeSelectionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ export class TreeSelectionState<T = any> {
const { selectionMap } = this;

const childPaths = selectionMap
.getKeysStartingWith(nodePath, true)
// todo this could be replaced with a .hasKeysUnder call (to be implemented in the deep map later)
.getUnnestedKeysStartingWith(nodePath, true)
.sort(shortestToLongest);

if (!childPaths.length) {
Expand Down
76 changes: 74 additions & 2 deletions source/src/utils/DeepMap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,77 @@ export class DeepMap<KeyType, ValueType> {
return result;
}

getUnnestedKeysStartingWith(
keys: KeyType[],
excludeSelf?: boolean,
depthLimit?: number,
): KeyType[][] {
const pairs: (Pair<KeyType, ValueType> & { keys: KeyType[] })[] = [];

const fn: (pair: Pair<KeyType, ValueType> & { keys: KeyType[] }) => void = (
pair,
) => {
pairs.push(pair);
};

let currentMap = this.map;
let pair: Pair<KeyType, ValueType> | undefined;
let stop = false;

if (keys.length) {
for (let i = 0, len = keys.length; i < len; i++) {
const key = keys[i];

pair = currentMap.get(key);

if (!pair || !pair.map) {
stop = true;
if (i === len - 1) {
// if on the last key
// we want to allow the if clause below to run and check if the value on the last
// pair is present
stop = true;
break;
} else {
return [];
}
}

currentMap = pair.map;
}
} else {
if (!excludeSelf) {
const hasEmptyKey = currentMap.has(this.emptyKey);
if (hasEmptyKey) {
return [[]];
}
}
}

if (pair && pair.value !== undefined) {
if (!excludeSelf) {
fn({ ...pair, keys });
stop = true;
}
}
if (stop) {
return pairs.sort(SORT_ASC_REVISION).map((pair) => pair.keys);
}

this.visitWithNext(
keys,
(_value, keys, _i, _next, pair) => {
fn({ ...pair, keys });
// don't call next to go deeper
},
currentMap,
depthLimit,
excludeSelf,
);

return pairs.sort(SORT_ASC_REVISION).map((pair) => pair.keys);
}

getKeysStartingWith(
keys: KeyType[],
excludeSelf?: boolean,
Expand Down Expand Up @@ -443,7 +514,8 @@ export class DeepMap<KeyType, ValueType> {
value: ValueType,
keys: KeyType[],
indexInGroup: number,
next?: VoidFn,
next: VoidFn | undefined,
pair: Pair<KeyType, ValueType>,
) => void,
currentMap: Map<KeyType, Pair<KeyType, ValueType>> = this.map,
depthLimit?: number,
Expand Down Expand Up @@ -488,7 +560,7 @@ export class DeepMap<KeyType, ValueType> {
: undefined;

if (pair.hasOwnProperty('value')) {
fn(pair.value!, keys, i, next);
fn(pair.value!, keys, i, next, pair);
i++;
} else {
next?.();
Expand Down
5 changes: 5 additions & 0 deletions www/content/docs/releases/index.page.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
title: Releases
description: All releases | Infinite Table DataGrid for React
---

## 6.0.5

@milestone id="131"

## 6.0.0

@milestone id="130"
Expand Down

0 comments on commit 39af92e

Please sign in to comment.