drizzle-cube 0.4.5 → 0.4.8

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 (140) hide show
  1. package/dist/adapters/express/index.cjs +8 -4
  2. package/dist/adapters/express/index.d.ts +7 -0
  3. package/dist/adapters/express/index.js +189 -139
  4. package/dist/adapters/fastify/index.cjs +8 -4
  5. package/dist/adapters/fastify/index.d.ts +7 -0
  6. package/dist/adapters/fastify/index.js +209 -150
  7. package/dist/adapters/handler-BLcxTuwi.cjs +23 -0
  8. package/dist/adapters/handler-odjn7MIB.js +1880 -0
  9. package/dist/adapters/hono/index.cjs +8 -4
  10. package/dist/adapters/hono/index.d.ts +7 -0
  11. package/dist/adapters/hono/index.js +202 -144
  12. package/dist/adapters/{mcp-transport-YHDZWKOi.js → mcp-transport-CU5g9bxj.js} +7 -3
  13. package/dist/adapters/{mcp-transport-BqLo4hKi.cjs → mcp-transport-KX92EgkF.cjs} +21 -21
  14. package/dist/adapters/nextjs/index.cjs +7 -3
  15. package/dist/adapters/nextjs/index.d.ts +14 -0
  16. package/dist/adapters/nextjs/index.js +220 -144
  17. package/dist/client/charts/chartConfigs.d.ts +2 -9
  18. package/dist/client/charts.js +72 -70
  19. package/dist/client/charts.js.map +1 -1
  20. package/dist/client/chunks/{RetentionCombinedChart.config-C-ILIaEb.js → RetentionCombinedChart.config-Bbp2ghim.js} +2 -1
  21. package/dist/client/chunks/RetentionCombinedChart.config-Bbp2ghim.js.map +1 -0
  22. package/dist/client/chunks/{RetentionHeatmap.config-CIvhc-GT.js → RetentionHeatmap.config-BWf_-vdj.js} +2 -1
  23. package/dist/client/chunks/RetentionHeatmap.config-BWf_-vdj.js.map +1 -0
  24. package/dist/client/chunks/{analysis-builder-CG5VIMYB.js → analysis-builder-Bov_gLsf.js} +1408 -1393
  25. package/dist/client/chunks/analysis-builder-Bov_gLsf.js.map +1 -0
  26. package/dist/client/chunks/{analysis-builder-shared-CjlKJgyA.js → analysis-builder-shared-NBk6y0md.js} +3 -3
  27. package/dist/client/chunks/{analysis-builder-shared-CjlKJgyA.js.map → analysis-builder-shared-NBk6y0md.js.map} +1 -1
  28. package/dist/client/chunks/{chart-activity-grid-DStNr34n.js → chart-activity-grid-CE7xGFQo.js} +2 -2
  29. package/dist/client/chunks/{chart-activity-grid-DStNr34n.js.map → chart-activity-grid-CE7xGFQo.js.map} +1 -1
  30. package/dist/client/chunks/chart-box-plot-Dja4LS3O.js +313 -0
  31. package/dist/client/chunks/chart-box-plot-Dja4LS3O.js.map +1 -0
  32. package/dist/client/chunks/{chart-config-activity-grid-CAlo1cHA.js → chart-config-activity-grid-CmOqDuOT.js} +4 -5
  33. package/dist/client/chunks/chart-config-activity-grid-CmOqDuOT.js.map +1 -0
  34. package/dist/client/chunks/{chart-config-area-CyyJOO2T.js → chart-config-area-CK_GVApT.js} +4 -5
  35. package/dist/client/chunks/chart-config-area-CK_GVApT.js.map +1 -0
  36. package/dist/client/chunks/{chart-config-bar-soxw6m2o.js → chart-config-bar-C8uzktxl.js} +4 -5
  37. package/dist/client/chunks/chart-config-bar-C8uzktxl.js.map +1 -0
  38. package/dist/client/chunks/chart-config-box-plot-D3DA7_pr.js +85 -0
  39. package/dist/client/chunks/chart-config-box-plot-D3DA7_pr.js.map +1 -0
  40. package/dist/client/chunks/{chart-config-bubble-CuSsCHZ4.js → chart-config-bubble-q3DoQX5F.js} +4 -5
  41. package/dist/client/chunks/chart-config-bubble-q3DoQX5F.js.map +1 -0
  42. package/dist/client/chunks/{chart-config-data-table-BhgqwoqT.js → chart-config-data-table-B20Y5JCm.js} +4 -5
  43. package/dist/client/chunks/chart-config-data-table-B20Y5JCm.js.map +1 -0
  44. package/dist/client/chunks/{chart-config-funnel-BlSQYng0.js → chart-config-funnel-3eYnGg8M.js} +4 -5
  45. package/dist/client/chunks/chart-config-funnel-3eYnGg8M.js.map +1 -0
  46. package/dist/client/chunks/{chart-config-heat-map-DHQGFZhX.js → chart-config-heat-map-_wEnTnRA.js} +4 -5
  47. package/dist/client/chunks/chart-config-heat-map-_wEnTnRA.js.map +1 -0
  48. package/dist/client/chunks/{chart-config-kpi-delta-yTA5ug_l.js → chart-config-kpi-delta-DLGZ2A3X.js} +4 -5
  49. package/dist/client/chunks/chart-config-kpi-delta-DLGZ2A3X.js.map +1 -0
  50. package/dist/client/chunks/{chart-config-kpi-number-nVAwDXzq.js → chart-config-kpi-number-K-wzviXF.js} +4 -5
  51. package/dist/client/chunks/chart-config-kpi-number-K-wzviXF.js.map +1 -0
  52. package/dist/client/chunks/{chart-config-kpi-text-DZjqsx-b.js → chart-config-kpi-text-BjYqwqaJ.js} +4 -5
  53. package/dist/client/chunks/chart-config-kpi-text-BjYqwqaJ.js.map +1 -0
  54. package/dist/client/chunks/{chart-config-line-D5ME6w0v.js → chart-config-line-JNagi9tf.js} +4 -5
  55. package/dist/client/chunks/chart-config-line-JNagi9tf.js.map +1 -0
  56. package/dist/client/chunks/{chart-config-markdown-BXKL5TbQ.js → chart-config-markdown-BWQSjJpy.js} +4 -5
  57. package/dist/client/chunks/chart-config-markdown-BWQSjJpy.js.map +1 -0
  58. package/dist/client/chunks/{chart-config-pie-DlHa2jTy.js → chart-config-pie-CNLXb-fr.js} +4 -5
  59. package/dist/client/chunks/chart-config-pie-CNLXb-fr.js.map +1 -0
  60. package/dist/client/chunks/{chart-config-radar-BBAVIF0S.js → chart-config-radar-oxHfRAa3.js} +4 -5
  61. package/dist/client/chunks/chart-config-radar-oxHfRAa3.js.map +1 -0
  62. package/dist/client/chunks/{chart-config-radial-bar-CTwjDRnB.js → chart-config-radial-bar-_Aw3jAEm.js} +4 -5
  63. package/dist/client/chunks/chart-config-radial-bar-_Aw3jAEm.js.map +1 -0
  64. package/dist/client/chunks/{chart-config-sankey-CNAgsMQ4.js → chart-config-sankey-C8FX9hGF.js} +4 -5
  65. package/dist/client/chunks/chart-config-sankey-C8FX9hGF.js.map +1 -0
  66. package/dist/client/chunks/{chart-config-scatter-CWvN2E-X.js → chart-config-scatter-DFKM80eO.js} +4 -5
  67. package/dist/client/chunks/chart-config-scatter-DFKM80eO.js.map +1 -0
  68. package/dist/client/chunks/{chart-config-sunburst-W_SKwaj0.js → chart-config-sunburst-BmC0NLTU.js} +4 -5
  69. package/dist/client/chunks/chart-config-sunburst-BmC0NLTU.js.map +1 -0
  70. package/dist/client/chunks/{chart-config-tree-map-IRAYf9YM.js → chart-config-tree-map-DGMbNTaa.js} +4 -5
  71. package/dist/client/chunks/chart-config-tree-map-DGMbNTaa.js.map +1 -0
  72. package/dist/client/chunks/{chart-data-table-Ch_1c1Zo.js → chart-data-table-Ba_6tuJw.js} +2 -2
  73. package/dist/client/chunks/{chart-data-table-Ch_1c1Zo.js.map → chart-data-table-Ba_6tuJw.js.map} +1 -1
  74. package/dist/client/chunks/{chart-kpi-delta-CWCmi8vL.js → chart-kpi-delta-D9XJoKuA.js} +3 -3
  75. package/dist/client/chunks/{chart-kpi-delta-CWCmi8vL.js.map → chart-kpi-delta-D9XJoKuA.js.map} +1 -1
  76. package/dist/client/chunks/{chart-kpi-number-C-5m3qt5.js → chart-kpi-number-C29Vj2g8.js} +2 -2
  77. package/dist/client/chunks/{chart-kpi-number-C-5m3qt5.js.map → chart-kpi-number-C29Vj2g8.js.map} +1 -1
  78. package/dist/client/chunks/{chart-kpi-text--t4ibPmx.js → chart-kpi-text-CgjjrurK.js} +2 -2
  79. package/dist/client/chunks/{chart-kpi-text--t4ibPmx.js.map → chart-kpi-text-CgjjrurK.js.map} +1 -1
  80. package/dist/client/chunks/chart-markdown-Du4Z2iqK.js +2695 -0
  81. package/dist/client/chunks/chart-markdown-Du4Z2iqK.js.map +1 -0
  82. package/dist/client/chunks/{charts-loader-m5Ussksz.js → charts-loader-HYQFVOo4.js} +14 -13
  83. package/dist/client/chunks/charts-loader-HYQFVOo4.js.map +1 -0
  84. package/dist/client/chunks/{components-D-5p1LVQ.js → components-O0hh7ooo.js} +6 -6
  85. package/dist/client/chunks/components-O0hh7ooo.js.map +1 -0
  86. package/dist/client/chunks/{icons-DRreo6m8.js → icons-DAeqv1iX.js} +7 -7
  87. package/dist/client/chunks/{icons-DRreo6m8.js.map → icons-DAeqv1iX.js.map} +1 -1
  88. package/dist/client/components/AgenticNotebook/AgentChatPanel.d.ts +8 -0
  89. package/dist/client/components/AgenticNotebook/ChatInput.d.ts +14 -0
  90. package/dist/client/components/AgenticNotebook/ChatMessage.d.ts +7 -0
  91. package/dist/client/components/AgenticNotebook/NotebookCanvas.d.ts +3 -0
  92. package/dist/client/components/AgenticNotebook/NotebookMarkdownBlock.d.ts +12 -0
  93. package/dist/client/components/AgenticNotebook/NotebookPortletBlock.d.ts +12 -0
  94. package/dist/client/components/AgenticNotebook/index.d.ts +34 -0
  95. package/dist/client/components/charts/BoxPlotChart.config.d.ts +11 -0
  96. package/dist/client/components/charts/BoxPlotChart.d.ts +4 -0
  97. package/dist/client/components/charts/index.d.ts +1 -0
  98. package/dist/client/components.js +1 -1
  99. package/dist/client/hooks/useAgentChat.d.ts +36 -0
  100. package/dist/client/icons.js +1 -1
  101. package/dist/client/index.d.ts +6 -0
  102. package/dist/client/index.js +923 -187
  103. package/dist/client/index.js.map +1 -1
  104. package/dist/client/stores/notebookStore.d.ts +152 -0
  105. package/dist/client/styles.css +1 -1
  106. package/dist/client/types.d.ts +1 -1
  107. package/dist/client/utils.js +3 -3
  108. package/dist/client-bundle-stats.html +4 -4
  109. package/dist/server/index.cjs +116 -90
  110. package/dist/server/index.d.ts +155 -0
  111. package/dist/server/index.js +7088 -4852
  112. package/package.json +12 -6
  113. package/dist/client/chunks/RetentionCombinedChart.config-C-ILIaEb.js.map +0 -1
  114. package/dist/client/chunks/RetentionHeatmap.config-CIvhc-GT.js.map +0 -1
  115. package/dist/client/chunks/analysis-builder-CG5VIMYB.js.map +0 -1
  116. package/dist/client/chunks/chart-config-activity-grid-CAlo1cHA.js.map +0 -1
  117. package/dist/client/chunks/chart-config-area-CyyJOO2T.js.map +0 -1
  118. package/dist/client/chunks/chart-config-bar-soxw6m2o.js.map +0 -1
  119. package/dist/client/chunks/chart-config-bubble-CuSsCHZ4.js.map +0 -1
  120. package/dist/client/chunks/chart-config-data-table-BhgqwoqT.js.map +0 -1
  121. package/dist/client/chunks/chart-config-funnel-BlSQYng0.js.map +0 -1
  122. package/dist/client/chunks/chart-config-heat-map-DHQGFZhX.js.map +0 -1
  123. package/dist/client/chunks/chart-config-kpi-delta-yTA5ug_l.js.map +0 -1
  124. package/dist/client/chunks/chart-config-kpi-number-nVAwDXzq.js.map +0 -1
  125. package/dist/client/chunks/chart-config-kpi-text-DZjqsx-b.js.map +0 -1
  126. package/dist/client/chunks/chart-config-line-D5ME6w0v.js.map +0 -1
  127. package/dist/client/chunks/chart-config-markdown-BXKL5TbQ.js.map +0 -1
  128. package/dist/client/chunks/chart-config-pie-DlHa2jTy.js.map +0 -1
  129. package/dist/client/chunks/chart-config-radar-BBAVIF0S.js.map +0 -1
  130. package/dist/client/chunks/chart-config-radial-bar-CTwjDRnB.js.map +0 -1
  131. package/dist/client/chunks/chart-config-sankey-CNAgsMQ4.js.map +0 -1
  132. package/dist/client/chunks/chart-config-scatter-CWvN2E-X.js.map +0 -1
  133. package/dist/client/chunks/chart-config-sunburst-W_SKwaj0.js.map +0 -1
  134. package/dist/client/chunks/chart-config-tree-map-IRAYf9YM.js.map +0 -1
  135. package/dist/client/chunks/chart-markdown-Rq6ORisB.js +0 -276
  136. package/dist/client/chunks/chart-markdown-Rq6ORisB.js.map +0 -1
  137. package/dist/client/chunks/chartConfigRegistry-C5dZm-ZK.js +0 -44
  138. package/dist/client/chunks/chartConfigRegistry-C5dZm-ZK.js.map +0 -1
  139. package/dist/client/chunks/charts-loader-m5Ussksz.js.map +0 -1
  140. package/dist/client/chunks/components-D-5p1LVQ.js.map +0 -1
@@ -1,6 +1,5 @@
1
- import { a as e } from "./icons-DRreo6m8.js";
2
- const a = {
3
- icon: e("sunburst"),
1
+ const e = {
2
+ label: "Sunburst Chart",
4
3
  description: "Show hierarchical flow as radial rings",
5
4
  useCase: "Best for visualizing forward paths from a starting event in a compact radial layout",
6
5
  dropZones: [
@@ -46,6 +45,6 @@ const a = {
46
45
  ]
47
46
  };
48
47
  export {
49
- a as sunburstChartConfig
48
+ e as sunburstChartConfig
50
49
  };
51
- //# sourceMappingURL=chart-config-sunburst-W_SKwaj0.js.map
50
+ //# sourceMappingURL=chart-config-sunburst-BmC0NLTU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-config-sunburst-BmC0NLTU.js","sources":["../../../src/client/components/charts/SunburstChart.config.ts"],"sourcesContent":["import type { ChartTypeConfig } from '../../charts/chartConfigs'\n\n/**\n * Configuration for the sunburst chart type\n *\n * Sunburst charts visualize hierarchical flow data as concentric rings.\n * They work with the same flow data as Sankey but show only \"after\" steps\n * radiating outward from the central starting step.\n */\nexport const sunburstChartConfig: ChartTypeConfig = {\n label: 'Sunburst Chart',\n description: 'Show hierarchical flow as radial rings',\n useCase: 'Best for visualizing forward paths from a starting event in a compact radial layout',\n dropZones: [\n // Sunburst charts work with pre-calculated flow data like Sankey\n {\n key: 'xAxis',\n label: 'Event Type',\n description: 'Event dimension that categorizes flow nodes',\n mandatory: false,\n maxItems: 1,\n acceptTypes: ['dimension'],\n emptyText: 'Auto-populated from flow config',\n },\n {\n key: 'yAxis',\n label: 'Flow Count',\n description: 'Count of entities following each path',\n mandatory: false,\n maxItems: 1,\n acceptTypes: ['measure'],\n emptyText: 'Calculated from flow execution',\n },\n ],\n displayOptions: ['hideHeader'],\n displayOptionsConfig: [\n {\n key: 'innerRadius',\n label: 'Inner Radius',\n type: 'number',\n defaultValue: 40,\n min: 0,\n max: 100,\n step: 10,\n description: 'Size of the center hole (0 for full circle)',\n },\n {\n key: 'hideSummaryFooter',\n label: 'Hide Summary Footer',\n type: 'boolean',\n defaultValue: true,\n description: 'Hide the statistics footer below the chart',\n },\n ],\n}\n"],"names":["sunburstChartConfig"],"mappings":"AASO,MAAMA,IAAuC;AAAA,EAClD,OAAO;AAAA,EACP,aAAa;AAAA,EACb,SAAS;AAAA,EACT,WAAW;AAAA;AAAA,IAET;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,WAAW;AAAA,MACzB,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,SAAS;AAAA,MACvB,WAAW;AAAA,IAAA;AAAA,EACb;AAAA,EAEF,gBAAgB,CAAC,YAAY;AAAA,EAC7B,sBAAsB;AAAA,IACpB;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,cAAc;AAAA,MACd,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,IAAA;AAAA,IAEf;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,cAAc;AAAA,MACd,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ;"}
@@ -1,6 +1,5 @@
1
- import { a as e } from "./icons-DRreo6m8.js";
2
- const a = {
3
- icon: e("treemap"),
1
+ const e = {
2
+ label: "TreeMap",
4
3
  description: "Visualize hierarchical data with nested rectangles",
5
4
  useCase: "Best for showing part-to-whole relationships in hierarchical data, disk usage, budget allocation",
6
5
  dropZones: [
@@ -43,6 +42,6 @@ const a = {
43
42
  clickableElements: { cell: !0 }
44
43
  };
45
44
  export {
46
- a as treemapChartConfig
45
+ e as treemapChartConfig
47
46
  };
48
- //# sourceMappingURL=chart-config-tree-map-IRAYf9YM.js.map
47
+ //# sourceMappingURL=chart-config-tree-map-DGMbNTaa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chart-config-tree-map-DGMbNTaa.js","sources":["../../../src/client/components/charts/TreeMapChart.config.ts"],"sourcesContent":["import type { ChartTypeConfig } from '../../charts/chartConfigs'\n\n/**\n * Configuration for the treemap chart type\n */\nexport const treemapChartConfig: ChartTypeConfig = {\n label: 'TreeMap',\n description: 'Visualize hierarchical data with nested rectangles',\n useCase: 'Best for showing part-to-whole relationships in hierarchical data, disk usage, budget allocation',\n dropZones: [\n {\n key: 'xAxis',\n label: 'Categories',\n description: 'Dimensions for treemap rectangles',\n mandatory: true,\n acceptTypes: ['dimension'],\n emptyText: 'Drop dimensions for categories'\n },\n {\n key: 'yAxis',\n label: 'Size',\n description: 'Measure for rectangle sizes',\n mandatory: true,\n maxItems: 1,\n acceptTypes: ['measure'],\n emptyText: 'Drop a measure for size'\n },\n {\n key: 'series',\n label: 'Color Groups',\n description: 'Dimension to color rectangles by category',\n mandatory: false,\n maxItems: 1,\n acceptTypes: ['dimension'],\n emptyText: 'Drop a dimension for color grouping'\n }\n ],\n displayOptions: ['showLegend', 'showTooltip', 'hideHeader'],\n displayOptionsConfig: [\n {\n key: 'leftYAxisFormat',\n label: 'Value Format',\n type: 'axisFormat',\n description: 'Number formatting for size values'\n }\n ],\n clickableElements: { cell: true }\n}"],"names":["treemapChartConfig"],"mappings":"AAKO,MAAMA,IAAsC;AAAA,EACjD,OAAO;AAAA,EACP,aAAa;AAAA,EACb,SAAS;AAAA,EACT,WAAW;AAAA,IACT;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,aAAa,CAAC,WAAW;AAAA,MACzB,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,SAAS;AAAA,MACvB,WAAW;AAAA,IAAA;AAAA,IAEb;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,MACV,aAAa,CAAC,WAAW;AAAA,MACzB,WAAW;AAAA,IAAA;AAAA,EACb;AAAA,EAEF,gBAAgB,CAAC,cAAc,eAAe,YAAY;AAAA,EAC1D,sBAAsB;AAAA,IACpB;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IAAA;AAAA,EACf;AAAA,EAEF,mBAAmB,EAAE,MAAM,GAAA;AAC7B;"}
@@ -2,7 +2,7 @@ import { jsx as c, jsxs as u } from "react/jsx-runtime";
2
2
  import k, { useMemo as y } from "react";
3
3
  import { u as S } from "./providers-CgxXm6Ll.js";
4
4
  import { d as g, f as w } from "./charts-core-DmGfleFz.js";
5
- import { g as F } from "./icons-DRreo6m8.js";
5
+ import { g as F } from "./icons-DAeqv1iX.js";
6
6
  function A(e) {
7
7
  if (!e) return [];
8
8
  const t = [];
@@ -290,4 +290,4 @@ export {
290
290
  M as h,
291
291
  R as p
292
292
  };
293
- //# sourceMappingURL=chart-data-table-Ch_1c1Zo.js.map
293
+ //# sourceMappingURL=chart-data-table-Ba_6tuJw.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-data-table-Ch_1c1Zo.js","sources":["../../../src/client/utils/pivotUtils.ts","../../../src/client/components/charts/DataTable.tsx"],"sourcesContent":["/**\n * Pivot utilities for DataTable time dimension pivoting\n *\n * When a query includes a time dimension with granularity, transforms flat data\n * into a pivoted structure with time periods as columns.\n */\n\nimport type { CubeQuery, CubeMeta } from '../types'\nimport { formatTimeValue } from './chartUtils'\n\n/**\n * Derives ordered column list from a CubeQuery object.\n * Order: dimensions, timeDimensions (as field names), measures\n *\n * @param queryObject The CubeQuery object\n * @returns Array of field names in order\n */\nexport function getOrderedColumnsFromQuery(queryObject?: CubeQuery): string[] {\n if (!queryObject) return []\n\n const columns: string[] = []\n\n // Add regular dimensions first\n if (queryObject.dimensions) {\n columns.push(...queryObject.dimensions)\n }\n\n // Add time dimensions\n if (queryObject.timeDimensions) {\n queryObject.timeDimensions.forEach(td => {\n if (!columns.includes(td.dimension)) {\n columns.push(td.dimension)\n }\n })\n }\n\n // Add measures last\n if (queryObject.measures) {\n columns.push(...queryObject.measures)\n }\n\n return columns\n}\n\n/**\n * Configuration for pivoting based on query structure\n */\nexport interface PivotConfig {\n /** Time dimension field name (e.g., \"Sales.date\") */\n timeDimension: string\n /** Time granularity (e.g., \"month\", \"day\", \"year\") */\n granularity: string\n /** Non-time dimension fields */\n dimensions: string[]\n /** Measure fields */\n measures: string[]\n}\n\n/**\n * Column definition for pivoted table\n */\nexport interface PivotColumn {\n /** Column key for data access */\n key: string\n /** Display label for column header */\n label: string\n /** Whether this is a time column (vs row identifier column) */\n isTimeColumn: boolean\n /** Whether this is the measure column */\n isMeasureColumn?: boolean\n}\n\n/**\n * Row in the pivoted table\n */\nexport interface PivotRow {\n /** Unique row identifier */\n id: string\n /** The measure field name (for icon lookup) */\n measureField: string\n /** Values keyed by column key */\n values: Record<string, any>\n /** Whether this is the first row in a dimension group (for row spanning) */\n isFirstInGroup?: boolean\n /** Number of rows to span for dimension cells (only set on first row in group) */\n dimensionRowSpan?: number\n}\n\n/**\n * Result of pivoting table data\n */\nexport interface PivotedTableData {\n /** Whether data was pivoted (has time dimension with granularity) */\n isPivoted: boolean\n /** Column definitions for the pivoted table */\n columns: PivotColumn[]\n /** Rows of pivoted data */\n rows: PivotRow[]\n}\n\n/**\n * Determines if a query has a time dimension with granularity that should trigger pivoting\n * @param queryObject The CubeQuery object\n * @param xAxisOverride Optional array of fields to use for filtering dimensions and measures\n * (for respecting chartConfig.xAxis configuration)\n * @returns PivotConfig if pivoting should occur, null otherwise\n */\nexport function hasTimeDimensionForPivot(\n queryObject?: CubeQuery,\n xAxisOverride?: string[]\n): PivotConfig | null {\n if (!queryObject?.timeDimensions?.length) return null\n\n // Find the first time dimension with granularity\n const timeDim = queryObject.timeDimensions.find(td => td.granularity)\n if (!timeDim?.granularity) return null\n\n // Must have at least one measure to pivot\n if (!queryObject.measures?.length) return null\n\n let dimensions: string[]\n let measures: string[]\n\n if (xAxisOverride && xAxisOverride.length > 0) {\n // Filter dimensions from xAxisOverride (excluding time dimension and measures)\n dimensions = xAxisOverride.filter(field => {\n // Exclude the time dimension being pivoted (it becomes columns)\n if (field === timeDim.dimension) return false\n // Exclude measures (they become row values, not dimension columns)\n if (queryObject.measures?.includes(field)) return false\n return true\n })\n\n // Filter measures from xAxisOverride - only show measures that are in xAxis\n const measuresInXAxis = xAxisOverride.filter(field =>\n queryObject.measures?.includes(field)\n )\n // If xAxis contains measures, use only those; otherwise fall back to all measures\n measures = measuresInXAxis.length > 0 ? measuresInXAxis : queryObject.measures\n } else {\n dimensions = queryObject.dimensions || []\n measures = queryObject.measures\n }\n\n // Must have at least one measure after filtering\n if (measures.length === 0) return null\n\n return {\n timeDimension: timeDim.dimension,\n granularity: timeDim.granularity,\n dimensions,\n measures\n }\n}\n\n/**\n * Extracts unique time values from data and sorts them chronologically\n */\nfunction extractAndSortTimeValues(\n data: any[],\n timeDimension: string,\n granularity: string\n): string[] {\n const timeSet = new Set<string>()\n\n data.forEach(row => {\n const rawTime = row[timeDimension]\n if (rawTime != null) {\n const formattedTime = formatTimeValue(rawTime, granularity)\n timeSet.add(formattedTime)\n }\n })\n\n // Sort chronologically - ISO date strings sort correctly alphabetically\n return Array.from(timeSet).sort()\n}\n\n/**\n * Builds column definitions for pivoted table\n * Order: Measure (if multiple) -> Dimensions -> Time columns\n */\nfunction buildColumns(\n config: PivotConfig,\n timeValues: string[],\n getFieldLabel: (field: string) => string\n): PivotColumn[] {\n const columns: PivotColumn[] = []\n\n // Add measure column first (if multiple measures)\n if (config.measures.length > 1) {\n columns.push({\n key: '__measure__',\n label: 'Measure',\n isTimeColumn: false,\n isMeasureColumn: true\n })\n }\n\n // Add dimension columns\n config.dimensions.forEach(dim => {\n columns.push({\n key: dim,\n label: getFieldLabel(dim),\n isTimeColumn: false\n })\n })\n\n // Add time columns (already sorted chronologically)\n timeValues.forEach(timeVal => {\n columns.push({\n key: timeVal,\n label: timeVal,\n isTimeColumn: true\n })\n })\n\n return columns\n}\n\n/**\n * Groups data by dimension values, then by time period\n * Returns Map<dimensionKey, Map<formattedTime, dataRow>>\n */\nfunction groupByDimensions(\n data: any[],\n config: PivotConfig\n): Map<string, Map<string, any>> {\n const grouped = new Map<string, Map<string, any>>()\n\n data.forEach(row => {\n // Build dimension key from all dimension values\n const dimKey = config.dimensions.length > 0\n ? config.dimensions.map(dim => String(row[dim] ?? '')).join('|')\n : '__all__'\n\n // Get or create time map for this dimension combo\n if (!grouped.has(dimKey)) {\n grouped.set(dimKey, new Map())\n }\n\n // Store data point by formatted time value\n const rawTime = row[config.timeDimension]\n if (rawTime != null) {\n const formattedTime = formatTimeValue(rawTime, config.granularity)\n grouped.get(dimKey)!.set(formattedTime, row)\n }\n })\n\n return grouped\n}\n\n/**\n * Builds pivoted rows from grouped data\n * Rows are grouped by measure first (all Revenue rows together, all Quantity rows together)\n * Then within each measure group, rows are ordered by dimension values\n */\nfunction buildPivotedRows(\n data: any[],\n config: PivotConfig,\n timeValues: string[],\n getFieldLabel: (field: string) => string\n): PivotRow[] {\n // Group data by dimensions and time\n const grouped = groupByDimensions(data, config)\n const dimensionKeys = Array.from(grouped.keys())\n\n const rows: PivotRow[] = []\n const measureCount = config.measures.length\n const dimensionCount = dimensionKeys.length\n\n // Iterate over measures first, then dimensions\n // This groups all rows for one measure together\n config.measures.forEach((measure) => {\n dimensionKeys.forEach((dimensionKey, dimIndex) => {\n const timeData = grouped.get(dimensionKey)!\n const rowId = measureCount > 1\n ? `${measure}|${dimensionKey}`\n : dimensionKey\n\n const values: Record<string, any> = {}\n\n // Add dimension values\n const dimValues = dimensionKey === '__all__' ? [] : dimensionKey.split('|')\n config.dimensions.forEach((dim, idx) => {\n values[dim] = dimValues[idx] ?? ''\n })\n\n // Add measure name if multiple measures (for display in Measure column)\n if (measureCount > 1) {\n values['__measure__'] = getFieldLabel(measure)\n }\n\n // Add time period values\n timeValues.forEach(timeVal => {\n const dataPoint = timeData.get(timeVal)\n values[timeVal] = dataPoint?.[measure] ?? null\n })\n\n // Track grouping for row spanning (when multiple measures)\n // First row of each measure group should span all dimension rows\n const isFirstInGroup = dimIndex === 0\n const measureRowSpan = isFirstInGroup && measureCount > 1 ? dimensionCount : undefined\n\n rows.push({\n id: rowId,\n measureField: measure,\n values,\n isFirstInGroup,\n dimensionRowSpan: measureRowSpan\n })\n })\n })\n\n return rows\n}\n\n/**\n * Pivots flat data into time-columned table structure\n *\n * @param data Raw data array from query result\n * @param config Pivot configuration\n * @param getFieldLabel Function to get display label for a field\n * @param meta Optional cube metadata for looking up measure types\n * @returns Pivoted table data structure\n */\nexport function pivotTableData(\n data: any[],\n config: PivotConfig,\n getFieldLabel: (field: string) => string,\n _meta?: CubeMeta | null\n): PivotedTableData {\n if (!data || data.length === 0) {\n return { isPivoted: true, columns: [], rows: [] }\n }\n\n // Extract unique time values and sort chronologically\n const timeValues = extractAndSortTimeValues(data, config.timeDimension, config.granularity)\n\n // Build column definitions\n const columns = buildColumns(config, timeValues, getFieldLabel)\n\n // Build pivoted rows\n const rows = buildPivotedRows(data, config, timeValues, getFieldLabel)\n\n return { isPivoted: true, columns, rows }\n}\n\n/**\n * Looks up the measure type from metadata\n *\n * @param measureField The fully qualified measure field name (e.g., \"Sales.revenue\")\n * @param meta Cube metadata\n * @returns The measure type (e.g., \"sum\", \"count\", \"avg\") or undefined\n */\nexport function getMeasureType(measureField: string, meta: CubeMeta | null): string | undefined {\n if (!meta?.cubes) return undefined\n\n for (const cube of meta.cubes) {\n const measure = cube.measures.find(m => m.name === measureField)\n if (measure) {\n return measure.type\n }\n }\n\n return undefined\n}\n","/**\n * Data Table component with time dimension pivoting\n *\n * When a query includes a time dimension with granularity, the table\n * automatically pivots to show time periods as columns.\n */\n\nimport React, { useMemo } from 'react'\nimport { useCubeMeta } from '../../providers/CubeProvider'\nimport { getMeasureTypeIcon } from '../../icons'\nimport {\n hasTimeDimensionForPivot,\n pivotTableData,\n getMeasureType,\n getOrderedColumnsFromQuery,\n type PivotedTableData,\n type PivotColumn,\n type PivotRow\n} from '../../utils/pivotUtils'\nimport { formatAxisValue } from '../../utils/chartUtils'\nimport type { ChartProps, AxisFormatConfig } from '../../types'\n\nconst DataTable = React.memo(function DataTable({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = 300\n}: ChartProps) {\n const { getFieldLabel, meta } = useCubeMeta()\n\n // Detect if we should pivot based on query structure\n // Pass chartConfig.xAxis to respect user-configured column ordering\n const pivotConfig = useMemo(\n () => hasTimeDimensionForPivot(queryObject, chartConfig?.xAxis),\n [queryObject, chartConfig?.xAxis]\n )\n\n // Check if pivoting is enabled (default: true when time dimension present)\n const enablePivot = displayConfig?.pivotTimeDimension !== false\n\n // Compute pivoted data if applicable\n const pivotedData = useMemo<PivotedTableData | null>(() => {\n if (!pivotConfig || !enablePivot) return null\n return pivotTableData(data, pivotConfig, getFieldLabel, meta)\n }, [data, pivotConfig, enablePivot, getFieldLabel, meta])\n\n // Empty state\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data to display in table</div>\n </div>\n </div>\n )\n }\n\n // Render pivoted table if applicable\n if (pivotedData?.isPivoted && pivotedData.columns.length > 0) {\n return (\n <PivotedTable\n pivotedData={pivotedData}\n height={height}\n meta={meta}\n leftYAxisFormat={displayConfig?.leftYAxisFormat}\n />\n )\n }\n\n // Fallback to flat table rendering\n return (\n <FlatTable\n data={data}\n chartConfig={chartConfig}\n queryObject={queryObject}\n height={height}\n getFieldLabel={getFieldLabel}\n leftYAxisFormat={displayConfig?.leftYAxisFormat}\n />\n )\n})\n\nexport default DataTable\n\n/**\n * Pivoted table component - renders time dimension as columns\n */\nfunction PivotedTable({\n pivotedData,\n height,\n meta,\n leftYAxisFormat\n}: {\n pivotedData: PivotedTableData\n height: number | string\n meta: any\n leftYAxisFormat?: AxisFormatConfig\n}) {\n const { columns, rows } = pivotedData\n\n if (columns.length === 0 || rows.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data to display in table</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:overflow-auto\" style={{ height }}>\n <table className=\"dc:min-w-full dc:divide-y border-dc-border\">\n <thead className=\"bg-dc-surface-secondary dc:sticky dc:top-0\">\n <tr>\n {columns.map((col: PivotColumn) => (\n <th\n key={col.key}\n className={`dc:px-3 dc:py-2 dc:text-xs dc:font-medium text-dc-text-muted dc:uppercase dc:tracking-wider dc:whitespace-nowrap ${\n col.isTimeColumn ? 'dc:text-right' : 'dc:text-left'\n }`}\n >\n {col.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"bg-dc-surface dc:divide-y border-dc-border\">\n {rows.map((row: PivotRow) => (\n <PivotedTableRow\n key={row.id}\n row={row}\n columns={columns}\n meta={meta}\n leftYAxisFormat={leftYAxisFormat}\n />\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n/**\n * Single row in the pivoted table\n * Supports row spanning for measure cells when grouped by measure\n */\nfunction PivotedTableRow({\n row,\n columns,\n meta,\n leftYAxisFormat\n}: {\n row: PivotRow\n columns: PivotColumn[]\n meta: any\n leftYAxisFormat?: AxisFormatConfig\n}) {\n // Get measure icon for this row\n const measureType = getMeasureType(row.measureField, meta)\n const MeasureIcon = getMeasureTypeIcon(measureType)\n\n return (\n <tr className=\"hover:bg-dc-surface-secondary\">\n {columns.map((col: PivotColumn) => {\n const value = row.values[col.key]\n\n // Measure column - show icon + label with row spanning\n if (col.isMeasureColumn) {\n // Skip this cell if not first in measure group\n if (row.isFirstInGroup === false) {\n return null\n }\n\n return (\n <td\n key={col.key}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm text-dc-text dc:align-top\"\n rowSpan={row.dimensionRowSpan}\n >\n <div className=\"dc:flex dc:items-center\">\n <MeasureIcon className=\"dc:w-3.5 dc:h-3.5 dc:mr-1.5 text-dc-text-muted dc:shrink-0\" />\n <span>{value}</span>\n </div>\n </td>\n )\n }\n\n // Time column - right-aligned, formatted values (these are measure values)\n if (col.isTimeColumn) {\n return (\n <td\n key={col.key}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm dc:text-right text-dc-text\"\n >\n {formatPivotCellValue(value, leftYAxisFormat)}\n </td>\n )\n }\n\n // Dimension column - left-aligned (no row spanning) - no number formatting\n return (\n <td\n key={col.key}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm text-dc-text\"\n >\n {formatPivotCellValue(value)}\n </td>\n )\n })}\n </tr>\n )\n}\n\n/**\n * Format cell value for pivoted table display\n * Shows \"-\" for null/undefined values\n */\nfunction formatPivotCellValue(value: any, formatConfig?: AxisFormatConfig): string {\n if (value === null || value === undefined) return '-'\n if (typeof value === 'number') {\n // Use formatAxisValue if config provided\n if (formatConfig) {\n return formatAxisValue(value, formatConfig)\n }\n // Format with locale and up to 2 decimal places\n if (Number.isInteger(value)) {\n return value.toLocaleString()\n }\n return parseFloat(value.toFixed(2)).toLocaleString()\n }\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No'\n }\n return String(value)\n}\n\n/**\n * Flat table component - original non-pivoted table rendering\n */\nfunction FlatTable({\n data,\n chartConfig,\n queryObject,\n height,\n getFieldLabel,\n leftYAxisFormat\n}: {\n data: any[]\n chartConfig?: { xAxis?: string[] }\n queryObject?: ChartProps['queryObject']\n height: number | string\n getFieldLabel: (field: string) => string\n leftYAxisFormat?: AxisFormatConfig\n}) {\n // Get all columns available in data\n const allColumns = Object.keys(data[0] || {})\n\n // Determine column order with proper fallback:\n // 1. If xAxis is configured, use that order\n // 2. Otherwise, derive order from queryObject (dimensions + timeDimensions + measures)\n // 3. Fallback: Object.keys order\n const columns = useMemo(() => {\n // If xAxis is configured, use that order (filtered to existing columns)\n if (chartConfig?.xAxis && chartConfig.xAxis.length > 0) {\n return chartConfig.xAxis.filter(col => allColumns.includes(col))\n }\n\n // Derive order from queryObject\n const queryOrder = getOrderedColumnsFromQuery(queryObject)\n if (queryOrder.length > 0) {\n // Filter to only columns that exist in data\n const ordered = queryOrder.filter(col => allColumns.includes(col))\n // Add any columns in data that weren't in query (edge case)\n const remaining = allColumns.filter(col => !ordered.includes(col))\n return [...ordered, ...remaining]\n }\n\n // Final fallback: Object.keys order\n return allColumns\n }, [chartConfig?.xAxis, queryObject, allColumns])\n\n if (columns.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No columns available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Data structure is invalid</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:overflow-auto\" style={{ height }}>\n <table className=\"dc:min-w-full dc:divide-y border-dc-border\">\n <thead className=\"bg-dc-surface-secondary dc:sticky dc:top-0\">\n <tr>\n {columns.map((column) => (\n <th\n key={column}\n className=\"dc:px-3 dc:py-2 dc:text-left dc:text-xs dc:font-medium text-dc-text-muted dc:uppercase dc:tracking-wider\"\n >\n {getFieldLabel(column)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"bg-dc-surface dc:divide-y border-dc-border\">\n {data.map((row, index) => (\n <tr key={index} className=\"hover:bg-dc-surface-secondary\">\n {columns.map((column) => (\n <td\n key={column}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm text-dc-text\"\n >\n {formatCellValue(row[column], leftYAxisFormat)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n/**\n * Format cell value for flat table display\n */\nfunction formatCellValue(value: any, formatConfig?: AxisFormatConfig): string {\n if (value == null) return ''\n if (typeof value === 'number') {\n // Use formatAxisValue if config provided\n if (formatConfig) {\n return formatAxisValue(value, formatConfig)\n }\n return value.toLocaleString()\n }\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No'\n }\n return String(value)\n}\n"],"names":["getOrderedColumnsFromQuery","queryObject","columns","td","hasTimeDimensionForPivot","xAxisOverride","timeDim","dimensions","measures","field","measuresInXAxis","extractAndSortTimeValues","data","timeDimension","granularity","timeSet","row","rawTime","formattedTime","formatTimeValue","buildColumns","config","timeValues","getFieldLabel","dim","timeVal","groupByDimensions","grouped","dimKey","buildPivotedRows","dimensionKeys","rows","measureCount","dimensionCount","measure","dimensionKey","dimIndex","timeData","rowId","values","dimValues","idx","dataPoint","isFirstInGroup","measureRowSpan","pivotTableData","_meta","getMeasureType","measureField","meta","cube","m","DataTable","React","chartConfig","displayConfig","height","useCubeMeta","pivotConfig","useMemo","enablePivot","pivotedData","jsx","jsxs","PivotedTable","FlatTable","leftYAxisFormat","col","PivotedTableRow","measureType","MeasureIcon","getMeasureTypeIcon","value","formatPivotCellValue","formatConfig","formatAxisValue","allColumns","queryOrder","ordered","remaining","column","index","formatCellValue"],"mappings":"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"}
1
+ {"version":3,"file":"chart-data-table-Ba_6tuJw.js","sources":["../../../src/client/utils/pivotUtils.ts","../../../src/client/components/charts/DataTable.tsx"],"sourcesContent":["/**\n * Pivot utilities for DataTable time dimension pivoting\n *\n * When a query includes a time dimension with granularity, transforms flat data\n * into a pivoted structure with time periods as columns.\n */\n\nimport type { CubeQuery, CubeMeta } from '../types'\nimport { formatTimeValue } from './chartUtils'\n\n/**\n * Derives ordered column list from a CubeQuery object.\n * Order: dimensions, timeDimensions (as field names), measures\n *\n * @param queryObject The CubeQuery object\n * @returns Array of field names in order\n */\nexport function getOrderedColumnsFromQuery(queryObject?: CubeQuery): string[] {\n if (!queryObject) return []\n\n const columns: string[] = []\n\n // Add regular dimensions first\n if (queryObject.dimensions) {\n columns.push(...queryObject.dimensions)\n }\n\n // Add time dimensions\n if (queryObject.timeDimensions) {\n queryObject.timeDimensions.forEach(td => {\n if (!columns.includes(td.dimension)) {\n columns.push(td.dimension)\n }\n })\n }\n\n // Add measures last\n if (queryObject.measures) {\n columns.push(...queryObject.measures)\n }\n\n return columns\n}\n\n/**\n * Configuration for pivoting based on query structure\n */\nexport interface PivotConfig {\n /** Time dimension field name (e.g., \"Sales.date\") */\n timeDimension: string\n /** Time granularity (e.g., \"month\", \"day\", \"year\") */\n granularity: string\n /** Non-time dimension fields */\n dimensions: string[]\n /** Measure fields */\n measures: string[]\n}\n\n/**\n * Column definition for pivoted table\n */\nexport interface PivotColumn {\n /** Column key for data access */\n key: string\n /** Display label for column header */\n label: string\n /** Whether this is a time column (vs row identifier column) */\n isTimeColumn: boolean\n /** Whether this is the measure column */\n isMeasureColumn?: boolean\n}\n\n/**\n * Row in the pivoted table\n */\nexport interface PivotRow {\n /** Unique row identifier */\n id: string\n /** The measure field name (for icon lookup) */\n measureField: string\n /** Values keyed by column key */\n values: Record<string, any>\n /** Whether this is the first row in a dimension group (for row spanning) */\n isFirstInGroup?: boolean\n /** Number of rows to span for dimension cells (only set on first row in group) */\n dimensionRowSpan?: number\n}\n\n/**\n * Result of pivoting table data\n */\nexport interface PivotedTableData {\n /** Whether data was pivoted (has time dimension with granularity) */\n isPivoted: boolean\n /** Column definitions for the pivoted table */\n columns: PivotColumn[]\n /** Rows of pivoted data */\n rows: PivotRow[]\n}\n\n/**\n * Determines if a query has a time dimension with granularity that should trigger pivoting\n * @param queryObject The CubeQuery object\n * @param xAxisOverride Optional array of fields to use for filtering dimensions and measures\n * (for respecting chartConfig.xAxis configuration)\n * @returns PivotConfig if pivoting should occur, null otherwise\n */\nexport function hasTimeDimensionForPivot(\n queryObject?: CubeQuery,\n xAxisOverride?: string[]\n): PivotConfig | null {\n if (!queryObject?.timeDimensions?.length) return null\n\n // Find the first time dimension with granularity\n const timeDim = queryObject.timeDimensions.find(td => td.granularity)\n if (!timeDim?.granularity) return null\n\n // Must have at least one measure to pivot\n if (!queryObject.measures?.length) return null\n\n let dimensions: string[]\n let measures: string[]\n\n if (xAxisOverride && xAxisOverride.length > 0) {\n // Filter dimensions from xAxisOverride (excluding time dimension and measures)\n dimensions = xAxisOverride.filter(field => {\n // Exclude the time dimension being pivoted (it becomes columns)\n if (field === timeDim.dimension) return false\n // Exclude measures (they become row values, not dimension columns)\n if (queryObject.measures?.includes(field)) return false\n return true\n })\n\n // Filter measures from xAxisOverride - only show measures that are in xAxis\n const measuresInXAxis = xAxisOverride.filter(field =>\n queryObject.measures?.includes(field)\n )\n // If xAxis contains measures, use only those; otherwise fall back to all measures\n measures = measuresInXAxis.length > 0 ? measuresInXAxis : queryObject.measures\n } else {\n dimensions = queryObject.dimensions || []\n measures = queryObject.measures\n }\n\n // Must have at least one measure after filtering\n if (measures.length === 0) return null\n\n return {\n timeDimension: timeDim.dimension,\n granularity: timeDim.granularity,\n dimensions,\n measures\n }\n}\n\n/**\n * Extracts unique time values from data and sorts them chronologically\n */\nfunction extractAndSortTimeValues(\n data: any[],\n timeDimension: string,\n granularity: string\n): string[] {\n const timeSet = new Set<string>()\n\n data.forEach(row => {\n const rawTime = row[timeDimension]\n if (rawTime != null) {\n const formattedTime = formatTimeValue(rawTime, granularity)\n timeSet.add(formattedTime)\n }\n })\n\n // Sort chronologically - ISO date strings sort correctly alphabetically\n return Array.from(timeSet).sort()\n}\n\n/**\n * Builds column definitions for pivoted table\n * Order: Measure (if multiple) -> Dimensions -> Time columns\n */\nfunction buildColumns(\n config: PivotConfig,\n timeValues: string[],\n getFieldLabel: (field: string) => string\n): PivotColumn[] {\n const columns: PivotColumn[] = []\n\n // Add measure column first (if multiple measures)\n if (config.measures.length > 1) {\n columns.push({\n key: '__measure__',\n label: 'Measure',\n isTimeColumn: false,\n isMeasureColumn: true\n })\n }\n\n // Add dimension columns\n config.dimensions.forEach(dim => {\n columns.push({\n key: dim,\n label: getFieldLabel(dim),\n isTimeColumn: false\n })\n })\n\n // Add time columns (already sorted chronologically)\n timeValues.forEach(timeVal => {\n columns.push({\n key: timeVal,\n label: timeVal,\n isTimeColumn: true\n })\n })\n\n return columns\n}\n\n/**\n * Groups data by dimension values, then by time period\n * Returns Map<dimensionKey, Map<formattedTime, dataRow>>\n */\nfunction groupByDimensions(\n data: any[],\n config: PivotConfig\n): Map<string, Map<string, any>> {\n const grouped = new Map<string, Map<string, any>>()\n\n data.forEach(row => {\n // Build dimension key from all dimension values\n const dimKey = config.dimensions.length > 0\n ? config.dimensions.map(dim => String(row[dim] ?? '')).join('|')\n : '__all__'\n\n // Get or create time map for this dimension combo\n if (!grouped.has(dimKey)) {\n grouped.set(dimKey, new Map())\n }\n\n // Store data point by formatted time value\n const rawTime = row[config.timeDimension]\n if (rawTime != null) {\n const formattedTime = formatTimeValue(rawTime, config.granularity)\n grouped.get(dimKey)!.set(formattedTime, row)\n }\n })\n\n return grouped\n}\n\n/**\n * Builds pivoted rows from grouped data\n * Rows are grouped by measure first (all Revenue rows together, all Quantity rows together)\n * Then within each measure group, rows are ordered by dimension values\n */\nfunction buildPivotedRows(\n data: any[],\n config: PivotConfig,\n timeValues: string[],\n getFieldLabel: (field: string) => string\n): PivotRow[] {\n // Group data by dimensions and time\n const grouped = groupByDimensions(data, config)\n const dimensionKeys = Array.from(grouped.keys())\n\n const rows: PivotRow[] = []\n const measureCount = config.measures.length\n const dimensionCount = dimensionKeys.length\n\n // Iterate over measures first, then dimensions\n // This groups all rows for one measure together\n config.measures.forEach((measure) => {\n dimensionKeys.forEach((dimensionKey, dimIndex) => {\n const timeData = grouped.get(dimensionKey)!\n const rowId = measureCount > 1\n ? `${measure}|${dimensionKey}`\n : dimensionKey\n\n const values: Record<string, any> = {}\n\n // Add dimension values\n const dimValues = dimensionKey === '__all__' ? [] : dimensionKey.split('|')\n config.dimensions.forEach((dim, idx) => {\n values[dim] = dimValues[idx] ?? ''\n })\n\n // Add measure name if multiple measures (for display in Measure column)\n if (measureCount > 1) {\n values['__measure__'] = getFieldLabel(measure)\n }\n\n // Add time period values\n timeValues.forEach(timeVal => {\n const dataPoint = timeData.get(timeVal)\n values[timeVal] = dataPoint?.[measure] ?? null\n })\n\n // Track grouping for row spanning (when multiple measures)\n // First row of each measure group should span all dimension rows\n const isFirstInGroup = dimIndex === 0\n const measureRowSpan = isFirstInGroup && measureCount > 1 ? dimensionCount : undefined\n\n rows.push({\n id: rowId,\n measureField: measure,\n values,\n isFirstInGroup,\n dimensionRowSpan: measureRowSpan\n })\n })\n })\n\n return rows\n}\n\n/**\n * Pivots flat data into time-columned table structure\n *\n * @param data Raw data array from query result\n * @param config Pivot configuration\n * @param getFieldLabel Function to get display label for a field\n * @param meta Optional cube metadata for looking up measure types\n * @returns Pivoted table data structure\n */\nexport function pivotTableData(\n data: any[],\n config: PivotConfig,\n getFieldLabel: (field: string) => string,\n _meta?: CubeMeta | null\n): PivotedTableData {\n if (!data || data.length === 0) {\n return { isPivoted: true, columns: [], rows: [] }\n }\n\n // Extract unique time values and sort chronologically\n const timeValues = extractAndSortTimeValues(data, config.timeDimension, config.granularity)\n\n // Build column definitions\n const columns = buildColumns(config, timeValues, getFieldLabel)\n\n // Build pivoted rows\n const rows = buildPivotedRows(data, config, timeValues, getFieldLabel)\n\n return { isPivoted: true, columns, rows }\n}\n\n/**\n * Looks up the measure type from metadata\n *\n * @param measureField The fully qualified measure field name (e.g., \"Sales.revenue\")\n * @param meta Cube metadata\n * @returns The measure type (e.g., \"sum\", \"count\", \"avg\") or undefined\n */\nexport function getMeasureType(measureField: string, meta: CubeMeta | null): string | undefined {\n if (!meta?.cubes) return undefined\n\n for (const cube of meta.cubes) {\n const measure = cube.measures.find(m => m.name === measureField)\n if (measure) {\n return measure.type\n }\n }\n\n return undefined\n}\n","/**\n * Data Table component with time dimension pivoting\n *\n * When a query includes a time dimension with granularity, the table\n * automatically pivots to show time periods as columns.\n */\n\nimport React, { useMemo } from 'react'\nimport { useCubeMeta } from '../../providers/CubeProvider'\nimport { getMeasureTypeIcon } from '../../icons'\nimport {\n hasTimeDimensionForPivot,\n pivotTableData,\n getMeasureType,\n getOrderedColumnsFromQuery,\n type PivotedTableData,\n type PivotColumn,\n type PivotRow\n} from '../../utils/pivotUtils'\nimport { formatAxisValue } from '../../utils/chartUtils'\nimport type { ChartProps, AxisFormatConfig } from '../../types'\n\nconst DataTable = React.memo(function DataTable({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = 300\n}: ChartProps) {\n const { getFieldLabel, meta } = useCubeMeta()\n\n // Detect if we should pivot based on query structure\n // Pass chartConfig.xAxis to respect user-configured column ordering\n const pivotConfig = useMemo(\n () => hasTimeDimensionForPivot(queryObject, chartConfig?.xAxis),\n [queryObject, chartConfig?.xAxis]\n )\n\n // Check if pivoting is enabled (default: true when time dimension present)\n const enablePivot = displayConfig?.pivotTimeDimension !== false\n\n // Compute pivoted data if applicable\n const pivotedData = useMemo<PivotedTableData | null>(() => {\n if (!pivotConfig || !enablePivot) return null\n return pivotTableData(data, pivotConfig, getFieldLabel, meta)\n }, [data, pivotConfig, enablePivot, getFieldLabel, meta])\n\n // Empty state\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data to display in table</div>\n </div>\n </div>\n )\n }\n\n // Render pivoted table if applicable\n if (pivotedData?.isPivoted && pivotedData.columns.length > 0) {\n return (\n <PivotedTable\n pivotedData={pivotedData}\n height={height}\n meta={meta}\n leftYAxisFormat={displayConfig?.leftYAxisFormat}\n />\n )\n }\n\n // Fallback to flat table rendering\n return (\n <FlatTable\n data={data}\n chartConfig={chartConfig}\n queryObject={queryObject}\n height={height}\n getFieldLabel={getFieldLabel}\n leftYAxisFormat={displayConfig?.leftYAxisFormat}\n />\n )\n})\n\nexport default DataTable\n\n/**\n * Pivoted table component - renders time dimension as columns\n */\nfunction PivotedTable({\n pivotedData,\n height,\n meta,\n leftYAxisFormat\n}: {\n pivotedData: PivotedTableData\n height: number | string\n meta: any\n leftYAxisFormat?: AxisFormatConfig\n}) {\n const { columns, rows } = pivotedData\n\n if (columns.length === 0 || rows.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">No data to display in table</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:overflow-auto\" style={{ height }}>\n <table className=\"dc:min-w-full dc:divide-y border-dc-border\">\n <thead className=\"bg-dc-surface-secondary dc:sticky dc:top-0\">\n <tr>\n {columns.map((col: PivotColumn) => (\n <th\n key={col.key}\n className={`dc:px-3 dc:py-2 dc:text-xs dc:font-medium text-dc-text-muted dc:uppercase dc:tracking-wider dc:whitespace-nowrap ${\n col.isTimeColumn ? 'dc:text-right' : 'dc:text-left'\n }`}\n >\n {col.label}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"bg-dc-surface dc:divide-y border-dc-border\">\n {rows.map((row: PivotRow) => (\n <PivotedTableRow\n key={row.id}\n row={row}\n columns={columns}\n meta={meta}\n leftYAxisFormat={leftYAxisFormat}\n />\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n/**\n * Single row in the pivoted table\n * Supports row spanning for measure cells when grouped by measure\n */\nfunction PivotedTableRow({\n row,\n columns,\n meta,\n leftYAxisFormat\n}: {\n row: PivotRow\n columns: PivotColumn[]\n meta: any\n leftYAxisFormat?: AxisFormatConfig\n}) {\n // Get measure icon for this row\n const measureType = getMeasureType(row.measureField, meta)\n const MeasureIcon = getMeasureTypeIcon(measureType)\n\n return (\n <tr className=\"hover:bg-dc-surface-secondary\">\n {columns.map((col: PivotColumn) => {\n const value = row.values[col.key]\n\n // Measure column - show icon + label with row spanning\n if (col.isMeasureColumn) {\n // Skip this cell if not first in measure group\n if (row.isFirstInGroup === false) {\n return null\n }\n\n return (\n <td\n key={col.key}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm text-dc-text dc:align-top\"\n rowSpan={row.dimensionRowSpan}\n >\n <div className=\"dc:flex dc:items-center\">\n <MeasureIcon className=\"dc:w-3.5 dc:h-3.5 dc:mr-1.5 text-dc-text-muted dc:shrink-0\" />\n <span>{value}</span>\n </div>\n </td>\n )\n }\n\n // Time column - right-aligned, formatted values (these are measure values)\n if (col.isTimeColumn) {\n return (\n <td\n key={col.key}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm dc:text-right text-dc-text\"\n >\n {formatPivotCellValue(value, leftYAxisFormat)}\n </td>\n )\n }\n\n // Dimension column - left-aligned (no row spanning) - no number formatting\n return (\n <td\n key={col.key}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm text-dc-text\"\n >\n {formatPivotCellValue(value)}\n </td>\n )\n })}\n </tr>\n )\n}\n\n/**\n * Format cell value for pivoted table display\n * Shows \"-\" for null/undefined values\n */\nfunction formatPivotCellValue(value: any, formatConfig?: AxisFormatConfig): string {\n if (value === null || value === undefined) return '-'\n if (typeof value === 'number') {\n // Use formatAxisValue if config provided\n if (formatConfig) {\n return formatAxisValue(value, formatConfig)\n }\n // Format with locale and up to 2 decimal places\n if (Number.isInteger(value)) {\n return value.toLocaleString()\n }\n return parseFloat(value.toFixed(2)).toLocaleString()\n }\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No'\n }\n return String(value)\n}\n\n/**\n * Flat table component - original non-pivoted table rendering\n */\nfunction FlatTable({\n data,\n chartConfig,\n queryObject,\n height,\n getFieldLabel,\n leftYAxisFormat\n}: {\n data: any[]\n chartConfig?: { xAxis?: string[] }\n queryObject?: ChartProps['queryObject']\n height: number | string\n getFieldLabel: (field: string) => string\n leftYAxisFormat?: AxisFormatConfig\n}) {\n // Get all columns available in data\n const allColumns = Object.keys(data[0] || {})\n\n // Determine column order with proper fallback:\n // 1. If xAxis is configured, use that order\n // 2. Otherwise, derive order from queryObject (dimensions + timeDimensions + measures)\n // 3. Fallback: Object.keys order\n const columns = useMemo(() => {\n // If xAxis is configured, use that order (filtered to existing columns)\n if (chartConfig?.xAxis && chartConfig.xAxis.length > 0) {\n return chartConfig.xAxis.filter(col => allColumns.includes(col))\n }\n\n // Derive order from queryObject\n const queryOrder = getOrderedColumnsFromQuery(queryObject)\n if (queryOrder.length > 0) {\n // Filter to only columns that exist in data\n const ordered = queryOrder.filter(col => allColumns.includes(col))\n // Add any columns in data that weren't in query (edge case)\n const remaining = allColumns.filter(col => !ordered.includes(col))\n return [...ordered, ...remaining]\n }\n\n // Final fallback: Object.keys order\n return allColumns\n }, [chartConfig?.xAxis, queryObject, allColumns])\n\n if (columns.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No columns available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Data structure is invalid</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:overflow-auto\" style={{ height }}>\n <table className=\"dc:min-w-full dc:divide-y border-dc-border\">\n <thead className=\"bg-dc-surface-secondary dc:sticky dc:top-0\">\n <tr>\n {columns.map((column) => (\n <th\n key={column}\n className=\"dc:px-3 dc:py-2 dc:text-left dc:text-xs dc:font-medium text-dc-text-muted dc:uppercase dc:tracking-wider\"\n >\n {getFieldLabel(column)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"bg-dc-surface dc:divide-y border-dc-border\">\n {data.map((row, index) => (\n <tr key={index} className=\"hover:bg-dc-surface-secondary\">\n {columns.map((column) => (\n <td\n key={column}\n className=\"dc:px-3 dc:py-2 dc:whitespace-nowrap dc:text-sm text-dc-text\"\n >\n {formatCellValue(row[column], leftYAxisFormat)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n/**\n * Format cell value for flat table display\n */\nfunction formatCellValue(value: any, formatConfig?: AxisFormatConfig): string {\n if (value == null) return ''\n if (typeof value === 'number') {\n // Use formatAxisValue if config provided\n if (formatConfig) {\n return formatAxisValue(value, formatConfig)\n }\n return value.toLocaleString()\n }\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No'\n }\n return String(value)\n}\n"],"names":["getOrderedColumnsFromQuery","queryObject","columns","td","hasTimeDimensionForPivot","xAxisOverride","timeDim","dimensions","measures","field","measuresInXAxis","extractAndSortTimeValues","data","timeDimension","granularity","timeSet","row","rawTime","formattedTime","formatTimeValue","buildColumns","config","timeValues","getFieldLabel","dim","timeVal","groupByDimensions","grouped","dimKey","buildPivotedRows","dimensionKeys","rows","measureCount","dimensionCount","measure","dimensionKey","dimIndex","timeData","rowId","values","dimValues","idx","dataPoint","isFirstInGroup","measureRowSpan","pivotTableData","_meta","getMeasureType","measureField","meta","cube","m","DataTable","React","chartConfig","displayConfig","height","useCubeMeta","pivotConfig","useMemo","enablePivot","pivotedData","jsx","jsxs","PivotedTable","FlatTable","leftYAxisFormat","col","PivotedTableRow","measureType","MeasureIcon","getMeasureTypeIcon","value","formatPivotCellValue","formatConfig","formatAxisValue","allColumns","queryOrder","ordered","remaining","column","index","formatCellValue"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as t, jsxs as s } from "react/jsx-runtime";
2
2
  import ce, { useState as O, useRef as U, useEffect as se } from "react";
3
- import { I as de, d as ne } from "./icons-DRreo6m8.js";
3
+ import { I as de, d as ne } from "./icons-DAeqv1iX.js";
4
4
  import { u as ie } from "./charts-core-DmGfleFz.js";
5
- import { f as re } from "./chart-kpi-number-C-5m3qt5.js";
5
+ import { f as re } from "./chart-kpi-number-C29Vj2g8.js";
6
6
  function oe({
7
7
  values: w,
8
8
  lastValue: p,
@@ -348,4 +348,4 @@ const he = ce.memo(function({
348
348
  export {
349
349
  he as default
350
350
  };
351
- //# sourceMappingURL=chart-kpi-delta-CWCmi8vL.js.map
351
+ //# sourceMappingURL=chart-kpi-delta-D9XJoKuA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chart-kpi-delta-CWCmi8vL.js","sources":["../../../src/client/components/charts/KpiDelta.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport { Icon } from \"@iconify/react\";\nimport infoCircleIcon from \"@iconify-icons/tabler/info-circle\";\nimport { useCubeFieldLabel } from \"../../hooks/useCubeFieldLabel\";\nimport { filterIncompletePeriod } from \"../../utils/periodUtils\";\nimport type { ChartProps } from \"../../types\";\n\ninterface VarianceHistogramProps {\n values: number[];\n lastValue: number;\n positiveColor: string;\n negativeColor: string;\n formatValue: (value: number) => string;\n width: number;\n height: number;\n}\n\nfunction VarianceHistogram({\n values,\n lastValue,\n positiveColor,\n negativeColor,\n formatValue,\n width,\n height,\n}: VarianceHistogramProps) {\n // Limit to most recent N values to fit in the histogram\n // Calculate max bars based on width (minimum 8px per bar including gap)\n const maxBars = Math.max(10, Math.floor(width / 10));\n const limitedValues =\n values.length > maxBars\n ? values.slice(-maxBars) // Take the most recent values\n : values;\n\n // Calculate variance (difference) from current/last value for each point\n const variances = limitedValues.map((value) => value - lastValue);\n\n // Find min/max variance for scaling (include 0 as baseline)\n const minVariance = Math.min(...variances, 0);\n const maxVariance = Math.max(...variances, 0);\n const range = Math.max(Math.abs(minVariance), Math.abs(maxVariance));\n\n if (range === 0 || variances.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center bg-dc-bg-secondary dc:rounded-sm dc:border border-dc-border\"\n style={{ width: `${width}px`, height: `${height}px` }}\n >\n <span className=\"dc:text-xs text-dc-text-muted\">No variance data</span>\n </div>\n );\n }\n\n // Calculate bar dimensions\n const barGap = 2;\n const availableWidth = width - (limitedValues.length - 1) * barGap;\n const barWidth = Math.max(4, availableWidth / limitedValues.length);\n\n // Calculate where zero line should be positioned (as percentage from top)\n // If maxVariance = 67 and minVariance = -24, total range = 91\n // Zero should be at 67/91 = 73.6% from top\n const totalRange = maxVariance - minVariance;\n const zeroLinePercent =\n totalRange > 0 ? (maxVariance / totalRange) * 100 : 50;\n\n return (\n <div className=\"dc:flex dc:items-center dc:space-x-2\">\n {/* Histogram bars */}\n <div\n className=\"dc:relative\"\n style={{\n width: `${width}px`,\n height: `${height}px`,\n }}\n >\n {/* Zero line (represents current value) */}\n <div\n className=\"dc:absolute dc:left-0 dc:right-0\"\n style={{\n height: \"1px\",\n top: `${zeroLinePercent}%`,\n backgroundColor: \"var(--dc-border)\",\n zIndex: 1,\n }}\n />\n\n {/* Variance bars - oldest to newest (left to right) */}\n {variances.map((variance, index) => {\n // Calculate bar height as proportion of total range\n const normalizedHeight = Math.abs(variance) / totalRange;\n const barHeight = Math.max(2, normalizedHeight * (height - 4));\n const isPositive = variance >= 0;\n const isLastValue = index === limitedValues.length - 1;\n const color = isPositive ? positiveColor : negativeColor;\n const xPosition = index * (barWidth + barGap);\n\n return (\n <div\n key={index}\n className=\"dc:absolute rounded-xs\"\n style={{\n left: `${xPosition}px`,\n width: `${barWidth}px`,\n height: `${barHeight}px`,\n backgroundColor: color,\n opacity: isLastValue ? 1 : 0.6,\n // Position bar relative to zero line\n ...(isPositive\n ? { bottom: `${100 - zeroLinePercent}%` }\n : { top: `${zeroLinePercent}%` }),\n zIndex: 2,\n }}\n title={`${formatValue(limitedValues[index])}: ${variance >= 0 ? \"+\" : \"\"}${formatValue(variance)} vs current`}\n />\n );\n })}\n </div>\n\n {/* Variance labels on the right - show actual value difference */}\n <div\n className=\"dc:flex dc:flex-col dc:justify-between dc:text-xs text-dc-text-muted\"\n style={{ height: `${height}px` }}\n >\n <span>+{formatValue(maxVariance)}</span>\n <span>\n {minVariance < 0 ? \"\" : \"\"}\n {formatValue(minVariance)}\n </span>\n </div>\n </div>\n );\n}\n\nconst KpiDelta = React.memo(function KpiDelta({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n}: ChartProps) {\n const [fontSize, setFontSize] = useState(32);\n const [textWidth, setTextWidth] = useState(250);\n const containerRef = useRef<HTMLDivElement>(null);\n const valueRef = useRef<HTMLDivElement>(null);\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel();\n\n // Calculate font size and text width based on container dimensions\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const container = containerRef.current;\n const rect = container.getBoundingClientRect();\n const containerWidth = rect.width;\n const containerHeight = rect.height;\n\n if (containerWidth > 0 && containerHeight > 0) {\n const widthBasedSize = containerWidth / 4;\n const heightBasedSize = containerHeight / 4;\n const baseFontSize = Math.min(widthBasedSize, heightBasedSize);\n const clampedFontSize = Math.max(28, Math.min(baseFontSize, 140));\n setFontSize(clampedFontSize);\n\n setTimeout(() => {\n if (valueRef.current) {\n const textRect = valueRef.current.getBoundingClientRect();\n const measuredWidth = textRect.width;\n // Scale histogram width with container, accounting for labels on the right (~60px)\n const maxHistogramWidth = containerWidth - 100; // Leave room for padding and labels\n const effectiveWidth = Math.max(\n measuredWidth,\n Math.min(maxHistogramWidth, containerWidth * 0.7),\n );\n setTextWidth(Math.max(100, effectiveWidth)); // Minimum 100px\n }\n }, 10);\n }\n }\n };\n\n const timer = setTimeout(updateDimensions, 50);\n\n const resizeObserver = new ResizeObserver(() => {\n setTimeout(updateDimensions, 10);\n });\n\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current);\n }\n\n return () => {\n clearTimeout(timer);\n resizeObserver.disconnect();\n };\n }, [data, chartConfig]);\n\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n No data points to display\n </div>\n </div>\n </div>\n );\n }\n\n // Extract value and dimension fields from chart config\n let valueFields: string[] = [];\n let dimensionFields: string[] = [];\n\n if (chartConfig?.yAxis) {\n valueFields = Array.isArray(chartConfig.yAxis)\n ? chartConfig.yAxis\n : [chartConfig.yAxis];\n }\n\n if (chartConfig?.xAxis) {\n dimensionFields = Array.isArray(chartConfig.xAxis)\n ? chartConfig.xAxis\n : [chartConfig.xAxis];\n }\n\n if (valueFields.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n backgroundColor: \"var(--dc-danger-bg)\",\n color: \"var(--dc-danger)\",\n borderColor: \"var(--dc-danger-border)\",\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Error</div>\n <div className=\"dc:text-xs\">No measure field configured</div>\n </div>\n </div>\n );\n }\n\n const valueField = valueFields[0];\n const dimensionField = dimensionFields[0]; // Optional\n\n // Sort data by dimension if available (for time series)\n let sortedData = [...data];\n if (dimensionField) {\n sortedData = sortedData.sort((a, b) => {\n const aVal = a[dimensionField];\n const bVal = b[dimensionField];\n if (aVal < bVal) return -1;\n if (aVal > bVal) return 1;\n return 0;\n });\n }\n\n // Filter out incomplete or last period if enabled\n const { useLastCompletePeriod = true, skipLastPeriod = false } =\n displayConfig;\n const {\n filteredData,\n excludedIncompletePeriod,\n skippedLastPeriod,\n granularity,\n } = filterIncompletePeriod(\n sortedData,\n dimensionField,\n queryObject,\n useLastCompletePeriod,\n skipLastPeriod,\n );\n\n // Use filtered data for calculations\n const dataToUse = filteredData;\n\n // Extract values from filtered data\n const values = dataToUse\n .map((row) => row[valueField])\n .filter((val) => val !== null && val !== undefined && !isNaN(Number(val)))\n .map((val) => Number(val));\n\n if (values.length < 2) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n backgroundColor: \"var(--dc-warning-bg)\",\n color: \"var(--dc-warning)\",\n borderColor: \"var(--dc-warning-border)\",\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Insufficient Data</div>\n <div className=\"dc:text-xs\">\n Delta calculation requires at least 2 data points\n </div>\n <div className=\"dc:text-xs\">Current data points: {values.length}</div>\n </div>\n </div>\n );\n }\n\n // Calculate delta between last and second-last values\n const lastValue = values[values.length - 1];\n const secondLastValue = values[values.length - 2];\n const absoluteChange = lastValue - secondLastValue;\n const percentageChange =\n secondLastValue !== 0\n ? (absoluteChange / Math.abs(secondLastValue)) * 100\n : 0;\n\n const isPositiveChange = absoluteChange >= 0;\n\n // Format number with appropriate units and decimals\n const formatNumber = (value: number | null | undefined): string => {\n // If custom formatValue is provided, use it exclusively\n if (displayConfig.formatValue) {\n return displayConfig.formatValue(value);\n }\n\n // Null handling: Show placeholder for missing data\n if (value === null || value === undefined) {\n return \"—\";\n }\n\n const decimals = displayConfig.decimals ?? 0;\n const prefix = displayConfig.prefix ?? \"\";\n\n let formattedValue: string;\n\n if (Math.abs(value) >= 1e9) {\n formattedValue = (value / 1e9).toFixed(decimals) + \"B\";\n } else if (Math.abs(value) >= 1e6) {\n formattedValue = (value / 1e6).toFixed(decimals) + \"M\";\n } else if (Math.abs(value) >= 1e3) {\n formattedValue = (value / 1e3).toFixed(decimals) + \"K\";\n } else {\n formattedValue = value.toFixed(decimals);\n }\n\n return prefix + formattedValue;\n };\n\n // Get colors from palette\n const getPositiveColor = (): string => {\n if (\n displayConfig.positiveColorIndex !== undefined &&\n colorPalette?.colors\n ) {\n const colorIndex = displayConfig.positiveColorIndex;\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex];\n }\n }\n return \"#10b981\"; // Default green\n };\n\n const getNegativeColor = (): string => {\n if (\n displayConfig.negativeColorIndex !== undefined &&\n colorPalette?.colors\n ) {\n const colorIndex = displayConfig.negativeColorIndex;\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex];\n }\n }\n return \"#ef4444\"; // Default red\n };\n\n const positiveColor = getPositiveColor();\n const negativeColor = getNegativeColor();\n const currentColor = isPositiveChange ? positiveColor : negativeColor;\n\n return (\n <div\n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n }}\n >\n {/* Field Label */}\n <div\n className=\"text-dc-text-secondary dc:font-bold dc:text-center dc:mb-2 dc:flex dc:items-center dc:justify-center dc:gap-1\"\n style={{\n fontSize: \"14px\",\n lineHeight: \"1.2\",\n }}\n >\n <span>\n {(() => {\n const label = getFieldLabel(valueField);\n return label && label.length > 1 ? label : valueField;\n })()}\n </span>\n {(excludedIncompletePeriod || skippedLastPeriod) && (\n <span\n title={\n skippedLastPeriod\n ? `Excludes last ${granularity || \"period\"}`\n : `Excludes current incomplete ${granularity}`\n }\n className=\"dc:cursor-help\"\n >\n <Icon\n icon={infoCircleIcon}\n className=\"dc:w-4 dc:h-4 text-dc-text-muted dc:opacity-70\"\n />\n </span>\n )}\n </div>\n\n {/* Main KPI Value and Delta */}\n <div className=\"dc:flex dc:items-center dc:justify-center dc:space-x-4 dc:mb-2\">\n {/* Main KPI Value */}\n <div\n ref={valueRef}\n className=\"dc:font-bold dc:leading-none\"\n style={{\n fontSize: `${fontSize}px`,\n color: \"var(--dc-text)\", // Keep main value neutral\n }}\n >\n {formatNumber(lastValue)}\n </div>\n\n {/* Delta Information */}\n <div className=\"dc:flex dc:items-center dc:space-x-1\">\n {/* Arrow */}\n <div\n className=\"dc:font-bold\"\n style={{\n color: currentColor,\n fontSize: `${fontSize * 0.35}px`,\n }}\n >\n {isPositiveChange ? \"▲\" : \"▼\"}\n </div>\n\n {/* Delta Values */}\n <div className=\"dc:text-left\">\n <div\n className=\"dc:font-bold dc:leading-tight\"\n style={{\n fontSize: `${fontSize * 0.35}px`,\n color: currentColor,\n }}\n >\n {isPositiveChange ? \"+\" : \"\"}\n {formatNumber(absoluteChange)}\n </div>\n <div\n className=\"dc:font-semibold dc:leading-tight\"\n style={{\n fontSize: `${fontSize * 0.28}px`,\n color: currentColor,\n opacity: 0.8,\n }}\n >\n {isPositiveChange ? \"+\" : \"\"}\n {percentageChange.toFixed(1)}%\n </div>\n </div>\n </div>\n </div>\n\n {/* Unit/Suffix (hidden when formatValue is provided) */}\n {displayConfig.suffix && !displayConfig.formatValue && (\n <div\n className=\"text-dc-text-muted dc:text-center dc:mb-3\"\n style={{\n fontSize: \"14px\",\n lineHeight: \"1.2\",\n opacity: 0.8,\n }}\n >\n {displayConfig.suffix}\n </div>\n )}\n\n {/* Variance Histogram */}\n {displayConfig.showHistogram !== false && values.length > 2 && (\n <div className=\"dc:mt-2 dc:w-full dc:flex dc:justify-center dc:overflow-hidden\">\n <VarianceHistogram\n values={values}\n lastValue={lastValue}\n positiveColor={positiveColor}\n negativeColor={negativeColor}\n formatValue={formatNumber}\n width={textWidth}\n height={64}\n />\n </div>\n )}\n </div>\n );\n})\n\nexport default KpiDelta\n"],"names":["VarianceHistogram","values","lastValue","positiveColor","negativeColor","formatValue","width","height","maxBars","limitedValues","variances","value","minVariance","maxVariance","jsx","barGap","availableWidth","barWidth","totalRange","zeroLinePercent","jsxs","variance","index","normalizedHeight","barHeight","isPositive","isLastValue","color","xPosition","KpiDelta","React","data","chartConfig","displayConfig","queryObject","colorPalette","fontSize","setFontSize","useState","textWidth","setTextWidth","containerRef","useRef","valueRef","getFieldLabel","useCubeFieldLabel","useEffect","updateDimensions","rect","containerWidth","containerHeight","widthBasedSize","heightBasedSize","baseFontSize","clampedFontSize","measuredWidth","maxHistogramWidth","effectiveWidth","timer","resizeObserver","valueFields","dimensionFields","valueField","dimensionField","sortedData","a","b","aVal","bVal","useLastCompletePeriod","skipLastPeriod","filteredData","excludedIncompletePeriod","skippedLastPeriod","granularity","filterIncompletePeriod","row","val","secondLastValue","absoluteChange","percentageChange","isPositiveChange","formatNumber","decimals","prefix","formattedValue","getPositiveColor","colorIndex","getNegativeColor","currentColor","label","Icon","infoCircleIcon"],"mappings":"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"}
1
+ {"version":3,"file":"chart-kpi-delta-D9XJoKuA.js","sources":["../../../src/client/components/charts/KpiDelta.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from \"react\";\nimport { Icon } from \"@iconify/react\";\nimport infoCircleIcon from \"@iconify-icons/tabler/info-circle\";\nimport { useCubeFieldLabel } from \"../../hooks/useCubeFieldLabel\";\nimport { filterIncompletePeriod } from \"../../utils/periodUtils\";\nimport type { ChartProps } from \"../../types\";\n\ninterface VarianceHistogramProps {\n values: number[];\n lastValue: number;\n positiveColor: string;\n negativeColor: string;\n formatValue: (value: number) => string;\n width: number;\n height: number;\n}\n\nfunction VarianceHistogram({\n values,\n lastValue,\n positiveColor,\n negativeColor,\n formatValue,\n width,\n height,\n}: VarianceHistogramProps) {\n // Limit to most recent N values to fit in the histogram\n // Calculate max bars based on width (minimum 8px per bar including gap)\n const maxBars = Math.max(10, Math.floor(width / 10));\n const limitedValues =\n values.length > maxBars\n ? values.slice(-maxBars) // Take the most recent values\n : values;\n\n // Calculate variance (difference) from current/last value for each point\n const variances = limitedValues.map((value) => value - lastValue);\n\n // Find min/max variance for scaling (include 0 as baseline)\n const minVariance = Math.min(...variances, 0);\n const maxVariance = Math.max(...variances, 0);\n const range = Math.max(Math.abs(minVariance), Math.abs(maxVariance));\n\n if (range === 0 || variances.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center bg-dc-bg-secondary dc:rounded-sm dc:border border-dc-border\"\n style={{ width: `${width}px`, height: `${height}px` }}\n >\n <span className=\"dc:text-xs text-dc-text-muted\">No variance data</span>\n </div>\n );\n }\n\n // Calculate bar dimensions\n const barGap = 2;\n const availableWidth = width - (limitedValues.length - 1) * barGap;\n const barWidth = Math.max(4, availableWidth / limitedValues.length);\n\n // Calculate where zero line should be positioned (as percentage from top)\n // If maxVariance = 67 and minVariance = -24, total range = 91\n // Zero should be at 67/91 = 73.6% from top\n const totalRange = maxVariance - minVariance;\n const zeroLinePercent =\n totalRange > 0 ? (maxVariance / totalRange) * 100 : 50;\n\n return (\n <div className=\"dc:flex dc:items-center dc:space-x-2\">\n {/* Histogram bars */}\n <div\n className=\"dc:relative\"\n style={{\n width: `${width}px`,\n height: `${height}px`,\n }}\n >\n {/* Zero line (represents current value) */}\n <div\n className=\"dc:absolute dc:left-0 dc:right-0\"\n style={{\n height: \"1px\",\n top: `${zeroLinePercent}%`,\n backgroundColor: \"var(--dc-border)\",\n zIndex: 1,\n }}\n />\n\n {/* Variance bars - oldest to newest (left to right) */}\n {variances.map((variance, index) => {\n // Calculate bar height as proportion of total range\n const normalizedHeight = Math.abs(variance) / totalRange;\n const barHeight = Math.max(2, normalizedHeight * (height - 4));\n const isPositive = variance >= 0;\n const isLastValue = index === limitedValues.length - 1;\n const color = isPositive ? positiveColor : negativeColor;\n const xPosition = index * (barWidth + barGap);\n\n return (\n <div\n key={index}\n className=\"dc:absolute rounded-xs\"\n style={{\n left: `${xPosition}px`,\n width: `${barWidth}px`,\n height: `${barHeight}px`,\n backgroundColor: color,\n opacity: isLastValue ? 1 : 0.6,\n // Position bar relative to zero line\n ...(isPositive\n ? { bottom: `${100 - zeroLinePercent}%` }\n : { top: `${zeroLinePercent}%` }),\n zIndex: 2,\n }}\n title={`${formatValue(limitedValues[index])}: ${variance >= 0 ? \"+\" : \"\"}${formatValue(variance)} vs current`}\n />\n );\n })}\n </div>\n\n {/* Variance labels on the right - show actual value difference */}\n <div\n className=\"dc:flex dc:flex-col dc:justify-between dc:text-xs text-dc-text-muted\"\n style={{ height: `${height}px` }}\n >\n <span>+{formatValue(maxVariance)}</span>\n <span>\n {minVariance < 0 ? \"\" : \"\"}\n {formatValue(minVariance)}\n </span>\n </div>\n </div>\n );\n}\n\nconst KpiDelta = React.memo(function KpiDelta({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n}: ChartProps) {\n const [fontSize, setFontSize] = useState(32);\n const [textWidth, setTextWidth] = useState(250);\n const containerRef = useRef<HTMLDivElement>(null);\n const valueRef = useRef<HTMLDivElement>(null);\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel();\n\n // Calculate font size and text width based on container dimensions\n useEffect(() => {\n const updateDimensions = () => {\n if (containerRef.current) {\n const container = containerRef.current;\n const rect = container.getBoundingClientRect();\n const containerWidth = rect.width;\n const containerHeight = rect.height;\n\n if (containerWidth > 0 && containerHeight > 0) {\n const widthBasedSize = containerWidth / 4;\n const heightBasedSize = containerHeight / 4;\n const baseFontSize = Math.min(widthBasedSize, heightBasedSize);\n const clampedFontSize = Math.max(28, Math.min(baseFontSize, 140));\n setFontSize(clampedFontSize);\n\n setTimeout(() => {\n if (valueRef.current) {\n const textRect = valueRef.current.getBoundingClientRect();\n const measuredWidth = textRect.width;\n // Scale histogram width with container, accounting for labels on the right (~60px)\n const maxHistogramWidth = containerWidth - 100; // Leave room for padding and labels\n const effectiveWidth = Math.max(\n measuredWidth,\n Math.min(maxHistogramWidth, containerWidth * 0.7),\n );\n setTextWidth(Math.max(100, effectiveWidth)); // Minimum 100px\n }\n }, 10);\n }\n }\n };\n\n const timer = setTimeout(updateDimensions, 50);\n\n const resizeObserver = new ResizeObserver(() => {\n setTimeout(updateDimensions, 10);\n });\n\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current);\n }\n\n return () => {\n clearTimeout(timer);\n resizeObserver.disconnect();\n };\n }, [data, chartConfig]);\n\n if (!data || data.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n }}\n >\n <div className=\"dc:text-center text-dc-text-muted\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">No data available</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n No data points to display\n </div>\n </div>\n </div>\n );\n }\n\n // Extract value and dimension fields from chart config\n let valueFields: string[] = [];\n let dimensionFields: string[] = [];\n\n if (chartConfig?.yAxis) {\n valueFields = Array.isArray(chartConfig.yAxis)\n ? chartConfig.yAxis\n : [chartConfig.yAxis];\n }\n\n if (chartConfig?.xAxis) {\n dimensionFields = Array.isArray(chartConfig.xAxis)\n ? chartConfig.xAxis\n : [chartConfig.xAxis];\n }\n\n if (valueFields.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n backgroundColor: \"var(--dc-danger-bg)\",\n color: \"var(--dc-danger)\",\n borderColor: \"var(--dc-danger-border)\",\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Configuration Error</div>\n <div className=\"dc:text-xs\">No measure field configured</div>\n </div>\n </div>\n );\n }\n\n const valueField = valueFields[0];\n const dimensionField = dimensionFields[0]; // Optional\n\n // Sort data by dimension if available (for time series)\n let sortedData = [...data];\n if (dimensionField) {\n sortedData = sortedData.sort((a, b) => {\n const aVal = a[dimensionField];\n const bVal = b[dimensionField];\n if (aVal < bVal) return -1;\n if (aVal > bVal) return 1;\n return 0;\n });\n }\n\n // Filter out incomplete or last period if enabled\n const { useLastCompletePeriod = true, skipLastPeriod = false } =\n displayConfig;\n const {\n filteredData,\n excludedIncompletePeriod,\n skippedLastPeriod,\n granularity,\n } = filterIncompletePeriod(\n sortedData,\n dimensionField,\n queryObject,\n useLastCompletePeriod,\n skipLastPeriod,\n );\n\n // Use filtered data for calculations\n const dataToUse = filteredData;\n\n // Extract values from filtered data\n const values = dataToUse\n .map((row) => row[valueField])\n .filter((val) => val !== null && val !== undefined && !isNaN(Number(val)))\n .map((val) => Number(val));\n\n if (values.length < 2) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full dc:h-full\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n backgroundColor: \"var(--dc-warning-bg)\",\n color: \"var(--dc-warning)\",\n borderColor: \"var(--dc-warning-border)\",\n }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Insufficient Data</div>\n <div className=\"dc:text-xs\">\n Delta calculation requires at least 2 data points\n </div>\n <div className=\"dc:text-xs\">Current data points: {values.length}</div>\n </div>\n </div>\n );\n }\n\n // Calculate delta between last and second-last values\n const lastValue = values[values.length - 1];\n const secondLastValue = values[values.length - 2];\n const absoluteChange = lastValue - secondLastValue;\n const percentageChange =\n secondLastValue !== 0\n ? (absoluteChange / Math.abs(secondLastValue)) * 100\n : 0;\n\n const isPositiveChange = absoluteChange >= 0;\n\n // Format number with appropriate units and decimals\n const formatNumber = (value: number | null | undefined): string => {\n // If custom formatValue is provided, use it exclusively\n if (displayConfig.formatValue) {\n return displayConfig.formatValue(value);\n }\n\n // Null handling: Show placeholder for missing data\n if (value === null || value === undefined) {\n return \"—\";\n }\n\n const decimals = displayConfig.decimals ?? 0;\n const prefix = displayConfig.prefix ?? \"\";\n\n let formattedValue: string;\n\n if (Math.abs(value) >= 1e9) {\n formattedValue = (value / 1e9).toFixed(decimals) + \"B\";\n } else if (Math.abs(value) >= 1e6) {\n formattedValue = (value / 1e6).toFixed(decimals) + \"M\";\n } else if (Math.abs(value) >= 1e3) {\n formattedValue = (value / 1e3).toFixed(decimals) + \"K\";\n } else {\n formattedValue = value.toFixed(decimals);\n }\n\n return prefix + formattedValue;\n };\n\n // Get colors from palette\n const getPositiveColor = (): string => {\n if (\n displayConfig.positiveColorIndex !== undefined &&\n colorPalette?.colors\n ) {\n const colorIndex = displayConfig.positiveColorIndex;\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex];\n }\n }\n return \"#10b981\"; // Default green\n };\n\n const getNegativeColor = (): string => {\n if (\n displayConfig.negativeColorIndex !== undefined &&\n colorPalette?.colors\n ) {\n const colorIndex = displayConfig.negativeColorIndex;\n if (colorIndex >= 0 && colorIndex < colorPalette.colors.length) {\n return colorPalette.colors[colorIndex];\n }\n }\n return \"#ef4444\"; // Default red\n };\n\n const positiveColor = getPositiveColor();\n const negativeColor = getNegativeColor();\n const currentColor = isPositiveChange ? positiveColor : negativeColor;\n\n return (\n <div\n ref={containerRef}\n className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full dc:h-full dc:p-4\"\n style={{\n height: height === \"100%\" ? \"100%\" : height,\n minHeight: height === \"100%\" ? \"200px\" : undefined,\n }}\n >\n {/* Field Label */}\n <div\n className=\"text-dc-text-secondary dc:font-bold dc:text-center dc:mb-2 dc:flex dc:items-center dc:justify-center dc:gap-1\"\n style={{\n fontSize: \"14px\",\n lineHeight: \"1.2\",\n }}\n >\n <span>\n {(() => {\n const label = getFieldLabel(valueField);\n return label && label.length > 1 ? label : valueField;\n })()}\n </span>\n {(excludedIncompletePeriod || skippedLastPeriod) && (\n <span\n title={\n skippedLastPeriod\n ? `Excludes last ${granularity || \"period\"}`\n : `Excludes current incomplete ${granularity}`\n }\n className=\"dc:cursor-help\"\n >\n <Icon\n icon={infoCircleIcon}\n className=\"dc:w-4 dc:h-4 text-dc-text-muted dc:opacity-70\"\n />\n </span>\n )}\n </div>\n\n {/* Main KPI Value and Delta */}\n <div className=\"dc:flex dc:items-center dc:justify-center dc:space-x-4 dc:mb-2\">\n {/* Main KPI Value */}\n <div\n ref={valueRef}\n className=\"dc:font-bold dc:leading-none\"\n style={{\n fontSize: `${fontSize}px`,\n color: \"var(--dc-text)\", // Keep main value neutral\n }}\n >\n {formatNumber(lastValue)}\n </div>\n\n {/* Delta Information */}\n <div className=\"dc:flex dc:items-center dc:space-x-1\">\n {/* Arrow */}\n <div\n className=\"dc:font-bold\"\n style={{\n color: currentColor,\n fontSize: `${fontSize * 0.35}px`,\n }}\n >\n {isPositiveChange ? \"▲\" : \"▼\"}\n </div>\n\n {/* Delta Values */}\n <div className=\"dc:text-left\">\n <div\n className=\"dc:font-bold dc:leading-tight\"\n style={{\n fontSize: `${fontSize * 0.35}px`,\n color: currentColor,\n }}\n >\n {isPositiveChange ? \"+\" : \"\"}\n {formatNumber(absoluteChange)}\n </div>\n <div\n className=\"dc:font-semibold dc:leading-tight\"\n style={{\n fontSize: `${fontSize * 0.28}px`,\n color: currentColor,\n opacity: 0.8,\n }}\n >\n {isPositiveChange ? \"+\" : \"\"}\n {percentageChange.toFixed(1)}%\n </div>\n </div>\n </div>\n </div>\n\n {/* Unit/Suffix (hidden when formatValue is provided) */}\n {displayConfig.suffix && !displayConfig.formatValue && (\n <div\n className=\"text-dc-text-muted dc:text-center dc:mb-3\"\n style={{\n fontSize: \"14px\",\n lineHeight: \"1.2\",\n opacity: 0.8,\n }}\n >\n {displayConfig.suffix}\n </div>\n )}\n\n {/* Variance Histogram */}\n {displayConfig.showHistogram !== false && values.length > 2 && (\n <div className=\"dc:mt-2 dc:w-full dc:flex dc:justify-center dc:overflow-hidden\">\n <VarianceHistogram\n values={values}\n lastValue={lastValue}\n positiveColor={positiveColor}\n negativeColor={negativeColor}\n formatValue={formatNumber}\n width={textWidth}\n height={64}\n />\n </div>\n )}\n </div>\n );\n})\n\nexport default KpiDelta\n"],"names":["VarianceHistogram","values","lastValue","positiveColor","negativeColor","formatValue","width","height","maxBars","limitedValues","variances","value","minVariance","maxVariance","jsx","barGap","availableWidth","barWidth","totalRange","zeroLinePercent","jsxs","variance","index","normalizedHeight","barHeight","isPositive","isLastValue","color","xPosition","KpiDelta","React","data","chartConfig","displayConfig","queryObject","colorPalette","fontSize","setFontSize","useState","textWidth","setTextWidth","containerRef","useRef","valueRef","getFieldLabel","useCubeFieldLabel","useEffect","updateDimensions","rect","containerWidth","containerHeight","widthBasedSize","heightBasedSize","baseFontSize","clampedFontSize","measuredWidth","maxHistogramWidth","effectiveWidth","timer","resizeObserver","valueFields","dimensionFields","valueField","dimensionField","sortedData","a","b","aVal","bVal","useLastCompletePeriod","skipLastPeriod","filteredData","excludedIncompletePeriod","skippedLastPeriod","granularity","filterIncompletePeriod","row","val","secondLastValue","absoluteChange","percentageChange","isPositiveChange","formatNumber","decimals","prefix","formattedValue","getPositiveColor","colorIndex","getNegativeColor","currentColor","label","Icon","infoCircleIcon"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { jsxs as x, jsx as c } from "react/jsx-runtime";
2
2
  import te, { useState as j, useRef as _, useMemo as N, useCallback as ne, useEffect as re } from "react";
3
- import { I as se, d as ce } from "./icons-DRreo6m8.js";
3
+ import { I as se, d as ce } from "./icons-DAeqv1iX.js";
4
4
  import { u as ie, p as de, j as oe, k as ae } from "./charts-core-DmGfleFz.js";
5
5
  function le(o, r) {
6
6
  const e = new Date(o);
@@ -473,4 +473,4 @@ export {
473
473
  le as g,
474
474
  ue as i
475
475
  };
476
- //# sourceMappingURL=chart-kpi-number-C-5m3qt5.js.map
476
+ //# sourceMappingURL=chart-kpi-number-C29Vj2g8.js.map