@quillsql/react 2.16.21 → 2.16.22

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.
Files changed (3) hide show
  1. package/dist/index.cjs +221 -24
  2. package/dist/index.js +221 -24
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -263,6 +263,9 @@ var init_valueFormatter = __esm({
263
263
  maximumFractionDigits: 2
264
264
  });
265
265
  formatPercent = (value) => {
266
+ if (typeof value === "string" && /^\s*[+-]?(?:\d+(?:\.\d+)?|\.\d+)\s*%\s*$/.test(value)) {
267
+ return value;
268
+ }
266
269
  return formatterPercent.format(Number(value));
267
270
  };
268
271
  _getUTCDateHelper = (value, fmt) => {
@@ -19879,11 +19882,12 @@ async function cleanDashboardItem({
19879
19882
  page: DEFAULT_PAGINATION
19880
19883
  };
19881
19884
  if (item.pivot && skipPivotFetch && item.rows && item.fields) {
19885
+ const pivotSourceRows = item.rows.map((row) => ({ ...row }));
19882
19886
  const dateFilter = dashboardFilters?.find(
19883
19887
  (filter) => filter.filterType === "date_range"
19884
19888
  );
19885
19889
  pivotTable = processPivotData({
19886
- rows: item.rows,
19890
+ rows: pivotSourceRows,
19887
19891
  fields: item.fields,
19888
19892
  pivot: {
19889
19893
  ...item.pivot,
@@ -22145,7 +22149,20 @@ var applyFiltersInMemory = (rows, filters, options) => {
22145
22149
  // src/utils/inMemoryPivotEngine.ts
22146
22150
  init_columnType();
22147
22151
  var MS_IN_DAY = 24 * 60 * 60 * 1e3;
22148
- var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
22152
+ var MONTHS = [
22153
+ "Jan",
22154
+ "Feb",
22155
+ "Mar",
22156
+ "Apr",
22157
+ "May",
22158
+ "Jun",
22159
+ "Jul",
22160
+ "Aug",
22161
+ "Sep",
22162
+ "Oct",
22163
+ "Nov",
22164
+ "Dec"
22165
+ ];
22149
22166
  var INVALID_DATE_KEY = "-2026";
22150
22167
  function singleAggToMultiAgg(pivot) {
22151
22168
  if (pivot.aggregations) {
@@ -22153,7 +22170,12 @@ function singleAggToMultiAgg(pivot) {
22153
22170
  }
22154
22171
  const newPivot = { ...pivot };
22155
22172
  const newAgg = { aggregationType: pivot.aggregationType };
22156
- const fieldsToCopy = ["valueField", "valueFieldType", "valueField2", "valueField2Type"];
22173
+ const fieldsToCopy = [
22174
+ "valueField",
22175
+ "valueFieldType",
22176
+ "valueField2",
22177
+ "valueField2Type"
22178
+ ];
22157
22179
  fieldsToCopy.forEach((x) => {
22158
22180
  if (pivot[x]) {
22159
22181
  newAgg[x] = pivot[x];
@@ -22184,6 +22206,12 @@ function isValidDate3(date) {
22184
22206
  return false;
22185
22207
  }
22186
22208
  }
22209
+ function isDateLikeType(fieldType) {
22210
+ if (!fieldType) {
22211
+ return false;
22212
+ }
22213
+ return isDateType(fieldType) || isDateFormat2(fieldType);
22214
+ }
22187
22215
  function inferDateBucketFromFilters(pivot, filters) {
22188
22216
  if (!pivot?.rowFieldType) {
22189
22217
  return void 0;
@@ -22327,8 +22355,12 @@ function getDateRangeFromFilters(filters) {
22327
22355
  }
22328
22356
  function generateBucketKeys(start2, end, bucket) {
22329
22357
  const keys = /* @__PURE__ */ new Set();
22330
- const startDay = new Date(Date.UTC(start2.getUTCFullYear(), start2.getUTCMonth(), start2.getUTCDate()));
22331
- const endDay = new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate()));
22358
+ const startDay = new Date(
22359
+ Date.UTC(start2.getUTCFullYear(), start2.getUTCMonth(), start2.getUTCDate())
22360
+ );
22361
+ const endDay = new Date(
22362
+ Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate())
22363
+ );
22332
22364
  const cur = new Date(startDay);
22333
22365
  while (cur <= endDay) {
22334
22366
  keys.add(getDateKey(cur, bucket));
@@ -22352,7 +22384,9 @@ function getBucketRange(dateKey, bucket) {
22352
22384
  let end = new Date(d);
22353
22385
  switch (bucket) {
22354
22386
  case "day":
22355
- start2 = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
22387
+ start2 = new Date(
22388
+ Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())
22389
+ );
22356
22390
  end = new Date(start2);
22357
22391
  break;
22358
22392
  case "week":
@@ -22394,10 +22428,18 @@ function getDateKey(date, bucket) {
22394
22428
  }
22395
22429
  switch (bucket) {
22396
22430
  case "day":
22397
- return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()).toString();
22431
+ return Date.UTC(
22432
+ date.getUTCFullYear(),
22433
+ date.getUTCMonth(),
22434
+ date.getUTCDate()
22435
+ ).toString();
22398
22436
  case "week": {
22399
22437
  const day = date.getUTCDay();
22400
- const mondayUtc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() - (day + 6) % 7);
22438
+ const mondayUtc = Date.UTC(
22439
+ date.getUTCFullYear(),
22440
+ date.getUTCMonth(),
22441
+ date.getUTCDate() - (day + 6) % 7
22442
+ );
22401
22443
  return mondayUtc.toString();
22402
22444
  }
22403
22445
  case "month":
@@ -22461,7 +22503,11 @@ function assembleFinalRows(seen, rowKey, dateBucket, dateRange) {
22461
22503
  if (bucketEnd > dateRange.end) bucketEnd = dateRange.end;
22462
22504
  }
22463
22505
  return {
22464
- [rowKey]: formatBucketNameFromRange(bucketStart, bucketEnd, dateBucket),
22506
+ [rowKey]: formatBucketNameFromRange(
22507
+ bucketStart,
22508
+ bucketEnd,
22509
+ dateBucket
22510
+ ),
22465
22511
  ...filled[k],
22466
22512
  __quillRawDate: bucketStart.toISOString()
22467
22513
  };
@@ -22620,7 +22666,13 @@ function aggregateWithColumn(rows, colKey, aggregations, getGroupKey) {
22620
22666
  const seen = {};
22621
22667
  const multiAgg = aggregations.length > 1;
22622
22668
  aggregations.forEach((agg) => {
22623
- const { aggregationType: type, valueField, valueFieldType, valueField2, valueField2Type } = agg;
22669
+ const {
22670
+ aggregationType: type,
22671
+ valueField,
22672
+ valueFieldType,
22673
+ valueField2,
22674
+ valueField2Type
22675
+ } = agg;
22624
22676
  if (!valueField) {
22625
22677
  if (type !== "count" && type !== "percentage") return;
22626
22678
  }
@@ -22653,7 +22705,10 @@ function aggregateWithColumn(rows, colKey, aggregations, getGroupKey) {
22653
22705
  });
22654
22706
  Object.keys(accs).forEach((groupKey) => {
22655
22707
  if (!seen[groupKey]) seen[groupKey] = {};
22656
- const sumOfDenom = Object.values(accs[groupKey]).reduce((t, a) => t + a.count, 0);
22708
+ const sumOfDenom = Object.values(accs[groupKey]).reduce(
22709
+ (t, a) => t + a.count,
22710
+ 0
22711
+ );
22657
22712
  Object.keys(accs[groupKey]).forEach((colVal) => {
22658
22713
  const acc = accs[groupKey][colVal];
22659
22714
  const finalKey = `${colVal}` + (multiAgg ? `_${type}` : "");
@@ -22675,7 +22730,13 @@ function aggregateWithoutColumn(rows, aggregations, getGroupKey) {
22675
22730
  const seen = {};
22676
22731
  const multiAgg = aggregations.length > 1;
22677
22732
  aggregations.forEach((agg) => {
22678
- const { aggregationType: type, valueField, valueFieldType, valueField2, valueField2Type } = agg;
22733
+ const {
22734
+ aggregationType: type,
22735
+ valueField,
22736
+ valueFieldType,
22737
+ valueField2,
22738
+ valueField2Type
22739
+ } = agg;
22679
22740
  if (!valueField) {
22680
22741
  if (type !== "count" && type !== "percentage") return;
22681
22742
  }
@@ -22706,7 +22767,10 @@ function aggregateWithoutColumn(rows, aggregations, getGroupKey) {
22706
22767
  }
22707
22768
  updateAccumulator(acc, row, agg, false);
22708
22769
  });
22709
- const sumOfDenom = Object.values(accs).reduce((t, a) => t + a.count, 0);
22770
+ const sumOfDenom = Object.values(accs).reduce(
22771
+ (t, a) => t + a.count,
22772
+ 0
22773
+ );
22710
22774
  Object.keys(accs).forEach((k) => {
22711
22775
  const acc = accs[k];
22712
22776
  seen[k][finalKey] = getFinalAggregationValue({
@@ -22734,13 +22798,18 @@ function applyPivotInMemory(rows, pivot, filters) {
22734
22798
  const dateRange = dateBucket ? getDateRangeFromFilters(filters) : void 0;
22735
22799
  const getRowKey = dateBucket ? (row) => {
22736
22800
  const rawValue = row[rowField];
22737
- const rawDateValue = rawValue !== null && typeof rawValue === "object" && rawValue.value ? rawValue.value : rawValue;
22801
+ const rawDateFromQuill = row.__quillRawDate;
22802
+ const rawDateValue = rawDateFromQuill ?? (rawValue !== null && typeof rawValue === "object" && rawValue.value ? rawValue.value : rawValue);
22738
22803
  return getDateKey(new Date(rawDateValue), dateBucket);
22739
22804
  } : (row) => row[rowField];
22740
22805
  const aggregated = columnField ? aggregateWithColumn(rows, columnField, aggregations, getRowKey) : aggregateWithoutColumn(rows, aggregations, getRowKey);
22741
22806
  const aggregatedRows = aggregated || {};
22742
22807
  if (rows.length === 0 && dateBucket && dateRange && !columnField) {
22743
- const bucketKeys = generateBucketKeys(dateRange.start, dateRange.end, dateBucket);
22808
+ const bucketKeys = generateBucketKeys(
22809
+ dateRange.start,
22810
+ dateRange.end,
22811
+ dateBucket
22812
+ );
22744
22813
  const emptyAgg = buildEmptyAggRow(aggregations);
22745
22814
  bucketKeys.forEach((k) => {
22746
22815
  aggregatedRows[k] = { ...emptyAgg };
@@ -22758,6 +22827,61 @@ function applyPivotInMemory(rows, pivot, filters) {
22758
22827
  }
22759
22828
  return sorted;
22760
22829
  }
22830
+ function generatePivotColumnsInMemory({
22831
+ pivot,
22832
+ pivotRows,
22833
+ sourceColumns
22834
+ }) {
22835
+ if (!pivot?.rowField || !Array.isArray(pivotRows) || pivotRows.length === 0) {
22836
+ return void 0;
22837
+ }
22838
+ const columns = Array.isArray(sourceColumns) ? sourceColumns : [];
22839
+ const rowSource = columns.find((col) => col.field === pivot.rowField);
22840
+ const isRowFieldDate = isDateLikeType(pivot.rowFieldType);
22841
+ const rowFieldType = rowSource?.fieldType ?? pivot.rowFieldType ?? "string";
22842
+ const rowColumn = {
22843
+ field: pivot.rowField,
22844
+ label: rowSource?.label ?? pivot.rowField,
22845
+ format: isRowFieldDate ? "string" : rowSource?.format ?? "string",
22846
+ fieldType: rowFieldType,
22847
+ dataTypeID: rowSource?.dataTypeID ?? 1043,
22848
+ jsType: rowSource?.jsType ?? (isRowFieldDate ? "date" : "string")
22849
+ };
22850
+ const valueFieldFormat = (valueField) => columns.find((col) => col.field === valueField)?.format ?? "whole_number";
22851
+ const multiAgg = (pivot.aggregations?.length ?? 0) > 1;
22852
+ const aggregationBySuffix = new Map(
22853
+ (pivot.aggregations ?? []).map((agg) => [
22854
+ multiAgg ? `_${agg.aggregationType}` : "",
22855
+ agg
22856
+ ])
22857
+ );
22858
+ const valueKeys = Array.from(
22859
+ new Set(
22860
+ pivotRows.flatMap(
22861
+ (row) => Object.keys(row).filter(
22862
+ (key) => key !== pivot.rowField && key !== "__quillRawDate"
22863
+ )
22864
+ )
22865
+ )
22866
+ );
22867
+ const valueColumns = valueKeys.map((key) => {
22868
+ const matchingSuffix = Array.from(aggregationBySuffix.keys()).find(
22869
+ (suffix) => suffix && key.endsWith(suffix)
22870
+ );
22871
+ const matchedAgg = matchingSuffix ? aggregationBySuffix.get(matchingSuffix) : pivot.aggregations?.[0];
22872
+ const format9 = matchedAgg?.aggregationType === "percentage" ? "percent" : valueFieldFormat(matchedAgg?.valueField);
22873
+ const valueFieldType = matchedAgg?.valueFieldType ?? "number";
22874
+ return {
22875
+ field: key,
22876
+ label: key,
22877
+ format: format9,
22878
+ fieldType: valueFieldType,
22879
+ jsType: valueFieldType,
22880
+ dataTypeID: columns.find((col) => col.field === matchedAgg?.valueField)?.dataTypeID ?? 20
22881
+ };
22882
+ });
22883
+ return [rowColumn, ...valueColumns];
22884
+ }
22761
22885
 
22762
22886
  // src/utils/cacheCab.ts
22763
22887
  var import_idb = require("idb");
@@ -22875,7 +22999,12 @@ var CacheCab = class {
22875
22999
  }
22876
23000
  const newRows = await this.applyPivotsAndFilters(result, dashboardFilters, customFilters, pivot, tenantPart, false);
22877
23001
  if (pivot) {
22878
- return { ...result, pivotRows: newRows, pivotRowCount: newRows.length };
23002
+ const pivotColumns = generatePivotColumnsInMemory({
23003
+ pivot,
23004
+ pivotRows: newRows,
23005
+ sourceColumns: result.columnInternal ?? result.columns
23006
+ });
23007
+ return { ...result, pivotRows: newRows, pivotColumns: pivotColumns ?? result.pivotColumns, pivotRowCount: newRows.length };
22879
23008
  }
22880
23009
  return { ...result, rows: newRows, rowCount: newRows.length };
22881
23010
  } else {
@@ -22961,7 +23090,12 @@ var CacheCab = class {
22961
23090
  await this.persistMetaToStorage();
22962
23091
  const newRows = await this.applyPivotsAndFilters(merged, dashboardFilters, customFilters, pivot, tenantPart, false);
22963
23092
  if (pivot) {
22964
- return { ...merged, pivotRows: newRows, pivotRowCount: newRows.length };
23093
+ const pivotColumns = generatePivotColumnsInMemory({
23094
+ pivot,
23095
+ pivotRows: newRows,
23096
+ sourceColumns: merged.columnInternal ?? merged.columns
23097
+ });
23098
+ return { ...merged, pivotRows: newRows, pivotColumns: pivotColumns ?? merged.pivotColumns, pivotRowCount: newRows.length };
22965
23099
  }
22966
23100
  return { ...merged, rows: newRows, rowCount: newRows.length };
22967
23101
  }
@@ -22989,7 +23123,12 @@ var CacheCab = class {
22989
23123
  const tenantPart = tenants ? JSON.stringify(tenants) : "";
22990
23124
  const newRows = await this.applyPivotsAndFilters(parsed, dashboardFilters, customFilters, pivot, tenantPart);
22991
23125
  if (pivot) {
22992
- return { ...parsed, pivotRows: newRows, pivotRowCount: newRows.length };
23126
+ const pivotColumns = generatePivotColumnsInMemory({
23127
+ pivot,
23128
+ pivotRows: newRows,
23129
+ sourceColumns: parsed.columnInternal ?? parsed.columns
23130
+ });
23131
+ return { ...parsed, pivotRows: newRows, pivotColumns: pivotColumns ?? parsed.pivotColumns, pivotRowCount: newRows.length };
22993
23132
  }
22994
23133
  return { ...parsed, rows: newRows, rowCount: newRows.length };
22995
23134
  } catch (err) {
@@ -26359,6 +26498,29 @@ var useDashboard = (dashboardName, config) => {
26359
26498
  };
26360
26499
  const usePivotTask = !cacheEnabled && !!reportInfo.pivot;
26361
26500
  const allFilters = dashboardFilters2.concat(customFilters).concat(customReportFiltersArray);
26501
+ const applyInMemoryPivotIfNeeded = (report2) => {
26502
+ const pivotToApply = reportInfo.pivot ?? report2.pivot;
26503
+ if (!pivotToApply || usePivotTask) {
26504
+ return report2;
26505
+ }
26506
+ const pivotRows = applyPivotInMemory(
26507
+ report2.rows ?? [],
26508
+ pivotToApply,
26509
+ allFilters
26510
+ );
26511
+ const pivotColumns = generatePivotColumnsInMemory({
26512
+ pivot: pivotToApply,
26513
+ pivotRows,
26514
+ sourceColumns: report2.columnInternal ?? report2.columns
26515
+ });
26516
+ return {
26517
+ ...report2,
26518
+ pivot: pivotToApply,
26519
+ pivotRows,
26520
+ pivotColumns: pivotColumns ?? report2.pivotColumns,
26521
+ pivotRowCount: pivotRows.length
26522
+ };
26523
+ };
26362
26524
  if (cacheEnabled && cacheCab.isCacheable(reportId)) {
26363
26525
  const report2 = await cacheCab.get(reportId, dashboardFilters2, customFilters.concat(customReportFiltersArray), reportInfo.pivot, client, tenants, flags, pageSize, getToken, eventTracking, forceCacheToRefresh);
26364
26526
  if (reportRequestIds.current[reportId] !== requestId) {
@@ -26416,11 +26578,12 @@ var useDashboard = (dashboardName, config) => {
26416
26578
  if (reportRequestIds.current[reportId] !== requestId) {
26417
26579
  return null;
26418
26580
  }
26581
+ const uncacheableReportWithPivot = applyInMemoryPivotIfNeeded(uncacheableReport);
26419
26582
  reportsDispatch({
26420
26583
  type: "UPDATE_REPORT",
26421
26584
  id: reportId,
26422
26585
  data: {
26423
- ...uncacheableReport,
26586
+ ...uncacheableReportWithPivot,
26424
26587
  pagination,
26425
26588
  triggerReload: false
26426
26589
  }
@@ -26471,7 +26634,7 @@ var useDashboard = (dashboardName, config) => {
26471
26634
  console.error("Failed to fetch background rows", e);
26472
26635
  });
26473
26636
  }
26474
- return uncacheableReport;
26637
+ return uncacheableReportWithPivot;
26475
26638
  } catch (error2) {
26476
26639
  console.error(error2);
26477
26640
  return null;
@@ -38684,13 +38847,28 @@ function Chart({
38684
38847
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { errorMessage: report?.error ?? error }) });
38685
38848
  }
38686
38849
  if (isMissingDateField) {
38687
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { errorMessage: `The query for this report is missing dashboard date filter field ${report?.dateField?.field}, which is necessary for date filtering on this dashboard when the cache is enabled.` }) });
38850
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
38851
+ ChartError,
38852
+ {
38853
+ errorMessage: `The query for this report is missing dashboard date filter field ${report?.dateField?.field}, which is necessary for date filtering on this dashboard when the cache is enabled.`
38854
+ }
38855
+ ) });
38688
38856
  }
38689
38857
  if (usesLimitInQuery) {
38690
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { errorMessage: `The query for this report uses the LIMIT keyword, which is not supported when the cache is enabled.` }) });
38858
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
38859
+ ChartError,
38860
+ {
38861
+ errorMessage: `The query for this report uses the LIMIT keyword, which is not supported when the cache is enabled.`
38862
+ }
38863
+ ) });
38691
38864
  }
38692
38865
  if (missingDashboardFilterFields.length) {
38693
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ChartError, { errorMessage: `The query for this report is missing dashboard filter fields: ${missingDashboardFilterFields.join(", ")}` }) });
38866
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { style: containerStyle, className, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
38867
+ ChartError,
38868
+ {
38869
+ errorMessage: `The query for this report is missing dashboard filter fields: ${missingDashboardFilterFields.join(", ")}`
38870
+ }
38871
+ ) });
38694
38872
  }
38695
38873
  return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
38696
38874
  "div",
@@ -56520,10 +56698,29 @@ function StaticChart(props) {
56520
56698
  ...report,
56521
56699
  ...report.pivot ? formattedPivotRowsAndColumns(report) : {}
56522
56700
  } : void 0;
56701
+ const patchedConfig = config && config.pivot ? {
56702
+ ...config,
56703
+ yAxisFields: config.columns?.slice(1).map((col) => ({
56704
+ field: col.field,
56705
+ label: col.label ?? col.field,
56706
+ format: col.format ?? "number"
56707
+ })) ?? config.yAxisFields
56708
+ } : config;
56709
+ if (patchedConfig) {
56710
+ const sample = (patchedConfig.pivotRows ?? patchedConfig.rows ?? []).slice(0, 1).map((row) => {
56711
+ const field = patchedConfig.yAxisFields?.[0]?.field;
56712
+ return {
56713
+ ...row,
56714
+ _firstField: field,
56715
+ _firstFieldType: field ? typeof row[field] : void 0
56716
+ };
56717
+ });
56718
+ }
56523
56719
  return /* @__PURE__ */ (0, import_jsx_runtime84.jsx)(
56524
56720
  ChartDisplay,
56525
56721
  {
56526
- config,
56722
+ reportId,
56723
+ config: patchedConfig,
56527
56724
  onClickChartElement,
56528
56725
  loading,
56529
56726
  className,
package/dist/index.js CHANGED
@@ -277,6 +277,9 @@ var init_valueFormatter = __esm({
277
277
  maximumFractionDigits: 2
278
278
  });
279
279
  formatPercent = (value) => {
280
+ if (typeof value === "string" && /^\s*[+-]?(?:\d+(?:\.\d+)?|\.\d+)\s*%\s*$/.test(value)) {
281
+ return value;
282
+ }
280
283
  return formatterPercent.format(Number(value));
281
284
  };
282
285
  _getUTCDateHelper = (value, fmt) => {
@@ -19893,11 +19896,12 @@ async function cleanDashboardItem({
19893
19896
  page: DEFAULT_PAGINATION
19894
19897
  };
19895
19898
  if (item.pivot && skipPivotFetch && item.rows && item.fields) {
19899
+ const pivotSourceRows = item.rows.map((row) => ({ ...row }));
19896
19900
  const dateFilter = dashboardFilters?.find(
19897
19901
  (filter) => filter.filterType === "date_range"
19898
19902
  );
19899
19903
  pivotTable = processPivotData({
19900
- rows: item.rows,
19904
+ rows: pivotSourceRows,
19901
19905
  fields: item.fields,
19902
19906
  pivot: {
19903
19907
  ...item.pivot,
@@ -22177,7 +22181,20 @@ var applyFiltersInMemory = (rows, filters, options) => {
22177
22181
  // src/utils/inMemoryPivotEngine.ts
22178
22182
  init_columnType();
22179
22183
  var MS_IN_DAY = 24 * 60 * 60 * 1e3;
22180
- var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
22184
+ var MONTHS = [
22185
+ "Jan",
22186
+ "Feb",
22187
+ "Mar",
22188
+ "Apr",
22189
+ "May",
22190
+ "Jun",
22191
+ "Jul",
22192
+ "Aug",
22193
+ "Sep",
22194
+ "Oct",
22195
+ "Nov",
22196
+ "Dec"
22197
+ ];
22181
22198
  var INVALID_DATE_KEY = "-2026";
22182
22199
  function singleAggToMultiAgg(pivot) {
22183
22200
  if (pivot.aggregations) {
@@ -22185,7 +22202,12 @@ function singleAggToMultiAgg(pivot) {
22185
22202
  }
22186
22203
  const newPivot = { ...pivot };
22187
22204
  const newAgg = { aggregationType: pivot.aggregationType };
22188
- const fieldsToCopy = ["valueField", "valueFieldType", "valueField2", "valueField2Type"];
22205
+ const fieldsToCopy = [
22206
+ "valueField",
22207
+ "valueFieldType",
22208
+ "valueField2",
22209
+ "valueField2Type"
22210
+ ];
22189
22211
  fieldsToCopy.forEach((x) => {
22190
22212
  if (pivot[x]) {
22191
22213
  newAgg[x] = pivot[x];
@@ -22216,6 +22238,12 @@ function isValidDate3(date) {
22216
22238
  return false;
22217
22239
  }
22218
22240
  }
22241
+ function isDateLikeType(fieldType) {
22242
+ if (!fieldType) {
22243
+ return false;
22244
+ }
22245
+ return isDateType(fieldType) || isDateFormat2(fieldType);
22246
+ }
22219
22247
  function inferDateBucketFromFilters(pivot, filters) {
22220
22248
  if (!pivot?.rowFieldType) {
22221
22249
  return void 0;
@@ -22359,8 +22387,12 @@ function getDateRangeFromFilters(filters) {
22359
22387
  }
22360
22388
  function generateBucketKeys(start2, end, bucket) {
22361
22389
  const keys = /* @__PURE__ */ new Set();
22362
- const startDay = new Date(Date.UTC(start2.getUTCFullYear(), start2.getUTCMonth(), start2.getUTCDate()));
22363
- const endDay = new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate()));
22390
+ const startDay = new Date(
22391
+ Date.UTC(start2.getUTCFullYear(), start2.getUTCMonth(), start2.getUTCDate())
22392
+ );
22393
+ const endDay = new Date(
22394
+ Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate())
22395
+ );
22364
22396
  const cur = new Date(startDay);
22365
22397
  while (cur <= endDay) {
22366
22398
  keys.add(getDateKey(cur, bucket));
@@ -22384,7 +22416,9 @@ function getBucketRange(dateKey, bucket) {
22384
22416
  let end = new Date(d);
22385
22417
  switch (bucket) {
22386
22418
  case "day":
22387
- start2 = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
22419
+ start2 = new Date(
22420
+ Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())
22421
+ );
22388
22422
  end = new Date(start2);
22389
22423
  break;
22390
22424
  case "week":
@@ -22426,10 +22460,18 @@ function getDateKey(date, bucket) {
22426
22460
  }
22427
22461
  switch (bucket) {
22428
22462
  case "day":
22429
- return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()).toString();
22463
+ return Date.UTC(
22464
+ date.getUTCFullYear(),
22465
+ date.getUTCMonth(),
22466
+ date.getUTCDate()
22467
+ ).toString();
22430
22468
  case "week": {
22431
22469
  const day = date.getUTCDay();
22432
- const mondayUtc = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() - (day + 6) % 7);
22470
+ const mondayUtc = Date.UTC(
22471
+ date.getUTCFullYear(),
22472
+ date.getUTCMonth(),
22473
+ date.getUTCDate() - (day + 6) % 7
22474
+ );
22433
22475
  return mondayUtc.toString();
22434
22476
  }
22435
22477
  case "month":
@@ -22493,7 +22535,11 @@ function assembleFinalRows(seen, rowKey, dateBucket, dateRange) {
22493
22535
  if (bucketEnd > dateRange.end) bucketEnd = dateRange.end;
22494
22536
  }
22495
22537
  return {
22496
- [rowKey]: formatBucketNameFromRange(bucketStart, bucketEnd, dateBucket),
22538
+ [rowKey]: formatBucketNameFromRange(
22539
+ bucketStart,
22540
+ bucketEnd,
22541
+ dateBucket
22542
+ ),
22497
22543
  ...filled[k],
22498
22544
  __quillRawDate: bucketStart.toISOString()
22499
22545
  };
@@ -22652,7 +22698,13 @@ function aggregateWithColumn(rows, colKey, aggregations, getGroupKey) {
22652
22698
  const seen = {};
22653
22699
  const multiAgg = aggregations.length > 1;
22654
22700
  aggregations.forEach((agg) => {
22655
- const { aggregationType: type, valueField, valueFieldType, valueField2, valueField2Type } = agg;
22701
+ const {
22702
+ aggregationType: type,
22703
+ valueField,
22704
+ valueFieldType,
22705
+ valueField2,
22706
+ valueField2Type
22707
+ } = agg;
22656
22708
  if (!valueField) {
22657
22709
  if (type !== "count" && type !== "percentage") return;
22658
22710
  }
@@ -22685,7 +22737,10 @@ function aggregateWithColumn(rows, colKey, aggregations, getGroupKey) {
22685
22737
  });
22686
22738
  Object.keys(accs).forEach((groupKey) => {
22687
22739
  if (!seen[groupKey]) seen[groupKey] = {};
22688
- const sumOfDenom = Object.values(accs[groupKey]).reduce((t, a) => t + a.count, 0);
22740
+ const sumOfDenom = Object.values(accs[groupKey]).reduce(
22741
+ (t, a) => t + a.count,
22742
+ 0
22743
+ );
22689
22744
  Object.keys(accs[groupKey]).forEach((colVal) => {
22690
22745
  const acc = accs[groupKey][colVal];
22691
22746
  const finalKey = `${colVal}` + (multiAgg ? `_${type}` : "");
@@ -22707,7 +22762,13 @@ function aggregateWithoutColumn(rows, aggregations, getGroupKey) {
22707
22762
  const seen = {};
22708
22763
  const multiAgg = aggregations.length > 1;
22709
22764
  aggregations.forEach((agg) => {
22710
- const { aggregationType: type, valueField, valueFieldType, valueField2, valueField2Type } = agg;
22765
+ const {
22766
+ aggregationType: type,
22767
+ valueField,
22768
+ valueFieldType,
22769
+ valueField2,
22770
+ valueField2Type
22771
+ } = agg;
22711
22772
  if (!valueField) {
22712
22773
  if (type !== "count" && type !== "percentage") return;
22713
22774
  }
@@ -22738,7 +22799,10 @@ function aggregateWithoutColumn(rows, aggregations, getGroupKey) {
22738
22799
  }
22739
22800
  updateAccumulator(acc, row, agg, false);
22740
22801
  });
22741
- const sumOfDenom = Object.values(accs).reduce((t, a) => t + a.count, 0);
22802
+ const sumOfDenom = Object.values(accs).reduce(
22803
+ (t, a) => t + a.count,
22804
+ 0
22805
+ );
22742
22806
  Object.keys(accs).forEach((k) => {
22743
22807
  const acc = accs[k];
22744
22808
  seen[k][finalKey] = getFinalAggregationValue({
@@ -22766,13 +22830,18 @@ function applyPivotInMemory(rows, pivot, filters) {
22766
22830
  const dateRange = dateBucket ? getDateRangeFromFilters(filters) : void 0;
22767
22831
  const getRowKey = dateBucket ? (row) => {
22768
22832
  const rawValue = row[rowField];
22769
- const rawDateValue = rawValue !== null && typeof rawValue === "object" && rawValue.value ? rawValue.value : rawValue;
22833
+ const rawDateFromQuill = row.__quillRawDate;
22834
+ const rawDateValue = rawDateFromQuill ?? (rawValue !== null && typeof rawValue === "object" && rawValue.value ? rawValue.value : rawValue);
22770
22835
  return getDateKey(new Date(rawDateValue), dateBucket);
22771
22836
  } : (row) => row[rowField];
22772
22837
  const aggregated = columnField ? aggregateWithColumn(rows, columnField, aggregations, getRowKey) : aggregateWithoutColumn(rows, aggregations, getRowKey);
22773
22838
  const aggregatedRows = aggregated || {};
22774
22839
  if (rows.length === 0 && dateBucket && dateRange && !columnField) {
22775
- const bucketKeys = generateBucketKeys(dateRange.start, dateRange.end, dateBucket);
22840
+ const bucketKeys = generateBucketKeys(
22841
+ dateRange.start,
22842
+ dateRange.end,
22843
+ dateBucket
22844
+ );
22776
22845
  const emptyAgg = buildEmptyAggRow(aggregations);
22777
22846
  bucketKeys.forEach((k) => {
22778
22847
  aggregatedRows[k] = { ...emptyAgg };
@@ -22790,6 +22859,61 @@ function applyPivotInMemory(rows, pivot, filters) {
22790
22859
  }
22791
22860
  return sorted;
22792
22861
  }
22862
+ function generatePivotColumnsInMemory({
22863
+ pivot,
22864
+ pivotRows,
22865
+ sourceColumns
22866
+ }) {
22867
+ if (!pivot?.rowField || !Array.isArray(pivotRows) || pivotRows.length === 0) {
22868
+ return void 0;
22869
+ }
22870
+ const columns = Array.isArray(sourceColumns) ? sourceColumns : [];
22871
+ const rowSource = columns.find((col) => col.field === pivot.rowField);
22872
+ const isRowFieldDate = isDateLikeType(pivot.rowFieldType);
22873
+ const rowFieldType = rowSource?.fieldType ?? pivot.rowFieldType ?? "string";
22874
+ const rowColumn = {
22875
+ field: pivot.rowField,
22876
+ label: rowSource?.label ?? pivot.rowField,
22877
+ format: isRowFieldDate ? "string" : rowSource?.format ?? "string",
22878
+ fieldType: rowFieldType,
22879
+ dataTypeID: rowSource?.dataTypeID ?? 1043,
22880
+ jsType: rowSource?.jsType ?? (isRowFieldDate ? "date" : "string")
22881
+ };
22882
+ const valueFieldFormat = (valueField) => columns.find((col) => col.field === valueField)?.format ?? "whole_number";
22883
+ const multiAgg = (pivot.aggregations?.length ?? 0) > 1;
22884
+ const aggregationBySuffix = new Map(
22885
+ (pivot.aggregations ?? []).map((agg) => [
22886
+ multiAgg ? `_${agg.aggregationType}` : "",
22887
+ agg
22888
+ ])
22889
+ );
22890
+ const valueKeys = Array.from(
22891
+ new Set(
22892
+ pivotRows.flatMap(
22893
+ (row) => Object.keys(row).filter(
22894
+ (key) => key !== pivot.rowField && key !== "__quillRawDate"
22895
+ )
22896
+ )
22897
+ )
22898
+ );
22899
+ const valueColumns = valueKeys.map((key) => {
22900
+ const matchingSuffix = Array.from(aggregationBySuffix.keys()).find(
22901
+ (suffix) => suffix && key.endsWith(suffix)
22902
+ );
22903
+ const matchedAgg = matchingSuffix ? aggregationBySuffix.get(matchingSuffix) : pivot.aggregations?.[0];
22904
+ const format9 = matchedAgg?.aggregationType === "percentage" ? "percent" : valueFieldFormat(matchedAgg?.valueField);
22905
+ const valueFieldType = matchedAgg?.valueFieldType ?? "number";
22906
+ return {
22907
+ field: key,
22908
+ label: key,
22909
+ format: format9,
22910
+ fieldType: valueFieldType,
22911
+ jsType: valueFieldType,
22912
+ dataTypeID: columns.find((col) => col.field === matchedAgg?.valueField)?.dataTypeID ?? 20
22913
+ };
22914
+ });
22915
+ return [rowColumn, ...valueColumns];
22916
+ }
22793
22917
 
22794
22918
  // src/utils/cacheCab.ts
22795
22919
  import { openDB } from "idb";
@@ -22907,7 +23031,12 @@ var CacheCab = class {
22907
23031
  }
22908
23032
  const newRows = await this.applyPivotsAndFilters(result, dashboardFilters, customFilters, pivot, tenantPart, false);
22909
23033
  if (pivot) {
22910
- return { ...result, pivotRows: newRows, pivotRowCount: newRows.length };
23034
+ const pivotColumns = generatePivotColumnsInMemory({
23035
+ pivot,
23036
+ pivotRows: newRows,
23037
+ sourceColumns: result.columnInternal ?? result.columns
23038
+ });
23039
+ return { ...result, pivotRows: newRows, pivotColumns: pivotColumns ?? result.pivotColumns, pivotRowCount: newRows.length };
22911
23040
  }
22912
23041
  return { ...result, rows: newRows, rowCount: newRows.length };
22913
23042
  } else {
@@ -22993,7 +23122,12 @@ var CacheCab = class {
22993
23122
  await this.persistMetaToStorage();
22994
23123
  const newRows = await this.applyPivotsAndFilters(merged, dashboardFilters, customFilters, pivot, tenantPart, false);
22995
23124
  if (pivot) {
22996
- return { ...merged, pivotRows: newRows, pivotRowCount: newRows.length };
23125
+ const pivotColumns = generatePivotColumnsInMemory({
23126
+ pivot,
23127
+ pivotRows: newRows,
23128
+ sourceColumns: merged.columnInternal ?? merged.columns
23129
+ });
23130
+ return { ...merged, pivotRows: newRows, pivotColumns: pivotColumns ?? merged.pivotColumns, pivotRowCount: newRows.length };
22997
23131
  }
22998
23132
  return { ...merged, rows: newRows, rowCount: newRows.length };
22999
23133
  }
@@ -23021,7 +23155,12 @@ var CacheCab = class {
23021
23155
  const tenantPart = tenants ? JSON.stringify(tenants) : "";
23022
23156
  const newRows = await this.applyPivotsAndFilters(parsed, dashboardFilters, customFilters, pivot, tenantPart);
23023
23157
  if (pivot) {
23024
- return { ...parsed, pivotRows: newRows, pivotRowCount: newRows.length };
23158
+ const pivotColumns = generatePivotColumnsInMemory({
23159
+ pivot,
23160
+ pivotRows: newRows,
23161
+ sourceColumns: parsed.columnInternal ?? parsed.columns
23162
+ });
23163
+ return { ...parsed, pivotRows: newRows, pivotColumns: pivotColumns ?? parsed.pivotColumns, pivotRowCount: newRows.length };
23025
23164
  }
23026
23165
  return { ...parsed, rows: newRows, rowCount: newRows.length };
23027
23166
  } catch (err) {
@@ -26397,6 +26536,29 @@ var useDashboard = (dashboardName, config) => {
26397
26536
  };
26398
26537
  const usePivotTask = !cacheEnabled && !!reportInfo.pivot;
26399
26538
  const allFilters = dashboardFilters2.concat(customFilters).concat(customReportFiltersArray);
26539
+ const applyInMemoryPivotIfNeeded = (report2) => {
26540
+ const pivotToApply = reportInfo.pivot ?? report2.pivot;
26541
+ if (!pivotToApply || usePivotTask) {
26542
+ return report2;
26543
+ }
26544
+ const pivotRows = applyPivotInMemory(
26545
+ report2.rows ?? [],
26546
+ pivotToApply,
26547
+ allFilters
26548
+ );
26549
+ const pivotColumns = generatePivotColumnsInMemory({
26550
+ pivot: pivotToApply,
26551
+ pivotRows,
26552
+ sourceColumns: report2.columnInternal ?? report2.columns
26553
+ });
26554
+ return {
26555
+ ...report2,
26556
+ pivot: pivotToApply,
26557
+ pivotRows,
26558
+ pivotColumns: pivotColumns ?? report2.pivotColumns,
26559
+ pivotRowCount: pivotRows.length
26560
+ };
26561
+ };
26400
26562
  if (cacheEnabled && cacheCab.isCacheable(reportId)) {
26401
26563
  const report2 = await cacheCab.get(reportId, dashboardFilters2, customFilters.concat(customReportFiltersArray), reportInfo.pivot, client, tenants, flags, pageSize, getToken, eventTracking, forceCacheToRefresh);
26402
26564
  if (reportRequestIds.current[reportId] !== requestId) {
@@ -26454,11 +26616,12 @@ var useDashboard = (dashboardName, config) => {
26454
26616
  if (reportRequestIds.current[reportId] !== requestId) {
26455
26617
  return null;
26456
26618
  }
26619
+ const uncacheableReportWithPivot = applyInMemoryPivotIfNeeded(uncacheableReport);
26457
26620
  reportsDispatch({
26458
26621
  type: "UPDATE_REPORT",
26459
26622
  id: reportId,
26460
26623
  data: {
26461
- ...uncacheableReport,
26624
+ ...uncacheableReportWithPivot,
26462
26625
  pagination,
26463
26626
  triggerReload: false
26464
26627
  }
@@ -26509,7 +26672,7 @@ var useDashboard = (dashboardName, config) => {
26509
26672
  console.error("Failed to fetch background rows", e);
26510
26673
  });
26511
26674
  }
26512
- return uncacheableReport;
26675
+ return uncacheableReportWithPivot;
26513
26676
  } catch (error2) {
26514
26677
  console.error(error2);
26515
26678
  return null;
@@ -38793,13 +38956,28 @@ function Chart({
38793
38956
  return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(ChartError, { errorMessage: report?.error ?? error }) });
38794
38957
  }
38795
38958
  if (isMissingDateField) {
38796
- return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(ChartError, { errorMessage: `The query for this report is missing dashboard date filter field ${report?.dateField?.field}, which is necessary for date filtering on this dashboard when the cache is enabled.` }) });
38959
+ return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(
38960
+ ChartError,
38961
+ {
38962
+ errorMessage: `The query for this report is missing dashboard date filter field ${report?.dateField?.field}, which is necessary for date filtering on this dashboard when the cache is enabled.`
38963
+ }
38964
+ ) });
38797
38965
  }
38798
38966
  if (usesLimitInQuery) {
38799
- return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(ChartError, { errorMessage: `The query for this report uses the LIMIT keyword, which is not supported when the cache is enabled.` }) });
38967
+ return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(
38968
+ ChartError,
38969
+ {
38970
+ errorMessage: `The query for this report uses the LIMIT keyword, which is not supported when the cache is enabled.`
38971
+ }
38972
+ ) });
38800
38973
  }
38801
38974
  if (missingDashboardFilterFields.length) {
38802
- return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(ChartError, { errorMessage: `The query for this report is missing dashboard filter fields: ${missingDashboardFilterFields.join(", ")}` }) });
38975
+ return /* @__PURE__ */ jsx49("div", { style: containerStyle, className, children: /* @__PURE__ */ jsx49(
38976
+ ChartError,
38977
+ {
38978
+ errorMessage: `The query for this report is missing dashboard filter fields: ${missingDashboardFilterFields.join(", ")}`
38979
+ }
38980
+ ) });
38803
38981
  }
38804
38982
  return /* @__PURE__ */ jsxs37(
38805
38983
  "div",
@@ -56731,10 +56909,29 @@ function StaticChart(props) {
56731
56909
  ...report,
56732
56910
  ...report.pivot ? formattedPivotRowsAndColumns(report) : {}
56733
56911
  } : void 0;
56912
+ const patchedConfig = config && config.pivot ? {
56913
+ ...config,
56914
+ yAxisFields: config.columns?.slice(1).map((col) => ({
56915
+ field: col.field,
56916
+ label: col.label ?? col.field,
56917
+ format: col.format ?? "number"
56918
+ })) ?? config.yAxisFields
56919
+ } : config;
56920
+ if (patchedConfig) {
56921
+ const sample = (patchedConfig.pivotRows ?? patchedConfig.rows ?? []).slice(0, 1).map((row) => {
56922
+ const field = patchedConfig.yAxisFields?.[0]?.field;
56923
+ return {
56924
+ ...row,
56925
+ _firstField: field,
56926
+ _firstFieldType: field ? typeof row[field] : void 0
56927
+ };
56928
+ });
56929
+ }
56734
56930
  return /* @__PURE__ */ jsx84(
56735
56931
  ChartDisplay,
56736
56932
  {
56737
- config,
56933
+ reportId,
56934
+ config: patchedConfig,
56738
56935
  onClickChartElement,
56739
56936
  loading,
56740
56937
  className,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quillsql/react",
3
- "version": "2.16.21",
3
+ "version": "2.16.22",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {