Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 146 additions & 11 deletions api/data-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,141 @@ function applySearchText(data, searchText) {
});
}

// Helper function to create group rows with aggregations
function createGroupRow(groupKey, groupValue, children, level, groupColumns) {
// Calculate aggregations for the group
const totalValue = children.reduce(
(sum, child) => sum + (child.value || 0),
0,
);
const totalAmountDelivered = children.reduce(
(sum, child) => sum + (child.amountDelivered || 0),
0,
);
const avgPercentDelivered =
children.length > 0
? children.reduce(
(sum, child) => sum + (child.percentDelivered || 0),
0,
) / children.length
: 0;
const totalEstimatedHours = children.reduce(
(sum, child) => sum + (child.estimatedHours || 0),
0,
);
const totalActualHours = children.reduce(
(sum, child) => sum + (child.actualHours || 0),
0,
);

const groupRow = {
// AG Grid group row properties
group: true,
groupKey: groupKey || "",

// Aggregated values
value: totalValue,
amountDelivered: totalAmountDelivered,
remaining: totalValue - totalAmountDelivered,
percentDelivered: Math.round(avgPercentDelivered),
estimatedHours: totalEstimatedHours,
actualHours: totalActualHours,

// Group metadata
childCount: children.length,
expanded: false,
level: level,
};

// Add the group field dynamically if we have valid column info
if (groupColumns && groupColumns[level]) {
groupRow[groupColumns[level]] = groupValue;
}

return groupRow;
}

// Function to perform server-side grouping
function performGrouping(data, rowGroupCols, groupKeys) {
// Normalize rowGroupCols - it might be an array of objects or strings
const groupColumns = Array.isArray(rowGroupCols)
? rowGroupCols.map((col) =>
typeof col === "string" ? col : col.field || col.id,
)
: [];

if (groupColumns.length === 0) {
return data; // No grouping requested
}

// If we have group keys, we're fetching children of a specific group
if (groupKeys && groupKeys.length > 0) {
// Filter data to match all group keys
let filteredData = data;
for (let i = 0; i < groupKeys.length; i++) {
const groupCol = groupColumns[i];
const groupValue = groupKeys[i];
filteredData = filteredData.filter((row) => row[groupCol] === groupValue);
}

// If we've reached the deepest level, return leaf nodes
if (groupKeys.length === groupColumns.length) {
return filteredData;
}

// Otherwise, group by the next column
const nextGroupCol = groupColumns[groupKeys.length];
const groups = {};

filteredData.forEach((row) => {
const groupValue = row[nextGroupCol];
if (!groups[groupValue]) {
groups[groupValue] = [];
}
groups[groupValue].push(row);
});

// Create group rows
const groupRows = [];
Object.entries(groups).forEach(([groupValue, children]) => {
const groupKey = [...groupKeys, groupValue].join("|");
groupRows.push(
createGroupRow(
groupKey,
groupValue,
children,
groupKeys.length,
groupColumns,
),
);
});

return groupRows;
}

// Top level grouping - group by first column
const firstGroupCol = groupColumns[0];
const groups = {};

data.forEach((row) => {
const groupValue = row[firstGroupCol];
if (!groups[groupValue]) {
groups[groupValue] = [];
}
groups[groupValue].push(row);
});

// Create top-level group rows
const groupRows = [];
Object.entries(groups).forEach(([groupValue, children]) => {
groupRows.push(
createGroupRow(groupValue, groupValue, children, 0, groupColumns),
);
});

return groupRows;
}

// Main function to process data request
export function processDataRequest({
startRow = 0,
Expand All @@ -248,21 +383,21 @@ export function processDataRequest({
// Apply filters
data = applyFilters(data, filterModel);

// Apply sorting
data = applySorting(data, sortModel);

// Handle row grouping if enabled
if (rowGroupCols && rowGroupCols.length > 0) {
// TODO: Implement proper grouping logic
// For now, just return flat data
console.log(
"Row grouping requested but not fully implemented:",
rowGroupCols,
groupKeys,
);
// Perform server-side grouping with aggregations
data = performGrouping(data, rowGroupCols, groupKeys);

// Apply sorting to grouped data
if (sortModel && sortModel.length > 0) {
data = applySorting(data, sortModel);
}
} else {
// Apply sorting to flat data
data = applySorting(data, sortModel);
}

// Get total after filtering
// Get total after filtering and grouping
const totalRows = data.length;

// Apply pagination
Expand Down
30 changes: 27 additions & 3 deletions src/demo/components/ServerSideDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ export const ServerSideDemo: React.FC = () => {
filterModel: params.request.filterModel,
sortModel: params.request.sortModel,
searchText: searchTextRef.current,
// Pass grouping information for server-side grouping
rowGroupCols: params.request.rowGroupCols,
groupKeys: params.request.groupKeys,
}),
});

Expand Down Expand Up @@ -255,12 +258,18 @@ export const ServerSideDemo: React.FC = () => {
</svg>
</button>
<h3 className="text-blue-400 font-semibold mb-2">
🚀 Server-Side Row Model Demo
🚀 Server-Side Row Model Demo with Grouping
</h3>
<p className="text-gray-300 text-sm pr-8">
This demo uses AG Grid's Server-Side Row Model with a real API
backend. Data is fetched on-demand as you scroll, filter, and sort.
The API endpoint is{" "}
backend. Data is fetched on-demand as you scroll, filter, sort, and
group.
<strong className="text-blue-300">
{" "}
Server-side grouping with aggregations is now enabled!
</strong>
Drag columns to the grouping panel above to see server-calculated
aggregations. The API endpoint is{" "}
<code className="bg-gray-800 px-2 py-1 rounded text-xs">
{apiUrl}/tasks
</code>
Expand Down Expand Up @@ -329,6 +338,8 @@ export const ServerSideDemo: React.FC = () => {
columnDefs={columnDefs}
defaultColDef={defaultColDef}
rowModelType="serverSide"
serverSideEnableClientSideSort={false}
serverSideOnlyRefreshFilteredGroups={true}
cacheBlockSize={100}
maxBlocksInCache={10}
onGridReady={onGridReady}
Expand All @@ -345,6 +356,19 @@ export const ServerSideDemo: React.FC = () => {
sideBar={sideBarConfig}
statusBar={statusBarConfig}
domLayout="normal"
// Enable row grouping
rowGroupPanelShow="always"
suppressAggFuncInHeader={true}
groupDisplayType="singleColumn"
autoGroupColumnDef={{
headerName: "Group",
minWidth: 220,
cellRendererParams: {
suppressCount: false,
checkbox: false,
},
filter: false,
}}
pinnedBottomRowData={
aggregations
? [
Expand Down
Loading