@adaptabletools/adaptable
Version:
Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
1,002 lines (1,001 loc) • 178 kB
JavaScript
import { debounce } from '../Utilities/Helpers/TimingHelper';
import { createGrid, LocalEventService, } from 'ag-grid-enterprise';
import { AdaptableLogger } from './AdaptableLogger';
import { PrimaryKeyDocsLink } from '../Utilities/Constants/DocumentationLinkConstants';
import StringExtensions from '../Utilities/Extensions/StringExtensions';
import { applyQuickSearchFindCssVars } from '../Utilities/Helpers/QuickSearchHelper';
import Emitter from '../Utilities/Emitter';
import { applyDefaultAdaptableOptions } from '../AdaptableOptions/DefaultAdaptableOptions';
import { resolveContainerElement } from '../Utilities/resolveContainerElement';
import { AgGridAdapter } from './AgGridAdapter';
import * as GeneralConstants from '../Utilities/Constants/GeneralConstants';
import { AG_GRID_GRAND_TOTAL_ROW_ID, AG_GRID_GROUPED_COLUMN, AUTOGENERATED_PK_COLUMN, ERROR_LAYOUT, GROUP_PATH_SEPARATOR, HALF_SECOND, QUARTER_SECOND, } from '../Utilities/Constants/GeneralConstants';
import { DataService } from '../Utilities/Services/DataService';
import { AdaptableStore } from '../Redux/Store/AdaptableStore';
import { AdaptableApiImpl } from '../Api/Implementation/AdaptableApiImpl';
import { Fdc3Service } from '../Utilities/Services/Fdc3Service';
import { AnnotationsService } from '../Utilities/Services/AnnotationsService';
import { ChartingService } from '../Utilities/Services/ChartingService';
import { ThemeService } from '../Utilities/Services/ThemeService';
import { ValidationService } from '../Utilities/Services/ValidationService';
import { ModuleService } from '../Utilities/Services/ModuleService';
import { CalculatedColumnExpressionService } from '../Utilities/Services/CalculatedColumnExpressionService';
import { expandCellDataChangedInfosWithCalculatedColumns } from '../Utilities/Services/CalculatedColumnExpressionService';
import { QueryLanguageService } from '../Utilities/Services/QueryLanguageService';
import { AlertService } from '../Utilities/Services/AlertService';
import { TeamSharingService } from '../Utilities/Services/TeamSharingService';
import { LicenseService } from '../Utilities/Services/LicenseService';
import { ALL_TOOL_PANELS } from '../AdaptableState/Common/Types';
import * as ModuleConstants from '../Utilities/Constants/ModuleConstants';
import { GridFilterModuleId } from '../Utilities/Constants/ModuleConstants';
import { DashboardModule } from '../Strategy/DashboardModule';
import { AlertModule } from '../Strategy/AlertModule';
import { FlashingCellModule } from '../Strategy/FlashingCellModule';
import { BulkUpdateModule } from '../Strategy/BulkUpdateModule';
import { CalculatedColumnModule } from '../Strategy/CalculatedColumnModule';
import { CellSummaryModule } from '../Strategy/CellSummaryModule';
import { CustomSortModule } from '../Strategy/CustomSortModule';
import { DataChangeHistoryModule } from '../Strategy/DataChangeHistoryModule';
import { DataImportModule } from '../Strategy/DataImportModule';
import { DataSetModule } from '../Strategy/DataSetModule';
import { ExportModule } from '../Strategy/ExportModule';
import { ColumnFilterModule } from '../Strategy/ColumnFilterModule';
import { FormatColumnModule } from '../Strategy/FormatColumnModule';
import { FreeTextColumnModule } from '../Strategy/FreeTextColumnModule';
import { LayoutModule } from '../Strategy/LayoutModule';
import { PlusMinusModule } from '../Strategy/PlusMinusModule';
import { QuickSearchModule } from '../Strategy/QuickSearchModule';
import { SmartEditModule } from '../Strategy/SmartEditModule';
import { ShortcutModule } from '../Strategy/ShortcutModule';
import { StateManagementModule } from '../Strategy/StateManagementModule';
import { TeamSharingModule } from '../Strategy/TeamSharingModule';
import { ToolPanelModule } from '../Strategy/ToolPanelModule';
import { SystemStatusModule } from '../Strategy/SystemStatusModule';
import { ThemeModule } from '../Strategy/ThemeModule';
import { GridInfoModule } from '../Strategy/GridInfoModule';
import { ColumnInfoModule } from '../Strategy/ColumnInfoModule';
import { SettingsPanelModule } from '../Strategy/SettingsPanelModule';
import { StatusBarModule } from '../Strategy/StatusBarModule';
import { ChartingModule } from '../Strategy/ChartingModule';
import { NoteModule } from '../Strategy/NoteModule';
import { StyledColumnModule } from '../Strategy/StyledColumnModule';
import { Fdc3Module } from '../Strategy/Fdc3Module';
import { GridFilterModule } from '../Strategy/GridFilterModule';
import { NamedQueryModule } from '../Strategy/NamedQueryModule';
import { CommentModule } from '../Strategy/CommentModule';
import { Helper } from '../Utilities/Helpers/Helper';
import { createUuid } from '../components/utils/uuid';
import UIHelper from '../View/UIHelper';
import { getAdaptableToolPanelAgGridComponent } from '../View/Components/ToolPanel/AdaptableToolPanel';
import { ADAPTABLE_STATUS_PANEL } from '../AdaptableState/StatusBarState';
import { AdaptableStatusBar } from '../View/StatusBar/AdaptableStatusBar';
import ArrayExtensions from '../Utilities/Extensions/ArrayExtensions';
import { AgGridMenuAdapter } from './AgGridMenuAdapter';
import { AdaptableApp } from '../View/AdaptableView';
import { renderReactRoot as defaultRenderReactRoot } from '../renderReactRoot';
import { AgGridOptionsService } from './AgGridOptionsService';
import { parseDateValue } from '../Utilities/Helpers/DateHelper';
import { AgGridColumnAdapter } from './AgGridColumnAdapter';
import getScrollbarSize from '../Utilities/getScrollbarSize';
import { ONLY_AGG_FN_NAME, WEIGHTED_AVERAGE_AGG_FN_NAME, } from '../AdaptableState/Common/AggregationColumns';
import { RowFormService } from '../Utilities/Services/RowFormService';
import { ADAPTABLE_PUBLISH_TIMESTAMP } from '../EnvVars';
import { AdaptableUpgradeHelper } from '../migration/AdaptableUpgradeHelper';
import { stripDeprecatedStateKeys } from '../migration/DeprecatedStateKeys';
import { ensureLoadingScreenPortalElement } from '../components/Modal';
import { AdaptableLoadingScreen } from '../View/Components/Popups/AdaptableLoadingScreen';
import { createElement } from 'react';
import { createAgStatusPanelComponent } from '../Utilities/createAgStatusPanelComponent';
import { only } from '../AdaptableState/Aggregations/only';
import { weightedAverage } from '../AdaptableState/Aggregations/weightedAverage';
import { ROW_SUMMARY_ROW_ID } from '../AdaptableState/Common/RowSummary';
import { FlashingCellService } from '../Utilities/Services/FlashingCellService';
import { AgGridExportAdapter } from './AgGridExportAdapter';
import { checkForDuplicateColumns, resetLayoutHelperErrorOnceMessages, getLayoutRowGroupValuesExceptionGroupKeys, isPivotLayout, layoutModelToLayoutState, layoutStateToLayoutModel, normalizeLayout, } from '../Api/Implementation/LayoutHelpers';
import { LayoutManager } from '../layout-manager/src';
import { rowGroupDisplayTypeToGridOption } from '../layout-manager/src/rowGroupDisplayType';
import { isPivotLayoutModel } from '../layout-manager/src/isPivotLayoutModel';
import { ACTION_COLUMN_TYPE, CALCULATED_COLUMN_TYPE, FDC3_COLUMN_TYPE, FREE_TEXT_COLUMN_TYPE, HIDDEN_COLUMN_TYPE, hiddenColDefConfig, PIVOT_AGGREGATION_TOTAL_COLUMN_TYPE, PIVOT_ANY_TOTAL_COLUMN_TYPE, PIVOT_COLUMN_TOTAL_COLUMN_TYPE, PIVOT_GRAND_TOTAL_COLUMN_TYPE, } from '../AdaptableState/Common/AdaptableColumn';
import { agGridDataTypeDefinitions } from './agGridDataTypeDefinitions';
import { AgGridThemeAdapter } from './AgGridThemeAdapter';
import { mapOldTypeToDataType } from '../migration/VersionUpgrade20';
import { tagProvidedByAdaptable } from '../Utilities/adaptableOverrideCheck';
import { AgGridModulesAdapter } from './AgGridModulesAdapter';
import { getMarker } from '../devTools';
import { DeepMap } from '@infinite-table/infinite-react';
import { DateFormatter } from '../Utilities/Helpers/DisplayFormatHelper';
import { clearPredicateDefMapMemo } from '../Api/Implementation/PredicateApiImpl';
import { AgGridFilterAdapterFactory } from './AgGridFilterAdapter';
import { AdaptableFilterHandler } from './AdaptableFilterHandler';
import { AgGridFloatingFilterAdapterFactory } from './AgGridFloatingFilterAdapter';
import { listenForDevTools } from '../setupDevTools';
const LocalEventService_Prototype = LocalEventService.prototype;
const LocalEventService_dispatchEvent = LocalEventService_Prototype.dispatchEvent;
LocalEventService_Prototype.dispatchEvent = function (event) {
const agGridApi = event.api;
if (agGridApi?.isDestroyed()) {
return;
}
LocalEventService_dispatchEvent.apply(this, arguments);
if (event.type === 'cellChanged' || event.type === 'dataChanged') {
const eventRowNode = event.node;
if (!eventRowNode) {
AdaptableLogger.consoleErrorBase(`No RowNode found in passed event, this should never happen!`, event);
return;
}
const extractGridApiFromRowNode = (rowNode) => {
const rowNodeApi = rowNode?.beans?.gridApi;
if (!rowNodeApi) {
AdaptableLogger.consoleErrorBase(`No GridAPI found in passed RowNode, this should never happen!`, rowNode);
}
return rowNodeApi;
};
if (eventRowNode) {
AdaptableAgGrid.forEachAdaptable((adaptable) => {
if (extractGridApiFromRowNode(eventRowNode) !== adaptable.agGridAdapter?.getAgGridApi(true)) {
return;
}
if (adaptable.isDestroyed) {
return;
}
const fn = adaptable.rowListeners ? adaptable.rowListeners[event.type] : null;
if (fn) {
fn(event);
}
});
}
}
};
const adaptableInstances = {};
const publishTimestamp = Number(ADAPTABLE_PUBLISH_TIMESTAMP);
export class AdaptableAgGrid {
logger;
_id;
lifecycleState;
variant;
emitter;
hasAutogeneratedPrimaryKey;
hasAdaptableToolPanel;
initWithLazyData;
_rawAdaptableOptions;
adaptableOptions;
_isDetailGrid;
_isDetailGridForIndex;
agGridOptionsService;
agGridAdapter;
agGridColumnAdapter;
agGridMenuAdapter;
agGridExportAdapter;
agGridThemeAdapter;
agGridModulesAdapter;
DANGER_USE_GETTER_adaptableContainerElement;
DANGER_USE_GETTER_agGridContainerElement;
api;
adaptableStore;
adaptableModules;
DataService;
CalculatedColumnExpressionService;
ModuleService;
ValidationService;
QueryLanguageService;
AlertService;
TeamSharingService;
RowFormService;
Fdc3Service;
AnnotationsService;
FlashingCellService;
ThemeService;
LicenseService;
ChartingService;
rowListeners;
debouncedSetSelectedRows;
debouncedSetSelectedCells;
agGridListenerKeydown;
agGridListenerMouseEnter;
agGridListenerMouseLeave;
listenerGlobalSetRowSelection;
listenerGlobalChartingChanges;
listenerCellEditingStarted;
listenerFirstDataRendered;
listenerPivotChanged;
listenerCellSelectionChanged;
listenerSortChanged;
listenerColumnGroupOpened;
layoutManager;
columnMinMaxValuesCache = {};
renderReactRoot = (node, container) => defaultRenderReactRoot(node, container);
unmountReactRoot;
unmountLoadingScreen;
adaptableStatusPanelKeys = [];
adaptableStatusPanelDefs = [];
hasAdaptableStatusBar;
_PRIVATE_adaptableJSXElement;
_prevLayout;
__prevLayoutForRefresh;
constructor(config) {
this.lifecycleState = 'initial';
this.emitter = new Emitter();
this.agGridOptionsService = new AgGridOptionsService(this);
this.agGridAdapter = new AgGridAdapter(this, config);
this.agGridMenuAdapter = new AgGridMenuAdapter(this);
this.agGridColumnAdapter = new AgGridColumnAdapter(this);
this.agGridExportAdapter = new AgGridExportAdapter(this);
this.agGridThemeAdapter = new AgGridThemeAdapter(this);
this.agGridModulesAdapter = new AgGridModulesAdapter(this);
this.DataService = new DataService(this);
}
static forEachAdaptable(fn) {
Object.keys(adaptableInstances).forEach((key) => {
fn(adaptableInstances[key]);
});
}
static collectInstance(adaptable, adaptableId) {
adaptable._id = adaptableId;
adaptableInstances[adaptable._id] = adaptable;
}
static dismissInstance(adaptable) {
delete adaptableInstances[adaptable._id];
}
get isAgGridInitialising() {
return this.lifecycleState === 'initAgGrid';
}
get isReady() {
return this.lifecycleState === 'ready';
}
get isAvailable() {
return this.lifecycleState === 'available' || this.lifecycleState === 'ready';
}
get isDestroyed() {
return this.lifecycleState === 'preDestroyed';
}
_emit = (eventName, data) => {
if (this.emitter) {
return this.emitter.emit(eventName, data);
}
};
_emitSync = (eventName, data) => {
if (this.emitter) {
return this.emitter.emitSync(eventName, data);
}
};
_on = (eventName, callback) => {
if (!this.emitter) {
return () => { };
}
return this.emitter.on(eventName, callback);
};
_onIncludeFired = (eventName, callback) => {
if (!this.emitter) {
return () => { };
}
return this.emitter.onIncludeFired(eventName, callback);
};
static async _initInternal(config) {
let promise = null;
if (Array.isArray(config.adaptableOptions.plugins)) {
const agGridOptions = {
gridOptions: config.gridOptions,
modules: config.modules,
};
for (let plugin of config.adaptableOptions.plugins) {
promise =
promise && promise.then
? promise.then(() => {
return plugin.beforeInit(config.adaptableOptions, agGridOptions);
})
: plugin.beforeInit(config.adaptableOptions, agGridOptions);
}
if (agGridOptions.gridOptions !== config.gridOptions) {
config.gridOptions = agGridOptions.gridOptions;
}
}
const doInit = (adaptableInstance) => {
return adaptableInstance._initAdaptableAgGrid(config).then((api) => {
listenForDevTools(adaptableInstance);
if (Array.isArray(config.adaptableOptions.plugins)) {
config.adaptableOptions.plugins.forEach((plugin) => {
plugin.afterInit(adaptableInstance);
});
}
return api;
});
};
if (promise && promise.then) {
return promise.then(() => {
const adaptableInstance = new AdaptableAgGrid({
getAgGridColumnApiModuleReference: config.getAgGridColumnApiModuleReference,
});
return doInit(adaptableInstance);
});
}
else {
const adaptableInstance = new AdaptableAgGrid({
getAgGridColumnApiModuleReference: config.getAgGridColumnApiModuleReference,
});
return doInit(adaptableInstance);
}
}
async _initAdaptableAgGrid(config) {
this._isDetailGrid = config.isDetailGrid === true;
this._isDetailGridForIndex = config.isDetailGridForRowIndex;
this.lifecycleState = 'preprocessOptions';
this._rawAdaptableOptions = config.adaptableOptions;
if (StringExtensions.IsNullOrEmptyOrWhiteSpace(this._rawAdaptableOptions.adaptableId)) {
this._rawAdaptableOptions.adaptableId = `adaptable_id_${Date.now()}`;
}
this.logger = this.logger ?? new AdaptableLogger(this._rawAdaptableOptions.adaptableId);
resetLayoutHelperErrorOnceMessages();
const adaptableId = this._rawAdaptableOptions.adaptableId;
const initMarker = getMarker(adaptableId).track.Init.label.Init.start();
const perfInitAdaptableAgGrid = this.logger.beginPerf(`Adaptable._initAdaptableAgGrid()`);
AdaptableAgGrid.collectInstance(this, this._rawAdaptableOptions.adaptableId);
this.variant = config.variant;
this.initWithLazyData =
config.gridOptions.rowData == undefined || config.gridOptions.rowData.length === 0;
this.hasAutogeneratedPrimaryKey = !!this._rawAdaptableOptions.autogeneratePrimaryKey;
this.adaptableOptions = applyDefaultAdaptableOptions(this._rawAdaptableOptions);
this.adaptableOptions = this.normalizeAdaptableOptions(this.adaptableOptions);
const { showLoadingScreen, loadingScreenDelay, loadingScreenText, loadingScreenTitle } = this.adaptableOptions.userInterfaceOptions.loadingScreenOptions;
if (showLoadingScreen) {
this.logger.info('Showing loading screen');
const portalElement = ensureLoadingScreenPortalElement();
if (portalElement) {
this.unmountLoadingScreen = this.renderReactRoot(createElement(AdaptableLoadingScreen, {
showLoadingScreen,
loadingScreenDelay,
loadingScreenText,
loadingScreenTitle,
}), portalElement);
}
else {
this.logger.consoleError('Failed to create loading screen portal element.');
}
}
this.forPlugins((plugin) => plugin.afterInitOptions(this, this.adaptableOptions));
this.api = new AdaptableApiImpl(this);
this.forPlugins((plugin) => plugin.afterInitApi(this, this.api));
this.lifecycleState = 'initAdaptableState';
this.initServices();
this.forPlugins((plugin) => plugin.afterInitServices(this));
this.adaptableModules = this.initModules();
this.forPlugins((plugin) => plugin.afterInitModules(this, this.adaptableModules));
const loadStoreMarker = getMarker(adaptableId).track.Init.label.LoadStore.start();
const perfLoadStore = this.logger.beginPerf(`loadStore()`);
this.adaptableStore = this.initAdaptableStore();
this.forPlugins((plugin) => plugin.afterInitStore(this));
await this.adaptableStore.loadStore({
adaptable: this,
adaptableStateKey: this.adaptableOptions.adaptableStateKey,
postLoadHook: (state) => {
if (this.adaptableOptions.stateOptions.autoMigrateState) {
this.api.logError;
const config = {
fromVersion: 16,
logger: this.logger,
};
state = AdaptableUpgradeHelper.migrateAdaptableState(state, config);
}
state = this.normalizeAdaptableState(state, config.gridOptions);
return state;
},
});
perfLoadStore.end();
loadStoreMarker.end();
if (this.isDestroyed) {
this.midwayDestroy();
return Promise.reject('Adaptable was destroyed while loading the store.');
}
this.forPlugins((plugin) => plugin.afterInitialStateLoaded(this));
this.api.entitlementApi.internalApi.setModulesEntitlements();
this.lifecycleState = 'setupAgGrid';
const gridOptions = config.gridOptions;
let columnDefs = this.agGridAdapter.getColumnDefinitionsInclSpecialColumns(gridOptions.columnDefs || []);
this.agGridAdapter.patchColDefs(columnDefs, (colDef) => {
if (colDef.cellDataType === 'dateString') {
this.logger.consoleError(`Column "${colDef.colId}" uses cellDataType="dateString" which is no longer supported. It has been replaced with cellDataType="date". Please update your column definition.`);
colDef.cellDataType = 'date';
}
});
gridOptions.columnDefs = columnDefs;
this.setInitialGridOptions(gridOptions, config.variant);
const { gridState: initialGridState, layoutModel } = this.mapAdaptableStateToAgGridState(this.adaptableStore.TheStore.getState(), gridOptions.columnDefs, {
isTree: !!gridOptions.treeData,
colTypes: gridOptions.columnTypes,
defaultColDef: gridOptions.defaultColDef,
});
columnDefs = LayoutManager.getColumnDefsChangesForLayout(layoutModel, columnDefs) ?? columnDefs;
gridOptions.columnDefs = columnDefs;
gridOptions.initialState = initialGridState;
const initialRowSelection = gridOptions.rowSelection;
if (layoutModel) {
if (isPivotLayoutModel(layoutModel)) {
gridOptions.pivotDefaultExpanded = layoutModel.PivotExpandLevel;
}
gridOptions.groupDisplayType = rowGroupDisplayTypeToGridOption(layoutModel.RowGroupDisplayType);
gridOptions.suppressAggFuncInHeader = !!layoutModel.SuppressAggFuncInHeader;
if (!isPivotLayoutModel(layoutModel) &&
LayoutManager.shouldUnlockSelectionColumnPosition(layoutModel)) {
gridOptions.selectionColumnDef = {
...gridOptions.selectionColumnDef,
lockPosition: false,
};
}
gridOptions.rowSelection = LayoutManager.getGridOptionForRowSelectionFromLayout(layoutModel.RowSelection, gridOptions.rowSelection);
}
this.lifecycleState = 'initAgGrid';
this.agGridAdapter.initialGridOptions = gridOptions;
const perfInitAgGrid = this.logger.beginPerf(`initAgGrid()`);
const initAgGridMarker = getMarker(adaptableId).track.Init.label.InitAGGrid.start();
this.validateColumnDefTypes(gridOptions.columnDefs);
const agGridApi = await this.initializeAgGrid(gridOptions, config.modules, config.renderAgGridFrameworkComponent);
if (agGridApi === false) {
this.midwayDestroy();
this.logger.consoleError('Failed to initialize AG Grid.');
return Promise.reject('Failed to initialize AG Grid.');
}
this.agGridAdapter.setAgGridApi(agGridApi);
this.layoutManager = new LayoutManager({
gridApi: agGridApi,
debugId: this.adaptableOptions.adaptableId,
initialRowSelection,
});
this.silentUpdateCurrentLayoutModel(layoutModel);
if (isPivotLayoutModel(layoutModel)) {
this.layoutManager.setLayout(layoutModel, {
force: true,
});
}
this.layoutManager.onChange((layoutModel) => {
const newLayoutObject = layoutModelToLayoutState(layoutModel);
this.onLayoutChange(newLayoutObject);
});
this.layoutManager.onColumnDefsChanged(() => {
this.updateColumnModelAndRefreshGrid();
});
this.logger.info('Hiding loading screen');
this.unmountLoadingScreen?.();
perfInitAgGrid.end();
initAgGridMarker.end();
this.agGridAdapter.monkeyPatchingGridOptionsUpdates();
this.agGridAdapter.monkeyPatchingAggColumnFilters();
this.agGridAdapter.monkeyPatchingAggFuncLabels();
this.lifecycleState = 'agGridReady';
this.api.entitlementApi.internalApi.setModulesAgGridDepsInfos();
this.ModuleService.logMissingAgGridDepsInfos();
this.logger.info('Registered AG Grid modules (including dependents):', this.agGridModulesAdapter.getAgGridRegisteredModuleNames().sort());
this.deriveAdaptableColumnStateFromAgGrid();
this.agGridColumnAdapter.setupColumns();
this.lifecycleState = 'available';
this.api.themeApi.applyCurrentTheme();
this.validatePrimaryKey();
this.checkShouldClearExistingFiltersOrSearches();
const filteringApplied = this.applyFiltering();
if (!filteringApplied) {
this.refreshInitialSortIfNeeded();
}
const quickSearchState = this.api.stateApi.getQuickSearchState();
if (quickSearchState.QuickSearchText) {
this.setAgGridFindSearchValue(quickSearchState.QuickSearchText);
}
else {
this.applyQuickSearchFindCssVars();
}
this.addGridEventListeners();
this.temporaryAdaptableStateUpdates();
this.redrawBody();
this.refreshHeader();
const currentLayout = this.api.layoutApi.getCurrentLayout();
checkForDuplicateColumns(currentLayout);
this._prevLayout = currentLayout;
this.__prevLayoutForRefresh = currentLayout;
const layoutModelForApply = layoutStateToLayoutModel(currentLayout);
this.layoutManager.applyRowGroupValues(layoutModelForApply.RowGroupValues, layoutModelForApply.RowGroupedColumns);
this.layoutManager.applyColumnGroupCollapseExpandState(layoutModelForApply);
this.autoSizeLayoutIfNeeded();
this.ModuleService.createModuleUIItems();
const adaptableContainerElem = this.getAdaptableContainerElement();
if (adaptableContainerElem != null) {
adaptableContainerElem.innerHTML = '';
if (this.variant === 'react') {
this._PRIVATE_adaptableJSXElement = AdaptableApp({ Adaptable: this });
}
else {
this.unmountReactRoot = this.renderReactRoot(AdaptableApp({ Adaptable: this }), adaptableContainerElem);
}
}
this.lifecycleState = 'ready';
this.forPlugins((plugin) => plugin.onAdaptableReady(this, this.adaptableOptions));
setTimeout(() => {
this.api?.eventApi?.emit('AdaptableReady', {
adaptableApi: this.api,
agGridApi: this.agGridAdapter.getAgGridApi(),
});
});
perfInitAdaptableAgGrid.end();
initMarker.end();
return Promise.resolve(this.api);
}
midwayDestroy() {
this.destroy({
destroyAgGrid: false,
unmount: false,
});
}
normalizeAdaptableState(state, agGridOptions) {
state = stripDeprecatedStateKeys(state, this.logger);
state = this.normaliseLayoutState(state, agGridOptions);
state = this.normaliseToolPanelState(state);
return state;
}
normaliseLayoutState(state, gridOptions) {
const layoutState = state.Layout;
if (!layoutState || !layoutState.Layouts?.length) {
this.logger.consoleError('No Layouts defined in InitialState.Layout.Layouts[]. At least one Layout is required.');
}
if (!layoutState.CurrentLayout ||
!layoutState.Layouts.find((l) => l.Name === layoutState.CurrentLayout)) {
layoutState.CurrentLayout = layoutState.Layouts?.[0]?.Name;
}
if (gridOptions.rowModelType === 'viewport') {
if (state.Layout.Layouts) {
state.Layout.Layouts = state.Layout.Layouts.filter((layout) => {
if (isPivotLayout(layout)) {
return false;
}
if (layout.RowGroupedColumns) {
delete layout.RowGroupedColumns;
}
if (layout.TableAggregationColumns) {
delete layout.TableAggregationColumns;
}
return true;
});
}
}
if (state.Layout.Layouts) {
const normalizeOptions = {
isTree: !!gridOptions.treeData,
};
state.Layout.Layouts = state.Layout.Layouts.map((layout) => normalizeLayout(layout, normalizeOptions));
state.Layout.Layouts = state.Layout.Layouts.map((layout) => {
if (Array.isArray(layout.ColumnFilters)) {
layout.ColumnFilters = layout.ColumnFilters.map((columnFilter) => {
if (columnFilter.ColumnId === AG_GRID_GROUPED_COLUMN) {
if (Array.isArray(columnFilter.Predicates)) {
columnFilter.Predicates = columnFilter.Predicates.map((predicate) => {
if (predicate.PredicateId === 'In' || predicate.PredicateId === 'NotIn') {
if (Array.isArray(predicate.Inputs)) {
predicate.Inputs = predicate.Inputs.map((input) => {
if (!Array.isArray(input)) {
return [input];
}
return input;
});
}
}
return predicate;
});
}
}
return columnFilter;
});
}
return layout;
});
}
return state;
}
normaliseToolPanelState(state) {
if (state?.ToolPanel?.ToolPanels) {
return state;
}
const defaultToolPanels = [];
this.adaptableOptions.toolPanelOptions?.customToolPanels?.forEach((customToolPanel) => defaultToolPanels.push({ Name: customToolPanel.name }));
ALL_TOOL_PANELS.forEach((moduleToolPanel) => defaultToolPanels.push({ Name: moduleToolPanel }));
const toolPanelState = state.ToolPanel || {};
toolPanelState.ToolPanels = defaultToolPanels;
state.ToolPanel = toolPanelState;
return state;
}
getCurrentLayoutModel() {
const currentLayout = this.api.layoutApi.getCurrentLayout();
if (!currentLayout) {
return null;
}
return layoutStateToLayoutModel(currentLayout);
}
silentUpdateCurrentLayoutModel(layoutModel = this.getCurrentLayoutModel()) {
if (!layoutModel) {
return;
}
this.layoutManager.silentSetCurrentLayout(layoutModel, {
normalize: true,
});
}
getDefaultColumnWidthForCol(columnId) {
return this.layoutManager.getDefaultColumnWidthForCol(columnId);
}
applyFiltering(config) {
let filteringApplied = false;
const updateColumnFilterModel = config?.updateColumnFilterModel ?? true;
const agGridApi = this.agGridAdapter.getAgGridApi();
if (updateColumnFilterModel) {
const columnFilters = this.api.filterApi.columnFilterApi
.getActiveColumnFilters()
.filter((columnFilter) => this.api.filterApi.columnFilterApi.isColumnFilterActive(columnFilter));
const filterModel = {};
columnFilters.forEach((columnFilter) => {
filterModel[columnFilter.ColumnId] = columnFilter;
});
agGridApi.setFilterModel(filterModel);
filteringApplied = Object.keys(filterModel).length > 0;
}
this.refreshSelectedCellsState();
this.refreshSelectedRowsState();
if (!filteringApplied) {
agGridApi.onFilterChanged();
filteringApplied = true;
}
this._emit('AdapTableFiltersApplied');
return filteringApplied;
}
refreshInitialSortIfNeeded() {
const currentLayout = this.api.layoutApi.getCurrentLayout();
const columnSorts = currentLayout?.ColumnSorts;
if (!columnSorts || columnSorts.length === 0) {
return;
}
const hasCustomSortForSortedColumn = columnSorts.some((columnSort) => {
const customSort = this.api.customSortApi.getCustomSortForColumn(columnSort.ColumnId);
if (customSort && !customSort.IsSuspended) {
return true;
}
if (this.api.customSortApi.internalApi.columnHasCustomSortComparer(columnSort.ColumnId)) {
return true;
}
return false;
});
if (hasCustomSortForSortedColumn) {
this.layoutManager.refreshSort();
}
}
showQuickFilter() {
const height = this.api.optionsApi.getFilterOptions().columnFilterOptions.quickFilterHeight;
this.agGridAdapter.getAgGridApi().setGridOption('floatingFiltersHeight', height);
}
hideQuickFilter() {
this.agGridAdapter.getAgGridApi().setGridOption('floatingFiltersHeight', 0);
}
showAdaptableToolPanel() {
if (!this.hasAdaptableToolPanel) {
if (this.api.entitlementApi.isModuleHiddenEntitlement('ToolPanel')) {
return;
}
const currentSideBar = this.agGridAdapter.getGridOption('sideBar');
if (currentSideBar?.toolPanels) {
const updatedSideBar = {
...currentSideBar,
toolPanels: [...currentSideBar.toolPanels, this.buildAdaptableToolPanelDef()],
};
this.agGridAdapter.setGridOption('sideBar', updatedSideBar);
this.hasAdaptableToolPanel = true;
}
}
}
hideAdaptableToolPanel() {
if (this.hasAdaptableToolPanel) {
this.api.toolPanelApi.closeAdapTableToolPanel();
const currentSideBar = this.agGridAdapter.getGridOption('sideBar');
if (currentSideBar?.toolPanels) {
const updatedSideBar = {
...currentSideBar,
toolPanels: currentSideBar.toolPanels.filter((toolPanelDef) => {
if (typeof toolPanelDef === 'string') {
return toolPanelDef !== GeneralConstants.ADAPTABLE_TOOLPANEL_ID;
}
return toolPanelDef.id !== GeneralConstants.ADAPTABLE_TOOLPANEL_ID;
}),
};
this.agGridAdapter.setGridOption('sideBar', updatedSideBar);
}
this.hasAdaptableToolPanel = false;
}
}
buildAdaptableToolPanelDef() {
return {
id: GeneralConstants.ADAPTABLE_TOOLPANEL_ID,
toolPanel: GeneralConstants.ADAPTABLE_TOOLPANEL_COMPONENT,
labelDefault: GeneralConstants.ADAPTABLE,
labelKey: 'adaptable',
iconKey: 'menu',
width: UIHelper.getAdaptableToolPanelWidth(),
minWidth: UIHelper.getAdaptableToolPanelWidth(),
};
}
showAdaptableStatusBar() {
if (!this.hasAdaptableStatusBar && this.adaptableStatusPanelDefs.length > 0) {
const currentStatusBar = this.agGridAdapter.getGridOption('statusBar');
if (currentStatusBar) {
const existingNonAdaptablePanels = (currentStatusBar.statusPanels ?? []).filter((panel) => !this.adaptableStatusPanelKeys.includes(panel.key));
const updatedStatusBar = {
...currentStatusBar,
statusPanels: [...existingNonAdaptablePanels, ...this.adaptableStatusPanelDefs],
};
this.agGridAdapter.setGridOption('statusBar', updatedStatusBar);
this.hasAdaptableStatusBar = true;
}
}
}
hideAdaptableStatusBar() {
if (this.hasAdaptableStatusBar) {
const currentStatusBar = this.agGridAdapter.getGridOption('statusBar');
if (currentStatusBar?.statusPanels) {
const updatedStatusBar = {
...currentStatusBar,
statusPanels: currentStatusBar.statusPanels.filter((panel) => !this.adaptableStatusPanelKeys.includes(panel.key)),
};
this.agGridAdapter.setGridOption('statusBar', updatedStatusBar);
}
this.hasAdaptableStatusBar = false;
}
}
normalizeAdaptableOptions(adaptableOptions) {
if (this.hasAutogeneratedPrimaryKey) {
this.logger.warn(`Autogenerated primary key is enabled (adaptableOptions.autogeneratedPrimaryKey = true). This should be a last resort as it limits some Adaptable features. See: ${PrimaryKeyDocsLink}`);
this.adaptableOptions.primaryKey = AUTOGENERATED_PK_COLUMN;
return this.adaptableOptions;
}
if (StringExtensions.IsNullOrEmpty(adaptableOptions.primaryKey)) {
this.logger.consoleError(`adaptableOptions.primaryKey is required and must not be empty. As a fallback, set adaptableOptions.autogeneratedPrimaryKey = true. See: ${PrimaryKeyDocsLink}`);
}
return adaptableOptions;
}
setInitialGridOptions(gridOptions, variant) {
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'context', (original_context) => {
const userContext = original_context || {};
return {
...userContext,
__adaptable: this,
adaptableApi: this.api,
};
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'gridId', (original_gridId) => {
let agGridId = original_gridId || this.adaptableOptions.adaptableId;
if (this._isDetailGridForIndex != null) {
agGridId = `${agGridId}_detail-${this._isDetailGridForIndex}`;
}
this.agGridAdapter.setAgGridId(agGridId);
return agGridId;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'defaultColDef', (original_defaultColDef) => {
if (original_defaultColDef?.headerValueGetter) {
this.logger.warn('defaultColDef.headerValueGetter overrides the Adaptable header mechanism. Consider using ColumnOptions.columnHeader instead.');
return original_defaultColDef;
}
const defaultColDef = { ...original_defaultColDef };
defaultColDef.headerValueGetter = tagProvidedByAdaptable((params) => {
const columnHeaderName = this.api.columnApi.internalApi.getColumnHeaderName(params);
const formattedHeaderName = this.api.formatColumnApi.internalApi.formatColumnHeaderName(columnHeaderName, params);
return formattedHeaderName;
});
return defaultColDef;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'defaultColGroupDef', (original_defaultColGroupDef) => {
if (original_defaultColGroupDef?.headerValueGetter) {
this.logger.warn('defaultColGroupDef.headerValueGetter overrides the Adaptable header mechanism. Consider using ColumnOptions.tableColumnHeader instead.');
return original_defaultColGroupDef;
}
const defaultColGroupDef = { ...original_defaultColGroupDef };
defaultColGroupDef.headerValueGetter = tagProvidedByAdaptable((params) => {
return this.api.columnApi.internalApi.getColumnHeaderName(params);
});
return defaultColGroupDef;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'autoGroupColumnDef', (original_autoGroupColumnDef) => {
const useAdaptableFilter = this.adaptableOptions.filterOptions.useAdaptableFiltering;
if (!useAdaptableFilter) {
return original_autoGroupColumnDef;
}
if (original_autoGroupColumnDef?.filter === false) {
this.logger.info('autoGroupColumnDef.filter is disabled via user configuration.');
return original_autoGroupColumnDef;
}
if (typeof original_autoGroupColumnDef?.filter === 'object') {
this.logger.consoleWarn('autoGroupColumnDef.filter overrides the Adaptable filtering mechanism for the Group Column. Adaptable-managed filters will not apply to this column. Contact support for alternatives.');
return original_autoGroupColumnDef;
}
const autoGroupColumnDef = { ...original_autoGroupColumnDef };
autoGroupColumnDef.filterValueGetter = (params) => {
this.logger.consoleWarn('Unexpected invocation of autoGroupColumnDef.filterValueGetter. This is not expected under normal operation. Please contact support.', params);
return '';
};
const autoGroupFilterComponent = AgGridFilterAdapterFactory(this);
const autoGroupFilterHandlerGenerator = () => new AdaptableFilterHandler(this.api);
Object.defineProperty(autoGroupColumnDef, 'filter', {
get: () => {
if (this.isDestroyed) {
return;
}
const rowGroupDisplayType = this.api.layoutApi.internalApi.getCurrentLayoutRowGroupDisplayType();
if (rowGroupDisplayType === 'single') {
return {
component: autoGroupFilterComponent,
handler: autoGroupFilterHandlerGenerator,
};
}
if (rowGroupDisplayType === 'multi') {
return 'agGroupColumnFilter';
}
return original_autoGroupColumnDef?.filter;
},
enumerable: true,
configurable: true,
});
if (original_autoGroupColumnDef?.floatingFilter !== false) {
autoGroupColumnDef.suppressFloatingFilterButton = true;
Object.defineProperty(autoGroupColumnDef, 'floatingFilter', {
get: () => {
if (this.isDestroyed) {
return;
}
const rowGroupDisplayType = this.api.layoutApi.internalApi.getCurrentLayoutRowGroupDisplayType();
if (rowGroupDisplayType === 'single') {
return true;
}
return original_autoGroupColumnDef?.floatingFilter;
},
enumerable: true,
configurable: true,
});
const autoGroupFloatingFilterComponent = AgGridFloatingFilterAdapterFactory(this);
Object.defineProperty(autoGroupColumnDef, 'floatingFilterComponent', {
get: () => {
if (this.isDestroyed) {
return;
}
const rowGroupDisplayType = this.api.layoutApi.internalApi.getCurrentLayoutRowGroupDisplayType();
if (rowGroupDisplayType === 'single') {
return autoGroupFloatingFilterComponent;
}
return;
},
enumerable: true,
configurable: true,
});
}
return autoGroupColumnDef;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'theme', (original_theme) => {
this.agGridThemeAdapter.setAgGridThemeMode(original_theme === 'legacy' ? 'legacy' : 'themingApi');
return original_theme;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'getRowId', (original_getRowId) => {
if (original_getRowId) {
return original_getRowId;
}
const primaryKey = this.adaptableOptions.primaryKey;
if (StringExtensions.IsNullOrEmpty(primaryKey)) {
return original_getRowId;
}
if (this.hasAutogeneratedPrimaryKey) {
return (params) => {
if (Helper.objectNotExists(params.data[primaryKey])) {
params.data[primaryKey] = createUuid();
}
return params.data[primaryKey];
};
}
return (params) => {
if (params.data?.[ROW_SUMMARY_ROW_ID] != undefined) {
return params.data[ROW_SUMMARY_ROW_ID];
}
if (params.level > 0) {
const parentKeys = params.parentKeys ?? [];
const values = Object.values(params.data);
let hash = 0;
for (let i = 0; i < values.length; i++) {
const str = String(values[i] ?? '');
for (let j = 0; j < str.length; j++) {
hash = ((hash << 5) - hash + str.charCodeAt(j)) | 0;
}
}
const id = [...parentKeys, Math.abs(hash)].join('/');
return id;
}
if (params.data?.[primaryKey] != undefined) {
const primaryKeyValue = params.data[primaryKey];
return typeof primaryKeyValue === 'number'
? `${primaryKeyValue}`
: params.data[primaryKey];
}
const parentKeys = params.parentKeys ?? [];
const values = Object.values(params.data);
if (values.length) {
const id = [...parentKeys, values[0]].join('/');
return id;
}
};
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'grandTotalRow', (original_grandTotalRow) => {
const currentLayout = this.api.layoutApi.getCurrentLayout();
if (!currentLayout) {
return original_grandTotalRow;
}
return currentLayout.GrandTotalRow === true
? 'top'
: currentLayout.GrandTotalRow === false
? undefined
: currentLayout.GrandTotalRow;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'suppressAggFuncInHeader', (original_suppressAggFuncInHeader) => {
const currentLayout = this.api.layoutApi.getCurrentLayout();
if (!currentLayout) {
return original_suppressAggFuncInHeader;
}
return currentLayout.SuppressAggFuncInHeader;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'aggFuncs', (original_aggFuncs) => {
const aggregationFunctions = original_aggFuncs || {};
aggregationFunctions[ONLY_AGG_FN_NAME] = (params) => {
return only(params);
};
aggregationFunctions[WEIGHTED_AVERAGE_AGG_FN_NAME] = (params) => {
const columnId = params.column.getColId();
const adaptableAggFunc = this.getActiveAdaptableAggFuncForCol(columnId);
if (!adaptableAggFunc) {
return undefined;
}
if (adaptableAggFunc.type === 'weightedAverage') {
return weightedAverage(params, params.colDef.colId, adaptableAggFunc.weightedColumnId);
}
return undefined;
};
return aggregationFunctions;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'allowContextMenuWithControlKey', (original_allowContextMenuWithControlKey) => {
return original_allowContextMenuWithControlKey === undefined
? true
: original_allowContextMenuWithControlKey;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'enableFilterHandlers', (original_enableFilterHandlers) => {
const useAdaptableFiltering = this.api.optionsApi.getFilterOptions().useAdaptableFiltering;
if (useAdaptableFiltering) {
return true;
}
return original_enableFilterHandlers;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'suppressSetFilterByDefault', (original_suppressSetFilterByDefault) => {
const useAdaptableFiltering = this.api.optionsApi.getFilterOptions().useAdaptableFiltering;
if (useAdaptableFiltering) {
return true;
}
return original_suppressSetFilterByDefault;
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'isExternalFilterPresent', (original_isExternalFilterPresent) => {
return (params) => {
if (!this.isAvailable) {
return false;
}
const isGridFilterActive = StringExtensions.IsNotNullOrEmpty(this.api.filterApi.gridFilterApi.getCurrentGridFilterExpression());
return (isGridFilterActive ||
(original_isExternalFilterPresent ? original_isExternalFilterPresent(params) : false));
};
});
this.agGridOptionsService.setGridOptionsProperty(gridOptions, 'doesExternalFilterPass', (original_doesExternalFilterPass) => {
return (node) => {
if (!this.isAvailable) {
return true;
}
if (this.isGroupRowNode(node)) {
if (this.api.gridApi.isTreeDataGrid()) {
if (node.data == undefined) {
return false;
}
}
else {
return true;
}
}
const isRowFilterable = this.api.gridApi.internalApi.isRowFilterable(node);
if (!isRowFilterable) {
return true;