@quillsql/react 2.16.101 → 2.16.102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.cjs +414 -23
  2. package/dist/index.js +414 -23
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -23368,7 +23368,7 @@ async function fetchReportRows({
23368
23368
  additionalProcessing,
23369
23369
  overwriteCache = false
23370
23370
  }) {
23371
- const startedAt = performance.now();
23371
+ const startedAt2 = performance.now();
23372
23372
  profileDashboard("raw-report-rows-fetch-start", { reportId });
23373
23373
  const fetchResp = await quillFetch({
23374
23374
  client,
@@ -23389,7 +23389,7 @@ async function fetchReportRows({
23389
23389
  const resp = await parseFetchResponse(client, "report", fetchResp, getToken);
23390
23390
  profileDashboard("raw-report-rows-fetch-finish", {
23391
23391
  reportId,
23392
- elapsedMs: Math.round(performance.now() - startedAt),
23392
+ elapsedMs: Math.round(performance.now() - startedAt2),
23393
23393
  rowCount: resp.rows?.length ?? 0
23394
23394
  });
23395
23395
  if (client.databaseType?.toLowerCase() === "bigquery") {
@@ -23427,7 +23427,7 @@ async function fetchReport({
23427
23427
  }) {
23428
23428
  let reportInfo = void 0;
23429
23429
  let errorMessage = void 0;
23430
- const startedAt = performance.now();
23430
+ const startedAt2 = performance.now();
23431
23431
  try {
23432
23432
  const task = usePivotTask ? "pivot-template" : useReportTask ? "report" : "item";
23433
23433
  profileDashboard("fetch-report-start", {
@@ -23482,7 +23482,7 @@ async function fetchReport({
23482
23482
  profileDashboard("fetch-report-response", {
23483
23483
  reportId: reportId ?? null,
23484
23484
  task,
23485
- elapsedMs: Math.round(performance.now() - startedAt),
23485
+ elapsedMs: Math.round(performance.now() - startedAt2),
23486
23486
  hasRows: !!resp?.rows,
23487
23487
  rowCount: resp?.rows?.length ?? 0,
23488
23488
  hasFields: !!resp?.fields,
@@ -23507,7 +23507,7 @@ async function fetchReport({
23507
23507
  profileDashboard("fetch-report-processed", {
23508
23508
  reportId: reportId ?? null,
23509
23509
  task,
23510
- elapsedMs: Math.round(performance.now() - startedAt),
23510
+ elapsedMs: Math.round(performance.now() - startedAt2),
23511
23511
  rowCount: reportInfo.rows?.length ?? 0,
23512
23512
  pivotRowCount: reportInfo.pivotRows?.length ?? 0
23513
23513
  });
@@ -23736,6 +23736,15 @@ async function saveReport({
23736
23736
  }
23737
23737
  return data;
23738
23738
  }
23739
+ function isPlainNumericCellValue(value) {
23740
+ if (value === null || value === void 0 || value === "") return true;
23741
+ if (typeof value === "number") return Number.isFinite(value);
23742
+ if (typeof value === "bigint") return true;
23743
+ if (typeof value !== "string") return false;
23744
+ const trimmed = value.trim();
23745
+ if (!trimmed) return true;
23746
+ return /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i.test(trimmed);
23747
+ }
23739
23748
  var formatRowsFromReport = (report, xAxisField, xAxisFormat) => {
23740
23749
  if (!report.rows || !report.columns) {
23741
23750
  return [];
@@ -23763,6 +23772,10 @@ var formatRowsFromReport = (report, xAxisField, xAxisFormat) => {
23763
23772
  const formattedRow = {};
23764
23773
  for (const column of resolvedColumns) {
23765
23774
  const rawValue = row[column.field];
23775
+ if (NUMBER_FORMAT_TYPES.includes(String(column.format ?? "")) && !isPlainNumericCellValue(rawValue)) {
23776
+ formattedRow[column.field] = rawValue === null || rawValue === void 0 || rawValue === "" ? "-" : String(rawValue);
23777
+ continue;
23778
+ }
23766
23779
  formattedRow[column.field] = column.inferFormat ? quillAutoFormat(rawValue) : getFormattedWithCache(column.format, rawValue);
23767
23780
  }
23768
23781
  return formattedRow;
@@ -39693,7 +39706,7 @@ var ChartDataLoader = ({
39693
39706
  }
39694
39707
  const fetchRowsRequestId = rowsRequestId.current + 1;
39695
39708
  rowsRequestId.current = fetchRowsRequestId;
39696
- const startedAt = performance.now();
39709
+ const startedAt2 = performance.now();
39697
39710
  profileDashboard("chart-data-loader-fetch-start", {
39698
39711
  reportId: item.id,
39699
39712
  requestId: fetchRowsRequestId,
@@ -39839,7 +39852,7 @@ var ChartDataLoader = ({
39839
39852
  reportId: item.id,
39840
39853
  requestId: fetchRowsRequestId,
39841
39854
  reason,
39842
- elapsedMs: Math.round(performance.now() - startedAt),
39855
+ elapsedMs: Math.round(performance.now() - startedAt2),
39843
39856
  isLatestRequest: fetchRowsRequestId === rowsRequestId.current,
39844
39857
  startsBackgroundFetch: !!backgroundFetch
39845
39858
  });
@@ -62391,6 +62404,345 @@ function resolveReportFromCacheCab({
62391
62404
 
62392
62405
  // src/hooks/useForm.tsx
62393
62406
  init_dashboardProfiler();
62407
+
62408
+ // src/hooks/useReport.nanPivotDiag.ts
62409
+ init_valueFormatter();
62410
+ var NAN_PIVOT_DEBUG_FLAG = "__QUILL_DEBUG_NAN_PIVOT__";
62411
+ var NAN_PIVOT_LOG_FLAG = "__QUILL_NAN_PIVOT_LOG__";
62412
+ var startedAt = Date.now();
62413
+ function globalRecord() {
62414
+ return globalThis;
62415
+ }
62416
+ function isNanPivotDebugEnabled() {
62417
+ const globalValue = globalRecord()[NAN_PIVOT_DEBUG_FLAG];
62418
+ if (globalValue === true) return true;
62419
+ if (typeof process !== "undefined" && typeof process.env !== "undefined") {
62420
+ const envValue = String(process.env.QUILL_DEBUG_NAN_PIVOT ?? "").trim().toLowerCase();
62421
+ return envValue === "1" || envValue === "true";
62422
+ }
62423
+ return false;
62424
+ }
62425
+ function getNanPivotLog() {
62426
+ const log = globalRecord()[NAN_PIVOT_LOG_FLAG];
62427
+ return Array.isArray(log) ? log : [];
62428
+ }
62429
+ function findNanValues(value, path = "root") {
62430
+ if (typeof value === "number" && Number.isNaN(value)) {
62431
+ return [`${path}=NaN`];
62432
+ }
62433
+ if (typeof value === "string" && /^[-+]?NaN(?:%|\s*)$/i.test(value.trim())) {
62434
+ return [`${path}=${JSON.stringify(value)}`];
62435
+ }
62436
+ if (Array.isArray(value)) {
62437
+ return value.flatMap(
62438
+ (entry, index) => findNanValues(entry, `${path}[${index}]`)
62439
+ );
62440
+ }
62441
+ if (value && typeof value === "object") {
62442
+ return Object.entries(value).flatMap(
62443
+ ([key, entry]) => findNanValues(entry, `${path}.${key}`)
62444
+ );
62445
+ }
62446
+ return [];
62447
+ }
62448
+ function pivotKindOf(pivot) {
62449
+ if (pivot == null) return "none";
62450
+ if (typeof pivot !== "object") return "none";
62451
+ const value = pivot;
62452
+ const rowField = String(value.rowField ?? "").trim();
62453
+ const columnField = String(value.columnField ?? "").trim();
62454
+ const hasAggregation = Array.isArray(value.aggregations) && value.aggregations.length > 0 || Boolean(String(value.aggregationType ?? "").trim());
62455
+ if (rowField && columnField) return "2D";
62456
+ if (rowField || columnField) return "1D";
62457
+ if (hasAggregation) return "aggregation-only";
62458
+ return "empty-object";
62459
+ }
62460
+ function reportDetailSurfaceOf(chart) {
62461
+ if (!chart || typeof chart !== "object") return "none";
62462
+ const value = chart;
62463
+ const chartType = String(value.chartType ?? "").trim().toLowerCase();
62464
+ if (chartType !== "table") {
62465
+ return "chart-display-chart";
62466
+ }
62467
+ const isPivotTable = Boolean(value.pivot) && Array.isArray(value.columns) && value.columns.length > 0;
62468
+ return isPivotTable ? "chart-display-pivot-table" : "flat-table";
62469
+ }
62470
+ function columnFormats(columns) {
62471
+ if (!Array.isArray(columns)) return [];
62472
+ return columns.map((column) => {
62473
+ const value = column ?? {};
62474
+ return {
62475
+ field: String(value.field ?? ""),
62476
+ label: String(value.label ?? ""),
62477
+ format: String(value.format ?? "")
62478
+ };
62479
+ });
62480
+ }
62481
+ function sampleRows(rows, count = 2) {
62482
+ return Array.isArray(rows) ? rows.slice(0, count) : [];
62483
+ }
62484
+ function hitsFor(surface, value) {
62485
+ return findNanValues(value).map((path) => ({ surface, path }));
62486
+ }
62487
+ function looksNumeric(value) {
62488
+ if (typeof value === "number") return Number.isFinite(value);
62489
+ if (typeof value !== "string") return false;
62490
+ const trimmed = value.trim();
62491
+ if (!trimmed) return false;
62492
+ return Number.isFinite(Number(trimmed.replace(/,/g, "")));
62493
+ }
62494
+ function alreadyGroupedNumberString(value) {
62495
+ return typeof value === "string" && /^-?\d{1,3}(?:,\d{3})+(?:\.\d+)?$/.test(value.trim());
62496
+ }
62497
+ function formatRowsAsChartDisplay(chart, rows, columns) {
62498
+ if (!Array.isArray(rows) || rows.length === 0) return [];
62499
+ const value = chart ?? {};
62500
+ try {
62501
+ return formatRowsFromReport(
62502
+ {
62503
+ ...value,
62504
+ rows,
62505
+ columns: Array.isArray(columns) ? columns : [],
62506
+ pivot: chart?.pivot
62507
+ },
62508
+ value.xAxisField,
62509
+ value.xAxisFormat
62510
+ );
62511
+ } catch {
62512
+ return [];
62513
+ }
62514
+ }
62515
+ function formatMismatchesFor(columns, rows) {
62516
+ if (!Array.isArray(rows) || rows.length === 0) return [];
62517
+ const mismatches = [];
62518
+ for (const column of columns) {
62519
+ if (!NUMBER_FORMAT_TYPES.includes(column.format)) continue;
62520
+ for (let index = 0; index < Math.min(rows.length, 8); index += 1) {
62521
+ const row = rows[index];
62522
+ if (!row || typeof row !== "object") continue;
62523
+ const cell = row[column.field];
62524
+ if (cell == null || cell === "") continue;
62525
+ if (looksNumeric(cell)) continue;
62526
+ mismatches.push(
62527
+ `${column.field} format=${column.format} row[${index}]=${JSON.stringify(cell)}`
62528
+ );
62529
+ break;
62530
+ }
62531
+ }
62532
+ return mismatches;
62533
+ }
62534
+ function chartDisplayRows(chart) {
62535
+ if (!chart || typeof chart !== "object") return [];
62536
+ const value = chart;
62537
+ if (String(value.chartType ?? "").toLowerCase() !== "table") {
62538
+ return Array.isArray(value.rows) ? value.rows : [];
62539
+ }
62540
+ const tableColumns = value.includeCustomFields && value.columnsWithCustomFields && !value.pivot ? value.columnsWithCustomFields : value.columns ?? value.yAxisFields ?? [];
62541
+ try {
62542
+ return formatRowsFromReport(
62543
+ { ...value, rows: value.rows ?? [], columns: tableColumns },
62544
+ value.xAxisField,
62545
+ value.xAxisFormat
62546
+ );
62547
+ } catch {
62548
+ return [];
62549
+ }
62550
+ }
62551
+ function pivotFieldHits(pivot) {
62552
+ if (!pivot || typeof pivot !== "object") return [];
62553
+ return hitsFor("pivotFields", {
62554
+ rowField: pivot.rowField,
62555
+ columnField: pivot.columnField,
62556
+ rowFieldTable: pivot.rowFieldTable,
62557
+ columnFieldTable: pivot.columnFieldTable
62558
+ });
62559
+ }
62560
+ function jsonSafe(value) {
62561
+ try {
62562
+ return JSON.parse(
62563
+ JSON.stringify(value, (_key, current) => {
62564
+ if (typeof current === "number" && Number.isNaN(current)) {
62565
+ return "__NaN__";
62566
+ }
62567
+ if (current === void 0) return "__undefined__";
62568
+ return current;
62569
+ })
62570
+ );
62571
+ } catch {
62572
+ return value;
62573
+ }
62574
+ }
62575
+ function snapshotUseReportNanState(input) {
62576
+ const chart = input.chart ?? null;
62577
+ const table = input.table ?? null;
62578
+ const sourceReport = input.sourceReport ?? null;
62579
+ const chartType = String(chart?.chartType ?? input.chartType ?? "").trim();
62580
+ const tableColumns = columnFormats(table?.columns);
62581
+ const chartColumns = columnFormats(chart?.columns);
62582
+ const tableRows = Array.isArray(table?.rows) ? table.rows : [];
62583
+ const chartRows = Array.isArray(chart?.rows) ? chart.rows : [];
62584
+ const pivotRows = Array.isArray(chart?.pivotRows) ? chart.pivotRows : [];
62585
+ const sourceRows = Array.isArray(sourceReport?.rows) ? sourceReport.rows : [];
62586
+ const sourcePivotRows = Array.isArray(sourceReport?.pivotRows) ? sourceReport.pivotRows : [];
62587
+ const displayRows = chartDisplayRows(chart);
62588
+ const doubleFormatRows = formatRowsAsChartDisplay(
62589
+ chart,
62590
+ tableRows,
62591
+ table?.columns ?? chart?.columns
62592
+ );
62593
+ const formPivot = input.formPivot ?? null;
62594
+ const nextPivot = input.nextPivot ?? null;
62595
+ const sourcePivot = sourceReport?.pivot ?? null;
62596
+ const chartPivot = chart?.pivot ?? null;
62597
+ const kind = pivotKindOf(chartPivot ?? nextPivot ?? formPivot ?? sourcePivot);
62598
+ const groupRowsBy = String(input.groupRowsBy ?? "").trim() || null;
62599
+ const groupColumnsBy = String(input.groupColumnsBy ?? "").trim() || null;
62600
+ const hasFormPivotSelection = Boolean(
62601
+ groupRowsBy || groupColumnsBy || Array.isArray(input.aggregations) && input.aggregations.some((value) => String(value ?? "").trim())
62602
+ );
62603
+ const unexpectedPivot = !hasFormPivotSelection && (kind === "1D" || kind === "2D" || kind === "aggregation-only" || kind === "empty-object");
62604
+ const nanHits = [
62605
+ ...hitsFor("useReport.table", tableRows),
62606
+ ...hitsFor("useReport.chart.rows", chartRows),
62607
+ ...hitsFor("useReport.chart.pivotRows", pivotRows),
62608
+ ...hitsFor("sourceReport.rows", sourceRows),
62609
+ ...hitsFor("sourceReport.pivotRows", sourcePivotRows),
62610
+ ...hitsFor("chartDisplay.formattedRows", displayRows),
62611
+ ...hitsFor("chartDisplay.doubleFormatTableRows", doubleFormatRows),
62612
+ ...hitsFor("columnLabels", [
62613
+ ...tableColumns.map((column) => column.label),
62614
+ ...chartColumns.map((column) => column.label)
62615
+ ]),
62616
+ ...hitsFor("columnFields", [
62617
+ ...tableColumns.map((column) => column.field),
62618
+ ...chartColumns.map((column) => column.field)
62619
+ ]),
62620
+ ...pivotFieldHits(chartPivot),
62621
+ ...pivotFieldHits(formPivot),
62622
+ ...pivotFieldHits(sourcePivot)
62623
+ ];
62624
+ return {
62625
+ at: (/* @__PURE__ */ new Date()).toISOString(),
62626
+ atMs: Date.now() - startedAt,
62627
+ source: input.source ?? "useReport",
62628
+ flow: input.flow,
62629
+ step: input.step,
62630
+ reportId: String(input.reportId ?? ""),
62631
+ datasources: Array.isArray(input.datasources) ? input.datasources.map((value) => String(value)) : [],
62632
+ chartType,
62633
+ chartLoading: Boolean(input.chartLoading),
62634
+ tableLoading: Boolean(input.tableLoading),
62635
+ loading: Boolean(input.loading),
62636
+ groupRowsBy,
62637
+ groupColumnsBy,
62638
+ aggregations: input.aggregations ?? [],
62639
+ formPivot,
62640
+ nextPivot,
62641
+ sourcePivot,
62642
+ chartPivot,
62643
+ pivotKind: kind,
62644
+ unexpectedPivot,
62645
+ isPivotTableChart: Boolean(input.isPivotTableChart),
62646
+ reportDetailSurface: reportDetailSurfaceOf(chart),
62647
+ tableColumnFormats: tableColumns,
62648
+ chartColumnFormats: chartColumns,
62649
+ tableRowCount: tableRows.length,
62650
+ chartRowCount: chartRows.length,
62651
+ pivotRowCount: pivotRows.length,
62652
+ tableSample: sampleRows(tableRows),
62653
+ chartRowSample: sampleRows(chartRows),
62654
+ pivotRowSample: sampleRows(pivotRows),
62655
+ chartDisplaySample: sampleRows(displayRows),
62656
+ doubleFormatSample: sampleRows(doubleFormatRows),
62657
+ formatMismatches: [
62658
+ ...formatMismatchesFor(tableColumns, sourceRows.length ? sourceRows : tableRows),
62659
+ ...formatMismatchesFor(chartColumns, chartRows.length ? chartRows : pivotRows),
62660
+ ...tableRows.flatMap((row, index) => {
62661
+ if (!row || typeof row !== "object") return [];
62662
+ return tableColumns.filter(
62663
+ (column) => NUMBER_FORMAT_TYPES.includes(column.format) && alreadyGroupedNumberString(
62664
+ row[column.field]
62665
+ )
62666
+ ).map(
62667
+ (column) => `already-formatted ${column.field} row[${index}]=${JSON.stringify(
62668
+ row[column.field]
62669
+ )}`
62670
+ );
62671
+ })
62672
+ ],
62673
+ nanHits
62674
+ };
62675
+ }
62676
+ var lastSerializedBySource = /* @__PURE__ */ new Map();
62677
+ function recordUseReportNanPivotState(input) {
62678
+ if (!isNanPivotDebugEnabled()) return null;
62679
+ const snapshot = snapshotUseReportNanState(input);
62680
+ const key = `${snapshot.source}:${snapshot.flow ?? ""}:${snapshot.reportId}`;
62681
+ const serialized = JSON.stringify(jsonSafe(snapshot));
62682
+ if (lastSerializedBySource.get(key) === serialized) {
62683
+ return snapshot;
62684
+ }
62685
+ lastSerializedBySource.set(key, serialized);
62686
+ const log = getNanPivotLog();
62687
+ log.push(snapshot);
62688
+ globalRecord()[NAN_PIVOT_LOG_FLAG] = log;
62689
+ const liveHits = snapshot.nanHits.filter(
62690
+ (hit) => hit.surface !== "chartDisplay.doubleFormatTableRows"
62691
+ );
62692
+ const compact = {
62693
+ atMs: snapshot.atMs,
62694
+ source: snapshot.source,
62695
+ flow: snapshot.flow,
62696
+ step: snapshot.step,
62697
+ reportId: snapshot.reportId,
62698
+ datasources: snapshot.datasources,
62699
+ chartType: snapshot.chartType,
62700
+ loading: snapshot.loading,
62701
+ chartLoading: snapshot.chartLoading,
62702
+ tableLoading: snapshot.tableLoading,
62703
+ groupRowsBy: snapshot.groupRowsBy,
62704
+ groupColumnsBy: snapshot.groupColumnsBy,
62705
+ pivotKind: snapshot.pivotKind,
62706
+ unexpectedPivot: snapshot.unexpectedPivot,
62707
+ isPivotTableChart: snapshot.isPivotTableChart,
62708
+ reportDetailSurface: snapshot.reportDetailSurface,
62709
+ tableRowCount: snapshot.tableRowCount,
62710
+ chartRowCount: snapshot.chartRowCount,
62711
+ pivotRowCount: snapshot.pivotRowCount,
62712
+ formatMismatches: snapshot.formatMismatches.slice(0, 8),
62713
+ nanHits: snapshot.nanHits.slice(0, 12)
62714
+ };
62715
+ if (liveHits.length > 0 || snapshot.unexpectedPivot) {
62716
+ console.log(
62717
+ "[useReport][nan-pivot][hit]",
62718
+ JSON.stringify(
62719
+ jsonSafe({
62720
+ ...compact,
62721
+ tableSample: snapshot.tableSample,
62722
+ chartRowSample: snapshot.chartRowSample,
62723
+ pivotRowSample: snapshot.pivotRowSample,
62724
+ chartDisplaySample: snapshot.chartDisplaySample,
62725
+ doubleFormatSample: snapshot.doubleFormatSample,
62726
+ formPivot: snapshot.formPivot,
62727
+ chartPivot: snapshot.chartPivot,
62728
+ sourcePivot: snapshot.sourcePivot
62729
+ }),
62730
+ null,
62731
+ 2
62732
+ )
62733
+ );
62734
+ } else if (snapshot.nanHits.length > 0) {
62735
+ console.log(
62736
+ "[useReport][nan-pivot][double-format]",
62737
+ JSON.stringify(compact)
62738
+ );
62739
+ } else {
62740
+ console.log("[useReport][nan-pivot][state]", JSON.stringify(compact));
62741
+ }
62742
+ return snapshot;
62743
+ }
62744
+
62745
+ // src/hooks/useForm.tsx
62394
62746
  init_reportRequestPool();
62395
62747
 
62396
62748
  // src/hooks/useForm.queries.ts
@@ -66598,7 +66950,7 @@ function useReport(reportIdArg, options = {}) {
66598
66950
  pivot,
66599
66951
  operation
66600
66952
  }) => {
66601
- const startedAt = performance.now();
66953
+ const startedAt2 = performance.now();
66602
66954
  const snapshot = await cacheCab.getReportSnapshot(
66603
66955
  effectiveReportId,
66604
66956
  tenants
@@ -66617,7 +66969,7 @@ function useReport(reportIdArg, options = {}) {
66617
66969
  )
66618
66970
  });
66619
66971
  const diagnostics = globalThis.__QUILL_CACHECAB_DIAGNOSTICS__;
66620
- const durationMs = performance.now() - startedAt;
66972
+ const durationMs = performance.now() - startedAt2;
66621
66973
  const outcome = resolution.resolved ? "hit" : "fallback";
66622
66974
  if (Array.isArray(diagnostics)) {
66623
66975
  diagnostics.push({
@@ -69605,11 +69957,12 @@ function useReport(reportIdArg, options = {}) {
69605
69957
  registerOption(column.field, column.label, column.format);
69606
69958
  }
69607
69959
  for (const yAxis2 of yAxisResolved.measures) {
69608
- registerOption(yAxis2.field, yAxis2.label, yAxis2.format);
69960
+ const field = String(yAxis2.field ?? "").trim();
69961
+ registerOption(field, field, yAxis2.format);
69609
69962
  if (yAxis2.format) {
69610
- const existing = optionsByField.get(yAxis2.field);
69963
+ const existing = optionsByField.get(field);
69611
69964
  if (existing) {
69612
- optionsByField.set(yAxis2.field, {
69965
+ optionsByField.set(field, {
69613
69966
  ...existing,
69614
69967
  format: toAxisFormat(yAxis2.format, existing.format)
69615
69968
  });
@@ -69686,12 +70039,17 @@ function useReport(reportIdArg, options = {}) {
69686
70039
  ];
69687
70040
  }, [chartAxisOptions, yAxisResolved.measures]);
69688
70041
  const yAxisOptions = (0, import_react63.useMemo)(
69689
- () => yAxisMeasures.map((measure) => ({
69690
- value: measure.field,
69691
- label: measure.label,
69692
- format: toAxisFormat(measure.format, "string")
69693
- })),
69694
- [yAxisMeasures]
70042
+ () => yAxisMeasures.map((measure) => {
70043
+ const field = String(measure.field ?? "").trim();
70044
+ const catalog = chartAxisOptionByField.get(field);
70045
+ if (catalog) return catalog;
70046
+ return {
70047
+ value: field,
70048
+ label: toTitleCaseLabel(field),
70049
+ format: toAxisFormat(measure.format, "string")
70050
+ };
70051
+ }),
70052
+ [chartAxisOptionByField, yAxisMeasures]
69695
70053
  );
69696
70054
  const normalizedChartYAxisOptions = (0, import_react63.useMemo)(() => {
69697
70055
  return yAxisOptions.map((option) => ({
@@ -70031,11 +70389,7 @@ function useReport(reportIdArg, options = {}) {
70031
70389
  );
70032
70390
  const isPivotTableChart = String(chartType ?? "").toLowerCase() === "table" && Boolean(pivotState);
70033
70391
  const pivotTableColumns = (0, import_react63.useMemo)(
70034
- () => isPivotTableChart ? buildPivotTableColumns(
70035
- pivotState,
70036
- chart,
70037
- resolveTableDisplayLabel
70038
- ) : null,
70392
+ () => isPivotTableChart ? buildPivotTableColumns(pivotState, chart, resolveTableDisplayLabel) : null,
70039
70393
  [chart, isPivotTableChart, pivotState, resolveTableDisplayLabel]
70040
70394
  );
70041
70395
  const chartAxes = (0, import_react63.useMemo)(() => {
@@ -70686,6 +71040,43 @@ function useReport(reportIdArg, options = {}) {
70686
71040
  tableRefreshQuery.isFetching,
70687
71041
  tableRefreshQueryEnabled
70688
71042
  ]);
71043
+ (0, import_react63.useEffect)(() => {
71044
+ if (!isNanPivotDebugEnabled()) return;
71045
+ recordUseReportNanPivotState({
71046
+ source: "useReport",
71047
+ reportId: effectiveReportId,
71048
+ datasources,
71049
+ chartType: resolvedChartType,
71050
+ chartLoading,
71051
+ tableLoading,
71052
+ loading,
71053
+ groupRowsBy,
71054
+ groupColumnsBy,
71055
+ aggregations: aggregationValues,
71056
+ formPivot: pivotState,
71057
+ nextPivot,
71058
+ sourceReport,
71059
+ chart: chartWithSort,
71060
+ table,
71061
+ isPivotTableChart
71062
+ });
71063
+ }, [
71064
+ aggregationValues,
71065
+ chartLoading,
71066
+ chartWithSort,
71067
+ datasources,
71068
+ effectiveReportId,
71069
+ groupColumnsBy,
71070
+ groupRowsBy,
71071
+ isPivotTableChart,
71072
+ loading,
71073
+ nextPivot,
71074
+ pivotState,
71075
+ resolvedChartType,
71076
+ sourceReport,
71077
+ table,
71078
+ tableLoading
71079
+ ]);
70689
71080
  const buildSetReportColumnsFromIds = (nextColumnIds, settingsById) => {
70690
71081
  const normalizedNextIds = nextColumnIds.map((columnId) => String(columnId ?? "").trim()).filter(Boolean);
70691
71082
  return normalizedNextIds.map((columnId) => {
package/dist/index.js CHANGED
@@ -23350,7 +23350,7 @@ async function fetchReportRows({
23350
23350
  additionalProcessing,
23351
23351
  overwriteCache = false
23352
23352
  }) {
23353
- const startedAt = performance.now();
23353
+ const startedAt2 = performance.now();
23354
23354
  profileDashboard("raw-report-rows-fetch-start", { reportId });
23355
23355
  const fetchResp = await quillFetch({
23356
23356
  client,
@@ -23371,7 +23371,7 @@ async function fetchReportRows({
23371
23371
  const resp = await parseFetchResponse(client, "report", fetchResp, getToken);
23372
23372
  profileDashboard("raw-report-rows-fetch-finish", {
23373
23373
  reportId,
23374
- elapsedMs: Math.round(performance.now() - startedAt),
23374
+ elapsedMs: Math.round(performance.now() - startedAt2),
23375
23375
  rowCount: resp.rows?.length ?? 0
23376
23376
  });
23377
23377
  if (client.databaseType?.toLowerCase() === "bigquery") {
@@ -23409,7 +23409,7 @@ async function fetchReport({
23409
23409
  }) {
23410
23410
  let reportInfo = void 0;
23411
23411
  let errorMessage = void 0;
23412
- const startedAt = performance.now();
23412
+ const startedAt2 = performance.now();
23413
23413
  try {
23414
23414
  const task = usePivotTask ? "pivot-template" : useReportTask ? "report" : "item";
23415
23415
  profileDashboard("fetch-report-start", {
@@ -23464,7 +23464,7 @@ async function fetchReport({
23464
23464
  profileDashboard("fetch-report-response", {
23465
23465
  reportId: reportId ?? null,
23466
23466
  task,
23467
- elapsedMs: Math.round(performance.now() - startedAt),
23467
+ elapsedMs: Math.round(performance.now() - startedAt2),
23468
23468
  hasRows: !!resp?.rows,
23469
23469
  rowCount: resp?.rows?.length ?? 0,
23470
23470
  hasFields: !!resp?.fields,
@@ -23489,7 +23489,7 @@ async function fetchReport({
23489
23489
  profileDashboard("fetch-report-processed", {
23490
23490
  reportId: reportId ?? null,
23491
23491
  task,
23492
- elapsedMs: Math.round(performance.now() - startedAt),
23492
+ elapsedMs: Math.round(performance.now() - startedAt2),
23493
23493
  rowCount: reportInfo.rows?.length ?? 0,
23494
23494
  pivotRowCount: reportInfo.pivotRows?.length ?? 0
23495
23495
  });
@@ -23718,6 +23718,15 @@ async function saveReport({
23718
23718
  }
23719
23719
  return data;
23720
23720
  }
23721
+ function isPlainNumericCellValue(value) {
23722
+ if (value === null || value === void 0 || value === "") return true;
23723
+ if (typeof value === "number") return Number.isFinite(value);
23724
+ if (typeof value === "bigint") return true;
23725
+ if (typeof value !== "string") return false;
23726
+ const trimmed = value.trim();
23727
+ if (!trimmed) return true;
23728
+ return /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i.test(trimmed);
23729
+ }
23721
23730
  var formatRowsFromReport = (report, xAxisField, xAxisFormat) => {
23722
23731
  if (!report.rows || !report.columns) {
23723
23732
  return [];
@@ -23745,6 +23754,10 @@ var formatRowsFromReport = (report, xAxisField, xAxisFormat) => {
23745
23754
  const formattedRow = {};
23746
23755
  for (const column of resolvedColumns) {
23747
23756
  const rawValue = row[column.field];
23757
+ if (NUMBER_FORMAT_TYPES.includes(String(column.format ?? "")) && !isPlainNumericCellValue(rawValue)) {
23758
+ formattedRow[column.field] = rawValue === null || rawValue === void 0 || rawValue === "" ? "-" : String(rawValue);
23759
+ continue;
23760
+ }
23748
23761
  formattedRow[column.field] = column.inferFormat ? quillAutoFormat(rawValue) : getFormattedWithCache(column.format, rawValue);
23749
23762
  }
23750
23763
  return formattedRow;
@@ -39780,7 +39793,7 @@ var ChartDataLoader = ({
39780
39793
  }
39781
39794
  const fetchRowsRequestId = rowsRequestId.current + 1;
39782
39795
  rowsRequestId.current = fetchRowsRequestId;
39783
- const startedAt = performance.now();
39796
+ const startedAt2 = performance.now();
39784
39797
  profileDashboard("chart-data-loader-fetch-start", {
39785
39798
  reportId: item.id,
39786
39799
  requestId: fetchRowsRequestId,
@@ -39926,7 +39939,7 @@ var ChartDataLoader = ({
39926
39939
  reportId: item.id,
39927
39940
  requestId: fetchRowsRequestId,
39928
39941
  reason,
39929
- elapsedMs: Math.round(performance.now() - startedAt),
39942
+ elapsedMs: Math.round(performance.now() - startedAt2),
39930
39943
  isLatestRequest: fetchRowsRequestId === rowsRequestId.current,
39931
39944
  startsBackgroundFetch: !!backgroundFetch
39932
39945
  });
@@ -62599,6 +62612,345 @@ function resolveReportFromCacheCab({
62599
62612
 
62600
62613
  // src/hooks/useForm.tsx
62601
62614
  init_dashboardProfiler();
62615
+
62616
+ // src/hooks/useReport.nanPivotDiag.ts
62617
+ init_valueFormatter();
62618
+ var NAN_PIVOT_DEBUG_FLAG = "__QUILL_DEBUG_NAN_PIVOT__";
62619
+ var NAN_PIVOT_LOG_FLAG = "__QUILL_NAN_PIVOT_LOG__";
62620
+ var startedAt = Date.now();
62621
+ function globalRecord() {
62622
+ return globalThis;
62623
+ }
62624
+ function isNanPivotDebugEnabled() {
62625
+ const globalValue = globalRecord()[NAN_PIVOT_DEBUG_FLAG];
62626
+ if (globalValue === true) return true;
62627
+ if (typeof process !== "undefined" && typeof process.env !== "undefined") {
62628
+ const envValue = String(process.env.QUILL_DEBUG_NAN_PIVOT ?? "").trim().toLowerCase();
62629
+ return envValue === "1" || envValue === "true";
62630
+ }
62631
+ return false;
62632
+ }
62633
+ function getNanPivotLog() {
62634
+ const log = globalRecord()[NAN_PIVOT_LOG_FLAG];
62635
+ return Array.isArray(log) ? log : [];
62636
+ }
62637
+ function findNanValues(value, path = "root") {
62638
+ if (typeof value === "number" && Number.isNaN(value)) {
62639
+ return [`${path}=NaN`];
62640
+ }
62641
+ if (typeof value === "string" && /^[-+]?NaN(?:%|\s*)$/i.test(value.trim())) {
62642
+ return [`${path}=${JSON.stringify(value)}`];
62643
+ }
62644
+ if (Array.isArray(value)) {
62645
+ return value.flatMap(
62646
+ (entry, index) => findNanValues(entry, `${path}[${index}]`)
62647
+ );
62648
+ }
62649
+ if (value && typeof value === "object") {
62650
+ return Object.entries(value).flatMap(
62651
+ ([key, entry]) => findNanValues(entry, `${path}.${key}`)
62652
+ );
62653
+ }
62654
+ return [];
62655
+ }
62656
+ function pivotKindOf(pivot) {
62657
+ if (pivot == null) return "none";
62658
+ if (typeof pivot !== "object") return "none";
62659
+ const value = pivot;
62660
+ const rowField = String(value.rowField ?? "").trim();
62661
+ const columnField = String(value.columnField ?? "").trim();
62662
+ const hasAggregation = Array.isArray(value.aggregations) && value.aggregations.length > 0 || Boolean(String(value.aggregationType ?? "").trim());
62663
+ if (rowField && columnField) return "2D";
62664
+ if (rowField || columnField) return "1D";
62665
+ if (hasAggregation) return "aggregation-only";
62666
+ return "empty-object";
62667
+ }
62668
+ function reportDetailSurfaceOf(chart) {
62669
+ if (!chart || typeof chart !== "object") return "none";
62670
+ const value = chart;
62671
+ const chartType = String(value.chartType ?? "").trim().toLowerCase();
62672
+ if (chartType !== "table") {
62673
+ return "chart-display-chart";
62674
+ }
62675
+ const isPivotTable = Boolean(value.pivot) && Array.isArray(value.columns) && value.columns.length > 0;
62676
+ return isPivotTable ? "chart-display-pivot-table" : "flat-table";
62677
+ }
62678
+ function columnFormats(columns) {
62679
+ if (!Array.isArray(columns)) return [];
62680
+ return columns.map((column) => {
62681
+ const value = column ?? {};
62682
+ return {
62683
+ field: String(value.field ?? ""),
62684
+ label: String(value.label ?? ""),
62685
+ format: String(value.format ?? "")
62686
+ };
62687
+ });
62688
+ }
62689
+ function sampleRows(rows, count = 2) {
62690
+ return Array.isArray(rows) ? rows.slice(0, count) : [];
62691
+ }
62692
+ function hitsFor(surface, value) {
62693
+ return findNanValues(value).map((path) => ({ surface, path }));
62694
+ }
62695
+ function looksNumeric(value) {
62696
+ if (typeof value === "number") return Number.isFinite(value);
62697
+ if (typeof value !== "string") return false;
62698
+ const trimmed = value.trim();
62699
+ if (!trimmed) return false;
62700
+ return Number.isFinite(Number(trimmed.replace(/,/g, "")));
62701
+ }
62702
+ function alreadyGroupedNumberString(value) {
62703
+ return typeof value === "string" && /^-?\d{1,3}(?:,\d{3})+(?:\.\d+)?$/.test(value.trim());
62704
+ }
62705
+ function formatRowsAsChartDisplay(chart, rows, columns) {
62706
+ if (!Array.isArray(rows) || rows.length === 0) return [];
62707
+ const value = chart ?? {};
62708
+ try {
62709
+ return formatRowsFromReport(
62710
+ {
62711
+ ...value,
62712
+ rows,
62713
+ columns: Array.isArray(columns) ? columns : [],
62714
+ pivot: chart?.pivot
62715
+ },
62716
+ value.xAxisField,
62717
+ value.xAxisFormat
62718
+ );
62719
+ } catch {
62720
+ return [];
62721
+ }
62722
+ }
62723
+ function formatMismatchesFor(columns, rows) {
62724
+ if (!Array.isArray(rows) || rows.length === 0) return [];
62725
+ const mismatches = [];
62726
+ for (const column of columns) {
62727
+ if (!NUMBER_FORMAT_TYPES.includes(column.format)) continue;
62728
+ for (let index = 0; index < Math.min(rows.length, 8); index += 1) {
62729
+ const row = rows[index];
62730
+ if (!row || typeof row !== "object") continue;
62731
+ const cell = row[column.field];
62732
+ if (cell == null || cell === "") continue;
62733
+ if (looksNumeric(cell)) continue;
62734
+ mismatches.push(
62735
+ `${column.field} format=${column.format} row[${index}]=${JSON.stringify(cell)}`
62736
+ );
62737
+ break;
62738
+ }
62739
+ }
62740
+ return mismatches;
62741
+ }
62742
+ function chartDisplayRows(chart) {
62743
+ if (!chart || typeof chart !== "object") return [];
62744
+ const value = chart;
62745
+ if (String(value.chartType ?? "").toLowerCase() !== "table") {
62746
+ return Array.isArray(value.rows) ? value.rows : [];
62747
+ }
62748
+ const tableColumns = value.includeCustomFields && value.columnsWithCustomFields && !value.pivot ? value.columnsWithCustomFields : value.columns ?? value.yAxisFields ?? [];
62749
+ try {
62750
+ return formatRowsFromReport(
62751
+ { ...value, rows: value.rows ?? [], columns: tableColumns },
62752
+ value.xAxisField,
62753
+ value.xAxisFormat
62754
+ );
62755
+ } catch {
62756
+ return [];
62757
+ }
62758
+ }
62759
+ function pivotFieldHits(pivot) {
62760
+ if (!pivot || typeof pivot !== "object") return [];
62761
+ return hitsFor("pivotFields", {
62762
+ rowField: pivot.rowField,
62763
+ columnField: pivot.columnField,
62764
+ rowFieldTable: pivot.rowFieldTable,
62765
+ columnFieldTable: pivot.columnFieldTable
62766
+ });
62767
+ }
62768
+ function jsonSafe(value) {
62769
+ try {
62770
+ return JSON.parse(
62771
+ JSON.stringify(value, (_key, current) => {
62772
+ if (typeof current === "number" && Number.isNaN(current)) {
62773
+ return "__NaN__";
62774
+ }
62775
+ if (current === void 0) return "__undefined__";
62776
+ return current;
62777
+ })
62778
+ );
62779
+ } catch {
62780
+ return value;
62781
+ }
62782
+ }
62783
+ function snapshotUseReportNanState(input) {
62784
+ const chart = input.chart ?? null;
62785
+ const table = input.table ?? null;
62786
+ const sourceReport = input.sourceReport ?? null;
62787
+ const chartType = String(chart?.chartType ?? input.chartType ?? "").trim();
62788
+ const tableColumns = columnFormats(table?.columns);
62789
+ const chartColumns = columnFormats(chart?.columns);
62790
+ const tableRows = Array.isArray(table?.rows) ? table.rows : [];
62791
+ const chartRows = Array.isArray(chart?.rows) ? chart.rows : [];
62792
+ const pivotRows = Array.isArray(chart?.pivotRows) ? chart.pivotRows : [];
62793
+ const sourceRows = Array.isArray(sourceReport?.rows) ? sourceReport.rows : [];
62794
+ const sourcePivotRows = Array.isArray(sourceReport?.pivotRows) ? sourceReport.pivotRows : [];
62795
+ const displayRows = chartDisplayRows(chart);
62796
+ const doubleFormatRows = formatRowsAsChartDisplay(
62797
+ chart,
62798
+ tableRows,
62799
+ table?.columns ?? chart?.columns
62800
+ );
62801
+ const formPivot = input.formPivot ?? null;
62802
+ const nextPivot = input.nextPivot ?? null;
62803
+ const sourcePivot = sourceReport?.pivot ?? null;
62804
+ const chartPivot = chart?.pivot ?? null;
62805
+ const kind = pivotKindOf(chartPivot ?? nextPivot ?? formPivot ?? sourcePivot);
62806
+ const groupRowsBy = String(input.groupRowsBy ?? "").trim() || null;
62807
+ const groupColumnsBy = String(input.groupColumnsBy ?? "").trim() || null;
62808
+ const hasFormPivotSelection = Boolean(
62809
+ groupRowsBy || groupColumnsBy || Array.isArray(input.aggregations) && input.aggregations.some((value) => String(value ?? "").trim())
62810
+ );
62811
+ const unexpectedPivot = !hasFormPivotSelection && (kind === "1D" || kind === "2D" || kind === "aggregation-only" || kind === "empty-object");
62812
+ const nanHits = [
62813
+ ...hitsFor("useReport.table", tableRows),
62814
+ ...hitsFor("useReport.chart.rows", chartRows),
62815
+ ...hitsFor("useReport.chart.pivotRows", pivotRows),
62816
+ ...hitsFor("sourceReport.rows", sourceRows),
62817
+ ...hitsFor("sourceReport.pivotRows", sourcePivotRows),
62818
+ ...hitsFor("chartDisplay.formattedRows", displayRows),
62819
+ ...hitsFor("chartDisplay.doubleFormatTableRows", doubleFormatRows),
62820
+ ...hitsFor("columnLabels", [
62821
+ ...tableColumns.map((column) => column.label),
62822
+ ...chartColumns.map((column) => column.label)
62823
+ ]),
62824
+ ...hitsFor("columnFields", [
62825
+ ...tableColumns.map((column) => column.field),
62826
+ ...chartColumns.map((column) => column.field)
62827
+ ]),
62828
+ ...pivotFieldHits(chartPivot),
62829
+ ...pivotFieldHits(formPivot),
62830
+ ...pivotFieldHits(sourcePivot)
62831
+ ];
62832
+ return {
62833
+ at: (/* @__PURE__ */ new Date()).toISOString(),
62834
+ atMs: Date.now() - startedAt,
62835
+ source: input.source ?? "useReport",
62836
+ flow: input.flow,
62837
+ step: input.step,
62838
+ reportId: String(input.reportId ?? ""),
62839
+ datasources: Array.isArray(input.datasources) ? input.datasources.map((value) => String(value)) : [],
62840
+ chartType,
62841
+ chartLoading: Boolean(input.chartLoading),
62842
+ tableLoading: Boolean(input.tableLoading),
62843
+ loading: Boolean(input.loading),
62844
+ groupRowsBy,
62845
+ groupColumnsBy,
62846
+ aggregations: input.aggregations ?? [],
62847
+ formPivot,
62848
+ nextPivot,
62849
+ sourcePivot,
62850
+ chartPivot,
62851
+ pivotKind: kind,
62852
+ unexpectedPivot,
62853
+ isPivotTableChart: Boolean(input.isPivotTableChart),
62854
+ reportDetailSurface: reportDetailSurfaceOf(chart),
62855
+ tableColumnFormats: tableColumns,
62856
+ chartColumnFormats: chartColumns,
62857
+ tableRowCount: tableRows.length,
62858
+ chartRowCount: chartRows.length,
62859
+ pivotRowCount: pivotRows.length,
62860
+ tableSample: sampleRows(tableRows),
62861
+ chartRowSample: sampleRows(chartRows),
62862
+ pivotRowSample: sampleRows(pivotRows),
62863
+ chartDisplaySample: sampleRows(displayRows),
62864
+ doubleFormatSample: sampleRows(doubleFormatRows),
62865
+ formatMismatches: [
62866
+ ...formatMismatchesFor(tableColumns, sourceRows.length ? sourceRows : tableRows),
62867
+ ...formatMismatchesFor(chartColumns, chartRows.length ? chartRows : pivotRows),
62868
+ ...tableRows.flatMap((row, index) => {
62869
+ if (!row || typeof row !== "object") return [];
62870
+ return tableColumns.filter(
62871
+ (column) => NUMBER_FORMAT_TYPES.includes(column.format) && alreadyGroupedNumberString(
62872
+ row[column.field]
62873
+ )
62874
+ ).map(
62875
+ (column) => `already-formatted ${column.field} row[${index}]=${JSON.stringify(
62876
+ row[column.field]
62877
+ )}`
62878
+ );
62879
+ })
62880
+ ],
62881
+ nanHits
62882
+ };
62883
+ }
62884
+ var lastSerializedBySource = /* @__PURE__ */ new Map();
62885
+ function recordUseReportNanPivotState(input) {
62886
+ if (!isNanPivotDebugEnabled()) return null;
62887
+ const snapshot = snapshotUseReportNanState(input);
62888
+ const key = `${snapshot.source}:${snapshot.flow ?? ""}:${snapshot.reportId}`;
62889
+ const serialized = JSON.stringify(jsonSafe(snapshot));
62890
+ if (lastSerializedBySource.get(key) === serialized) {
62891
+ return snapshot;
62892
+ }
62893
+ lastSerializedBySource.set(key, serialized);
62894
+ const log = getNanPivotLog();
62895
+ log.push(snapshot);
62896
+ globalRecord()[NAN_PIVOT_LOG_FLAG] = log;
62897
+ const liveHits = snapshot.nanHits.filter(
62898
+ (hit) => hit.surface !== "chartDisplay.doubleFormatTableRows"
62899
+ );
62900
+ const compact = {
62901
+ atMs: snapshot.atMs,
62902
+ source: snapshot.source,
62903
+ flow: snapshot.flow,
62904
+ step: snapshot.step,
62905
+ reportId: snapshot.reportId,
62906
+ datasources: snapshot.datasources,
62907
+ chartType: snapshot.chartType,
62908
+ loading: snapshot.loading,
62909
+ chartLoading: snapshot.chartLoading,
62910
+ tableLoading: snapshot.tableLoading,
62911
+ groupRowsBy: snapshot.groupRowsBy,
62912
+ groupColumnsBy: snapshot.groupColumnsBy,
62913
+ pivotKind: snapshot.pivotKind,
62914
+ unexpectedPivot: snapshot.unexpectedPivot,
62915
+ isPivotTableChart: snapshot.isPivotTableChart,
62916
+ reportDetailSurface: snapshot.reportDetailSurface,
62917
+ tableRowCount: snapshot.tableRowCount,
62918
+ chartRowCount: snapshot.chartRowCount,
62919
+ pivotRowCount: snapshot.pivotRowCount,
62920
+ formatMismatches: snapshot.formatMismatches.slice(0, 8),
62921
+ nanHits: snapshot.nanHits.slice(0, 12)
62922
+ };
62923
+ if (liveHits.length > 0 || snapshot.unexpectedPivot) {
62924
+ console.log(
62925
+ "[useReport][nan-pivot][hit]",
62926
+ JSON.stringify(
62927
+ jsonSafe({
62928
+ ...compact,
62929
+ tableSample: snapshot.tableSample,
62930
+ chartRowSample: snapshot.chartRowSample,
62931
+ pivotRowSample: snapshot.pivotRowSample,
62932
+ chartDisplaySample: snapshot.chartDisplaySample,
62933
+ doubleFormatSample: snapshot.doubleFormatSample,
62934
+ formPivot: snapshot.formPivot,
62935
+ chartPivot: snapshot.chartPivot,
62936
+ sourcePivot: snapshot.sourcePivot
62937
+ }),
62938
+ null,
62939
+ 2
62940
+ )
62941
+ );
62942
+ } else if (snapshot.nanHits.length > 0) {
62943
+ console.log(
62944
+ "[useReport][nan-pivot][double-format]",
62945
+ JSON.stringify(compact)
62946
+ );
62947
+ } else {
62948
+ console.log("[useReport][nan-pivot][state]", JSON.stringify(compact));
62949
+ }
62950
+ return snapshot;
62951
+ }
62952
+
62953
+ // src/hooks/useForm.tsx
62602
62954
  init_reportRequestPool();
62603
62955
 
62604
62956
  // src/hooks/useForm.queries.ts
@@ -66806,7 +67158,7 @@ function useReport(reportIdArg, options = {}) {
66806
67158
  pivot,
66807
67159
  operation
66808
67160
  }) => {
66809
- const startedAt = performance.now();
67161
+ const startedAt2 = performance.now();
66810
67162
  const snapshot = await cacheCab.getReportSnapshot(
66811
67163
  effectiveReportId,
66812
67164
  tenants
@@ -66825,7 +67177,7 @@ function useReport(reportIdArg, options = {}) {
66825
67177
  )
66826
67178
  });
66827
67179
  const diagnostics = globalThis.__QUILL_CACHECAB_DIAGNOSTICS__;
66828
- const durationMs = performance.now() - startedAt;
67180
+ const durationMs = performance.now() - startedAt2;
66829
67181
  const outcome = resolution.resolved ? "hit" : "fallback";
66830
67182
  if (Array.isArray(diagnostics)) {
66831
67183
  diagnostics.push({
@@ -69813,11 +70165,12 @@ function useReport(reportIdArg, options = {}) {
69813
70165
  registerOption(column.field, column.label, column.format);
69814
70166
  }
69815
70167
  for (const yAxis2 of yAxisResolved.measures) {
69816
- registerOption(yAxis2.field, yAxis2.label, yAxis2.format);
70168
+ const field = String(yAxis2.field ?? "").trim();
70169
+ registerOption(field, field, yAxis2.format);
69817
70170
  if (yAxis2.format) {
69818
- const existing = optionsByField.get(yAxis2.field);
70171
+ const existing = optionsByField.get(field);
69819
70172
  if (existing) {
69820
- optionsByField.set(yAxis2.field, {
70173
+ optionsByField.set(field, {
69821
70174
  ...existing,
69822
70175
  format: toAxisFormat(yAxis2.format, existing.format)
69823
70176
  });
@@ -69894,12 +70247,17 @@ function useReport(reportIdArg, options = {}) {
69894
70247
  ];
69895
70248
  }, [chartAxisOptions, yAxisResolved.measures]);
69896
70249
  const yAxisOptions = useMemo33(
69897
- () => yAxisMeasures.map((measure) => ({
69898
- value: measure.field,
69899
- label: measure.label,
69900
- format: toAxisFormat(measure.format, "string")
69901
- })),
69902
- [yAxisMeasures]
70250
+ () => yAxisMeasures.map((measure) => {
70251
+ const field = String(measure.field ?? "").trim();
70252
+ const catalog = chartAxisOptionByField.get(field);
70253
+ if (catalog) return catalog;
70254
+ return {
70255
+ value: field,
70256
+ label: toTitleCaseLabel(field),
70257
+ format: toAxisFormat(measure.format, "string")
70258
+ };
70259
+ }),
70260
+ [chartAxisOptionByField, yAxisMeasures]
69903
70261
  );
69904
70262
  const normalizedChartYAxisOptions = useMemo33(() => {
69905
70263
  return yAxisOptions.map((option) => ({
@@ -70239,11 +70597,7 @@ function useReport(reportIdArg, options = {}) {
70239
70597
  );
70240
70598
  const isPivotTableChart = String(chartType ?? "").toLowerCase() === "table" && Boolean(pivotState);
70241
70599
  const pivotTableColumns = useMemo33(
70242
- () => isPivotTableChart ? buildPivotTableColumns(
70243
- pivotState,
70244
- chart,
70245
- resolveTableDisplayLabel
70246
- ) : null,
70600
+ () => isPivotTableChart ? buildPivotTableColumns(pivotState, chart, resolveTableDisplayLabel) : null,
70247
70601
  [chart, isPivotTableChart, pivotState, resolveTableDisplayLabel]
70248
70602
  );
70249
70603
  const chartAxes = useMemo33(() => {
@@ -70894,6 +71248,43 @@ function useReport(reportIdArg, options = {}) {
70894
71248
  tableRefreshQuery.isFetching,
70895
71249
  tableRefreshQueryEnabled
70896
71250
  ]);
71251
+ useEffect33(() => {
71252
+ if (!isNanPivotDebugEnabled()) return;
71253
+ recordUseReportNanPivotState({
71254
+ source: "useReport",
71255
+ reportId: effectiveReportId,
71256
+ datasources,
71257
+ chartType: resolvedChartType,
71258
+ chartLoading,
71259
+ tableLoading,
71260
+ loading,
71261
+ groupRowsBy,
71262
+ groupColumnsBy,
71263
+ aggregations: aggregationValues,
71264
+ formPivot: pivotState,
71265
+ nextPivot,
71266
+ sourceReport,
71267
+ chart: chartWithSort,
71268
+ table,
71269
+ isPivotTableChart
71270
+ });
71271
+ }, [
71272
+ aggregationValues,
71273
+ chartLoading,
71274
+ chartWithSort,
71275
+ datasources,
71276
+ effectiveReportId,
71277
+ groupColumnsBy,
71278
+ groupRowsBy,
71279
+ isPivotTableChart,
71280
+ loading,
71281
+ nextPivot,
71282
+ pivotState,
71283
+ resolvedChartType,
71284
+ sourceReport,
71285
+ table,
71286
+ tableLoading
71287
+ ]);
70897
71288
  const buildSetReportColumnsFromIds = (nextColumnIds, settingsById) => {
70898
71289
  const normalizedNextIds = nextColumnIds.map((columnId) => String(columnId ?? "").trim()).filter(Boolean);
70899
71290
  return normalizedNextIds.map((columnId) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quillsql/react",
3
- "version": "2.16.101",
3
+ "version": "2.16.102",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {