@quillsql/react 2.16.10 → 2.16.12

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/dist/index.js CHANGED
@@ -1292,6 +1292,8 @@ import {
1292
1292
  addDays,
1293
1293
  differenceInDays,
1294
1294
  endOfDay,
1295
+ endOfMonth,
1296
+ endOfQuarter,
1295
1297
  endOfToday,
1296
1298
  format as format2,
1297
1299
  isEqual,
@@ -1300,9 +1302,13 @@ import {
1300
1302
  min,
1301
1303
  set,
1302
1304
  startOfDay,
1305
+ startOfMonth,
1306
+ startOfQuarter,
1303
1307
  startOfToday,
1304
1308
  startOfWeek as startOfWeek2,
1305
- sub
1309
+ sub,
1310
+ subMonths,
1311
+ subQuarters
1306
1312
  } from "date-fns";
1307
1313
  var primaryRangeCustomIntervals, adjustForLeapYear, convertCustomIntervalToDateRange, getLabelForCustomInterval, convertPresetOptionsToSelectableList, PRIMARY_RANGE, COMPARISON_OPTIONS, COMPARISON_RANGE, defaultOptionsV2, reportBuilderOptions, getRangeFromPresetOptions;
1308
1314
  var init_dateRangePickerUtils = __esm({
@@ -1430,6 +1436,9 @@ var init_dateRangePickerUtils = __esm({
1430
1436
  value: 12,
1431
1437
  unit: "months"
1432
1438
  },
1439
+ {
1440
+ type: "previous_month"
1441
+ },
1433
1442
  {
1434
1443
  type: "relative",
1435
1444
  value: 1,
@@ -1469,11 +1478,33 @@ var init_dateRangePickerUtils = __esm({
1469
1478
  })
1470
1479
  };
1471
1480
  }
1472
- case "relative":
1481
+ case "relative": {
1482
+ if (interval2.unit === "months" && interval2.value === 1 && (!interval2.label || interval2.label === "Last month")) {
1483
+ const lastMonth = subMonths(startOfToday(), 1);
1484
+ return {
1485
+ startDate: startOfMonth(lastMonth),
1486
+ endDate: endOfMonth(lastMonth)
1487
+ };
1488
+ }
1473
1489
  return {
1474
1490
  startDate: sub(startOfToday(), { [interval2.unit]: interval2.value }),
1475
1491
  endDate: endOfToday()
1476
1492
  };
1493
+ }
1494
+ case "previous_month": {
1495
+ const lastMonth = subMonths(startOfToday(), 1);
1496
+ return {
1497
+ startDate: startOfMonth(lastMonth),
1498
+ endDate: endOfMonth(lastMonth)
1499
+ };
1500
+ }
1501
+ case "previous_quarter": {
1502
+ const lastQuarter = subQuarters(startOfToday(), 1);
1503
+ return {
1504
+ startDate: startOfQuarter(lastQuarter),
1505
+ endDate: endOfQuarter(lastQuarter)
1506
+ };
1507
+ }
1477
1508
  case "repeating": {
1478
1509
  const currentDate = /* @__PURE__ */ new Date();
1479
1510
  const currentYear = currentDate.getFullYear();
@@ -1518,24 +1549,39 @@ var init_dateRangePickerUtils = __esm({
1518
1549
  getLabelForCustomInterval = (interval2) => {
1519
1550
  switch (interval2.type) {
1520
1551
  case "week":
1521
- return "This week";
1552
+ return interval2.label ?? "This week";
1522
1553
  case "static":
1523
1554
  return interval2.label ?? "Custom";
1524
1555
  case "relative":
1525
1556
  return interval2.label ?? `Last ${interval2.value === 1 ? "" : interval2.value + " "}${interval2.value === 1 ? interval2.unit.slice(0, -1) : interval2.unit}`;
1557
+ case "previous_month":
1558
+ return interval2.label ?? "Last month";
1559
+ case "previous_quarter":
1560
+ return interval2.label ?? "Last quarter";
1526
1561
  case "repeating":
1527
- return "This " + interval2.label.toLowerCase();
1562
+ if (interval2.label === "Month") return "This month";
1563
+ if (interval2.label === "Year") return "This year";
1564
+ return interval2.label;
1528
1565
  }
1529
1566
  };
1530
1567
  convertPresetOptionsToSelectableList = (customIntervals, defaultIntervals) => {
1531
- const defaultCustomIntervals = defaultIntervals.map(
1532
- (interval2) => {
1533
- if (interval2.label === "This week") {
1534
- return {
1568
+ const customLabelMap = /* @__PURE__ */ new Map();
1569
+ defaultIntervals.forEach((interval2) => {
1570
+ if (interval2.customLabel) {
1571
+ customLabelMap.set(interval2.label, interval2.customLabel);
1572
+ }
1573
+ });
1574
+ const defaultCustomIntervals = defaultIntervals.flatMap((interval2) => {
1575
+ let createdIntervals = [];
1576
+ if (interval2.label === "This week") {
1577
+ createdIntervals = [
1578
+ {
1535
1579
  type: "week"
1536
- };
1537
- } else if (interval2.label === "This month" || interval2.label === "Monthly") {
1538
- return {
1580
+ }
1581
+ ];
1582
+ } else if (interval2.label === "This month" || interval2.label === "Monthly") {
1583
+ createdIntervals = [
1584
+ {
1539
1585
  type: "repeating",
1540
1586
  label: "Month",
1541
1587
  loopDate: { day: 1, month: 1 },
@@ -1615,9 +1661,11 @@ var init_dateRangePickerUtils = __esm({
1615
1661
  endDate: { day: 31, month: 12 }
1616
1662
  }
1617
1663
  ]
1618
- };
1619
- } else if (interval2.label === "This year" || interval2.label === "Yearly") {
1620
- return {
1664
+ }
1665
+ ];
1666
+ } else if (interval2.label === "This year" || interval2.label === "Yearly") {
1667
+ createdIntervals = [
1668
+ {
1621
1669
  type: "repeating",
1622
1670
  label: "Year",
1623
1671
  loopDate: { day: 1, month: 1 },
@@ -1631,42 +1679,69 @@ var init_dateRangePickerUtils = __esm({
1631
1679
  endDate: { day: 31, month: 12 }
1632
1680
  }
1633
1681
  ]
1634
- };
1635
- } else if (interval2.label === "Last 7 days") {
1636
- return {
1682
+ }
1683
+ ];
1684
+ } else if (interval2.label === "Last 7 days") {
1685
+ createdIntervals = [
1686
+ {
1637
1687
  type: "relative",
1638
1688
  value: 7,
1639
1689
  unit: "days"
1640
- };
1641
- } else if (interval2.label === "Last 30 days") {
1642
- return {
1690
+ }
1691
+ ];
1692
+ } else if (interval2.label === "Last 30 days") {
1693
+ createdIntervals = [
1694
+ {
1643
1695
  type: "relative",
1644
1696
  value: 30,
1645
1697
  unit: "days"
1646
- };
1647
- } else if (interval2.label === "Last 90 days") {
1648
- return {
1698
+ }
1699
+ ];
1700
+ } else if (interval2.label === "Last 90 days") {
1701
+ createdIntervals = [
1702
+ {
1649
1703
  type: "relative",
1650
1704
  value: 90,
1651
1705
  unit: "days"
1652
- };
1653
- } else if (interval2.label === "Last 6 months") {
1654
- return {
1706
+ }
1707
+ ];
1708
+ } else if (interval2.label === "Last 6 months") {
1709
+ createdIntervals = [
1710
+ {
1655
1711
  type: "relative",
1656
1712
  value: 6,
1657
1713
  unit: "months"
1658
- };
1659
- } else if (interval2.label === "Last 12 months") {
1660
- return {
1714
+ }
1715
+ ];
1716
+ } else if (interval2.label === "Last 12 months") {
1717
+ createdIntervals = [
1718
+ {
1661
1719
  type: "relative",
1662
1720
  value: 12,
1663
1721
  unit: "months"
1664
- };
1665
- } else {
1666
- throw new Error("Invalid interval");
1667
- }
1722
+ }
1723
+ ];
1724
+ } else if (interval2.label === "Last month") {
1725
+ createdIntervals = [
1726
+ {
1727
+ type: "previous_month"
1728
+ }
1729
+ ];
1730
+ } else if (interval2.label === "Last quarter") {
1731
+ createdIntervals = [
1732
+ {
1733
+ type: "previous_quarter"
1734
+ }
1735
+ ];
1668
1736
  }
1669
- );
1737
+ if (interval2.customLabel && createdIntervals.length > 0) {
1738
+ return createdIntervals.map((i) => ({
1739
+ ...i,
1740
+ label: interval2.customLabel
1741
+ }));
1742
+ }
1743
+ return createdIntervals;
1744
+ });
1670
1745
  return customIntervals?.length || defaultCustomIntervals?.length ? (defaultCustomIntervals ?? []).concat(customIntervals ?? []).flatMap((option) => {
1671
1746
  if (option.type === "repeating" && option.loopStart) {
1672
1747
  const presets = [];
@@ -1708,8 +1783,19 @@ var init_dateRangePickerUtils = __esm({
1708
1783
  }
1709
1784
  };
1710
1785
  const currentYear = currentDate.getFullYear();
1786
+ const baseLabel = getLabelForSubInterval(currentSubInterval);
1787
+ let customLabel2;
1788
+ if (option.label && option.label !== "Month" && option.label !== "Year") {
1789
+ customLabel2 = option.label;
1790
+ } else {
1791
+ if (option.label === "Month") {
1792
+ customLabel2 = customLabelMap.get("This month") || customLabelMap.get("Monthly");
1793
+ } else if (option.label === "Year") {
1794
+ customLabel2 = customLabelMap.get("This year") || customLabelMap.get("Yearly");
1795
+ }
1796
+ }
1711
1797
  presets.push({
1712
- label: getLabelForSubInterval(currentSubInterval),
1798
+ label: customLabel2 || baseLabel,
1713
1799
  value: getLabelForSubInterval(currentSubInterval).toUpperCase().replace(/ /g, "_") ?? "",
1714
1800
  startDate: set(/* @__PURE__ */ new Date(), {
1715
1801
  year: currentYear,
@@ -1741,9 +1827,12 @@ var init_dateRangePickerUtils = __esm({
1741
1827
  return presets;
1742
1828
  }
1743
1829
  const dateRange = convertCustomIntervalToDateRange(option);
1830
+ const generatedLabel = getLabelForCustomInterval(option);
1831
+ const customLabel = customLabelMap.get(generatedLabel);
1832
+ const finalLabel = customLabel || generatedLabel;
1744
1833
  return [
1745
1834
  {
1746
- label: getLabelForCustomInterval(option),
1835
+ label: finalLabel,
1747
1836
  // Value is option label in uppercase with spaces replaced by underscores
1748
1837
  value: getLabelForCustomInterval(option).toUpperCase().replace(/ /g, "_") ?? "",
1749
1838
  startDate: dateRange.startDate,
@@ -1800,6 +1889,7 @@ var init_dateRangePickerUtils = __esm({
1800
1889
  LAST_12_MONTHS: convertCustomIntervalToDateRange(
1801
1890
  primaryRangeCustomIntervals[7]
1802
1891
  ),
1892
+ LAST_MONTH: convertCustomIntervalToDateRange(primaryRangeCustomIntervals[8]),
1803
1893
  ALL_TIME: { startDate: void 0, endDate: void 0 }
1804
1894
  };
1805
1895
  COMPARISON_OPTIONS = [
@@ -1874,6 +1964,12 @@ var init_dateRangePickerUtils = __esm({
1874
1964
  startDate: PRIMARY_RANGE["LAST_30_DAYS"].startDate,
1875
1965
  endDate: PRIMARY_RANGE["LAST_30_DAYS"].endDate
1876
1966
  },
1967
+ {
1968
+ value: "LAST_MONTH",
1969
+ label: "Last month",
1970
+ startDate: PRIMARY_RANGE["LAST_MONTH"].startDate,
1971
+ endDate: PRIMARY_RANGE["LAST_MONTH"].endDate
1972
+ },
1877
1973
  {
1878
1974
  value: "LAST_90_DAYS",
1879
1975
  label: "Last 90 days",
@@ -2439,7 +2535,7 @@ import {
2439
2535
  parse as parse2,
2440
2536
  subDays,
2441
2537
  subHours,
2442
- subMonths,
2538
+ subMonths as subMonths2,
2443
2539
  subWeeks,
2444
2540
  subYears
2445
2541
  } from "date-fns";
@@ -2565,7 +2661,7 @@ function parseStartEndDate(operatorLeft, operatorRight, valueLeft, valueRight, u
2565
2661
  leftDate = format3(subYears(currentDate, valueLeft), "yyyy-MM-dd");
2566
2662
  break;
2567
2663
  case "month":
2568
- leftDate = format3(subMonths(currentDate, valueLeft), "yyyy-MM-dd");
2664
+ leftDate = format3(subMonths2(currentDate, valueLeft), "yyyy-MM-dd");
2569
2665
  break;
2570
2666
  case "week":
2571
2667
  leftDate = format3(subWeeks(currentDate, valueLeft), "yyyy-MM-dd");
@@ -2588,7 +2684,7 @@ function parseStartEndDate(operatorLeft, operatorRight, valueLeft, valueRight, u
2588
2684
  rightDate = format3(subYears(currentDate, valueRight), "yyyy-MM-dd");
2589
2685
  break;
2590
2686
  case "month":
2591
- rightDate = format3(subMonths(currentDate, valueRight), "yyyy-MM-dd");
2687
+ rightDate = format3(subMonths2(currentDate, valueRight), "yyyy-MM-dd");
2592
2688
  break;
2593
2689
  case "week":
2594
2690
  rightDate = format3(subWeeks(currentDate, valueRight), "yyyy-MM-dd");
@@ -15372,7 +15468,10 @@ var init_filterProcessing = __esm({
15372
15468
  })
15373
15469
  ).values()
15374
15470
  ],
15375
- options: defaultOptionsV2,
15471
+ options: filter.presetOptions || filter.defaultPresetRanges ? convertPresetOptionsToSelectableList(
15472
+ filter.presetOptions ?? [],
15473
+ filter.defaultPresetRanges ?? []
15474
+ ) : defaultOptionsV2,
15376
15475
  preset: filter.primaryRange,
15377
15476
  dashboardName,
15378
15477
  comparisonRange: filter.comparison && comparisonRangeStart && comparisonRangeEnd ? {
@@ -16261,6 +16360,128 @@ async function generatePivotTable({
16261
16360
  }
16262
16361
  throw Error("Failed to generate pivot table: invalid report");
16263
16362
  }
16363
+ function processPivotData({
16364
+ rows: responseRows,
16365
+ fields: responseFields,
16366
+ pivot,
16367
+ dateBucket,
16368
+ dateFilter,
16369
+ client,
16370
+ rowCount
16371
+ }) {
16372
+ const databaseType = client.databaseType || "postgresql";
16373
+ const rows = pivot.rowField ? responseRows.map(
16374
+ (row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
16375
+ ) : responseRows;
16376
+ if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
16377
+ rows.forEach((row) => {
16378
+ Object.keys(row).forEach((key) => {
16379
+ const processedKey = processColumnName(key);
16380
+ if (processedKey !== key) {
16381
+ row[processedKey] = row[key];
16382
+ delete row[key];
16383
+ }
16384
+ });
16385
+ });
16386
+ }
16387
+ const columns = responseFields?.map((field) => ({
16388
+ field: processColumnName(field.field || field.name),
16389
+ label: snakeCaseToTitleCase(
16390
+ processColumnName(
16391
+ (field.field || field.name).replace("comparison_", "comparison ")
16392
+ )
16393
+ ),
16394
+ format: (field.field || field.name) === pivot.rowField ? "string" : pivot.aggregations?.find(
16395
+ (agg) => agg.valueField === (field.field || field.name) || `${agg.valueField}_percentage` === (field.field || field.name) || !agg.valueField && agg.aggregationType === "percentage" && (field.field || field.name)?.endsWith("percentage")
16396
+ )?.aggregationType === "percentage" ? "percent" : "whole_number",
16397
+ fieldType: field.fieldType,
16398
+ jsType: field.jsType,
16399
+ dataTypeID: field.dataTypeID
16400
+ })).filter(
16401
+ (field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
16402
+ ).sort((a, b) => {
16403
+ if (a.field === pivot.rowField) {
16404
+ return -1;
16405
+ }
16406
+ if (b.field === pivot.rowField) {
16407
+ return 1;
16408
+ }
16409
+ return 0;
16410
+ });
16411
+ if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
16412
+ rows.forEach((row) => {
16413
+ row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16414
+ let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16415
+ if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
16416
+ const rowDate = new Date(value);
16417
+ if (rowDate < dateFilter.startDate) {
16418
+ value = dateFilter.startDate.toISOString();
16419
+ } else if (rowDate > dateFilter.endDate) {
16420
+ value = dateFilter.endDate.toISOString();
16421
+ }
16422
+ }
16423
+ const dateString = getDateString(
16424
+ value,
16425
+ dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
16426
+ dateBucket,
16427
+ databaseType
16428
+ );
16429
+ row[pivot.rowField || ""] = dateString;
16430
+ });
16431
+ if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
16432
+ const dateSet = new Set(
16433
+ rows.map((row) => row[pivot.rowField || ""])
16434
+ );
16435
+ for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
16436
+ const formattedDate = getDateString(
16437
+ date.toISOString(),
16438
+ { start: dateFilter.startDate, end: dateFilter.endDate },
16439
+ dateBucket,
16440
+ databaseType
16441
+ );
16442
+ if (!dateSet.has(formattedDate)) {
16443
+ const newRow = {};
16444
+ newRow[pivot.rowField] = formattedDate;
16445
+ newRow.__quillRawDate = date.toISOString();
16446
+ rows.push(newRow);
16447
+ dateSet.add(formattedDate);
16448
+ }
16449
+ }
16450
+ }
16451
+ if (!pivot.sort || pivot.sortField === pivot.rowField) {
16452
+ rows.sort((a, b) => {
16453
+ const direction = pivot.sort && pivot.sortDirection === "DESC" ? -1 : 1;
16454
+ if (a.__quillRawDate < b.__quillRawDate) {
16455
+ return -1 * direction;
16456
+ }
16457
+ if (a.__quillRawDate > b.__quillRawDate) {
16458
+ return 1 * direction;
16459
+ }
16460
+ return 0;
16461
+ });
16462
+ }
16463
+ }
16464
+ columns?.forEach((column, index) => {
16465
+ if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
16466
+ column.label = "Count";
16467
+ }
16468
+ });
16469
+ const numericColumns = columns?.filter(
16470
+ (column) => column.format === "whole_number" || column.format === "percentage"
16471
+ );
16472
+ rows.forEach((row) => {
16473
+ numericColumns?.forEach((column) => {
16474
+ row[column.field] = row[column.field] ?? 0;
16475
+ });
16476
+ });
16477
+ return {
16478
+ rows,
16479
+ columns: columns ?? [],
16480
+ rowCount: rowCount || rows.length,
16481
+ pivotQuery: "",
16482
+ comparisonPivotQuery: ""
16483
+ };
16484
+ }
16264
16485
  var init_pivotConstructor = __esm({
16265
16486
  "src/utils/pivotConstructor.ts"() {
16266
16487
  "use strict";
@@ -17833,6 +18054,22 @@ var init_tableProcessing = __esm({
17833
18054
  return {};
17834
18055
  }
17835
18056
  let uniqueValuesByColumn = {};
18057
+ const aliasToField = {};
18058
+ const fieldToAlias = {};
18059
+ columns.forEach((col) => {
18060
+ if (col.alias) {
18061
+ aliasToField[col.alias] = col.field;
18062
+ fieldToAlias[col.field] = col.alias;
18063
+ }
18064
+ });
18065
+ reportBuilderState?.columns?.forEach((col) => {
18066
+ if (col.alias) {
18067
+ aliasToField[col.alias] = col.field;
18068
+ if (!fieldToAlias[col.field]) {
18069
+ fieldToAlias[col.field] = col.alias;
18070
+ }
18071
+ }
18072
+ });
17836
18073
  let rows = resp?.rows;
17837
18074
  if (!rows && fetchResult.queries?.queryResults?.[0]?.rows) {
17838
18075
  rows = fetchResult.queries.queryResults[0].rows;
@@ -17841,11 +18078,24 @@ var init_tableProcessing = __esm({
17841
18078
  uniqueValuesByColumn = resp.uniqueValues;
17842
18079
  } else if (rows && Array.isArray(rows)) {
17843
18080
  rows.forEach((row) => {
17844
- if (row.field && row.string_values) {
18081
+ if (row?.field && row?.string_values) {
17845
18082
  uniqueValuesByColumn[row.field] = row.string_values;
17846
18083
  }
17847
18084
  });
17848
18085
  }
18086
+ const normalizedUniqueValuesByColumn = {};
18087
+ Object.entries(uniqueValuesByColumn).forEach(([key, values]) => {
18088
+ if (!Array.isArray(values)) {
18089
+ return;
18090
+ }
18091
+ const fieldKey = aliasToField[key] || key;
18092
+ normalizedUniqueValuesByColumn[fieldKey] = values;
18093
+ const aliasKey = fieldToAlias[fieldKey];
18094
+ if (aliasKey) {
18095
+ normalizedUniqueValuesByColumn[aliasKey] = values;
18096
+ }
18097
+ });
18098
+ uniqueValuesByColumn = normalizedUniqueValuesByColumn;
17849
18099
  const uniqueValues2 = {};
17850
18100
  tables.forEach((tableName) => {
17851
18101
  const tableUniqueValues = {};
@@ -19753,10 +20003,14 @@ async function cleanDashboardItem({
19753
20003
  const pivotChartProcessing = {
19754
20004
  page: DEFAULT_PAGINATION
19755
20005
  };
19756
- pivotTable = await getPivotTable(
19757
- {
19758
- ...item,
19759
- pivot: item.pivot && !skipPivotFetch ? {
20006
+ if (item.pivot && skipPivotFetch && item.rows && item.fields) {
20007
+ const dateFilter = dashboardFilters?.find(
20008
+ (filter) => filter.filterType === "date_range"
20009
+ );
20010
+ pivotTable = processPivotData({
20011
+ rows: item.rows,
20012
+ fields: item.fields,
20013
+ pivot: {
19760
20014
  ...item.pivot,
19761
20015
  aggregations: item.pivot.aggregations ?? [
19762
20016
  {
@@ -19767,18 +20021,40 @@ async function cleanDashboardItem({
19767
20021
  aggregationType: item.pivot.aggregationType
19768
20022
  }
19769
20023
  ]
19770
- } : void 0
19771
- },
19772
- dashboardFilters,
19773
- item.dashboardName,
19774
- getToken,
19775
- client,
19776
- eventTracking,
19777
- dateBucket,
19778
- shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
19779
- tenants,
19780
- customFields
19781
- );
20024
+ },
20025
+ dateBucket,
20026
+ dateFilter,
20027
+ client,
20028
+ rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length
20029
+ });
20030
+ } else {
20031
+ pivotTable = await getPivotTable(
20032
+ {
20033
+ ...item,
20034
+ pivot: item.pivot && !skipPivotFetch ? {
20035
+ ...item.pivot,
20036
+ aggregations: item.pivot.aggregations ?? [
20037
+ {
20038
+ valueField: item.pivot.valueField,
20039
+ valueFieldType: item.pivot.valueFieldType,
20040
+ valueField2: item.pivot.valueField2,
20041
+ valueField2Type: item.pivot.valueField2Type,
20042
+ aggregationType: item.pivot.aggregationType
20043
+ }
20044
+ ]
20045
+ } : void 0
20046
+ },
20047
+ dashboardFilters,
20048
+ item.dashboardName,
20049
+ getToken,
20050
+ client,
20051
+ eventTracking,
20052
+ dateBucket,
20053
+ shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
20054
+ tenants,
20055
+ customFields
20056
+ );
20057
+ }
19782
20058
  } catch (e) {
19783
20059
  pivotTable = void 0;
19784
20060
  eventTracking?.logError?.({
@@ -20186,6 +20462,44 @@ function extractAllReportValuesFromQuillInternalReport(reportInternal) {
20186
20462
  pivotRowCount: reportInternal.pivotRowCount
20187
20463
  };
20188
20464
  }
20465
+ async function fetchReportRows({
20466
+ reportId,
20467
+ client,
20468
+ tenants,
20469
+ filters = [],
20470
+ getToken,
20471
+ abortSignal,
20472
+ additionalProcessing
20473
+ }) {
20474
+ const fetchResp = await quillFetch({
20475
+ client,
20476
+ task: "report",
20477
+ metadata: {
20478
+ reportId,
20479
+ clientId: client.publicKey,
20480
+ databaseType: client.databaseType,
20481
+ filters: filters.map((filter) => ({ ...filter, options: void 0 })),
20482
+ useNewNodeSql: true,
20483
+ tenants,
20484
+ additionalProcessing
20485
+ },
20486
+ abortSignal,
20487
+ getToken
20488
+ });
20489
+ const resp = await parseFetchResponse(client, "report", fetchResp, getToken);
20490
+ if (client.databaseType?.toLowerCase() === "bigquery") {
20491
+ parseValueFromBigQueryDates(resp.rows, resp.fields);
20492
+ }
20493
+ const columns = (resp.fields || []).map(
20494
+ (field) => convertPostgresColumn(field)
20495
+ );
20496
+ return {
20497
+ rows: resp.rows || [],
20498
+ rowCount: resp.rowCount || 0,
20499
+ columns,
20500
+ fields: resp.fields || []
20501
+ };
20502
+ }
20189
20503
  async function fetchReport({
20190
20504
  reportId,
20191
20505
  client,
@@ -20200,14 +20514,15 @@ async function fetchReport({
20200
20514
  rowCountOnly,
20201
20515
  abortSignal,
20202
20516
  getToken,
20203
- eventTracking
20517
+ eventTracking,
20518
+ usePivotTask = false
20204
20519
  }) {
20205
20520
  let reportInfo = void 0;
20206
20521
  let errorMessage = void 0;
20207
20522
  try {
20208
20523
  const fetchResp = await quillFetch({
20209
20524
  client,
20210
- task: useReportTask ? "report" : "item",
20525
+ task: usePivotTask ? "pivot-template" : useReportTask ? "report" : "item",
20211
20526
  metadata: {
20212
20527
  reportId,
20213
20528
  dashboardItemId: reportId,
@@ -20227,7 +20542,7 @@ async function fetchReport({
20227
20542
  });
20228
20543
  const resp = await parseFetchResponse(
20229
20544
  client,
20230
- useReportTask ? "report" : "item",
20545
+ usePivotTask ? "pivot-template" : useReportTask ? "report" : "item",
20231
20546
  fetchResp,
20232
20547
  getToken
20233
20548
  );
@@ -20235,12 +20550,13 @@ async function fetchReport({
20235
20550
  resp,
20236
20551
  client,
20237
20552
  filters,
20238
- dateBucket,
20553
+ dateBucket: resp.dateBucket ?? dateBucket,
20239
20554
  additionalProcessing,
20240
20555
  customFields,
20241
20556
  getToken,
20242
20557
  eventTracking,
20243
- tenants
20558
+ tenants,
20559
+ skipPivotFetch: usePivotTask
20244
20560
  });
20245
20561
  } catch (error) {
20246
20562
  if (error instanceof Error && error.name === "AbortError") {
@@ -20289,8 +20605,10 @@ async function processReportResponse({
20289
20605
  customFields,
20290
20606
  getToken,
20291
20607
  eventTracking,
20292
- tenants
20608
+ tenants,
20609
+ skipPivotFetch = false
20293
20610
  }) {
20611
+ const shouldSkipPivotFetch = skipPivotFetch || !!resp?.pivotRows && !!resp?.fields;
20294
20612
  const dashboardItem = {
20295
20613
  ...resp,
20296
20614
  filtersApplied: filters?.filter(
@@ -20320,7 +20638,8 @@ async function processReportResponse({
20320
20638
  customFields,
20321
20639
  getToken,
20322
20640
  tenants,
20323
- eventTracking
20641
+ eventTracking,
20642
+ skipPivotFetch: shouldSkipPivotFetch
20324
20643
  });
20325
20644
  if (additionalProcessing) {
20326
20645
  reportInfo.pagination = additionalProcessing.page;
@@ -22349,6 +22668,34 @@ var ContextProvider = ({
22349
22668
  );
22350
22669
  if (currentProcessId === loadDashboardProcessId.current[dashboardName]) {
22351
22670
  if (!equal(resp, curDashboardConfig)) {
22671
+ Object.values(
22672
+ resp.sections ?? {}
22673
+ ).flat().forEach((report) => {
22674
+ const existing = reports[report.id];
22675
+ if (existing) {
22676
+ const merged = {
22677
+ ...report,
22678
+ // prefer fresh server metadata (chartType, flags, etc.)
22679
+ // preserve existing row payload if server response is metadata-only
22680
+ ...existing.rows ? { rows: existing.rows } : {},
22681
+ ...existing.rowCount !== void 0 ? { rowCount: existing.rowCount } : {},
22682
+ ...existing.columns ? { columns: existing.columns } : {},
22683
+ ...existing.columnInternal ? { columnInternal: existing.columnInternal } : {},
22684
+ ...existing.pagination ? { pagination: existing.pagination } : {}
22685
+ };
22686
+ reportsDispatch({
22687
+ type: "UPDATE_REPORT",
22688
+ id: report.id,
22689
+ data: merged
22690
+ });
22691
+ } else {
22692
+ reportsDispatch({
22693
+ type: "ADD_REPORT",
22694
+ id: report.id,
22695
+ data: report
22696
+ });
22697
+ }
22698
+ });
22352
22699
  dashboardConfigDispatch({
22353
22700
  type: "UPDATE_DASHBOARD",
22354
22701
  id: dashboardName,
@@ -23022,7 +23369,7 @@ init_columnType();
23022
23369
  import {
23023
23370
  add,
23024
23371
  startOfDay as startOfDay3,
23025
- startOfMonth,
23372
+ startOfMonth as startOfMonth2,
23026
23373
  startOfWeek as startOfWeek3,
23027
23374
  startOfYear
23028
23375
  } from "date-fns";
@@ -23170,11 +23517,12 @@ var useDashboardInternal = (dashboardName, customFilters) => {
23170
23517
  dashboardName,
23171
23518
  sectionOrder
23172
23519
  };
23173
- void quillFetchWithToken({
23174
- client,
23175
- task: "set-section-order",
23176
- metadata: body
23177
- }).then((response) => {
23520
+ try {
23521
+ const response = await quillFetchWithToken({
23522
+ client,
23523
+ task: "set-section-order",
23524
+ metadata: body
23525
+ });
23178
23526
  Object.entries(response?.data?.newIds ?? {}).forEach(
23179
23527
  ([section, newId2]) => {
23180
23528
  dashboardConfigDispatch({
@@ -23196,11 +23544,24 @@ var useDashboardInternal = (dashboardName, customFilters) => {
23196
23544
  });
23197
23545
  }
23198
23546
  );
23199
- }).catch((error) => {
23200
- if (error instanceof Error && error.name === "AbortError") {
23547
+ } catch (e) {
23548
+ if (e instanceof Error && e.name === "AbortError") {
23201
23549
  return;
23202
23550
  }
23203
- });
23551
+ eventTracking?.logError?.({
23552
+ type: "bug",
23553
+ // TODO: determine type
23554
+ severity: "high",
23555
+ message: "Error setting section order",
23556
+ errorMessage: e?.message,
23557
+ errorStack: e?.stack,
23558
+ errorData: {
23559
+ caller: "useDashboard",
23560
+ function: "setSectionOrder"
23561
+ }
23562
+ });
23563
+ console.error(e);
23564
+ }
23204
23565
  }
23205
23566
  };
23206
23567
  function isDashboardFilterLoading(filterName) {
@@ -23458,7 +23819,8 @@ var useDashboards = () => {
23458
23819
  (preset) => ({
23459
23820
  ...preset,
23460
23821
  loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
23461
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
23822
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0,
23823
+ customLabel: preset.customLabel
23462
23824
  })
23463
23825
  )
23464
23826
  } : void 0,
@@ -23518,7 +23880,8 @@ var useDashboards = () => {
23518
23880
  (preset) => ({
23519
23881
  ...preset,
23520
23882
  loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
23521
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
23883
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0,
23884
+ customLabel: preset.customLabel
23522
23885
  })
23523
23886
  ),
23524
23887
  dashboardName: updated.data.dashboard.name,
@@ -23636,6 +23999,7 @@ var useDashboard = (dashboardName, config) => {
23636
23999
  const { customReportFilters } = useContext(ReportFiltersContext);
23637
24000
  const { eventTracking } = useContext(EventTrackingContext);
23638
24001
  const customFiltersRef = useRef2(customReportFilters);
24002
+ const reportRequestIds = useRef2({});
23639
24003
  useEffect2(() => {
23640
24004
  customFiltersRef.current = customReportFilters;
23641
24005
  }, [customReportFilters]);
@@ -23778,6 +24142,8 @@ var useDashboard = (dashboardName, config) => {
23778
24142
  await Promise.all(
23779
24143
  allReports.map(async (reportInfo) => {
23780
24144
  const reportId = reportInfo.id;
24145
+ const requestId = (reportRequestIds.current[reportId] ?? 0) + 1;
24146
+ reportRequestIds.current[reportId] = requestId;
23781
24147
  reportsLoadingStateDispatch({
23782
24148
  type: "SET_REPORT_LOADING",
23783
24149
  id: reportId,
@@ -23795,6 +24161,7 @@ var useDashboard = (dashboardName, config) => {
23795
24161
  const additionalProcessing = {
23796
24162
  page: pagination
23797
24163
  };
24164
+ const usePivotTask = !!reportInfo.pivot;
23798
24165
  const { report, error } = await fetchReport({
23799
24166
  reportId,
23800
24167
  client,
@@ -23803,12 +24170,16 @@ var useDashboard = (dashboardName, config) => {
23803
24170
  additionalProcessing,
23804
24171
  filters: dashboardFilters2.concat(customFilters).concat(customReportFiltersArray),
23805
24172
  getToken,
23806
- eventTracking
24173
+ eventTracking,
24174
+ usePivotTask
23807
24175
  });
23808
24176
  if (error) {
23809
24177
  console.error(error);
23810
24178
  return null;
23811
24179
  }
24180
+ if (reportRequestIds.current[reportId] !== requestId) {
24181
+ return null;
24182
+ }
23812
24183
  reportsDispatch({
23813
24184
  type: "UPDATE_REPORT",
23814
24185
  id: reportId,
@@ -23822,6 +24193,40 @@ var useDashboard = (dashboardName, config) => {
23822
24193
  id: reportId,
23823
24194
  data: false
23824
24195
  });
24196
+ if (usePivotTask) {
24197
+ fetchReportRows({
24198
+ reportId,
24199
+ client,
24200
+ tenants,
24201
+ filters: dashboardFilters2.concat(customFilters).concat(customReportFiltersArray),
24202
+ getToken,
24203
+ additionalProcessing
24204
+ }).then(({ rows, rowCount, columns, fields }) => {
24205
+ if (reportRequestIds.current[reportId] !== requestId) {
24206
+ return;
24207
+ }
24208
+ reportsDispatch({
24209
+ type: "UPDATE_REPORT",
24210
+ id: reportId,
24211
+ data: {
24212
+ rows,
24213
+ rowCount,
24214
+ columnInternal: columns,
24215
+ columns: columns.map((col) => ({
24216
+ field: col.field,
24217
+ format: col.format,
24218
+ label: col.label,
24219
+ inferFormat: col.inferFormat
24220
+ })),
24221
+ // @ts-ignore fields is not typed on QuillReportInternal
24222
+ fields
24223
+ }
24224
+ });
24225
+ }).catch((e) => {
24226
+ if (e instanceof Error && e.name === "AbortError") return;
24227
+ console.error("Failed to fetch background rows", e);
24228
+ });
24229
+ }
23825
24230
  return report;
23826
24231
  })
23827
24232
  );
@@ -28143,6 +28548,8 @@ var axisFormatter = ({ value, field, fields }) => {
28143
28548
  return formatPercent2(value);
28144
28549
  case "dollar_amount":
28145
28550
  return formatDollarAmount2(value);
28551
+ case "dollar_cents":
28552
+ return formatDollarCents2(value);
28146
28553
  case "whole_number":
28147
28554
  return formatWholeNumber2(value);
28148
28555
  case "two_decimal_places":
@@ -28207,6 +28614,12 @@ var formatterDollar2 = new Intl.NumberFormat("en-US", {
28207
28614
  currency: "USD",
28208
28615
  maximumFractionDigits: 0
28209
28616
  });
28617
+ var formatterDollarCents = new Intl.NumberFormat("en-US", {
28618
+ style: "currency",
28619
+ currency: "USD",
28620
+ minimumFractionDigits: 2,
28621
+ maximumFractionDigits: 2
28622
+ });
28210
28623
  var formatDollarAmount2 = (value) => {
28211
28624
  const num = Number(value ?? 0);
28212
28625
  if (num >= 1e3 || num === 0) {
@@ -28215,6 +28628,9 @@ var formatDollarAmount2 = (value) => {
28215
28628
  return formatterDollar2.format(num);
28216
28629
  }
28217
28630
  };
28631
+ var formatDollarCents2 = (value) => {
28632
+ return formatterDollarCents.format(Number(value ?? 0));
28633
+ };
28218
28634
  var formatterBigWholeNumber = new Intl.NumberFormat("en-US", {
28219
28635
  minimumSignificantDigits: 1,
28220
28636
  maximumSignificantDigits: 2,
@@ -29630,11 +30046,11 @@ import {
29630
30046
  useState as useState11
29631
30047
  } from "react";
29632
30048
  import {
29633
- startOfMonth as startOfMonth2,
29634
- endOfMonth,
30049
+ startOfMonth as startOfMonth3,
30050
+ endOfMonth as endOfMonth2,
29635
30051
  format as format7,
29636
30052
  eachDayOfInterval,
29637
- subMonths as subMonths2,
30053
+ subMonths as subMonths3,
29638
30054
  startOfWeek as startOfWeek5,
29639
30055
  endOfWeek as endOfWeek3,
29640
30056
  differenceInDays as differenceInDays3,
@@ -30159,19 +30575,19 @@ function CalendarRow({
30159
30575
  }) {
30160
30576
  const firstMonthDisplayedDates = eachDayOfInterval({
30161
30577
  start: startOfWeek5(anchorStartDate),
30162
- end: endOfWeek3(endOfMonth(anchorStartDate))
30578
+ end: endOfWeek3(endOfMonth2(anchorStartDate))
30163
30579
  });
30164
30580
  const secondMonthDisplayedDates = eachDayOfInterval({
30165
- start: startOfWeek5(startOfMonth2(anchorEndDate)),
30581
+ start: startOfWeek5(startOfMonth3(anchorEndDate)),
30166
30582
  end: endOfWeek3(anchorEndDate)
30167
30583
  });
30168
30584
  const incrementAnchorDates = () => {
30169
- setAnchorStartDate(startOfMonth2(addMonths(anchorStartDate, 1)));
30170
- setAnchorEndDate(endOfMonth(addMonths(anchorEndDate, 1)));
30585
+ setAnchorStartDate(startOfMonth3(addMonths(anchorStartDate, 1)));
30586
+ setAnchorEndDate(endOfMonth2(addMonths(anchorEndDate, 1)));
30171
30587
  };
30172
30588
  const decrementAnchorDates = () => {
30173
- setAnchorStartDate(startOfMonth2(subMonths2(anchorStartDate, 1)));
30174
- setAnchorEndDate(endOfMonth(subMonths2(anchorEndDate, 1)));
30589
+ setAnchorStartDate(startOfMonth3(subMonths3(anchorStartDate, 1)));
30590
+ setAnchorEndDate(endOfMonth2(subMonths3(anchorEndDate, 1)));
30175
30591
  };
30176
30592
  return /* @__PURE__ */ jsx39("div", { style: { position: "absolute", zIndex: 100, marginTop: 12 }, children: /* @__PURE__ */ jsxs29(
30177
30593
  "div",
@@ -30488,31 +30904,31 @@ function DayPicker({
30488
30904
  }
30489
30905
  function getAnchorStartDate(startDate, endDate) {
30490
30906
  if (!startDate && !endDate) {
30491
- return startOfMonth2(subMonths2(/* @__PURE__ */ new Date(), 1));
30907
+ return startOfMonth3(subMonths3(/* @__PURE__ */ new Date(), 1));
30492
30908
  }
30493
30909
  if (startDate && !endDate) {
30494
- return startOfMonth2(startDate);
30910
+ return startOfMonth3(startDate);
30495
30911
  }
30496
30912
  if (!startDate && endDate) {
30497
- return startOfMonth2(subMonths2(endDate, 1));
30913
+ return startOfMonth3(subMonths3(endDate, 1));
30498
30914
  }
30499
30915
  if (startDate && endDate) {
30500
- return startOfMonth2(startDate);
30916
+ return startOfMonth3(startDate);
30501
30917
  }
30502
30918
  return /* @__PURE__ */ new Date();
30503
30919
  }
30504
30920
  function getAnchorEndDate(startDate, endDate) {
30505
30921
  if (!startDate && !endDate) {
30506
- return endOfMonth(/* @__PURE__ */ new Date());
30922
+ return endOfMonth2(/* @__PURE__ */ new Date());
30507
30923
  }
30508
30924
  if (startDate && !endDate) {
30509
- return endOfMonth(addMonths(startDate, 1));
30925
+ return endOfMonth2(addMonths(startDate, 1));
30510
30926
  }
30511
30927
  if (!startDate && endDate) {
30512
- return endOfMonth(endDate);
30928
+ return endOfMonth2(endDate);
30513
30929
  }
30514
30930
  if (startDate && endDate) {
30515
- return endOfMonth(addMonths(startDate, 1));
30931
+ return endOfMonth2(addMonths(startDate, 1));
30516
30932
  }
30517
30933
  return /* @__PURE__ */ new Date();
30518
30934
  }
@@ -32333,6 +32749,8 @@ function DataLoader({
32333
32749
  previousUserFilters.current = userFilters;
32334
32750
  rowsAbortController.current?.abort();
32335
32751
  rowsAbortController.current = new AbortController();
32752
+ const usePivotTask = !!item.pivot;
32753
+ let backgroundFetch = null;
32336
32754
  try {
32337
32755
  if (dashboardName) {
32338
32756
  const { report: fetchedReport, error: error2 } = await fetchReport({
@@ -32348,18 +32766,62 @@ function DataLoader({
32348
32766
  rowCountOnly: false,
32349
32767
  abortSignal: rowsAbortController.current.signal,
32350
32768
  getToken,
32351
- eventTracking
32769
+ eventTracking,
32770
+ usePivotTask
32352
32771
  });
32772
+ const existingReport = dashboard[item.id] ?? reports[item.id];
32773
+ const baseReport = error2 && existingReport ? { ...existingReport, error: error2 } : fetchedReport;
32774
+ const reportToAdd = {
32775
+ ...baseReport,
32776
+ rows: baseReport?.rows ?? [],
32777
+ columns: baseReport?.columns ?? [],
32778
+ columnInternal: baseReport?.columnInternal ?? []
32779
+ };
32353
32780
  addReport({
32354
- ...fetchedReport,
32781
+ ...reportToAdd,
32355
32782
  id: item.id,
32356
32783
  triggerReload: false,
32357
- rowCount: fetchedReport.pivot ? fetchedReport.rowCount : 0,
32784
+ rowCount: reportToAdd.pivot ? reportToAdd.rowCount : 0,
32358
32785
  filtersApplied: userFilters,
32359
32786
  loadingRows: false
32360
32787
  // rowCount 0 indicates it's still loading if row length is nonzero
32361
32788
  });
32362
32789
  setError(error2);
32790
+ if (usePivotTask) {
32791
+ const backgroundAbortController = new AbortController();
32792
+ backgroundFetch = () => {
32793
+ fetchReportRows({
32794
+ reportId: item.id,
32795
+ client,
32796
+ tenants,
32797
+ filters: filters.concat(userFilters ?? []),
32798
+ getToken,
32799
+ abortSignal: backgroundAbortController.signal,
32800
+ additionalProcessing: {
32801
+ ...processing,
32802
+ ...{ page: DEFAULT_PAGINATION }
32803
+ }
32804
+ }).then(({ rows, rowCount, columns, fields }) => {
32805
+ updateReport({
32806
+ id: item.id,
32807
+ rows,
32808
+ rowCount,
32809
+ columnInternal: columns,
32810
+ columns: columns.map((col) => ({
32811
+ field: col.field,
32812
+ format: col.format,
32813
+ label: col.label,
32814
+ inferFormat: col.inferFormat
32815
+ })),
32816
+ // @ts-ignore
32817
+ fields
32818
+ });
32819
+ }).catch((e) => {
32820
+ if (e instanceof Error && e.name === "AbortError") return;
32821
+ console.error("Failed to fetch background rows", e);
32822
+ });
32823
+ };
32824
+ }
32363
32825
  } else {
32364
32826
  try {
32365
32827
  await fetchIndividualReport({
@@ -32416,6 +32878,9 @@ function DataLoader({
32416
32878
  if (fetchRowsRequestId === rowsRequestId.current) {
32417
32879
  rowsAbortController.current = null;
32418
32880
  setLoading(false);
32881
+ if (backgroundFetch) {
32882
+ backgroundFetch();
32883
+ }
32419
32884
  }
32420
32885
  }
32421
32886
  };
@@ -32480,7 +32945,11 @@ var ChartDataLoader = ({
32480
32945
  dashboardName,
32481
32946
  propagateChanges
32482
32947
  }) => {
32483
- const { dashboardReports: dashboard, addReport } = useDashboardReports(dashboardName);
32948
+ const {
32949
+ dashboardReports: dashboard,
32950
+ addReport,
32951
+ updateReport
32952
+ } = useDashboardReports(dashboardName);
32484
32953
  const { dashboardFilters } = useContext13(DashboardFiltersContext);
32485
32954
  const { reports, fetchIndividualReport } = useContext13(ReportsContext);
32486
32955
  const { getToken } = useContext13(FetchContext);
@@ -32530,6 +32999,8 @@ var ChartDataLoader = ({
32530
32999
  setLoading(true);
32531
33000
  fetchReportAbortController.current?.abort();
32532
33001
  fetchReportAbortController.current = new AbortController();
33002
+ const usePivotTask = !!item.pivot;
33003
+ let backgroundFetch = null;
32533
33004
  try {
32534
33005
  if (dashboardName) {
32535
33006
  const { report, error: error2 } = await fetchReport({
@@ -32547,16 +33018,60 @@ var ChartDataLoader = ({
32547
33018
  customFields: schemaData.customFields,
32548
33019
  abortSignal: fetchReportAbortController.current.signal,
32549
33020
  getToken,
32550
- eventTracking
33021
+ eventTracking,
33022
+ usePivotTask
32551
33023
  });
33024
+ const existingReport = dashboard[item.id] ?? reports[item.id];
33025
+ const baseReport = error2 && existingReport ? { ...existingReport, error: error2 } : report;
33026
+ const reportToAdd = {
33027
+ ...baseReport,
33028
+ rows: baseReport?.rows ?? [],
33029
+ columns: baseReport?.columns ?? [],
33030
+ columnInternal: baseReport?.columnInternal ?? []
33031
+ };
32552
33032
  addReport({
32553
- ...report,
33033
+ ...reportToAdd,
32554
33034
  id: item.id,
32555
33035
  triggerReload: false,
32556
33036
  filtersApplied: userFilters,
32557
33037
  loadingRows: false
32558
33038
  });
32559
33039
  setError(error2);
33040
+ if (usePivotTask) {
33041
+ const backgroundAbortController = new AbortController();
33042
+ backgroundFetch = () => {
33043
+ fetchReportRows({
33044
+ reportId: item.id,
33045
+ client,
33046
+ tenants,
33047
+ filters: filters.concat(userFilters ?? []),
33048
+ getToken,
33049
+ abortSignal: backgroundAbortController.signal,
33050
+ additionalProcessing: {
33051
+ ...additionalProcessing,
33052
+ ...{ page: DEFAULT_PAGINATION }
33053
+ }
33054
+ }).then(({ rows, rowCount, columns, fields }) => {
33055
+ updateReport({
33056
+ id: item.id,
33057
+ rows,
33058
+ rowCount,
33059
+ columnInternal: columns,
33060
+ columns: columns.map((col) => ({
33061
+ field: col.field,
33062
+ format: col.format,
33063
+ label: col.label,
33064
+ inferFormat: col.inferFormat
33065
+ })),
33066
+ // @ts-ignore
33067
+ fields
33068
+ });
33069
+ }).catch((e) => {
33070
+ if (e instanceof Error && e.name === "AbortError") return;
33071
+ console.error("Failed to fetch background rows", e);
33072
+ });
33073
+ };
33074
+ }
32560
33075
  } else {
32561
33076
  try {
32562
33077
  await fetchIndividualReport({
@@ -32612,6 +33127,9 @@ var ChartDataLoader = ({
32612
33127
  if (fetchRowsRequestId === rowsRequestId.current) {
32613
33128
  fetchReportAbortController.current = null;
32614
33129
  setLoading(false);
33130
+ if (backgroundFetch) {
33131
+ backgroundFetch();
33132
+ }
32615
33133
  }
32616
33134
  }
32617
33135
  };
@@ -38789,7 +39307,7 @@ function Dashboard({
38789
39307
  filters: populatedDashboardFilters ?? [],
38790
39308
  userFilters: dataLoaderUserFilters,
38791
39309
  additionalProcessing: {
38792
- page: DEFAULT_PAGINATION,
39310
+ page: pagination,
38793
39311
  last: additionalProcessing?.last
38794
39312
  },
38795
39313
  dashboardName: name2,
@@ -41129,7 +41647,7 @@ var PivotModal = ({
41129
41647
  });
41130
41648
  }
41131
41649
  },
41132
- options: (samplePivotTable?.columns ?? []).map((column) => ({
41650
+ options: (samplePivotTable?.columns && samplePivotTable.columns.length > 0 ? samplePivotTable.columns : pivotRowField ? [{ field: pivotRowField }] : []).map((column) => ({
41133
41651
  label: snakeAndCamelCaseToTitleCase(
41134
41652
  column.field
41135
41653
  ),
@@ -41549,6 +42067,7 @@ init_Filter();
41549
42067
  init_filterProcessing();
41550
42068
  init_dateRangePickerUtils();
41551
42069
  import { Fragment as Fragment11, jsx as jsx63, jsxs as jsxs45 } from "react/jsx-runtime";
42070
+ var MULTISELECT_REQUEST_DEBOUNCE_MS = 1e3;
41552
42071
  var TogglePrimitive = ({
41553
42072
  value,
41554
42073
  onClick,
@@ -41688,6 +42207,20 @@ function InternalChart({
41688
42207
  ) : defaultOptionsV2;
41689
42208
  }, [reportDateFilter]);
41690
42209
  const [filterValues, setFilterValues] = useState27({});
42210
+ const multiselectDebounceRef = useRef16({});
42211
+ const latestMultiselectValueRef = useRef16({});
42212
+ const [lockedFilters, setLockedFilters] = useState27(
42213
+ {}
42214
+ );
42215
+ useEffect22(() => {
42216
+ return () => {
42217
+ Object.values(multiselectDebounceRef.current).forEach((timer2) => {
42218
+ if (timer2) {
42219
+ clearTimeout(timer2);
42220
+ }
42221
+ });
42222
+ };
42223
+ }, []);
41691
42224
  useEffect22(() => {
41692
42225
  if (reportDateFilter) {
41693
42226
  const customDateFilter = filters?.find(
@@ -41794,6 +42327,46 @@ function InternalChart({
41794
42327
  ...filterValues2,
41795
42328
  [filter.label]: filterValue
41796
42329
  }));
42330
+ if (filter.filterType === "string" /* String */ && filter.stringFilterType === "multiselect") {
42331
+ latestMultiselectValueRef.current[filter.label] = filterValue;
42332
+ const existingTimer = multiselectDebounceRef.current[filter.label];
42333
+ if (existingTimer) {
42334
+ clearTimeout(existingTimer);
42335
+ }
42336
+ multiselectDebounceRef.current[filter.label] = setTimeout(() => {
42337
+ multiselectDebounceRef.current[filter.label] = void 0;
42338
+ setLockedFilters((prev) => ({
42339
+ ...prev,
42340
+ [filter.label]: true
42341
+ }));
42342
+ try {
42343
+ const maybePromise = onDashboardFilterChange(
42344
+ filter.label,
42345
+ latestMultiselectValueRef.current[filter.label]
42346
+ );
42347
+ if (maybePromise && typeof maybePromise.finally === "function") {
42348
+ maybePromise.finally(() => {
42349
+ setLockedFilters((prev) => ({
42350
+ ...prev,
42351
+ [filter.label]: false
42352
+ }));
42353
+ });
42354
+ } else {
42355
+ setLockedFilters((prev) => ({
42356
+ ...prev,
42357
+ [filter.label]: false
42358
+ }));
42359
+ }
42360
+ } catch (e) {
42361
+ setLockedFilters((prev) => ({
42362
+ ...prev,
42363
+ [filter.label]: false
42364
+ }));
42365
+ throw e;
42366
+ }
42367
+ }, MULTISELECT_REQUEST_DEBOUNCE_MS);
42368
+ return;
42369
+ }
41797
42370
  onDashboardFilterChange(filter.label, filterValue);
41798
42371
  };
41799
42372
  const [filtersExpanded, setFiltersExpanded] = useState27(false);
@@ -41951,7 +42524,7 @@ function InternalChart({
41951
42524
  SelectComponent,
41952
42525
  MultiSelectComponent,
41953
42526
  DateRangePickerComponent,
41954
- disabled: !filtersEnabled,
42527
+ disabled: !filtersEnabled || lockedFilters[filter.filter.label],
41955
42528
  containerStyle: {
41956
42529
  // display: !filtersExpanded && visibleFilters[index] ? 'none' : 'inline',
41957
42530
  visibility: !filtersExpanded && visibleFilters[index] ? "hidden" : "visible"
@@ -43817,6 +44390,7 @@ function ChartBuilder({
43817
44390
  client,
43818
44391
  uniqueValues,
43819
44392
  dashboardName: destinationDashboardName,
44393
+ dashboardFilters: dashboardFilters2,
43820
44394
  tenants,
43821
44395
  additionalProcessing: baseProcessing,
43822
44396
  getToken,
@@ -43928,7 +44502,7 @@ function ChartBuilder({
43928
44502
  }
43929
44503
  return filter;
43930
44504
  });
43931
- loadFiltersForReport(
44505
+ return loadFiltersForReport(
43932
44506
  report?.id ?? TEMP_REPORT_ID,
43933
44507
  "ChartBuilder",
43934
44508
  updatedFilters,
@@ -43938,7 +44512,7 @@ function ChartBuilder({
43938
44512
  ).then(() => {
43939
44513
  setCurrentPage(0);
43940
44514
  setMaxPage(0);
43941
- handleRunQuery(baseProcessing, updatedFilters);
44515
+ return handleRunQuery(baseProcessing, updatedFilters);
43942
44516
  });
43943
44517
  };
43944
44518
  const filtersEnabledRef = useRef18(filtersEnabled);
@@ -44497,12 +45071,21 @@ function ChartBuilder({
44497
45071
  error: void 0,
44498
45072
  section: formData.section
44499
45073
  };
44500
- addReport(data);
44501
- reportsDispatch({
44502
- type: "ADD_REPORT",
44503
- id: resp.id,
44504
- data
44505
- });
45074
+ const reportFlags = data.flags;
45075
+ const hasRestrictedFlags = reportFlags && Object.values(reportFlags).some(
45076
+ (v) => Array.isArray(v) && v.length > 0
45077
+ );
45078
+ const currentTenantCanSee = !hasRestrictedFlags || flags && Object.values(reportFlags).some(
45079
+ (v) => v === "QUILL_ALL_TENANTS" || Array.isArray(v) && v.some((f) => flags.includes(f))
45080
+ );
45081
+ if (currentTenantCanSee) {
45082
+ addReport(data);
45083
+ reportsDispatch({
45084
+ type: "ADD_REPORT",
45085
+ id: resp.id,
45086
+ data
45087
+ });
45088
+ }
44506
45089
  if (onAddToDashboardComplete) {
44507
45090
  onAddToDashboardComplete(data);
44508
45091
  } else {
@@ -48924,6 +49507,14 @@ var useReportBuilderInternal = ({
48924
49507
  report,
48925
49508
  skipPivotColumnFetch
48926
49509
  }) => {
49510
+ const tablesEqual = (a, b) => {
49511
+ if (a.length !== b.length) return false;
49512
+ const aNames = a.map((t) => t.name).sort();
49513
+ const bNames = b.map((t) => t.name).sort();
49514
+ return aNames.every((name2, idx) => name2 === bNames[idx]);
49515
+ };
49516
+ const haveTablesChanged = tablesChanged ?? !tablesEqual(state.tables, tables);
49517
+ const needsFilteredUniqueValues = !!filtersChanged || !!limitChanged || haveTablesChanged;
48927
49518
  if (!client) {
48928
49519
  return;
48929
49520
  }
@@ -48931,8 +49522,8 @@ var useReportBuilderInternal = ({
48931
49522
  state,
48932
49523
  pivot: state.pivot,
48933
49524
  previousReport: report,
48934
- requiresNewFilteredUniqueValues: filtersChanged || limitChanged,
48935
- requiresNewUnfilteredUniqueValues: tablesChanged,
49525
+ requiresNewFilteredUniqueValues: needsFilteredUniqueValues,
49526
+ requiresNewUnfilteredUniqueValues: haveTablesChanged,
48936
49527
  skipPivotColumnFetch
48937
49528
  });
48938
49529
  };
@@ -49543,18 +50134,10 @@ var useReportBuilderInternal = ({
49543
50134
  }, [client]);
49544
50135
  useEffect26(() => {
49545
50136
  const loadChart = async () => {
49546
- let report;
49547
- if (!client) {
49548
- return;
49549
- }
50137
+ if (!client || !reportId) return;
50138
+ const report = allReportsById[reportId];
50139
+ if (!report) return;
49550
50140
  try {
49551
- if (!reportId) {
49552
- throw new Error("Report ID is required");
49553
- }
49554
- report = allReportsById[reportId];
49555
- if (!report) {
49556
- throw new Error("Report not found");
49557
- }
49558
50141
  const { ast: newAst, pivot: newPivot } = await fetchASTFromQuillReport(
49559
50142
  report,
49560
50143
  client,
@@ -52879,15 +53462,20 @@ function ChartEditor({
52879
53462
  const parentRef = useRef22(null);
52880
53463
  const [modalWidth, setModalWidth] = useState38(200);
52881
53464
  const [modalHeight, setModalHeight] = useState38(200);
52882
- const { addReport } = useDashboardReports(destinationDashboard);
52883
53465
  const { allReportsById } = useAllReports();
53466
+ const report = allReportsById[reportId];
53467
+ const resolvedDashboard = useMemo26(
53468
+ () => destinationDashboard ?? report?.dashboardName ?? null,
53469
+ [destinationDashboard, report?.dashboardName]
53470
+ );
53471
+ const { addReport } = useDashboardReports(resolvedDashboard ?? void 0);
52884
53472
  const { tenants, flags } = useContext33(TenantContext);
52885
53473
  const { getToken } = useContext33(FetchContext);
52886
- const report = allReportsById[reportId];
52887
53474
  const [client, isClientLoading] = useContext33(ClientContext);
52888
53475
  const [schemaData] = useContext33(SchemaDataContext);
52889
53476
  const { dashboardFilters } = useContext33(DashboardFiltersContext);
52890
53477
  const { eventTracking } = useContext33(EventTrackingContext);
53478
+ const { reload } = useDashboardInternal(resolvedDashboard);
52891
53479
  const specificDashboardFilters = useMemo26(() => {
52892
53480
  if (!report) {
52893
53481
  return [];
@@ -52895,7 +53483,7 @@ function ChartEditor({
52895
53483
  return Object.values(dashboardFilters[report.dashboardName] || {}).map(
52896
53484
  (f) => f.filter
52897
53485
  );
52898
- }, [dashboardFilters]);
53486
+ }, [dashboardFilters, report?.dashboardName]);
52899
53487
  const [filtersEnabled, setFiltersEnabled] = useState38(true);
52900
53488
  const [chartBuilderKey, setChartBuilderKey] = useState38(0);
52901
53489
  const dateFilter = Object.values(specificDashboardFilters).find(
@@ -52921,7 +53509,7 @@ function ChartEditor({
52921
53509
  };
52922
53510
  }, []);
52923
53511
  const fetchReportHelper = async (processing) => {
52924
- if (!client) {
53512
+ if (!client || !reportId) {
52925
53513
  return;
52926
53514
  }
52927
53515
  const minimalFilters = Object.values(specificDashboardFilters).length ? Object.values(specificDashboardFilters).map((filter) => {
@@ -52953,10 +53541,13 @@ function ChartEditor({
52953
53541
  addReport(report2);
52954
53542
  };
52955
53543
  useEffect30(() => {
53544
+ if (!isOpen || !reportId) {
53545
+ return;
53546
+ }
52956
53547
  if (!isClientLoading && !report) {
52957
53548
  fetchReportHelper();
52958
53549
  }
52959
- }, [reportId, isClientLoading, allReportsById]);
53550
+ }, [reportId, isClientLoading, allReportsById, isOpen]);
52960
53551
  return /* @__PURE__ */ jsx82("div", { ref: parentRef, style: { height: "100%" }, children: /* @__PURE__ */ jsx82(
52961
53552
  ModalComponent,
52962
53553
  {
@@ -52970,7 +53561,7 @@ function ChartEditor({
52970
53561
  title: chartBuilderTitle || "Add to dashboard",
52971
53562
  width: isHorizontalView ? modalWidth : void 0,
52972
53563
  height: isHorizontalView ? modalHeight : void 0,
52973
- children: allReportsById[reportId] ? /* @__PURE__ */ jsx82(
53564
+ children: reportId && allReportsById[reportId] ? /* @__PURE__ */ jsx82(
52974
53565
  ChartBuilder,
52975
53566
  {
52976
53567
  reportId,
@@ -52985,8 +53576,15 @@ function ChartEditor({
52985
53576
  } else if (onAddToDashboardComplete) {
52986
53577
  onAddToDashboardComplete(data);
52987
53578
  }
53579
+ const targetDashboard = data?.dashboardName ?? resolvedDashboard;
53580
+ if (targetDashboard) {
53581
+ reload(targetDashboard, true, {
53582
+ report: data,
53583
+ action: "upsert"
53584
+ });
53585
+ }
52988
53586
  },
52989
- destinationDashboard,
53587
+ destinationDashboard: resolvedDashboard ?? void 0,
52990
53588
  destinationSection,
52991
53589
  dateRange,
52992
53590
  SelectComponent,