@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
728 lines (727 loc) • 32.3 kB
JavaScript
import { ColumnApiModule, } from 'ag-grid-enterprise';
import { ACTION_COLUMN_TYPE, CALCULATED_COLUMN_TYPE, FDC3_COLUMN_TYPE, FREE_TEXT_COLUMN_TYPE, } from '../AdaptableState/Common/AdaptableColumn';
import { ADAPTABLE_FDC3_ACTION_COLUMN_FRIENDLY_NAME, } from '../Utilities/Constants/GeneralConstants';
import { createUuid } from '../AdaptableState/Uuid';
import ArrayExtensions from '../Utilities/Extensions/ArrayExtensions';
import * as ModuleConstants from '../Utilities/Constants/ModuleConstants';
import { ALL_AG_GRID_MODULES } from './agGridModules';
import { agGridDataTypeDefinitions, ALL_ADAPTABLE_DATA_TYPES } from './agGridDataTypeDefinitions';
// AG GRID obfuscates its internals, this is (currently) the best way to get hold of its internal services
const DANGER_AG_GRID_BEANS_MAP = {};
const getColumnApiModule = () => ColumnApiModule;
export class AgGridAdapter {
constructor(_adaptableInstance, config) {
this._adaptableInstance = _adaptableInstance;
const columnApiModuleReference = config?.getAgGridColumnApiModuleReference?.() ?? getColumnApiModule();
const ColumnDefFactory_Prototype = columnApiModuleReference?.beans?.[0]?.prototype;
if (!ColumnDefFactory_Prototype) {
console.error(`CRITICAL: could not get hold of AG Grid beans, this should never happen!`);
}
else {
const ColumnDefFactory_Prototye_preWireBeans = ColumnDefFactory_Prototype.preWireBeans;
ColumnDefFactory_Prototype.preWireBeans = function (beans) {
ColumnDefFactory_Prototye_preWireBeans?.apply(this, arguments);
const gridId = beans?.context?.getGridId();
if (!gridId) {
console.error('CRITICAL: No gridId found in beans, this should never happen!');
}
DANGER_AG_GRID_BEANS_MAP[gridId] = beans;
};
}
}
destroy() {
delete DANGER_AG_GRID_BEANS_MAP[this._agGridId];
this.initialGridOptions = null;
this.DANGER_gridApi_from_args = null;
this.DANGER_USE_GETTER_gridApi = null;
this.DANGER_updateGridOptionsMonkeyPatcher = null;
this._adaptableInstance = null;
}
get adaptableOptions() {
return this._adaptableInstance.adaptableOptions;
}
get adaptableApi() {
return this._adaptableInstance.api;
}
get logger() {
return this._adaptableInstance.logger;
}
get agGridOptionsService() {
return this._adaptableInstance.agGridOptionsService;
}
setAgGridId(agGridId) {
this._agGridId = agGridId;
}
setAgGridApi(gridApi) {
this.DANGER_USE_GETTER_gridApi = gridApi;
}
getAgGridApi(skipLogging) {
if (this.DANGER_USE_GETTER_gridApi) {
return this.DANGER_USE_GETTER_gridApi;
}
if (this.DANGER_gridApi_from_args) {
return this.DANGER_gridApi_from_args;
}
if (!skipLogging) {
console.error('AgGridApi is not available yet');
}
}
// #gridOpts_monkey_patch
// we need to intercept some of the GridOptions updates and refresh the Adaptable state
monkeyPatchingGridOptionsUpdates(agGridApi) {
const agGridOptionsService = this.DANGER_getPrivateAgGridBeans()?.gos;
if (!agGridOptionsService) {
return;
}
const agGridOptionsServicePrototype = Object.getPrototypeOf(agGridOptionsService);
const GridOptionsService_updateGridOptions = agGridOptionsServicePrototype.updateGridOptions;
const self = this;
this.DANGER_updateGridOptionsMonkeyPatcher = function ({ options, force, source = 'api', }) {
const passedColumnDefs = options.columnDefs;
if (passedColumnDefs) {
const colDefsWithSpecialColumns = self.getColumnDefinitionsInclSpecialColumns(passedColumnDefs);
const allDisplayedColIds = self
.getAgGridApi()
.getAllDisplayedColumns()
.map((col) => col.getColId());
// mark as hidden the colDefs of special columns which are not visible
self.patchColDefs(colDefsWithSpecialColumns, (colDef) => {
if (self.adaptableApi.columnApi.internalApi.isSpecialColumn(colDef.colId)) {
colDef.hide = !allDisplayedColIds.includes(colDef.colId);
}
});
options['columnDefs'] = colDefsWithSpecialColumns;
self.logger.info(`Added SpecialColumns on GridOptions.columnDefs update (source=${source})`);
}
// `context`
const passedContext = options.context;
if (passedContext) {
passedContext['__adaptable'] = self._adaptableInstance;
passedContext['adaptableApi'] = self.adaptableApi;
}
// we mutated the options array, so it's OK to use the 'arguments' object
GridOptionsService_updateGridOptions.apply(this, arguments);
};
agGridOptionsService.updateGridOptions = this.DANGER_updateGridOptionsMonkeyPatcher;
}
DANGER_getPrivateAgGridBeans() {
const beans = DANGER_AG_GRID_BEANS_MAP[this._agGridId];
if (!beans) {
this.logger.consoleError('Could not get hold of AgGridBeans! This is a critical error and will prevent Adaptable from working correctly.');
}
return beans;
}
DANGER_getLiveGridOptions() {
return this.DANGER_getPrivateAgGridBeans()?.gridOptions;
}
isAgGridModuleRegistered(moduleName) {
const agGridOptionsService = this.DANGER_getPrivateAgGridBeans()?.gos;
if (!agGridOptionsService) {
this.logger.consoleError('Could not get hold of GridOptionsService! This is a critical error and will prevent Adaptable from working correctly.');
return false;
}
return agGridOptionsService.isModuleRegistered(moduleName);
}
getAgGridRegisteredModules() {
const allModulesSet = ALL_AG_GRID_MODULES;
const registeredModules = [];
allModulesSet.forEach((module) => {
if (this.isAgGridModuleRegistered(module.moduleName)) {
registeredModules.push(module);
}
});
return registeredModules;
}
getAgGridRegisteredModuleNames() {
return this.getAgGridRegisteredModules().map((module) => module.moduleName);
}
getAgGridRootElement() {
return this.DANGER_getPrivateAgGridBeans()?.eGridDiv;
}
/**
* When AG Grid is rendered the first time, the AG GridApi is not yet set in the Adaptable context (as it's set only AFTER the grid is fully initialised)
* yet we need it when evaluating custom GridOptions properties on the first render.
* to handle this edge case, we try to extract the AG GridApi from the invocation arguments
*/
grabAgGridApiOnTheFly(args) {
if (this.DANGER_USE_GETTER_gridApi || this.DANGER_gridApi_from_args) {
return;
}
if (Array.isArray(args) &&
args[0] &&
typeof args[0].api === 'object' &&
// can't ise instanceof operator because gridApi is exported as interface
typeof args[0].api?.getGridId === 'function') {
this.DANGER_gridApi_from_args = args[0].api;
}
}
updateGridOptions(options) {
this.getAgGridApi()?.updateGridOptions(options);
}
getGridOption(key) {
return this.getAgGridApi()?.getGridOption(key);
}
setGridOption(key, value) {
this.getAgGridApi()?.setGridOption(key, value);
}
getUserGridOptionsProperty(propertyName) {
return this.agGridOptionsService.getUserGridOptionsProperty(propertyName);
}
updateColumnFilterActiveState() {
const filteredCols = new Set();
const columnFilters = this.adaptableApi.filterApi.columnFilterApi.getActiveColumnFilters();
columnFilters?.forEach?.((columnFilter) => {
if (this.adaptableApi.filterApi.columnFilterApi.isColumnFilterActive(columnFilter)) {
filteredCols.add(columnFilter.ColumnId);
}
});
const agGridApi = this.getAgGridApi();
(agGridApi.getColumns() || []).forEach((col) => {
col.filterActive = filteredCols.has(col.getColId());
});
}
getColumnDefinitionsInclSpecialColumns(agGridColDefs) {
const allColDefs = this.enhanceColDefsWithSpecialColumns(agGridColDefs ?? this.getAgGridApi().getColumnDefs());
return allColDefs;
}
enhanceColDefsWithSpecialColumns(agGridColDefs) {
this.assignColumnIdsToColDefs(agGridColDefs);
const specialColDefs = this.getSpecialColDefs();
const isSpecialColDef = (colDef) => {
const { type } = colDef;
const colTypes = Array.isArray(type) ? type : [type];
return colTypes.some((colType) => [
ACTION_COLUMN_TYPE,
CALCULATED_COLUMN_TYPE,
FREE_TEXT_COLUMN_TYPE,
FDC3_COLUMN_TYPE,
].includes(colType));
};
const processedSpecialColDefIds = [];
const mapColDefs = (colDefs) => {
return colDefs.map((colDef) => {
if (this._adaptableInstance.agGridColumnAdapter.isColGroupDef(colDef)) {
// if it's a group column, recursively map its children
colDef.children = mapColDefs(colDef.children);
return colDef;
}
else {
if (!isSpecialColDef(colDef)) {
// if it's not a special column, return it as is
// without a minWidth, columns in details grid are VERY wide
// so the line below fixes https://github.com/AdaptableTools/adaptable/issues/2559
return { minWidth: 10, ...colDef };
}
const newlyCreatedSpecialColDef = specialColDefs.find((specialColDef) => specialColDef.colId === colDef.colId);
if (newlyCreatedSpecialColDef) {
// if it's a special column and we have a special col def for it, return the special col def
processedSpecialColDefIds.push(colDef.colId);
// merge the user defined colDef with the special col def
// this way the user may provide some custom settings for the special col def (tooltip, etc)
const mergedColDef = {
// see above comment for minWidth
minWidth: 10,
...colDef,
...newlyCreatedSpecialColDef,
};
return mergedColDef;
}
else {
// otherwise, return the original col def
return colDef;
}
}
});
};
let resultColDefs = mapColDefs(agGridColDefs);
// check if there are any special colDefs that were not processed
// in that case, add them to the end of the colDefs
specialColDefs.forEach((specialColDef) => {
if (!processedSpecialColDefIds.includes(specialColDef.colId)) {
resultColDefs.push(specialColDef);
}
});
// remove special column that are no longer defined
resultColDefs = resultColDefs.filter((colDef) => {
if (isSpecialColDef(colDef)) {
// must be in specialColDefs
return specialColDefs.some((specialColDef) => specialColDef.colId === colDef.colId);
}
return true;
});
return resultColDefs;
}
getSpecialColDefs() {
const specialColDefs = [
...this.adaptableApi.calculatedColumnApi.internalApi.getColDefsForCalculatedColumns(),
...this.adaptableApi.actionColumnApi.internalApi.getColDefsForActionColumns(),
...this.adaptableApi.freeTextColumnApi.internalApi.getColDefsForFreeTextColumns(),
...this.adaptableApi.fdc3Api.internalApi.getFdc3ActionColDefs(),
];
this.assignColumnIdsToColDefs(specialColDefs);
return specialColDefs;
}
deriveSelectedCellInfoFromAgGrid() {
const selected = this.getAgGridApi().getCellRanges();
const columns = [];
const gridCells = [];
// we iterate for each ranges
selected.forEach((rangeSelection) => {
let shouldIncludeRange = true;
if (rangeSelection.startRow && rangeSelection.endRow) {
let isStartRowPin = rangeSelection.startRow.rowPinned != null;
let isEndRowPin = rangeSelection.endRow.rowPinned != null;
// Warn user if trying to select pinned rows and if only selecting them, stop
if (isStartRowPin) {
if (isEndRowPin) {
shouldIncludeRange = false;
}
this.logger.consoleWarn('Cannot select pinned rows in AG Grid.');
}
if (shouldIncludeRange) {
const y1 = Math.min(rangeSelection.startRow.rowIndex, rangeSelection.endRow.rowIndex);
const y2 = Math.max(rangeSelection.startRow.rowIndex, rangeSelection.endRow.rowIndex);
for (const column of rangeSelection.columns) {
if (column != null) {
const colId = column.getColId();
const selectedColumn = this.adaptableApi.columnApi.getColumnWithColumnId(colId);
if (selectedColumn && !columns.includes(selectedColumn)) {
columns.push(selectedColumn);
}
for (let rowIndex = y1; rowIndex <= y2; rowIndex++) {
const rowNode = this.getAgGridApi().getDisplayedRowAtIndex(rowIndex);
// we used NOT to return grouped rows but I think that was wrong - if someone wants to return them then that is up to them...
// we definitely dont return pinned rows as they cannot be selected
if (rowNode && !this.isPinnedRowNode(rowNode)) {
const selectedCell = this.adaptableApi.gridApi.getGridCellFromRowNode(rowNode, colId);
gridCells.push(selectedCell);
}
}
}
}
}
}
});
const selectedCellInfo = {
columns,
gridCells,
};
return selectedCellInfo;
}
deriveSelectedRowInfoFromAgGrid() {
const nodes = this.getAgGridApi().getSelectedNodes();
const selectedRows = [];
if (this.getAgGridApi().isPivotMode()) {
// dont perform row selection in pivot mode
return undefined;
}
if (ArrayExtensions.IsNotNullOrEmpty(nodes)) {
nodes.forEach((node) => {
const rowInfo = {
isMaster: !!(node.master != null && node.master == true),
isExpanded: !!(node.expanded != null && node.expanded == true),
isGroup: !!(node.group != null && node.group == true),
isSelected: true,
isDisplayed: node.displayed == true,
rowGroupLevel: node.level,
};
const gridRow = {
primaryKeyValue: this.adaptableApi.gridApi.getPrimaryKeyValueForRowNode(node),
rowData: node.data,
rowNode: node,
rowInfo,
};
selectedRows.push(gridRow);
});
}
return { gridRows: selectedRows };
}
isPinnedRowNode(rowNode) {
if (!rowNode) {
return false;
}
if (rowNode.isRowPinned()) {
return true;
}
return false;
}
createAdaptableColumnFromAgGridColumn(agGridColumn, colsToGroups) {
const colId = agGridColumn.getColId();
const colDef = agGridColumn.getColDef();
const { columnApi } = this.adaptableApi;
const ColumnId = colId;
const pkColumn = this.adaptableOptions.primaryKey;
const ColumnGroup = colsToGroups?.[ColumnId];
const isRealColumnGroup = ColumnGroup
? ColumnGroup.columnGroupId !== ColumnGroup.friendlyName
: false;
const isFdc3MainActionColumn = this.adaptableApi.fdc3Api.internalApi.isFdc3MainActionColumn(colId);
let friendlyName;
const isGeneratedRowGroupColumn = columnApi.isAutoRowGroupColumn(ColumnId);
const isGeneratedPivotResultColumn = columnApi.isPivotResultColumn(ColumnId) && !agGridColumn.isPrimary();
const colExists = columnApi.doesColumnExist(ColumnId) ||
isGeneratedRowGroupColumn ||
isGeneratedPivotResultColumn;
if (colExists) {
friendlyName = columnApi.getFriendlyNameForColumnId(ColumnId);
}
else {
const displayName = this.getAgGridApi().getDisplayNameForColumn(agGridColumn, 'header');
const columnFriendlyName = this.adaptableOptions.columnOptions.columnFriendlyName;
const customFriendlyName = typeof columnFriendlyName === 'function'
? columnFriendlyName({
colId: colId,
agColumn: agGridColumn,
columnGroup: isRealColumnGroup ? ColumnGroup : undefined,
displayName: displayName,
})
: null;
friendlyName =
customFriendlyName ??
(isFdc3MainActionColumn ? ADAPTABLE_FDC3_ACTION_COLUMN_FRIENDLY_NAME : displayName);
// Add Column Group;s friendlyname to the Column Friendly Name if its in a legitimate Column Group
if (this.adaptableOptions.columnOptions.addColumnGroupToColumnFriendlyName &&
ColumnGroup &&
ColumnGroup.columnGroupId !== ColumnGroup.friendlyName) {
friendlyName += ' [' + ColumnGroup.friendlyName + ']';
}
}
const dataType = isGeneratedPivotResultColumn
? 'number'
: this.deriveAdaptableColumnDataType(agGridColumn, false);
const isTreeColumn = this.isTreeColumn(isGeneratedRowGroupColumn);
const visible = agGridColumn.isVisible();
const alwaysHidden = !visible &&
!isTreeColumn &&
colDef.lockVisible === true &&
colDef.suppressColumnsToolPanel === true &&
colDef.suppressFiltersToolPanel === true;
const isGenerated = isGeneratedRowGroupColumn || isGeneratedPivotResultColumn;
const abColumn = {
Uuid: createUuid(),
isTreeColumn,
columnId: ColumnId,
field: colDef.field,
friendlyName: friendlyName,
isPrimaryKey: ColumnId === pkColumn,
dataType: dataType,
visible,
alwaysHidden,
readOnly: this.isColumnReadonly(colDef),
columnGroup: ColumnGroup,
fieldOnly: isGenerated ? false : this.isColumnFieldonly(colDef),
sortable: isGenerated ? false : this.isColumnSortable(colDef),
filterable: this.isColumnFilterable(colDef),
queryable: true, // override later when we have the column object
exportable: true, // override later when we have the column object
groupable: isGenerated ? false : this.isColumnRowGroupable(colDef),
pivotable: isGenerated ? false : this.isColumnPivotable(colDef),
aggregatable: isGenerated ? false : this.isColumnAggregetable(colDef),
availableAggregationFunctions: null,
aggregationFunction: null,
moveable: this.isColumnMoveable(colDef),
hideable: this.isColumnHideable(colDef),
isGrouped: isGenerated ? false : this.isColumnRowGrouped(colDef),
isGeneratedRowGroupColumn,
isGeneratedPivotResultColumn,
isFixed: this.isColumnFixed(colDef),
pinned: this.getColumnPinnedPosition(colDef),
columnTypes: this.getColumnTypes(colDef),
isSparkline: this.isColumnSparkline(colDef),
isCalculatedColumn: this.isCalculatedColumn(colDef),
isFreeTextColumn: this.isFreeTextColumn(colDef),
isActionColumn: this.isActionColumn(colDef),
};
abColumn.queryable = this.isColumnQueryable(abColumn);
abColumn.exportable = this.isColumnExportable(abColumn);
if (abColumn.aggregatable) {
abColumn.availableAggregationFunctions = this.getColumnAggregationFunctions(colDef);
if (typeof colDef.aggFunc === 'string') {
abColumn.aggregationFunction = colDef.aggFunc;
}
}
return abColumn;
}
deriveAdaptableColumnDataType(agColumn, logWarning = true) {
// Some columns can have no ID or Title. we return string as a consequence but it needs testing
if (!agColumn) {
this.logger.warn(`Column is undefined, returning 'text' for Type`);
return 'text';
}
const colDefType = [].concat(agColumn.getColDef()?.type || []).filter(Boolean);
const skippedSpecialCols = ['actionColumn', 'fdc3Column'];
if (skippedSpecialCols.some((specialColType) => colDefType.includes(specialColType))) {
return 'unknown';
}
let dataType = 'unknown';
// get the column type if already in store (and not unknown)
const existingColumn = this.adaptableApi.columnApi.getColumnWithColumnId(agColumn.getId(), logWarning);
if (existingColumn && existingColumn.dataType !== 'unknown') {
return existingColumn.dataType;
}
// check for colDef dataType
const colDefDataType = agColumn.getColDef().cellDataType;
if (typeof colDefDataType === 'string' && ALL_ADAPTABLE_DATA_TYPES.includes(colDefDataType)) {
return colDefDataType;
}
// see #agGridDataTypeDefinitions
// theoretically, if AG Grid was not able to infer the type, we should not be able to either
// but we give it a try, AG Grid is limited when the colDef has a valueGetter, valueParser, etc
// see https://www.ag-grid.com/javascript-data-grid/cell-data-types/#inferring-data-types
let row = this.getAgGridApi().getDisplayedRowAtIndex(0);
if (row == null) {
// possible that there will be no data.
this.logger.consoleError(`No data in grid, returning type "unknown" for Column: "${agColumn.getColId()}". This will impact several Adaptable features, such as Filters and ColumnFormats.`);
return 'unknown';
}
// if it's a group we need the content of the group
if (row.group) {
const childNodes = row.childrenAfterGroup;
if (ArrayExtensions.IsNullOrEmpty(childNodes)) {
this.logger.consoleError(`No data in grid, returning type "unknown" for Column: "${agColumn.getColId()}". This will impact several Adaptable features, such as Filters and ColumnFormats.`);
return 'unknown';
}
row = childNodes[0];
}
const value = this._agGridApi_getValue(agColumn, row);
switch (typeof value) {
case 'string':
dataType = 'text';
break;
case 'number':
dataType = 'number';
break;
case 'boolean':
dataType = 'boolean';
break;
case 'object':
dataType = 'object';
break;
}
if (value instanceof Date) {
dataType = 'date';
}
else if (Array.isArray(value)) {
const arrayDataType = ALL_ADAPTABLE_DATA_TYPES.find((arrayType) => {
const dataTypeDefinition = agGridDataTypeDefinitions[arrayType];
const dataTypeMatching = dataTypeDefinition?.dataTypeMatcher?.(value);
return dataTypeMatching;
});
if (arrayDataType) {
dataType = arrayDataType;
}
}
this.logger.consoleWarn(`No defined type for column '${agColumn.getColId()}'. Defaulting to type of first row value: ${dataType}`);
return dataType;
}
isColumnReadonly(colDef) {
if (!colDef) {
return true;
}
// if the column has conditional/dynamic editability, we assume some rows may be editable
if (typeof colDef.editable === 'function') {
return false;
}
// otherwise we evaluate the colDef.editable property (columns are NOT editable by default)
return !colDef.editable;
}
isColumnFieldonly(colDef) {
if (colDef.hide == true && colDef.initialHide == true && colDef.lockVisible == true) {
return true;
}
return false;
}
isColumnSortable(colDef) {
if (colDef && colDef.sortable != null) {
return colDef.sortable;
}
return false;
}
isColumnRowGroupable(colDef) {
if (colDef && colDef.enableRowGroup != null) {
return colDef.enableRowGroup;
}
return false;
}
isColumnPivotable(colDef) {
if (colDef && colDef.enablePivot != null) {
return colDef.enablePivot;
}
return false;
}
isColumnAggregetable(colDef) {
if (colDef && colDef.enableValue != null) {
return colDef.enableValue;
}
return false;
}
getColumnAggregationFunctions(colDef) {
return colDef.allowedAggFuncs || ['sum', 'min', 'max', 'count', 'avg', 'first', 'last']; // those are the default fns aggrid supports out-of-the-box
}
isTreeColumn(isGeneratedRowGroupColumn) {
return this.adaptableApi.gridApi.isTreeDataGrid() ? isGeneratedRowGroupColumn : false;
}
isColumnMoveable(colDef) {
if (!colDef) {
return false;
}
if (colDef.suppressMovable != null && colDef.suppressMovable == true) {
return false;
}
if (this.isColumnFixed(colDef)) {
return false;
}
return true;
}
isColumnQueryable(abColumn) {
return (
// !this.adaptableApi.columnApi.isPivotResultColumn(abColumn.columnId) &&
(this.adaptableApi.expressionApi.isColumnQueryable(abColumn))
);
}
isColumnExportable(abColumn) {
return this.adaptableApi.exportApi.isColumnExportable(abColumn);
}
isColumnHideable(colDef) {
if (!colDef) {
return false;
}
if (this.adaptableApi.gridApi.isTreeDataGrid() &&
this.adaptableApi.columnApi.isAutoRowGroupColumn(colDef.colId)) {
return false;
}
if (colDef.lockVisible != null && colDef.lockVisible == true) {
return false;
}
return true;
}
isCalculatedColumn(colDef) {
return (this.adaptableApi.calculatedColumnApi.getCalculatedColumnForColumnId(colDef.colId) != null);
}
isFreeTextColumn(colDef) {
return this.adaptableApi.freeTextColumnApi.getFreeTextColumnForColumnId(colDef.colId) != null;
}
isActionColumn(colDef) {
return this.adaptableApi.actionColumnApi.getActionColumnForColumnId(colDef.colId) != null;
}
isColumnFilterable(colDef) {
// follow agGrid logic which is that ONLY filterable if explicitly set
if (this.adaptableApi.entitlementApi.getEntitlementAccessLevelForModule(ModuleConstants.ColumnFilterModuleId) == 'Hidden') {
return false;
}
return colDef != null && colDef.filter != null && colDef.filter != false;
}
getColumnTypes(colDef) {
if (!colDef.type) {
return [];
}
const allTypes = typeof colDef.type === 'string' ? [colDef.type] : colDef.type;
return allTypes;
}
getColumnPinnedPosition(colDef) {
return colDef.pinned
? colDef.pinned === 'left' || colDef.pinned === true
? 'left'
: 'right'
: false;
}
// used for AG Grid when the column is FixedPinned, meaning it should never be unpinned
isColumnFixed(colDef) {
if (!colDef) {
return false;
}
if (colDef.lockPosition != null && colDef.lockPosition == true) {
return true;
}
if (colDef.lockPinned != null && colDef.lockPinned == true) {
return true;
}
return false;
}
isColumnRowGrouped(colDef) {
if (!colDef) {
return false;
}
if (colDef.rowGroup != null && colDef.rowGroup == true) {
return true;
}
if (colDef.rowGroupIndex != null) {
return true;
}
return false;
}
isColumnSparkline(colDef) {
// see https://www.ag-grid.com/javascript-data-grid/sparklines-overview/#enabling-sparklines
return colDef?.cellRenderer === 'agSparklineCellRenderer';
}
isVisibleNode(rowNode) {
const foundNode = this.getAgGridApi()
?.getRenderedNodes()
.find((n) => n.id == rowNode.id);
return foundNode != null;
}
getFlattenedColDefs(colDefs = []) {
const flattenedColDefs = [];
colDefs.forEach((colDef) => {
if (colDef.children) {
flattenedColDefs.push(...this.getFlattenedColDefs(colDef.children));
}
else {
flattenedColDefs.push(colDef);
}
});
this.assignColumnIdsToColDefs(flattenedColDefs);
return flattenedColDefs;
}
/**
* Mutates the colDefs to ensure that each column has a colId
*/
assignColumnIdsToColDefs(colDefs = []) {
const assignColId = (colDef) => {
if (!colDef) {
return;
}
if (colDef.field && !colDef.colId) {
colDef.colId = colDef.field;
}
if (!colDef.colId) {
this.logger.warn('A column is missing the colId - please check ', colDef, 'Either pass a "field" property or a "colId" property.');
}
};
this.patchColDefs(colDefs, assignColId);
}
patchColDefs(colDefs = [], patchFn) {
const applyPatch = (colDef) => {
if (!colDef) {
return;
}
if (!colDef.children) {
patchFn(colDef);
}
if (colDef.children) {
colDef.children.forEach((childColDef) => applyPatch(childColDef));
}
};
colDefs.forEach((colDef) => applyPatch(colDef));
}
traverseColDefs(colDefs, modifyFn) {
const applyModification = (colDef) => {
if ('children' in colDef) {
const updatedChildren = colDef.children.map(applyModification).filter(Boolean);
return { ...colDef, children: updatedChildren };
}
else {
return modifyFn(colDef);
}
};
return colDefs.map(applyModification).filter(Boolean);
}
getDefaultColumnDefinition() {
// for early init phase, gridApi might not be ready yet
return this.getAgGridApi(true)?.getGridOption('defaultColDef') ?? {};
}
_agGridApi_getValue(colKey, rowNode, gridApi) {
gridApi = gridApi || this.getAgGridApi();
return gridApi.getCellValue({ colKey, rowNode });
}
}