@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.cjs CHANGED
@@ -1401,6 +1401,9 @@ var init_dateRangePickerUtils = __esm({
1401
1401
  value: 12,
1402
1402
  unit: "months"
1403
1403
  },
1404
+ {
1405
+ type: "previous_month"
1406
+ },
1404
1407
  {
1405
1408
  type: "relative",
1406
1409
  value: 1,
@@ -1440,11 +1443,33 @@ var init_dateRangePickerUtils = __esm({
1440
1443
  })
1441
1444
  };
1442
1445
  }
1443
- case "relative":
1446
+ case "relative": {
1447
+ if (interval2.unit === "months" && interval2.value === 1 && (!interval2.label || interval2.label === "Last month")) {
1448
+ const lastMonth = (0, import_date_fns2.subMonths)((0, import_date_fns2.startOfToday)(), 1);
1449
+ return {
1450
+ startDate: (0, import_date_fns2.startOfMonth)(lastMonth),
1451
+ endDate: (0, import_date_fns2.endOfMonth)(lastMonth)
1452
+ };
1453
+ }
1444
1454
  return {
1445
1455
  startDate: (0, import_date_fns2.sub)((0, import_date_fns2.startOfToday)(), { [interval2.unit]: interval2.value }),
1446
1456
  endDate: (0, import_date_fns2.endOfToday)()
1447
1457
  };
1458
+ }
1459
+ case "previous_month": {
1460
+ const lastMonth = (0, import_date_fns2.subMonths)((0, import_date_fns2.startOfToday)(), 1);
1461
+ return {
1462
+ startDate: (0, import_date_fns2.startOfMonth)(lastMonth),
1463
+ endDate: (0, import_date_fns2.endOfMonth)(lastMonth)
1464
+ };
1465
+ }
1466
+ case "previous_quarter": {
1467
+ const lastQuarter = (0, import_date_fns2.subQuarters)((0, import_date_fns2.startOfToday)(), 1);
1468
+ return {
1469
+ startDate: (0, import_date_fns2.startOfQuarter)(lastQuarter),
1470
+ endDate: (0, import_date_fns2.endOfQuarter)(lastQuarter)
1471
+ };
1472
+ }
1448
1473
  case "repeating": {
1449
1474
  const currentDate = /* @__PURE__ */ new Date();
1450
1475
  const currentYear = currentDate.getFullYear();
@@ -1489,24 +1514,39 @@ var init_dateRangePickerUtils = __esm({
1489
1514
  getLabelForCustomInterval = (interval2) => {
1490
1515
  switch (interval2.type) {
1491
1516
  case "week":
1492
- return "This week";
1517
+ return interval2.label ?? "This week";
1493
1518
  case "static":
1494
1519
  return interval2.label ?? "Custom";
1495
1520
  case "relative":
1496
1521
  return interval2.label ?? `Last ${interval2.value === 1 ? "" : interval2.value + " "}${interval2.value === 1 ? interval2.unit.slice(0, -1) : interval2.unit}`;
1522
+ case "previous_month":
1523
+ return interval2.label ?? "Last month";
1524
+ case "previous_quarter":
1525
+ return interval2.label ?? "Last quarter";
1497
1526
  case "repeating":
1498
- return "This " + interval2.label.toLowerCase();
1527
+ if (interval2.label === "Month") return "This month";
1528
+ if (interval2.label === "Year") return "This year";
1529
+ return interval2.label;
1499
1530
  }
1500
1531
  };
1501
1532
  convertPresetOptionsToSelectableList = (customIntervals, defaultIntervals) => {
1502
- const defaultCustomIntervals = defaultIntervals.map(
1503
- (interval2) => {
1504
- if (interval2.label === "This week") {
1505
- return {
1533
+ const customLabelMap = /* @__PURE__ */ new Map();
1534
+ defaultIntervals.forEach((interval2) => {
1535
+ if (interval2.customLabel) {
1536
+ customLabelMap.set(interval2.label, interval2.customLabel);
1537
+ }
1538
+ });
1539
+ const defaultCustomIntervals = defaultIntervals.flatMap((interval2) => {
1540
+ let createdIntervals = [];
1541
+ if (interval2.label === "This week") {
1542
+ createdIntervals = [
1543
+ {
1506
1544
  type: "week"
1507
- };
1508
- } else if (interval2.label === "This month" || interval2.label === "Monthly") {
1509
- return {
1545
+ }
1546
+ ];
1547
+ } else if (interval2.label === "This month" || interval2.label === "Monthly") {
1548
+ createdIntervals = [
1549
+ {
1510
1550
  type: "repeating",
1511
1551
  label: "Month",
1512
1552
  loopDate: { day: 1, month: 1 },
@@ -1586,9 +1626,11 @@ var init_dateRangePickerUtils = __esm({
1586
1626
  endDate: { day: 31, month: 12 }
1587
1627
  }
1588
1628
  ]
1589
- };
1590
- } else if (interval2.label === "This year" || interval2.label === "Yearly") {
1591
- return {
1629
+ }
1630
+ ];
1631
+ } else if (interval2.label === "This year" || interval2.label === "Yearly") {
1632
+ createdIntervals = [
1633
+ {
1592
1634
  type: "repeating",
1593
1635
  label: "Year",
1594
1636
  loopDate: { day: 1, month: 1 },
@@ -1602,42 +1644,69 @@ var init_dateRangePickerUtils = __esm({
1602
1644
  endDate: { day: 31, month: 12 }
1603
1645
  }
1604
1646
  ]
1605
- };
1606
- } else if (interval2.label === "Last 7 days") {
1607
- return {
1647
+ }
1648
+ ];
1649
+ } else if (interval2.label === "Last 7 days") {
1650
+ createdIntervals = [
1651
+ {
1608
1652
  type: "relative",
1609
1653
  value: 7,
1610
1654
  unit: "days"
1611
- };
1612
- } else if (interval2.label === "Last 30 days") {
1613
- return {
1655
+ }
1656
+ ];
1657
+ } else if (interval2.label === "Last 30 days") {
1658
+ createdIntervals = [
1659
+ {
1614
1660
  type: "relative",
1615
1661
  value: 30,
1616
1662
  unit: "days"
1617
- };
1618
- } else if (interval2.label === "Last 90 days") {
1619
- return {
1663
+ }
1664
+ ];
1665
+ } else if (interval2.label === "Last 90 days") {
1666
+ createdIntervals = [
1667
+ {
1620
1668
  type: "relative",
1621
1669
  value: 90,
1622
1670
  unit: "days"
1623
- };
1624
- } else if (interval2.label === "Last 6 months") {
1625
- return {
1671
+ }
1672
+ ];
1673
+ } else if (interval2.label === "Last 6 months") {
1674
+ createdIntervals = [
1675
+ {
1626
1676
  type: "relative",
1627
1677
  value: 6,
1628
1678
  unit: "months"
1629
- };
1630
- } else if (interval2.label === "Last 12 months") {
1631
- return {
1679
+ }
1680
+ ];
1681
+ } else if (interval2.label === "Last 12 months") {
1682
+ createdIntervals = [
1683
+ {
1632
1684
  type: "relative",
1633
1685
  value: 12,
1634
1686
  unit: "months"
1635
- };
1636
- } else {
1637
- throw new Error("Invalid interval");
1638
- }
1687
+ }
1688
+ ];
1689
+ } else if (interval2.label === "Last month") {
1690
+ createdIntervals = [
1691
+ {
1692
+ type: "previous_month"
1693
+ }
1694
+ ];
1695
+ } else if (interval2.label === "Last quarter") {
1696
+ createdIntervals = [
1697
+ {
1698
+ type: "previous_quarter"
1699
+ }
1700
+ ];
1639
1701
  }
1640
- );
1702
+ if (interval2.customLabel && createdIntervals.length > 0) {
1703
+ return createdIntervals.map((i) => ({
1704
+ ...i,
1705
+ label: interval2.customLabel
1706
+ }));
1707
+ }
1708
+ return createdIntervals;
1709
+ });
1641
1710
  return customIntervals?.length || defaultCustomIntervals?.length ? (defaultCustomIntervals ?? []).concat(customIntervals ?? []).flatMap((option) => {
1642
1711
  if (option.type === "repeating" && option.loopStart) {
1643
1712
  const presets = [];
@@ -1679,8 +1748,19 @@ var init_dateRangePickerUtils = __esm({
1679
1748
  }
1680
1749
  };
1681
1750
  const currentYear = currentDate.getFullYear();
1751
+ const baseLabel = getLabelForSubInterval(currentSubInterval);
1752
+ let customLabel2;
1753
+ if (option.label && option.label !== "Month" && option.label !== "Year") {
1754
+ customLabel2 = option.label;
1755
+ } else {
1756
+ if (option.label === "Month") {
1757
+ customLabel2 = customLabelMap.get("This month") || customLabelMap.get("Monthly");
1758
+ } else if (option.label === "Year") {
1759
+ customLabel2 = customLabelMap.get("This year") || customLabelMap.get("Yearly");
1760
+ }
1761
+ }
1682
1762
  presets.push({
1683
- label: getLabelForSubInterval(currentSubInterval),
1763
+ label: customLabel2 || baseLabel,
1684
1764
  value: getLabelForSubInterval(currentSubInterval).toUpperCase().replace(/ /g, "_") ?? "",
1685
1765
  startDate: (0, import_date_fns2.set)(/* @__PURE__ */ new Date(), {
1686
1766
  year: currentYear,
@@ -1712,9 +1792,12 @@ var init_dateRangePickerUtils = __esm({
1712
1792
  return presets;
1713
1793
  }
1714
1794
  const dateRange = convertCustomIntervalToDateRange(option);
1795
+ const generatedLabel = getLabelForCustomInterval(option);
1796
+ const customLabel = customLabelMap.get(generatedLabel);
1797
+ const finalLabel = customLabel || generatedLabel;
1715
1798
  return [
1716
1799
  {
1717
- label: getLabelForCustomInterval(option),
1800
+ label: finalLabel,
1718
1801
  // Value is option label in uppercase with spaces replaced by underscores
1719
1802
  value: getLabelForCustomInterval(option).toUpperCase().replace(/ /g, "_") ?? "",
1720
1803
  startDate: dateRange.startDate,
@@ -1771,6 +1854,7 @@ var init_dateRangePickerUtils = __esm({
1771
1854
  LAST_12_MONTHS: convertCustomIntervalToDateRange(
1772
1855
  primaryRangeCustomIntervals[7]
1773
1856
  ),
1857
+ LAST_MONTH: convertCustomIntervalToDateRange(primaryRangeCustomIntervals[8]),
1774
1858
  ALL_TIME: { startDate: void 0, endDate: void 0 }
1775
1859
  };
1776
1860
  COMPARISON_OPTIONS = [
@@ -1845,6 +1929,12 @@ var init_dateRangePickerUtils = __esm({
1845
1929
  startDate: PRIMARY_RANGE["LAST_30_DAYS"].startDate,
1846
1930
  endDate: PRIMARY_RANGE["LAST_30_DAYS"].endDate
1847
1931
  },
1932
+ {
1933
+ value: "LAST_MONTH",
1934
+ label: "Last month",
1935
+ startDate: PRIMARY_RANGE["LAST_MONTH"].startDate,
1936
+ endDate: PRIMARY_RANGE["LAST_MONTH"].endDate
1937
+ },
1848
1938
  {
1849
1939
  value: "LAST_90_DAYS",
1850
1940
  label: "Last 90 days",
@@ -15335,7 +15425,10 @@ var init_filterProcessing = __esm({
15335
15425
  })
15336
15426
  ).values()
15337
15427
  ],
15338
- options: defaultOptionsV2,
15428
+ options: filter.presetOptions || filter.defaultPresetRanges ? convertPresetOptionsToSelectableList(
15429
+ filter.presetOptions ?? [],
15430
+ filter.defaultPresetRanges ?? []
15431
+ ) : defaultOptionsV2,
15339
15432
  preset: filter.primaryRange,
15340
15433
  dashboardName,
15341
15434
  comparisonRange: filter.comparison && comparisonRangeStart && comparisonRangeEnd ? {
@@ -16224,6 +16317,128 @@ async function generatePivotTable({
16224
16317
  }
16225
16318
  throw Error("Failed to generate pivot table: invalid report");
16226
16319
  }
16320
+ function processPivotData({
16321
+ rows: responseRows,
16322
+ fields: responseFields,
16323
+ pivot,
16324
+ dateBucket,
16325
+ dateFilter,
16326
+ client,
16327
+ rowCount
16328
+ }) {
16329
+ const databaseType = client.databaseType || "postgresql";
16330
+ const rows = pivot.rowField ? responseRows.map(
16331
+ (row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
16332
+ ) : responseRows;
16333
+ if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
16334
+ rows.forEach((row) => {
16335
+ Object.keys(row).forEach((key) => {
16336
+ const processedKey = processColumnName(key);
16337
+ if (processedKey !== key) {
16338
+ row[processedKey] = row[key];
16339
+ delete row[key];
16340
+ }
16341
+ });
16342
+ });
16343
+ }
16344
+ const columns = responseFields?.map((field) => ({
16345
+ field: processColumnName(field.field || field.name),
16346
+ label: snakeCaseToTitleCase(
16347
+ processColumnName(
16348
+ (field.field || field.name).replace("comparison_", "comparison ")
16349
+ )
16350
+ ),
16351
+ format: (field.field || field.name) === pivot.rowField ? "string" : pivot.aggregations?.find(
16352
+ (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")
16353
+ )?.aggregationType === "percentage" ? "percent" : "whole_number",
16354
+ fieldType: field.fieldType,
16355
+ jsType: field.jsType,
16356
+ dataTypeID: field.dataTypeID
16357
+ })).filter(
16358
+ (field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
16359
+ ).sort((a, b) => {
16360
+ if (a.field === pivot.rowField) {
16361
+ return -1;
16362
+ }
16363
+ if (b.field === pivot.rowField) {
16364
+ return 1;
16365
+ }
16366
+ return 0;
16367
+ });
16368
+ if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
16369
+ rows.forEach((row) => {
16370
+ row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16371
+ let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16372
+ if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
16373
+ const rowDate = new Date(value);
16374
+ if (rowDate < dateFilter.startDate) {
16375
+ value = dateFilter.startDate.toISOString();
16376
+ } else if (rowDate > dateFilter.endDate) {
16377
+ value = dateFilter.endDate.toISOString();
16378
+ }
16379
+ }
16380
+ const dateString = getDateString(
16381
+ value,
16382
+ dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
16383
+ dateBucket,
16384
+ databaseType
16385
+ );
16386
+ row[pivot.rowField || ""] = dateString;
16387
+ });
16388
+ if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
16389
+ const dateSet = new Set(
16390
+ rows.map((row) => row[pivot.rowField || ""])
16391
+ );
16392
+ for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
16393
+ const formattedDate = getDateString(
16394
+ date.toISOString(),
16395
+ { start: dateFilter.startDate, end: dateFilter.endDate },
16396
+ dateBucket,
16397
+ databaseType
16398
+ );
16399
+ if (!dateSet.has(formattedDate)) {
16400
+ const newRow = {};
16401
+ newRow[pivot.rowField] = formattedDate;
16402
+ newRow.__quillRawDate = date.toISOString();
16403
+ rows.push(newRow);
16404
+ dateSet.add(formattedDate);
16405
+ }
16406
+ }
16407
+ }
16408
+ if (!pivot.sort || pivot.sortField === pivot.rowField) {
16409
+ rows.sort((a, b) => {
16410
+ const direction = pivot.sort && pivot.sortDirection === "DESC" ? -1 : 1;
16411
+ if (a.__quillRawDate < b.__quillRawDate) {
16412
+ return -1 * direction;
16413
+ }
16414
+ if (a.__quillRawDate > b.__quillRawDate) {
16415
+ return 1 * direction;
16416
+ }
16417
+ return 0;
16418
+ });
16419
+ }
16420
+ }
16421
+ columns?.forEach((column, index) => {
16422
+ if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
16423
+ column.label = "Count";
16424
+ }
16425
+ });
16426
+ const numericColumns = columns?.filter(
16427
+ (column) => column.format === "whole_number" || column.format === "percentage"
16428
+ );
16429
+ rows.forEach((row) => {
16430
+ numericColumns?.forEach((column) => {
16431
+ row[column.field] = row[column.field] ?? 0;
16432
+ });
16433
+ });
16434
+ return {
16435
+ rows,
16436
+ columns: columns ?? [],
16437
+ rowCount: rowCount || rows.length,
16438
+ pivotQuery: "",
16439
+ comparisonPivotQuery: ""
16440
+ };
16441
+ }
16227
16442
  var init_pivotConstructor = __esm({
16228
16443
  "src/utils/pivotConstructor.ts"() {
16229
16444
  "use strict";
@@ -17797,6 +18012,22 @@ var init_tableProcessing = __esm({
17797
18012
  return {};
17798
18013
  }
17799
18014
  let uniqueValuesByColumn = {};
18015
+ const aliasToField = {};
18016
+ const fieldToAlias = {};
18017
+ columns.forEach((col) => {
18018
+ if (col.alias) {
18019
+ aliasToField[col.alias] = col.field;
18020
+ fieldToAlias[col.field] = col.alias;
18021
+ }
18022
+ });
18023
+ reportBuilderState?.columns?.forEach((col) => {
18024
+ if (col.alias) {
18025
+ aliasToField[col.alias] = col.field;
18026
+ if (!fieldToAlias[col.field]) {
18027
+ fieldToAlias[col.field] = col.alias;
18028
+ }
18029
+ }
18030
+ });
17800
18031
  let rows = resp?.rows;
17801
18032
  if (!rows && fetchResult.queries?.queryResults?.[0]?.rows) {
17802
18033
  rows = fetchResult.queries.queryResults[0].rows;
@@ -17805,11 +18036,24 @@ var init_tableProcessing = __esm({
17805
18036
  uniqueValuesByColumn = resp.uniqueValues;
17806
18037
  } else if (rows && Array.isArray(rows)) {
17807
18038
  rows.forEach((row) => {
17808
- if (row.field && row.string_values) {
18039
+ if (row?.field && row?.string_values) {
17809
18040
  uniqueValuesByColumn[row.field] = row.string_values;
17810
18041
  }
17811
18042
  });
17812
18043
  }
18044
+ const normalizedUniqueValuesByColumn = {};
18045
+ Object.entries(uniqueValuesByColumn).forEach(([key, values]) => {
18046
+ if (!Array.isArray(values)) {
18047
+ return;
18048
+ }
18049
+ const fieldKey = aliasToField[key] || key;
18050
+ normalizedUniqueValuesByColumn[fieldKey] = values;
18051
+ const aliasKey = fieldToAlias[fieldKey];
18052
+ if (aliasKey) {
18053
+ normalizedUniqueValuesByColumn[aliasKey] = values;
18054
+ }
18055
+ });
18056
+ uniqueValuesByColumn = normalizedUniqueValuesByColumn;
17813
18057
  const uniqueValues2 = {};
17814
18058
  tables.forEach((tableName) => {
17815
18059
  const tableUniqueValues = {};
@@ -19745,10 +19989,14 @@ async function cleanDashboardItem({
19745
19989
  const pivotChartProcessing = {
19746
19990
  page: DEFAULT_PAGINATION
19747
19991
  };
19748
- pivotTable = await getPivotTable(
19749
- {
19750
- ...item,
19751
- pivot: item.pivot && !skipPivotFetch ? {
19992
+ if (item.pivot && skipPivotFetch && item.rows && item.fields) {
19993
+ const dateFilter = dashboardFilters?.find(
19994
+ (filter) => filter.filterType === "date_range"
19995
+ );
19996
+ pivotTable = processPivotData({
19997
+ rows: item.rows,
19998
+ fields: item.fields,
19999
+ pivot: {
19752
20000
  ...item.pivot,
19753
20001
  aggregations: item.pivot.aggregations ?? [
19754
20002
  {
@@ -19759,18 +20007,40 @@ async function cleanDashboardItem({
19759
20007
  aggregationType: item.pivot.aggregationType
19760
20008
  }
19761
20009
  ]
19762
- } : void 0
19763
- },
19764
- dashboardFilters,
19765
- item.dashboardName,
19766
- getToken,
19767
- client,
19768
- eventTracking,
19769
- dateBucket,
19770
- shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
19771
- tenants,
19772
- customFields
19773
- );
20010
+ },
20011
+ dateBucket,
20012
+ dateFilter,
20013
+ client,
20014
+ rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length
20015
+ });
20016
+ } else {
20017
+ pivotTable = await getPivotTable(
20018
+ {
20019
+ ...item,
20020
+ pivot: item.pivot && !skipPivotFetch ? {
20021
+ ...item.pivot,
20022
+ aggregations: item.pivot.aggregations ?? [
20023
+ {
20024
+ valueField: item.pivot.valueField,
20025
+ valueFieldType: item.pivot.valueFieldType,
20026
+ valueField2: item.pivot.valueField2,
20027
+ valueField2Type: item.pivot.valueField2Type,
20028
+ aggregationType: item.pivot.aggregationType
20029
+ }
20030
+ ]
20031
+ } : void 0
20032
+ },
20033
+ dashboardFilters,
20034
+ item.dashboardName,
20035
+ getToken,
20036
+ client,
20037
+ eventTracking,
20038
+ dateBucket,
20039
+ shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
20040
+ tenants,
20041
+ customFields
20042
+ );
20043
+ }
19774
20044
  } catch (e) {
19775
20045
  pivotTable = void 0;
19776
20046
  eventTracking?.logError?.({
@@ -20178,6 +20448,44 @@ function extractAllReportValuesFromQuillInternalReport(reportInternal) {
20178
20448
  pivotRowCount: reportInternal.pivotRowCount
20179
20449
  };
20180
20450
  }
20451
+ async function fetchReportRows({
20452
+ reportId,
20453
+ client,
20454
+ tenants,
20455
+ filters = [],
20456
+ getToken,
20457
+ abortSignal,
20458
+ additionalProcessing
20459
+ }) {
20460
+ const fetchResp = await quillFetch({
20461
+ client,
20462
+ task: "report",
20463
+ metadata: {
20464
+ reportId,
20465
+ clientId: client.publicKey,
20466
+ databaseType: client.databaseType,
20467
+ filters: filters.map((filter) => ({ ...filter, options: void 0 })),
20468
+ useNewNodeSql: true,
20469
+ tenants,
20470
+ additionalProcessing
20471
+ },
20472
+ abortSignal,
20473
+ getToken
20474
+ });
20475
+ const resp = await parseFetchResponse(client, "report", fetchResp, getToken);
20476
+ if (client.databaseType?.toLowerCase() === "bigquery") {
20477
+ parseValueFromBigQueryDates(resp.rows, resp.fields);
20478
+ }
20479
+ const columns = (resp.fields || []).map(
20480
+ (field) => convertPostgresColumn(field)
20481
+ );
20482
+ return {
20483
+ rows: resp.rows || [],
20484
+ rowCount: resp.rowCount || 0,
20485
+ columns,
20486
+ fields: resp.fields || []
20487
+ };
20488
+ }
20181
20489
  async function fetchReport({
20182
20490
  reportId,
20183
20491
  client,
@@ -20192,14 +20500,15 @@ async function fetchReport({
20192
20500
  rowCountOnly,
20193
20501
  abortSignal,
20194
20502
  getToken,
20195
- eventTracking
20503
+ eventTracking,
20504
+ usePivotTask = false
20196
20505
  }) {
20197
20506
  let reportInfo = void 0;
20198
20507
  let errorMessage = void 0;
20199
20508
  try {
20200
20509
  const fetchResp = await quillFetch({
20201
20510
  client,
20202
- task: useReportTask ? "report" : "item",
20511
+ task: usePivotTask ? "pivot-template" : useReportTask ? "report" : "item",
20203
20512
  metadata: {
20204
20513
  reportId,
20205
20514
  dashboardItemId: reportId,
@@ -20219,7 +20528,7 @@ async function fetchReport({
20219
20528
  });
20220
20529
  const resp = await parseFetchResponse(
20221
20530
  client,
20222
- useReportTask ? "report" : "item",
20531
+ usePivotTask ? "pivot-template" : useReportTask ? "report" : "item",
20223
20532
  fetchResp,
20224
20533
  getToken
20225
20534
  );
@@ -20227,12 +20536,13 @@ async function fetchReport({
20227
20536
  resp,
20228
20537
  client,
20229
20538
  filters,
20230
- dateBucket,
20539
+ dateBucket: resp.dateBucket ?? dateBucket,
20231
20540
  additionalProcessing,
20232
20541
  customFields,
20233
20542
  getToken,
20234
20543
  eventTracking,
20235
- tenants
20544
+ tenants,
20545
+ skipPivotFetch: usePivotTask
20236
20546
  });
20237
20547
  } catch (error) {
20238
20548
  if (error instanceof Error && error.name === "AbortError") {
@@ -20281,8 +20591,10 @@ async function processReportResponse({
20281
20591
  customFields,
20282
20592
  getToken,
20283
20593
  eventTracking,
20284
- tenants
20594
+ tenants,
20595
+ skipPivotFetch = false
20285
20596
  }) {
20597
+ const shouldSkipPivotFetch = skipPivotFetch || !!resp?.pivotRows && !!resp?.fields;
20286
20598
  const dashboardItem = {
20287
20599
  ...resp,
20288
20600
  filtersApplied: filters?.filter(
@@ -20312,7 +20624,8 @@ async function processReportResponse({
20312
20624
  customFields,
20313
20625
  getToken,
20314
20626
  tenants,
20315
- eventTracking
20627
+ eventTracking,
20628
+ skipPivotFetch: shouldSkipPivotFetch
20316
20629
  });
20317
20630
  if (additionalProcessing) {
20318
20631
  reportInfo.pagination = additionalProcessing.page;
@@ -22341,6 +22654,34 @@ var ContextProvider = ({
22341
22654
  );
22342
22655
  if (currentProcessId === loadDashboardProcessId.current[dashboardName]) {
22343
22656
  if (!(0, import_fast_deep_equal.default)(resp, curDashboardConfig)) {
22657
+ Object.values(
22658
+ resp.sections ?? {}
22659
+ ).flat().forEach((report) => {
22660
+ const existing = reports[report.id];
22661
+ if (existing) {
22662
+ const merged = {
22663
+ ...report,
22664
+ // prefer fresh server metadata (chartType, flags, etc.)
22665
+ // preserve existing row payload if server response is metadata-only
22666
+ ...existing.rows ? { rows: existing.rows } : {},
22667
+ ...existing.rowCount !== void 0 ? { rowCount: existing.rowCount } : {},
22668
+ ...existing.columns ? { columns: existing.columns } : {},
22669
+ ...existing.columnInternal ? { columnInternal: existing.columnInternal } : {},
22670
+ ...existing.pagination ? { pagination: existing.pagination } : {}
22671
+ };
22672
+ reportsDispatch({
22673
+ type: "UPDATE_REPORT",
22674
+ id: report.id,
22675
+ data: merged
22676
+ });
22677
+ } else {
22678
+ reportsDispatch({
22679
+ type: "ADD_REPORT",
22680
+ id: report.id,
22681
+ data: report
22682
+ });
22683
+ }
22684
+ });
22344
22685
  dashboardConfigDispatch({
22345
22686
  type: "UPDATE_DASHBOARD",
22346
22687
  id: dashboardName,
@@ -23156,11 +23497,12 @@ var useDashboardInternal = (dashboardName, customFilters) => {
23156
23497
  dashboardName,
23157
23498
  sectionOrder
23158
23499
  };
23159
- void quillFetchWithToken({
23160
- client,
23161
- task: "set-section-order",
23162
- metadata: body
23163
- }).then((response) => {
23500
+ try {
23501
+ const response = await quillFetchWithToken({
23502
+ client,
23503
+ task: "set-section-order",
23504
+ metadata: body
23505
+ });
23164
23506
  Object.entries(response?.data?.newIds ?? {}).forEach(
23165
23507
  ([section, newId2]) => {
23166
23508
  dashboardConfigDispatch({
@@ -23182,11 +23524,24 @@ var useDashboardInternal = (dashboardName, customFilters) => {
23182
23524
  });
23183
23525
  }
23184
23526
  );
23185
- }).catch((error) => {
23186
- if (error instanceof Error && error.name === "AbortError") {
23527
+ } catch (e) {
23528
+ if (e instanceof Error && e.name === "AbortError") {
23187
23529
  return;
23188
23530
  }
23189
- });
23531
+ eventTracking?.logError?.({
23532
+ type: "bug",
23533
+ // TODO: determine type
23534
+ severity: "high",
23535
+ message: "Error setting section order",
23536
+ errorMessage: e?.message,
23537
+ errorStack: e?.stack,
23538
+ errorData: {
23539
+ caller: "useDashboard",
23540
+ function: "setSectionOrder"
23541
+ }
23542
+ });
23543
+ console.error(e);
23544
+ }
23190
23545
  }
23191
23546
  };
23192
23547
  function isDashboardFilterLoading(filterName) {
@@ -23444,7 +23799,8 @@ var useDashboards = () => {
23444
23799
  (preset) => ({
23445
23800
  ...preset,
23446
23801
  loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
23447
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
23802
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0,
23803
+ customLabel: preset.customLabel
23448
23804
  })
23449
23805
  )
23450
23806
  } : void 0,
@@ -23504,7 +23860,8 @@ var useDashboards = () => {
23504
23860
  (preset) => ({
23505
23861
  ...preset,
23506
23862
  loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
23507
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
23863
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0,
23864
+ customLabel: preset.customLabel
23508
23865
  })
23509
23866
  ),
23510
23867
  dashboardName: updated.data.dashboard.name,
@@ -23622,6 +23979,7 @@ var useDashboard = (dashboardName, config) => {
23622
23979
  const { customReportFilters } = (0, import_react2.useContext)(ReportFiltersContext);
23623
23980
  const { eventTracking } = (0, import_react2.useContext)(EventTrackingContext);
23624
23981
  const customFiltersRef = (0, import_react2.useRef)(customReportFilters);
23982
+ const reportRequestIds = (0, import_react2.useRef)({});
23625
23983
  (0, import_react2.useEffect)(() => {
23626
23984
  customFiltersRef.current = customReportFilters;
23627
23985
  }, [customReportFilters]);
@@ -23764,6 +24122,8 @@ var useDashboard = (dashboardName, config) => {
23764
24122
  await Promise.all(
23765
24123
  allReports.map(async (reportInfo) => {
23766
24124
  const reportId = reportInfo.id;
24125
+ const requestId = (reportRequestIds.current[reportId] ?? 0) + 1;
24126
+ reportRequestIds.current[reportId] = requestId;
23767
24127
  reportsLoadingStateDispatch({
23768
24128
  type: "SET_REPORT_LOADING",
23769
24129
  id: reportId,
@@ -23781,6 +24141,7 @@ var useDashboard = (dashboardName, config) => {
23781
24141
  const additionalProcessing = {
23782
24142
  page: pagination
23783
24143
  };
24144
+ const usePivotTask = !!reportInfo.pivot;
23784
24145
  const { report, error } = await fetchReport({
23785
24146
  reportId,
23786
24147
  client,
@@ -23789,12 +24150,16 @@ var useDashboard = (dashboardName, config) => {
23789
24150
  additionalProcessing,
23790
24151
  filters: dashboardFilters2.concat(customFilters).concat(customReportFiltersArray),
23791
24152
  getToken,
23792
- eventTracking
24153
+ eventTracking,
24154
+ usePivotTask
23793
24155
  });
23794
24156
  if (error) {
23795
24157
  console.error(error);
23796
24158
  return null;
23797
24159
  }
24160
+ if (reportRequestIds.current[reportId] !== requestId) {
24161
+ return null;
24162
+ }
23798
24163
  reportsDispatch({
23799
24164
  type: "UPDATE_REPORT",
23800
24165
  id: reportId,
@@ -23808,6 +24173,40 @@ var useDashboard = (dashboardName, config) => {
23808
24173
  id: reportId,
23809
24174
  data: false
23810
24175
  });
24176
+ if (usePivotTask) {
24177
+ fetchReportRows({
24178
+ reportId,
24179
+ client,
24180
+ tenants,
24181
+ filters: dashboardFilters2.concat(customFilters).concat(customReportFiltersArray),
24182
+ getToken,
24183
+ additionalProcessing
24184
+ }).then(({ rows, rowCount, columns, fields }) => {
24185
+ if (reportRequestIds.current[reportId] !== requestId) {
24186
+ return;
24187
+ }
24188
+ reportsDispatch({
24189
+ type: "UPDATE_REPORT",
24190
+ id: reportId,
24191
+ data: {
24192
+ rows,
24193
+ rowCount,
24194
+ columnInternal: columns,
24195
+ columns: columns.map((col) => ({
24196
+ field: col.field,
24197
+ format: col.format,
24198
+ label: col.label,
24199
+ inferFormat: col.inferFormat
24200
+ })),
24201
+ // @ts-ignore fields is not typed on QuillReportInternal
24202
+ fields
24203
+ }
24204
+ });
24205
+ }).catch((e) => {
24206
+ if (e instanceof Error && e.name === "AbortError") return;
24207
+ console.error("Failed to fetch background rows", e);
24208
+ });
24209
+ }
23811
24210
  return report;
23812
24211
  })
23813
24212
  );
@@ -28108,6 +28507,8 @@ var axisFormatter = ({ value, field, fields }) => {
28108
28507
  return formatPercent2(value);
28109
28508
  case "dollar_amount":
28110
28509
  return formatDollarAmount2(value);
28510
+ case "dollar_cents":
28511
+ return formatDollarCents2(value);
28111
28512
  case "whole_number":
28112
28513
  return formatWholeNumber2(value);
28113
28514
  case "two_decimal_places":
@@ -28172,6 +28573,12 @@ var formatterDollar2 = new Intl.NumberFormat("en-US", {
28172
28573
  currency: "USD",
28173
28574
  maximumFractionDigits: 0
28174
28575
  });
28576
+ var formatterDollarCents = new Intl.NumberFormat("en-US", {
28577
+ style: "currency",
28578
+ currency: "USD",
28579
+ minimumFractionDigits: 2,
28580
+ maximumFractionDigits: 2
28581
+ });
28175
28582
  var formatDollarAmount2 = (value) => {
28176
28583
  const num = Number(value ?? 0);
28177
28584
  if (num >= 1e3 || num === 0) {
@@ -28180,6 +28587,9 @@ var formatDollarAmount2 = (value) => {
28180
28587
  return formatterDollar2.format(num);
28181
28588
  }
28182
28589
  };
28590
+ var formatDollarCents2 = (value) => {
28591
+ return formatterDollarCents.format(Number(value ?? 0));
28592
+ };
28183
28593
  var formatterBigWholeNumber = new Intl.NumberFormat("en-US", {
28184
28594
  minimumSignificantDigits: 1,
28185
28595
  maximumSignificantDigits: 2,
@@ -32253,6 +32663,8 @@ function DataLoader({
32253
32663
  previousUserFilters.current = userFilters;
32254
32664
  rowsAbortController.current?.abort();
32255
32665
  rowsAbortController.current = new AbortController();
32666
+ const usePivotTask = !!item.pivot;
32667
+ let backgroundFetch = null;
32256
32668
  try {
32257
32669
  if (dashboardName) {
32258
32670
  const { report: fetchedReport, error: error2 } = await fetchReport({
@@ -32268,18 +32680,62 @@ function DataLoader({
32268
32680
  rowCountOnly: false,
32269
32681
  abortSignal: rowsAbortController.current.signal,
32270
32682
  getToken,
32271
- eventTracking
32683
+ eventTracking,
32684
+ usePivotTask
32272
32685
  });
32686
+ const existingReport = dashboard[item.id] ?? reports[item.id];
32687
+ const baseReport = error2 && existingReport ? { ...existingReport, error: error2 } : fetchedReport;
32688
+ const reportToAdd = {
32689
+ ...baseReport,
32690
+ rows: baseReport?.rows ?? [],
32691
+ columns: baseReport?.columns ?? [],
32692
+ columnInternal: baseReport?.columnInternal ?? []
32693
+ };
32273
32694
  addReport({
32274
- ...fetchedReport,
32695
+ ...reportToAdd,
32275
32696
  id: item.id,
32276
32697
  triggerReload: false,
32277
- rowCount: fetchedReport.pivot ? fetchedReport.rowCount : 0,
32698
+ rowCount: reportToAdd.pivot ? reportToAdd.rowCount : 0,
32278
32699
  filtersApplied: userFilters,
32279
32700
  loadingRows: false
32280
32701
  // rowCount 0 indicates it's still loading if row length is nonzero
32281
32702
  });
32282
32703
  setError(error2);
32704
+ if (usePivotTask) {
32705
+ const backgroundAbortController = new AbortController();
32706
+ backgroundFetch = () => {
32707
+ fetchReportRows({
32708
+ reportId: item.id,
32709
+ client,
32710
+ tenants,
32711
+ filters: filters.concat(userFilters ?? []),
32712
+ getToken,
32713
+ abortSignal: backgroundAbortController.signal,
32714
+ additionalProcessing: {
32715
+ ...processing,
32716
+ ...{ page: DEFAULT_PAGINATION }
32717
+ }
32718
+ }).then(({ rows, rowCount, columns, fields }) => {
32719
+ updateReport({
32720
+ id: item.id,
32721
+ rows,
32722
+ rowCount,
32723
+ columnInternal: columns,
32724
+ columns: columns.map((col) => ({
32725
+ field: col.field,
32726
+ format: col.format,
32727
+ label: col.label,
32728
+ inferFormat: col.inferFormat
32729
+ })),
32730
+ // @ts-ignore
32731
+ fields
32732
+ });
32733
+ }).catch((e) => {
32734
+ if (e instanceof Error && e.name === "AbortError") return;
32735
+ console.error("Failed to fetch background rows", e);
32736
+ });
32737
+ };
32738
+ }
32283
32739
  } else {
32284
32740
  try {
32285
32741
  await fetchIndividualReport({
@@ -32336,6 +32792,9 @@ function DataLoader({
32336
32792
  if (fetchRowsRequestId === rowsRequestId.current) {
32337
32793
  rowsAbortController.current = null;
32338
32794
  setLoading(false);
32795
+ if (backgroundFetch) {
32796
+ backgroundFetch();
32797
+ }
32339
32798
  }
32340
32799
  }
32341
32800
  };
@@ -32400,7 +32859,11 @@ var ChartDataLoader = ({
32400
32859
  dashboardName,
32401
32860
  propagateChanges
32402
32861
  }) => {
32403
- const { dashboardReports: dashboard, addReport } = useDashboardReports(dashboardName);
32862
+ const {
32863
+ dashboardReports: dashboard,
32864
+ addReport,
32865
+ updateReport
32866
+ } = useDashboardReports(dashboardName);
32404
32867
  const { dashboardFilters } = (0, import_react25.useContext)(DashboardFiltersContext);
32405
32868
  const { reports, fetchIndividualReport } = (0, import_react25.useContext)(ReportsContext);
32406
32869
  const { getToken } = (0, import_react25.useContext)(FetchContext);
@@ -32450,6 +32913,8 @@ var ChartDataLoader = ({
32450
32913
  setLoading(true);
32451
32914
  fetchReportAbortController.current?.abort();
32452
32915
  fetchReportAbortController.current = new AbortController();
32916
+ const usePivotTask = !!item.pivot;
32917
+ let backgroundFetch = null;
32453
32918
  try {
32454
32919
  if (dashboardName) {
32455
32920
  const { report, error: error2 } = await fetchReport({
@@ -32467,16 +32932,60 @@ var ChartDataLoader = ({
32467
32932
  customFields: schemaData.customFields,
32468
32933
  abortSignal: fetchReportAbortController.current.signal,
32469
32934
  getToken,
32470
- eventTracking
32935
+ eventTracking,
32936
+ usePivotTask
32471
32937
  });
32938
+ const existingReport = dashboard[item.id] ?? reports[item.id];
32939
+ const baseReport = error2 && existingReport ? { ...existingReport, error: error2 } : report;
32940
+ const reportToAdd = {
32941
+ ...baseReport,
32942
+ rows: baseReport?.rows ?? [],
32943
+ columns: baseReport?.columns ?? [],
32944
+ columnInternal: baseReport?.columnInternal ?? []
32945
+ };
32472
32946
  addReport({
32473
- ...report,
32947
+ ...reportToAdd,
32474
32948
  id: item.id,
32475
32949
  triggerReload: false,
32476
32950
  filtersApplied: userFilters,
32477
32951
  loadingRows: false
32478
32952
  });
32479
32953
  setError(error2);
32954
+ if (usePivotTask) {
32955
+ const backgroundAbortController = new AbortController();
32956
+ backgroundFetch = () => {
32957
+ fetchReportRows({
32958
+ reportId: item.id,
32959
+ client,
32960
+ tenants,
32961
+ filters: filters.concat(userFilters ?? []),
32962
+ getToken,
32963
+ abortSignal: backgroundAbortController.signal,
32964
+ additionalProcessing: {
32965
+ ...additionalProcessing,
32966
+ ...{ page: DEFAULT_PAGINATION }
32967
+ }
32968
+ }).then(({ rows, rowCount, columns, fields }) => {
32969
+ updateReport({
32970
+ id: item.id,
32971
+ rows,
32972
+ rowCount,
32973
+ columnInternal: columns,
32974
+ columns: columns.map((col) => ({
32975
+ field: col.field,
32976
+ format: col.format,
32977
+ label: col.label,
32978
+ inferFormat: col.inferFormat
32979
+ })),
32980
+ // @ts-ignore
32981
+ fields
32982
+ });
32983
+ }).catch((e) => {
32984
+ if (e instanceof Error && e.name === "AbortError") return;
32985
+ console.error("Failed to fetch background rows", e);
32986
+ });
32987
+ };
32988
+ }
32480
32989
  } else {
32481
32990
  try {
32482
32991
  await fetchIndividualReport({
@@ -32532,6 +33041,9 @@ var ChartDataLoader = ({
32532
33041
  if (fetchRowsRequestId === rowsRequestId.current) {
32533
33042
  fetchReportAbortController.current = null;
32534
33043
  setLoading(false);
33044
+ if (backgroundFetch) {
33045
+ backgroundFetch();
33046
+ }
32535
33047
  }
32536
33048
  }
32537
33049
  };
@@ -38697,7 +39209,7 @@ function Dashboard({
38697
39209
  filters: populatedDashboardFilters ?? [],
38698
39210
  userFilters: dataLoaderUserFilters,
38699
39211
  additionalProcessing: {
38700
- page: DEFAULT_PAGINATION,
39212
+ page: pagination,
38701
39213
  last: additionalProcessing?.last
38702
39214
  },
38703
39215
  dashboardName: name2,
@@ -40990,7 +41502,7 @@ var PivotModal = ({
40990
41502
  });
40991
41503
  }
40992
41504
  },
40993
- options: (samplePivotTable?.columns ?? []).map((column) => ({
41505
+ options: (samplePivotTable?.columns && samplePivotTable.columns.length > 0 ? samplePivotTable.columns : pivotRowField ? [{ field: pivotRowField }] : []).map((column) => ({
40994
41506
  label: snakeAndCamelCaseToTitleCase(
40995
41507
  column.field
40996
41508
  ),
@@ -41403,6 +41915,7 @@ init_Filter();
41403
41915
  init_filterProcessing();
41404
41916
  init_dateRangePickerUtils();
41405
41917
  var import_jsx_runtime63 = require("react/jsx-runtime");
41918
+ var MULTISELECT_REQUEST_DEBOUNCE_MS = 1e3;
41406
41919
  var TogglePrimitive = ({
41407
41920
  value,
41408
41921
  onClick,
@@ -41542,6 +42055,20 @@ function InternalChart({
41542
42055
  ) : defaultOptionsV2;
41543
42056
  }, [reportDateFilter]);
41544
42057
  const [filterValues, setFilterValues] = (0, import_react42.useState)({});
42058
+ const multiselectDebounceRef = (0, import_react42.useRef)({});
42059
+ const latestMultiselectValueRef = (0, import_react42.useRef)({});
42060
+ const [lockedFilters, setLockedFilters] = (0, import_react42.useState)(
42061
+ {}
42062
+ );
42063
+ (0, import_react42.useEffect)(() => {
42064
+ return () => {
42065
+ Object.values(multiselectDebounceRef.current).forEach((timer2) => {
42066
+ if (timer2) {
42067
+ clearTimeout(timer2);
42068
+ }
42069
+ });
42070
+ };
42071
+ }, []);
41545
42072
  (0, import_react42.useEffect)(() => {
41546
42073
  if (reportDateFilter) {
41547
42074
  const customDateFilter = filters?.find(
@@ -41648,6 +42175,46 @@ function InternalChart({
41648
42175
  ...filterValues2,
41649
42176
  [filter.label]: filterValue
41650
42177
  }));
42178
+ if (filter.filterType === "string" /* String */ && filter.stringFilterType === "multiselect") {
42179
+ latestMultiselectValueRef.current[filter.label] = filterValue;
42180
+ const existingTimer = multiselectDebounceRef.current[filter.label];
42181
+ if (existingTimer) {
42182
+ clearTimeout(existingTimer);
42183
+ }
42184
+ multiselectDebounceRef.current[filter.label] = setTimeout(() => {
42185
+ multiselectDebounceRef.current[filter.label] = void 0;
42186
+ setLockedFilters((prev) => ({
42187
+ ...prev,
42188
+ [filter.label]: true
42189
+ }));
42190
+ try {
42191
+ const maybePromise = onDashboardFilterChange(
42192
+ filter.label,
42193
+ latestMultiselectValueRef.current[filter.label]
42194
+ );
42195
+ if (maybePromise && typeof maybePromise.finally === "function") {
42196
+ maybePromise.finally(() => {
42197
+ setLockedFilters((prev) => ({
42198
+ ...prev,
42199
+ [filter.label]: false
42200
+ }));
42201
+ });
42202
+ } else {
42203
+ setLockedFilters((prev) => ({
42204
+ ...prev,
42205
+ [filter.label]: false
42206
+ }));
42207
+ }
42208
+ } catch (e) {
42209
+ setLockedFilters((prev) => ({
42210
+ ...prev,
42211
+ [filter.label]: false
42212
+ }));
42213
+ throw e;
42214
+ }
42215
+ }, MULTISELECT_REQUEST_DEBOUNCE_MS);
42216
+ return;
42217
+ }
41651
42218
  onDashboardFilterChange(filter.label, filterValue);
41652
42219
  };
41653
42220
  const [filtersExpanded, setFiltersExpanded] = (0, import_react42.useState)(false);
@@ -41805,7 +42372,7 @@ function InternalChart({
41805
42372
  SelectComponent,
41806
42373
  MultiSelectComponent,
41807
42374
  DateRangePickerComponent,
41808
- disabled: !filtersEnabled,
42375
+ disabled: !filtersEnabled || lockedFilters[filter.filter.label],
41809
42376
  containerStyle: {
41810
42377
  // display: !filtersExpanded && visibleFilters[index] ? 'none' : 'inline',
41811
42378
  visibility: !filtersExpanded && visibleFilters[index] ? "hidden" : "visible"
@@ -43666,6 +44233,7 @@ function ChartBuilder({
43666
44233
  client,
43667
44234
  uniqueValues,
43668
44235
  dashboardName: destinationDashboardName,
44236
+ dashboardFilters: dashboardFilters2,
43669
44237
  tenants,
43670
44238
  additionalProcessing: baseProcessing,
43671
44239
  getToken,
@@ -43777,7 +44345,7 @@ function ChartBuilder({
43777
44345
  }
43778
44346
  return filter;
43779
44347
  });
43780
- loadFiltersForReport(
44348
+ return loadFiltersForReport(
43781
44349
  report?.id ?? TEMP_REPORT_ID,
43782
44350
  "ChartBuilder",
43783
44351
  updatedFilters,
@@ -43787,7 +44355,7 @@ function ChartBuilder({
43787
44355
  ).then(() => {
43788
44356
  setCurrentPage(0);
43789
44357
  setMaxPage(0);
43790
- handleRunQuery(baseProcessing, updatedFilters);
44358
+ return handleRunQuery(baseProcessing, updatedFilters);
43791
44359
  });
43792
44360
  };
43793
44361
  const filtersEnabledRef = (0, import_react44.useRef)(filtersEnabled);
@@ -44346,12 +44914,21 @@ function ChartBuilder({
44346
44914
  error: void 0,
44347
44915
  section: formData.section
44348
44916
  };
44349
- addReport(data);
44350
- reportsDispatch({
44351
- type: "ADD_REPORT",
44352
- id: resp.id,
44353
- data
44354
- });
44917
+ const reportFlags = data.flags;
44918
+ const hasRestrictedFlags = reportFlags && Object.values(reportFlags).some(
44919
+ (v) => Array.isArray(v) && v.length > 0
44920
+ );
44921
+ const currentTenantCanSee = !hasRestrictedFlags || flags && Object.values(reportFlags).some(
44922
+ (v) => v === "QUILL_ALL_TENANTS" || Array.isArray(v) && v.some((f) => flags.includes(f))
44923
+ );
44924
+ if (currentTenantCanSee) {
44925
+ addReport(data);
44926
+ reportsDispatch({
44927
+ type: "ADD_REPORT",
44928
+ id: resp.id,
44929
+ data
44930
+ });
44931
+ }
44355
44932
  if (onAddToDashboardComplete) {
44356
44933
  onAddToDashboardComplete(data);
44357
44934
  } else {
@@ -48768,6 +49345,14 @@ var useReportBuilderInternal = ({
48768
49345
  report,
48769
49346
  skipPivotColumnFetch
48770
49347
  }) => {
49348
+ const tablesEqual = (a, b) => {
49349
+ if (a.length !== b.length) return false;
49350
+ const aNames = a.map((t) => t.name).sort();
49351
+ const bNames = b.map((t) => t.name).sort();
49352
+ return aNames.every((name2, idx) => name2 === bNames[idx]);
49353
+ };
49354
+ const haveTablesChanged = tablesChanged ?? !tablesEqual(state.tables, tables);
49355
+ const needsFilteredUniqueValues = !!filtersChanged || !!limitChanged || haveTablesChanged;
48771
49356
  if (!client) {
48772
49357
  return;
48773
49358
  }
@@ -48775,8 +49360,8 @@ var useReportBuilderInternal = ({
48775
49360
  state,
48776
49361
  pivot: state.pivot,
48777
49362
  previousReport: report,
48778
- requiresNewFilteredUniqueValues: filtersChanged || limitChanged,
48779
- requiresNewUnfilteredUniqueValues: tablesChanged,
49363
+ requiresNewFilteredUniqueValues: needsFilteredUniqueValues,
49364
+ requiresNewUnfilteredUniqueValues: haveTablesChanged,
48780
49365
  skipPivotColumnFetch
48781
49366
  });
48782
49367
  };
@@ -49387,18 +49972,10 @@ var useReportBuilderInternal = ({
49387
49972
  }, [client]);
49388
49973
  (0, import_react48.useEffect)(() => {
49389
49974
  const loadChart = async () => {
49390
- let report;
49391
- if (!client) {
49392
- return;
49393
- }
49975
+ if (!client || !reportId) return;
49976
+ const report = allReportsById[reportId];
49977
+ if (!report) return;
49394
49978
  try {
49395
- if (!reportId) {
49396
- throw new Error("Report ID is required");
49397
- }
49398
- report = allReportsById[reportId];
49399
- if (!report) {
49400
- throw new Error("Report not found");
49401
- }
49402
49979
  const { ast: newAst, pivot: newPivot } = await fetchASTFromQuillReport(
49403
49980
  report,
49404
49981
  client,
@@ -52692,15 +53269,20 @@ function ChartEditor({
52692
53269
  const parentRef = (0, import_react55.useRef)(null);
52693
53270
  const [modalWidth, setModalWidth] = (0, import_react55.useState)(200);
52694
53271
  const [modalHeight, setModalHeight] = (0, import_react55.useState)(200);
52695
- const { addReport } = useDashboardReports(destinationDashboard);
52696
53272
  const { allReportsById } = useAllReports();
53273
+ const report = allReportsById[reportId];
53274
+ const resolvedDashboard = (0, import_react55.useMemo)(
53275
+ () => destinationDashboard ?? report?.dashboardName ?? null,
53276
+ [destinationDashboard, report?.dashboardName]
53277
+ );
53278
+ const { addReport } = useDashboardReports(resolvedDashboard ?? void 0);
52697
53279
  const { tenants, flags } = (0, import_react55.useContext)(TenantContext);
52698
53280
  const { getToken } = (0, import_react55.useContext)(FetchContext);
52699
- const report = allReportsById[reportId];
52700
53281
  const [client, isClientLoading] = (0, import_react55.useContext)(ClientContext);
52701
53282
  const [schemaData] = (0, import_react55.useContext)(SchemaDataContext);
52702
53283
  const { dashboardFilters } = (0, import_react55.useContext)(DashboardFiltersContext);
52703
53284
  const { eventTracking } = (0, import_react55.useContext)(EventTrackingContext);
53285
+ const { reload } = useDashboardInternal(resolvedDashboard);
52704
53286
  const specificDashboardFilters = (0, import_react55.useMemo)(() => {
52705
53287
  if (!report) {
52706
53288
  return [];
@@ -52708,7 +53290,7 @@ function ChartEditor({
52708
53290
  return Object.values(dashboardFilters[report.dashboardName] || {}).map(
52709
53291
  (f) => f.filter
52710
53292
  );
52711
- }, [dashboardFilters]);
53293
+ }, [dashboardFilters, report?.dashboardName]);
52712
53294
  const [filtersEnabled, setFiltersEnabled] = (0, import_react55.useState)(true);
52713
53295
  const [chartBuilderKey, setChartBuilderKey] = (0, import_react55.useState)(0);
52714
53296
  const dateFilter = Object.values(specificDashboardFilters).find(
@@ -52734,7 +53316,7 @@ function ChartEditor({
52734
53316
  };
52735
53317
  }, []);
52736
53318
  const fetchReportHelper = async (processing) => {
52737
- if (!client) {
53319
+ if (!client || !reportId) {
52738
53320
  return;
52739
53321
  }
52740
53322
  const minimalFilters = Object.values(specificDashboardFilters).length ? Object.values(specificDashboardFilters).map((filter) => {
@@ -52766,10 +53348,13 @@ function ChartEditor({
52766
53348
  addReport(report2);
52767
53349
  };
52768
53350
  (0, import_react55.useEffect)(() => {
53351
+ if (!isOpen || !reportId) {
53352
+ return;
53353
+ }
52769
53354
  if (!isClientLoading && !report) {
52770
53355
  fetchReportHelper();
52771
53356
  }
52772
- }, [reportId, isClientLoading, allReportsById]);
53357
+ }, [reportId, isClientLoading, allReportsById, isOpen]);
52773
53358
  return /* @__PURE__ */ (0, import_jsx_runtime82.jsx)("div", { ref: parentRef, style: { height: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
52774
53359
  ModalComponent,
52775
53360
  {
@@ -52783,7 +53368,7 @@ function ChartEditor({
52783
53368
  title: chartBuilderTitle || "Add to dashboard",
52784
53369
  width: isHorizontalView ? modalWidth : void 0,
52785
53370
  height: isHorizontalView ? modalHeight : void 0,
52786
- children: allReportsById[reportId] ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
53371
+ children: reportId && allReportsById[reportId] ? /* @__PURE__ */ (0, import_jsx_runtime82.jsx)(
52787
53372
  ChartBuilder,
52788
53373
  {
52789
53374
  reportId,
@@ -52798,8 +53383,15 @@ function ChartEditor({
52798
53383
  } else if (onAddToDashboardComplete) {
52799
53384
  onAddToDashboardComplete(data);
52800
53385
  }
53386
+ const targetDashboard = data?.dashboardName ?? resolvedDashboard;
53387
+ if (targetDashboard) {
53388
+ reload(targetDashboard, true, {
53389
+ report: data,
53390
+ action: "upsert"
53391
+ });
53392
+ }
52801
53393
  },
52802
- destinationDashboard,
53394
+ destinationDashboard: resolvedDashboard ?? void 0,
52803
53395
  destinationSection,
52804
53396
  dateRange,
52805
53397
  SelectComponent,