UNPKG

@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
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;