@gooddata/react-components
Version:
GoodData.UI - A powerful JavaScript library for building analytical applications
919 lines • 62.7 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var ag_grid_react_1 = require("ag-grid-react");
var classNames = require("classnames");
var CustomEvent = require("custom-event");
var invariant = require("invariant");
var React = require("react");
require("../../../styles/css/pivotTable.css");
var visualizationTypes_1 = require("../../constants/visualizationTypes");
var domUtils_1 = require("../../helpers/domUtils");
var headerPredicate_1 = require("../../helpers/headerPredicate");
var tableCell_1 = require("../../helpers/tableCell");
var DrillEvents_1 = require("../../interfaces/DrillEvents");
var MappingHeader_1 = require("../../interfaces/MappingHeader");
var PivotTable_1 = require("../../interfaces/PivotTable");
var LoadingComponent_1 = require("../simple/LoadingComponent");
var utils_1 = require("../visualizations/table/totals/utils");
var BaseVisualization_1 = require("./base/BaseVisualization");
var VisualizationLoadingHOC_1 = require("./base/VisualizationLoadingHOC");
var aggregationsMenuHelper_1 = require("./pivotTable/aggregationsMenuHelper");
var agGridApiWrapper_1 = require("./pivotTable/agGridApiWrapper");
var agGridConst_1 = require("./pivotTable/agGridConst");
var agGridDataSource_1 = require("./pivotTable/agGridDataSource");
var agGridDrilling_1 = require("./pivotTable/agGridDrilling");
var agGridSorting_1 = require("./pivotTable/agGridSorting");
var agGridUtils_1 = require("./pivotTable/agGridUtils");
var ColumnGroupHeader_1 = require("./pivotTable/ColumnGroupHeader");
var ColumnHeader_1 = require("./pivotTable/ColumnHeader");
var GroupingProvider_1 = require("./pivotTable/GroupingProvider");
var RowLoadingElement_1 = require("./pivotTable/RowLoadingElement");
var stickyRowHandler_1 = require("./pivotTable/stickyRowHandler");
var utils_2 = require("../../helpers/utils");
var drilldownEventing_1 = require("../visualizations/utils/drilldownEventing");
var drilldownEventingLegacy_1 = require("../visualizations/utils/drilldownEventingLegacy");
var cloneDeep = require("lodash/cloneDeep");
var get = require("lodash/get");
var isEqual = require("lodash/isEqual");
var noop = require("lodash/noop");
var sumBy = require("lodash/sumBy");
var difference = require("lodash/difference");
var debounce = require("lodash/debounce");
var agGridColumnSizing_1 = require("./pivotTable/agGridColumnSizing");
var agColumnWrapper_1 = require("./pivotTable/agColumnWrapper");
var ResizedColumnsStore_1 = require("./pivotTable/ResizedColumnsStore");
var DEFAULT_ROW_HEIGHT = 28;
var DEFAULT_AUTOSIZE_PADDING = 10;
var AG_NUMERIC_CELL_CLASSNAME = "ag-numeric-cell";
var AG_NUMERIC_HEADER_CLASSNAME = "ag-numeric-header";
exports.WATCHING_TABLE_RENDERED_INTERVAL = 500;
var AGGRID_RENDER_NEW_COLUMNS_TIMEOUT = 100;
var AGGRID_BEFORE_RESIZE_TIMEOUT = 100;
var AGGRID_ON_RESIZE_TIMEOUT = 300;
var COLUMN_RESIZE_TIMEOUT = 300;
exports.DEFAULT_COLUMN_WIDTH = 200;
/**
* Pivot Table react component
*/
var PivotTableInner = /** @class */ (function (_super) {
__extends(PivotTableInner, _super);
function PivotTableInner(props) {
var _this = _super.call(this, props) || this;
_this.lastScrollPosition = {
top: 0,
left: 0,
};
_this.autoResizedColumns = {};
_this.growToFittedColumns = {};
_this.resizing = false;
_this.lastResizedWidth = 0;
_this.lastResizedHeight = 0;
_this.numberOfColumnResizedCalls = 0;
_this.columnWidthsChangeWaitingForExecution = true;
_this.isMetaOrCtrlKeyPressed = false;
_this.isAltKeyPressed = false;
//
// getters / setters / manipulators
//
_this.setContainerRef = function (container) {
_this.containerRef = container;
};
_this.setGroupingProvider = function (sortedByFirstAttr) {
_this.groupingProvider = GroupingProvider_1.GroupingProviderFactory.createProvider(sortedByFirstAttr);
};
_this.updateGrouping = function () {
_this.setGroupingProvider(_this.props.groupRows && _this.state.sortedByFirstAttribute);
};
_this.getExecutionResponse = function () {
return _this.state.execution ? _this.state.execution.executionResponse : null;
};
_this.getExecutionResult = function () {
return _this.state.execution ? _this.state.execution.executionResult : null;
};
_this.getAfmFilters = function () {
return _this.props.dataSource.getAfm().filters || [];
};
_this.getColumnTotals = function () {
return _this.state.columnTotals;
};
_this.getExecution = function () {
return _this.state.execution;
};
_this.getGridApi = function () { return _this.gridApi; };
_this.getColumnIds = function (columns) {
return columns.map(function (column) { return column.getColId(); });
};
_this.getAutoResizedColumns = function (columns) {
return columns.reduce(function (acc, col) {
var _a;
var columnId = agGridUtils_1.getColumnIdentifier(col);
var resizedColumn = acc[columnId];
if (resizedColumn) {
return acc;
}
return __assign({}, acc, (_a = {}, _a[columnId] = {
width: col.getActualWidth(),
}, _a));
}, _this.autoResizedColumns);
};
_this.autoresizeVisibleColumns = function (columnApi, previouslyResizedColumnIds, firstCall) {
if (firstCall === void 0) { firstCall = true; }
return __awaiter(_this, void 0, void 0, function () {
var displayedVirtualColumns, autoWidthColumnIds;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.shouldPerformAutoresize()) {
return [2 /*return*/, Promise.resolve()];
}
if (!this.isColumnAutoresizeEnabled()) {
return [2 /*return*/, Promise.resolve()];
}
if (!firstCall) return [3 /*break*/, 2];
return [4 /*yield*/, utils_2.sleep(AGGRID_BEFORE_RESIZE_TIMEOUT)];
case 1:
_a.sent();
_a.label = 2;
case 2:
displayedVirtualColumns = columnApi.getAllDisplayedVirtualColumns();
autoWidthColumnIds = this.getColumnIds(displayedVirtualColumns);
if (previouslyResizedColumnIds.length >= autoWidthColumnIds.length) {
this.autoResizedColumns = this.getAutoResizedColumns(columnApi.getAllDisplayedVirtualColumns());
return [2 /*return*/, Promise.resolve()];
}
return [2 /*return*/, new Promise(function (resolve) { return __awaiter(_this, void 0, void 0, function () {
var newColumnIds;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
newColumnIds = difference(autoWidthColumnIds, previouslyResizedColumnIds);
this.autoresizeColumnsByColumnId(columnApi, newColumnIds);
return [4 /*yield*/, utils_2.sleep(AGGRID_RENDER_NEW_COLUMNS_TIMEOUT)];
case 1:
_a.sent();
resolve(this.autoresizeVisibleColumns(columnApi, autoWidthColumnIds, false));
return [2 /*return*/];
}
});
}); })];
}
});
});
};
_this.isColumnAutoresizeEnabled = function () { return _this.getDefaultWidthFromProps(_this.props) === "viewport"; };
_this.isGrowToFitEnabled = function (props) {
if (props === void 0) { props = _this.props; }
return props.config && props.config.columnSizing ? !!props.config.columnSizing.growToFit : false;
};
_this.isPivotTableReady = function (api) {
var noRowHeadersOrRows = function (executionResult) {
return executionResult &&
(executionResult.data.length === 0 &&
executionResult.headerItems[0] &&
executionResult.headerItems[0].length === 0);
};
var dataRendered = function () {
var executionResult = _this.getExecutionResult();
return (noRowHeadersOrRows(executionResult) || (executionResult && api.getRenderedNodes().length > 0));
};
var tablePagesLoaded = function () {
var pages = api.getCacheBlockState();
return (pages &&
Object.keys(pages).every(function (pageId) {
return pages[pageId].pageStatus === "loaded" || pages[pageId].pageStatus === "failed";
}));
};
return _this.state.execution && tablePagesLoaded() && dataRendered();
};
_this.autoresizeColumns = function (event, force, previouslyResizedColumnIds) {
if (force === void 0) { force = false; }
if (previouslyResizedColumnIds === void 0) { previouslyResizedColumnIds = []; }
return __awaiter(_this, void 0, void 0, function () {
var alreadyResized, columns;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
alreadyResized = function () { return _this.state.resized || _this.resizing; };
if (!(this.isPivotTableReady(event.api) && (!alreadyResized() || (alreadyResized() && force)))) return [3 /*break*/, 2];
this.resizing = true;
// we need to know autosize width for each column, even manually resized ones, to support removal of columnWidth def from props
return [4 /*yield*/, this.autoresizeVisibleColumns(event.columnApi, previouslyResizedColumnIds)];
case 1:
// we need to know autosize width for each column, even manually resized ones, to support removal of columnWidth def from props
_a.sent();
// after that we need to reset manually resized columns back to its manually set width by growToFit or by helper. See UT resetColumnsWidthToDefault for width priorities
if (this.isGrowToFitEnabled()) {
this.growToFit(event.columnApi);
}
else if (this.shouldPerformAutoresize() && this.isColumnAutoresizeEnabled()) {
columns = this.columnApi.getAllColumns();
this.resetColumnsWidthToDefault(this.columnApi, columns);
}
this.resizing = false;
this.setState({
resized: true,
});
_a.label = 2;
case 2: return [2 /*return*/];
}
});
});
};
_this.gridSizeChanged = function (gridSizeChangedEvent) { return __awaiter(_this, void 0, void 0, function () {
var resizedColumnsGridIds;
return __generator(this, function (_a) {
if (!this.resizing &&
(this.lastResizedWidth !== gridSizeChangedEvent.clientWidth ||
this.lastResizedHeight !== gridSizeChangedEvent.clientHeight)) {
this.lastResizedWidth = gridSizeChangedEvent.clientWidth;
this.lastResizedHeight = gridSizeChangedEvent.clientHeight;
resizedColumnsGridIds = this.mapFieldIdToGridId(gridSizeChangedEvent.columnApi, Object.keys(this.autoResizedColumns));
this.autoresizeColumns(gridSizeChangedEvent, true, resizedColumnsGridIds);
}
return [2 /*return*/];
});
}); };
_this.gridColumnsChanged = function () {
_this.updateStickyRow();
};
_this.shouldAutoResizeColumns = function () {
var columnAutoresize = _this.isColumnAutoresizeEnabled() && _this.getExecution();
var growToFit = _this.isGrowToFitEnabled() && _this.getExecution();
return columnAutoresize || growToFit;
};
_this.onModelUpdated = function (event) { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.shouldAutoResizeColumns()) return [3 /*break*/, 2];
return [4 /*yield*/, this.autoresizeColumns(event)];
case 1:
_a.sent();
this.updateStickyRow();
return [3 /*break*/, 3];
case 2:
if (this.columnApi && this.isGrowToFitEnabled()) {
this.growToFit(this.columnApi);
}
this.updateStickyRow();
_a.label = 3;
case 3: return [2 /*return*/];
}
});
}); };
_this.sortChanged = function (event) { return __awaiter(_this, void 0, void 0, function () {
var execution, sortModel, sortItems;
return __generator(this, function (_a) {
execution = this.getExecution();
invariant(execution, "changing sorts without prior execution cannot work");
sortModel = event.columnApi
.getAllColumns()
.filter(function (col) { return col.getSort() !== undefined && col.getSort() !== null; })
.map(function (col) { return ({
colId: col.getColDef().field,
sort: col.getSort(),
}); });
sortItems = agGridSorting_1.getSortsFromModel(sortModel, execution);
this.props.pushData({
properties: {
sortItems: sortItems,
},
});
this.updateGrouping();
return [2 /*return*/];
});
}); };
//
// event handlers
//
_this.onGridReady = function (params) {
_this.gridApi = params.api;
_this.columnApi = params.columnApi;
_this.setGridDataSource();
if (_this.props.groupRows) {
stickyRowHandler_1.initializeStickyRow(_this.gridApi);
}
};
_this.startWatchingTableRendered = function () {
var missingContainerRef = !_this.containerRef; // table having no data will be unmounted, it causes ref null
var isTableRendered = _this.shouldAutoResizeColumns()
? _this.state.resized
: _this.isPivotTableReady(_this.gridApi);
if (missingContainerRef || isTableRendered) {
_this.stopWatchingTableRendered();
}
};
_this.stopWatchingTableRendered = function () {
clearInterval(_this.watchingIntervalId);
_this.watchingIntervalId = null;
_this.props.afterRender();
};
_this.onFirstDataRendered = function () {
// Since issue here is not resolved, https://github.com/ag-grid/ag-grid/issues/3263,
// work-around by using 'setInterval'
if (!_this.watchingIntervalId) {
// onFirstDataRendered can be called multiple times
_this.watchingIntervalId = window.setInterval(_this.startWatchingTableRendered, exports.WATCHING_TABLE_RENDERED_INTERVAL);
}
};
_this.getItemAndAttributeHeaders = function (attributeItemHeaders, columnDefs) {
return Object.keys(attributeItemHeaders).reduce(function (headers, colId) {
var attributeHeader = _this.getAttributeHeader(colId, columnDefs);
if (attributeHeader) {
headers.push(attributeItemHeaders[colId]);
headers.push(attributeHeader);
}
return headers;
}, []);
};
_this.getAttributeDrillItemsForMeasureDrill = function (cellEvent, columnDefs) {
var rowDrillItems = get(cellEvent, ["data", "headerItemMap"]);
return _this.getItemAndAttributeHeaders(rowDrillItems, columnDefs);
};
_this.isSomeTotal = function (rowType) {
var isRowTotal = rowType === agGridConst_1.ROW_TOTAL;
var isRowSubtotal = rowType === agGridConst_1.ROW_SUBTOTAL;
return isRowTotal || isRowSubtotal;
};
_this.getRowDrillItem = function (cellEvent) {
return get(cellEvent, ["data", "headerItemMap", cellEvent.colDef.field]);
};
_this.getDrillItems = function (cellEvent) {
var colDef = cellEvent.colDef;
var rowDrillItem = _this.getRowDrillItem(cellEvent);
return rowDrillItem ? [rowDrillItem].concat(colDef.drillItems) : colDef.drillItems;
};
_this.getDrillIntersection = function (cellEvent, drillItems, columnDefs) {
var rowDrillItem = _this.getRowDrillItem(cellEvent);
var completeDrillItems = rowDrillItem
? drillItems
: drillItems.concat(_this.getAttributeDrillItemsForMeasureDrill(cellEvent, columnDefs));
return drilldownEventing_1.getDrillIntersection(completeDrillItems);
};
_this.cellClicked = function (cellEvent) {
var _a = _this.props, onDrill = _a.onDrill, executionResponse = _a.execution.executionResponse;
var columnDefs = _this.state.columnDefs;
var afm = _this.props.dataSource.getAfm();
var drillablePredicates = _this.getDrillablePredicates();
var colDef = cellEvent.colDef, rowIndex = cellEvent.rowIndex;
var rowType = get(cellEvent, ["data", "type"], "");
if (_this.isSomeTotal(rowType)) {
return false;
}
var drillItems = _this.getDrillItems(cellEvent);
var drillableHeaders = drillItems.filter(function (drillItem) {
return headerPredicate_1.isSomeHeaderPredicateMatched(drillablePredicates, drillItem, afm, executionResponse);
});
if (drillableHeaders.length === 0) {
return false;
}
var leafColumnDefs = agGridUtils_1.getTreeLeaves(columnDefs);
var columnIndex = leafColumnDefs.findIndex(function (gridHeader) { return gridHeader.field === colDef.field; });
var row = agGridDrilling_1.getDrillRowData(leafColumnDefs, cellEvent.data);
var intersection = _this.getDrillIntersection(cellEvent, drillItems, columnDefs);
var drillContextExtended = {
type: visualizationTypes_1.VisualizationTypes.TABLE,
element: "cell",
columnIndex: columnIndex,
rowIndex: rowIndex,
row: row,
intersection: intersection,
};
var drillEventExtended = {
executionContext: afm,
drillContext: drillContextExtended,
};
if (onDrill) {
onDrill(drillEventExtended);
}
return _this.handleLegacyOnFireDrillEvent(drillEventExtended, cellEvent);
};
_this.handleLegacyOnFireDrillEvent = function (drillEventExtended, cellEvent) {
var onFiredDrillEvent = _this.props.onFiredDrillEvent;
var executionContext = drillEventExtended.executionContext, drillContext = drillEventExtended.drillContext;
// this type guard is here only for casting because drillContext came from event as IDrillEventContextExtended
if (DrillEvents_1.isDrillEventContextTableExtended(drillContext)) {
// Old drill event for backward compatibility
var drillContextLegacy = drilldownEventingLegacy_1.convertDrillContextToLegacy(drillContext, executionContext);
var drillEvent = {
executionContext: executionContext,
drillContext: drillContextLegacy,
};
if (onFiredDrillEvent(drillEvent)) {
// This is needed for /analyze/embedded/ drilling with post message
// tslint:disable-next-line:max-line-length
// More info: https://github.com/gooddata/gdc-analytical-designer/blob/develop/test/drillEventing/drillEventing_page.html
var event_1 = new CustomEvent("drill", {
detail: drillEvent,
bubbles: true,
});
cellEvent.event.target.dispatchEvent(event_1);
return true;
}
}
return false;
};
_this.getDefaultWidth = function () {
return exports.DEFAULT_COLUMN_WIDTH;
};
_this.onGridColumnResized = function (columnEvent) { return __awaiter(_this, void 0, void 0, function () {
var executionResult;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!columnEvent.finished) {
return [2 /*return*/]; // only update the height once the user is done setting the column size
}
executionResult = this.getExecutionResult();
if (executionResult) {
this.updateDesiredHeight(executionResult);
}
if (!this.isManualResizing(columnEvent)) return [3 /*break*/, 4];
this.numberOfColumnResizedCalls++;
return [4 /*yield*/, utils_2.sleep(COLUMN_RESIZE_TIMEOUT)];
case 1:
_a.sent();
if (!(this.numberOfColumnResizedCalls === PivotTable_1.UIClick.DOUBLE_CLICK)) return [3 /*break*/, 3];
this.numberOfColumnResizedCalls = 0;
return [4 /*yield*/, this.onColumnsManualReset(columnEvent.columns)];
case 2:
_a.sent();
return [3 /*break*/, 4];
case 3:
if (this.numberOfColumnResizedCalls === PivotTable_1.UIClick.CLICK) {
this.numberOfColumnResizedCalls = 0;
this.onColumnsManualResized(columnEvent.columns);
}
_a.label = 4;
case 4: return [2 /*return*/];
}
});
}); };
_this.onColumnsManualReset = function (columns) { return __awaiter(_this, void 0, void 0, function () {
var columnsToReset, _i, columnsToReset_1, column;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
columnsToReset = columns;
if (this.isAllMeasureResizeOperation(columns)) {
this.resizedColumnsStore.removeAllMeasureColumns();
columnsToReset = this.getAllMeasureColumns();
}
if (this.isWeakMeasureResizeOperation(columns)) {
columnsToReset = this.resizedColumnsStore.getMatchingColumnsByMeasure(columns[0], this.getAllMeasureColumns());
this.resizedColumnsStore.removeWeakMeasureColumn(columns[0]);
}
_i = 0, columnsToReset_1 = columnsToReset;
_a.label = 1;
case 1:
if (!(_i < columnsToReset_1.length)) return [3 /*break*/, 4];
column = columnsToReset_1[_i];
return [4 /*yield*/, this.resetResizedColumn(column)];
case 2:
_a.sent();
_a.label = 3;
case 3:
_i++;
return [3 /*break*/, 1];
case 4:
this.afterOnResizeColumns();
return [2 /*return*/];
}
});
}); };
_this.onColumnsManualResized = function (columns) {
if (_this.isAllMeasureResizeOperation(columns)) {
agGridColumnSizing_1.resizeAllMeasuresColumns(_this.columnApi, _this.resizedColumnsStore, columns[0]);
}
else if (_this.isWeakMeasureResizeOperation(columns)) {
agGridColumnSizing_1.resizeWeakMeasureColumns(_this.columnApi, _this.resizedColumnsStore, columns[0]);
}
else {
columns.forEach(function (column) {
_this.resizedColumnsStore.addToManuallyResizedColumn(column);
});
}
_this.afterOnResizeColumns();
};
_this.onMenuAggregationClick = function (menuAggregationClickConfig) {
var newColumnTotals = aggregationsMenuHelper_1.getUpdatedColumnTotals(_this.getColumnTotals(), menuAggregationClickConfig);
_this.props.pushData({
properties: {
totals: newColumnTotals,
},
});
_this.setState({ columnTotals: newColumnTotals });
_this.updateGrouping();
};
_this.onBodyScroll = function (event) {
var scrollPosition = {
top: Math.max(event.top, 0),
left: event.left,
};
_this.updateStickyRowContent(scrollPosition);
};
_this.onContainerMouseDown = function (event) {
if (event.target && _this.isHeaderResizer(event.target)) {
event.stopPropagation();
}
_this.isMetaOrCtrlKeyPressed = event.metaKey || event.ctrlKey;
_this.isAltKeyPressed = event.altKey;
};
_this.getColumnWidths = function (props) {
return props.config && props.config.columnSizing && props.config.columnSizing.columnWidths;
};
_this.hasColumnWidths = function () {
return !!_this.getColumnWidths(_this.props);
};
_this.getDefaultWidthFromProps = function (props) {
return ((props.config && props.config.columnSizing && props.config.columnSizing.defaultWidth) || "unset");
};
//
// grid options & styling
//
_this.createGridOptions = function () {
var _a;
var _b = _this.state, columnDefs = _b.columnDefs, rowData = _b.rowData;
var pageSize = _this.props.pageSize;
var separators = get(_this.props, ["config", "separators"], undefined);
var menu = get(_this.props, ["config", "menu"]);
var commonHeaderComponentParams = {
onMenuAggregationClick: _this.onMenuAggregationClick,
getExecutionResponse: _this.getExecutionResponse,
getColumnTotals: _this.getColumnTotals,
getAfmFilters: _this.getAfmFilters,
intl: _this.props.intl,
};
return {
// Initial data
columnDefs: columnDefs,
rowData: rowData,
defaultColDef: {
cellClass: _this.getCellClass(null),
headerComponentFramework: ColumnHeader_1.default,
headerComponentParams: __assign({ menu: menu, enableSorting: true }, commonHeaderComponentParams),
minWidth: agGridColumnSizing_1.MIN_WIDTH,
sortable: true,
resizable: true,
},
defaultColGroupDef: {
headerClass: _this.getHeaderClass(null),
children: [],
headerGroupComponentFramework: ColumnGroupHeader_1.default,
headerGroupComponentParams: __assign({ menu: menu }, commonHeaderComponentParams),
},
onCellClicked: _this.cellClicked,
onSortChanged: _this.sortChanged,
onColumnResized: _this.onGridColumnResized,
onGridSizeChanged: _this.gridSizeChanged,
onGridColumnsChanged: _this.gridColumnsChanged,
// Basic options
suppressMovableColumns: true,
suppressCellSelection: true,
suppressAutoSize: _this.hasColumnWidths(),
enableFilter: false,
// infinite scrolling model
rowModelType: "infinite",
paginationPageSize: pageSize,
cacheOverflowSize: pageSize,
cacheBlockSize: pageSize,
maxConcurrentDatasourceRequests: 1,
infiniteInitialRowCount: _this.getInfiniteInitialRowCountRowCount(),
maxBlocksInCache: 10,
onGridReady: _this.onGridReady,
onFirstDataRendered: _this.onFirstDataRendered,
onModelUpdated: _this.onModelUpdated,
onBodyScroll: _this.onBodyScroll,
// this provides persistent row selection (if enabled)
getRowNodeId: agGridUtils_1.getRowNodeId,
// Column types
columnTypes: (_a = {},
_a[agGridConst_1.ROW_ATTRIBUTE_COLUMN] = {
cellClass: _this.getCellClass("gd-row-attribute-column"),
headerClass: _this.getHeaderClass("gd-row-attribute-column-header"),
colSpan: function (params) {
if (
// params.data is undefined when rows are in loading state
params.data &&
params.data.colSpan &&
utils_1.AVAILABLE_TOTALS.find(function (item) { return item === params.data[params.data.colSpan.headerKey]; })) {
return params.data.colSpan.count;
}
return 1;
},
valueFormatter: function (params) {
return params.value === undefined ? null : params.value;
},
cellRenderer: agGridUtils_1.cellRenderer,
},
_a[agGridConst_1.COLUMN_ATTRIBUTE_COLUMN] = {
cellClass: _this.getCellClass("gd-column-attribute-column"),
headerClass: _this.getHeaderClass("gd-column-attribute-column-header"),
},
_a[agGridConst_1.MEASURE_COLUMN] = {
cellClass: _this.getCellClass(classNames(AG_NUMERIC_CELL_CLASSNAME, "gd-measure-column")),
headerClass: _this.getHeaderClass(classNames(AG_NUMERIC_HEADER_CLASSNAME, "gd-measure-column-header")),
// wrong params type from ag-grid, we need any
valueFormatter: function (params) {
return agGridUtils_1.isMeasureColumnReadyToRender(params, _this.state.execution)
? tableCell_1.getMeasureCellFormattedValue(params.value, agGridUtils_1.getMeasureFormat(params.colDef, _this.state.execution), separators)
: null;
},
cellStyle: function (params) {
return agGridUtils_1.isMeasureColumnReadyToRender(params, _this.state.execution)
? tableCell_1.getMeasureCellStyle(params.value, agGridUtils_1.getMeasureFormat(params.colDef, _this.state.execution), separators, true)
: null;
},
cellRenderer: agGridUtils_1.cellRenderer,
},
_a),
// Custom renderers
frameworkComponents: {
// any is needed here because of incompatible types with AgGridReact types
loadingRenderer: RowLoadingElement_1.RowLoadingElement,
},
// Custom CSS classes
rowClass: "gd-table-row",
rowHeight: DEFAULT_ROW_HEIGHT,
autoSizePadding: DEFAULT_AUTOSIZE_PADDING,
};
};
/**
* getCellClass returns class for drillable cells. (maybe format in the future as well)
*/
_this.getCellClass = function (classList) { return function (cellClassParams) {
var _a = _this.props, dataSource = _a.dataSource, executionResponse = _a.execution.executionResponse;
var rowIndex = cellClassParams.rowIndex;
var colDef = cellClassParams.colDef;
var drillablePredicates = _this.getDrillablePredicates();
// return none if no drillableItems are specified
var afm = dataSource.getAfm();
var hasDrillableHeader = false;
var rowType = get(cellClassParams, ["data", "type"], "");
var isRowTotal = rowType === agGridConst_1.ROW_TOTAL;
var isRowSubtotal = rowType === agGridConst_1.ROW_SUBTOTAL;
if (drillablePredicates.length !== 0 && !isRowTotal && !isRowSubtotal) {
var rowDrillItem = get(cellClassParams, ["data", "headerItemMap", colDef.field]);
var headers = rowDrillItem
? colDef.drillItems.concat([rowDrillItem]) : colDef.drillItems;
hasDrillableHeader = headers.some(function (drillItem) {
return headerPredicate_1.isSomeHeaderPredicateMatched(drillablePredicates, drillItem, afm, executionResponse);
});
}
var attributeId = colDef.field;
var isPinnedRow = cellClassParams.node.isRowPinned();
var hiddenCell = !isPinnedRow && _this.groupingProvider.isRepeatedValue(attributeId, rowIndex);
var rowSeparator = !hiddenCell && _this.groupingProvider.isGroupBoundary(rowIndex);
var subtotalStyle = get(cellClassParams, ["data", "subtotalStyle"]);
return classNames(classList, tableCell_1.getCellClassNames(rowIndex, colDef.index, hasDrillableHeader), colDef.index !== undefined ? "gd-column-index-" + colDef.index : null, colDef.measureIndex !== undefined ? "gd-column-measure-" + colDef.measureIndex : null, isRowTotal ? "gd-row-total" : null, subtotalStyle ? "gd-table-row-subtotal gd-table-row-subtotal-" + subtotalStyle : null, hiddenCell ? "gd-cell-hide s-gd-cell-hide" : null, rowSeparator ? "gd-table-row-separator s-gd-table-row-separator" : null);
}; };
_this.getHeaderClass = function (classList) { return function (headerClassParams) {
var colDef = headerClassParams.colDef;
var field = colDef.field, measureIndex = colDef.measureIndex, index = colDef.index;
var treeIndexes = colDef
? agGridUtils_1.indexOfTreeNode(colDef, _this.state.columnDefs, function (nodeA, nodeB) { return nodeA.field !== undefined && nodeA.field === nodeB.field; })
: null;
var colGroupIndex = treeIndexes ? treeIndexes[treeIndexes.length - 1] : null;
var isFirstColumn = treeIndexes !== null && !treeIndexes.some(function (index) { return index !== 0; });
return classNames(classList, "gd-column-group-header", colGroupIndex !== null ? "gd-column-group-header-" + colGroupIndex : null, colGroupIndex !== null ? "s-table-measure-column-header-group-cell-" + colGroupIndex : null, measureIndex !== null && measureIndex !== undefined
? "s-table-measure-column-header-cell-" + measureIndex
: null, index ? "s-table-measure-column-header-index-" + index : null, !field ? "gd-column-group-header--empty" : null, isFirstColumn ? "gd-column-group-header--first" : null);
}; };
_this.state = {
columnDefs: [],
rowData: [],
execution: null,
columnTotals: cloneDeep(utils_1.default.getColumnTotalsFromResultSpec(_this.props.resultSpec)),
agGridRerenderNumber: 1,
desiredHeight: props.config.maxHeight,
sortedByFirstAttribute: true,
resized: false,
};
_this.agGridDataSource = null;
_this.gridApi = null;
_this.resizedColumnsStore = new ResizedColumnsStore_1.ResizedColumnsStore();
_this.setGroupingProvider(props.groupRows);
_this.gridSizeChanged = debounce(_this.gridSizeChanged, AGGRID_ON_RESIZE_TIMEOUT);
return _this;
}
PivotTableInner.prototype.componentWillMount = function () {
this.createAGGridDataSource();
};
PivotTableInner.prototype.componentDidMount = function () {
if (this.containerRef) {
this.containerRef.addEventListener("mousedown", this.onContainerMouseDown);
}
};
PivotTableInner.prototype.componentWillUnmount = function () {
if (this.containerRef) {
this.containerRef.removeEventListener("mousedown", this.onContainerMouseDown);
}
};
PivotTableInner.prototype.componentWillUpdate = function (nextProps, nextState) {
if (this.props.groupRows !== nextProps.groupRows ||
this.state.sortedByFirstAttribute !== nextState.sortedByFirstAttribute) {
this.setGroupingProvider(nextProps.groupRows && nextState.sortedByFirstAttribute);
}
};
PivotTableInner.prototype.componentDidUpdate = function (prevProps, prevState) {
var _this = this;
var prevPropsTotals = utils_1.default.getColumnTotalsFromResultSpec(prevProps.resultSpec);
var currentPropsTotals = utils_1.default.getColumnTotalsFromResultSpec(this.props.resultSpec);
var totalsPropsChanged = !isEqual(prevPropsTotals, currentPropsTotals);
var prevStateTotals = prevState.columnTotals;
var currentStateTotals = this.state.columnTotals;
var totalsStateChanged = !isEqual(prevStateTotals, currentStateTotals);
var prevColumnWidths = this.getColumnWidths(prevProps);
var columnWidths = this.getColumnWidths(this.props);
new Promise(function (resolve) {
if (totalsPropsChanged) {
_this.setState({
columnTotals: currentPropsTotals,
}, resolve);
}
else {
resolve();
}
}).then(function () {
var agGridDataSourceUpdateNeeded = false;
if (totalsStateChanged) {
_this.props.updateTotals(_this.state.columnTotals);
agGridDataSourceUpdateNeeded = true;
}
if (_this.isNewAGGridDataSourceNeeded(prevProps)) {
_this.groupingProvider.reset();
agGridDataSourceUpdateNeeded = true;
}
var fingerprint = agGridUtils_1.sanitizeFingerprint(_this.props.dataSource.getFingerprint());
var prevFingerprint = agGridUtils_1.sanitizeFingerprint(prevProps.dataSource.getFingerprint());
var dataSourceChanged = fingerprint !== prevFingerprint;
if (dataSourceChanged) {
_this.columnWidthsChangeWaitingForExecution = true;
}
if (dataSourceChanged || totalsPropsChanged || totalsStateChanged) {
// we need update last scroll position to be able call updateStickyRow
// solve blank cell after scroll and sort change
_this.lastScrollPosition = {
top: 0,
left: 0,
};
_this.autoResizedColumns = {};
_this.clearFittedColumns();
_this.setState({
resized: false,
});
}
if (_this.isGrowToFitEnabled(prevProps) !== _this.isGrowToFitEnabled()) {
_this.growToFit(_this.columnApi);
}
if (!isEqual(prevColumnWidths, columnWidths) && !_this.columnWidthsChangeWaitingForExecution) {
if (_this.shouldWaitForExecution(totalsPropsChanged, totalsStateChanged)) {
_this.columnWidthsChangeWaitingForExecution = true;
}
else {
_this.handleColumnWidthsChange(columnWidths);
}
}
if (agGridDataSourceUpdateNeeded) {
_this.updateAGGridDataSource();
}
});
if (this.isAgGridRerenderNeeded(this.props, prevProps)) {
this.forceRerender();
}
if (this.props.config.maxHeight && this.state.execution) {
this.updateDesiredHeight(this.state.execution.executionResult);
}
};
PivotTableInner.prototype.renderVisualization = function () {
var desiredHeight = this.state.desiredHeight;
var gridOptions = this.createGridOptions();
var CustomLoadingComponent = this.props.LoadingComponent;
// wait for columnDefs are loaded with first page request and initial column resizing is done.
// Show overlay loading before first page is available.
var tableLoadingOverlay = this.isTableHidden() ? (React.createElement("div", { style: {
position: "absolute",
left: 0,
right: 0,
top: 0,
bottom: 0,
background: "white",
}, className: "s-loading" }, CustomLoadingComponent !== null ? (CustomLoadingComponent ? (React.createElement(CustomLoadingComponent, null)) : (React.createElement(LoadingComponent_1.LoadingComponent, null))) : null)) : null;
var style = {
height: desiredHeight || "100%",
position: "relative",
overflow: "hidden",
};
return (React.createElement("div", { className: "gd-table-component", style: style },
React.createElement("div", { className: "gd-table ag-theme-balham s-pivot-table", style: style, ref: this.setContainerRef },
React.createElement(ag_grid_react_1.AgGridReact, __assign({}, gridOptions, {
// To force Ag grid rerender because AFAIK there is no way
// to tell Ag grid header cell to rerender
key: agGridUtils_1.generateAgGridComponentKey(this.props.dataSource.getAfm(), this.state.agGridRerenderNumber) })),
tableLoadingOverlay)));
};
PivotTableInner.prototype.isTableHidden = function () {
return (this.state.columnDefs.length === 0 ||
((this.isColumnAutoresizeEnabled() || this.isGrowToFitEnabled()) && !this.state.resized));
};
PivotTableInner.prototype.forceRerender = function () {
this.setState(function (state) { return ({
agGridRerenderNumber: state.agGridRerenderNumber + 1,
}); });
};
//
// working with data source
//
PivotTableInner.prototype.isNewAGGridDataSourceNeeded = function (prevProps) {
var _this = this;
// cannot compare dataSource using deep equal as it stores execution promises that almost always differ
var dataSourceChanged = this.props.dataSource.getFingerprint() !== prevProps.dataSource.getFingerprint();
var dataSourceInvalidatingPropNames = [
"resultSpec",
"getPage",
// drillable items need fresh execution because drillable context for row attribute is kept in rowData
// It could be refactored to assign drillability without execution,
// but it would suffer a significant performance hit
"drillableItems",
];
var dataSourceInvalidatingPropChanged = dataSourceInvalidatingPropNames.some(function (propKey) { return !isEqual(_this.props[propKey], prevProps[propKey]); });
return dataSourceChanged || dataSourceInvalidatingPropChanged;
};
PivotTableInner.prototype.isAgGridRerenderNeeded = function (props, prevProps) {
var propsRequiringAgGridRerender = [["config", "menu"]];
return propsRequiringAgGridRerender.some(function (propKey) { return !isEqual(get(props, propKey), get(prevProps, propKey)); });
};
PivotTableInner.prototype.updateAGGridDataSource = function () {
this.createAGGridDataSource();
this.setGridDataSource();
};
PivotTableInner.prototype.autoresizeColumnsByColumnId = function (columnApi, columnIds) {
agColumnWrapper_1.setColumnMaxWidth(columnApi, columnIds, agGridColumnSizing_1.AUTO_SIZED_MAX_WIDTH);
columnApi.autoSizeColumns(columnIds);
agColumnWrapper_1.setColumnMaxWidth(columnApi, columnIds, agGridColumnSizing_1.MANUALLY_SIZED_MAX_WIDTH);
};
PivotTableInner.prototype.shouldPerformAutoresize = function () {
var _this = this;
var execution = this.state.execution;
var tableIsNotScrolled = funct