@cellaware/utils 8.11.16 → 8.11.18

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.
@@ -21,6 +21,7 @@ export interface VisualDatagridState extends DatagridState {
21
21
  }
22
22
  export declare function initVisualDatagridState(): VisualDatagridState;
23
23
  export type ColumnState = {
24
+ /** Maps to ColumnFormat `name`. */
24
25
  colId: string;
25
26
  hide?: boolean | null;
26
27
  sort?: 'asc' | 'desc' | null;
@@ -30,6 +31,7 @@ export type ColumnState = {
30
31
  pivotIndex?: number | null;
31
32
  rowGroup?: boolean;
32
33
  rowGroupIndex?: number | null;
34
+ pinned?: 'left' | 'right' | null;
33
35
  };
34
36
  type FilterType = 'text' | 'number' | 'set';
35
37
  type Operator = 'AND' | 'OR';
@@ -48,6 +50,7 @@ type CompoundFilter = {
48
50
  type ColumnFilter = SimpleCondition | CompoundFilter;
49
51
  type FilterModel = Record<string, ColumnFilter>;
50
52
  export interface ColumnFormat {
53
+ /** Maps to ColumnState `colId`. */
51
54
  name: string;
52
55
  displayName: string;
53
56
  /** `text` | `number` | `date` | `boolean` */
@@ -685,8 +685,9 @@ function pivotData(data, rowGroupCols, pivotCols, valueCols) {
685
685
  const pivotBuckets = new Map();
686
686
  for (const row of groupRows) {
687
687
  const pivotKey = pivotBy(row);
688
- if (!pivotBuckets.has(pivotKey))
688
+ if (!pivotBuckets.has(pivotKey)) {
689
689
  pivotBuckets.set(pivotKey, []);
690
+ }
690
691
  pivotBuckets.get(pivotKey).push(row);
691
692
  }
692
693
  for (const [pivotKey, rows] of pivotBuckets.entries()) {
@@ -704,29 +705,50 @@ function pivotData(data, rowGroupCols, pivotCols, valueCols) {
704
705
  switch (aggFunc) {
705
706
  case 'sum':
706
707
  groupObj[key] = values.map(Number).reduce((a, b) => a + b, 0);
708
+ if (!groupObj[key]) {
709
+ groupObj[key] = 0;
710
+ }
707
711
  break;
708
712
  case 'count':
709
713
  groupObj[key] = values.length;
714
+ if (!groupObj[key]) {
715
+ groupObj[key] = 0;
716
+ }
710
717
  break;
711
718
  case 'min':
712
719
  groupObj[key] = values.reduce((a, b) => (a < b ? a : b), values[0]);
720
+ if (!groupObj[key]) {
721
+ groupObj[key] = 0;
722
+ }
713
723
  break;
714
724
  case 'max':
715
725
  groupObj[key] = values.reduce((a, b) => (a > b ? a : b), values[0]);
726
+ if (!groupObj[key]) {
727
+ groupObj[key] = 0;
728
+ }
716
729
  break;
717
730
  case 'avg': {
718
731
  const nums = values.map(Number).filter(n => !isNaN(n));
719
732
  groupObj[key] = nums.length ? nums.reduce((a, b) => a + b, 0) / nums.length : null;
733
+ if (!groupObj[key]) {
734
+ groupObj[key] = 0;
735
+ }
720
736
  break;
721
737
  }
722
738
  case 'first':
723
739
  groupObj[key] = values[0];
740
+ if (!groupObj[key]) {
741
+ groupObj[key] = '';
742
+ }
724
743
  break;
725
744
  case 'last':
726
745
  groupObj[key] = values[values.length - 1];
746
+ if (!groupObj[key]) {
747
+ groupObj[key] = '';
748
+ }
727
749
  break;
728
750
  default:
729
- groupObj[key] = null;
751
+ groupObj[key] = '';
730
752
  }
731
753
  }
732
754
  }
@@ -1223,6 +1245,25 @@ export function createTeamsTransposeTableRow(row, columnStyle) {
1223
1245
  cells: [keyCell, valueCell]
1224
1246
  };
1225
1247
  }
1248
+ function getColumnSequenceRank(column, pivot) {
1249
+ let seq = 2;
1250
+ // Check pin state first.
1251
+ // Important: we do not care about pinning if the grid is pivoted.
1252
+ if (!pivot) {
1253
+ if (column.pinned === 'left') {
1254
+ seq = 0;
1255
+ }
1256
+ else if (column.pinned === 'right') {
1257
+ seq = 3;
1258
+ }
1259
+ }
1260
+ // Row group second.
1261
+ if (!!column.rowGroup && column.rowGroupIndex === 0) {
1262
+ seq = 1;
1263
+ }
1264
+ // Nothing else to check.
1265
+ return seq;
1266
+ }
1226
1267
  /**
1227
1268
  * **Important:** `html` and `teamsRows` output will be limited to **1,000 rows/24 rows** and **8 columns**, respectively.
1228
1269
  *
@@ -1250,8 +1291,11 @@ export function transformDatagrid(rows, datagridState, locale, condition) {
1250
1291
  rows = pivotOutput.rows;
1251
1292
  rows = sortModel.length > 0 ? sortRows(rows, sortModel) : rows;
1252
1293
  let mappedDisplayColumnNames = new Map();
1253
- // Should not need to do hidden/visible column analysis -- pivoting creates new results with only the necessary columns.
1254
- // Also should not need to analyze column sequence -- our newly created results *should* respect the correct sequence.
1294
+ // For pivots, we cannot trust the `hide` field.
1295
+ // Visibility will depend on `rowGroup`, `pivot`, and `aggFunc`.
1296
+ const visibleColumnState = columnState.filter(column => (!!column.rowGroup && column.rowGroupIndex === 0) || // We only display the **first** row group.
1297
+ (!!column.pivot) ||
1298
+ (!!column.aggFunc)).sort((a, b) => getColumnSequenceRank(a, true) - getColumnSequenceRank(b, true));
1255
1299
  let rowIdx = 0;
1256
1300
  rows.forEach((row) => {
1257
1301
  let adjRow = {};
@@ -1262,49 +1306,54 @@ export function transformDatagrid(rows, datagridState, locale, condition) {
1262
1306
  let htmlTransposeColumnStyles = [];
1263
1307
  let teamsRowStyles = [];
1264
1308
  let teamsColumnStyles = [];
1265
- columnFormats.forEach(columnFormat => {
1266
- if (columnFormat.name in row) {
1267
- const value = row[columnFormat.name];
1268
- const formattedValue = evaluateValueFormat(columnFormat, value, locale);
1269
- adjRow[columnFormat.displayName] = formattedValue;
1270
- chartRow[columnFormat.displayName] = formatNumberEnabled(columnFormat.valueFormat) ? value : formattedValue;
1271
- htmlRowValues.push(formattedValue);
1272
- [htmlRowStyles, htmlColumnStyles] = processHtmlStyles(formattedValue, columnFormat.displayName, columnFormat, htmlRowStyles, htmlColumnStyles);
1273
- htmlTransposeColumnStyles = processHtmlTransposeStyles(formattedValue, columnFormat.displayName, columnFormat, htmlTransposeColumnStyles);
1274
- if (rowIdx === 0) {
1275
- htmlColumnNames.push(columnFormat.displayName);
1309
+ // Important: anchoring to column state will ensure we add columns in the correct sequence.
1310
+ visibleColumnState.forEach(column => {
1311
+ const columnFormat = columnFormats.find(columnFormat => columnFormat.name === column.colId);
1312
+ if (!!columnFormat) {
1313
+ if (columnFormat.name in row) {
1314
+ const value = row[columnFormat.name];
1315
+ const formattedValue = evaluateValueFormat(columnFormat, value, locale);
1316
+ adjRow[columnFormat.displayName] = formattedValue;
1317
+ chartRow[columnFormat.displayName] = formatNumberEnabled(columnFormat.valueFormat) ? value : formattedValue;
1318
+ htmlRowValues.push(formattedValue);
1319
+ [htmlRowStyles, htmlColumnStyles] = processHtmlStyles(formattedValue, columnFormat.displayName, columnFormat, htmlRowStyles, htmlColumnStyles);
1320
+ htmlTransposeColumnStyles = processHtmlTransposeStyles(formattedValue, columnFormat.displayName, columnFormat, htmlTransposeColumnStyles);
1321
+ if (rowIdx === 0) {
1322
+ htmlColumnNames.push(columnFormat.displayName);
1323
+ }
1276
1324
  }
1277
- }
1278
- else {
1279
- const mappedColumnNamesSet = pivotOutput.mappedColumnNames.get(columnFormat.name);
1280
- if (!!mappedColumnNamesSet) {
1281
- const mappedColumnNamesArr = Array.from(mappedColumnNamesSet);
1282
- for (const mappedColumnName of mappedColumnNamesArr) {
1283
- if (mappedColumnName in row) {
1284
- const adjDisplayName = mappedColumnName.replace(columnFormat.name, columnFormat.displayName);
1285
- const value = row[mappedColumnName];
1286
- const formattedValue = evaluateValueFormat(columnFormat, value, locale);
1287
- adjRow[adjDisplayName] = formattedValue;
1288
- chartRow[adjDisplayName] = formatNumberEnabled(columnFormat.valueFormat) ? value : formattedValue;
1289
- htmlRowValues.push(formattedValue);
1290
- [htmlRowStyles, htmlColumnStyles] = processHtmlStyles(formattedValue, adjDisplayName, columnFormat, htmlRowStyles, htmlColumnStyles);
1291
- htmlTransposeColumnStyles = processHtmlTransposeStyles(formattedValue, adjDisplayName, columnFormat, htmlTransposeColumnStyles);
1292
- if (rowIdx === 0) {
1293
- htmlColumnNames.push(adjDisplayName);
1294
- }
1295
- let displayColumnNames = mappedDisplayColumnNames.get(columnFormat.displayName);
1296
- if (!!displayColumnNames) {
1297
- displayColumnNames.add(adjDisplayName);
1298
- }
1299
- else {
1300
- displayColumnNames = new Set([adjDisplayName]);
1301
- mappedDisplayColumnNames.set(columnFormat.displayName, displayColumnNames);
1325
+ else {
1326
+ const mappedColumnNamesSet = pivotOutput.mappedColumnNames.get(columnFormat.name);
1327
+ if (!!mappedColumnNamesSet) {
1328
+ const mappedColumnNamesArr = Array.from(mappedColumnNamesSet);
1329
+ for (const mappedColumnName of mappedColumnNamesArr) {
1330
+ if (mappedColumnName in row) {
1331
+ const adjDisplayName = mappedColumnName.replace(columnFormat.name, columnFormat.displayName);
1332
+ const value = row[mappedColumnName];
1333
+ const formattedValue = evaluateValueFormat(columnFormat, value, locale);
1334
+ adjRow[adjDisplayName] = formattedValue;
1335
+ chartRow[adjDisplayName] = formatNumberEnabled(columnFormat.valueFormat) ? value : formattedValue;
1336
+ htmlRowValues.push(formattedValue);
1337
+ [htmlRowStyles, htmlColumnStyles] = processHtmlStyles(formattedValue, adjDisplayName, columnFormat, htmlRowStyles, htmlColumnStyles);
1338
+ htmlTransposeColumnStyles = processHtmlTransposeStyles(formattedValue, adjDisplayName, columnFormat, htmlTransposeColumnStyles);
1339
+ if (rowIdx === 0) {
1340
+ htmlColumnNames.push(adjDisplayName);
1341
+ }
1342
+ let displayColumnNames = mappedDisplayColumnNames.get(columnFormat.displayName);
1343
+ if (!!displayColumnNames) {
1344
+ displayColumnNames.add(adjDisplayName);
1345
+ }
1346
+ else {
1347
+ displayColumnNames = new Set([adjDisplayName]);
1348
+ mappedDisplayColumnNames.set(columnFormat.displayName, displayColumnNames);
1349
+ }
1302
1350
  }
1303
1351
  }
1304
1352
  }
1305
1353
  }
1306
1354
  }
1307
1355
  });
1356
+ adjRows.push(adjRow);
1308
1357
  chartRows.push(chartRow);
1309
1358
  if (rowIdx < DATAGRID_HTML_ROWS) {
1310
1359
  htmlBuf += buildHtmlRow(htmlRowValues, htmlRowStyles, htmlColumnStyles, DATAGRID_HTML_COLS);
@@ -1334,7 +1383,10 @@ export function transformDatagrid(rows, datagridState, locale, condition) {
1334
1383
  rows = groupAndAggregate(rows, rowGroupCols, [], valueCols);
1335
1384
  }
1336
1385
  rows = sortModel.length > 0 ? sortRows(rows, sortModel) : rows;
1337
- const visibleColumnState = columnState.filter(column => !column.hide);
1386
+ // We cannot always trust the `hide` field -- we need to look at the row group configuration.
1387
+ const visibleColumnState = columnState.filter(column => !column.hide || // Important: `hide` will be true if we are dealing with a row group.
1388
+ (!!column.rowGroup && column.rowGroupIndex === 0) // We only display the **first** row group.
1389
+ ).sort((a, b) => getColumnSequenceRank(a) - getColumnSequenceRank(b));
1338
1390
  let rowIdx = 0;
1339
1391
  rows.forEach((row) => {
1340
1392
  let adjRow = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cellaware/utils",
3
- "version": "8.11.16",
3
+ "version": "8.11.18",
4
4
  "description": "Cellaware Utilities for Node.js",
5
5
  "author": "Cellaware Technologies",
6
6
  "type": "module",