eru-grid 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/eru-grid.mjs +283 -946
- package/fesm2022/eru-grid.mjs.map +1 -1
- package/index.d.ts +46 -206
- package/package.json +1 -1
package/fesm2022/eru-grid.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Injectable, inject, signal, computed, DOCUMENT, effect, Directive, InjectionToken, forwardRef, Input, Component, ElementRef, input, ChangeDetectorRef, model, Renderer2, ViewChild, ViewEncapsulation, ChangeDetectionStrategy, HostListener } from '@angular/core';
|
|
3
|
-
import { of, delay } from 'rxjs';
|
|
4
3
|
import * as i2$1 from '@angular/common';
|
|
5
4
|
import { NgFor, NgIf, NgClass, DatePipe, CommonModule } from '@angular/common';
|
|
6
5
|
import { CdkListbox, CdkOption } from '@angular/cdk/listbox';
|
|
@@ -101,53 +100,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImpor
|
|
|
101
100
|
}]
|
|
102
101
|
}] });
|
|
103
102
|
|
|
104
|
-
/**
|
|
105
|
-
* Type definitions for Excel export functionality
|
|
106
|
-
*/
|
|
107
|
-
/**
|
|
108
|
-
* Type guard to check if a property is a cell reference (not a special Excel property)
|
|
109
|
-
*/
|
|
110
|
-
function isCellReference(key) {
|
|
111
|
-
return !key.startsWith('!');
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Type guard to check if a property is a special Excel property
|
|
115
|
-
*/
|
|
116
|
-
function isExcelSpecialProperty(key) {
|
|
117
|
-
return key.startsWith('!');
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Color palette for Excel export styling
|
|
121
|
-
*/
|
|
122
|
-
const EXCEL_COLORS = {
|
|
123
|
-
// Header colors (blue gradient)
|
|
124
|
-
HEADER_PRIMARY: '4472C4',
|
|
125
|
-
HEADER_SECONDARY: '5B9BD5',
|
|
126
|
-
HEADER_TERTIARY: 'A5A5A5',
|
|
127
|
-
HEADER_QUATERNARY: '70AD47',
|
|
128
|
-
// Subtotal colors
|
|
129
|
-
SUBTOTAL_HEADER: 'FFD700', // Gold
|
|
130
|
-
SUBTOTAL_ROW: 'F0F8FF', // Light blue
|
|
131
|
-
GRAND_TOTAL_ROW: 'E6E6FA', // Light purple
|
|
132
|
-
// Border colors
|
|
133
|
-
BORDER_DARK: '000000', // Black
|
|
134
|
-
BORDER_LIGHT: 'CCCCCC', // Light gray
|
|
135
|
-
// Text colors
|
|
136
|
-
TEXT_WHITE: 'FFFFFF',
|
|
137
|
-
TEXT_BLACK: '000000',
|
|
138
|
-
TEXT_DARK: '333333'
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Default Excel export configuration
|
|
142
|
-
*/
|
|
143
|
-
const DEFAULT_EXCEL_CONFIG = {
|
|
144
|
-
filename: 'pivot-table.xlsx',
|
|
145
|
-
sheetName: 'Pivot Table',
|
|
146
|
-
includeHeaders: true,
|
|
147
|
-
includeStyling: true,
|
|
148
|
-
includeMerges: true
|
|
149
|
-
};
|
|
150
|
-
|
|
151
103
|
class PivotTransformService {
|
|
152
104
|
columnGroupState = {};
|
|
153
105
|
/**
|
|
@@ -1848,352 +1800,12 @@ class PivotTransformService {
|
|
|
1848
1800
|
}
|
|
1849
1801
|
return groups;
|
|
1850
1802
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
return pivotResult.columnDefinitions.map(col => {
|
|
1858
|
-
const value = row[col.name];
|
|
1859
|
-
return typeof value === 'string' && value.includes(',')
|
|
1860
|
-
? `"${value}"`
|
|
1861
|
-
: value || '';
|
|
1862
|
-
}).join(',');
|
|
1863
|
-
});
|
|
1864
|
-
return [headers, ...rows].join('\n');
|
|
1865
|
-
}
|
|
1866
|
-
/**
|
|
1867
|
-
* Export pivot data to Excel format with proper formatting, cell merging, and styling
|
|
1868
|
-
* Returns a workbook object compatible with xlsx library
|
|
1869
|
-
*/
|
|
1870
|
-
exportToExcel(pivotResult, options) {
|
|
1871
|
-
const { data, columnDefinitions, headerStructure, configuration } = pivotResult;
|
|
1872
|
-
const exportOptions = { ...DEFAULT_EXCEL_CONFIG, ...options };
|
|
1873
|
-
if (!headerStructure) {
|
|
1874
|
-
throw new Error('Header structure is required for Excel export');
|
|
1875
|
-
}
|
|
1876
|
-
// Use simplified approach that works reliably
|
|
1877
|
-
const sheet = this.createSimplifiedXlsxSheet(data, columnDefinitions, headerStructure, configuration, exportOptions);
|
|
1878
|
-
const workbook = {
|
|
1879
|
-
SheetNames: [exportOptions.sheetName],
|
|
1880
|
-
Sheets: {
|
|
1881
|
-
[exportOptions.sheetName]: sheet
|
|
1882
|
-
}
|
|
1883
|
-
};
|
|
1884
|
-
return workbook;
|
|
1885
|
-
}
|
|
1886
|
-
/**
|
|
1887
|
-
* Export pivot data to Excel file using xlsx library
|
|
1888
|
-
* This method requires the xlsx library to be installed: npm install xlsx
|
|
1889
|
-
* Usage:
|
|
1890
|
-
* import * as XLSX from 'xlsx';
|
|
1891
|
-
* const workbook = pivotService.exportToExcel(pivotResult);
|
|
1892
|
-
* XLSX.writeFile(workbook, 'pivot-table.xlsx');
|
|
1893
|
-
*/
|
|
1894
|
-
exportToExcelFile(pivotResult, filename = 'pivot-table.xlsx') {
|
|
1895
|
-
const workbook = this.exportToExcel(pivotResult);
|
|
1896
|
-
// This requires xlsx library
|
|
1897
|
-
// import * as XLSX from 'xlsx';
|
|
1898
|
-
// XLSX.writeFile(workbook, filename);
|
|
1899
|
-
console.log('Excel workbook created. Use XLSX.writeFile(workbook, filename) to save the file.');
|
|
1900
|
-
console.log('Workbook structure:', workbook);
|
|
1901
|
-
}
|
|
1902
|
-
/**
|
|
1903
|
-
* Create xlsx-compatible sheet with proper formatting and cell merging
|
|
1904
|
-
*/
|
|
1905
|
-
createXlsxSheet(data, columnDefinitions, headerStructure, rowspanInfo, configuration, options) {
|
|
1906
|
-
const sheet = {};
|
|
1907
|
-
const merges = [];
|
|
1908
|
-
// Start row for data (after headers)
|
|
1909
|
-
let currentRow = headerStructure.maxDepth + 1;
|
|
1910
|
-
// Add header rows with proper formatting
|
|
1911
|
-
if (options.includeHeaders) {
|
|
1912
|
-
this.addXlsxHeaders(sheet, headerStructure, merges, options);
|
|
1913
|
-
}
|
|
1914
|
-
// Add data rows with rowspan handling
|
|
1915
|
-
this.addXlsxDataRows(sheet, data, columnDefinitions, rowspanInfo, currentRow, merges, options);
|
|
1916
|
-
// Set column widths
|
|
1917
|
-
this.setXlsxColumnWidths(sheet, columnDefinitions);
|
|
1918
|
-
// Set merge ranges - only if we have valid merges
|
|
1919
|
-
if (options.includeMerges && merges.length > 0) {
|
|
1920
|
-
// Filter out invalid merges
|
|
1921
|
-
const validMerges = merges.filter(merge => merge.s && merge.e &&
|
|
1922
|
-
merge.s.r >= 0 && merge.s.c >= 0 &&
|
|
1923
|
-
merge.e.r >= 0 && merge.e.c >= 0 &&
|
|
1924
|
-
merge.s.r <= merge.e.r && merge.s.c <= merge.e.c);
|
|
1925
|
-
if (validMerges.length > 0) {
|
|
1926
|
-
sheet['!merges'] = validMerges;
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
// Set sheet range
|
|
1930
|
-
const range = this.getXlsxRange(sheet);
|
|
1931
|
-
if (range) {
|
|
1932
|
-
sheet['!ref'] = range;
|
|
1933
|
-
}
|
|
1934
|
-
return sheet;
|
|
1935
|
-
}
|
|
1936
|
-
/**
|
|
1937
|
-
* Create Excel sheet with proper formatting and cell merging (legacy method)
|
|
1938
|
-
*/
|
|
1939
|
-
createExcelSheet(data, columnDefinitions, headerStructure, rowspanInfo, configuration, options) {
|
|
1940
|
-
const sheet = {};
|
|
1941
|
-
// Define cell ranges for merging
|
|
1942
|
-
const merges = [];
|
|
1943
|
-
// Start row for data (after headers)
|
|
1944
|
-
let currentRow = headerStructure.maxDepth + 1;
|
|
1945
|
-
// Add header rows with proper formatting
|
|
1946
|
-
if (options.includeHeaders) {
|
|
1947
|
-
this.addExcelHeaders(sheet, headerStructure, merges, options);
|
|
1948
|
-
}
|
|
1949
|
-
// Add data rows with rowspan handling
|
|
1950
|
-
this.addExcelDataRows(sheet, data, columnDefinitions, rowspanInfo, currentRow, merges, options);
|
|
1951
|
-
// Set column widths
|
|
1952
|
-
this.setExcelColumnWidths(sheet, columnDefinitions);
|
|
1953
|
-
// Apply styling
|
|
1954
|
-
if (options.includeStyling) {
|
|
1955
|
-
this.applyExcelStyling(sheet, headerStructure, data, configuration);
|
|
1956
|
-
}
|
|
1957
|
-
// Set merge ranges
|
|
1958
|
-
if (options.includeMerges) {
|
|
1959
|
-
sheet['!merges'] = merges.map(range => {
|
|
1960
|
-
const [startCell, endCell] = range.split(':');
|
|
1961
|
-
const startRef = this.parseExcelCellRef(startCell);
|
|
1962
|
-
const endRef = this.parseExcelCellRef(endCell);
|
|
1963
|
-
return {
|
|
1964
|
-
s: { r: startRef.row, c: startRef.col },
|
|
1965
|
-
e: { r: endRef.row, c: endRef.col }
|
|
1966
|
-
};
|
|
1967
|
-
});
|
|
1968
|
-
}
|
|
1969
|
-
return sheet;
|
|
1970
|
-
}
|
|
1971
|
-
/**
|
|
1972
|
-
* Add Excel header rows with proper formatting and merging
|
|
1973
|
-
*/
|
|
1974
|
-
addExcelHeaders(sheet, headerStructure, merges, options) {
|
|
1975
|
-
const { headerRows, maxDepth } = headerStructure;
|
|
1976
|
-
headerRows.forEach((headerRow, rowIndex) => {
|
|
1977
|
-
headerRow.forEach((header, colIndex) => {
|
|
1978
|
-
const cellRef = this.getExcelCellRef(rowIndex, colIndex);
|
|
1979
|
-
sheet[cellRef] = {
|
|
1980
|
-
v: header.label,
|
|
1981
|
-
t: 's',
|
|
1982
|
-
s: this.getHeaderCellStyle(header, rowIndex, maxDepth)
|
|
1983
|
-
};
|
|
1984
|
-
// Add merge ranges for headers with colspan > 1
|
|
1985
|
-
if (header.colspan > 1) {
|
|
1986
|
-
const endCol = colIndex + header.colspan - 1;
|
|
1987
|
-
const mergeRange = `${cellRef}:${this.getExcelCellRef(rowIndex, endCol)}`;
|
|
1988
|
-
merges.push(mergeRange);
|
|
1989
|
-
}
|
|
1990
|
-
// Add merge ranges for headers with rowspan > 1
|
|
1991
|
-
if (header.rowspan > 1) {
|
|
1992
|
-
const endRow = rowIndex + header.rowspan - 1;
|
|
1993
|
-
const mergeRange = `${cellRef}:${this.getExcelCellRef(endRow, colIndex)}`;
|
|
1994
|
-
merges.push(mergeRange);
|
|
1995
|
-
}
|
|
1996
|
-
});
|
|
1997
|
-
});
|
|
1998
|
-
}
|
|
1999
|
-
/**
|
|
2000
|
-
* Add Excel data rows with rowspan handling
|
|
2001
|
-
*/
|
|
2002
|
-
addExcelDataRows(sheet, data, columnDefinitions, rowspanInfo, startRow, merges, options) {
|
|
2003
|
-
data.forEach((row, rowIndex) => {
|
|
2004
|
-
const excelRowIndex = startRow + rowIndex;
|
|
2005
|
-
columnDefinitions.forEach((col, colIndex) => {
|
|
2006
|
-
const cellRef = this.getExcelCellRef(excelRowIndex, colIndex);
|
|
2007
|
-
const value = row[col.name];
|
|
2008
|
-
// Check if this cell should be merged (rowspan)
|
|
2009
|
-
const rowspanKey = `${rowIndex}_${col.name}`;
|
|
2010
|
-
const spanInfo = rowspanInfo.get(rowspanKey);
|
|
2011
|
-
if (spanInfo && spanInfo.skip) {
|
|
2012
|
-
// Skip this cell as it's merged with a previous cell
|
|
2013
|
-
return;
|
|
2014
|
-
}
|
|
2015
|
-
// Set cell value and style
|
|
2016
|
-
sheet[cellRef] = {
|
|
2017
|
-
v: this.formatExcelValue(value, col.datatype),
|
|
2018
|
-
t: this.getExcelValueType(value, col.datatype),
|
|
2019
|
-
s: this.getDataCellStyle(row, col, spanInfo)
|
|
2020
|
-
};
|
|
2021
|
-
// Add merge range if this cell has rowspan > 1
|
|
2022
|
-
if (spanInfo && spanInfo.rowspan > 1) {
|
|
2023
|
-
const endRow = excelRowIndex + spanInfo.rowspan - 1;
|
|
2024
|
-
const mergeRange = `${cellRef}:${this.getExcelCellRef(endRow, colIndex)}`;
|
|
2025
|
-
merges.push(mergeRange);
|
|
2026
|
-
}
|
|
2027
|
-
});
|
|
2028
|
-
});
|
|
2029
|
-
}
|
|
2030
|
-
/**
|
|
2031
|
-
* Get Excel cell reference (e.g., A1, B2, etc.)
|
|
2032
|
-
*/
|
|
2033
|
-
getExcelCellRef(row, col) {
|
|
2034
|
-
const colLetter = this.getExcelColumnLetter(col);
|
|
2035
|
-
return `${colLetter}${row + 1}`;
|
|
2036
|
-
}
|
|
2037
|
-
/**
|
|
2038
|
-
* Convert column index to Excel column letter
|
|
2039
|
-
*/
|
|
2040
|
-
getExcelColumnLetter(col) {
|
|
2041
|
-
let result = '';
|
|
2042
|
-
while (col >= 0) {
|
|
2043
|
-
result = String.fromCharCode(65 + (col % 26)) + result;
|
|
2044
|
-
col = Math.floor(col / 26) - 1;
|
|
2045
|
-
}
|
|
2046
|
-
return result;
|
|
2047
|
-
}
|
|
2048
|
-
/**
|
|
2049
|
-
* Format value for Excel based on data type
|
|
2050
|
-
*/
|
|
2051
|
-
formatExcelValue(value, datatype) {
|
|
2052
|
-
if (value === null || value === undefined)
|
|
2053
|
-
return '';
|
|
2054
|
-
switch (datatype) {
|
|
2055
|
-
case 'number':
|
|
2056
|
-
case 'currency':
|
|
2057
|
-
return typeof value === 'number' ? value : parseFloat(value) || 0;
|
|
2058
|
-
case 'date':
|
|
2059
|
-
return value instanceof Date ? value : new Date(value);
|
|
2060
|
-
default:
|
|
2061
|
-
return String(value);
|
|
2062
|
-
}
|
|
2063
|
-
}
|
|
2064
|
-
/**
|
|
2065
|
-
* Get Excel value type
|
|
2066
|
-
*/
|
|
2067
|
-
getExcelValueType(value, datatype) {
|
|
2068
|
-
if (value === null || value === undefined)
|
|
2069
|
-
return 's';
|
|
2070
|
-
switch (datatype) {
|
|
2071
|
-
case 'number':
|
|
2072
|
-
case 'currency':
|
|
2073
|
-
return 'n';
|
|
2074
|
-
case 'date':
|
|
2075
|
-
return 'd';
|
|
2076
|
-
default:
|
|
2077
|
-
return 's';
|
|
2078
|
-
}
|
|
2079
|
-
}
|
|
2080
|
-
/**
|
|
2081
|
-
* Get header cell style
|
|
2082
|
-
*/
|
|
2083
|
-
getHeaderCellStyle(header, rowIndex, maxDepth) {
|
|
2084
|
-
const baseStyle = {
|
|
2085
|
-
font: { bold: true, color: { rgb: EXCEL_COLORS.TEXT_WHITE } },
|
|
2086
|
-
fill: { fgColor: { rgb: this.getHeaderColor(rowIndex, maxDepth) } },
|
|
2087
|
-
alignment: { horizontal: 'center', vertical: 'center' },
|
|
2088
|
-
border: {
|
|
2089
|
-
top: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_DARK } },
|
|
2090
|
-
bottom: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_DARK } },
|
|
2091
|
-
left: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_DARK } },
|
|
2092
|
-
right: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_DARK } }
|
|
2093
|
-
}
|
|
2094
|
-
};
|
|
2095
|
-
// Special styling for subtotals
|
|
2096
|
-
if (header.isSubtotal) {
|
|
2097
|
-
baseStyle.fill.fgColor.rgb = EXCEL_COLORS.SUBTOTAL_HEADER;
|
|
2098
|
-
baseStyle.font.color.rgb = EXCEL_COLORS.TEXT_BLACK;
|
|
2099
|
-
}
|
|
2100
|
-
return baseStyle;
|
|
2101
|
-
}
|
|
2102
|
-
/**
|
|
2103
|
-
* Get data cell style
|
|
2104
|
-
*/
|
|
2105
|
-
getDataCellStyle(row, col, spanInfo) {
|
|
2106
|
-
const baseStyle = {
|
|
2107
|
-
alignment: { horizontal: 'center', vertical: 'center' },
|
|
2108
|
-
border: {
|
|
2109
|
-
top: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_LIGHT } },
|
|
2110
|
-
bottom: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_LIGHT } },
|
|
2111
|
-
left: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_LIGHT } },
|
|
2112
|
-
right: { style: 'thin', color: { rgb: EXCEL_COLORS.BORDER_LIGHT } }
|
|
2113
|
-
}
|
|
2114
|
-
};
|
|
2115
|
-
// Special styling for subtotal and grand total rows
|
|
2116
|
-
if (row._isSubtotal) {
|
|
2117
|
-
baseStyle.fill = { fgColor: { rgb: EXCEL_COLORS.SUBTOTAL_ROW } };
|
|
2118
|
-
baseStyle.font = { bold: true };
|
|
2119
|
-
}
|
|
2120
|
-
else if (row._isGrandTotal) {
|
|
2121
|
-
baseStyle.fill = { fgColor: { rgb: EXCEL_COLORS.GRAND_TOTAL_ROW } };
|
|
2122
|
-
baseStyle.font = { bold: true };
|
|
2123
|
-
}
|
|
2124
|
-
// Number formatting
|
|
2125
|
-
if (col.datatype === 'number' || col.datatype === 'currency') {
|
|
2126
|
-
baseStyle.numFmt = col.datatype === 'currency' ? '$#,##0.00' : '#,##0.00';
|
|
2127
|
-
}
|
|
2128
|
-
return baseStyle;
|
|
2129
|
-
}
|
|
2130
|
-
/**
|
|
2131
|
-
* Get header color based on row index and depth
|
|
2132
|
-
*/
|
|
2133
|
-
getHeaderColor(rowIndex, maxDepth) {
|
|
2134
|
-
const colors = [
|
|
2135
|
-
EXCEL_COLORS.HEADER_PRIMARY,
|
|
2136
|
-
EXCEL_COLORS.HEADER_SECONDARY,
|
|
2137
|
-
EXCEL_COLORS.HEADER_TERTIARY,
|
|
2138
|
-
EXCEL_COLORS.HEADER_QUATERNARY
|
|
2139
|
-
];
|
|
2140
|
-
return colors[rowIndex % colors.length];
|
|
2141
|
-
}
|
|
2142
|
-
/**
|
|
2143
|
-
* Set column widths based on field definitions
|
|
2144
|
-
*/
|
|
2145
|
-
setExcelColumnWidths(sheet, columnDefinitions) {
|
|
2146
|
-
const colWidths = [];
|
|
2147
|
-
columnDefinitions.forEach(col => {
|
|
2148
|
-
// Convert field_size to Excel column width (Excel uses character units)
|
|
2149
|
-
const width = Math.max(col.field_size / 7, 10); // Minimum width of 10
|
|
2150
|
-
colWidths.push({ wch: width });
|
|
2151
|
-
});
|
|
2152
|
-
sheet['!cols'] = colWidths;
|
|
2153
|
-
}
|
|
2154
|
-
/**
|
|
2155
|
-
* Apply additional Excel styling
|
|
2156
|
-
*/
|
|
2157
|
-
applyExcelStyling(sheet, headerStructure, data, configuration) {
|
|
2158
|
-
// Set sheet properties
|
|
2159
|
-
sheet['!ref'] = this.getExcelRange(headerStructure.maxDepth + data.length + 1, configuration.rows.length + 10);
|
|
2160
|
-
// Add freeze panes (freeze header rows)
|
|
2161
|
-
sheet['!freeze'] = { xSplit: configuration.rows.length, ySplit: headerStructure.maxDepth };
|
|
2162
|
-
// Set print settings
|
|
2163
|
-
sheet['!print'] = {
|
|
2164
|
-
orientation: 'landscape',
|
|
2165
|
-
fitToPage: true,
|
|
2166
|
-
fitToWidth: 1,
|
|
2167
|
-
fitToHeight: 0
|
|
2168
|
-
};
|
|
2169
|
-
}
|
|
2170
|
-
/**
|
|
2171
|
-
* Get Excel range reference
|
|
2172
|
-
*/
|
|
2173
|
-
getExcelRange(maxRow, maxCol) {
|
|
2174
|
-
const startCell = this.getExcelCellRef(0, 0);
|
|
2175
|
-
const endCell = this.getExcelCellRef(maxRow - 1, maxCol - 1);
|
|
2176
|
-
return `${startCell}:${endCell}`;
|
|
2177
|
-
}
|
|
2178
|
-
/**
|
|
2179
|
-
* Parse Excel cell reference to row and column indices
|
|
2180
|
-
*/
|
|
2181
|
-
parseExcelCellRef(cellRef) {
|
|
2182
|
-
const match = cellRef.match(/^([A-Z]+)(\d+)$/);
|
|
2183
|
-
if (!match) {
|
|
2184
|
-
throw new Error(`Invalid cell reference: ${cellRef}`);
|
|
2185
|
-
}
|
|
2186
|
-
const colStr = match[1];
|
|
2187
|
-
const rowStr = match[2];
|
|
2188
|
-
// Convert column letters to index
|
|
2189
|
-
let col = 0;
|
|
2190
|
-
for (let i = 0; i < colStr.length; i++) {
|
|
2191
|
-
col = col * 26 + (colStr.charCodeAt(i) - 64);
|
|
2192
|
-
}
|
|
2193
|
-
col -= 1; // Convert to 0-based index
|
|
2194
|
-
const row = parseInt(rowStr) - 1; // Convert to 0-based index
|
|
2195
|
-
return { row, col };
|
|
2196
|
-
}
|
|
1803
|
+
// Excel/CSV export methods removed
|
|
1804
|
+
// Export functionality should be implemented in the consuming application
|
|
1805
|
+
// Previously removed methods: exportToCsv, exportToExcel, exportToExcelFile, createXlsxSheet,
|
|
1806
|
+
// createSimplifiedXlsxSheet, addXlsxHeaders, addXlsxDataRows, setXlsxColumnWidths,
|
|
1807
|
+
// applyXlsxStyling, getXlsxHeaderStyle, getXlsxDataStyle, formatXlsxValue,
|
|
1808
|
+
// getXlsxValueType, getXlsxRange, generateRowKeyForExcel, and all xlsx helper methods
|
|
2197
1809
|
/**
|
|
2198
1810
|
* Initialize column group state based on configuration
|
|
2199
1811
|
*/
|
|
@@ -2749,264 +2361,6 @@ class PivotTransformService {
|
|
|
2749
2361
|
});
|
|
2750
2362
|
return groups;
|
|
2751
2363
|
}
|
|
2752
|
-
// ==================== XLSX-COMPATIBLE METHODS ====================
|
|
2753
|
-
/**
|
|
2754
|
-
* Create simplified xlsx sheet that works reliably without complex merging
|
|
2755
|
-
*/
|
|
2756
|
-
createSimplifiedXlsxSheet(data, columnDefinitions, headerStructure, configuration, options) {
|
|
2757
|
-
const sheet = {};
|
|
2758
|
-
let rowIndex = 1;
|
|
2759
|
-
// Add headers from header structure
|
|
2760
|
-
if (options.includeHeaders && headerStructure.headerRows) {
|
|
2761
|
-
headerStructure.headerRows.forEach((headerRow, headerRowIndex) => {
|
|
2762
|
-
headerRow.forEach((header, colIndex) => {
|
|
2763
|
-
const cellRef = this.getExcelCellRef(headerRowIndex, colIndex);
|
|
2764
|
-
sheet[cellRef] = {
|
|
2765
|
-
v: header.label,
|
|
2766
|
-
t: 's',
|
|
2767
|
-
s: {
|
|
2768
|
-
font: { bold: true, color: { rgb: EXCEL_COLORS.TEXT_WHITE } },
|
|
2769
|
-
fill: { fgColor: { rgb: EXCEL_COLORS.HEADER_PRIMARY } },
|
|
2770
|
-
alignment: { horizontal: 'center', vertical: 'center' }
|
|
2771
|
-
}
|
|
2772
|
-
};
|
|
2773
|
-
});
|
|
2774
|
-
rowIndex++;
|
|
2775
|
-
});
|
|
2776
|
-
}
|
|
2777
|
-
else {
|
|
2778
|
-
// Fallback: simple headers from column definitions
|
|
2779
|
-
columnDefinitions.forEach((col, colIndex) => {
|
|
2780
|
-
const cellRef = this.getExcelCellRef(0, colIndex);
|
|
2781
|
-
sheet[cellRef] = {
|
|
2782
|
-
v: col.label || col.name,
|
|
2783
|
-
t: 's',
|
|
2784
|
-
s: {
|
|
2785
|
-
font: { bold: true, color: { rgb: EXCEL_COLORS.TEXT_WHITE } },
|
|
2786
|
-
fill: { fgColor: { rgb: EXCEL_COLORS.HEADER_PRIMARY } },
|
|
2787
|
-
alignment: { horizontal: 'center', vertical: 'center' }
|
|
2788
|
-
}
|
|
2789
|
-
};
|
|
2790
|
-
});
|
|
2791
|
-
rowIndex = 2;
|
|
2792
|
-
}
|
|
2793
|
-
// Add data rows
|
|
2794
|
-
data.forEach((row) => {
|
|
2795
|
-
columnDefinitions.forEach((col, colIndex) => {
|
|
2796
|
-
const cellRef = this.getExcelCellRef(rowIndex - 1, colIndex);
|
|
2797
|
-
const value = row[col.name];
|
|
2798
|
-
let cellStyle = {
|
|
2799
|
-
alignment: { horizontal: 'center', vertical: 'center' }
|
|
2800
|
-
};
|
|
2801
|
-
// Add styling for special rows
|
|
2802
|
-
if (row['isGrandTotal']) {
|
|
2803
|
-
cellStyle.font = { bold: true };
|
|
2804
|
-
cellStyle.fill = { fgColor: { rgb: EXCEL_COLORS.GRAND_TOTAL_ROW } };
|
|
2805
|
-
}
|
|
2806
|
-
else if (row['isSubtotal']) {
|
|
2807
|
-
cellStyle.font = { bold: true };
|
|
2808
|
-
cellStyle.fill = { fgColor: { rgb: EXCEL_COLORS.SUBTOTAL_ROW } };
|
|
2809
|
-
}
|
|
2810
|
-
sheet[cellRef] = {
|
|
2811
|
-
v: this.formatXlsxValue(value, col.datatype),
|
|
2812
|
-
t: this.getXlsxValueType(col.datatype),
|
|
2813
|
-
s: cellStyle
|
|
2814
|
-
};
|
|
2815
|
-
});
|
|
2816
|
-
rowIndex++;
|
|
2817
|
-
});
|
|
2818
|
-
// Set range
|
|
2819
|
-
const maxCol = columnDefinitions.length - 1;
|
|
2820
|
-
const maxRow = rowIndex - 1;
|
|
2821
|
-
sheet['!ref'] = `A1:${this.getExcelCellRef(maxRow - 1, maxCol)}`;
|
|
2822
|
-
// Set column widths
|
|
2823
|
-
sheet['!cols'] = columnDefinitions.map(col => ({
|
|
2824
|
-
wch: Math.max(col.label?.length || col.name.length, 15)
|
|
2825
|
-
}));
|
|
2826
|
-
return sheet;
|
|
2827
|
-
}
|
|
2828
|
-
/**
|
|
2829
|
-
* Add headers to xlsx sheet with proper formatting
|
|
2830
|
-
*/
|
|
2831
|
-
addXlsxHeaders(sheet, headerStructure, merges, options) {
|
|
2832
|
-
const { headerRows } = headerStructure;
|
|
2833
|
-
// Add each header row
|
|
2834
|
-
headerRows.forEach((headerRow, rowIndex) => {
|
|
2835
|
-
headerRow.forEach((header, colIndex) => {
|
|
2836
|
-
const cellRef = this.getExcelCellRef(rowIndex, colIndex);
|
|
2837
|
-
const cell = {
|
|
2838
|
-
v: header.label,
|
|
2839
|
-
t: 's'
|
|
2840
|
-
};
|
|
2841
|
-
// Add styling
|
|
2842
|
-
if (options.includeStyling) {
|
|
2843
|
-
cell.s = this.getXlsxHeaderStyle(header);
|
|
2844
|
-
}
|
|
2845
|
-
sheet[cellRef] = cell;
|
|
2846
|
-
// Handle colspan merging
|
|
2847
|
-
if (header.colspan > 1) {
|
|
2848
|
-
const endCol = colIndex + header.colspan - 1;
|
|
2849
|
-
merges.push({
|
|
2850
|
-
s: { r: rowIndex, c: colIndex },
|
|
2851
|
-
e: { r: rowIndex, c: endCol }
|
|
2852
|
-
});
|
|
2853
|
-
}
|
|
2854
|
-
// Handle rowspan merging
|
|
2855
|
-
if (header.rowspan > 1) {
|
|
2856
|
-
const endRow = rowIndex + header.rowspan - 1;
|
|
2857
|
-
merges.push({
|
|
2858
|
-
s: { r: rowIndex, c: colIndex },
|
|
2859
|
-
e: { r: endRow, c: colIndex }
|
|
2860
|
-
});
|
|
2861
|
-
}
|
|
2862
|
-
});
|
|
2863
|
-
});
|
|
2864
|
-
}
|
|
2865
|
-
/**
|
|
2866
|
-
* Add data rows to xlsx sheet with rowspan handling
|
|
2867
|
-
*/
|
|
2868
|
-
addXlsxDataRows(sheet, data, columnDefinitions, rowspanInfo, startRow, merges, options) {
|
|
2869
|
-
let currentRow = startRow;
|
|
2870
|
-
data.forEach((row, rowIndex) => {
|
|
2871
|
-
const rowKey = this.generateRowKeyForExcel(row);
|
|
2872
|
-
const spanInfo = rowspanInfo.get(rowKey);
|
|
2873
|
-
if (spanInfo && spanInfo.skip) {
|
|
2874
|
-
return; // Skip this row as it's merged with parent
|
|
2875
|
-
}
|
|
2876
|
-
// Add row data
|
|
2877
|
-
columnDefinitions.forEach((col, colIndex) => {
|
|
2878
|
-
const cellRef = this.getExcelCellRef(currentRow, colIndex);
|
|
2879
|
-
const value = row[col.name];
|
|
2880
|
-
const cell = {
|
|
2881
|
-
v: this.formatXlsxValue(value, col.datatype),
|
|
2882
|
-
t: this.getXlsxValueType(col.datatype)
|
|
2883
|
-
};
|
|
2884
|
-
// Add styling
|
|
2885
|
-
if (options.includeStyling) {
|
|
2886
|
-
cell.s = this.getXlsxDataStyle(row, col);
|
|
2887
|
-
}
|
|
2888
|
-
sheet[cellRef] = cell;
|
|
2889
|
-
});
|
|
2890
|
-
// Handle rowspan merging
|
|
2891
|
-
if (spanInfo && spanInfo.rowspan > 1) {
|
|
2892
|
-
const endRow = currentRow + spanInfo.rowspan - 1;
|
|
2893
|
-
columnDefinitions.forEach((col, colIndex) => {
|
|
2894
|
-
merges.push({
|
|
2895
|
-
s: { r: currentRow, c: colIndex },
|
|
2896
|
-
e: { r: endRow, c: colIndex }
|
|
2897
|
-
});
|
|
2898
|
-
});
|
|
2899
|
-
}
|
|
2900
|
-
currentRow++;
|
|
2901
|
-
});
|
|
2902
|
-
}
|
|
2903
|
-
/**
|
|
2904
|
-
* Set column widths for xlsx sheet
|
|
2905
|
-
*/
|
|
2906
|
-
setXlsxColumnWidths(sheet, columnDefinitions) {
|
|
2907
|
-
const colWidths = [];
|
|
2908
|
-
columnDefinitions.forEach(col => {
|
|
2909
|
-
colWidths.push({
|
|
2910
|
-
wch: Math.max(col.name.length, 15) // Minimum width of 15 characters
|
|
2911
|
-
});
|
|
2912
|
-
});
|
|
2913
|
-
sheet['!cols'] = colWidths;
|
|
2914
|
-
}
|
|
2915
|
-
/**
|
|
2916
|
-
* Apply styling to xlsx sheet
|
|
2917
|
-
*/
|
|
2918
|
-
applyXlsxStyling(sheet, headerStructure, data, configuration) {
|
|
2919
|
-
// Styling is applied during cell creation in addXlsxHeaders and addXlsxDataRows
|
|
2920
|
-
// This method can be used for additional global styling if needed
|
|
2921
|
-
}
|
|
2922
|
-
/**
|
|
2923
|
-
* Get xlsx header cell style
|
|
2924
|
-
*/
|
|
2925
|
-
getXlsxHeaderStyle(header) {
|
|
2926
|
-
return {
|
|
2927
|
-
font: { bold: true, color: { rgb: EXCEL_COLORS.TEXT_WHITE } },
|
|
2928
|
-
fill: { fgColor: { rgb: EXCEL_COLORS.HEADER_PRIMARY } },
|
|
2929
|
-
alignment: { horizontal: 'center', vertical: 'center' }
|
|
2930
|
-
};
|
|
2931
|
-
}
|
|
2932
|
-
/**
|
|
2933
|
-
* Get xlsx data cell style
|
|
2934
|
-
*/
|
|
2935
|
-
getXlsxDataStyle(row, column) {
|
|
2936
|
-
const baseStyle = {
|
|
2937
|
-
alignment: { horizontal: 'center', vertical: 'center' }
|
|
2938
|
-
};
|
|
2939
|
-
// Add specific styling based on row type
|
|
2940
|
-
if (row['isGrandTotal']) {
|
|
2941
|
-
baseStyle.font = { bold: true };
|
|
2942
|
-
baseStyle.fill = { fgColor: { rgb: EXCEL_COLORS.GRAND_TOTAL_ROW } };
|
|
2943
|
-
}
|
|
2944
|
-
else if (row['isSubtotal']) {
|
|
2945
|
-
baseStyle.font = { bold: true };
|
|
2946
|
-
baseStyle.fill = { fgColor: { rgb: EXCEL_COLORS.SUBTOTAL_ROW } };
|
|
2947
|
-
}
|
|
2948
|
-
return baseStyle;
|
|
2949
|
-
}
|
|
2950
|
-
/**
|
|
2951
|
-
* Format value for xlsx
|
|
2952
|
-
*/
|
|
2953
|
-
formatXlsxValue(value, type) {
|
|
2954
|
-
if (value === null || value === undefined) {
|
|
2955
|
-
return '';
|
|
2956
|
-
}
|
|
2957
|
-
switch (type) {
|
|
2958
|
-
case 'number':
|
|
2959
|
-
return typeof value === 'number' ? value : parseFloat(value) || 0;
|
|
2960
|
-
case 'date':
|
|
2961
|
-
return value instanceof Date ? value : new Date(value);
|
|
2962
|
-
default:
|
|
2963
|
-
return String(value);
|
|
2964
|
-
}
|
|
2965
|
-
}
|
|
2966
|
-
/**
|
|
2967
|
-
* Get xlsx value type
|
|
2968
|
-
*/
|
|
2969
|
-
getXlsxValueType(type) {
|
|
2970
|
-
switch (type) {
|
|
2971
|
-
case 'number':
|
|
2972
|
-
return 'n';
|
|
2973
|
-
case 'date':
|
|
2974
|
-
return 'd';
|
|
2975
|
-
default:
|
|
2976
|
-
return 's';
|
|
2977
|
-
}
|
|
2978
|
-
}
|
|
2979
|
-
/**
|
|
2980
|
-
* Get xlsx sheet range
|
|
2981
|
-
*/
|
|
2982
|
-
getXlsxRange(sheet) {
|
|
2983
|
-
const cells = Object.keys(sheet).filter(key => key.match(/^[A-Z]+\d+$/));
|
|
2984
|
-
if (cells.length === 0)
|
|
2985
|
-
return null;
|
|
2986
|
-
const rows = cells.map(cell => parseInt(cell.replace(/[A-Z]+/, '')));
|
|
2987
|
-
const cols = cells.map(cell => this.parseExcelCellRef(cell).col);
|
|
2988
|
-
const minRow = Math.min(...rows);
|
|
2989
|
-
const maxRow = Math.max(...rows);
|
|
2990
|
-
const minCol = Math.min(...cols);
|
|
2991
|
-
const maxCol = Math.max(...cols);
|
|
2992
|
-
const startCell = this.getExcelCellRef(minRow, minCol);
|
|
2993
|
-
const endCell = this.getExcelCellRef(maxRow, maxCol);
|
|
2994
|
-
return `${startCell}:${endCell}`;
|
|
2995
|
-
}
|
|
2996
|
-
/**
|
|
2997
|
-
* Generate row key for Excel export
|
|
2998
|
-
*/
|
|
2999
|
-
generateRowKeyForExcel(row) {
|
|
3000
|
-
// Create a unique key for the row based on its data
|
|
3001
|
-
const keyParts = [];
|
|
3002
|
-
// Add dimension values
|
|
3003
|
-
Object.keys(row).forEach(key => {
|
|
3004
|
-
if (key !== 'isSubtotal' && key !== 'isGrandTotal' && row[key] !== null && row[key] !== undefined) {
|
|
3005
|
-
keyParts.push(`${key}:${row[key]}`);
|
|
3006
|
-
}
|
|
3007
|
-
});
|
|
3008
|
-
return keyParts.join('|');
|
|
3009
|
-
}
|
|
3010
2364
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: PivotTransformService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3011
2365
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: PivotTransformService, providedIn: 'root' });
|
|
3012
2366
|
}
|
|
@@ -3047,7 +2401,9 @@ class EruGridStore {
|
|
|
3047
2401
|
// Pivot-specific signals
|
|
3048
2402
|
_pivotConfiguration = signal(null, ...(ngDevMode ? [{ debugName: "_pivotConfiguration" }] : []));
|
|
3049
2403
|
_pivotResult = signal(null, ...(ngDevMode ? [{ debugName: "_pivotResult" }] : []));
|
|
3050
|
-
|
|
2404
|
+
_drilldown = signal(null, ...(ngDevMode ? [{ debugName: "_drilldown" }] : []));
|
|
2405
|
+
// Data request signal for virtual scrolling pagination
|
|
2406
|
+
_dataRequest = signal(null, ...(ngDevMode ? [{ debugName: "_dataRequest" }] : []));
|
|
3051
2407
|
// Computed signals
|
|
3052
2408
|
columns = this._columns.asReadonly();
|
|
3053
2409
|
groups = this._groups.asReadonly();
|
|
@@ -3060,7 +2416,9 @@ class EruGridStore {
|
|
|
3060
2416
|
// Pivot-specific readonly signals
|
|
3061
2417
|
pivotConfiguration = this._pivotConfiguration.asReadonly();
|
|
3062
2418
|
pivotResult = this._pivotResult.asReadonly();
|
|
3063
|
-
|
|
2419
|
+
drilldown = this._drilldown.asReadonly();
|
|
2420
|
+
// Data request readonly signal (exposed to consumers)
|
|
2421
|
+
dataRequest = this._dataRequest.asReadonly();
|
|
3064
2422
|
// Computed properties
|
|
3065
2423
|
selectedRows = computed(() => this.rows().filter(row => this.selectedRowIds().has(row.entity_id)), ...(ngDevMode ? [{ debugName: "selectedRows" }] : []));
|
|
3066
2424
|
totalSelectedCount = computed(() => this.selectedRowIds().size, ...(ngDevMode ? [{ debugName: "totalSelectedCount" }] : []));
|
|
@@ -3343,13 +2701,9 @@ class EruGridStore {
|
|
|
3343
2701
|
setError(error) {
|
|
3344
2702
|
this._error.set(error);
|
|
3345
2703
|
}
|
|
3346
|
-
// Data fetching method
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
const endIndex = startIndex + pageSize;
|
|
3350
|
-
const data = this.configuration().data?.slice(startIndex, endIndex) || [];
|
|
3351
|
-
return of(data).pipe(delay(1000));
|
|
3352
|
-
}
|
|
2704
|
+
// Data fetching method - REMOVED
|
|
2705
|
+
// This method has been removed as part of refactoring to signal-based architecture
|
|
2706
|
+
// Data fetching is now handled by the consuming application via dataRequest signal
|
|
3353
2707
|
// Helper methods
|
|
3354
2708
|
isRowSelected(rowId) {
|
|
3355
2709
|
return this.selectedRowIds().has(rowId);
|
|
@@ -3454,20 +2808,8 @@ class EruGridStore {
|
|
|
3454
2808
|
this._pivotResult.set(null);
|
|
3455
2809
|
this.transformToPivot();
|
|
3456
2810
|
}
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
if (!pivotResult) {
|
|
3460
|
-
return null;
|
|
3461
|
-
}
|
|
3462
|
-
return this.pivotTransformService.exportToCsv(pivotResult);
|
|
3463
|
-
}
|
|
3464
|
-
exportPivotToExcel() {
|
|
3465
|
-
const pivotResult = this.pivotResult();
|
|
3466
|
-
if (!pivotResult) {
|
|
3467
|
-
return null;
|
|
3468
|
-
}
|
|
3469
|
-
return this.pivotTransformService.exportToExcel(pivotResult);
|
|
3470
|
-
}
|
|
2811
|
+
// Excel/CSV export methods removed
|
|
2812
|
+
// Export functionality should be implemented in the consuming application
|
|
3471
2813
|
validatePivotConfiguration(config) {
|
|
3472
2814
|
return this.gridConfigService.validatePivotConfiguration(config);
|
|
3473
2815
|
}
|
|
@@ -3550,22 +2892,74 @@ class EruGridStore {
|
|
|
3550
2892
|
isFreezeGrandTotalEnabled() {
|
|
3551
2893
|
return this.configuration().config?.freezeGrandTotal ?? false;
|
|
3552
2894
|
}
|
|
3553
|
-
|
|
3554
|
-
if (
|
|
3555
|
-
drilldown.
|
|
2895
|
+
setDrilldown(drilldown, columnValues) {
|
|
2896
|
+
if (this.isPivotMode()) {
|
|
2897
|
+
if (drilldown.frozenGrandTotalCell) {
|
|
2898
|
+
drilldown.rowData = this.pivotGrandTotalData()[0];
|
|
2899
|
+
}
|
|
2900
|
+
else {
|
|
2901
|
+
drilldown.rowData = this.pivotDisplayData()[parseInt(drilldown.rowId)];
|
|
2902
|
+
}
|
|
3556
2903
|
}
|
|
3557
2904
|
else {
|
|
3558
|
-
drilldown.rowData = this.
|
|
2905
|
+
drilldown.rowData = this.rows()[parseInt(drilldown.rowId) - 2];
|
|
3559
2906
|
}
|
|
3560
2907
|
const columnValuesArray = columnValues.split('|');
|
|
3561
2908
|
const cols = this.configuration()?.pivot?.cols;
|
|
3562
2909
|
columnValuesArray.forEach((value, index) => {
|
|
3563
2910
|
drilldown.rowData[cols[index]] = value;
|
|
3564
2911
|
});
|
|
3565
|
-
|
|
2912
|
+
console.log('🔄 SET DRILLDOWN: Drilldown', drilldown);
|
|
2913
|
+
this._drilldown.set(drilldown);
|
|
3566
2914
|
}
|
|
3567
2915
|
clearPivotDrilldown() {
|
|
3568
|
-
this.
|
|
2916
|
+
this._drilldown.set(null);
|
|
2917
|
+
}
|
|
2918
|
+
// Data request methods for signal-based virtual scrolling
|
|
2919
|
+
/**
|
|
2920
|
+
* Emit a data request signal (called by grid component)
|
|
2921
|
+
*/
|
|
2922
|
+
setDataRequest(request) {
|
|
2923
|
+
console.log('📤 Grid Store: Emitting data request', request);
|
|
2924
|
+
this._dataRequest.set(request);
|
|
2925
|
+
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Clear the data request signal (called by consumer after handling)
|
|
2928
|
+
*/
|
|
2929
|
+
clearDataRequest() {
|
|
2930
|
+
this._dataRequest.set(null);
|
|
2931
|
+
}
|
|
2932
|
+
/**
|
|
2933
|
+
* Mark a group as loading (called by grid component before requesting)
|
|
2934
|
+
*/
|
|
2935
|
+
startGroupLoading(groupId) {
|
|
2936
|
+
this.updateGroupLoadingState(groupId, true);
|
|
2937
|
+
}
|
|
2938
|
+
/**
|
|
2939
|
+
* Complete loading for a group (called by consumer after data received)
|
|
2940
|
+
*/
|
|
2941
|
+
completeGroupLoading(groupId) {
|
|
2942
|
+
this.updateGroupLoadingState(groupId, false);
|
|
2943
|
+
}
|
|
2944
|
+
/**
|
|
2945
|
+
* Add rows for a specific group (called by consumer with API data)
|
|
2946
|
+
*/
|
|
2947
|
+
addRowsForGroup(groupId, rows, hasMore) {
|
|
2948
|
+
console.log(`✅ Grid Store: Received ${rows.length} rows for group ${groupId}`);
|
|
2949
|
+
// Add rows to existing rows
|
|
2950
|
+
const existingRows = this.rows();
|
|
2951
|
+
const newRows = [...existingRows, ...rows];
|
|
2952
|
+
this._rows.set(newRows);
|
|
2953
|
+
// Update group state
|
|
2954
|
+
this.updateGroupAfterLoading(groupId, rows.length, !hasMore);
|
|
2955
|
+
}
|
|
2956
|
+
/**
|
|
2957
|
+
* Handle error for data request (called by consumer when API fails)
|
|
2958
|
+
*/
|
|
2959
|
+
handleDataRequestError(groupId, error) {
|
|
2960
|
+
console.error(`❌ Grid Store: Data request failed for group ${groupId}`, error);
|
|
2961
|
+
this.updateGroupLoadingState(groupId, false);
|
|
2962
|
+
this.setError(`Failed to load data for group ${groupId}`);
|
|
3569
2963
|
}
|
|
3570
2964
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EruGridStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3571
2965
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EruGridStore });
|
|
@@ -3871,18 +3265,8 @@ class EruGridService {
|
|
|
3871
3265
|
clear_pivot() {
|
|
3872
3266
|
this.eruGridStore.clearPivot();
|
|
3873
3267
|
}
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
*/
|
|
3877
|
-
export_pivot_to_csv() {
|
|
3878
|
-
return this.eruGridStore.exportPivotToCsv();
|
|
3879
|
-
}
|
|
3880
|
-
/**
|
|
3881
|
-
* Export pivot data to Excel format
|
|
3882
|
-
*/
|
|
3883
|
-
export_pivot_to_excel() {
|
|
3884
|
-
return this.eruGridStore.exportPivotToExcel();
|
|
3885
|
-
}
|
|
3268
|
+
// Excel/CSV export methods removed
|
|
3269
|
+
// Export functionality should be implemented in the consuming application
|
|
3886
3270
|
/**
|
|
3887
3271
|
* Validate pivot configuration
|
|
3888
3272
|
*/
|
|
@@ -4544,7 +3928,7 @@ class DataCellComponent {
|
|
|
4544
3928
|
columnValue: this.currentValue()
|
|
4545
3929
|
});
|
|
4546
3930
|
console.log(columnValues);
|
|
4547
|
-
this.eruGridStore().
|
|
3931
|
+
this.eruGridStore().setDrilldown({
|
|
4548
3932
|
frozenGrandTotalCell: this.frozenGrandTotalCell(),
|
|
4549
3933
|
columnName: columnName.join('_'),
|
|
4550
3934
|
rowId: rowId,
|
|
@@ -5500,8 +4884,6 @@ class EruGridComponent {
|
|
|
5500
4884
|
initialTotalWidth = 0;
|
|
5501
4885
|
vp;
|
|
5502
4886
|
groups = computed(() => this.gridStore.groups(), ...(ngDevMode ? [{ debugName: "groups" }] : []));
|
|
5503
|
-
rowLoadQueue = [];
|
|
5504
|
-
isProcessingQueue = false;
|
|
5505
4887
|
// Computed properties using the new GridStore
|
|
5506
4888
|
groupedRows = computed(() => this.createGroupedRows(), ...(ngDevMode ? [{ debugName: "groupedRows" }] : []));
|
|
5507
4889
|
columns = computed(() => this.gridStore.columns(), ...(ngDevMode ? [{ debugName: "columns" }] : []));
|
|
@@ -5596,34 +4978,39 @@ class EruGridComponent {
|
|
|
5596
4978
|
let totalWidth = columns.reduce((total, column) => total + column.field_size, 0);
|
|
5597
4979
|
return totalWidth;
|
|
5598
4980
|
}
|
|
5599
|
-
getContainerHeight() {
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
4981
|
+
/* getContainerHeight(): number {
|
|
4982
|
+
const element = this.rowContainer?.nativeElement;
|
|
4983
|
+
if (element) {
|
|
4984
|
+
return element.clientHeight;
|
|
5603
4985
|
}
|
|
5604
|
-
|
|
5605
|
-
}
|
|
4986
|
+
return window.innerHeight; // Fallback to viewport height
|
|
4987
|
+
} */
|
|
5606
4988
|
getMinHeightPx() {
|
|
5607
4989
|
//const parentHeight = this.getContainerHeight();
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
4990
|
+
if (this.gridStore.isPivotMode()) {
|
|
4991
|
+
let headerHeight = 0;
|
|
4992
|
+
let grandTotalHeight = 0;
|
|
4993
|
+
let rowHeight = this.gridStore.pivotDisplayData().length * 50;
|
|
4994
|
+
// Adjust based on frozen elements
|
|
4995
|
+
if (this.freezeHeader()) {
|
|
4996
|
+
headerHeight = this.maxDepth() * 35;
|
|
4997
|
+
}
|
|
4998
|
+
if (this.freezeGrandTotal() && this.grandTotalPosition() === 'before') {
|
|
4999
|
+
headerHeight = headerHeight + 50;
|
|
5000
|
+
}
|
|
5001
|
+
if (this.freezeGrandTotal() && this.grandTotalPosition() === 'after') {
|
|
5002
|
+
grandTotalHeight = 60;
|
|
5003
|
+
}
|
|
5004
|
+
let minHeight = (this.gridHeight() - headerHeight); // Start with 50% of parent
|
|
5005
|
+
// Ensure minimum usable height
|
|
5006
|
+
minHeight = Math.min(minHeight, rowHeight);
|
|
5007
|
+
minHeight = minHeight + 1;
|
|
5008
|
+
// Don't exceed parent height
|
|
5009
|
+
return minHeight;
|
|
5617
5010
|
}
|
|
5618
|
-
|
|
5619
|
-
|
|
5011
|
+
else {
|
|
5012
|
+
return this.gridHeight();
|
|
5620
5013
|
}
|
|
5621
|
-
let minHeight = (this.gridHeight() - headerHeight); // Start with 50% of parent
|
|
5622
|
-
// Ensure minimum usable height
|
|
5623
|
-
minHeight = Math.min(minHeight, rowHeight);
|
|
5624
|
-
minHeight = minHeight + 1;
|
|
5625
|
-
// Don't exceed parent height
|
|
5626
|
-
return minHeight;
|
|
5627
5014
|
}
|
|
5628
5015
|
adjustScrollWidth() {
|
|
5629
5016
|
let headerHeight = 0;
|
|
@@ -5639,14 +5026,16 @@ class EruGridComponent {
|
|
|
5639
5026
|
* Get the rendered range (what's in the DOM including buffer)
|
|
5640
5027
|
* @returns Object with start, end, and count of rendered items
|
|
5641
5028
|
*/
|
|
5642
|
-
getRenderedRange() {
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5029
|
+
/* getRenderedRange(): { start: number; end: number; count: number } {
|
|
5030
|
+
if (!this.viewport) {
|
|
5031
|
+
return { start: 0, end: 0, count: 0 };
|
|
5032
|
+
}
|
|
5033
|
+
|
|
5034
|
+
const range = this.viewport.getRenderedRange();
|
|
5035
|
+
const count = range.end - range.start;
|
|
5036
|
+
|
|
5037
|
+
return { start: range.start, end: range.end, count };
|
|
5038
|
+
} */
|
|
5650
5039
|
ROWS_PER_PAGE = 50;
|
|
5651
5040
|
SCROLL_THRESHOLD = 10;
|
|
5652
5041
|
lastLoadedGroupIds = new Set();
|
|
@@ -5724,7 +5113,7 @@ class EruGridComponent {
|
|
|
5724
5113
|
const rows = this.gridStore.rows();
|
|
5725
5114
|
const groups = this.gridStore.groups();
|
|
5726
5115
|
console.log("groups", groups);
|
|
5727
|
-
console.log("rows", rows);
|
|
5116
|
+
console.log("rows", rows?.length);
|
|
5728
5117
|
const flattenedRows = [];
|
|
5729
5118
|
if (groups.length > 0) {
|
|
5730
5119
|
groups.forEach(group => {
|
|
@@ -5754,70 +5143,25 @@ class EruGridComponent {
|
|
|
5754
5143
|
flattenedRows.push({ type: 'row', group: undefined, row });
|
|
5755
5144
|
});
|
|
5756
5145
|
}
|
|
5757
|
-
console.log("flattenedRows", flattenedRows);
|
|
5146
|
+
console.log("flattenedRows", flattenedRows?.length);
|
|
5758
5147
|
return flattenedRows;
|
|
5759
5148
|
}
|
|
5760
5149
|
initializeGroups() {
|
|
5761
5150
|
this.fetchInitialRows();
|
|
5762
5151
|
}
|
|
5763
5152
|
fetchInitialRows() {
|
|
5153
|
+
console.log("fetchInitialRows", this.gridStore.groups());
|
|
5764
5154
|
this.gridStore.groups().forEach(group => {
|
|
5765
5155
|
if (group.isExpanded) {
|
|
5766
|
-
this.
|
|
5156
|
+
this.requestRowsForGroup(group);
|
|
5767
5157
|
}
|
|
5768
5158
|
});
|
|
5769
5159
|
}
|
|
5770
|
-
fetchRowsForGroup
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
if (!group || !group.hasMoreRows) {
|
|
5774
|
-
resolve();
|
|
5775
|
-
return;
|
|
5776
|
-
}
|
|
5777
|
-
if (group.isLoading) {
|
|
5778
|
-
resolve();
|
|
5779
|
-
return;
|
|
5780
|
-
}
|
|
5781
|
-
this.gridStore.updateGroupLoadingState(groupId, true);
|
|
5782
|
-
const skip = page * pageSize;
|
|
5783
|
-
const loadTimeout = setTimeout(() => {
|
|
5784
|
-
this.gridStore.updateGroupLoadingState(groupId, false);
|
|
5785
|
-
reject(new Error('Task loading timed out'));
|
|
5786
|
-
}, 10000);
|
|
5787
|
-
this.gridStore.fetchNewRowData(pageSize, skip, group).subscribe({
|
|
5788
|
-
next: (response) => {
|
|
5789
|
-
clearTimeout(loadTimeout);
|
|
5790
|
-
if (!response || response.length === 0) {
|
|
5791
|
-
this.gridStore.updateGroupAfterLoading(groupId, 0, true);
|
|
5792
|
-
resolve();
|
|
5793
|
-
return;
|
|
5794
|
-
}
|
|
5795
|
-
const newRows = this.normalizeRowData(response.map((r) => ({ ...r, groupId })), group);
|
|
5796
|
-
this.gridStore.addRows(newRows);
|
|
5797
|
-
this.gridStore.updateGroupAfterLoading(groupId, newRows.length);
|
|
5798
|
-
this.changeDetectorRef.markForCheck();
|
|
5799
|
-
resolve();
|
|
5800
|
-
},
|
|
5801
|
-
error: (error) => {
|
|
5802
|
-
clearTimeout(loadTimeout);
|
|
5803
|
-
console.error(`Error loading tasks for group ${groupId}:`, error);
|
|
5804
|
-
this.gridStore.updateGroupLoadingState(groupId, false);
|
|
5805
|
-
this.markGroupAsNoMoreRows(groupId);
|
|
5806
|
-
reject(error);
|
|
5807
|
-
}
|
|
5808
|
-
});
|
|
5809
|
-
});
|
|
5810
|
-
}
|
|
5160
|
+
// fetchRowsForGroup - REMOVED
|
|
5161
|
+
// Data fetching is now handled by the consuming application via signal
|
|
5162
|
+
// See requestRowsForGroup() method below for the new approach
|
|
5811
5163
|
onScroll(scrollIndex) {
|
|
5812
|
-
|
|
5813
|
-
const visibleGroups = this.getVisibleGroups();
|
|
5814
|
-
visibleGroups.forEach(group => {
|
|
5815
|
-
if (group.isExpanded &&
|
|
5816
|
-
group.hasMoreRows &&
|
|
5817
|
-
!group.isLoading) {
|
|
5818
|
-
this.checkGroupRowLoading(group);
|
|
5819
|
-
}
|
|
5820
|
-
});
|
|
5164
|
+
console.log("onScroll called", scrollIndex);
|
|
5821
5165
|
this.checkAndLoadMoreRows();
|
|
5822
5166
|
}
|
|
5823
5167
|
getVisibleGroups() {
|
|
@@ -5836,7 +5180,7 @@ class EruGridComponent {
|
|
|
5836
5180
|
.filter((group) => group !== undefined);
|
|
5837
5181
|
}
|
|
5838
5182
|
getGroupItemAtIndex(index) {
|
|
5839
|
-
const groupItems = this.
|
|
5183
|
+
const groupItems = this.groupedRows();
|
|
5840
5184
|
return groupItems[index];
|
|
5841
5185
|
}
|
|
5842
5186
|
checkAndLoadMoreRows() {
|
|
@@ -5845,6 +5189,7 @@ class EruGridComponent {
|
|
|
5845
5189
|
const renderedRange = this.viewport.getRenderedRange();
|
|
5846
5190
|
const dataLength = this.viewport.getDataLength();
|
|
5847
5191
|
const isNearEnd = renderedRange.end >= (dataLength - this.SCROLL_THRESHOLD);
|
|
5192
|
+
console.log("isNearEnd", renderedRange, dataLength, isNearEnd);
|
|
5848
5193
|
if (isNearEnd) {
|
|
5849
5194
|
this.intelligentRowLoading();
|
|
5850
5195
|
}
|
|
@@ -5856,38 +5201,41 @@ class EruGridComponent {
|
|
|
5856
5201
|
!group.isLoading &&
|
|
5857
5202
|
!this.lastLoadedGroupIds.has(group.id));
|
|
5858
5203
|
const sortedGroupsToLoad = groupsToLoad.sort((a, b) => (a.currentLoadedRows || 0) - (b.currentLoadedRows || 0));
|
|
5204
|
+
console.log("sortedGroupsToLoad", sortedGroupsToLoad);
|
|
5859
5205
|
if (sortedGroupsToLoad.length > 0) {
|
|
5860
5206
|
const groupToLoad = sortedGroupsToLoad[0];
|
|
5861
|
-
|
|
5862
|
-
this.
|
|
5863
|
-
setTimeout(() => {
|
|
5864
|
-
this.lastLoadedGroupIds.delete(groupToLoad.id);
|
|
5865
|
-
}, 5000);
|
|
5866
|
-
}
|
|
5867
|
-
}
|
|
5868
|
-
checkGroupRowLoading(group) {
|
|
5869
|
-
const shouldLoadRows = group.currentLoadedRows < group.totalRowCount &&
|
|
5870
|
-
!this.lastLoadedGroupIds.has(group.id);
|
|
5871
|
-
if (shouldLoadRows) {
|
|
5872
|
-
this.queueRowLoading(group);
|
|
5873
|
-
}
|
|
5874
|
-
}
|
|
5875
|
-
queueRowLoading(group) {
|
|
5876
|
-
if (!group) {
|
|
5877
|
-
const groups = this.gridStore.groups();
|
|
5878
|
-
group = groups.find(g => g.isExpanded &&
|
|
5879
|
-
g.hasMoreRows &&
|
|
5880
|
-
!g.isLoading);
|
|
5881
|
-
}
|
|
5882
|
-
if (group) {
|
|
5883
|
-
this.rowLoadQueue.push({
|
|
5884
|
-
groupId: group.id,
|
|
5885
|
-
page: group.currentPage || 0,
|
|
5886
|
-
pageSize: group.totalRowCount < this.ROWS_PER_PAGE ? group.totalRowCount : this.ROWS_PER_PAGE
|
|
5887
|
-
});
|
|
5888
|
-
this.processRowLoadQueue();
|
|
5207
|
+
console.log("groupToLoad", groupToLoad);
|
|
5208
|
+
this.requestRowsForGroup(groupToLoad);
|
|
5889
5209
|
}
|
|
5890
5210
|
}
|
|
5211
|
+
// queueRowLoading - REPLACED with requestRowsForGroup
|
|
5212
|
+
// This method has been replaced with direct signal emission
|
|
5213
|
+
/**
|
|
5214
|
+
* Request rows for a specific group via signal
|
|
5215
|
+
*/
|
|
5216
|
+
requestRowsForGroup(group) {
|
|
5217
|
+
// Prevent duplicate requests
|
|
5218
|
+
console.log("requestRowsForGroup", group);
|
|
5219
|
+
if (this.lastLoadedGroupIds.has(group.id))
|
|
5220
|
+
return;
|
|
5221
|
+
const request = {
|
|
5222
|
+
groupId: group.id,
|
|
5223
|
+
page: group.currentPage || 0,
|
|
5224
|
+
pageSize: group.totalRowCount < this.ROWS_PER_PAGE ? group.totalRowCount : this.ROWS_PER_PAGE,
|
|
5225
|
+
timestamp: Date.now(),
|
|
5226
|
+
groupTitle: group.title
|
|
5227
|
+
};
|
|
5228
|
+
console.log('📤 Grid Component: Emitting data request', request);
|
|
5229
|
+
// Emit signal via store
|
|
5230
|
+
this.gridStore.setDataRequest(request);
|
|
5231
|
+
// Mark group as loading
|
|
5232
|
+
this.gridStore.startGroupLoading(group.id);
|
|
5233
|
+
// Prevent duplicate requests for 5 seconds
|
|
5234
|
+
this.lastLoadedGroupIds.add(group.id);
|
|
5235
|
+
setTimeout(() => {
|
|
5236
|
+
this.lastLoadedGroupIds.delete(group.id);
|
|
5237
|
+
}, 1000);
|
|
5238
|
+
}
|
|
5891
5239
|
trackByColumnFn(index, column) {
|
|
5892
5240
|
return column.name;
|
|
5893
5241
|
}
|
|
@@ -5951,35 +5299,36 @@ class EruGridComponent {
|
|
|
5951
5299
|
this.gridStore.setColumns(normalizedColumns);
|
|
5952
5300
|
}
|
|
5953
5301
|
// Enhanced method to normalize row data
|
|
5954
|
-
normalizeRowData(rows, group) {
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5302
|
+
/* private normalizeRowData(rows: any[], group?: RowGroup): any[] {
|
|
5303
|
+
return rows.map(row => ({
|
|
5304
|
+
...row,
|
|
5305
|
+
|
|
5306
|
+
groupTitle: group?.title,
|
|
5307
|
+
|
|
5308
|
+
displayValue: this.getDisplayValue(row),
|
|
5309
|
+
height: 50
|
|
5310
|
+
}));
|
|
5311
|
+
} */
|
|
5312
|
+
/* private getDisplayValue(row: any, column?: string): string {
|
|
5313
|
+
if (!column) {
|
|
5314
|
+
return this.getGenericRowDisplay(row);
|
|
5315
|
+
}
|
|
5316
|
+
|
|
5317
|
+
const value = row[column];
|
|
5318
|
+
if (value === null || value === undefined) return '';
|
|
5319
|
+
if (typeof value === 'string') return value.trim();
|
|
5320
|
+
if (typeof value === 'number') return value.toString();
|
|
5321
|
+
|
|
5322
|
+
return JSON.stringify(value);
|
|
5323
|
+
} */
|
|
5324
|
+
/* private getGenericRowDisplay(row: any): string {
|
|
5325
|
+
const displayProps = ['title', 'id', 'status'];
|
|
5326
|
+
return displayProps
|
|
5327
|
+
.map(prop => row[prop])
|
|
5328
|
+
.filter(value => value != null)
|
|
5329
|
+
.join(' - ')
|
|
5330
|
+
.trim();
|
|
5331
|
+
} */
|
|
5983
5332
|
toggleRowSelection(event, row) {
|
|
5984
5333
|
event.stopPropagation();
|
|
5985
5334
|
const checkbox = event.target;
|
|
@@ -6024,45 +5373,24 @@ class EruGridComponent {
|
|
|
6024
5373
|
getSelectedRows() {
|
|
6025
5374
|
return Array.from(this.gridStore.selectedRowIds());
|
|
6026
5375
|
}
|
|
6027
|
-
markGroupAsNoMoreRows(groupId) {
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
}
|
|
5376
|
+
/* private markGroupAsNoMoreRows(groupId: string) {
|
|
5377
|
+
// This functionality is now handled by GridStore.updateGroupAfterLoading
|
|
5378
|
+
this.gridStore.updateGroupAfterLoading(groupId, 0, true);
|
|
5379
|
+
} */
|
|
6031
5380
|
toggleGroupExpansion(groupId) {
|
|
6032
5381
|
const group = this.gridStore.groups().find(g => g.id === groupId);
|
|
6033
5382
|
if (!group)
|
|
6034
5383
|
return;
|
|
6035
5384
|
const newExpandedState = !group.isExpanded;
|
|
6036
5385
|
this.gridStore.toggleGroupExpansion(groupId);
|
|
5386
|
+
// Request data when expanding group with no data
|
|
6037
5387
|
if (newExpandedState && (!group.rows || group.rows.length === 0)) {
|
|
6038
|
-
this.
|
|
6039
|
-
.catch(error => {
|
|
6040
|
-
console.error(`Error loading rows for expanded group ${groupId}:`, error);
|
|
6041
|
-
});
|
|
6042
|
-
}
|
|
6043
|
-
}
|
|
6044
|
-
processRowLoadQueue() {
|
|
6045
|
-
if (this.isProcessingQueue)
|
|
6046
|
-
return;
|
|
6047
|
-
if (this.rowLoadQueue.length === 0) {
|
|
6048
|
-
this.isProcessingQueue = false;
|
|
6049
|
-
return;
|
|
6050
|
-
}
|
|
6051
|
-
this.isProcessingQueue = true;
|
|
6052
|
-
const nextLoad = this.rowLoadQueue.shift();
|
|
6053
|
-
if (nextLoad) {
|
|
6054
|
-
this.fetchRowsForGroup(nextLoad.groupId, nextLoad.page, nextLoad.pageSize)
|
|
6055
|
-
.then(() => {
|
|
6056
|
-
this.isProcessingQueue = false;
|
|
6057
|
-
this.processRowLoadQueue();
|
|
6058
|
-
})
|
|
6059
|
-
.catch(error => {
|
|
6060
|
-
console.error('Error loading rows:', error);
|
|
6061
|
-
this.isProcessingQueue = false;
|
|
6062
|
-
this.processRowLoadQueue();
|
|
6063
|
-
});
|
|
5388
|
+
this.requestRowsForGroup(group);
|
|
6064
5389
|
}
|
|
6065
5390
|
}
|
|
5391
|
+
// processRowLoadQueue - REMOVED
|
|
5392
|
+
// Queue-based loading is replaced with direct signal emission
|
|
5393
|
+
// See requestRowsForGroup() method for the new approach
|
|
6066
5394
|
// Collapsible column methods
|
|
6067
5395
|
/**
|
|
6068
5396
|
* Toggle collapse/expand state of a column group
|
|
@@ -6149,94 +5477,103 @@ class EruGridComponent {
|
|
|
6149
5477
|
* Get rowspan value for a specific cell - VIRTUAL SCROLLING COMPATIBLE
|
|
6150
5478
|
* This is a compatibility wrapper around getEffectiveRowspan
|
|
6151
5479
|
*/
|
|
6152
|
-
getCellRowspan(rowIndex, columnName) {
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
5480
|
+
/* getCellRowspan(rowIndex: number, columnName: string): number {
|
|
5481
|
+
const effectiveRowspan = this.getEffectiveRowspan(rowIndex, columnName);
|
|
5482
|
+
return effectiveRowspan || 1;
|
|
5483
|
+
} */
|
|
6156
5484
|
/**
|
|
6157
5485
|
* Get columns that should be frozen on the left (all row dimensions up to and including freezeField)
|
|
6158
5486
|
*/
|
|
6159
|
-
getRowDimensionColumns() {
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
5487
|
+
/* getRowDimensionColumns(): any[] {
|
|
5488
|
+
if (!this.gridStore.isFreezeEnabled()) return [];
|
|
5489
|
+
|
|
5490
|
+
const freezeField = this.gridStore.getFreezeField();
|
|
5491
|
+
if (!freezeField) return [];
|
|
5492
|
+
|
|
5493
|
+
const allColumns = this.getLeafColumns();
|
|
5494
|
+
const pivotConfig = this.gridStore.pivotConfiguration();
|
|
5495
|
+
|
|
5496
|
+
if (!pivotConfig?.rows) return [];
|
|
5497
|
+
|
|
5498
|
+
// Find the index of the freeze field in the row dimensions
|
|
5499
|
+
const freezeFieldIndex = pivotConfig.rows.indexOf(freezeField);
|
|
5500
|
+
if (freezeFieldIndex === -1) return [];
|
|
5501
|
+
|
|
5502
|
+
// Return all row dimension columns up to and including the freeze field
|
|
5503
|
+
const rowDimensionsToFreeze = pivotConfig.rows.slice(0, freezeFieldIndex + 1);
|
|
5504
|
+
return allColumns.filter(col => rowDimensionsToFreeze.includes(col.name));
|
|
5505
|
+
} */
|
|
6177
5506
|
/**
|
|
6178
5507
|
* Get columns that should be scrollable on the right (all except frozen fields)
|
|
6179
5508
|
*/
|
|
6180
|
-
getColumnDimensionColumns() {
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
5509
|
+
/* getColumnDimensionColumns(): any[] {
|
|
5510
|
+
const allColumns = this.getLeafColumns();
|
|
5511
|
+
|
|
5512
|
+
if (!this.gridStore.isFreezeEnabled()) return allColumns;
|
|
5513
|
+
|
|
5514
|
+
const freezeField = this.gridStore.getFreezeField();
|
|
5515
|
+
if (!freezeField) return allColumns;
|
|
5516
|
+
|
|
5517
|
+
const pivotConfig = this.gridStore.pivotConfiguration();
|
|
5518
|
+
if (!pivotConfig?.rows) return allColumns;
|
|
5519
|
+
|
|
5520
|
+
// Find the index of the freeze field in the row dimensions
|
|
5521
|
+
const freezeFieldIndex = pivotConfig.rows.indexOf(freezeField);
|
|
5522
|
+
if (freezeFieldIndex === -1) return allColumns;
|
|
5523
|
+
|
|
5524
|
+
// Get all row dimensions that should be frozen
|
|
5525
|
+
const rowDimensionsToFreeze = pivotConfig.rows.slice(0, freezeFieldIndex + 1);
|
|
5526
|
+
|
|
5527
|
+
// Return all columns except the frozen row dimensions
|
|
5528
|
+
return allColumns.filter(col => !rowDimensionsToFreeze.includes(col.name));
|
|
5529
|
+
} */
|
|
6199
5530
|
/**
|
|
6200
5531
|
* Get headers that should be frozen (all row dimension headers up to and including freezeField)
|
|
6201
5532
|
*/
|
|
6202
|
-
getRowDimensionHeaders(headerRow) {
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
5533
|
+
/* getRowDimensionHeaders(headerRow: any[]): any[] {
|
|
5534
|
+
if (!this.gridStore.isFreezeEnabled()) return [];
|
|
5535
|
+
|
|
5536
|
+
const freezeField = this.gridStore.getFreezeField();
|
|
5537
|
+
if (!freezeField) return [];
|
|
5538
|
+
|
|
5539
|
+
const pivotConfig = this.gridStore.pivotConfiguration();
|
|
5540
|
+
if (!pivotConfig?.rows) return [];
|
|
5541
|
+
|
|
5542
|
+
// Find the index of the freeze field in the row dimensions
|
|
5543
|
+
const freezeFieldIndex = pivotConfig.rows.indexOf(freezeField);
|
|
5544
|
+
if (freezeFieldIndex === -1) return [];
|
|
5545
|
+
|
|
5546
|
+
// Get all row dimensions that should be frozen
|
|
5547
|
+
const rowDimensionsToFreeze = pivotConfig.rows.slice(0, freezeFieldIndex + 1);
|
|
5548
|
+
|
|
5549
|
+
return headerRow.filter(header =>
|
|
5550
|
+
rowDimensionsToFreeze.includes(header.name) ||
|
|
5551
|
+
(header.name && rowDimensionsToFreeze.includes(header.name))
|
|
5552
|
+
);
|
|
5553
|
+
} */
|
|
6220
5554
|
/**
|
|
6221
5555
|
* Get headers that should be scrollable (all except frozen fields)
|
|
6222
5556
|
*/
|
|
6223
|
-
getColumnDimensionHeaders(headerRow) {
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
5557
|
+
/* getColumnDimensionHeaders(headerRow: any[]): any[] {
|
|
5558
|
+
if (!this.gridStore.isFreezeEnabled()) return headerRow;
|
|
5559
|
+
|
|
5560
|
+
const freezeField = this.gridStore.getFreezeField();
|
|
5561
|
+
if (!freezeField) return headerRow;
|
|
5562
|
+
|
|
5563
|
+
const pivotConfig = this.gridStore.pivotConfiguration();
|
|
5564
|
+
if (!pivotConfig?.rows) return headerRow;
|
|
5565
|
+
|
|
5566
|
+
// Find the index of the freeze field in the row dimensions
|
|
5567
|
+
const freezeFieldIndex = pivotConfig.rows.indexOf(freezeField);
|
|
5568
|
+
if (freezeFieldIndex === -1) return headerRow;
|
|
5569
|
+
|
|
5570
|
+
// Get all row dimensions that should be frozen
|
|
5571
|
+
const rowDimensionsToFreeze = pivotConfig.rows.slice(0, freezeFieldIndex + 1);
|
|
5572
|
+
|
|
5573
|
+
return headerRow.filter(header =>
|
|
5574
|
+
!rowDimensionsToFreeze.includes(header.name)
|
|
5575
|
+
);
|
|
5576
|
+
} */
|
|
6240
5577
|
/**
|
|
6241
5578
|
* Check if a column should be sticky (frozen on the left)
|
|
6242
5579
|
*/
|
|
@@ -6424,7 +5761,7 @@ class EruGridComponent {
|
|
|
6424
5761
|
return this.columns().length;
|
|
6425
5762
|
}
|
|
6426
5763
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EruGridComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
6427
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: EruGridComponent, isStandalone: true, selector: "eru-grid", inputs: { gridConfig: "gridConfig" }, providers: [EruGridStore, EruGridService], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "rowContainer", first: true, predicate: ["rowContainer"], descendants: true }, { propertyName: "headerScroller", first: true, predicate: ["headerScroller"], descendants: true, read: ElementRef }, { propertyName: "gtScroller", first: true, predicate: ["gtScroller"], descendants: true, read: ElementRef }, { propertyName: "vp", first: true, predicate: ["vp"], descendants: true }], ngImport: i0, template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\n currentPivotScrollIndex {{currentPivotScrollIndex()}} | \n firstDataRowIndex {{firstDataRowIndex()}} | \n firstTr {{firstTr}} |\n maxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer \n [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode()\">\n \n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container >\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n \n \n <div class=\"pivot-single-table\" style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table> \n </div>\n } \n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport\n #vp\n [itemSize]=\"50\"\n class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\"\n (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\"\n style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\"\n >\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container> \n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n \n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\"\n class=\"pivot-row\"\n [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) { \n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n @if (!shouldSkipCell(i, column.name)) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [class.aggregation]=\"!!column.aggregationFunction\"\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n }\n } @else {\n <td [style.height.px]=\"50\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr> \n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\"\n [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n \n </table> \n </div>\n }\n \n\n </div>\n </div>\n </ng-container>\n} @else {\n \n<!-- Table Mode Template -->\n <ng-container>\n <cdk-virtual-scroll-viewport\n [itemSize]=\"30\"\n class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event)\"\n >\n <div class=\"table-wrapper\">\n \n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\" [class.show-column-lines]=\"showColumnLines()\">\n <thead>\n <tr>\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\"></th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"column-header\">\n {{column.label}}\n </th>\n </tr>\n </thead>\n <tbody *ngIf=\"columns() as columnsList\">\n <ng-container *cdkVirtualFor=\"let groupItem of groupedRows();\n trackBy: trackByGroupItemFn;\n let i = index;\n let first=first\">\n <tr\n *ngIf=\"groupItem.type === 'header' && groups().length > 1\"\n class=\"group-header\"\n (click)=\"toggleGroupExpansion(groupItem.group?.id || '')\"\n >\n \n <td class=\"checkbox-column\" style=\"border: none;\">\n {{ groupItem.group?.isExpanded ? '\u25BC' : '\u25B6' }}\n </td>\n \n <td [attr.colspan]=\"2\" style=\"border: none;\">\n <span class=\"group-title\">\n {{ groupItem.group?.title }}\n </span>\n <span class=\"group-row-count\">\n ({{ groupItem.group?.currentLoadedRows || 0 }}/{{ groupItem.group?.totalRowCount || 0 }})\n </span>\n </td>\n </tr>\n <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr>\n <tr\n *ngIf=\"groupItem.type === 'row' && groupItem.group?.isExpanded\"\n class=\"row-item\"\n [attr.data-row-id]=\"groupItem.row?.entity_id\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isRowSelected(groupItem.row?.entity_id)\"\n (change)=\"toggleRowSelection($event, groupItem.row)\"\n >\n </td>\n }\n <td #cell *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n [matTooltipClass]=\"'error-message'\"\n [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\"\n >\n <div class=\"cell-content\">\n <data-cell\n #datacell \n [td]=cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"groupItem.row?.[column.name] || ''\"\n [column]=\"column\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [drillable]=\"column.enableDrilldown || false\"\n [id]=\"groupItem.row?.['entity_id'] || '_' ||column.name\"\n [eruGridStore]=\"gridStore\"\n ></data-cell>\n </div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'ghost-loading' && groupItem.group?.isExpanded\"\n class=\"ghost-loading-row\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n <td class=\"checkbox-column\"></td>\n <td *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\"\n >\n <div class=\"ghost-cell\"></div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'row-place-holder'\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container> \n}\n</div>\n\n <!-- Pivot Table Header Template -->\n <ng-template #pivotTableHead>\n <thead>\n @if (hasNestedHeaders()) {\n <ng-container >\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" \n [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th\n [attr.colspan]=\"header.colspan\"\n [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\"\n [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\"\n [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n style=\"min-height: 40px; height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n \n <data-cell\n [fieldSize]=\"header.field_size\"\n [columnDatatype]=\"header.dataType\"\n [columnName]=\"header.name\"\n [value]=\"header.label\"\n [column]=\"header\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\" \n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n style = \"min-height: 40px;height: auto;padding: 8px 6px;position: relative;left: 0px;z-index: 1\">\n {{column.label}}\n </th>\n }\n </tr>\n </ng-container>\n }\n \n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n<tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr \n class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" \n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n}\n</tbody>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;height:100%;font-family:var(--grid-font-family);--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6;--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15)}.incremental-row-container{padding:10px;width:100%;height:100%;min-height:var(--table-min-height, 400px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);box-shadow:var(--grid-elevation-1);font-family:var(--grid-font-family)}.viewport{overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-viewport{background-color:var(--grid-surface);height:auto;min-height:var(--table-min-height, 300px);max-height:80vh;overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;background-color:var(--grid-surface);color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th:hover,.eru-grid-table td:hover{background-color:var(--grid-surface-variant)}.eru-grid-table thead{background-color:var(--grid-surface-container);transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{box-shadow:0 2px 4px #0000001a;border-bottom:2px solid var(--grid-outline)}.eru-grid-table thead th{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-weight:500;font-size:var(--grid-font-size-caption)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;border:1px solid var(--grid-outline);background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{border:1px solid var(--grid-outline);background-color:var(--grid-surface);transition:background-color .2s ease,box-shadow .2s ease}.row-item:hover{background-color:var(--grid-surface-variant);box-shadow:var(--grid-elevation-1)}.column-header{font-weight:500;text-align:center!important;font-size:var(--grid-font-size-caption, 12px);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-surface-container);color:var(--grid-on-surface)}.column-header:hover{background-color:var(--grid-surface-container-high)}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-outline-width, 1px) * 2);background-color:var(--grid-outline, #e0e0e0);pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}@media (max-width: 768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media (prefers-contrast: high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media (prefers-reduced-motion: reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .rowspan-cell{vertical-align:middle}.pivot-table .rowspan-cell .pivot-cell-content{height:100%}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:50px!important;height:50px!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:50px!important;height:50px!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:48px;display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:46px;display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:40px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}\n"], dependencies: [{ kind: "component", type: DataCellComponent, selector: "data-cell", inputs: ["eruGridStore", "fieldSize", "columnDatatype", "columnName", "column", "value", "id", "frozenGrandTotalCell", "td", "drillable", "mode", "isEditable"], outputs: ["tdChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1$2.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1$2.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1$2.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: ResizeColumnDirective, selector: "[resizeColumn]", inputs: ["resizeColumn", "index", "columnConfig", "gridConfig"] }, { kind: "directive", type: ColumnDragDirective, selector: "[columnDraggable]", inputs: ["columnDraggable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
5764
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: EruGridComponent, isStandalone: true, selector: "eru-grid", inputs: { gridConfig: "gridConfig" }, providers: [EruGridStore, EruGridService], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "rowContainer", first: true, predicate: ["rowContainer"], descendants: true }, { propertyName: "headerScroller", first: true, predicate: ["headerScroller"], descendants: true, read: ElementRef }, { propertyName: "gtScroller", first: true, predicate: ["gtScroller"], descendants: true, read: ElementRef }, { propertyName: "vp", first: true, predicate: ["vp"], descendants: true }], ngImport: i0, template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\n currentPivotScrollIndex {{currentPivotScrollIndex()}} | \n firstDataRowIndex {{firstDataRowIndex()}} | \n firstTr {{firstTr}} |\n maxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer \n [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode()\">\n \n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container >\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n \n \n <div class=\"pivot-single-table\" style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table> \n </div>\n } \n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport\n #vp\n [itemSize]=\"50\"\n class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\"\n (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\"\n style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\"\n >\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container> \n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n \n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\"\n class=\"pivot-row\"\n [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) { \n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n @if (!shouldSkipCell(i, column.name)) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [class.aggregation]=\"!!column.aggregationFunction\"\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n }\n } @else {\n <td [style.height.px]=\"50\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr> \n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\"\n [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n \n </table> \n </div>\n }\n \n\n </div>\n </div>\n </ng-container>\n} @else {\n \n<!-- Table Mode Template -->\n <ng-container>\n <cdk-virtual-scroll-viewport\n [itemSize]=\"30\"\n class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event)\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n >\n <div class=\"table-wrapper\">\n \n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\" [class.show-column-lines]=\"showColumnLines()\">\n <thead>\n <tr>\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\"></th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"column-header table-column-header\">\n {{column.label}}\n </th>\n </tr>\n </thead>\n <tbody *ngIf=\"columns() as columnsList\">\n <ng-container *cdkVirtualFor=\"let groupItem of groupedRows();\n trackBy: trackByGroupItemFn;\n let i = index;\n let first=first\">\n <tr\n *ngIf=\"groupItem.type === 'header' && groups().length > 1\"\n class=\"group-header\"\n (click)=\"toggleGroupExpansion(groupItem.group?.id || '')\"\n >\n \n <td class=\"checkbox-column\" style=\"border: none;\">\n {{ groupItem.group?.isExpanded ? '\u25BC' : '\u25B6' }}\n </td>\n \n <td [attr.colspan]=\"2\" style=\"border: none;\">\n <span class=\"group-title\">\n {{ groupItem.group?.title }}\n </span>\n <span class=\"group-row-count\">\n ({{ groupItem.group?.currentLoadedRows || 0 }}/{{ groupItem.group?.totalRowCount || 0 }})\n </span>\n </td>\n </tr>\n <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr>\n <tr\n *ngIf=\"groupItem.type === 'row' && groupItem.group?.isExpanded\"\n class=\"row-item\"\n [attr.data-row-id]=\"groupItem.row?.entity_id\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isRowSelected(groupItem.row?.entity_id)\"\n (change)=\"toggleRowSelection($event, groupItem.row)\"\n >\n </td>\n }\n <td #cell *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n [matTooltipClass]=\"'error-message'\"\n [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\"\n >\n <div class=\"cell-content\">\n <data-cell\n #datacell \n [td]=cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"groupItem.row?.[column.name] || ''\"\n [column]=\"column\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [drillable]=\"column.enableDrilldown || false\"\n [id]=\"i + '_' + column.name\"\n [eruGridStore]=\"gridStore\"\n ></data-cell>\n </div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'ghost-loading' && groupItem.group?.isExpanded\"\n class=\"ghost-loading-row\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\"></th>\n }\n <td *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\"\n >\n <div class=\"ghost-cell\"></div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'row-place-holder'\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container> \n}\n</div>\n\n <!-- Pivot Table Header Template -->\n <ng-template #pivotTableHead>\n <thead>\n @if (hasNestedHeaders()) {\n <ng-container >\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" \n [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th\n [attr.colspan]=\"header.colspan\"\n [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\"\n [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\"\n [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n style=\"min-height: 40px; height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n \n <data-cell\n [fieldSize]=\"header.field_size\"\n [columnDatatype]=\"header.dataType\"\n [columnName]=\"header.name\"\n [value]=\"header.label\"\n [column]=\"header\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\" \n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n style = \"min-height: 40px;height: auto;padding: 8px 6px;position: relative;left: 0px;z-index: 1\">\n {{column.label}}\n </th>\n }\n </tr>\n </ng-container>\n }\n \n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n<tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr \n class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" \n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n}\n</tbody>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;height:100%;font-family:var(--grid-font-family);--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6;--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15)}.incremental-row-container{padding:10px;width:100%;height:100%;min-height:var(--table-min-height, 400px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);box-shadow:var(--grid-elevation-1);font-family:var(--grid-font-family)}.viewport{overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-viewport{background-color:var(--grid-surface);height:auto;min-height:var(--table-min-height, 300px);max-height:80vh;overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;background-color:var(--grid-surface);color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th:hover,.eru-grid-table td:hover{background-color:var(--grid-surface-variant)}.eru-grid-table thead{background-color:var(--grid-surface-container);transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{box-shadow:0 2px 4px #0000001a;border-bottom:2px solid var(--grid-outline)}.eru-grid-table thead th{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-weight:500;font-size:var(--grid-font-size-caption)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;border:1px solid var(--grid-outline);background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{border:1px solid var(--grid-outline);background-color:var(--grid-surface);transition:background-color .2s ease,box-shadow .2s ease}.row-item:hover{background-color:var(--grid-surface-variant);box-shadow:var(--grid-elevation-1)}.table-column-header{padding:12px 8px}.column-header{font-weight:500;text-align:center!important;font-size:var(--grid-font-size-caption, 12px);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-surface-container);color:var(--grid-on-surface)}.column-header:hover{background-color:var(--grid-surface-container-high)}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-outline-width, 1px) * 2);background-color:var(--grid-outline, #e0e0e0);pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}@media (max-width: 768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media (prefers-contrast: high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media (prefers-reduced-motion: reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .rowspan-cell{vertical-align:middle}.pivot-table .rowspan-cell .pivot-cell-content{height:100%}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:50px!important;height:50px!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:50px!important;height:50px!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:48px;display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:46px;display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:40px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}\n"], dependencies: [{ kind: "component", type: DataCellComponent, selector: "data-cell", inputs: ["eruGridStore", "fieldSize", "columnDatatype", "columnName", "column", "value", "id", "frozenGrandTotalCell", "td", "drillable", "mode", "isEditable"], outputs: ["tdChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1$2.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1$2.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1$2.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: ResizeColumnDirective, selector: "[resizeColumn]", inputs: ["resizeColumn", "index", "columnConfig", "gridConfig"] }, { kind: "directive", type: ColumnDragDirective, selector: "[columnDraggable]", inputs: ["columnDraggable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
6428
5765
|
}
|
|
6429
5766
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: EruGridComponent, decorators: [{
|
|
6430
5767
|
type: Component,
|
|
@@ -6435,7 +5772,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImpor
|
|
|
6435
5772
|
MatTooltipModule,
|
|
6436
5773
|
ResizeColumnDirective,
|
|
6437
5774
|
ColumnDragDirective
|
|
6438
|
-
], template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\n currentPivotScrollIndex {{currentPivotScrollIndex()}} | \n firstDataRowIndex {{firstDataRowIndex()}} | \n firstTr {{firstTr}} |\n maxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer \n [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode()\">\n \n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container >\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n \n \n <div class=\"pivot-single-table\" style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table> \n </div>\n } \n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport\n #vp\n [itemSize]=\"50\"\n class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\"\n (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\"\n style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\"\n >\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container> \n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n \n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\"\n class=\"pivot-row\"\n [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) { \n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n @if (!shouldSkipCell(i, column.name)) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [class.aggregation]=\"!!column.aggregationFunction\"\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n }\n } @else {\n <td [style.height.px]=\"50\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr> \n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\"\n [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n \n </table> \n </div>\n }\n \n\n </div>\n </div>\n </ng-container>\n} @else {\n \n<!-- Table Mode Template -->\n <ng-container>\n <cdk-virtual-scroll-viewport\n [itemSize]=\"30\"\n class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event)\"\n >\n <div class=\"table-wrapper\">\n \n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\" [class.show-column-lines]=\"showColumnLines()\">\n <thead>\n <tr>\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\"></th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"column-header\">\n {{column.label}}\n </th>\n </tr>\n </thead>\n <tbody *ngIf=\"columns() as columnsList\">\n <ng-container *cdkVirtualFor=\"let groupItem of groupedRows();\n trackBy: trackByGroupItemFn;\n let i = index;\n let first=first\">\n <tr\n *ngIf=\"groupItem.type === 'header' && groups().length > 1\"\n class=\"group-header\"\n (click)=\"toggleGroupExpansion(groupItem.group?.id || '')\"\n >\n \n <td class=\"checkbox-column\" style=\"border: none;\">\n {{ groupItem.group?.isExpanded ? '\u25BC' : '\u25B6' }}\n </td>\n \n <td [attr.colspan]=\"2\" style=\"border: none;\">\n <span class=\"group-title\">\n {{ groupItem.group?.title }}\n </span>\n <span class=\"group-row-count\">\n ({{ groupItem.group?.currentLoadedRows || 0 }}/{{ groupItem.group?.totalRowCount || 0 }})\n </span>\n </td>\n </tr>\n <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr>\n <tr\n *ngIf=\"groupItem.type === 'row' && groupItem.group?.isExpanded\"\n class=\"row-item\"\n [attr.data-row-id]=\"groupItem.row?.entity_id\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isRowSelected(groupItem.row?.entity_id)\"\n (change)=\"toggleRowSelection($event, groupItem.row)\"\n >\n </td>\n }\n <td #cell *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n [matTooltipClass]=\"'error-message'\"\n [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\"\n >\n <div class=\"cell-content\">\n <data-cell\n #datacell \n [td]=cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"groupItem.row?.[column.name] || ''\"\n [column]=\"column\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [drillable]=\"column.enableDrilldown || false\"\n [id]=\"groupItem.row?.['entity_id'] || '_' ||column.name\"\n [eruGridStore]=\"gridStore\"\n ></data-cell>\n </div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'ghost-loading' && groupItem.group?.isExpanded\"\n class=\"ghost-loading-row\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n <td class=\"checkbox-column\"></td>\n <td *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\"\n >\n <div class=\"ghost-cell\"></div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'row-place-holder'\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container> \n}\n</div>\n\n <!-- Pivot Table Header Template -->\n <ng-template #pivotTableHead>\n <thead>\n @if (hasNestedHeaders()) {\n <ng-container >\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" \n [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th\n [attr.colspan]=\"header.colspan\"\n [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\"\n [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\"\n [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n style=\"min-height: 40px; height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n \n <data-cell\n [fieldSize]=\"header.field_size\"\n [columnDatatype]=\"header.dataType\"\n [columnName]=\"header.name\"\n [value]=\"header.label\"\n [column]=\"header\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\" \n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n style = \"min-height: 40px;height: auto;padding: 8px 6px;position: relative;left: 0px;z-index: 1\">\n {{column.label}}\n </th>\n }\n </tr>\n </ng-container>\n }\n \n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n<tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr \n class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" \n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n}\n</tbody>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;height:100%;font-family:var(--grid-font-family);--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6;--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15)}.incremental-row-container{padding:10px;width:100%;height:100%;min-height:var(--table-min-height, 400px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);box-shadow:var(--grid-elevation-1);font-family:var(--grid-font-family)}.viewport{overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-viewport{background-color:var(--grid-surface);height:auto;min-height:var(--table-min-height, 300px);max-height:80vh;overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;background-color:var(--grid-surface);color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th:hover,.eru-grid-table td:hover{background-color:var(--grid-surface-variant)}.eru-grid-table thead{background-color:var(--grid-surface-container);transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{box-shadow:0 2px 4px #0000001a;border-bottom:2px solid var(--grid-outline)}.eru-grid-table thead th{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-weight:500;font-size:var(--grid-font-size-caption)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;border:1px solid var(--grid-outline);background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{border:1px solid var(--grid-outline);background-color:var(--grid-surface);transition:background-color .2s ease,box-shadow .2s ease}.row-item:hover{background-color:var(--grid-surface-variant);box-shadow:var(--grid-elevation-1)}.column-header{font-weight:500;text-align:center!important;font-size:var(--grid-font-size-caption, 12px);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-surface-container);color:var(--grid-on-surface)}.column-header:hover{background-color:var(--grid-surface-container-high)}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-outline-width, 1px) * 2);background-color:var(--grid-outline, #e0e0e0);pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}@media (max-width: 768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media (prefers-contrast: high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media (prefers-reduced-motion: reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .rowspan-cell{vertical-align:middle}.pivot-table .rowspan-cell .pivot-cell-content{height:100%}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:50px!important;height:50px!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:50px!important;height:50px!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:48px;display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:46px;display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:40px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}\n"] }]
|
|
5775
|
+
], template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\n currentPivotScrollIndex {{currentPivotScrollIndex()}} | \n firstDataRowIndex {{firstDataRowIndex()}} | \n firstTr {{firstTr}} |\n maxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer \n [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode()\">\n \n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container >\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n \n \n <div class=\"pivot-single-table\" style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table> \n </div>\n } \n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport\n #vp\n [itemSize]=\"50\"\n class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\"\n (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\"\n style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\"\n >\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container> \n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n \n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\"\n class=\"pivot-row\"\n [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) { \n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n @if (!shouldSkipCell(i, column.name)) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [class.aggregation]=\"!!column.aggregationFunction\"\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n }\n } @else {\n <td [style.height.px]=\"50\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr> \n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\"\n [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\" \n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" \n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n \n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n \n </table> \n </div>\n }\n \n\n </div>\n </div>\n </ng-container>\n} @else {\n \n<!-- Table Mode Template -->\n <ng-container>\n <cdk-virtual-scroll-viewport\n [itemSize]=\"30\"\n class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event)\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n >\n <div class=\"table-wrapper\">\n \n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\" [class.show-column-lines]=\"showColumnLines()\">\n <thead>\n <tr>\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\"></th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"column-header table-column-header\">\n {{column.label}}\n </th>\n </tr>\n </thead>\n <tbody *ngIf=\"columns() as columnsList\">\n <ng-container *cdkVirtualFor=\"let groupItem of groupedRows();\n trackBy: trackByGroupItemFn;\n let i = index;\n let first=first\">\n <tr\n *ngIf=\"groupItem.type === 'header' && groups().length > 1\"\n class=\"group-header\"\n (click)=\"toggleGroupExpansion(groupItem.group?.id || '')\"\n >\n \n <td class=\"checkbox-column\" style=\"border: none;\">\n {{ groupItem.group?.isExpanded ? '\u25BC' : '\u25B6' }}\n </td>\n \n <td [attr.colspan]=\"2\" style=\"border: none;\">\n <span class=\"group-title\">\n {{ groupItem.group?.title }}\n </span>\n <span class=\"group-row-count\">\n ({{ groupItem.group?.currentLoadedRows || 0 }}/{{ groupItem.group?.totalRowCount || 0 }})\n </span>\n </td>\n </tr>\n <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr>\n <tr\n *ngIf=\"groupItem.type === 'row' && groupItem.group?.isExpanded\"\n class=\"row-item\"\n [attr.data-row-id]=\"groupItem.row?.entity_id\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isRowSelected(groupItem.row?.entity_id)\"\n (change)=\"toggleRowSelection($event, groupItem.row)\"\n >\n </td>\n }\n <td #cell *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n [matTooltipClass]=\"'error-message'\"\n [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\"\n >\n <div class=\"cell-content\">\n <data-cell\n #datacell \n [td]=cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"groupItem.row?.[column.name] || ''\"\n [column]=\"column\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [drillable]=\"column.enableDrilldown || false\"\n [id]=\"i + '_' + column.name\"\n [eruGridStore]=\"gridStore\"\n ></data-cell>\n </div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'ghost-loading' && groupItem.group?.isExpanded\"\n class=\"ghost-loading-row\"\n [style.height.px]=\"30\"\n [style.minHeight.px]=\"30\"\n [style.maxHeight.px]=\"30\"\n >\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\"></th>\n }\n <td *ngFor=\"let column of columns(); trackBy: trackByColumnFn\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\"\n >\n <div class=\"ghost-cell\"></div>\n </td>\n </tr>\n\n <tr\n *ngIf=\"groupItem.type === 'row-place-holder'\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr>\n </ng-container>\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container> \n}\n</div>\n\n <!-- Pivot Table Header Template -->\n <ng-template #pivotTableHead>\n <thead>\n @if (hasNestedHeaders()) {\n <ng-container >\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" \n [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th\n [attr.colspan]=\"header.colspan\"\n [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\"\n [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\"\n [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n style=\"min-height: 40px; height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n \n <data-cell\n [fieldSize]=\"header.field_size\"\n [columnDatatype]=\"header.dataType\"\n [columnName]=\"header.name\"\n [value]=\"header.label\"\n [column]=\"header\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\" \n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n style = \"min-height: 40px;height: auto;padding: 8px 6px;position: relative;left: 0px;z-index: 1\">\n {{column.label}}\n </th>\n }\n </tr>\n </ng-container>\n }\n \n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n<tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr \n class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\"\n [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td\n [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" \n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\"\n [style.height.px]=\"50\"\n [attr.xx]=\"i\"> \n <div class=\"cell-content pivot-cell-content\">\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\"\n [column]=\"column\"\n [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\"\n [mode]=\"mode()\"\n [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\"\n [eruGridStore]=\"gridStore\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n}\n</tbody>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:block;width:100%;height:100%;font-family:var(--grid-font-family);--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6;--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15)}.incremental-row-container{padding:10px;width:100%;height:100%;min-height:var(--table-min-height, 400px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);box-shadow:var(--grid-elevation-1);font-family:var(--grid-font-family)}.viewport{overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-viewport{background-color:var(--grid-surface);height:auto;min-height:var(--table-min-height, 300px);max-height:80vh;overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;background-color:var(--grid-surface);color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th:hover,.eru-grid-table td:hover{background-color:var(--grid-surface-variant)}.eru-grid-table thead{background-color:var(--grid-surface-container);transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{box-shadow:0 2px 4px #0000001a;border-bottom:2px solid var(--grid-outline)}.eru-grid-table thead th{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-weight:500;font-size:var(--grid-font-size-caption)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;border:1px solid var(--grid-outline);background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{border:1px solid var(--grid-outline);background-color:var(--grid-surface);transition:background-color .2s ease,box-shadow .2s ease}.row-item:hover{background-color:var(--grid-surface-variant);box-shadow:var(--grid-elevation-1)}.table-column-header{padding:12px 8px}.column-header{font-weight:500;text-align:center!important;font-size:var(--grid-font-size-caption, 12px);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-surface-container);color:var(--grid-on-surface)}.column-header:hover{background-color:var(--grid-surface-container-high)}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:var(--grid-surface);color:var(--grid-on-surface);font-size:var(--grid-font-size-body)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-outline-width, 1px) * 2);background-color:var(--grid-outline, #e0e0e0);pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines thead th{border-left:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}@media (max-width: 768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media (prefers-contrast: high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media (prefers-reduced-motion: reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .rowspan-cell{vertical-align:middle}.pivot-table .rowspan-cell .pivot-cell-content{height:100%}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:50px!important;height:50px!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:50px!important;height:50px!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:48px;display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:46px;display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:40px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}\n"] }]
|
|
6439
5776
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { viewport: [{
|
|
6440
5777
|
type: ViewChild,
|
|
6441
5778
|
args: [CdkVirtualScrollViewport]
|