Skip to content

Commit

Permalink
feat(react-grid): support custom grouping processing (#395)
Browse files Browse the repository at this point in the history
  • Loading branch information
kvet authored Oct 24, 2017
1 parent 728ea23 commit 4fb92d0
Show file tree
Hide file tree
Showing 35 changed files with 1,343 additions and 291 deletions.
1 change: 1 addition & 0 deletions packages/dx-grid-core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './plugins/local-filtering/computeds';
export * from './plugins/grouping-state/reducers';
export * from './plugins/grouping-state/computeds';
export * from './plugins/local-grouping/computeds';
export * from './plugins/custom-grouping/computeds';
export * from './plugins/grouping-panel/helpers';

export * from './plugins/paging-state/reducers';
Expand Down
54 changes: 54 additions & 0 deletions packages/dx-grid-core/src/plugins/custom-grouping/computeds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {
GROUP_KEY_SEPARATOR,
} from '../grouping-state/constants';
import {
GRID_GROUP_TYPE,
GRID_GROUP_CHECK,
GRID_GROUP_LEVEL_KEY,
} from '../local-grouping/constants';

export const customGroupedRows = (
currentRows,
grouping,
getChildGroups,
rootRows = currentRows,
keyPrefix = '',
) => {
if (!currentRows) return [];
if (!grouping.length) return currentRows;

const groupedBy = grouping[0].columnName;
const nestedGrouping = grouping.slice(1);
return getChildGroups(currentRows, grouping[0], rootRows)
.reduce((acc, { key, value = key, childRows }) => {
const compoundKey = `${keyPrefix}${key}`;
acc.push({
[GRID_GROUP_CHECK]: true,
[GRID_GROUP_LEVEL_KEY]: `${GRID_GROUP_TYPE}_${groupedBy}`,
groupedBy,
compoundKey,
key,
value,
});
acc.push(...customGroupedRows(
childRows,
nestedGrouping,
getChildGroups,
rootRows,
`${compoundKey}${GROUP_KEY_SEPARATOR}`,
));
return acc;
}, []);
};

export const customGroupingRowIdGetter = (getRowId, rows) => {
const firstRow = rows.find(row => !row[GRID_GROUP_CHECK]);
if (!firstRow || getRowId(firstRow)) {
return getRowId;
}
const map = new Map(rows
.filter(row => !row[GRID_GROUP_CHECK])
.map((row, rowIndex) => [row, rowIndex]));

return row => map.get(row);
};
232 changes: 232 additions & 0 deletions packages/dx-grid-core/src/plugins/custom-grouping/computeds.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import {
customGroupedRows,
customGroupingRowIdGetter,
} from './computeds';
import {
GRID_GROUP_TYPE,
GRID_GROUP_CHECK,
GRID_GROUP_LEVEL_KEY,
} from '../local-grouping/constants';

describe('CustomGrouping Plugin computeds', () => {
const groupRow = ({ groupedBy, ...restParams }) => ({
...restParams,
groupedBy,
[GRID_GROUP_CHECK]: true,
[GRID_GROUP_LEVEL_KEY]: `${GRID_GROUP_TYPE}_${groupedBy}`,
});

describe('#customGroupedRows', () => {
it('should process hierarchical data by one column', () => {
const hierarchicalSource = [{
key: 1,
items: [
{ a: 1, b: 1 },
{ a: 1, b: 2 },
],
}, {
key: 2,
items: [
{ a: 2, b: 1 },
{ a: 2, b: 2 },
],
}];
const getHierarchicalChildGroups = groups => groups
.map(group => ({ key: String(group.key), value: group.key, childRows: group.items }));
const groupings = [{ columnName: 'a' }];
const groupedRows = [
groupRow({
groupedBy: 'a',
compoundKey: '1',
key: '1',
value: 1,
}),
{ a: 1, b: 1 },
{ a: 1, b: 2 },
groupRow({
groupedBy: 'a',
compoundKey: '2',
key: '2',
value: 2,
}),
{ a: 2, b: 1 },
{ a: 2, b: 2 },
];

const getChildGroups = jest.fn(getHierarchicalChildGroups);

expect(customGroupedRows(
hierarchicalSource,
groupings,
getChildGroups,
))
.toEqual(groupedRows);

expect(getChildGroups)
.toBeCalledWith(hierarchicalSource, groupings[0], hierarchicalSource);
});

it('should process hierarchical data by one column with remote expanded groups', () => {
const hierarchicalSource = [{
key: 1,
items: null,
}];
const getHierarchicalChildGroups = groups => groups
.map(group => ({ key: String(group.key), value: group.key, childRows: group.items }));
const groupings = [{ columnName: 'a' }];
const groupedRows = [
groupRow({
groupedBy: 'a',
compoundKey: '1',
key: '1',
value: 1,
}),
];

const getChildGroups = jest.fn(getHierarchicalChildGroups);

expect(customGroupedRows(
hierarchicalSource,
groupings,
getChildGroups,
))
.toEqual(groupedRows);
});

it('should process hierarchical data by several columns', () => {
const hierarchicalSource = [{
key: 1,
items: [{
key: 1,
items: [
{ a: 1, b: 1 },
],
}, {
key: 2,
items: [
{ a: 1, b: 2 },
],
}],
}, {
key: 2,
items: [{
key: 1,
items: [
{ a: 2, b: 1 },
],
}, {
key: 2,
items: [
{ a: 2, b: 2 },
],
}],
}];
const getHierarchicalChildGroups = groups => groups
.map(group => ({ key: String(group.key), value: group.key, childRows: group.items }));
const groupings = [{ columnName: 'a' }, { columnName: 'b' }];
const groupedRows = [
groupRow({
groupedBy: 'a',
compoundKey: '1',
key: '1',
value: 1,
}),
groupRow({
groupedBy: 'b',
compoundKey: '1|1',
key: '1',
value: 1,
}),
{ a: 1, b: 1 },
groupRow({
groupedBy: 'b',
compoundKey: '1|2',
key: '2',
value: 2,
}),
{ a: 1, b: 2 },
groupRow({
groupedBy: 'a',
compoundKey: '2',
key: '2',
value: 2,
}),
groupRow({
groupedBy: 'b',
compoundKey: '2|1',
key: '1',
value: 1,
}),
{ a: 2, b: 1 },
groupRow({
groupedBy: 'b',
compoundKey: '2|2',
key: '2',
value: 2,
}),
{ a: 2, b: 2 },
];

const getChildGroups = jest.fn(getHierarchicalChildGroups);

expect(customGroupedRows(
hierarchicalSource,
groupings,
getChildGroups,
))
.toEqual(groupedRows);

expect(getChildGroups)
.toBeCalledWith(hierarchicalSource, groupings[0], hierarchicalSource);
expect(getChildGroups)
.toBeCalledWith(hierarchicalSource[0].items, groupings[1], hierarchicalSource);
expect(getChildGroups)
.toBeCalledWith(hierarchicalSource[1].items, groupings[1], hierarchicalSource);
});
});

describe('#customGroupingRowIdGetter', () => {
it('should define row ids to rows if not present', () => {
const groupedRows = [
groupRow({
groupedBy: 'a',
key: '1',
value: 1,
}),
{ a: 1, b: 1 },
{ a: 1, b: 2 },
];
const parentGetRowId = () => undefined;
const getRowId = customGroupingRowIdGetter(parentGetRowId, groupedRows);

expect(getRowId(groupedRows[1]))
.toBe(0);
expect(getRowId(groupedRows[2]))
.toBe(1);
});

it('should not define row ids to empty rows', () => {
const parentGetRowId = () => undefined;
const getRowId = customGroupingRowIdGetter(parentGetRowId, [], []);

expect(getRowId(1))
.toBe(undefined);
});

it('should not define row ids if getRowId is defined', () => {
const groupedRows = [
groupRow({
groupedBy: 'a',
key: '1',
value: 1,
}),
{ a: 1, b: 1 },
];
const parentGetRowId = () => 1;
const getRowId = customGroupingRowIdGetter(parentGetRowId, groupedRows);

expect(getRowId(1))
.toBe(1);
});
});
});
67 changes: 43 additions & 24 deletions packages/dx-grid-core/src/plugins/local-grouping/computeds.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { GROUP_KEY_SEPARATOR } from '../grouping-state/constants';
import {
GROUP_KEY_SEPARATOR,
} from '../grouping-state/constants';
import {
GRID_GROUP_TYPE,
GRID_GROUP_CHECK,
Expand All @@ -19,6 +21,7 @@ export const groupedRows = (
grouping,
getCellValue,
getColumnIdentity,
keyPrefix = '',
) => {
if (!grouping.length) return rows;

Expand All @@ -38,35 +41,51 @@ export const groupedRows = (
return acc;
}, new Map());

const groupedBy = grouping[0].columnName;
const nestedGrouping = grouping.slice(1);
return [...groups.values()]
.map(([value, key, items]) => ({
value,
key,
items: groupedRows(items, nestedGrouping, getCellValue, getColumnIdentity),
}));
};

export const expandedGroupRows = (rows, grouping, expandedGroups, keyPrefix = '') => {
if (!grouping.length) return rows;

const nestedGrouping = grouping.slice(1);
return rows.reduce((acc, { value, key: groupKey, items }) => {
const groupedBy = grouping[0].columnName;
const key = `${keyPrefix}${groupKey}`;
const expanded = expandedGroups.has(key);
return [
...acc,
{
.reduce((acc, [value, key, items]) => {
const compoundKey = `${keyPrefix}${key}`;
acc.push({
[GRID_GROUP_CHECK]: true,
[GRID_GROUP_LEVEL_KEY]: `${GRID_GROUP_TYPE}_${groupedBy}`,
groupedBy,
compoundKey,
key,
value,
},
...expanded
? expandedGroupRows(items, nestedGrouping, expandedGroups, `${key}${GROUP_KEY_SEPARATOR}`)
: [],
];
});
acc.push(...groupedRows(
items,
nestedGrouping,
getCellValue,
getColumnIdentity,
`${compoundKey}${GROUP_KEY_SEPARATOR}`,
));
return acc;
}, []);
};

export const expandedGroupRows = (rows, grouping, expandedGroups) => {
if (!grouping.length) return rows;

const groupingColumnNames = grouping.map(columnGrouping => columnGrouping.columnName);
let currentGroupExpanded = true;
let currentGroupLevel = 0;
return rows.reduce((acc, row) => {
if (!row[GRID_GROUP_CHECK]) {
if (currentGroupExpanded) acc.push(row);
return acc;
}

const groupLevel = groupingColumnNames.indexOf(row.groupedBy);
if (groupLevel > currentGroupLevel && !currentGroupExpanded) {
return acc;
}

currentGroupExpanded = expandedGroups.has(row.compoundKey);
currentGroupLevel = groupLevel;

acc.push(row);
return acc;
}, []);
};
Loading

0 comments on commit 4fb92d0

Please sign in to comment.