Skip to content

Commit 04015c5

Browse files
committed
feat(demo): implement server-side grouping with aggregations
- Add server-side grouping logic with aggregations in data-generator.js - Create helper functions for group row creation and hierarchical grouping - Pass rowGroupCols and groupKeys from client to server - Enable row grouping UI in ServerSideDemo component - Configure autoGroupColumnDef for proper group display - Support multi-level grouping with drill-down capabilities Demo-only branch - not intended for merge
1 parent 3b1a115 commit 04015c5

File tree

2 files changed

+173
-14
lines changed

2 files changed

+173
-14
lines changed

api/data-generator.js

Lines changed: 146 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,141 @@ function applySearchText(data, searchText) {
229229
});
230230
}
231231

232+
// Helper function to create group rows with aggregations
233+
function createGroupRow(groupKey, groupValue, children, level, groupColumns) {
234+
// Calculate aggregations for the group
235+
const totalValue = children.reduce(
236+
(sum, child) => sum + (child.value || 0),
237+
0,
238+
);
239+
const totalAmountDelivered = children.reduce(
240+
(sum, child) => sum + (child.amountDelivered || 0),
241+
0,
242+
);
243+
const avgPercentDelivered =
244+
children.length > 0
245+
? children.reduce(
246+
(sum, child) => sum + (child.percentDelivered || 0),
247+
0,
248+
) / children.length
249+
: 0;
250+
const totalEstimatedHours = children.reduce(
251+
(sum, child) => sum + (child.estimatedHours || 0),
252+
0,
253+
);
254+
const totalActualHours = children.reduce(
255+
(sum, child) => sum + (child.actualHours || 0),
256+
0,
257+
);
258+
259+
const groupRow = {
260+
// AG Grid group row properties
261+
group: true,
262+
groupKey: groupKey || "",
263+
264+
// Aggregated values
265+
value: totalValue,
266+
amountDelivered: totalAmountDelivered,
267+
remaining: totalValue - totalAmountDelivered,
268+
percentDelivered: Math.round(avgPercentDelivered),
269+
estimatedHours: totalEstimatedHours,
270+
actualHours: totalActualHours,
271+
272+
// Group metadata
273+
childCount: children.length,
274+
expanded: false,
275+
level: level,
276+
};
277+
278+
// Add the group field dynamically if we have valid column info
279+
if (groupColumns && groupColumns[level]) {
280+
groupRow[groupColumns[level]] = groupValue;
281+
}
282+
283+
return groupRow;
284+
}
285+
286+
// Function to perform server-side grouping
287+
function performGrouping(data, rowGroupCols, groupKeys) {
288+
// Normalize rowGroupCols - it might be an array of objects or strings
289+
const groupColumns = Array.isArray(rowGroupCols)
290+
? rowGroupCols.map((col) =>
291+
typeof col === "string" ? col : col.field || col.id,
292+
)
293+
: [];
294+
295+
if (groupColumns.length === 0) {
296+
return data; // No grouping requested
297+
}
298+
299+
// If we have group keys, we're fetching children of a specific group
300+
if (groupKeys && groupKeys.length > 0) {
301+
// Filter data to match all group keys
302+
let filteredData = data;
303+
for (let i = 0; i < groupKeys.length; i++) {
304+
const groupCol = groupColumns[i];
305+
const groupValue = groupKeys[i];
306+
filteredData = filteredData.filter((row) => row[groupCol] === groupValue);
307+
}
308+
309+
// If we've reached the deepest level, return leaf nodes
310+
if (groupKeys.length === groupColumns.length) {
311+
return filteredData;
312+
}
313+
314+
// Otherwise, group by the next column
315+
const nextGroupCol = groupColumns[groupKeys.length];
316+
const groups = {};
317+
318+
filteredData.forEach((row) => {
319+
const groupValue = row[nextGroupCol];
320+
if (!groups[groupValue]) {
321+
groups[groupValue] = [];
322+
}
323+
groups[groupValue].push(row);
324+
});
325+
326+
// Create group rows
327+
const groupRows = [];
328+
Object.entries(groups).forEach(([groupValue, children]) => {
329+
const groupKey = [...groupKeys, groupValue].join("|");
330+
groupRows.push(
331+
createGroupRow(
332+
groupKey,
333+
groupValue,
334+
children,
335+
groupKeys.length,
336+
groupColumns,
337+
),
338+
);
339+
});
340+
341+
return groupRows;
342+
}
343+
344+
// Top level grouping - group by first column
345+
const firstGroupCol = groupColumns[0];
346+
const groups = {};
347+
348+
data.forEach((row) => {
349+
const groupValue = row[firstGroupCol];
350+
if (!groups[groupValue]) {
351+
groups[groupValue] = [];
352+
}
353+
groups[groupValue].push(row);
354+
});
355+
356+
// Create top-level group rows
357+
const groupRows = [];
358+
Object.entries(groups).forEach(([groupValue, children]) => {
359+
groupRows.push(
360+
createGroupRow(groupValue, groupValue, children, 0, groupColumns),
361+
);
362+
});
363+
364+
return groupRows;
365+
}
366+
232367
// Main function to process data request
233368
export function processDataRequest({
234369
startRow = 0,
@@ -248,21 +383,21 @@ export function processDataRequest({
248383
// Apply filters
249384
data = applyFilters(data, filterModel);
250385

251-
// Apply sorting
252-
data = applySorting(data, sortModel);
253-
254386
// Handle row grouping if enabled
255387
if (rowGroupCols && rowGroupCols.length > 0) {
256-
// TODO: Implement proper grouping logic
257-
// For now, just return flat data
258-
console.log(
259-
"Row grouping requested but not fully implemented:",
260-
rowGroupCols,
261-
groupKeys,
262-
);
388+
// Perform server-side grouping with aggregations
389+
data = performGrouping(data, rowGroupCols, groupKeys);
390+
391+
// Apply sorting to grouped data
392+
if (sortModel && sortModel.length > 0) {
393+
data = applySorting(data, sortModel);
394+
}
395+
} else {
396+
// Apply sorting to flat data
397+
data = applySorting(data, sortModel);
263398
}
264399

265-
// Get total after filtering
400+
// Get total after filtering and grouping
266401
const totalRows = data.length;
267402

268403
// Apply pagination

src/demo/components/ServerSideDemo.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ export const ServerSideDemo: React.FC = () => {
182182
filterModel: params.request.filterModel,
183183
sortModel: params.request.sortModel,
184184
searchText: searchTextRef.current,
185+
// Pass grouping information for server-side grouping
186+
rowGroupCols: params.request.rowGroupCols,
187+
groupKeys: params.request.groupKeys,
185188
}),
186189
});
187190

@@ -255,12 +258,18 @@ export const ServerSideDemo: React.FC = () => {
255258
</svg>
256259
</button>
257260
<h3 className="text-blue-400 font-semibold mb-2">
258-
🚀 Server-Side Row Model Demo
261+
🚀 Server-Side Row Model Demo with Grouping
259262
</h3>
260263
<p className="text-gray-300 text-sm pr-8">
261264
This demo uses AG Grid's Server-Side Row Model with a real API
262-
backend. Data is fetched on-demand as you scroll, filter, and sort.
263-
The API endpoint is{" "}
265+
backend. Data is fetched on-demand as you scroll, filter, sort, and
266+
group.
267+
<strong className="text-blue-300">
268+
{" "}
269+
Server-side grouping with aggregations is now enabled!
270+
</strong>
271+
Drag columns to the grouping panel above to see server-calculated
272+
aggregations. The API endpoint is{" "}
264273
<code className="bg-gray-800 px-2 py-1 rounded text-xs">
265274
{apiUrl}/tasks
266275
</code>
@@ -329,6 +338,8 @@ export const ServerSideDemo: React.FC = () => {
329338
columnDefs={columnDefs}
330339
defaultColDef={defaultColDef}
331340
rowModelType="serverSide"
341+
serverSideEnableClientSideSort={false}
342+
serverSideOnlyRefreshFilteredGroups={true}
332343
cacheBlockSize={100}
333344
maxBlocksInCache={10}
334345
onGridReady={onGridReady}
@@ -345,6 +356,19 @@ export const ServerSideDemo: React.FC = () => {
345356
sideBar={sideBarConfig}
346357
statusBar={statusBarConfig}
347358
domLayout="normal"
359+
// Enable row grouping
360+
rowGroupPanelShow="always"
361+
suppressAggFuncInHeader={true}
362+
groupDisplayType="singleColumn"
363+
autoGroupColumnDef={{
364+
headerName: "Group",
365+
minWidth: 220,
366+
cellRendererParams: {
367+
suppressCount: false,
368+
checkbox: false,
369+
},
370+
filter: false,
371+
}}
348372
pinnedBottomRowData={
349373
aggregations
350374
? [

0 commit comments

Comments
 (0)