@adaptabletools/adaptable
Version:
Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
998 lines (997 loc) • 68.7 kB
JavaScript
import { kebabCase } from '../Utilities/Extensions/StringExtensions';
import { resolveDisplayFormat } from '../AdaptableState/Common/AdaptableFormatPresets';
import { merge } from '../Utilities/Extensions/ObjectExtensions';
import { resolveSparklineOptionsForRender } from '../Utilities/Helpers/StyledColumns/SparklineStyleHelper';
import { hasBarStyleCellTextConfigured } from '../Utilities/Helpers/StyledColumns/BarStylesHelper';
import { convertAdaptableStyleToCSS, getAutoContrastTextColor, getVariableColor, hasCellBoxStyle, hasCellFontStyle, normalizeStyleForAgGrid, } from '../Utilities/Helpers/StyleHelper';
import StringExtensions from '../Utilities/Extensions/StringExtensions';
import { ACTION_COLUMN_TYPE, CALCULATED_COLUMN_TYPE, FDC3_COLUMN_TYPE, FREE_TEXT_COLUMN_TYPE, } from '../AdaptableState/Common/AdaptableColumn';
import tinycolor from 'tinycolor2';
import UIHelper from '../View/UIHelper';
import { getPercentBarRendererForColumn } from './cellRenderers/PercentBarRenderer';
import { getBadgeRendererForColumn } from './cellRenderers/BadgeRenderer';
import { getBulletChartRendererForColumn } from './cellRenderers/BulletChartRenderer';
import { getRangeBarRendererForColumn } from './cellRenderers/RangeBarRenderer';
import { getRatingRendererForColumn } from './cellRenderers/RatingRenderer';
import { shouldRenderStyledColumnOnRow } from '../Utilities/Helpers/StyledColumns/StyledColumnHelper';
import { findIconStyleMappingForValue, getIconRendererForColumn, } from './cellRenderers/IconRenderer';
import { clamp } from '../Utilities/Extensions/NumberExtensions';
import { getRuleAlertProperties } from '../Utilities/Helpers/Scheduling/ScheduledAlertHelper';
import { isNegativeZeroCentredBand, expandGradientCellRanges, gradientStyleRangeLookupValueType, DEFAULT_GRADIENT_MIN_ALPHA, DEFAULT_GRADIENT_MAX_ALPHA, } from '../Utilities/Helpers/StyledColumns/GradientStyleHelper';
import { AdaptableNumberEditor, AdaptableReactNumberEditor } from './editors/AdaptableNumberEditor';
import { AdaptableDateEditor, AdaptableReactDateEditor } from './editors/AdaptableDateEditor';
import { AgGridExportAdapter } from './AgGridExportAdapter';
import { AdaptableHelper } from '../Utilities/Helpers/AdaptableHelper';
import { isProvidedByAdaptable } from '../Utilities/adaptableOverrideCheck';
import { AdaptableFilterHandler } from './AdaptableFilterHandler';
import { AgGridFilterAdapterFactory } from './AgGridFilterAdapter';
import { AgGridFloatingFilterAdapterFactory } from './AgGridFloatingFilterAdapter';
import { errorOnce } from './AdaptableLogger';
import { isUnsupportedColumnDataTypeForIconStyle } from '../Utilities/Helpers/StyledColumns/IconStyleHelper';
import { isWeightedAverageAggFuncName, } from '../AdaptableState/Common/AggregationColumns';
const FONT_CSS_KEYS = [
'color',
'fontWeight',
'fontStyle',
'fontSize',
'textDecoration',
'textAlign',
];
const CELL_BOX_CSS_KEYS = [
'backgroundColor',
'borderColor',
'borderRadius',
];
const stripCssKeys = (style, keys) => {
const out = { ...style };
keys.forEach((k) => delete out[k]);
return out;
};
const stripFontCssKeys = (style) => stripCssKeys(style, FONT_CSS_KEYS);
const stripCellBoxCssKeys = (style) => stripCssKeys(style, CELL_BOX_CSS_KEYS);
export function getEditorForColumnDataType(columnDataType, variant) {
if (columnDataType === 'number') {
return variant === 'react' ? AdaptableReactNumberEditor : AdaptableNumberEditor;
}
if (columnDataType === 'date') {
return variant === 'react' ? AdaptableReactDateEditor : AdaptableDateEditor;
}
}
export class AgGridColumnAdapter {
adaptableInstance;
colDefPropertyCache;
constructor(adaptableInstance) {
this.adaptableInstance = adaptableInstance;
this.colDefPropertyCache = new Map();
}
getVariant() {
return this.adaptableInstance.variant;
}
destroy() {
this.adaptableInstance = null;
this.colDefPropertyCache.clear();
this.colDefPropertyCache = null;
}
get adaptableApi() {
return this.adaptableInstance.api;
}
get adaptableOptions() {
return this.adaptableInstance.adaptableOptions;
}
get agGridApi() {
return this.adaptableApi.agGridApi;
}
setColDefProperty(col, propertyName, propertyGetter) {
const colId = col.getColId();
const colDef = col.getColDef();
const colSetupInfo = {
col,
colDef,
colId,
};
const userKey = `user.${colId}.${propertyName}`;
const adaptableKey = `adaptable.${colId}.${propertyName}`;
const value = colDef[propertyName];
const isUserDefined = value !== this.colDefPropertyCache.get(adaptableKey);
if (isUserDefined) {
this.colDefPropertyCache.set(userKey, value);
}
const userValue = this.colDefPropertyCache.get(userKey);
const adaptableValue = propertyGetter(userValue);
if (adaptableValue != null) {
this.colDefPropertyCache.set(adaptableKey, adaptableValue);
}
let theValue = adaptableValue ?? userValue;
this.adaptableInstance.forPlugins((plugin) => {
if (plugin.interceptSetupColumnProperty) {
theValue = plugin.interceptSetupColumnProperty(colSetupInfo, propertyName, theValue, this.adaptableApi);
}
});
if (propertyName === 'aggFunc') {
if (colDef[propertyName] !== (theValue ?? null)) {
this.agGridApi?.setColumnAggFunc(colId, theValue ?? null);
}
}
if (theValue === undefined && colDef[propertyName] === undefined) {
return;
}
colDef[propertyName] = theValue;
}
getUserColDefProperty(columnId, propertyName) {
const userKey = `user.${columnId}.${propertyName}`;
return this.colDefPropertyCache.get(userKey);
}
shouldSkipColumn(colId) {
return (colId.startsWith('ag-Grid-') &&
!this.adaptableApi.columnApi.isAutoRowGroupColumn(colId) &&
!this.adaptableApi.columnApi.isSelectionColumn(colId));
}
getAllAgGridColumns() {
const pivotMode = this.adaptableInstance.isInPivotMode();
let cols = pivotMode
?
this.agGridApi.getColumns()
:
this.agGridApi.getAllGridColumns();
if (pivotMode) {
const pivotResultColumns = this.agGridApi.getPivotResultColumns() || [];
const autoGroupColumns = this.agGridApi
.getAllGridColumns()
.filter((column) => this.adaptableApi.columnApi.isAutoRowGroupColumn(column.getColId()));
cols = [...autoGroupColumns, ...cols, ...pivotResultColumns];
}
return cols;
}
setupColumns(specificColumnIds) {
let cols = this.getAllAgGridColumns();
if (specificColumnIds?.length) {
cols = cols.filter((col) => specificColumnIds.includes(col.getColId()));
}
cols.forEach((col) => {
const colDef = col.getColDef();
const colId = col.getColId();
if (this.shouldSkipColumn(colId)) {
return;
}
const abColumn = this.adaptableApi.columnApi.getColumnWithColumnId(colId);
const colSetupInfo = {
col,
colDef,
colId,
abColumn,
};
const isAutoRowGroupColumn = this.adaptableApi.columnApi.isAutoRowGroupColumn(colId);
this.setupColumnCellRenderer(colSetupInfo);
this.setupColumnCellStyle(colSetupInfo);
this.setupColumnCellClass(colSetupInfo);
this.setupColumnHeaderStyle(colSetupInfo);
this.setupColumnHeaderClass(colSetupInfo);
this.setupColumnValueGetter(colSetupInfo);
this.setupColumnTooltipValueGetter(colSetupInfo);
if (!isAutoRowGroupColumn) {
this.setupColumnFilter(colSetupInfo);
this.setupColumnFloatingFilter(colSetupInfo);
}
this.setupColumnValueFormatter(colSetupInfo);
this.setupColumnEditable(colSetupInfo);
this.setupColumnValueSetter(colSetupInfo);
this.setupColumnComparator(colSetupInfo);
this.setupColumnGetFindText(colSetupInfo);
this.setupColumnCellEditor(colSetupInfo);
this.setupColumnHeader(colSetupInfo);
this.setupColumnQuickFilterText(colSetupInfo);
this.setupColumnAllowedAggFuncs(colSetupInfo);
this.setupColumnType(colSetupInfo);
this.setupColumnCellDataType(colSetupInfo);
});
}
setupColumnValueGetter({ col }) {
this.setColDefProperty(col, 'valueGetter', (userValue) => {
return userValue;
});
}
setupColumnCellClass({ col, colId, abColumn }) {
this.setColDefProperty(col, 'cellClass', (userCellClass) => {
const formatColumns = this.adaptableApi.formatColumnApi.internalApi.getFormatColumnWithStyleClassNameForColumn(abColumn, { target: 'cell' });
const cellClass = (params) => {
const gridCell = this.adaptableApi.gridApi.getGridCellFromRowNode(params.node, abColumn.columnId);
if (!gridCell.column) {
return null;
}
const isExcelExport = this.adaptableApi.exportApi.internalApi.isExcelExportInProgress();
const isVisualDataExport = this.adaptableApi.exportApi.internalApi.isVisualDataExportInProgress();
if (isExcelExport || isVisualDataExport) {
const excelStyleClasses = [];
const userDefinedCellClass = typeof userCellClass === 'function' ? userCellClass(params) : userCellClass;
if (userDefinedCellClass) {
if (Array.isArray(userDefinedCellClass)) {
excelStyleClasses.push(...userDefinedCellClass.filter(Boolean));
}
else {
excelStyleClasses.push(userDefinedCellClass);
}
}
if (isVisualDataExport) {
const cellClassKey = AgGridExportAdapter.getExcelClassNameForCell(colId, gridCell.primaryKeyValue, userDefinedCellClass);
const customCellClass = this.adaptableInstance.agGridExportAdapter.getExcelStyleIdForClassKey(cellClassKey);
if (customCellClass) {
excelStyleClasses.push(customCellClass);
}
}
return excelStyleClasses.length ? excelStyleClasses : null;
}
const isQuickSearchActive = this.isQuickSearchActive(gridCell);
const isServerSideRowModel = this.adaptableApi.gridApi.getAgGridRowModelType() === 'serverSide';
const editableClassName = this.getEditableCellClass(gridCell, params);
const readonlyClassName = this.getReadonlyCellClass(gridCell, params);
const editedClassName = this.getEditedCellClass(gridCell, params);
const highlightAlertClassName = this.getAlertCellClass(gridCell, params);
const flashingClassName = this.getFlashingCellClass(gridCell, params);
const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(colId);
const hasStyledColumn = !!styledColumn && !styledColumn.IsSuspended;
const noteClassName = this.getNoteCellClassName(gridCell, params);
const commentsClassName = this.getCommentCellClassName(gridCell, params);
const returnValue = [
typeof userCellClass === 'function' ? userCellClass(params) : userCellClass,
!hasStyledColumn && formatColumns.length
? this.getFormatColumnCellClass(formatColumns, abColumn, params)
: null,
isQuickSearchActive && !isServerSideRowModel ? 'ab-QuickSearchFind' : null,
editableClassName,
readonlyClassName,
editedClassName,
highlightAlertClassName,
flashingClassName,
noteClassName,
commentsClassName,
]
.flat()
.filter((x) => !!x);
const result = returnValue.length ? returnValue : undefined;
return result;
};
return cellClass;
});
}
setupColumnHeaderClass({ col, colId, abColumn }) {
this.setColDefProperty(col, 'headerClass', (userHeaderClass) => {
const headerClass = (params) => {
let baseHeaderClass = [];
const userDefinedHeaderClass = typeof userHeaderClass === 'function' ? userHeaderClass(params) : userHeaderClass;
if (userDefinedHeaderClass) {
baseHeaderClass =
typeof userDefinedHeaderClass === 'string'
? [userDefinedHeaderClass]
: Array.isArray(userDefinedHeaderClass)
? userDefinedHeaderClass
: [userDefinedHeaderClass];
}
if (params.floatingFilter) {
return baseHeaderClass;
}
if (params.columnGroup) {
return baseHeaderClass;
}
const isExcelExport = this.adaptableApi.exportApi.internalApi.isExcelExportInProgress();
const isVisualDataExport = this.adaptableApi.exportApi.internalApi.isVisualDataExportInProgress();
if (isExcelExport || isVisualDataExport) {
const excelStyleHeaderClasses = [];
if (userDefinedHeaderClass) {
if (Array.isArray(userDefinedHeaderClass)) {
excelStyleHeaderClasses.push(...userDefinedHeaderClass.filter(Boolean));
}
else {
excelStyleHeaderClasses.push(userDefinedHeaderClass);
}
}
if (isVisualDataExport) {
const headerClassKey = AgGridExportAdapter.getExcelClassNameForHeader(colId, userDefinedHeaderClass);
const customHeaderClass = this.adaptableInstance.agGridExportAdapter.getExcelStyleIdForClassKey(headerClassKey);
if (customHeaderClass) {
excelStyleHeaderClasses.push(customHeaderClass);
}
}
return excelStyleHeaderClasses.length ? excelStyleHeaderClasses : null;
}
const columnId = params.column.getColId();
const adaptableColumn = this.adaptableApi.columnApi.getColumnWithColumnId(columnId);
if (!adaptableColumn) {
return baseHeaderClass;
}
const target = 'columnHeader';
const formatColumnWithTextAlignment = this.getRelevantFormatColumnHeaderStyles(abColumn)
.find((fc) => fc.Style?.Alignment != undefined);
if (formatColumnWithTextAlignment) {
const alignment = formatColumnWithTextAlignment.Style.Alignment.toLowerCase();
baseHeaderClass = [...baseHeaderClass, `ab-header__align-${alignment}`];
}
const formatColumns = this.adaptableApi.formatColumnApi.internalApi.getFormatColumnWithStyleClassNameForColumn(abColumn, {
target,
});
if (!formatColumns.length) {
return baseHeaderClass;
}
const formatColumnClasses = formatColumns
.map((formatColumn) => {
if (formatColumn.Style?.ClassName &&
this.adaptableApi.formatColumnApi.internalApi.formatColumnShouldRenderInHeader(formatColumn, abColumn)) {
return formatColumn.Style?.ClassName;
}
})
.filter((x) => !!x);
return [...baseHeaderClass, ...formatColumnClasses];
};
return headerClass;
});
}
quickSearchStyleToDynamicCssVars(style) {
if (!style) {
return undefined;
}
return Object.entries(style).reduce((acc, [key, value]) => {
acc[`--ab-dynamic-${kebabCase(key)}`] = value;
return acc;
}, {});
}
setupColumnCellStyle({ col }) {
this.setColDefProperty(col, 'cellStyle', (userCellStyle) => {
const cellStyle = (params) => {
const quickSearchStyle = this.getQuickSearchCellStyle();
const quickSearchTextMatchStyle = this.getQuickSearchTextMatchStyle();
const quickSearchCurrentTextMatchStyle = this.getQuickSearchCurrentTextMatchStyle();
const textMatchStyle = this.quickSearchStyleToDynamicCssVars(quickSearchTextMatchStyle);
const currentTextMatchStyle = this.quickSearchStyleToDynamicCssVars(quickSearchCurrentTextMatchStyle);
const hasQuickSearchStyle = quickSearchStyle != undefined ||
quickSearchTextMatchStyle != undefined ||
quickSearchCurrentTextMatchStyle != undefined;
const columnId = params.column.getColId();
const gridCell = this.adaptableApi.gridApi.getGridCellFromRowNode(params.node, columnId);
if (!gridCell || !gridCell.column) {
return {};
}
const isQuickSearchActive = hasQuickSearchStyle && this.isQuickSearchActive(gridCell);
const isQuickSearchAvailable = this.adaptableApi.internalApi
.getModuleService()
.isAdapTableModulePresent('QuickSearch');
const isCurrentMatch = isQuickSearchAvailable &&
this.adaptableApi.agGridApi.findGetActiveMatch()?.node === params.node;
const textStyleToApply = isCurrentMatch
? { ...textMatchStyle, ...currentTextMatchStyle }
: textMatchStyle;
let baseStyles = {};
if (this.adaptableApi.columnApi.isPivotResultColumn(columnId)) {
const baseColumn = params.column.getColDef()?.pivotValueColumn;
if (baseColumn) {
const baseColDefCellStyle = baseColumn?.getColDef()?.cellStyle;
const baseColParams = {
...params,
column: baseColumn,
__pivotResultColumn: params.column,
};
baseStyles =
typeof baseColDefCellStyle === 'function'
? baseColDefCellStyle(baseColParams)
: baseColDefCellStyle;
}
}
else {
baseStyles = typeof userCellStyle === 'function' ? userCellStyle(params) : userCellStyle;
}
const result = {
...baseStyles,
...this.getReadOnlyCellStyle(gridCell, params),
...this.getEditableCellStyle(gridCell, params),
...this.getEditedCellStyle(gridCell, params),
...this.getFormatColumnAndStyledColumnCellStyle(gridCell.column, params),
...(isQuickSearchActive ? quickSearchStyle : {}),
...(isQuickSearchActive && textStyleToApply ? textStyleToApply : {}),
...this.getAlertCellStyle(gridCell, params),
...this.getFlashingCellStyle(gridCell, params),
...this.getCellHighlightStyle(gridCell, params),
...this.getColumnHighlightStyle(gridCell, params),
};
return normalizeStyleForAgGrid(result);
};
return cellStyle;
});
}
setupColumnHeaderStyle({ col }) {
this.setColDefProperty(col, 'headerStyle', (userHeaderStyle) => {
const headerStyleFunc = (params) => {
let baseStyles = {};
baseStyles =
typeof userHeaderStyle === 'function' ? userHeaderStyle(params) : userHeaderStyle;
if (params.floatingFilter) {
return baseStyles;
}
const columnId = params.column.getColId();
const adaptableColumn = this.adaptableApi.columnApi.getColumnWithColumnId(columnId);
if (!adaptableColumn) {
return baseStyles;
}
const result = {
...baseStyles,
...this.getFormatColumnHeaderStyle(adaptableColumn, params),
};
if (result['borderColor']) {
result['borderWidth'] = `1px`;
result['borderStyle'] = 'solid';
}
return normalizeStyleForAgGrid(result);
};
return headerStyleFunc;
});
}
setupColumnCellEditor({ colId, col, colDef, abColumn }) {
const shouldShowSelectCellEditor = this.adaptableApi.userInterfaceApi.internalApi.shouldShowSelectCellEditor(abColumn);
const hasRichSelectCellEditor = this.adaptableApi.internalApi
.getAgGridModulesAdapter()
.isAgGridModuleRegistered('RichSelectModule');
this.setColDefProperty(col, 'cellEditor', () => {
if (shouldShowSelectCellEditor) {
if (hasRichSelectCellEditor) {
return 'agRichSelectCellEditor';
}
else {
this.adaptableApi.logWarn(`Cannot show Select Editor as missing required AG Grid module: RichSelect`);
return colDef.cellEditor;
}
}
else {
if (colDef.cellEditor) {
return colDef.cellEditor;
}
const cellDataTypeEditor = getEditorForColumnDataType(abColumn.dataType, this.getVariant());
return cellDataTypeEditor;
}
});
this.setColDefProperty(col, 'cellEditorParams', (params) => {
if (shouldShowSelectCellEditor) {
return (params) => {
const gridCell = this.adaptableApi.gridApi.getGridCellFromRowNode(params?.node, colId);
const options = this.adaptableApi.gridApi.internalApi.getDistinctEditDisplayValuesForColumn({
columnId: colId,
gridCell,
currentSearchValue: '',
});
const valueToLabelMap = new Map();
const values = options.then((options) => options.map((option) => {
valueToLabelMap.set(option.value, option.label);
return option.value;
}));
const fetchSelectItems = (_params) => {
return values;
};
return {
values: fetchSelectItems,
formatValue: (value) => valueToLabelMap.get(value) ?? value,
};
};
}
});
}
setupColumnCellRenderer({ col, colId, abColumn }) {
this.setColDefProperty(col, 'cellRenderer', () => {
const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(abColumn.columnId);
if (styledColumn && !styledColumn.IsSuspended) {
if (styledColumn.PercentBarStyle) {
return getPercentBarRendererForColumn(styledColumn, abColumn, this.adaptableApi);
}
if (styledColumn.BulletChartStyle) {
return getBulletChartRendererForColumn(styledColumn, abColumn, this.adaptableApi);
}
if (styledColumn.RangeBarStyle) {
return getRangeBarRendererForColumn(styledColumn, abColumn, this.adaptableApi);
}
if (styledColumn.RatingStyle) {
return getRatingRendererForColumn(styledColumn, abColumn, this.adaptableApi);
}
if (styledColumn.IconStyle) {
return getIconRendererForColumn(styledColumn, abColumn, this.adaptableApi);
}
if (styledColumn.BadgeStyle) {
return getBadgeRendererForColumn(styledColumn, abColumn, this.adaptableApi);
}
if (styledColumn.SparklineStyle) {
return 'agSparklineCellRenderer';
}
}
});
this.setColDefProperty(col, 'cellRendererParams', (userDefined) => {
const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(abColumn.columnId);
if (styledColumn && !styledColumn.IsSuspended) {
if (styledColumn.SparklineStyle) {
const sanitizedSparklineOptions = AdaptableHelper.removeAdaptableObjectPrimitives(styledColumn.SparklineStyle.options);
const sparklineOptions = resolveSparklineOptionsForRender(merge({}, userDefined?.sparklineOptions, sanitizedSparklineOptions));
return {
...userDefined,
sparklineOptions,
};
}
}
});
}
setupColumnTooltipValueGetter({ col, colId, abColumn }) {
let hasTooptip = false;
this.setColDefProperty(col, 'tooltipValueGetter', () => {
const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(colId);
if (!styledColumn || styledColumn.IsSuspended) {
return undefined;
}
if (styledColumn.IconStyle && !isUnsupportedColumnDataTypeForIconStyle(abColumn.dataType)) {
const iconTokens = styledColumn.IconStyle.ToolTipText ?? [];
if (iconTokens.length === 0) {
return undefined;
}
hasTooptip = true;
return (params) => {
const parts = [];
if (iconTokens.includes('CellValue')) {
parts.push(String(params.value ?? ''));
}
if (iconTokens.includes('IconDescription')) {
const matched = findIconStyleMappingForValue(styledColumn.IconStyle, params.value);
if (matched?.Description) {
parts.push(matched.Description);
}
}
const trimmed = parts.filter(Boolean).join(' · ').trim();
return trimmed ? trimmed : String(params.value ?? '');
};
}
if (styledColumn.RatingStyle) {
const ratingToolTip = styledColumn.RatingStyle.ToolTipText ?? [];
if (ratingToolTip.length === 0) {
return undefined;
}
hasTooptip = true;
const ratingMax = styledColumn.RatingStyle.Max ?? 5;
return (params) => {
let returnValue = '';
if (ratingToolTip.includes('CellValue')) {
returnValue = String(params.value ?? '');
}
if (ratingToolTip.includes('PercentageValue') && ratingMax > 0) {
const n = Number(params.value);
if (!isNaN(n)) {
const clamped = clamp(n, 0, ratingMax);
const percentageValue = (clamped / ratingMax) * 100;
const pct = `${percentageValue.toFixed(0)}%`;
returnValue = returnValue ? `${returnValue} (${pct})` : pct;
}
}
const trimmed = returnValue.trim();
return trimmed ? trimmed : String(params.value ?? '');
};
}
const tooltipStyle = styledColumn.PercentBarStyle ??
styledColumn.BulletChartStyle ??
styledColumn.GradientStyle ??
styledColumn.RangeBarStyle;
const textOptions = tooltipStyle?.ToolTipText;
if (!tooltipStyle || !textOptions || textOptions.length === 0) {
return undefined;
}
hasTooptip = true;
return (params) => {
const isRangeBar = tooltipStyle === styledColumn.RangeBarStyle;
let min;
let max;
if (isRangeBar) {
const rangeStyle = styledColumn.RangeBarStyle;
min = this.resolveRangeBarBound(rangeStyle.Min, abColumn, params.node);
max = this.resolveRangeBarBound(rangeStyle.Max, abColumn, params.node);
}
else {
min = this.adaptableApi.styledColumnApi.internalApi.getNumericStyleMinValue(styledColumn, abColumn, params.node, params.value);
max = this.adaptableApi.styledColumnApi.internalApi.getNumericStyleMaxValue(styledColumn, abColumn, params.node, params.value);
}
let returnValue = '';
if (textOptions.includes('CellValue')) {
returnValue = String(params.value ?? '');
}
if (textOptions.includes('PercentageValue') && min != undefined && max != undefined) {
let percentageValue;
if (styledColumn.PercentBarStyle?.ColumnComparison) {
const absMax = Math.abs(max);
percentageValue = absMax === 0 ? 0 : (Number(params.value) / absMax) * 100;
}
else {
const scaleSpan = max - min;
const clamped = clamp(Number(params.value), min, max);
percentageValue = scaleSpan === 0 ? 0 : ((clamped - min) / scaleSpan) * 100;
}
returnValue += ` (${percentageValue.toFixed(0)}%)`;
}
const trimmed = returnValue.trim();
return trimmed ? trimmed : String(params.value ?? '');
};
});
}
resolveRangeBarBound(bound, abColumn, rowNode) {
if (bound == undefined) {
return undefined;
}
if (typeof bound === 'number') {
return bound;
}
const internalApi = this.adaptableApi.styledColumnApi.internalApi;
if (bound === 'Col-Min') {
return internalApi.getMinValueForNumericColumn(abColumn);
}
if (bound === 'Col-Max') {
return internalApi.getMaxValueForNumericColumn(abColumn);
}
if (bound === 'Col-Avg') {
return internalApi.getAvgValueForNumericColumn(abColumn);
}
if (bound === 'Col-Median') {
return internalApi.getMedianValueForNumericColumn(abColumn);
}
if (typeof bound === 'string') {
if (!this.adaptableApi.columnApi.isColumnInGrid(bound)) {
return undefined;
}
const raw = this.adaptableApi.gridApi.getRawValueFromRowNode(rowNode, bound);
const num = typeof raw === 'number' ? raw : Number(raw);
return isNaN(num) ? undefined : num;
}
return undefined;
}
setupColumnQuickFilterText({ col, abColumn }) {
this.setColDefProperty(col, 'getQuickFilterText', (userGetQuickFilterText) => {
if (userGetQuickFilterText) {
return userGetQuickFilterText;
}
return (params) => {
const visibleColumnsMap = this.adaptableApi.layoutApi.getCurrentVisibleColumnIdsMapForTableLayout();
const isVisible = visibleColumnsMap[abColumn.columnId];
if (!isVisible) {
return '';
}
return this.adaptableApi.gridApi.getDisplayValueFromRowNode(params.node, abColumn.columnId);
};
});
}
setupColumnAllowedAggFuncs({ col, abColumn }) {
this.setColDefProperty(col, 'allowedAggFuncs', () => {
if (!abColumn.availableAggregationFunctions) {
return undefined;
}
return abColumn.availableAggregationFunctions.filter((func) => !isWeightedAverageAggFuncName(func));
});
}
setupColumnType(columnSetupInfo) {
const { col, colId } = columnSetupInfo;
this.setColDefProperty(col, 'type', (original_columnType) => {
const originalTypes = original_columnType == undefined
? []
: Array.isArray(original_columnType)
? original_columnType
: [original_columnType];
const columnTypes = new Set(originalTypes);
if (this.adaptableApi.columnApi.isCalculatedColumn(colId)) {
columnTypes.add(CALCULATED_COLUMN_TYPE);
}
if (this.adaptableApi.columnApi.isFreeTextColumn(colId)) {
columnTypes.add(FREE_TEXT_COLUMN_TYPE);
}
if (this.adaptableApi.columnApi.isActionColumn(colId)) {
columnTypes.add(ACTION_COLUMN_TYPE);
}
if (this.adaptableApi.columnApi.isFdc3Column(colId)) {
columnTypes.add(FDC3_COLUMN_TYPE);
}
return Array.from(columnTypes);
});
}
setupColumnCellDataType(columnSetupInfo) {
const { col, colId } = columnSetupInfo;
this.setColDefProperty(col, 'cellDataType', (original_cellDataType) => {
if (original_cellDataType === 'dateString') {
errorOnce(`AG Grid: Column '${colId}' specifies cellDataType='dateString' which is no longer supported. It has been automatically replaced with cellDataType='date'. Please update your column definition.`);
return 'date';
}
return original_cellDataType ?? true;
});
}
setupColumnHeader({ col }) {
this.setColDefProperty(col, 'headerValueGetter', (original_headerValueGetter) => {
if (!isProvidedByAdaptable(original_headerValueGetter)) {
this.adaptableApi.logWarn(`colDef.headerValueGetter is defined for column '${col.getColId()}', and overrides the Adaptable custom header mechanism! We recommend using a ColumnOptions.columnHeader instead!`);
}
return original_headerValueGetter;
});
}
setupColumnFilter(columnSetup) {
const { col, colDef, abColumn, colId } = columnSetup;
const useAdaptableFilter = this.adaptableOptions.filterOptions.useAdaptableFiltering;
if (!useAdaptableFilter) {
return;
}
if (this.adaptableApi.columnApi.isAutoRowGroupColumn(col.getColId())) {
if (this.adaptableApi.gridApi.isTreeDataGrid()) {
this.setColDefProperty(col, 'filter', (original_filter) => {
const autoGroupColumnDef = this.agGridApi.getGridOption('autoGroupColumnDef');
if (autoGroupColumnDef?.filter != undefined) {
return original_filter;
}
else {
return false;
}
});
}
else {
this.setColDefProperty(col, 'filter', () => {
return 'agGroupColumnFilter';
});
}
if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(colId)) {
return;
}
}
this.setColDefProperty(col, 'filter', (original_filter) => {
const pivotMode = this.adaptableInstance.isInPivotMode();
if (!useAdaptableFilter) {
return original_filter;
}
if (!colDef.filter) {
return;
}
if (typeof original_filter !== 'boolean' &&
typeof original_filter?.handler !== 'function' &&
!pivotMode) {
this.adaptableApi.consoleError(`Column "${colId}" has a custom filter in colDef.filter, but Adaptable filtering only accepts boolean (true/false) values for this property.`);
return false;
}
return {
component: AgGridFilterAdapterFactory(this.adaptableInstance),
handler: () => new AdaptableFilterHandler(this.adaptableApi),
};
});
}
setupColumnFloatingFilter({ col, colDef }) {
const userProvidedFilterProp = this.getUserColDefProperty(col.getColId(), 'filter');
const hasInvalidFilterProp = typeof userProvidedFilterProp !== 'boolean' &&
typeof userProvidedFilterProp?.handler !== 'function' &&
!this.adaptableInstance.isInPivotMode();
if (hasInvalidFilterProp) {
return false;
}
const isFloatingFilterDisabled = !colDef.filter ||
!colDef.floatingFilter ||
!this.adaptableOptions.filterOptions.useAdaptableFiltering ||
!this.adaptableApi.filterApi.columnFilterApi.isQuickFilterVisible();
if (this.adaptableApi.columnApi.isAutoRowGroupColumnForMulti(col.getColId())) {
this.setColDefProperty(col, 'floatingFilter', (original_floatingFilter) => {
return original_floatingFilter;
});
this.setColDefProperty(col, 'suppressFloatingFilterButton', () => {
return true;
});
return;
}
this.setColDefProperty(col, 'floatingFilterComponent', () => {
if (isFloatingFilterDisabled) {
return;
}
return AgGridFloatingFilterAdapterFactory(this.adaptableInstance);
});
this.setColDefProperty(col, 'floatingFilter', () => {
if (isFloatingFilterDisabled) {
return;
}
return AgGridFloatingFilterAdapterFactory(this.adaptableInstance);
});
this.setColDefProperty(col, 'suppressFloatingFilterButton', () => {
return !isFloatingFilterDisabled;
});
}
setupColumnValueFormatter({ col, abColumn }) {
this.setColDefProperty(col, 'valueFormatter', (userPropertyValue) => {
const activeFormatColumnsWithDisplayFormat = this.adaptableApi.formatColumnApi.internalApi.getFormatColumnsWithDisplayFormatForColumn(abColumn, { target: 'cell' });
if (!activeFormatColumnsWithDisplayFormat.length) {
return;
}
return (params) => {
const { node, value } = params;
const mostRelevantFormatColumn = this.adaptableApi.formatColumnApi.internalApi.getMostRelevantFormatColumnForColumn(activeFormatColumnsWithDisplayFormat, abColumn, { node, value });
if (!mostRelevantFormatColumn) {
return value;
}
const resolvedDisplayFormat = resolveDisplayFormat(mostRelevantFormatColumn.DisplayFormat);
if (!resolvedDisplayFormat) {
return value;
}
const formatterOptions = resolvedDisplayFormat.Options;
if (resolvedDisplayFormat.Formatter === 'NumberFormatter') {
if (this.adaptableApi.columnScopeApi.isColumnInNumericScope(abColumn, mostRelevantFormatColumn.Scope)) {
let cellValue = params.value;
if (typeof params.value?.toNumber === 'function' &&
typeof params.value?.toString === 'function') {
cellValue = params.value.toNumber();
}
return this.adaptableApi.formatColumnApi.internalApi.getNumberFormattedValue(cellValue, params.node, abColumn, formatterOptions);
}
}
if (resolvedDisplayFormat.Formatter === 'DateFormatter') {
if (this.adaptableApi.columnScopeApi.isColumnInDateScope(abColumn, mostRelevantFormatColumn.Scope)) {
let cellValue = params.value;
if (typeof params.value?.toNumber === 'function' &&
typeof params.value?.toString === 'function') {
cellValue = params.value.toString();
}
return this.adaptableApi.formatColumnApi.internalApi.getDateFormattedValue(cellValue, params.node, abColumn, formatterOptions);
}
}
if (resolvedDisplayFormat.Formatter === 'StringFormatter') {
if (this.adaptableApi.columnScopeApi.isColumnInTextScope(abColumn, mostRelevantFormatColumn.Scope)) {
let cellValue = params.value;
if (typeof params.value?.toNumber === 'function' &&
typeof params.value?.toString === 'function') {
cellValue = params.value.toString();
}
return this.adaptableApi.formatColumnApi.internalApi.getStringFormattedValue(cellValue, params.node, abColumn, formatterOptions);
}
}
return value;
};
});
}
setupColumnEditable({ col }) {
this.setColDefProperty(col, 'editable', (original_editable) => {
const editableCallback = (params) => {
const getOriginalColDefEditable = () => {
if (typeof original_editable === 'function') {
return original_editable(params);
}
else {
return original_editable;
}
};
if (this.adaptableApi.gridApi.internalApi.hasCellEditableAccordingToEditOptions()) {
const gridCell = this.adaptableApi.gridApi.getGridCellFromRowNode(params.node, params.column.getColId());
return this.adaptableApi.gridApi.internalApi.isCellEditableAccordingToEditOptions(gridCell, getOriginalColDefEditable());
}
return getOriginalColDefEditable();
};
return editableCallback;
});
}
setupColumnValueSetter({ col, colId, abColumn }) {
this.setColDefProperty(col, 'valueSetter', (userValueSetter) => {
const preventEditAlertsForColumn = this.adaptableApi.alertApi.internalApi
.getAlertDefinitionsWithPreventEdit()
.filter((alertDefinition) => {
return this.adaptableApi.columnScopeApi.isColumnInScope(abColumn, alertDefinition.Scope);
});
const noValidations = !preventEditAlertsForColumn.length && !this.adaptableOptions.editOptions?.validateOnServer;
if (noValidations) {
return;
}
const valueSetter = (params) => {
const field = params.column.getColDef().field;
if (noValidations) {
if (typeof userValueSetter === 'function') {
return userValueSetter(params);
}
if (field) {
params.data[field] = params.newValue;
}
return true;
}
const cellDataChangedInfo = this.adaptableApi.internalApi.buildCellDataChangedInfo({
oldValue: params.oldValue,
newValue: params.newValue,
column: this.adaptableApi.columnApi.getColumnWithColumnId(params.column.getColId()),
primaryKeyValue: this.adaptableApi.gridApi.getPrimaryKeyValueForRowNode(params.node),
rowNode: params.node,
trigger: 'edit',
});
if (cellDataChangedInfo.oldValue === cellDataChangedInfo.newValue) {
return true;
}
const newRow = { ...params.node, data: { ...params.node.data } };
newRow.data[field] = params.newValue;
const cellDataChangeInfoForSyncValidation = {
...cellDataChangedInfo,
rowNode: newRow,
};
if (!this.adaptableApi.internalApi
.getValidationService()
.performValidation(cellDataChangeInfoForSyncValidation)) {
return false;
}
const onServerValidationCompleted = () => { };
if (this.adaptableOptions.editOptions?.validateOnServer) {
this.adaptableApi.internalApi
.getValidationService()
.performServerValidation(cellDataChangedInfo, {
onServerValidationCompleted,
})();
}
if (typeof userValueSetter === 'function') {
return userValueSetter(params);
}
if (field) {
params.data[field] = params.newValue;
}
else {
throw `Cannot edit a column without a field - column id was ${colId}`;
}
return true;
};
return valueSetter;
});
}
setupColumnComparator({ col, colId, abColumn }) {
const customSort = this.adaptableApi.customSortApi.getCustomSortForColumn(colId);
const customSortComparer = this.adaptableApi.customSortApi.internalApi.getCustomSortComparer(abColumn.columnId);
const memoizedDateValues = new Map();
const getDateValue = (rawDateValue) => {
if (memoizedDateValues.has(rawDateValue)) {
return memoizedDateValues.get(rawDateValue);
}
const dateValue = this.adaptableApi.internalApi.parseDateValue(rawDateValue);
memoizedDateValues.set(rawDateValue, dateValue);
return dateValue;
};
const comparatorGetter = (propName) => {
return (userPropertyValue) => {
if (customSortComparer) {
return customSortComparer.comparer;
}
if (customSort && !customSort.IsSuspended) {
return this.adaptableApi.customSortApi.internalApi.getDefaultCustomSortComparer(customSort.ColumnId, customSort.SortedValues);
}
if (userPropertyValue) {
return userPropertyValue;
}
if (abColumn.dataType === 'date') {
return (valueA, valueB) => {
const dateA = getDateValue(valueA);
const dateB = getDateValue(valueB);
if (dateA && dateB) {
return dateA.getTime() - dateB.getTime();
}
else if (dateA) {
return 1;
}
else if (dateB) {
return -1;
}
else {
return 0;
}
};
}
};
};
this.setColDefProperty(col, 'comparator', comparatorGetter('comparator'));
this.setColDefProperty(col, 'pivotComparator', comparatorGetter('pivotComparator'));
}
setupColumnGetFindText({ col, abColumn }) {
this.setColDefProperty(col, 'getFindText', (userGetFindText) => {
return (params) => {
const gridCell = this.adaptableApi.gridApi.getGridCellFromRowNode(params.node, abColumn.columnId);
if (!this.isCellSearchable(gridCell)) {
return null;
}
const getCellSearchText = this.adaptableOptions.quickSearchOptions.getCellSearchText;
if (getCellSearchText) {
return this.getCellSearchText(gridCell);
}
return userGetFindText?.(params) ?? gridCell.displayValue;
};
});
}
getCellSearchText(gridCell) {
const getCellSearchText = this.adaptableOptions.quickSearchOptions.getCellSearchText;
if (getCellSearchText) {
const quickSearchValue = this.adaptableApi.quickSearchApi.getQuickSearchValue();
const quickSearchContext = {
...this.adaptableApi.internalApi.buildBaseContext(),
gridCell,
quickSearchValue,
};
return getCellSearchText(quickSearchContext);