@sme.up/doc-alchemist 1.2.0-SNAPSHOT-20250626070253 → 1.2.0-SNAPSHOT-20250627103210

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/README.md CHANGED
@@ -187,7 +187,3 @@ The project includes comprehensive VS Code debug configurations:
187
187
  - Follow existing code formatting
188
188
  - Write tests for new features
189
189
  - Use meaningful variable and function names
190
-
191
- ---
192
-
193
- **Note**: This library is designed to work with SmeupDataTable and SmeupDataTree structures and requires the `@sme.up/kokos-sdk-node` package for type definitions. The library supports both tabular data (SmeupDataTable) and hierarchical tree data (SmeupDataTree) with automatic formatting and styling capabilities.
@@ -9,6 +9,7 @@ import { SmeupDataColumn } from "../types/data-structures/smeupDataTable.js";
9
9
  export declare const initializeWorksheet: (workbook: ExcelJS.Workbook) => ExcelJS.Worksheet;
10
10
  export declare const setHeaderStyling: (worksheet: Worksheet, background?: boolean) => void;
11
11
  export declare const addFooterTotalsRow: (worksheet: ExcelJS.Worksheet, columns: SmeupDataColumn[], props: GenericObject, webupManagerData: WebupManagerData) => void;
12
+ export declare const getExcelColumnLetter: (index: number) => string;
12
13
  /**
13
14
  * Returns the formula used in the footer to add Totals at the end of the table
14
15
  * @param totalOperation string
@@ -16,6 +17,6 @@ export declare const addFooterTotalsRow: (worksheet: ExcelJS.Worksheet, columns:
16
17
  * @param rowNumber number
17
18
  * @returns
18
19
  */
19
- export declare const getTotalFormula: (totalOperation: string, colIndex: number, rowNumber: number, filteredColumns: SmeupDataColumn[], isSmeupFormula: boolean) => string;
20
- export declare const getExcelColumnLetter: (index: number) => string;
20
+ export declare const getTotalFormula: (worksheet: ExcelJS.Worksheet, totalOperation: string, colIndex: number, rowNumber: number, filteredColumns: SmeupDataColumn[], isSmeupFormula: boolean) => string;
21
21
  export declare const smeupFormulaToExcelFormula: (formula: string, rowNumber: number, filteredColumns: SmeupDataColumn[]) => string;
22
+ export declare const getDistinctCount: (range: string, worksheet: ExcelJS.Worksheet) => string;
@@ -1,7 +1,7 @@
1
1
  import ExcelJS from "exceljs";
2
2
  import { allowedTotals, footerStyleFill, headerStyleFill, } from "./excel-generator.types.js";
3
3
  import { objectsIsDate } from "../utils/objects-utility.js";
4
- import { getExcelNumFormat } from "./matrix-generator.js";
4
+ import { getExcelNumFormatForGroupedRow } from "./matrix-generator.js";
5
5
  const { ValueType } = ExcelJS;
6
6
  /**
7
7
  * Adds creator, creation date to the workbook and creates a sheet
@@ -55,7 +55,7 @@ export const addFooterTotalsRow = (worksheet, columns, props, webupManagerData)
55
55
  const totalOperation = totals[column.name];
56
56
  if (!totalOperation)
57
57
  return;
58
- const formula = getTotalFormula(totalOperation, columnIndex + 1, // from base 0 to base 1
58
+ const formula = getTotalFormula(worksheet, totalOperation, columnIndex + 1, // from base 0 to base 1
59
59
  worksheet.rowCount, columns, totalOperation.startsWith("MATH"));
60
60
  return formula ? { formula: formula, type: ValueType.Formula } : " ";
61
61
  });
@@ -74,9 +74,18 @@ export const addFooterTotalsRow = (worksheet, columns, props, webupManagerData)
74
74
  exceljsCell.numFmt = dateFormat;
75
75
  return;
76
76
  }
77
- exceljsCell.numFmt = getExcelNumFormat(column.decimals ?? 0, column.integers ?? 0);
77
+ exceljsCell.numFmt = getExcelNumFormatForGroupedRow(column, totals);
78
78
  });
79
79
  };
80
+ export const getExcelColumnLetter = (index) => {
81
+ let columnLetter = "";
82
+ while (index > 0) {
83
+ index--; // Excel columns are 1-based, but calculations work better with 0-based
84
+ columnLetter = String.fromCharCode((index % 26) + 65) + columnLetter;
85
+ index = Math.floor(index / 26);
86
+ }
87
+ return columnLetter;
88
+ };
80
89
  /**
81
90
  * Returns the formula used in the footer to add Totals at the end of the table
82
91
  * @param totalOperation string
@@ -84,7 +93,7 @@ export const addFooterTotalsRow = (worksheet, columns, props, webupManagerData)
84
93
  * @param rowNumber number
85
94
  * @returns
86
95
  */
87
- export const getTotalFormula = (totalOperation, colIndex, rowNumber, filteredColumns, isSmeupFormula) => {
96
+ export const getTotalFormula = (worksheet, totalOperation, colIndex, rowNumber, filteredColumns, isSmeupFormula) => {
88
97
  const startRow = 2;
89
98
  const columnExcelLetter = getExcelColumnLetter(colIndex);
90
99
  if (isSmeupFormula) {
@@ -94,16 +103,12 @@ export const getTotalFormula = (totalOperation, colIndex, rowNumber, filteredCol
94
103
  console.warn(`Total operation [' ${totalOperation} '] is not supported`, "exportUtils.ts");
95
104
  return "";
96
105
  }
97
- return `${allowedTotals[totalOperation]}${columnExcelLetter}${startRow}:${columnExcelLetter}${rowNumber})`;
98
- };
99
- export const getExcelColumnLetter = (index) => {
100
- let columnLetter = "";
101
- while (index > 0) {
102
- index--; // Excel columns are 1-based, but calculations work better with 0-based
103
- columnLetter = String.fromCharCode((index % 26) + 65) + columnLetter;
104
- index = Math.floor(index / 26);
106
+ if (totalOperation === "Distinct") {
107
+ return getDistinctCount(`${columnExcelLetter}${startRow}:${columnExcelLetter}${rowNumber}`, worksheet);
108
+ }
109
+ else {
110
+ return `${allowedTotals[totalOperation]}${columnExcelLetter}${startRow}:${columnExcelLetter}${rowNumber})`;
105
111
  }
106
- return columnLetter;
107
112
  };
108
113
  export const smeupFormulaToExcelFormula = (formula, rowNumber, filteredColumns) => {
109
114
  return formula
@@ -117,4 +122,21 @@ export const smeupFormulaToExcelFormula = (formula, rowNumber, filteredColumns)
117
122
  })
118
123
  .replaceAll(",", "."); // Replace eventual , to . => The excel accepted decimal separator
119
124
  };
125
+ export const getDistinctCount = (range, worksheet) => {
126
+ const column = range.split(":")[0].replace(/[0-9]/g, ""); // Extract column letter
127
+ const startRow = parseInt(range.split(":")[0].replace(/\D/g, ""), 10);
128
+ const endRow = parseInt(range.split(":")[1].replace(/\D/g, ""), 10);
129
+ // Create a set to store unique values
130
+ const uniqueValues = new Set();
131
+ for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {
132
+ const cell = worksheet.getCell(`${column}${rowIndex}`);
133
+ if (cell.formula)
134
+ continue;
135
+ const cellValue = cell.value;
136
+ if (cellValue !== null && cellValue !== undefined) {
137
+ uniqueValues.add(cellValue.toString());
138
+ }
139
+ }
140
+ return uniqueValues.size.toString();
141
+ };
120
142
  //# sourceMappingURL=commons.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"commons.js","sourceRoot":"","sources":["../../src/excel/commons.ts"],"names":[],"mappings":"AAAA,OAAO,OAAsB,MAAM,SAAS,CAAC;AAC7C,OAAO,EACL,aAAa,EACb,eAAe,EACf,eAAe,GAChB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;AAE9B;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,QAA0B,EAAE,EAAE;IAChE,QAAQ,CAAC,OAAO,GAAG,4CAA4C,CAAC;IAChE,QAAQ,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;IAE9B,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAClD,0BAA0B;IAC1B,mCAAmC;IACnC,8BAA8B;IAC9B,qBAAqB;IACrB,oBAAoB;IACpB,mBAAmB;IACnB,eAAe;IACf,yCAAyC;IACzC,2CAA2C;IAC3C,uCAAuC;IACvC,6CAA6C;IAC7C,6CAA6C;IAC7C,6CAA6C;IAC7C,OAAO;IACP,2DAA2D;IAC3D,KAAK;IAEL,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,SAAoB,EACpB,UAAU,GAAG,KAAK,EACZ,EAAE;IACR,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACtC,SAAS,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAChC,SAAS,CAAC,SAAS,GAAG;QACpB,UAAU,EAAE,QAAQ;QACpB,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE,IAAI;KACf,CAAC;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;YACzD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC9B,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,SAA4B,EAC5B,OAA0B,EAC1B,KAAoB,EACpB,gBAAkC,EAClC,EAAE;IACF,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACvD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAAgC,CAAC;IAEtD,4BAA4B;IAC5B,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QACxD,MAAM,cAAc,GAAW,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,CAAC,cAAc;YAAE,OAAO;QAE5B,MAAM,OAAO,GAAG,eAAe,CAC7B,cAAc,EACd,WAAW,GAAG,CAAC,EAAE,wBAAwB;QACzC,SAAS,CAAC,QAAQ,EAClB,OAAO,EACP,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAClC,CAAC;QAEF,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IACvE,CAAC,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAElD,4BAA4B;IAC5B,SAAS,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAChC,SAAS,CAAC,SAAS,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;QAC5B,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,iCAAiC;QACnF,WAAW,CAAC,IAAI,GAAG,eAAe,CAAC;QAEnC,IACE,MAAM,CAAC,GAAG;YACV,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;YACzB,CAAC,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC;gBACjD,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,EACrD,CAAC;YACD,MAAM,UAAU,GACd,gBAAgB,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;YACtE,WAAW,CAAC,MAAM,GAAG,UAAU,CAAC;YAChC,OAAO;QACT,CAAC;QAED,WAAW,CAAC,MAAM,GAAG,iBAAiB,CACpC,MAAM,CAAC,QAAQ,IAAI,CAAC,EACpB,MAAM,CAAC,QAAQ,IAAI,CAAC,CACrB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,cAAsB,EACtB,QAAgB,EAChB,SAAiB,EACjB,eAAkC,EAClC,cAAuB,EACf,EAAE;IACV,MAAM,QAAQ,GAAG,CAAC,CAAC;IACnB,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAEzD,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,0BAA0B,CAC/B,cAAc,EACd,SAAS,EACT,eAAe,CAChB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CACV,sBAAsB,cAAc,sBAAsB,EAC1D,gBAAgB,CACjB,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,GAAG,aAAa,CAAC,cAAc,CAAC,GAAG,iBAAiB,GAAG,QAAQ,IAAI,iBAAiB,GAAG,SAAS,GAAG,CAAC;AAC7G,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAa,EAAU,EAAE;IAC5D,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,OAAO,KAAK,GAAG,CAAC,EAAE,CAAC;QACjB,KAAK,EAAE,CAAC,CAAC,uEAAuE;QAChF,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,YAAY,CAAC;QACrE,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,OAAe,EACf,SAAiB,EACjB,eAAkC,EAC1B,EAAE;IACV,OAAO,OAAO;SACX,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;SACnB,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAChC,MAAM,WAAW,GACf,eAAe,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B;QACpF,MAAM,YAAY,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;QACvD,OAAO,YAAY,IAAI,WAAW;YAChC,CAAC,CAAC,GAAG,YAAY,GAAG,SAAS,GAAG,CAAC,EAAE;YACnC,CAAC,CAAC,GAAG,CAAC,CAAC,oEAAoE;IAC/E,CAAC,CAAC;SACD,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,kEAAkE;AAC7F,CAAC,CAAC","sourcesContent":["import ExcelJS, { Worksheet } from \"exceljs\";\nimport {\n allowedTotals,\n footerStyleFill,\n headerStyleFill,\n} from \"./excel-generator.types.js\";\nimport { GenericObject, WebupManagerData } from \"../types/index.js\";\nimport { objectsIsDate } from \"../utils/objects-utility.js\";\nimport { getExcelNumFormat } from \"./matrix-generator.js\";\nimport { SmeupDataColumn } from \"../types/data-structures/smeupDataTable.js\";\nconst { ValueType } = ExcelJS;\n\n/**\n * Adds creator, creation date to the workbook and creates a sheet\n * @param workbook\n * @returns void\n */\nexport const initializeWorksheet = (workbook: ExcelJS.Workbook) => {\n workbook.creator = \"/doc-alchemist - dataTable excel generator\";\n workbook.created = new Date();\n\n const worksheet = workbook.addWorksheet(\"Export\");\n // worksheet.pageSetup = {\n // paperSize: 9, // A4 paper size\n // orientation: \"landscape\",\n // fitToPage: true,\n // fitToHeight: 1,\n // fitToWidth: 1,\n // margins: {\n // left: 0.5, // 0.5 inch left margin\n // right: 0.5, // 0.5 inch right margin\n // top: 0.5, // 0.5 inch top margin\n // bottom: 0.5, // 0.5 inch bottom margin\n // header: 0.3, // 0.3 inch header margin\n // footer: 0.3, // 0.3 inch footer margin\n // },\n // printTitlesRow: \"1:1\", // Print the first row as title\n // };\n\n return worksheet;\n};\n\nexport const setHeaderStyling = (\n worksheet: Worksheet,\n background = false,\n): void => {\n const headerRow = worksheet.getRow(1);\n headerRow.font = { bold: true };\n headerRow.alignment = {\n horizontal: \"center\",\n vertical: \"middle\",\n wrapText: true,\n };\n\n if (background) {\n for (let col = 1; col <= worksheet.columns.length; col++) {\n const cell = headerRow.getCell(col);\n cell.fill = headerStyleFill;\n }\n }\n};\n\nexport const addFooterTotalsRow = (\n worksheet: ExcelJS.Worksheet,\n columns: SmeupDataColumn[],\n props: GenericObject,\n webupManagerData: WebupManagerData,\n) => {\n if (!props?.totals || typeof props.totals !== \"object\") {\n return;\n }\n\n const totals = props.totals as Record<string, string>;\n\n // Set footer total formulas\n const footerRowData = columns.map((column, columnIndex) => {\n const totalOperation: string = totals[column.name];\n if (!totalOperation) return;\n\n const formula = getTotalFormula(\n totalOperation,\n columnIndex + 1, // from base 0 to base 1\n worksheet.rowCount,\n columns,\n totalOperation.startsWith(\"MATH\"),\n );\n\n return formula ? { formula: formula, type: ValueType.Formula } : \" \";\n });\n const footerRow = worksheet.addRow(footerRowData);\n\n // Format excel footer cells\n footerRow.font = { bold: true };\n footerRow.alignment = { horizontal: \"right\" };\n columns.map((column, index) => {\n const exceljsCell = footerRow.getCell(index + 1); // Convert base 0 index to base 1\n exceljsCell.fill = footerStyleFill;\n\n if (\n column.obj &&\n objectsIsDate(column.obj) &&\n (exceljsCell.formula?.startsWith(allowedTotals.Min) ||\n exceljsCell.formula?.startsWith(allowedTotals.Max))\n ) {\n const dateFormat =\n webupManagerData.datesLocale === \"it\" ? \"dd/mm/yyyy\" : \"mm/dd/yyyy\";\n exceljsCell.numFmt = dateFormat;\n return;\n }\n\n exceljsCell.numFmt = getExcelNumFormat(\n column.decimals ?? 0,\n column.integers ?? 0,\n );\n });\n};\n\n/**\n * Returns the formula used in the footer to add Totals at the end of the table\n * @param totalOperation string\n * @param colIndex string\n * @param rowNumber number\n * @returns\n */\nexport const getTotalFormula = (\n totalOperation: string,\n colIndex: number,\n rowNumber: number,\n filteredColumns: SmeupDataColumn[],\n isSmeupFormula: boolean,\n): string => {\n const startRow = 2;\n const columnExcelLetter = getExcelColumnLetter(colIndex);\n\n if (isSmeupFormula) {\n return smeupFormulaToExcelFormula(\n totalOperation,\n rowNumber,\n filteredColumns,\n );\n }\n\n if (!allowedTotals[totalOperation]) {\n console.warn(\n `Total operation [' ${totalOperation} '] is not supported`,\n \"exportUtils.ts\",\n );\n return \"\";\n }\n\n return `${allowedTotals[totalOperation]}${columnExcelLetter}${startRow}:${columnExcelLetter}${rowNumber})`;\n};\n\nexport const getExcelColumnLetter = (index: number): string => {\n let columnLetter = \"\";\n while (index > 0) {\n index--; // Excel columns are 1-based, but calculations work better with 0-based\n columnLetter = String.fromCharCode((index % 26) + 65) + columnLetter;\n index = Math.floor(index / 26);\n }\n return columnLetter;\n};\n\nexport const smeupFormulaToExcelFormula = (\n formula: string,\n rowNumber: number,\n filteredColumns: SmeupDataColumn[],\n): string => {\n return formula\n .replace(\"MATH\", \"\")\n .replace(/\\[(\\w+)\\]/g, (_, key) => {\n const columnIndex =\n filteredColumns.findIndex(col => col.name === key) + 1; // Convert to base 1 index\n const columnLetter = getExcelColumnLetter(columnIndex);\n return columnLetter && columnIndex\n ? `${columnLetter}${rowNumber + 1}`\n : key; // Return column letter with row number or original key if not found\n })\n .replaceAll(\",\", \".\"); // Replace eventual , to . => The excel accepted decimal separator\n};\n"]}
1
+ {"version":3,"file":"commons.js","sourceRoot":"","sources":["../../src/excel/commons.ts"],"names":[],"mappings":"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","sourcesContent":["import ExcelJS, { Worksheet } from \"exceljs\";\nimport {\n allowedTotals,\n footerStyleFill,\n headerStyleFill,\n} from \"./excel-generator.types.js\";\nimport { GenericObject, WebupManagerData } from \"../types/index.js\";\nimport { objectsIsDate } from \"../utils/objects-utility.js\";\nimport { getExcelNumFormatForGroupedRow } from \"./matrix-generator.js\";\nimport { SmeupDataColumn } from \"../types/data-structures/smeupDataTable.js\";\nconst { ValueType } = ExcelJS;\n\n/**\n * Adds creator, creation date to the workbook and creates a sheet\n * @param workbook\n * @returns void\n */\nexport const initializeWorksheet = (workbook: ExcelJS.Workbook) => {\n workbook.creator = \"/doc-alchemist - dataTable excel generator\";\n workbook.created = new Date();\n\n const worksheet = workbook.addWorksheet(\"Export\");\n // worksheet.pageSetup = {\n // paperSize: 9, // A4 paper size\n // orientation: \"landscape\",\n // fitToPage: true,\n // fitToHeight: 1,\n // fitToWidth: 1,\n // margins: {\n // left: 0.5, // 0.5 inch left margin\n // right: 0.5, // 0.5 inch right margin\n // top: 0.5, // 0.5 inch top margin\n // bottom: 0.5, // 0.5 inch bottom margin\n // header: 0.3, // 0.3 inch header margin\n // footer: 0.3, // 0.3 inch footer margin\n // },\n // printTitlesRow: \"1:1\", // Print the first row as title\n // };\n\n return worksheet;\n};\n\nexport const setHeaderStyling = (\n worksheet: Worksheet,\n background = false,\n): void => {\n const headerRow = worksheet.getRow(1);\n headerRow.font = { bold: true };\n headerRow.alignment = {\n horizontal: \"center\",\n vertical: \"middle\",\n wrapText: true,\n };\n\n if (background) {\n for (let col = 1; col <= worksheet.columns.length; col++) {\n const cell = headerRow.getCell(col);\n cell.fill = headerStyleFill;\n }\n }\n};\n\nexport const addFooterTotalsRow = (\n worksheet: ExcelJS.Worksheet,\n columns: SmeupDataColumn[],\n props: GenericObject,\n webupManagerData: WebupManagerData,\n) => {\n if (!props?.totals || typeof props.totals !== \"object\") {\n return;\n }\n\n const totals = props.totals as Record<string, string>;\n\n // Set footer total formulas\n const footerRowData = columns.map((column, columnIndex) => {\n const totalOperation: string = totals[column.name];\n if (!totalOperation) return;\n\n const formula = getTotalFormula(\n worksheet,\n totalOperation,\n columnIndex + 1, // from base 0 to base 1\n worksheet.rowCount,\n columns,\n totalOperation.startsWith(\"MATH\"),\n );\n\n return formula ? { formula: formula, type: ValueType.Formula } : \" \";\n });\n const footerRow = worksheet.addRow(footerRowData);\n\n // Format excel footer cells\n footerRow.font = { bold: true };\n footerRow.alignment = { horizontal: \"right\" };\n columns.map((column, index) => {\n const exceljsCell = footerRow.getCell(index + 1); // Convert base 0 index to base 1\n exceljsCell.fill = footerStyleFill;\n\n if (\n column.obj &&\n objectsIsDate(column.obj) &&\n (exceljsCell.formula?.startsWith(allowedTotals.Min) ||\n exceljsCell.formula?.startsWith(allowedTotals.Max))\n ) {\n const dateFormat =\n webupManagerData.datesLocale === \"it\" ? \"dd/mm/yyyy\" : \"mm/dd/yyyy\";\n exceljsCell.numFmt = dateFormat;\n return;\n }\n\n exceljsCell.numFmt = getExcelNumFormatForGroupedRow(column, totals);\n });\n};\n\nexport const getExcelColumnLetter = (index: number): string => {\n let columnLetter = \"\";\n while (index > 0) {\n index--; // Excel columns are 1-based, but calculations work better with 0-based\n columnLetter = String.fromCharCode((index % 26) + 65) + columnLetter;\n index = Math.floor(index / 26);\n }\n return columnLetter;\n};\n\n/**\n * Returns the formula used in the footer to add Totals at the end of the table\n * @param totalOperation string\n * @param colIndex string\n * @param rowNumber number\n * @returns\n */\nexport const getTotalFormula = (\n worksheet: ExcelJS.Worksheet,\n totalOperation: string,\n colIndex: number,\n rowNumber: number,\n filteredColumns: SmeupDataColumn[],\n isSmeupFormula: boolean,\n): string => {\n const startRow = 2;\n const columnExcelLetter = getExcelColumnLetter(colIndex);\n\n if (isSmeupFormula) {\n return smeupFormulaToExcelFormula(\n totalOperation,\n rowNumber,\n filteredColumns,\n );\n }\n\n if (!allowedTotals[totalOperation]) {\n console.warn(\n `Total operation [' ${totalOperation} '] is not supported`,\n \"exportUtils.ts\",\n );\n return \"\";\n }\n\n if (totalOperation === \"Distinct\") {\n return getDistinctCount(\n `${columnExcelLetter}${startRow}:${columnExcelLetter}${rowNumber}`,\n worksheet,\n );\n } else {\n return `${allowedTotals[totalOperation]}${columnExcelLetter}${startRow}:${columnExcelLetter}${rowNumber})`;\n }\n};\n\nexport const smeupFormulaToExcelFormula = (\n formula: string,\n rowNumber: number,\n filteredColumns: SmeupDataColumn[],\n): string => {\n return formula\n .replace(\"MATH\", \"\")\n .replace(/\\[(\\w+)\\]/g, (_, key) => {\n const columnIndex =\n filteredColumns.findIndex(col => col.name === key) + 1; // Convert to base 1 index\n const columnLetter = getExcelColumnLetter(columnIndex);\n return columnLetter && columnIndex\n ? `${columnLetter}${rowNumber + 1}`\n : key; // Return column letter with row number or original key if not found\n })\n .replaceAll(\",\", \".\"); // Replace eventual , to . => The excel accepted decimal separator\n};\n\nexport const getDistinctCount = (\n range: string,\n worksheet: ExcelJS.Worksheet,\n): string => {\n const column = range.split(\":\")[0].replace(/[0-9]/g, \"\"); // Extract column letter\n const startRow = parseInt(range.split(\":\")[0].replace(/\\D/g, \"\"), 10);\n const endRow = parseInt(range.split(\":\")[1].replace(/\\D/g, \"\"), 10);\n\n // Create a set to store unique values\n const uniqueValues = new Set<string>();\n\n for (let rowIndex = startRow; rowIndex <= endRow; rowIndex++) {\n const cell = worksheet.getCell(`${column}${rowIndex}`);\n if (cell.formula) continue;\n const cellValue = cell.value;\n if (cellValue !== null && cellValue !== undefined) {\n uniqueValues.add(cellValue.toString());\n }\n }\n\n return uniqueValues.size.toString();\n};\n"]}
@@ -17,6 +17,7 @@ export const allowedTotals = {
17
17
  ["Max"]: "SUBTOTAL(4,", // MAX
18
18
  ["Min"]: "SUBTOTAL(5,", // MIN
19
19
  ["Average"]: "SUBTOTAL(1,", // AVERAGE
20
+ ["Distinct"]: "COUNTA(UNIQUE(", // It is computed in JavaScript, when the Excel is localized in italian, it does not work
20
21
  };
21
22
  export const footerStyleFill = {
22
23
  type: "pattern",
@@ -1 +1 @@
1
- {"version":3,"file":"excel-generator.types.js","sourceRoot":"","sources":["../../src/excel/excel-generator.types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAY3D,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CAC5B,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,IAAI;IACnC,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE,KAAK;IACnC,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE,KAAK;IACnC,CAAC,sBAAsB,CAAC,UAAU,CAAC,EAAE,KAAK;CAC3C,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,sEAAsE;IACtE,CAAC,OAAoB,CAAC,EAAE,aAAa,EAAE,SAAS;IAChD,CAAC,KAAkB,CAAC,EAAE,aAAa,EAAE,MAAM;IAC3C,CAAC,KAAkB,CAAC,EAAE,aAAa,EAAE,MAAM;IAC3C,CAAC,KAAkB,CAAC,EAAE,aAAa,EAAE,MAAM;IAC3C,CAAC,SAAsB,CAAC,EAAE,aAAa,EAAE,UAAU;CACpD,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CAC5B,CAAC","sourcesContent":["import { Fill } from \"exceljs\";\nimport { SupportedExportFormats } from \"../types/index.js\";\n\nexport declare enum TotalMode {\n COUNT = \"Count\",\n SUM = \"Sum\",\n MIN = \"Min\",\n MAX = \"Max\",\n DISTINCT = \"Distinct\",\n AVERAGE = \"Average\",\n MATH = \"MATH\",\n}\n\nexport const headerStyleFill: Fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"E0E0E0\" },\n};\n\nexport const exportTypeSupportsFormatting = {\n [SupportedExportFormats.XLSX]: true,\n [SupportedExportFormats.CSV]: false,\n [SupportedExportFormats.TXT]: false,\n [SupportedExportFormats.PDF_SCHEDA]: false,\n};\n\nexport const allowedTotals = {\n // The different initial number indicates the specific subtotal action\n [\"Count\" as TotalMode]: \"SUBTOTAL(3,\", // COUNTA\n [\"Sum\" as TotalMode]: \"SUBTOTAL(9,\", // SUM\n [\"Max\" as TotalMode]: \"SUBTOTAL(4,\", // MAX\n [\"Min\" as TotalMode]: \"SUBTOTAL(5,\", // MIN\n [\"Average\" as TotalMode]: \"SUBTOTAL(1,\", // AVERAGE\n};\n\nexport const footerStyleFill: Fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"EEEEEE\" },\n};\n"]}
1
+ {"version":3,"file":"excel-generator.types.js","sourceRoot":"","sources":["../../src/excel/excel-generator.types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAY3D,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CAC5B,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,CAAC,sBAAsB,CAAC,IAAI,CAAC,EAAE,IAAI;IACnC,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE,KAAK;IACnC,CAAC,sBAAsB,CAAC,GAAG,CAAC,EAAE,KAAK;IACnC,CAAC,sBAAsB,CAAC,UAAU,CAAC,EAAE,KAAK;CAC3C,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,sEAAsE;IACtE,CAAC,OAAoB,CAAC,EAAE,aAAa,EAAE,SAAS;IAChD,CAAC,KAAkB,CAAC,EAAE,aAAa,EAAE,MAAM;IAC3C,CAAC,KAAkB,CAAC,EAAE,aAAa,EAAE,MAAM;IAC3C,CAAC,KAAkB,CAAC,EAAE,aAAa,EAAE,MAAM;IAC3C,CAAC,SAAsB,CAAC,EAAE,aAAa,EAAE,UAAU;IACnD,CAAC,UAAuB,CAAC,EAAE,gBAAgB,EAAE,yFAAyF;CACvI,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;CAC5B,CAAC","sourcesContent":["import { Fill } from \"exceljs\";\nimport { SupportedExportFormats } from \"../types/index.js\";\n\nexport declare enum TotalMode {\n COUNT = \"Count\",\n SUM = \"Sum\",\n MIN = \"Min\",\n MAX = \"Max\",\n DISTINCT = \"Distinct\",\n AVERAGE = \"Average\",\n MATH = \"MATH\",\n}\n\nexport const headerStyleFill: Fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"E0E0E0\" },\n};\n\nexport const exportTypeSupportsFormatting = {\n [SupportedExportFormats.XLSX]: true,\n [SupportedExportFormats.CSV]: false,\n [SupportedExportFormats.TXT]: false,\n [SupportedExportFormats.PDF_SCHEDA]: false,\n};\n\nexport const allowedTotals = {\n // The different initial number indicates the specific subtotal action\n [\"Count\" as TotalMode]: \"SUBTOTAL(3,\", // COUNTA\n [\"Sum\" as TotalMode]: \"SUBTOTAL(9,\", // SUM\n [\"Max\" as TotalMode]: \"SUBTOTAL(4,\", // MAX\n [\"Min\" as TotalMode]: \"SUBTOTAL(5,\", // MIN\n [\"Average\" as TotalMode]: \"SUBTOTAL(1,\", // AVERAGE\n [\"Distinct\" as TotalMode]: \"COUNTA(UNIQUE(\", // It is computed in JavaScript, when the Excel is localized in italian, it does not work\n};\n\nexport const footerStyleFill: Fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"EEEEEE\" },\n};\n"]}
@@ -7,4 +7,5 @@ export declare const dataTableToExcelWorkbook: (component: {
7
7
  props: GenericObject;
8
8
  }, fileFormat: SupportedExportFormats, webupManagerData: WebupManagerData) => ExcelJS.Workbook;
9
9
  export declare const addStyleToExceljsRow: (exceljsRow: ExcelJS.Row, columns: SmeupDataColumn[], row: SmeupDataRow | SmeupDataNode) => void;
10
+ export declare const getExcelNumFormatForGroupedRow: (column: SmeupDataColumn, totals: Record<string, string>) => string;
10
11
  export declare const getExcelNumFormat: (cellDecimals: number, cellIntegers: number) => string;
@@ -3,7 +3,7 @@ const { ValueType } = ExcelJS;
3
3
  import { getFilteredColumns, filterRows, updateMaxValueLength, calculateCellValue, hexToArgb, } from "../utils/generator-utility.js";
4
4
  import { exportTypeSupportsFormatting, allowedTotals, } from "./excel-generator.types.js";
5
5
  import { isColumnHidden } from "../utils/datastructure-utility.js";
6
- import { addFooterTotalsRow, getExcelColumnLetter, initializeWorksheet, setHeaderStyling, smeupFormulaToExcelFormula, } from "./commons.js";
6
+ import { addFooterTotalsRow, getDistinctCount, getExcelColumnLetter, initializeWorksheet, setHeaderStyling, smeupFormulaToExcelFormula, } from "./commons.js";
7
7
  export const dataTableToExcelWorkbook = (component, fileFormat, webupManagerData) => {
8
8
  // Create a new ExcelJS.Workbook and return it as a resolved Promise
9
9
  const { smeupDataTable: smeupDataTable, props } = component;
@@ -122,7 +122,7 @@ const insertDataTableGroupedRows = (worksheet, rows, groups, filteredColumns, un
122
122
  // Compute totals and format cells
123
123
  for (const [colIndex, col] of filteredColumns.entries()) {
124
124
  const cell = headerRow.getCell(colIndex + 1);
125
- cell.numFmt = getExcelNumFormat(col.decimals ?? 0, col.integers ?? 0);
125
+ cell.numFmt = getExcelNumFormatForGroupedRow(col, totals);
126
126
  decorateHeaderRow(cell);
127
127
  if (!totals)
128
128
  continue;
@@ -134,7 +134,7 @@ const insertDataTableGroupedRows = (worksheet, rows, groups, filteredColumns, un
134
134
  formula: smeupFormulaToExcelFormula(totalFormula.replace("MATH", ""), headerRowNumber - 1, filteredColumns),
135
135
  }
136
136
  : {
137
- formula: getSubGroupTotalFormula(totalFormula, colIndex + 1, headerRowNumber + 1, lastDataRow),
137
+ formula: getSubGroupTotalFormula(worksheet, totalFormula, colIndex + 1, headerRowNumber + 1, lastDataRow),
138
138
  };
139
139
  }
140
140
  }
@@ -218,6 +218,15 @@ const cellToXlsxStyleConverter = (cell, xlsxCell, optionalRowStyles) => {
218
218
  xlsxCell.numFmt = getExcelNumFormat(cell.data?.decimals ?? 0, cell.data?.integers ?? 0);
219
219
  }
220
220
  };
221
+ export const getExcelNumFormatForGroupedRow = (column, totals) => {
222
+ const totalOperation = totals?.[column.name];
223
+ if (totalOperation === "Distinct") {
224
+ return "0"; // Distinct count does not require decimals
225
+ }
226
+ else {
227
+ return getExcelNumFormat(column.decimals ?? 0, column.integers ?? 0);
228
+ }
229
+ };
221
230
  export const getExcelNumFormat = (cellDecimals, cellIntegers) => {
222
231
  // Step 1: Build the integer part with necessary '#' and '0'
223
232
  let integerPart = cellIntegers ? "#".repeat(cellIntegers - 1) + "0" : "0";
@@ -246,14 +255,18 @@ const decorateHeaderRow = (headerCell) => {
246
255
  fgColor: { argb: `${hexToArgb("e0e0e0")}` },
247
256
  };
248
257
  };
249
- const getSubGroupTotalFormula = (totalOperation, colIndex, firstDataRow, lastDataRow) => {
258
+ const getSubGroupTotalFormula = (worksheet, totalOperation, colIndex, firstDataRow, lastDataRow) => {
250
259
  const columnExcelLetter = getExcelColumnLetter(colIndex);
251
260
  if (!allowedTotals[totalOperation]) {
252
261
  console.warn(`Total operation [' ${totalOperation} '] is not supported`, "exportUtils.ts");
253
262
  return "";
254
263
  }
255
- // Use full range (includes both subheaders and data rows)
256
- return `${allowedTotals[totalOperation]}${columnExcelLetter}${firstDataRow}:${columnExcelLetter}${lastDataRow})`;
264
+ if (totalOperation === "Distinct") {
265
+ return getDistinctCount(`${columnExcelLetter}${firstDataRow}:${columnExcelLetter}${lastDataRow}`, worksheet);
266
+ }
267
+ else {
268
+ return `${allowedTotals[totalOperation]}${columnExcelLetter}${firstDataRow}:${columnExcelLetter}${lastDataRow})`;
269
+ }
257
270
  };
258
271
  const ensureGroupRowHasDescription = (worksheet) => {
259
272
  const firstVisibleColumnIndex = getFirstVisibleColumn(worksheet);
@@ -1 +1 @@
1
- {"version":3,"file":"matrix-generator.js","sourceRoot":"","sources":["../../src/excel/matrix-generator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Properties as CSSProperties } from \"csstype\";\nimport ExcelJS, { Worksheet, Cell } from \"exceljs\";\nconst { ValueType } = ExcelJS;\nimport {\n GenericObject,\n WebupManagerData,\n ColumnFilter,\n SmeupDataCellStyled,\n SupportedExportFormats,\n} from \"../types/index.js\";\nimport {\n getFilteredColumns,\n filterRows,\n updateMaxValueLength,\n calculateCellValue,\n hexToArgb,\n} from \"../utils/generator-utility.js\";\nimport {\n exportTypeSupportsFormatting,\n allowedTotals,\n} from \"./excel-generator.types.js\";\nimport { isColumnHidden } from \"../utils/datastructure-utility.js\";\nimport {\n addFooterTotalsRow,\n getExcelColumnLetter,\n initializeWorksheet,\n setHeaderStyling,\n smeupFormulaToExcelFormula,\n} from \"./commons.js\";\nimport {\n SmeupDataCell,\n SmeupDataColumn,\n SmeupDataRow,\n SmeupDataTable,\n} from \"../types/data-structures/smeupDataTable.js\";\nimport { SmeupDataNode } from \"../types/data-structures/smeupDataTree.js\";\n\nexport const dataTableToExcelWorkbook = (\n component: {\n smeupDataTable: SmeupDataTable;\n props: GenericObject;\n },\n fileFormat: SupportedExportFormats,\n webupManagerData: WebupManagerData,\n): ExcelJS.Workbook => {\n // Create a new ExcelJS.Workbook and return it as a resolved Promise\n const { smeupDataTable: smeupDataTable, props } = component;\n const workbook = new ExcelJS.Workbook();\n const worksheet = initializeWorksheet(workbook);\n\n const groupsArray: { column: string; visible: boolean }[] = Array.isArray(\n props?.groups,\n )\n ? props.groups\n : [];\n\n // Visible attribute is used only to determine if the column is visible,\n // ant not to determine if the group is active\n const activeGroups: string[] = groupsArray.map(\n (group: { column: string; visible: boolean }) => group.column,\n );\n\n const filteredColumns = getFilteredColumns(\n smeupDataTable.columns,\n props,\n groupsArray,\n );\n\n const maxColumnValueLenght: { [key: string]: number } = {};\n\n let rowNumber: number = 1; // Start row number\n\n // Headers setup\n setDataTableHeaderRow(worksheet, filteredColumns, maxColumnValueLenght);\n\n // Filter and sort rows (if filters are available)\n const rows = filterRows(\n smeupDataTable,\n filteredColumns,\n props?.filters as { [key: string]: ColumnFilter },\n );\n\n if (activeGroups?.length > 0) {\n // Sort rows based on the first active group column\n rows.sort((a, b) => {\n for (const group of activeGroups) {\n const valA =\n a.cells && a.cells[group]?.value !== undefined\n ? a.cells[group]?.value\n : \"\";\n const valB =\n b.cells && b.cells[group]?.value !== undefined\n ? b.cells[group]?.value\n : \"\";\n if (valA !== valB) return valA.localeCompare(valB);\n }\n return 0;\n });\n\n // Recursive grouping\n rowNumber = insertDataTableGroupedRows(\n worksheet,\n rows,\n activeGroups,\n filteredColumns,\n smeupDataTable.columns,\n rowNumber,\n fileFormat,\n webupManagerData,\n 1,\n maxColumnValueLenght,\n (props?.totals ?? {}) as Record<string, string>,\n );\n\n //INTERACTIVE GROUPS MANAGING\n //TODO: Add groups subtotals\n if (worksheet.getColumn(1).hidden) ensureGroupRowHasDescription(worksheet);\n applyDataTableOutlineLevels(worksheet);\n worksheet.properties.outlineProperties = {\n summaryBelow: false,\n summaryRight: false,\n };\n } else {\n // Process rows normally if no grouping\n rowNumber = insertDataTableRows(\n worksheet,\n rows,\n filteredColumns,\n rowNumber,\n fileFormat,\n webupManagerData,\n maxColumnValueLenght,\n );\n }\n\n if (exportTypeSupportsFormatting[fileFormat] && props?.totals) {\n addFooterTotalsRow(worksheet, filteredColumns, props, webupManagerData);\n }\n\n // Apply column width\n worksheet.columns.forEach(col => {\n const columnKey = col.key;\n if (columnKey) {\n col.width = (maxColumnValueLenght[columnKey] ?? 10) * 1.1;\n } else {\n col.width = 10 * 1.1; // Default width\n }\n });\n\n // Apply filter to column headers\n // TODO: look if it breaks groupings\n worksheet.autoFilter = {\n from: { row: 1, column: 1 },\n to: { row: rowNumber, column: filteredColumns.length },\n };\n\n // Forces full calculation when the workbook is opened\n workbook.calcProperties = {\n fullCalcOnLoad: true,\n };\n\n return workbook;\n};\n\n/**\n * Creates the first row of the table by looking at dataTable columns.\n * Also updates column width calculations\n * @param worksheet\n * @param filteredColumns\n * @param maxValueLengthMap\n */\nconst setDataTableHeaderRow = (\n worksheet: Worksheet,\n filteredColumns: SmeupDataColumn[],\n maxValueLengthMap: { [key: string]: number },\n) => {\n worksheet.columns = filteredColumns.map(col => {\n updateMaxValueLength(maxValueLengthMap, col.title, col.name);\n return {\n header: col.title,\n key: col.name,\n width: maxValueLengthMap[col.name], // Set the width to the updated value\n hidden: isColumnHidden(col),\n } as ExcelJS.Column;\n });\n\n setHeaderStyling(worksheet);\n};\n\nconst insertDataTableGroupedRows = (\n worksheet: ExcelJS.Worksheet,\n rows: SmeupDataRow[],\n groups: string[],\n filteredColumns: SmeupDataColumn[],\n unfilteredColumns: SmeupDataColumn[],\n rowNumber: number,\n fileFormat: SupportedExportFormats,\n webupManagerData: WebupManagerData,\n currentOutlineLevel: number = 1,\n maxColumnValueLength: Record<string, number>,\n totals: Record<string, string>,\n): number => {\n if (!groups.length) {\n return insertDataTableRows(\n worksheet,\n rows,\n filteredColumns,\n rowNumber,\n fileFormat,\n webupManagerData,\n maxColumnValueLength,\n );\n }\n\n const [currentGroup, ...remainingGroups] = groups;\n const uniqueGroupValues = [\n ...new Set(\n rows\n .map(row => row.cells && row.cells[currentGroup]?.value)\n .filter(value => value !== undefined),\n ),\n ].sort();\n const columnTitles = Object.fromEntries(\n unfilteredColumns.map(col => [col.name, col.title]),\n );\n\n for (const groupValue of uniqueGroupValues) {\n // Filter rows for the current group\n const groupedRows = rows.filter(\n row => row.cells && row.cells[currentGroup]?.value === groupValue,\n );\n const indentation = \" \".repeat((currentOutlineLevel - 1) * 8);\n\n // Insert header row\n const headerRow = worksheet.addRow([]);\n headerRow.getCell(1).value =\n `${indentation}▼${columnTitles[currentGroup]} - ${groupValue}`;\n const headerRowNumber = ++rowNumber;\n\n rowNumber = insertDataTableGroupedRows(\n worksheet,\n groupedRows,\n remainingGroups,\n filteredColumns,\n unfilteredColumns,\n rowNumber,\n fileFormat,\n webupManagerData,\n currentOutlineLevel + 1,\n maxColumnValueLength,\n totals,\n );\n const lastDataRow = rowNumber;\n\n // Compute totals and format cells\n for (const [colIndex, col] of filteredColumns.entries()) {\n const cell = headerRow.getCell(colIndex + 1);\n cell.numFmt = getExcelNumFormat(col.decimals ?? 0, col.integers ?? 0);\n decorateHeaderRow(cell);\n if (!totals) continue;\n const totalFormula = totals[col.name];\n if (totalFormula && col.visible) {\n cell.alignment = { horizontal: \"right\" };\n\n cell.value = totalFormula.startsWith(\"MATH\")\n ? {\n formula: smeupFormulaToExcelFormula(\n totalFormula.replace(\"MATH\", \"\"),\n headerRowNumber - 1,\n filteredColumns,\n ),\n }\n : {\n formula: getSubGroupTotalFormula(\n totalFormula,\n colIndex + 1,\n headerRowNumber + 1,\n lastDataRow,\n ),\n };\n }\n }\n }\n\n return rowNumber;\n};\n\n/**\n * Inserts normal rows (without grouping).\n */\nconst insertDataTableRows = (\n worksheet: ExcelJS.Worksheet,\n rows: SmeupDataRow[],\n filteredColumns: SmeupDataColumn[],\n rowNumber: number,\n fileFormat: SupportedExportFormats,\n webupManagerData: WebupManagerData,\n maxColumnValueLenght: { [key: string]: number },\n): number => {\n for (const row of rows) {\n const rowData = filteredColumns.map(column => {\n const cell: SmeupDataCell = (row?.cells ?? {})[column.name];\n updateMaxValueLength(maxColumnValueLenght, cell?.value, column.name);\n return column.formula\n ? {\n formula: `${smeupFormulaToExcelFormula(\n column.formula,\n rowNumber,\n filteredColumns,\n )}`,\n type: ValueType.Formula,\n }\n : calculateCellValue(cell, fileFormat, webupManagerData);\n });\n\n const newRow = worksheet.addRow(rowData);\n if (exportTypeSupportsFormatting[fileFormat]) {\n addStyleToExceljsRow(newRow, filteredColumns, row);\n }\n\n rowNumber++;\n }\n\n return rowNumber;\n};\n\nexport const addStyleToExceljsRow = (\n exceljsRow: ExcelJS.Row,\n columns: SmeupDataColumn[],\n row: SmeupDataRow | SmeupDataNode,\n) => {\n exceljsRow.eachCell((cell, cellIndex) => {\n const columnIndex = cellIndex - 1;\n const columnName = columns[columnIndex]?.name;\n const smeupCell = row?.cells?.[columnName];\n const smeupCellWithStyle = smeupCell as SmeupDataCellStyled;\n if (\n smeupCellWithStyle?.style &&\n Object.keys(smeupCellWithStyle.style).length > 0\n ) {\n cellToXlsxStyleConverter(smeupCellWithStyle, cell);\n } else if (\n (row as SmeupDataCellStyled)?.style &&\n Object.keys((row as SmeupDataCellStyled).style ?? {}).length > 0\n ) {\n cellToXlsxStyleConverter(\n smeupCellWithStyle,\n cell,\n (row as SmeupDataCellStyled).style,\n );\n }\n });\n};\n\n/**\n * Converts SmeupDataCell.style attributes to ExcelJS styles\n * @param cell SmeupDataCell - The TBL cell containing styless\n * @param xlsxCell ExcelJS.Cell - XLSX cell where styles will be applied\n * @returns any\n */\nconst cellToXlsxStyleConverter = (\n cell: SmeupDataCell,\n xlsxCell: Cell,\n optionalRowStyles?: CSSProperties,\n) => {\n const cellStyle = optionalRowStyles ?? (cell as SmeupDataCellStyled)?.style;\n if (!cellStyle) return;\n\n if (cellStyle.textAlign) {\n xlsxCell.alignment = {\n horizontal: cellStyle.textAlign as\n | \"left\"\n | \"center\"\n | \"right\"\n | \"fill\"\n | \"justify\"\n | \"centerContinuous\"\n | \"distributed\",\n };\n }\n\n if (cellStyle.backgroundColor) {\n xlsxCell.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: hexToArgb(cellStyle.backgroundColor) },\n };\n }\n if (cellStyle.fontWeight == \"bold\") {\n xlsxCell.font = {\n ...xlsxCell.font,\n bold: true,\n };\n }\n if (cellStyle.color) {\n xlsxCell.font = {\n ...xlsxCell.font,\n color: { argb: hexToArgb(cellStyle.color) },\n };\n }\n\n if (typeof xlsxCell.value === \"number\" || xlsxCell.formula) {\n xlsxCell.numFmt = getExcelNumFormat(\n (cell.data?.decimals as number) ?? 0,\n (cell.data?.integers as number) ?? 0,\n );\n }\n};\n\nexport const getExcelNumFormat = (\n cellDecimals: number,\n cellIntegers: number,\n): string => {\n // Step 1: Build the integer part with necessary '#' and '0'\n let integerPart = cellIntegers ? \"#\".repeat(cellIntegers - 1) + \"0\" : \"0\";\n\n // Step 2: Insert commas every three digits from the right\n if (cellIntegers > 3) {\n integerPart = integerPart\n .split(\"\")\n .reverse()\n .map((char, index) => (index > 0 && index % 3 === 0 ? char + \",\" : char))\n .reverse()\n .join(\"\");\n }\n\n // Step 3: Build the decimal part\n const decimalPart = cellDecimals > 0 ? \".\" + \"0\".repeat(cellDecimals) : \".00\";\n\n // Step 4: Construct the full format, including negative formatting\n let numFmt = integerPart + decimalPart;\n numFmt += `;[Red]-${numFmt}`;\n\n return numFmt;\n};\n\nconst decorateHeaderRow = (headerCell: ExcelJS.Cell) => {\n headerCell.font = { bold: true };\n headerCell.alignment = { horizontal: \"left\" };\n headerCell.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: `${hexToArgb(\"e0e0e0\")}` },\n };\n};\n\nconst getSubGroupTotalFormula = (\n totalOperation: string,\n colIndex: number,\n firstDataRow: number,\n lastDataRow: number,\n): string => {\n const columnExcelLetter = getExcelColumnLetter(colIndex);\n\n if (!allowedTotals[totalOperation]) {\n console.warn(\n `Total operation [' ${totalOperation} '] is not supported`,\n \"exportUtils.ts\",\n );\n return \"\";\n }\n\n // Use full range (includes both subheaders and data rows)\n return `${allowedTotals[totalOperation]}${columnExcelLetter}${firstDataRow}:${columnExcelLetter}${lastDataRow})`;\n};\n\nconst ensureGroupRowHasDescription = (worksheet: ExcelJS.Worksheet) => {\n const firstVisibleColumnIndex = getFirstVisibleColumn(worksheet);\n if (!firstVisibleColumnIndex) {\n console.warn(\"No visible columns found in the worksheet.\");\n return;\n }\n // Iterate through each row and check if the first cell contains \"▼\"\n worksheet.eachRow((row: ExcelJS.Row) => {\n const cellValue = row.getCell(1).value;\n if (cellValue && cellValue.toString().includes(\"▼\")) {\n row.getCell(firstVisibleColumnIndex).value = cellValue\n .toString()\n .replace(\"▼\", \"\");\n }\n });\n};\n\nconst getFirstVisibleColumn = (worksheet: ExcelJS.Worksheet) => {\n return (\n [...Array(worksheet.columnCount)]\n .map((_, i) => i + 1) // Convert to base 1 index\n .find(col => !worksheet.getColumn(col).hidden) || null\n );\n};\n\n// Function to analyze header indentation and assign outline levels\nconst applyDataTableOutlineLevels = (worksheet: ExcelJS.Worksheet) => {\n let lastOutlineLevel = 0;\n\n worksheet.eachRow((row, rowIndex) => {\n if (rowIndex !== 1) {\n const firstCell = row.getCell(1);\n const isHeader = firstCell.value?.toString().includes(\"▼\");\n\n if (isHeader) {\n row.getCell(1).value = (row.getCell(1).value as string).replace(\n \"▼\",\n \"\",\n );\n const leadingSpaces =\n (firstCell.value as string).match(/^ */)?.[0].length || 0;\n const outlineLevel = Math.floor(leadingSpaces / 8) + 1; // Each 8 spaces = 1 level\n row.outlineLevel = outlineLevel - 1; // Ensure headers get an outline level\n lastOutlineLevel = outlineLevel;\n } else {\n row.outlineLevel = lastOutlineLevel; // Normal rows follow the last assigned level\n }\n }\n });\n};\n"]}
1
+ {"version":3,"file":"matrix-generator.js","sourceRoot":"","sources":["../../src/excel/matrix-generator.ts"],"names":[],"mappings":"AACA,OAAO,OAA4B,MAAM,SAAS,CAAC;AACnD,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;AAQ9B,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,GACV,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,4BAA4B,EAC5B,aAAa,GACd,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,0BAA0B,GAC3B,MAAM,cAAc,CAAC;AAStB,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,SAGC,EACD,UAAkC,EAClC,gBAAkC,EAChB,EAAE;IACpB,oEAAoE;IACpE,MAAM,EAAE,cAAc,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;IAC5D,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IACxC,MAAM,SAAS,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAEhD,MAAM,WAAW,GAA2C,KAAK,CAAC,OAAO,CACvE,KAAK,EAAE,MAAM,CACd;QACC,CAAC,CAAC,KAAK,CAAC,MAAM;QACd,CAAC,CAAC,EAAE,CAAC;IAEP,wEAAwE;IACxE,8CAA8C;IAC9C,MAAM,YAAY,GAAa,WAAW,CAAC,GAAG,CAC5C,CAAC,KAA2C,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAC9D,CAAC;IAEF,MAAM,eAAe,GAAG,kBAAkB,CACxC,cAAc,CAAC,OAAO,EACtB,KAAK,EACL,WAAW,CACZ,CAAC;IAEF,MAAM,oBAAoB,GAA8B,EAAE,CAAC;IAE3D,IAAI,SAAS,GAAW,CAAC,CAAC,CAAC,mBAAmB;IAE9C,gBAAgB;IAChB,qBAAqB,CAAC,SAAS,EAAE,eAAe,EAAE,oBAAoB,CAAC,CAAC;IAExE,kDAAkD;IAClD,MAAM,IAAI,GAAG,UAAU,CACrB,cAAc,EACd,eAAe,EACf,KAAK,EAAE,OAA0C,CAClD,CAAC;IAEF,IAAI,YAAY,EAAE,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,mDAAmD;QACnD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACjB,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBACjC,MAAM,IAAI,GACR,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,SAAS;oBAC5C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK;oBACvB,CAAC,CAAC,EAAE,CAAC;gBACT,MAAM,IAAI,GACR,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,SAAS;oBAC5C,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK;oBACvB,CAAC,CAAC,EAAE,CAAC;gBACT,IAAI,IAAI,KAAK,IAAI;oBAAE,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;YACrD,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;QAEH,qBAAqB;QACrB,SAAS,GAAG,0BAA0B,CACpC,SAAS,EACT,IAAI,EACJ,YAAY,EACZ,eAAe,EACf,cAAc,CAAC,OAAO,EACtB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,CAAC,EACD,oBAAoB,EACpB,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAA2B,CAChD,CAAC;QAEF,6BAA6B;QAC7B,6BAA6B;QAC7B,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM;YAAE,4BAA4B,CAAC,SAAS,CAAC,CAAC;QAC3E,2BAA2B,CAAC,SAAS,CAAC,CAAC;QACvC,SAAS,CAAC,UAAU,CAAC,iBAAiB,GAAG;YACvC,YAAY,EAAE,KAAK;YACnB,YAAY,EAAE,KAAK;SACpB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,uCAAuC;QACvC,SAAS,GAAG,mBAAmB,CAC7B,SAAS,EACT,IAAI,EACJ,eAAe,EACf,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,oBAAoB,CACrB,CAAC;IACJ,CAAC;IAED,IAAI,4BAA4B,CAAC,UAAU,CAAC,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;QAC9D,kBAAkB,CAAC,SAAS,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;IAC1E,CAAC;IAED,qBAAqB;IACrB,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;QAC9B,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC;QAC1B,IAAI,SAAS,EAAE,CAAC;YACd,GAAG,CAAC,KAAK,GAAG,CAAC,oBAAoB,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,KAAK,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,gBAAgB;QACxC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,iCAAiC;IACjC,oCAAoC;IACpC,SAAS,CAAC,UAAU,GAAG;QACrB,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QAC3B,EAAE,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE;KACvD,CAAC;IAEF,sDAAsD;IACtD,QAAQ,CAAC,cAAc,GAAG;QACxB,cAAc,EAAE,IAAI;KACrB,CAAC;IAEF,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,qBAAqB,GAAG,CAC5B,SAAoB,EACpB,eAAkC,EAClC,iBAA4C,EAC5C,EAAE;IACF,SAAS,CAAC,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;QAC5C,oBAAoB,CAAC,iBAAiB,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC7D,OAAO;YACL,MAAM,EAAE,GAAG,CAAC,KAAK;YACjB,GAAG,EAAE,GAAG,CAAC,IAAI;YACb,KAAK,EAAE,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,qCAAqC;YACzE,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC;SACV,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,gBAAgB,CAAC,SAAS,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,0BAA0B,GAAG,CACjC,SAA4B,EAC5B,IAAoB,EACpB,MAAgB,EAChB,eAAkC,EAClC,iBAAoC,EACpC,SAAiB,EACjB,UAAkC,EAClC,gBAAkC,EAClC,sBAA8B,CAAC,EAC/B,oBAA4C,EAC5C,MAA8B,EACtB,EAAE;IACV,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,mBAAmB,CACxB,SAAS,EACT,IAAI,EACJ,eAAe,EACf,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,oBAAoB,CACrB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,YAAY,EAAE,GAAG,eAAe,CAAC,GAAG,MAAM,CAAC;IAClD,MAAM,iBAAiB,GAAG;QACxB,GAAG,IAAI,GAAG,CACR,IAAI;aACD,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC;aACvD,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CACxC;KACF,CAAC,IAAI,EAAE,CAAC;IACT,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CACrC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CACpD,CAAC;IAEF,KAAK,MAAM,UAAU,IAAI,iBAAiB,EAAE,CAAC;QAC3C,oCAAoC;QACpC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAC7B,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,KAAK,KAAK,UAAU,CAClE,CAAC;QACF,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,mBAAmB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAE9D,oBAAoB;QACpB,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACvC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK;YACxB,GAAG,WAAW,IAAI,YAAY,CAAC,YAAY,CAAC,MAAM,UAAU,EAAE,CAAC;QACjE,MAAM,eAAe,GAAG,EAAE,SAAS,CAAC;QAEpC,SAAS,GAAG,0BAA0B,CACpC,SAAS,EACT,WAAW,EACX,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,mBAAmB,GAAG,CAAC,EACvB,oBAAoB,EACpB,MAAM,CACP,CAAC;QACF,MAAM,WAAW,GAAG,SAAS,CAAC;QAE9B,kCAAkC;QAClC,KAAK,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC;YACxD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;YAC7C,IAAI,CAAC,MAAM,GAAG,8BAA8B,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC1D,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAExB,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,YAAY,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAChC,IAAI,CAAC,SAAS,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;gBAEzC,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC;oBAC1C,CAAC,CAAC;wBACE,OAAO,EAAE,0BAA0B,CACjC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAChC,eAAe,GAAG,CAAC,EACnB,eAAe,CAChB;qBACF;oBACH,CAAC,CAAC;wBACE,OAAO,EAAE,uBAAuB,CAC9B,SAAS,EACT,YAAY,EACZ,QAAQ,GAAG,CAAC,EACZ,eAAe,GAAG,CAAC,EACnB,WAAW,CACZ;qBACF,CAAC;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAAG,CAC1B,SAA4B,EAC5B,IAAoB,EACpB,eAAkC,EAClC,SAAiB,EACjB,UAAkC,EAClC,gBAAkC,EAClC,oBAA+C,EACvC,EAAE;IACV,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC3C,MAAM,IAAI,GAAkB,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5D,oBAAoB,CAAC,oBAAoB,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACrE,OAAO,MAAM,CAAC,OAAO;gBACnB,CAAC,CAAC;oBACE,OAAO,EAAE,GAAG,0BAA0B,CACpC,MAAM,CAAC,OAAO,EACd,SAAS,EACT,eAAe,CAChB,EAAE;oBACH,IAAI,EAAE,SAAS,CAAC,OAAO;iBACxB;gBACH,CAAC,CAAC,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,4BAA4B,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7C,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;QACrD,CAAC;QAED,SAAS,EAAE,CAAC;IACd,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,UAAuB,EACvB,OAA0B,EAC1B,GAAiC,EACjC,EAAE;IACF,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE;QACtC,MAAM,WAAW,GAAG,SAAS,GAAG,CAAC,CAAC;QAClC,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC;QAC9C,MAAM,SAAS,GAAG,GAAG,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,kBAAkB,GAAG,SAAgC,CAAC;QAC5D,IACE,kBAAkB,EAAE,KAAK;YACzB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAChD,CAAC;YACD,wBAAwB,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;QACrD,CAAC;aAAM,IACJ,GAA2B,EAAE,KAAK;YACnC,MAAM,CAAC,IAAI,CAAE,GAA2B,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAChE,CAAC;YACD,wBAAwB,CACtB,kBAAkB,EAClB,IAAI,EACH,GAA2B,CAAC,KAAK,CACnC,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,CAC/B,IAAmB,EACnB,QAAc,EACd,iBAAiC,EACjC,EAAE;IACF,MAAM,SAAS,GAAG,iBAAiB,IAAK,IAA4B,EAAE,KAAK,CAAC;IAC5E,IAAI,CAAC,SAAS;QAAE,OAAO;IAEvB,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QACxB,QAAQ,CAAC,SAAS,GAAG;YACnB,UAAU,EAAE,SAAS,CAAC,SAOL;SAClB,CAAC;IACJ,CAAC;IAED,IAAI,SAAS,CAAC,eAAe,EAAE,CAAC;QAC9B,QAAQ,CAAC,IAAI,GAAG;YACd,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE;SACxD,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,CAAC,UAAU,IAAI,MAAM,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,GAAG;YACd,GAAG,QAAQ,CAAC,IAAI;YAChB,IAAI,EAAE,IAAI;SACX,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,GAAG;YACd,GAAG,QAAQ,CAAC,IAAI;YAChB,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE;SAC5C,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,QAAQ,CAAC,KAAK,KAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QAC3D,QAAQ,CAAC,MAAM,GAAG,iBAAiB,CAChC,IAAI,CAAC,IAAI,EAAE,QAAmB,IAAI,CAAC,EACnC,IAAI,CAAC,IAAI,EAAE,QAAmB,IAAI,CAAC,CACrC,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,MAAuB,EACvB,MAA8B,EACtB,EAAE;IACV,MAAM,cAAc,GAAW,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;QAClC,OAAO,GAAG,CAAC,CAAC,2CAA2C;IACzD,CAAC;SAAM,CAAC;QACN,OAAO,iBAAiB,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;IACvE,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,YAAoB,EACpB,YAAoB,EACZ,EAAE;IACV,4DAA4D;IAC5D,IAAI,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE1E,0DAA0D;IAC1D,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACrB,WAAW,GAAG,WAAW;aACtB,KAAK,CAAC,EAAE,CAAC;aACT,OAAO,EAAE;aACT,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aACxE,OAAO,EAAE;aACT,IAAI,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IAED,iCAAiC;IACjC,MAAM,WAAW,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAE9E,mEAAmE;IACnE,IAAI,MAAM,GAAG,WAAW,GAAG,WAAW,CAAC;IACvC,MAAM,IAAI,UAAU,MAAM,EAAE,CAAC;IAE7B,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,UAAwB,EAAE,EAAE;IACrD,UAAU,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,UAAU,CAAC,SAAS,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAC9C,UAAU,CAAC,IAAI,GAAG;QAChB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO;QAChB,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE;KAC5C,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAC9B,SAA4B,EAC5B,cAAsB,EACtB,QAAgB,EAChB,YAAoB,EACpB,WAAmB,EACX,EAAE;IACV,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAEzD,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,IAAI,CACV,sBAAsB,cAAc,sBAAsB,EAC1D,gBAAgB,CACjB,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;QAClC,OAAO,gBAAgB,CACrB,GAAG,iBAAiB,GAAG,YAAY,IAAI,iBAAiB,GAAG,WAAW,EAAE,EACxE,SAAS,CACV,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,aAAa,CAAC,cAAc,CAAC,GAAG,iBAAiB,GAAG,YAAY,IAAI,iBAAiB,GAAG,WAAW,GAAG,CAAC;IACnH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,4BAA4B,GAAG,CAAC,SAA4B,EAAE,EAAE;IACpE,MAAM,uBAAuB,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACjE,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC3D,OAAO;IACT,CAAC;IACD,oEAAoE;IACpE,SAAS,CAAC,OAAO,CAAC,CAAC,GAAgB,EAAE,EAAE;QACrC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACvC,IAAI,SAAS,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,KAAK,GAAG,SAAS;iBACnD,QAAQ,EAAE;iBACV,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,SAA4B,EAAE,EAAE;IAC7D,OAAO,CACL,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B;SAC/C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CACzD,CAAC;AACJ,CAAC,CAAC;AAEF,mEAAmE;AACnE,MAAM,2BAA2B,GAAG,CAAC,SAA4B,EAAE,EAAE;IACnE,IAAI,gBAAgB,GAAG,CAAC,CAAC;IAEzB,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;QAClC,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnB,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAE3D,IAAI,QAAQ,EAAE,CAAC;gBACb,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,GAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAgB,CAAC,OAAO,CAC7D,GAAG,EACH,EAAE,CACH,CAAC;gBACF,MAAM,aAAa,GAChB,SAAS,CAAC,KAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;gBAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B;gBAClF,GAAG,CAAC,YAAY,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,sCAAsC;gBAC3E,gBAAgB,GAAG,YAAY,CAAC;YAClC,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,YAAY,GAAG,gBAAgB,CAAC,CAAC,6CAA6C;YACpF,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import type { Properties as CSSProperties } from \"csstype\";\nimport ExcelJS, { Worksheet, Cell } from \"exceljs\";\nconst { ValueType } = ExcelJS;\nimport {\n GenericObject,\n WebupManagerData,\n ColumnFilter,\n SmeupDataCellStyled,\n SupportedExportFormats,\n} from \"../types/index.js\";\nimport {\n getFilteredColumns,\n filterRows,\n updateMaxValueLength,\n calculateCellValue,\n hexToArgb,\n} from \"../utils/generator-utility.js\";\nimport {\n exportTypeSupportsFormatting,\n allowedTotals,\n} from \"./excel-generator.types.js\";\nimport { isColumnHidden } from \"../utils/datastructure-utility.js\";\nimport {\n addFooterTotalsRow,\n getDistinctCount,\n getExcelColumnLetter,\n initializeWorksheet,\n setHeaderStyling,\n smeupFormulaToExcelFormula,\n} from \"./commons.js\";\nimport {\n SmeupDataCell,\n SmeupDataColumn,\n SmeupDataRow,\n SmeupDataTable,\n} from \"../types/data-structures/smeupDataTable.js\";\nimport { SmeupDataNode } from \"../types/data-structures/smeupDataTree.js\";\n\nexport const dataTableToExcelWorkbook = (\n component: {\n smeupDataTable: SmeupDataTable;\n props: GenericObject;\n },\n fileFormat: SupportedExportFormats,\n webupManagerData: WebupManagerData,\n): ExcelJS.Workbook => {\n // Create a new ExcelJS.Workbook and return it as a resolved Promise\n const { smeupDataTable: smeupDataTable, props } = component;\n const workbook = new ExcelJS.Workbook();\n const worksheet = initializeWorksheet(workbook);\n\n const groupsArray: { column: string; visible: boolean }[] = Array.isArray(\n props?.groups,\n )\n ? props.groups\n : [];\n\n // Visible attribute is used only to determine if the column is visible,\n // ant not to determine if the group is active\n const activeGroups: string[] = groupsArray.map(\n (group: { column: string; visible: boolean }) => group.column,\n );\n\n const filteredColumns = getFilteredColumns(\n smeupDataTable.columns,\n props,\n groupsArray,\n );\n\n const maxColumnValueLenght: { [key: string]: number } = {};\n\n let rowNumber: number = 1; // Start row number\n\n // Headers setup\n setDataTableHeaderRow(worksheet, filteredColumns, maxColumnValueLenght);\n\n // Filter and sort rows (if filters are available)\n const rows = filterRows(\n smeupDataTable,\n filteredColumns,\n props?.filters as { [key: string]: ColumnFilter },\n );\n\n if (activeGroups?.length > 0) {\n // Sort rows based on the first active group column\n rows.sort((a, b) => {\n for (const group of activeGroups) {\n const valA =\n a.cells && a.cells[group]?.value !== undefined\n ? a.cells[group]?.value\n : \"\";\n const valB =\n b.cells && b.cells[group]?.value !== undefined\n ? b.cells[group]?.value\n : \"\";\n if (valA !== valB) return valA.localeCompare(valB);\n }\n return 0;\n });\n\n // Recursive grouping\n rowNumber = insertDataTableGroupedRows(\n worksheet,\n rows,\n activeGroups,\n filteredColumns,\n smeupDataTable.columns,\n rowNumber,\n fileFormat,\n webupManagerData,\n 1,\n maxColumnValueLenght,\n (props?.totals ?? {}) as Record<string, string>,\n );\n\n //INTERACTIVE GROUPS MANAGING\n //TODO: Add groups subtotals\n if (worksheet.getColumn(1).hidden) ensureGroupRowHasDescription(worksheet);\n applyDataTableOutlineLevels(worksheet);\n worksheet.properties.outlineProperties = {\n summaryBelow: false,\n summaryRight: false,\n };\n } else {\n // Process rows normally if no grouping\n rowNumber = insertDataTableRows(\n worksheet,\n rows,\n filteredColumns,\n rowNumber,\n fileFormat,\n webupManagerData,\n maxColumnValueLenght,\n );\n }\n\n if (exportTypeSupportsFormatting[fileFormat] && props?.totals) {\n addFooterTotalsRow(worksheet, filteredColumns, props, webupManagerData);\n }\n\n // Apply column width\n worksheet.columns.forEach(col => {\n const columnKey = col.key;\n if (columnKey) {\n col.width = (maxColumnValueLenght[columnKey] ?? 10) * 1.1;\n } else {\n col.width = 10 * 1.1; // Default width\n }\n });\n\n // Apply filter to column headers\n // TODO: look if it breaks groupings\n worksheet.autoFilter = {\n from: { row: 1, column: 1 },\n to: { row: rowNumber, column: filteredColumns.length },\n };\n\n // Forces full calculation when the workbook is opened\n workbook.calcProperties = {\n fullCalcOnLoad: true,\n };\n\n return workbook;\n};\n\n/**\n * Creates the first row of the table by looking at dataTable columns.\n * Also updates column width calculations\n * @param worksheet\n * @param filteredColumns\n * @param maxValueLengthMap\n */\nconst setDataTableHeaderRow = (\n worksheet: Worksheet,\n filteredColumns: SmeupDataColumn[],\n maxValueLengthMap: { [key: string]: number },\n) => {\n worksheet.columns = filteredColumns.map(col => {\n updateMaxValueLength(maxValueLengthMap, col.title, col.name);\n return {\n header: col.title,\n key: col.name,\n width: maxValueLengthMap[col.name], // Set the width to the updated value\n hidden: isColumnHidden(col),\n } as ExcelJS.Column;\n });\n\n setHeaderStyling(worksheet);\n};\n\nconst insertDataTableGroupedRows = (\n worksheet: ExcelJS.Worksheet,\n rows: SmeupDataRow[],\n groups: string[],\n filteredColumns: SmeupDataColumn[],\n unfilteredColumns: SmeupDataColumn[],\n rowNumber: number,\n fileFormat: SupportedExportFormats,\n webupManagerData: WebupManagerData,\n currentOutlineLevel: number = 1,\n maxColumnValueLength: Record<string, number>,\n totals: Record<string, string>,\n): number => {\n if (!groups.length) {\n return insertDataTableRows(\n worksheet,\n rows,\n filteredColumns,\n rowNumber,\n fileFormat,\n webupManagerData,\n maxColumnValueLength,\n );\n }\n\n const [currentGroup, ...remainingGroups] = groups;\n const uniqueGroupValues = [\n ...new Set(\n rows\n .map(row => row.cells && row.cells[currentGroup]?.value)\n .filter(value => value !== undefined),\n ),\n ].sort();\n const columnTitles = Object.fromEntries(\n unfilteredColumns.map(col => [col.name, col.title]),\n );\n\n for (const groupValue of uniqueGroupValues) {\n // Filter rows for the current group\n const groupedRows = rows.filter(\n row => row.cells && row.cells[currentGroup]?.value === groupValue,\n );\n const indentation = \" \".repeat((currentOutlineLevel - 1) * 8);\n\n // Insert header row\n const headerRow = worksheet.addRow([]);\n headerRow.getCell(1).value =\n `${indentation}▼${columnTitles[currentGroup]} - ${groupValue}`;\n const headerRowNumber = ++rowNumber;\n\n rowNumber = insertDataTableGroupedRows(\n worksheet,\n groupedRows,\n remainingGroups,\n filteredColumns,\n unfilteredColumns,\n rowNumber,\n fileFormat,\n webupManagerData,\n currentOutlineLevel + 1,\n maxColumnValueLength,\n totals,\n );\n const lastDataRow = rowNumber;\n\n // Compute totals and format cells\n for (const [colIndex, col] of filteredColumns.entries()) {\n const cell = headerRow.getCell(colIndex + 1);\n cell.numFmt = getExcelNumFormatForGroupedRow(col, totals);\n decorateHeaderRow(cell);\n\n if (!totals) continue;\n const totalFormula = totals[col.name];\n if (totalFormula && col.visible) {\n cell.alignment = { horizontal: \"right\" };\n\n cell.value = totalFormula.startsWith(\"MATH\")\n ? {\n formula: smeupFormulaToExcelFormula(\n totalFormula.replace(\"MATH\", \"\"),\n headerRowNumber - 1,\n filteredColumns,\n ),\n }\n : {\n formula: getSubGroupTotalFormula(\n worksheet,\n totalFormula,\n colIndex + 1,\n headerRowNumber + 1,\n lastDataRow,\n ),\n };\n }\n }\n }\n\n return rowNumber;\n};\n\n/**\n * Inserts normal rows (without grouping).\n */\nconst insertDataTableRows = (\n worksheet: ExcelJS.Worksheet,\n rows: SmeupDataRow[],\n filteredColumns: SmeupDataColumn[],\n rowNumber: number,\n fileFormat: SupportedExportFormats,\n webupManagerData: WebupManagerData,\n maxColumnValueLenght: { [key: string]: number },\n): number => {\n for (const row of rows) {\n const rowData = filteredColumns.map(column => {\n const cell: SmeupDataCell = (row?.cells ?? {})[column.name];\n updateMaxValueLength(maxColumnValueLenght, cell?.value, column.name);\n return column.formula\n ? {\n formula: `${smeupFormulaToExcelFormula(\n column.formula,\n rowNumber,\n filteredColumns,\n )}`,\n type: ValueType.Formula,\n }\n : calculateCellValue(cell, fileFormat, webupManagerData);\n });\n\n const newRow = worksheet.addRow(rowData);\n if (exportTypeSupportsFormatting[fileFormat]) {\n addStyleToExceljsRow(newRow, filteredColumns, row);\n }\n\n rowNumber++;\n }\n\n return rowNumber;\n};\n\nexport const addStyleToExceljsRow = (\n exceljsRow: ExcelJS.Row,\n columns: SmeupDataColumn[],\n row: SmeupDataRow | SmeupDataNode,\n) => {\n exceljsRow.eachCell((cell, cellIndex) => {\n const columnIndex = cellIndex - 1;\n const columnName = columns[columnIndex]?.name;\n const smeupCell = row?.cells?.[columnName];\n const smeupCellWithStyle = smeupCell as SmeupDataCellStyled;\n if (\n smeupCellWithStyle?.style &&\n Object.keys(smeupCellWithStyle.style).length > 0\n ) {\n cellToXlsxStyleConverter(smeupCellWithStyle, cell);\n } else if (\n (row as SmeupDataCellStyled)?.style &&\n Object.keys((row as SmeupDataCellStyled).style ?? {}).length > 0\n ) {\n cellToXlsxStyleConverter(\n smeupCellWithStyle,\n cell,\n (row as SmeupDataCellStyled).style,\n );\n }\n });\n};\n\n/**\n * Converts SmeupDataCell.style attributes to ExcelJS styles\n * @param cell SmeupDataCell - The TBL cell containing styless\n * @param xlsxCell ExcelJS.Cell - XLSX cell where styles will be applied\n * @returns any\n */\nconst cellToXlsxStyleConverter = (\n cell: SmeupDataCell,\n xlsxCell: Cell,\n optionalRowStyles?: CSSProperties,\n) => {\n const cellStyle = optionalRowStyles ?? (cell as SmeupDataCellStyled)?.style;\n if (!cellStyle) return;\n\n if (cellStyle.textAlign) {\n xlsxCell.alignment = {\n horizontal: cellStyle.textAlign as\n | \"left\"\n | \"center\"\n | \"right\"\n | \"fill\"\n | \"justify\"\n | \"centerContinuous\"\n | \"distributed\",\n };\n }\n\n if (cellStyle.backgroundColor) {\n xlsxCell.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: hexToArgb(cellStyle.backgroundColor) },\n };\n }\n if (cellStyle.fontWeight == \"bold\") {\n xlsxCell.font = {\n ...xlsxCell.font,\n bold: true,\n };\n }\n if (cellStyle.color) {\n xlsxCell.font = {\n ...xlsxCell.font,\n color: { argb: hexToArgb(cellStyle.color) },\n };\n }\n\n if (typeof xlsxCell.value === \"number\" || xlsxCell.formula) {\n xlsxCell.numFmt = getExcelNumFormat(\n (cell.data?.decimals as number) ?? 0,\n (cell.data?.integers as number) ?? 0,\n );\n }\n};\n\nexport const getExcelNumFormatForGroupedRow = (\n column: SmeupDataColumn,\n totals: Record<string, string>,\n): string => {\n const totalOperation: string = totals?.[column.name];\n if (totalOperation === \"Distinct\") {\n return \"0\"; // Distinct count does not require decimals\n } else {\n return getExcelNumFormat(column.decimals ?? 0, column.integers ?? 0);\n }\n};\n\nexport const getExcelNumFormat = (\n cellDecimals: number,\n cellIntegers: number,\n): string => {\n // Step 1: Build the integer part with necessary '#' and '0'\n let integerPart = cellIntegers ? \"#\".repeat(cellIntegers - 1) + \"0\" : \"0\";\n\n // Step 2: Insert commas every three digits from the right\n if (cellIntegers > 3) {\n integerPart = integerPart\n .split(\"\")\n .reverse()\n .map((char, index) => (index > 0 && index % 3 === 0 ? char + \",\" : char))\n .reverse()\n .join(\"\");\n }\n\n // Step 3: Build the decimal part\n const decimalPart = cellDecimals > 0 ? \".\" + \"0\".repeat(cellDecimals) : \".00\";\n\n // Step 4: Construct the full format, including negative formatting\n let numFmt = integerPart + decimalPart;\n numFmt += `;[Red]-${numFmt}`;\n\n return numFmt;\n};\n\nconst decorateHeaderRow = (headerCell: ExcelJS.Cell) => {\n headerCell.font = { bold: true };\n headerCell.alignment = { horizontal: \"left\" };\n headerCell.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: `${hexToArgb(\"e0e0e0\")}` },\n };\n};\n\nconst getSubGroupTotalFormula = (\n worksheet: ExcelJS.Worksheet,\n totalOperation: string,\n colIndex: number,\n firstDataRow: number,\n lastDataRow: number,\n): string => {\n const columnExcelLetter = getExcelColumnLetter(colIndex);\n\n if (!allowedTotals[totalOperation]) {\n console.warn(\n `Total operation [' ${totalOperation} '] is not supported`,\n \"exportUtils.ts\",\n );\n return \"\";\n }\n\n if (totalOperation === \"Distinct\") {\n return getDistinctCount(\n `${columnExcelLetter}${firstDataRow}:${columnExcelLetter}${lastDataRow}`,\n worksheet,\n );\n } else {\n return `${allowedTotals[totalOperation]}${columnExcelLetter}${firstDataRow}:${columnExcelLetter}${lastDataRow})`;\n }\n};\n\nconst ensureGroupRowHasDescription = (worksheet: ExcelJS.Worksheet) => {\n const firstVisibleColumnIndex = getFirstVisibleColumn(worksheet);\n if (!firstVisibleColumnIndex) {\n console.warn(\"No visible columns found in the worksheet.\");\n return;\n }\n // Iterate through each row and check if the first cell contains \"▼\"\n worksheet.eachRow((row: ExcelJS.Row) => {\n const cellValue = row.getCell(1).value;\n if (cellValue && cellValue.toString().includes(\"▼\")) {\n row.getCell(firstVisibleColumnIndex).value = cellValue\n .toString()\n .replace(\"▼\", \"\");\n }\n });\n};\n\nconst getFirstVisibleColumn = (worksheet: ExcelJS.Worksheet) => {\n return (\n [...Array(worksheet.columnCount)]\n .map((_, i) => i + 1) // Convert to base 1 index\n .find(col => !worksheet.getColumn(col).hidden) || null\n );\n};\n\n// Function to analyze header indentation and assign outline levels\nconst applyDataTableOutlineLevels = (worksheet: ExcelJS.Worksheet) => {\n let lastOutlineLevel = 0;\n\n worksheet.eachRow((row, rowIndex) => {\n if (rowIndex !== 1) {\n const firstCell = row.getCell(1);\n const isHeader = firstCell.value?.toString().includes(\"▼\");\n\n if (isHeader) {\n row.getCell(1).value = (row.getCell(1).value as string).replace(\n \"▼\",\n \"\",\n );\n const leadingSpaces =\n (firstCell.value as string).match(/^ */)?.[0].length || 0;\n const outlineLevel = Math.floor(leadingSpaces / 8) + 1; // Each 8 spaces = 1 level\n row.outlineLevel = outlineLevel - 1; // Ensure headers get an outline level\n lastOutlineLevel = outlineLevel;\n } else {\n row.outlineLevel = lastOutlineLevel; // Normal rows follow the last assigned level\n }\n }\n });\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sme.up/doc-alchemist",
3
- "version": "1.2.0-SNAPSHOT-20250626070253",
3
+ "version": "1.2.0-SNAPSHOT-20250627103210",
4
4
  "description": "Library for generating documents in various formats, including Excel and PDF.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Smeup LAB <info@smeup.com> (https://www.smeup.com/)",