@deephaven/js-plugin-ag-grid
Version:
Deephaven AG Grid plugin
246 lines • 10.1 kB
JavaScript
import { TableUtils } from '@deephaven/jsapi-utils';
import { assertNotNull } from '@deephaven/utils';
import { getCellStyleFunction, TREE_NODE_KEY, } from './AgGridTableUtils';
export function isPivotColumnGroupContext(context) {
return (context === null || context === void 0 ? void 0 : context.snapshotIndex) != null;
}
/**
* Converts an array of group keys to a string representation.
* @param groupKeys The group keys to convert to a string.
* @returns A string representation of the group keys.
*/
export function toGroupKeyString(groupKeys) {
return groupKeys.filter(key => key != null).join('/');
}
/**
* Converts a group key string and a value source name to a value key string.
* @param groupKeyString The group key string.
* @param valueSourceName The value source name.
* @returns A value key string.
*/
export function toValueKeyString(groupKeyString, valueSourceName) {
return `${groupKeyString}/${valueSourceName}`;
}
/**
* Get the row group keys from the provided row sources and data.
* @param rowSources The row sources to extract keys from.
* @param data The data object containing the values.
* @returns An array of row group keys.
*/
export function getRowGroupKeys(rowSources, data) {
const rowGroupKeys = [];
for (let i = 0; i < rowSources.length; i += 1) {
const rowSource = rowSources[i];
if (data[rowSource.name] != null) {
rowGroupKeys.push(String(data[rowSource.name]));
}
}
return rowGroupKeys;
}
/**
* Finds the index of a row in the pivot table snapshot based on the provided row group keys.
* @param rows Rows from the pivot table snapshot.
* @param rowGroupKeys The row group keys to find the index for.
* @returns The index of the row, or null if not found.
*/
export function findRowIndex(rows, rowGroupKeys) {
for (let r = 0; r < rows.count; r += 1) {
const rowkeys = rows.getKeys(r);
const nonNullRowKeys = rowkeys.filter(key => key != null);
if (rowGroupKeys.length === nonNullRowKeys.length &&
rowGroupKeys.every((key, index) => key === nonNullRowKeys[index])) {
return r;
}
}
return null;
}
export function getHeaderName(columnKeys) {
for (let i = columnKeys.length - 1; i >= 0; i -= 1) {
const columnKey = columnKeys[i];
if (columnKey != null) {
return columnKey;
}
}
throw new Error('No non-null column key found');
}
export function makePendingColDef(groupId) {
return {
headerName: '...',
field: `${groupId}/...`,
colId: `${groupId}/...`,
columnGroupShow: 'open',
maxWidth: 30, // We don't need the pending column to be very wide
};
}
/**
* Get the column definition for a column with value sources in a pivot table.
* If only one value source is provided, it will return a simple column definition.
* If multiple value sources are provided, it will return a column group definition
* @param headerName Header name of the value source group
* @param columnKey Column key of the value source group
* @param valueSources Value sources for the pivot table
* @returns The pivot value source group definition
*/
export function makeColumnValuesColDef(headerName, columnKey, valueSources) {
if (valueSources.length === 0) {
throw new Error('No value sources provided');
}
const children = valueSources.map(valueSource => {
const dataType = TableUtils.getNormalizedType(valueSource.type);
return {
headerName: valueSource.name,
field: toValueKeyString(columnKey, valueSource.name),
colId: toValueKeyString(columnKey, valueSource.name),
cellDataType: dataType,
cellStyle: getCellStyleFunction(dataType),
};
});
if (children.length === 1) {
return Object.assign(Object.assign({}, children[0]), { headerName });
}
return {
headerName,
groupId: columnKey,
children,
};
}
/**
* Get the pivot result columns from the provided pivot dimension data. This tells AG Grid how to display the columns, including expandable/collapsible groups.
* @param columns The pivot dimension data representing the columns.
* @param valueSources The value sources for the pivot table.
* @returns An array of column definitions for the pivot result.
*/
export function getPivotResultColumns(columns, valueSources) {
const result = [];
// This is the current groups in progress. So we know which ones to push to.
const currentGroups = [];
function getCurrentChildren() {
var _a, _b;
return (_b = (_a = currentGroups[currentGroups.length - 1]) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : result;
}
function closeGroup() {
var _a, _b;
// This isn't a child, we can pop the last group
const currentGroup = currentGroups.pop();
assertNotNull(currentGroup);
// If there were no children added to this group yet, that means we haven't expanded it yet. Add a placeholder so AG Grid knows it can be expanded.
if (currentGroup.children.length === 0) {
currentGroup.children.push(makePendingColDef((_a = currentGroup.groupId) !== null && _a !== void 0 ? _a : ''));
}
// Also add the totals for this group
const totalsValueGroup = makeColumnValuesColDef(`${currentGroup.headerName} Totals`, (_b = currentGroup.groupId) !== null && _b !== void 0 ? _b : '', valueSources);
currentGroup.children.push(totalsValueGroup);
getCurrentChildren().push(currentGroup);
}
for (let c = 0; c < columns.count; c += 1) {
const columnKeys = columns.getKeys(c);
const columnKey = toGroupKeyString(columnKeys);
const headerName = getHeaderName(columnKeys);
while (currentGroups.length > 0 &&
!columnKey.startsWith(`${currentGroups[currentGroups.length - 1].groupId}/`)) {
closeGroup();
}
if (columns.hasChildren(c)) {
const context = {
snapshotIndex: columns.offset + c,
};
currentGroups.push({
headerName,
groupId: columnKey,
context,
columnGroupShow: 'open',
children: [],
});
}
else {
const columnValueGroup = makeColumnValuesColDef(headerName, columnKey, valueSources);
getCurrentChildren().push(Object.assign(Object.assign({}, columnValueGroup), {
// We only want these values to show when the parent is open
columnGroupShow: 'open' }));
}
}
while (currentGroups.length > 0) {
closeGroup();
}
// Add a root level totals column for each value source as well
for (let v = 0; v < valueSources.length; v += 1) {
const valueSource = valueSources[v];
const dataType = TableUtils.getNormalizedType(valueSource.type);
result.push({
headerName: `${valueSource.name} Totals`,
field: valueSource.name,
colId: valueSource.name,
cellDataType: dataType,
cellStyle: getCellStyleFunction(dataType),
});
}
return result;
}
export function extractSnapshotRow(snapshot, table, rowIndex) {
const rowKeys = snapshot.rows.getKeys(rowIndex);
const row = {};
for (let rowSourceIndex = 0; rowSourceIndex < table.rowSources.length; rowSourceIndex += 1) {
const rowSource = table.rowSources[rowSourceIndex];
const rowSourceKey = rowKeys[rowSourceIndex];
if (rowSourceKey != null) {
row[rowSource.name] = rowSourceKey;
}
}
const depth = snapshot.rows.getDepth(rowIndex);
row[TREE_NODE_KEY] = {
hasChildren: snapshot.rows.hasChildren(rowIndex),
isExpanded: snapshot.rows.isExpanded(rowIndex),
depth,
index: rowIndex,
};
for (let c = 0; c < snapshot.columns.count; c += 1) {
const columnKey = toGroupKeyString(snapshot.columns.getKeys(c));
for (let v = 0; v < table.valueSources.length; v += 1) {
const valueSource = table.valueSources[v];
const valueKey = toValueKeyString(columnKey, valueSource.name);
const value = snapshot.getValue(valueSource, rowIndex, snapshot.columns.offset + c);
row[valueKey] = value;
}
}
// Add the totals data
for (let v = 0; v < table.valueSources.length; v += 1) {
const valueSource = table.valueSources[v];
row[valueSource.name] = snapshot.rows.getTotal(rowIndex, valueSource);
}
return row;
}
export function extractTotalsRow(snapshot, table) {
const totalsRow = {};
totalsRow[TREE_NODE_KEY] = {
hasChildren: false,
isExpanded: false,
depth: 0,
index: snapshot.rows.totalCount,
};
for (let c = 0; c < snapshot.columns.count; c += 1) {
const columnKey = toGroupKeyString(snapshot.columns.getKeys(c));
for (let v = 0; v < table.valueSources.length; v += 1) {
const valueSource = table.valueSources[v];
const valueKey = toValueKeyString(columnKey, valueSource.name);
const value = snapshot.columns.getTotal(c, valueSource);
totalsRow[valueKey] = value;
}
}
// Grand totals values
for (let v = 0; v < table.valueSources.length; v += 1) {
const valueSource = table.valueSources[v];
totalsRow[valueSource.name] = snapshot.getGrandTotal(valueSource);
}
return totalsRow;
}
export function extractSnapshotRows(snapshot, table) {
const rows = {};
for (let rowIndex = 0; rowIndex < snapshot.rows.count; rowIndex += 1) {
const row = extractSnapshotRow(snapshot, table, snapshot.rows.offset + rowIndex);
rows[snapshot.rows.offset + rowIndex] = row;
}
// Need to push a row for totals as well
rows[snapshot.rows.totalCount] = extractTotalsRow(snapshot, table);
return rows;
}
//# sourceMappingURL=AgGridPivotUtils.js.map