Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable consistent-return */
/* eslint-disable no-param-reassign */

/* eslint-disable @typescript-eslint/no-this-alias */
/* eslint-disable @typescript-eslint/init-declarations */
/* eslint-disable no-self-compare */
Expand All @@ -13,35 +12,30 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
import { compileGetter } from '@js/core/utils/data';
import { extend } from '@js/core/utils/extend';
import { each, map } from '@js/core/utils/iterator';
import { each } from '@js/core/utils/iterator';
import {
isDefined, isEmptyObject, isString,
} from '@js/core/utils/type';
import errors from '@js/ui/widget/ui.errors';
import type { DataSource } from '@ts/data/data_source/types';
import type { DataController } from '@ts/grids/grid_core/data_controller/data_controller';
import type { EditingController } from '@ts/grids/grid_core/editing/m_editing';
import type { ModuleType } from '@ts/grids/grid_core/m_types';

import gridCore from '../../m_core';
import { DATAGRID_GROUP_FOOTER_ROW_TYPE, DATAGRID_TOTAL_FOOTER_ROW_TYPE } from '../const';
import type { CalculateSummaryCellsArgs, ColumnMap, SummaryCellItem } from '../types';
import type {
CalculateSummaryCellsArgs, ColumnMap, SummaryCellItem,
} from '../types';
import { getColumnFromMap, getSummaryCellIndex } from '../utils';

const getGroupAggregates = (data) => data.summary || data.aggregates || [];
import { getGroupAggregates } from '../utils/get_group_aggregates';
import { getSummaryItemIndex } from '../utils/get_summary_item_index';

export const summaryDataControllerExtender = (
Base: ModuleType<DataController>,
): ModuleType<DataController> => class SummaryDataControllerExtender extends Base {
private _footerItems!: any[];

protected _editingController!: EditingController;

public init(): void {
this._footerItems = [];
this._editingController = this.getController('editing');
super.init();
}

Expand Down Expand Up @@ -277,205 +271,12 @@ export const summaryDataControllerExtender = (
super._updateItemsCore(change);
}

private _prepareUnsavedDataSelector(selector) {
if (this.option('summary.recalculateWhileEditing')) {
const editingController = this._editingController;
if (editingController) {
return function (data) {
data = editingController.getUpdatedData(data);
return selector(data);
};
}
}

return selector;
}

private _prepareAggregateSelector(selector, aggregator) {
selector = this._prepareUnsavedDataSelector(selector);

if (aggregator === 'avg' || aggregator === 'sum') {
return function (data) {
const value = selector(data);
return isDefined(value) ? Number(value) : value;
};
}

return selector;
}

private _getAggregates(summaryItems, remoteOperations) {
const that = this;
let calculateCustomSummary: any = that.option('summary.calculateCustomSummary');
const commonSkipEmptyValues = that.option('summary.skipEmptyValues');

return map(summaryItems || [], (summaryItem) => {
const column = this._columnsController.columnOption(summaryItem.column);
const calculateCellValue = column?.calculateCellValue ? column.calculateCellValue.bind(column) : compileGetter(column ? column.dataField : summaryItem.column);
let aggregator = summaryItem.summaryType || 'count';
const skipEmptyValues = isDefined(summaryItem.skipEmptyValues) ? summaryItem.skipEmptyValues : commonSkipEmptyValues;

if (remoteOperations) {
return {
selector: summaryItem.column,
summaryType: aggregator,
};
}
const selector = that._prepareAggregateSelector(calculateCellValue, aggregator);

if (aggregator === 'custom') {
if (!calculateCustomSummary) {
errors.log('E1026');
calculateCustomSummary = function () { };
}
const options: any = {
component: that.component,
name: summaryItem.name,
};
calculateCustomSummary(options);
options.summaryProcess = 'calculate';
aggregator = {
seed(groupIndex) {
options.summaryProcess = 'start';
options.totalValue = undefined;
options.groupIndex = groupIndex;
delete options.value;
calculateCustomSummary(options);
return options.totalValue;
},
step(totalValue, value) {
options.summaryProcess = 'calculate';
options.totalValue = totalValue;
options.value = value;
calculateCustomSummary(options);
return options.totalValue;
},
finalize(totalValue) {
options.summaryProcess = 'finalize';
options.totalValue = totalValue;
delete options.value;
calculateCustomSummary(options);
return options.totalValue;
},
};
}
return {
selector,
aggregator,
skipEmptyValues,
};
});
}

private _addSortInfo(sortByGroups, groupColumn, selector, sortOrder) {
if (groupColumn) {
const { groupIndex } = groupColumn;
sortOrder = sortOrder || groupColumn.sortOrder;
if (isDefined(groupIndex)) {
sortByGroups[groupIndex] = sortByGroups[groupIndex] || [];
sortByGroups[groupIndex].push({
selector,
desc: sortOrder === 'desc',
});
}
}
}

private _findSummaryItem(summaryItems, name) {
let summaryItemIndex: any = -1;

const getFullName = function (summaryItem) {
const { summaryType } = summaryItem;
const { column } = summaryItem;

return summaryType && column && `${summaryType}_${column}`;
};

if (isDefined(name)) {
// @ts-expect-error
each(summaryItems || [], function (index) {
if (this.name === name || index === name || this.summaryType === name || this.column === name || getFullName(this) === name) {
summaryItemIndex = index;
return false;
}
});
}
return summaryItemIndex;
}

private _getSummarySortByGroups(sortByGroupSummaryInfo, groupSummaryItems) {
const that = this;
const columnsController = that._columnsController;
const groupColumns = columnsController.getGroupColumns();
const sortByGroups = [];

if (!groupSummaryItems?.length) return;

each(sortByGroupSummaryInfo || [], function () {
const { sortOrder } = this;
let { groupColumn } = this;
const summaryItemIndex = that._findSummaryItem(groupSummaryItems, this.summaryItem);

if (summaryItemIndex < 0) return;

const selector = function (data) {
return getGroupAggregates(data)[summaryItemIndex];
};

if (isDefined(groupColumn)) {
groupColumn = columnsController.columnOption(groupColumn);
that._addSortInfo(sortByGroups, groupColumn, selector, sortOrder);
} else {
each(groupColumns, (groupIndex, groupColumn) => {
that._addSortInfo(sortByGroups, groupColumn, selector, sortOrder);
});
}
});
return sortByGroups;
}

protected _createDataSourceAdapter(dataSource: DataSource) {
const dataSourceAdapter = super._createDataSourceAdapter(dataSource);

// @ts-expect-error summaryGetter is defined in summary DataSourceAdapterExtender
dataSourceAdapter.summaryGetter((currentRemoteOperations) => {
const result = this._getSummaryOptions(
currentRemoteOperations ?? dataSourceAdapter.remoteOperations(),
);
return result;
});

return dataSourceAdapter;
}

private _getSummaryOptions(remoteOperations) {
const that = this;
const groupSummaryItems = that.option('summary.groupItems');
const totalSummaryItems = that.option('summary.totalItems');
const sortByGroupSummaryInfo = that.option('sortByGroupSummaryInfo');
const groupAggregates = that._getAggregates(groupSummaryItems, remoteOperations?.grouping && remoteOperations.summary);
const totalAggregates = that._getAggregates(totalSummaryItems, remoteOperations?.summary);
const sortByGroups = function () {
return that._getSummarySortByGroups(sortByGroupSummaryInfo, groupSummaryItems);
};

if (groupAggregates.length || totalAggregates.length) {
return {
groupAggregates,
totalAggregates,
sortByGroups,
};
}

return undefined;
}

public publicMethods(): string[] {
return [...super.publicMethods(), 'getTotalSummaryValue'];
}

private getTotalSummaryValue(summaryItemName) {
const summaryItemIndex = this._findSummaryItem(this.option('summary.totalItems'), summaryItemName);
const summaryItemIndex = getSummaryItemIndex(this.option('summary.totalItems'), summaryItemName);
const aggregates = this._dataSource.totalAggregates();

if (aggregates.length && summaryItemIndex > -1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import dataQuery from '@js/common/data/query';
import storeHelper from '@js/common/data/store_helper';
import { normalizeSortingInfo } from '@js/common/data/utils';
import $ from '@js/core/renderer';
import { noop } from '@js/core/utils/common';
import { extend } from '@js/core/utils/extend';
import { each } from '@js/core/utils/iterator';
import { isDefined, isFunction, isPlainObject } from '@js/core/utils/type';
import { isDefined, isPlainObject } from '@js/core/utils/type';
import type { DataSource } from '@ts/data/data_source/types';
import type { ColumnsController } from '@ts/grids/grid_core/columns_controller/m_columns_controller';
import type DataSourceAdapter from '@ts/grids/grid_core/data_source_adapter/m_data_source_adapter';
import type { RemoteOperationsOptions } from '@ts/grids/grid_core/data_source_adapter/types';
import type { EditingControllerRequired, ModuleType } from '@ts/grids/grid_core/m_types';
import { ColumnsView } from '@ts/grids/grid_core/views/m_columns_view';

Expand All @@ -27,6 +29,8 @@ import {
DATAGRID_TOTAL_FOOTER_CLASS,
DATAGRID_TOTAL_FOOTER_ROW_TYPE,
} from './const';
import type { SummaryOptions } from './types';
import { getSummaryOptions } from './utils/get_summary_options';

export const renderSummaryCell = function (cell, options, setAria) {
const $cell = $(cell);
Expand Down Expand Up @@ -149,7 +153,7 @@ const calculateAggregates = function (that: EditingControllerRequired, summary,
let calculator;

if ((that as any).option('summary.recalculateWhileEditing')) {
const editingController = that._editingController;
const { editingController } = that;
if (editingController) {
const insertedData = editingController.getInsertedData();
if (insertedData.length) {
Expand Down Expand Up @@ -284,42 +288,44 @@ export class FooterView extends ColumnsView {
export const dataSourceAdapterExtender = (Base: ModuleType<DataSourceAdapter>) => class SummaryDataSourceAdapterExtender extends Base implements EditingControllerRequired {
private _totalAggregates: any;

private _summaryGetter: any;
private columnsController!: ColumnsController;

public _editingController!: EditingController;
public editingController!: EditingController;

public init() {
super.init.apply(this, arguments as any);
public init(dataSource?: DataSource): void {
super.init(dataSource);

this._editingController = this.getController('editing');
this.columnsController = this.getController('columns');
this.editingController = this.getController('editing');
this._totalAggregates = [];
this._summaryGetter = noop;
}

private summaryGetter(summaryGetter?) {
if (!arguments.length) {
return this._summaryGetter;
}
private getSummary(remoteOperations?: RemoteOperationsOptions): SummaryOptions | undefined {
const summary = this.option('summary');

if (isFunction(summaryGetter)) {
this._summaryGetter = summaryGetter;
if (!summary) {
return undefined;
}
}

private summary(summary?) {
if (!arguments.length) {
return this._summaryGetter();
}
const result = getSummaryOptions({
summary,
sortByGroupSummaryInfo: this.option('sortByGroupSummaryInfo'),
remoteOperations: remoteOperations ?? this.remoteOperations(),
getUpdatedItemData: (data) => this.editingController.getUpdatedData(data),
columnOption: (id) => this.columnsController.columnOption(id),
groupColumns: this.columnsController.getGroupColumns(),
component: this.component as any,
});

this._summaryGetter = function () { return summary; };
return result;
}

private totalAggregates() {
return this._totalAggregates;
}

private isLastLevelGroupItemsPagingLocal() {
const summary = this.summary();
const summary = this.getSummary();
const sortByGroupsInfo = summary?.sortByGroups();

return sortByGroupsInfo?.length;
Expand All @@ -342,7 +348,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType<DataSourceAdapter>) =
}

protected _customizeRemoteOperations(options) {
const summary = this.summary();
const summary = this.getSummary();

if (summary) {
if (options.remoteOperations.summary) {
Expand Down Expand Up @@ -372,7 +378,7 @@ export const dataSourceAdapterExtender = (Base: ModuleType<DataSourceAdapter>) =
protected customizeLoadResultHandlerCore(options) {
const groups = normalizeSortingInfo(options.storeLoadOptions.group || options.loadOptions.group || []);
const remoteOperations = options.remoteOperations || {};
const summary = this.summaryGetter()(remoteOperations);
const summary = this.getSummary(remoteOperations);

if (!options.isCustomLoading || options.storeLoadOptions.isLoadingAll) {
if (remoteOperations.summary) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import messageLocalization from '@js/common/core/localization/message';
import type { SortByGroupSummaryInfoItem, Summary } from '@js/ui/data_grid';

import gridCore from '../m_core';
import dataSourceAdapterProvider from '../m_data_source_adapter';
Expand All @@ -11,7 +12,10 @@ import {
dataSourceAdapterProvider.extend(dataSourceAdapterExtender);

gridCore.registerModule('summary', {
defaultOptions() {
defaultOptions(): {
summary: Summary,
sortByGroupSummaryInfo: SortByGroupSummaryInfoItem[] | undefined
} {
return {
summary: {
groupItems: undefined,
Expand Down
Loading
Loading