drizzle-cube 0.4.42 → 0.4.43

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 (183) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/express/index.cjs +1 -1
  3. package/dist/adapters/express/index.js +2 -2
  4. package/dist/adapters/fastify/index.cjs +1 -1
  5. package/dist/adapters/fastify/index.js +2 -2
  6. package/dist/adapters/{handler-dHHEEbG9.cjs → handler-BneUGY0k.cjs} +1 -1
  7. package/dist/adapters/{handler-fto6TSVn.js → handler-CiQoQsnP.js} +1 -1
  8. package/dist/adapters/hono/index.cjs +1 -1
  9. package/dist/adapters/hono/index.js +5 -5
  10. package/dist/adapters/{mcp-transport-tB5a7Het.js → mcp-transport-CC3hQOnb.js} +1099 -1338
  11. package/dist/adapters/mcp-transport-mmuPvjfR.cjs +255 -0
  12. package/dist/adapters/nextjs/index.cjs +1 -1
  13. package/dist/adapters/nextjs/index.js +2 -2
  14. package/dist/adapters/{openai-Ckpe7iU7.js → openai-CQfaz257.js} +1 -1
  15. package/dist/{server/openai-DKpZPCay.cjs → adapters/openai-CZ74gWd4.cjs} +1 -1
  16. package/dist/adapters/{openai-Bc8qwEKW.cjs → openai-DLfardui.cjs} +1 -1
  17. package/dist/adapters/{openai-DxeVtl8X.js → openai-DaxuhJLS.js} +1 -1
  18. package/dist/client/charts.js +12 -12
  19. package/dist/client/chunks/{DashboardEditModal-4zzjtZRR.js → DashboardEditModal-BTdV528l.js} +1421 -1396
  20. package/dist/client/chunks/DashboardEditModal-BTdV528l.js.map +1 -0
  21. package/dist/client/chunks/{FieldSearchModal-trURu9Sa.js → FieldSearchModal-D75vy4Wb.js} +4 -4
  22. package/dist/client/chunks/{FieldSearchModal-trURu9Sa.js.map → FieldSearchModal-D75vy4Wb.js.map} +1 -1
  23. package/dist/client/chunks/KpiDelta-Bk8bzKYM.js +2 -0
  24. package/dist/client/chunks/KpiNumber-CKF-8e_T.js +2 -0
  25. package/dist/client/chunks/KpiText-Iz1vIvu_.js +2 -0
  26. package/dist/client/chunks/{RetentionCombinedChart-B1hUYaXt.js → RetentionCombinedChart-DIhK5pD8.js} +3 -3
  27. package/dist/client/chunks/{RetentionCombinedChart-B1hUYaXt.js.map → RetentionCombinedChart-DIhK5pD8.js.map} +1 -1
  28. package/dist/client/chunks/{RetentionHeatmap-Dn2ocjVf.js → RetentionHeatmap-CyREolyP.js} +1 -1
  29. package/dist/client/chunks/{RetentionHeatmap-Dn2ocjVf.js.map → RetentionHeatmap-CyREolyP.js.map} +1 -1
  30. package/dist/client/chunks/SchemaVisualization-B1GUT-FM.js +2 -0
  31. package/dist/client/chunks/SchemaVisualizationLazy-DymwT34e.js +2 -0
  32. package/dist/client/chunks/{analysis-builder-B7XSIMkr.js → analysis-builder-C1CJ0c7L.js} +52 -52
  33. package/dist/client/chunks/{analysis-builder-B7XSIMkr.js.map → analysis-builder-C1CJ0c7L.js.map} +1 -1
  34. package/dist/client/chunks/{analysis-builder-shared-DaqtrLxd.js → analysis-builder-shared-rkjJfWLT.js} +9 -9
  35. package/dist/client/chunks/{analysis-builder-shared-DaqtrLxd.js.map → analysis-builder-shared-rkjJfWLT.js.map} +1 -1
  36. package/dist/client/chunks/{chart-activity-grid-wR2Twpo7.js → chart-activity-grid-DLktOINm.js} +2 -2
  37. package/dist/client/chunks/{chart-activity-grid-wR2Twpo7.js.map → chart-activity-grid-DLktOINm.js.map} +1 -1
  38. package/dist/client/chunks/{chart-area-e9ysnatQ.js → chart-area-BwYaflNk.js} +3 -3
  39. package/dist/client/chunks/{chart-area-e9ysnatQ.js.map → chart-area-BwYaflNk.js.map} +1 -1
  40. package/dist/client/chunks/{chart-bar-CPt67rLR.js → chart-bar-BiENfFgE.js} +4 -4
  41. package/dist/client/chunks/{chart-bar-CPt67rLR.js.map → chart-bar-BiENfFgE.js.map} +1 -1
  42. package/dist/client/chunks/{chart-box-plot-Dp_nqQen.js → chart-box-plot-BJF1tBXC.js} +3 -3
  43. package/dist/client/chunks/{chart-box-plot-Dp_nqQen.js.map → chart-box-plot-BJF1tBXC.js.map} +1 -1
  44. package/dist/client/chunks/{chart-bubble-CYQ8loeS.js → chart-bubble-DQQhGVDJ.js} +3 -3
  45. package/dist/client/chunks/{chart-bubble-CYQ8loeS.js.map → chart-bubble-DQQhGVDJ.js.map} +1 -1
  46. package/dist/client/chunks/{chart-candlestick-DTeSf7C5.js → chart-candlestick-C2UuXbLe.js} +3 -3
  47. package/dist/client/chunks/{chart-candlestick-DTeSf7C5.js.map → chart-candlestick-C2UuXbLe.js.map} +1 -1
  48. package/dist/client/chunks/{chart-config-activity-grid-BSWS08cI.js → chart-config-activity-grid-DJOU3TEz.js} +2 -2
  49. package/dist/client/chunks/{chart-config-activity-grid-BSWS08cI.js.map → chart-config-activity-grid-DJOU3TEz.js.map} +1 -1
  50. package/dist/client/chunks/{chart-config-area-DKwgcHp4.js → chart-config-area-CWnWVT6a.js} +2 -2
  51. package/dist/client/chunks/{chart-config-area-DKwgcHp4.js.map → chart-config-area-CWnWVT6a.js.map} +1 -1
  52. package/dist/client/chunks/{chart-config-bar-deTjEhap.js → chart-config-bar-C-7Dr1Ho.js} +2 -2
  53. package/dist/client/chunks/{chart-config-bar-deTjEhap.js.map → chart-config-bar-C-7Dr1Ho.js.map} +1 -1
  54. package/dist/client/chunks/{chart-config-box-plot-DU4iWk3V.js → chart-config-box-plot-mVOwmLdu.js} +2 -2
  55. package/dist/client/chunks/{chart-config-box-plot-DU4iWk3V.js.map → chart-config-box-plot-mVOwmLdu.js.map} +1 -1
  56. package/dist/client/chunks/{chart-config-bubble-B8FSHSW-.js → chart-config-bubble-BPE2CeiD.js} +2 -2
  57. package/dist/client/chunks/{chart-config-bubble-B8FSHSW-.js.map → chart-config-bubble-BPE2CeiD.js.map} +1 -1
  58. package/dist/client/chunks/{chart-config-candlestick-BGfyWFft.js → chart-config-candlestick-BSB9DRy2.js} +2 -2
  59. package/dist/client/chunks/{chart-config-candlestick-BGfyWFft.js.map → chart-config-candlestick-BSB9DRy2.js.map} +1 -1
  60. package/dist/client/chunks/{chart-config-data-table-DKRcGa8t.js → chart-config-data-table-Bhdx5Hem.js} +2 -2
  61. package/dist/client/chunks/{chart-config-data-table-DKRcGa8t.js.map → chart-config-data-table-Bhdx5Hem.js.map} +1 -1
  62. package/dist/client/chunks/{chart-config-funnel-Bt4iGFo_.js → chart-config-funnel-Cl-v-bm1.js} +2 -2
  63. package/dist/client/chunks/{chart-config-funnel-Bt4iGFo_.js.map → chart-config-funnel-Cl-v-bm1.js.map} +1 -1
  64. package/dist/client/chunks/{chart-config-gauge-Bk4Jjp3W.js → chart-config-gauge-CdrUTJMJ.js} +2 -2
  65. package/dist/client/chunks/{chart-config-gauge-Bk4Jjp3W.js.map → chart-config-gauge-CdrUTJMJ.js.map} +1 -1
  66. package/dist/client/chunks/{chart-config-heat-map-CkHsqkrY.js → chart-config-heat-map-DGE3NzoF.js} +2 -2
  67. package/dist/client/chunks/{chart-config-heat-map-CkHsqkrY.js.map → chart-config-heat-map-DGE3NzoF.js.map} +1 -1
  68. package/dist/client/chunks/{chart-config-kpi-delta-CkUX98JV.js → chart-config-kpi-delta-DMrQerUW.js} +2 -2
  69. package/dist/client/chunks/{chart-config-kpi-delta-CkUX98JV.js.map → chart-config-kpi-delta-DMrQerUW.js.map} +1 -1
  70. package/dist/client/chunks/{chart-config-kpi-number-DcxyiUgs.js → chart-config-kpi-number-DCytCytn.js} +2 -2
  71. package/dist/client/chunks/{chart-config-kpi-number-DcxyiUgs.js.map → chart-config-kpi-number-DCytCytn.js.map} +1 -1
  72. package/dist/client/chunks/{chart-config-kpi-text-DI4mj8CN.js → chart-config-kpi-text-KdKQUvHo.js} +2 -2
  73. package/dist/client/chunks/{chart-config-kpi-text-DI4mj8CN.js.map → chart-config-kpi-text-KdKQUvHo.js.map} +1 -1
  74. package/dist/client/chunks/{chart-config-line--j7-dLue.js → chart-config-line-Bl9VDAdz.js} +2 -2
  75. package/dist/client/chunks/{chart-config-line--j7-dLue.js.map → chart-config-line-Bl9VDAdz.js.map} +1 -1
  76. package/dist/client/chunks/{chart-config-markdown-DUjvVjV4.js → chart-config-markdown-BX26b94i.js} +2 -2
  77. package/dist/client/chunks/{chart-config-markdown-DUjvVjV4.js.map → chart-config-markdown-BX26b94i.js.map} +1 -1
  78. package/dist/client/chunks/{chart-config-measure-profile-B9FKBNGc.js → chart-config-measure-profile-DwtRhEFh.js} +2 -2
  79. package/dist/client/chunks/{chart-config-measure-profile-B9FKBNGc.js.map → chart-config-measure-profile-DwtRhEFh.js.map} +1 -1
  80. package/dist/client/chunks/{chart-config-pie-yU4jipl9.js → chart-config-pie-BzBcqPMJ.js} +2 -2
  81. package/dist/client/chunks/{chart-config-pie-yU4jipl9.js.map → chart-config-pie-BzBcqPMJ.js.map} +1 -1
  82. package/dist/client/chunks/{chart-config-radar-R9Fkc8wL.js → chart-config-radar-6ZOgt__z.js} +2 -2
  83. package/dist/client/chunks/{chart-config-radar-R9Fkc8wL.js.map → chart-config-radar-6ZOgt__z.js.map} +1 -1
  84. package/dist/client/chunks/{chart-config-radial-bar-DeoXfpIp.js → chart-config-radial-bar-Df6Eta7N.js} +2 -2
  85. package/dist/client/chunks/{chart-config-radial-bar-DeoXfpIp.js.map → chart-config-radial-bar-Df6Eta7N.js.map} +1 -1
  86. package/dist/client/chunks/{chart-config-sankey-CXEsxo6s.js → chart-config-sankey-DgqKBFvN.js} +2 -2
  87. package/dist/client/chunks/{chart-config-sankey-CXEsxo6s.js.map → chart-config-sankey-DgqKBFvN.js.map} +1 -1
  88. package/dist/client/chunks/{chart-config-scatter-MVUFupub.js → chart-config-scatter-D5nVLDvi.js} +2 -2
  89. package/dist/client/chunks/{chart-config-scatter-MVUFupub.js.map → chart-config-scatter-D5nVLDvi.js.map} +1 -1
  90. package/dist/client/chunks/{chart-config-sunburst-Z_gqIY5u.js → chart-config-sunburst-Ca3FX9nW.js} +2 -2
  91. package/dist/client/chunks/{chart-config-sunburst-Z_gqIY5u.js.map → chart-config-sunburst-Ca3FX9nW.js.map} +1 -1
  92. package/dist/client/chunks/{chart-config-tree-map-BD-xAeIy.js → chart-config-tree-map-Bjy4QNa3.js} +2 -2
  93. package/dist/client/chunks/{chart-config-tree-map-BD-xAeIy.js.map → chart-config-tree-map-Bjy4QNa3.js.map} +1 -1
  94. package/dist/client/chunks/{chart-config-waterfall-CHwVkXZc.js → chart-config-waterfall-C5K2eqR7.js} +2 -2
  95. package/dist/client/chunks/{chart-config-waterfall-CHwVkXZc.js.map → chart-config-waterfall-C5K2eqR7.js.map} +1 -1
  96. package/dist/client/chunks/{chart-data-table-BZ7StNWv.js → chart-data-table-2iCsn0CF.js} +1099 -933
  97. package/dist/client/chunks/chart-data-table-2iCsn0CF.js.map +1 -0
  98. package/dist/client/chunks/{chart-funnel-C9JRW79j.js → chart-funnel-poyOf7-e.js} +3 -3
  99. package/dist/client/chunks/{chart-funnel-C9JRW79j.js.map → chart-funnel-poyOf7-e.js.map} +1 -1
  100. package/dist/client/chunks/{chart-gauge-_Xdgk_qI.js → chart-gauge-D5J4gRky.js} +3 -3
  101. package/dist/client/chunks/{chart-gauge-_Xdgk_qI.js.map → chart-gauge-D5J4gRky.js.map} +1 -1
  102. package/dist/client/chunks/{chart-heat-map-BOMQeUDL.js → chart-heat-map-BAMVhLGG.js} +3 -3
  103. package/dist/client/chunks/{chart-heat-map-BOMQeUDL.js.map → chart-heat-map-BAMVhLGG.js.map} +1 -1
  104. package/dist/client/chunks/{chart-kpi-delta-C2tdpWki.js → chart-kpi-delta-KQjUIeal.js} +71 -73
  105. package/dist/client/chunks/{chart-kpi-delta-C2tdpWki.js.map → chart-kpi-delta-KQjUIeal.js.map} +1 -1
  106. package/dist/client/chunks/{chart-kpi-number-BUNKM7yg.js → chart-kpi-number-CsQgV_x3.js} +62 -63
  107. package/dist/client/chunks/{chart-kpi-number-BUNKM7yg.js.map → chart-kpi-number-CsQgV_x3.js.map} +1 -1
  108. package/dist/client/chunks/{chart-kpi-text-COF8iN0K.js → chart-kpi-text-BR0IyeUU.js} +26 -27
  109. package/dist/client/chunks/{chart-kpi-text-COF8iN0K.js.map → chart-kpi-text-BR0IyeUU.js.map} +1 -1
  110. package/dist/client/chunks/{chart-line-D3SEwXDS.js → chart-line-B5_WntY5.js} +4 -4
  111. package/dist/client/chunks/{chart-line-D3SEwXDS.js.map → chart-line-B5_WntY5.js.map} +1 -1
  112. package/dist/client/chunks/{chart-markdown-DMekYkKz.js → chart-markdown-B6bENbel.js} +2 -2
  113. package/dist/client/chunks/{chart-markdown-DMekYkKz.js.map → chart-markdown-B6bENbel.js.map} +1 -1
  114. package/dist/client/chunks/{chart-measure-profile-BPhI1Z9s.js → chart-measure-profile-yWk-obNb.js} +4 -4
  115. package/dist/client/chunks/{chart-measure-profile-BPhI1Z9s.js.map → chart-measure-profile-yWk-obNb.js.map} +1 -1
  116. package/dist/client/chunks/{chart-pie-COl3Rmdk.js → chart-pie-BodrUoHv.js} +4 -4
  117. package/dist/client/chunks/{chart-pie-COl3Rmdk.js.map → chart-pie-BodrUoHv.js.map} +1 -1
  118. package/dist/client/chunks/{chart-radar-BKZXylBB.js → chart-radar-gG3zfLud.js} +4 -4
  119. package/dist/client/chunks/{chart-radar-BKZXylBB.js.map → chart-radar-gG3zfLud.js.map} +1 -1
  120. package/dist/client/chunks/{chart-radial-bar-CMfC7SPd.js → chart-radial-bar-C2IPCV8c.js} +4 -4
  121. package/dist/client/chunks/{chart-radial-bar-CMfC7SPd.js.map → chart-radial-bar-C2IPCV8c.js.map} +1 -1
  122. package/dist/client/chunks/{chart-sankey-8nRYnupt.js → chart-sankey-BOyxfG1Q.js} +3 -3
  123. package/dist/client/chunks/{chart-sankey-8nRYnupt.js.map → chart-sankey-BOyxfG1Q.js.map} +1 -1
  124. package/dist/client/chunks/{chart-scatter-xQMa3dUt.js → chart-scatter-B8OwlsAX.js} +4 -4
  125. package/dist/client/chunks/{chart-scatter-xQMa3dUt.js.map → chart-scatter-B8OwlsAX.js.map} +1 -1
  126. package/dist/client/chunks/{chart-sunburst-BGhJ4fui.js → chart-sunburst-D9lGEOCc.js} +4 -4
  127. package/dist/client/chunks/{chart-sunburst-BGhJ4fui.js.map → chart-sunburst-D9lGEOCc.js.map} +1 -1
  128. package/dist/client/chunks/{chart-tree-map-Cn1pmrAw.js → chart-tree-map-DZaKy9he.js} +4 -4
  129. package/dist/client/chunks/{chart-tree-map-Cn1pmrAw.js.map → chart-tree-map-DZaKy9he.js.map} +1 -1
  130. package/dist/client/chunks/{chart-waterfall-C2nVN4pn.js → chart-waterfall-BCdUx4DC.js} +4 -4
  131. package/dist/client/chunks/{chart-waterfall-C2nVN4pn.js.map → chart-waterfall-BCdUx4DC.js.map} +1 -1
  132. package/dist/client/chunks/{charts-core-Cy3rHADX.js → charts-core-C5Yokk-x.js} +2 -2
  133. package/dist/client/chunks/{charts-core-Cy3rHADX.js.map → charts-core-C5Yokk-x.js.map} +1 -1
  134. package/dist/client/chunks/{core-BdWfCZ3y.js → core-DcfMGTVa.js} +2 -2
  135. package/dist/client/chunks/{core-BdWfCZ3y.js.map → core-DcfMGTVa.js.map} +1 -1
  136. package/dist/client/chunks/{dist-BWPE2m_X.js → dist-eZurnOde.js} +1 -1
  137. package/dist/client/chunks/{dist-BWPE2m_X.js.map → dist-eZurnOde.js.map} +1 -1
  138. package/dist/client/chunks/exceljs.min-CcjgM-qg.js +31986 -0
  139. package/dist/client/chunks/exceljs.min-CcjgM-qg.js.map +1 -0
  140. package/dist/client/chunks/{javascript-O1RIRkZr.js → javascript-DFvvCuoP.js} +1 -1
  141. package/dist/client/chunks/{javascript-O1RIRkZr.js.map → javascript-DFvvCuoP.js.map} +1 -1
  142. package/dist/client/chunks/{json-C5bX2tt1.js → json-BBm9TlrA.js} +1 -1
  143. package/dist/client/chunks/{json-C5bX2tt1.js.map → json-BBm9TlrA.js.map} +1 -1
  144. package/dist/client/chunks/{rolldown-runtime-lc2dmIiU.js → rolldown-runtime-CCl2IeXn.js} +5 -2
  145. package/dist/client/chunks/{schema-visualization-DVdfx6N8.js → schema-visualization-t1KiOORo.js} +261 -265
  146. package/dist/client/chunks/{schema-visualization-DVdfx6N8.js.map → schema-visualization-t1KiOORo.js.map} +1 -1
  147. package/dist/client/chunks/{sql-D2qikO5q.js → sql-k0GA6oZ_.js} +1 -1
  148. package/dist/client/chunks/{sql-D2qikO5q.js.map → sql-k0GA6oZ_.js.map} +1 -1
  149. package/dist/client/chunks/{syntaxHighlighting-BYYWYmjr.js → syntaxHighlighting-CnDujqwg.js} +2 -2
  150. package/dist/client/chunks/{syntaxHighlighting-BYYWYmjr.js.map → syntaxHighlighting-CnDujqwg.js.map} +1 -1
  151. package/dist/client/chunks/{useDebounce-Bel8J05v.js → useDebounce-CKqkM42n.js} +11 -14
  152. package/dist/client/chunks/{useDebounce-Bel8J05v.js.map → useDebounce-CKqkM42n.js.map} +1 -1
  153. package/dist/client/chunks/{useExplainAI-CxdzY2N0.js → useExplainAI-DBIfYwz-.js} +12 -12
  154. package/dist/client/chunks/{useExplainAI-CxdzY2N0.js.map → useExplainAI-DBIfYwz-.js.map} +1 -1
  155. package/dist/client/chunks/{utils-CMkS7h9x.js → utils--qCr8Yn5.js} +2 -2
  156. package/dist/client/chunks/utils--qCr8Yn5.js.map +1 -0
  157. package/dist/client/chunks/{vendor-BoWEubRu.js → vendor-BRlsCGnK.js} +46 -46
  158. package/dist/client/chunks/{vendor-BoWEubRu.js.map → vendor-BRlsCGnK.js.map} +1 -1
  159. package/dist/client/components.js +3 -3
  160. package/dist/client/hooks.js +3 -3
  161. package/dist/client/icons/types.d.ts +1 -0
  162. package/dist/client/icons.js +1 -1
  163. package/dist/client/index.d.ts +2 -1
  164. package/dist/client/index.js +168 -168
  165. package/dist/client/index.js.map +1 -1
  166. package/dist/client/providers.js +1 -1
  167. package/dist/client/schema.js +1 -1
  168. package/dist/client/types.d.ts +6 -0
  169. package/dist/client/utils/exportXlsx.d.ts +20 -0
  170. package/dist/client/utils/index.d.ts +1 -0
  171. package/dist/client/utils.js +7 -7
  172. package/dist/client-bundle-stats.html +1 -1
  173. package/dist/server/index.cjs +1 -1
  174. package/dist/server/index.js +1 -1
  175. package/dist/server/{openai-DqCEogm0.js → openai-CqZg6zYL.js} +1 -1
  176. package/dist/server/{openai-0HbLlZq6.cjs → openai-D9Zjuby1.cjs} +1 -1
  177. package/dist/{adapters/openai-C96O8M75.cjs → server/openai-DmuEbFd6.cjs} +1 -1
  178. package/dist/server/{openai-DnGeU9PT.js → openai-rwauPzCT.js} +1 -1
  179. package/package.json +6 -1
  180. package/dist/adapters/mcp-transport-ro4OL4BW.cjs +0 -255
  181. package/dist/client/chunks/DashboardEditModal-4zzjtZRR.js.map +0 -1
  182. package/dist/client/chunks/chart-data-table-BZ7StNWv.js.map +0 -1
  183. package/dist/client/chunks/utils-CMkS7h9x.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./chart-kpi-delta-KQjUIeal.js";
2
+ export { e as default };
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./chart-kpi-number-CsQgV_x3.js";
2
+ export { e as default };
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./chart-kpi-text-BR0IyeUU.js";
2
+ export { e as default };
@@ -1,5 +1,5 @@
1
- import { i as e, n as t } from "./chart-activity-grid-wR2Twpo7.js";
2
- import { c as n, l as r } from "./chart-area-e9ysnatQ.js";
1
+ import { i as e, n as t } from "./chart-activity-grid-DLktOINm.js";
2
+ import { c as n, l as r } from "./chart-area-BwYaflNk.js";
3
3
  import { c as i } from "./retention-YhT1Oohi.js";
4
4
  import a, { useMemo as o, useState as s } from "react";
5
5
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
@@ -267,4 +267,4 @@ var S = a.memo(function({ data: a, height: b = "100%", displayConfig: S, colorPa
267
267
  //#endregion
268
268
  export { S as default };
269
269
 
270
- //# sourceMappingURL=RetentionCombinedChart-B1hUYaXt.js.map
270
+ //# sourceMappingURL=RetentionCombinedChart-DIhK5pD8.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RetentionCombinedChart-B1hUYaXt.js","names":[],"sources":["../../../src/client/components/charts/RetentionCombinedChart.tsx"],"sourcesContent":["/**\n * RetentionCombinedChart Component\n *\n * Combined visualization for retention analysis data.\n * Supports multiple display modes: heatmap, line chart, or combined view.\n *\n * Features:\n * - X-axis: Period numbers (P0, P1, P2...)\n * - Y-axis: Retention % (0-100%)\n * - Lines: One per breakdown value (or single if no breakdown)\n * - Display modes: 'heatmap' | 'line' | 'combined'\n * - Heatmap shows color-coded retention matrix\n * - Line chart shows retention curves over periods\n */\n\nimport React, { useMemo, useState } from 'react'\nimport {\n ComposedChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Legend,\n} from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS, CHART_MARGINS } from '../../utils/chartConstants'\nimport type { ChartProps } from '../../types'\nimport type { RetentionChartData, RetentionResultRow, RetentionGranularity } from '../../types/retention'\nimport { isRetentionData } from '../../types/retention'\n\n/**\n * Retention display mode\n * - 'heatmap': Show retention as color-coded bars\n * - 'line': Show retention as line curves\n * - 'combined': Show both heatmap background and line overlay\n */\nexport type RetentionDisplayMode = 'heatmap' | 'line' | 'combined'\n\n/**\n * Get color with opacity based on retention rate for heatmap cells\n * Uses a green gradient: higher retention = more saturated green\n */\nfunction getRetentionColor(rate: number): string {\n const clampedRate = Math.max(0, Math.min(1, rate))\n const alpha = 0.1 + clampedRate * 0.7\n return `rgba(34, 197, 94, ${alpha})`\n}\n\n/**\n * Format percentage for display\n */\nfunction formatPercentage(rate: number): string {\n return `${Math.round(rate * 100)}%`\n}\n\n/**\n * Format period label based on granularity\n * Period 0 shows \"< 1 Day\" / \"< 1 Week\" etc. to indicate the initial cohort\n * e.g., Period 0 with 'week' granularity → \"< 1 Week\", Period 1 → \"Week 1\"\n */\nfunction formatPeriodLabel(period: number, granularity?: RetentionGranularity): string {\n const prefix = granularity === 'day' ? 'Day'\n : granularity === 'week' ? 'Week'\n : granularity === 'month' ? 'Month'\n : 'P' // Fallback to P0, P1, etc.\n\n // Period 0 is special - shows \"< 1 Day\" / \"< 1 Week\" etc.\n if (period === 0) {\n return granularity ? `< 1 ${prefix}` : 'P0'\n }\n\n return granularity ? `${prefix} ${period}` : `P${period}`\n}\n\n/**\n * Get display label for the cohort total column\n * Shows \"Total\" regardless of binding key - it's the cohort size count\n */\nfunction getCohortLabel(_bindingKeyLabel?: string): string {\n return 'Total'\n}\n\n/**\n * Get default series name based on binding key\n * e.g., \"userId\" → \"userId Retention\", null → \"Retention\"\n */\nfunction getDefaultSeriesName(bindingKeyLabel?: string): string {\n if (!bindingKeyLabel) return 'Retention'\n return `${bindingKeyLabel} Retention`\n}\n\n/**\n * Transform retention data for chart display\n * Groups data by period with breakdown values as series\n */\nfunction transformRetentionData(\n rows: RetentionResultRow[],\n periods: number[],\n breakdownValues?: string[],\n granularity?: RetentionGranularity,\n bindingKeyLabel?: string\n): { chartData: any[]; seriesKeys: string[]; defaultSeriesName: string } {\n const defaultSeriesName = getDefaultSeriesName(bindingKeyLabel)\n\n // If no breakdown, single series\n if (!breakdownValues || breakdownValues.length === 0) {\n const chartData = periods.map((period) => {\n const row = rows.find((r) => r.period === period && !r.breakdownValue)\n return {\n period,\n periodLabel: formatPeriodLabel(period, granularity),\n [defaultSeriesName]: row ? row.retentionRate : null,\n cohortSize: row?.cohortSize ?? 0,\n retainedUsers: row?.retainedUsers ?? 0,\n }\n })\n return { chartData, seriesKeys: [defaultSeriesName], defaultSeriesName }\n }\n\n // With breakdown, create series per breakdown value\n const chartData = periods.map((period) => {\n const dataPoint: any = {\n period,\n periodLabel: formatPeriodLabel(period, granularity),\n }\n\n breakdownValues.forEach((bv) => {\n const row = rows.find((r) => r.period === period && r.breakdownValue === bv)\n dataPoint[bv] = row ? row.retentionRate : null\n dataPoint[`${bv}_cohortSize`] = row?.cohortSize ?? 0\n dataPoint[`${bv}_retainedUsers`] = row?.retainedUsers ?? 0\n })\n\n return dataPoint\n })\n\n return { chartData, seriesKeys: breakdownValues, defaultSeriesName }\n}\n\ninterface TooltipData {\n period: number\n breakdownValue?: string | null\n cohortSize: number\n retainedUsers: number\n retentionRate: number\n x: number\n y: number\n}\n\n/**\n * RetentionCombinedChart Component\n */\nconst RetentionCombinedChart = React.memo(function RetentionCombinedChart({\n data,\n height = '100%',\n displayConfig,\n colorPalette,\n}: ChartProps) {\n const [hoveredLegend, setHoveredLegend] = useState<string | null>(null)\n const [heatmapTooltip, setHeatmapTooltip] = useState<TooltipData | null>(null)\n\n // Parse retention data\n const retentionData = useMemo<RetentionChartData | null>(() => {\n if (!data) return null\n\n // Check if data is already in RetentionChartData format\n if (isRetentionData(data)) {\n return data\n }\n\n // If data is an array of RetentionResultRow, convert it\n if (Array.isArray(data) && data.length > 0) {\n const rows = data as RetentionResultRow[]\n const periods = [...new Set(rows.map((r) => r.period))].sort((a, b) => a - b)\n const breakdownValues = [\n ...new Set(rows.filter((r) => r.breakdownValue).map((r) => r.breakdownValue!)),\n ]\n\n return {\n rows,\n periods,\n breakdownValues: breakdownValues.length > 0 ? breakdownValues : undefined,\n }\n }\n\n return null\n }, [data])\n\n // Transform data for chart\n const { chartData, seriesKeys, defaultSeriesName } = useMemo(() => {\n if (!retentionData) {\n return { chartData: [], seriesKeys: [], defaultSeriesName: 'Retention' }\n }\n return transformRetentionData(\n retentionData.rows,\n retentionData.periods,\n retentionData.breakdownValues,\n retentionData.granularity,\n retentionData.bindingKeyLabel\n )\n }, [retentionData])\n\n // Get cohort label for heatmap column header\n const cohortLabel = getCohortLabel(retentionData?.bindingKeyLabel)\n\n // Display mode from config\n const displayMode: RetentionDisplayMode =\n (displayConfig as any)?.retentionDisplayMode || 'line'\n\n const showLegend = displayConfig?.showLegend ?? true\n const showGrid = displayConfig?.showGrid ?? true\n const showTooltip = displayConfig?.showTooltip ?? true\n\n // Handle empty/loading states\n if (!data || (Array.isArray(data) && data.length === 0)) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\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 Configure retention analysis to see results\n </div>\n </div>\n </div>\n )\n }\n\n if (!chartData || chartData.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Unable to render retention data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Data format may be incorrect</div>\n </div>\n </div>\n )\n }\n\n // Render line chart component (reused in line and combined modes)\n const renderLineChart = (chartHeight: string | number) => {\n const chartMargins = {\n ...CHART_MARGINS,\n left: 50,\n right: 20,\n }\n\n return (\n <ChartContainer height={chartHeight}>\n <ComposedChart data={chartData} margin={chartMargins} accessibilityLayer={false}>\n {showGrid && <CartesianGrid strokeDasharray=\"3 3\" />}\n <XAxis\n dataKey=\"periodLabel\"\n tick={{ fontSize: 12 }}\n axisLine={{ stroke: 'var(--dc-border)' }}\n tickLine={{ stroke: 'var(--dc-border)' }}\n />\n <YAxis\n domain={[0, 1]}\n tickFormatter={(value) => formatPercentage(value)}\n tick={{ fontSize: 12 }}\n axisLine={{ stroke: 'var(--dc-border)' }}\n tickLine={{ stroke: 'var(--dc-border)' }}\n label={{\n value: 'Retention %',\n angle: -90,\n position: 'insideLeft',\n style: { textAnchor: 'middle', fontSize: '12px', fill: 'var(--dc-text-secondary)' },\n }}\n />\n {showTooltip && (\n <ChartTooltip\n formatter={(value: any, name: string) => {\n if (value === null || value === undefined) {\n return ['No data', name]\n }\n return [formatPercentage(value), name]\n }}\n labelFormatter={(label: string) => label}\n />\n )}\n {showLegend && (\n <Legend\n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"line\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n\n {/* Render lines */}\n {seriesKeys.map((seriesKey, index) => (\n <Line\n key={seriesKey}\n type=\"monotone\"\n dataKey={seriesKey}\n stroke={\n (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n }\n strokeWidth={2}\n dot={{ r: 4, strokeWidth: 2 }}\n activeDot={{ r: 6 }}\n strokeOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 1 : 0.3) : 1}\n connectNulls={false}\n />\n ))}\n </ComposedChart>\n </ChartContainer>\n )\n }\n\n // Render heatmap table component (reused in heatmap and combined modes)\n const renderHeatmapTable = () => (\n <table className=\"dc:w-full dc:border-collapse dc:text-sm\">\n <thead className=\"dc:sticky dc:top-0 bg-dc-bg dc:z-10\">\n <tr>\n <th className=\"dc:text-left dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[100px] dc:whitespace-nowrap\">\n {retentionData?.breakdownValues?.length ? 'Segment' : 'Cohort'}\n </th>\n <th className=\"dc:text-right dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[60px] dc:whitespace-nowrap\">\n {cohortLabel}\n </th>\n {retentionData?.periods.map((period) => (\n <th\n key={period}\n className=\"dc:text-center dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[70px] dc:whitespace-nowrap\"\n >\n {formatPeriodLabel(period, retentionData?.granularity)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {seriesKeys.map((seriesKey, rowIndex) => {\n const period0Data = chartData.find((d) => d.period === 0)\n const isDefaultSeries = seriesKey === defaultSeriesName\n const cohortSize = isDefaultSeries\n ? period0Data?.cohortSize ?? 0\n : period0Data?.[`${seriesKey}_cohortSize`] ?? 0\n\n return (\n <tr\n key={seriesKey}\n className={rowIndex % 2 === 0 ? 'bg-dc-bg' : 'bg-dc-surface-secondary'}\n >\n <td className=\"dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:whitespace-nowrap\">\n {seriesKey}\n </td>\n <td className=\"dc:p-2 dc:text-right text-dc-text-secondary dc:border-b border-dc-border\">\n {cohortSize.toLocaleString()}\n </td>\n {retentionData?.periods.map((period) => {\n const dataPoint = chartData.find((d) => d.period === period)\n const rate = dataPoint?.[seriesKey] ?? 0\n const bgColor = rate > 0 ? getRetentionColor(rate) : 'transparent'\n const textColor = rate > 0.5 ? '#ffffff' : 'var(--dc-text)'\n\n return (\n <td\n key={period}\n className=\"dc:p-2 dc:text-center dc:border-b border-dc-border dc:cursor-default dc:transition-opacity dc:hover:opacity-80\"\n style={{ backgroundColor: bgColor, color: textColor }}\n onMouseEnter={(e) => {\n const rect = e.currentTarget.getBoundingClientRect()\n const retainedUsers = isDefaultSeries\n ? dataPoint?.retainedUsers ?? 0\n : dataPoint?.[`${seriesKey}_retainedUsers`] ?? 0\n setHeatmapTooltip({\n period,\n breakdownValue: isDefaultSeries ? null : seriesKey,\n cohortSize,\n retainedUsers,\n retentionRate: rate,\n x: rect.left + rect.width / 2,\n y: rect.top,\n })\n }}\n onMouseLeave={() => setHeatmapTooltip(null)}\n >\n {rate > 0 ? formatPercentage(rate) : '-'}\n </td>\n )\n })}\n </tr>\n )\n })}\n </tbody>\n </table>\n )\n\n // Render heatmap tooltip (shared between heatmap and combined modes)\n const renderHeatmapTooltip = () =>\n heatmapTooltip && (\n <div\n className=\"dc:fixed dc:z-50 dc:px-3 dc:py-2 bg-dc-surface dc:border border-dc-border dc:rounded dc:shadow-lg dc:text-sm dc:pointer-events-none\"\n style={{\n left: heatmapTooltip.x,\n top: heatmapTooltip.y - 10,\n transform: 'translate(-50%, -100%)',\n }}\n >\n <div className=\"dc:font-medium text-dc-text dc:mb-1\">\n {heatmapTooltip.breakdownValue\n ? `${heatmapTooltip.breakdownValue} - ${formatPeriodLabel(heatmapTooltip.period, retentionData?.granularity)}`\n : formatPeriodLabel(heatmapTooltip.period, retentionData?.granularity)}\n </div>\n <div className=\"text-dc-text-secondary dc:space-y-0.5\">\n <div>Cohort Size: {heatmapTooltip.cohortSize.toLocaleString()}</div>\n <div>Retained: {heatmapTooltip.retainedUsers.toLocaleString()}</div>\n <div className=\"dc:font-medium text-dc-text\">\n Rate: {formatPercentage(heatmapTooltip.retentionRate)}\n </div>\n </div>\n </div>\n )\n\n // Render heatmap mode (table-based only)\n if (displayMode === 'heatmap') {\n return (\n <div className=\"dc:relative dc:w-full dc:h-full dc:overflow-auto\" style={{ height }}>\n {renderHeatmapTable()}\n {renderHeatmapTooltip()}\n </div>\n )\n }\n\n // Combined mode: line chart on top, heatmap table below\n if (displayMode === 'combined') {\n return (\n <div className=\"dc:flex dc:flex-col dc:w-full dc:h-full\" style={{ height }}>\n {/* Line chart - takes remaining space after heatmap */}\n <div className=\"dc:flex-1 dc:min-h-[200px]\">\n {renderLineChart('100%')}\n </div>\n {/* Heatmap table - auto-height based on content, scrolls if needed */}\n <div className=\"dc:flex-shrink-0 dc:max-h-[40%] dc:overflow-auto dc:border-t border-dc-border\">\n {renderHeatmapTable()}\n </div>\n {/* Shared heatmap tooltip */}\n {renderHeatmapTooltip()}\n </div>\n )\n }\n\n // Line mode: just the line chart\n return renderLineChart(height)\n})\n\nexport default RetentionCombinedChart\n"],"mappings":"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"}
1
+ {"version":3,"file":"RetentionCombinedChart-DIhK5pD8.js","names":[],"sources":["../../../src/client/components/charts/RetentionCombinedChart.tsx"],"sourcesContent":["/**\n * RetentionCombinedChart Component\n *\n * Combined visualization for retention analysis data.\n * Supports multiple display modes: heatmap, line chart, or combined view.\n *\n * Features:\n * - X-axis: Period numbers (P0, P1, P2...)\n * - Y-axis: Retention % (0-100%)\n * - Lines: One per breakdown value (or single if no breakdown)\n * - Display modes: 'heatmap' | 'line' | 'combined'\n * - Heatmap shows color-coded retention matrix\n * - Line chart shows retention curves over periods\n */\n\nimport React, { useMemo, useState } from 'react'\nimport {\n ComposedChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Legend,\n} from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { CHART_COLORS, CHART_MARGINS } from '../../utils/chartConstants'\nimport type { ChartProps } from '../../types'\nimport type { RetentionChartData, RetentionResultRow, RetentionGranularity } from '../../types/retention'\nimport { isRetentionData } from '../../types/retention'\n\n/**\n * Retention display mode\n * - 'heatmap': Show retention as color-coded bars\n * - 'line': Show retention as line curves\n * - 'combined': Show both heatmap background and line overlay\n */\nexport type RetentionDisplayMode = 'heatmap' | 'line' | 'combined'\n\n/**\n * Get color with opacity based on retention rate for heatmap cells\n * Uses a green gradient: higher retention = more saturated green\n */\nfunction getRetentionColor(rate: number): string {\n const clampedRate = Math.max(0, Math.min(1, rate))\n const alpha = 0.1 + clampedRate * 0.7\n return `rgba(34, 197, 94, ${alpha})`\n}\n\n/**\n * Format percentage for display\n */\nfunction formatPercentage(rate: number): string {\n return `${Math.round(rate * 100)}%`\n}\n\n/**\n * Format period label based on granularity\n * Period 0 shows \"< 1 Day\" / \"< 1 Week\" etc. to indicate the initial cohort\n * e.g., Period 0 with 'week' granularity → \"< 1 Week\", Period 1 → \"Week 1\"\n */\nfunction formatPeriodLabel(period: number, granularity?: RetentionGranularity): string {\n const prefix = granularity === 'day' ? 'Day'\n : granularity === 'week' ? 'Week'\n : granularity === 'month' ? 'Month'\n : 'P' // Fallback to P0, P1, etc.\n\n // Period 0 is special - shows \"< 1 Day\" / \"< 1 Week\" etc.\n if (period === 0) {\n return granularity ? `< 1 ${prefix}` : 'P0'\n }\n\n return granularity ? `${prefix} ${period}` : `P${period}`\n}\n\n/**\n * Get display label for the cohort total column\n * Shows \"Total\" regardless of binding key - it's the cohort size count\n */\nfunction getCohortLabel(_bindingKeyLabel?: string): string {\n return 'Total'\n}\n\n/**\n * Get default series name based on binding key\n * e.g., \"userId\" → \"userId Retention\", null → \"Retention\"\n */\nfunction getDefaultSeriesName(bindingKeyLabel?: string): string {\n if (!bindingKeyLabel) return 'Retention'\n return `${bindingKeyLabel} Retention`\n}\n\n/**\n * Transform retention data for chart display\n * Groups data by period with breakdown values as series\n */\nfunction transformRetentionData(\n rows: RetentionResultRow[],\n periods: number[],\n breakdownValues?: string[],\n granularity?: RetentionGranularity,\n bindingKeyLabel?: string\n): { chartData: any[]; seriesKeys: string[]; defaultSeriesName: string } {\n const defaultSeriesName = getDefaultSeriesName(bindingKeyLabel)\n\n // If no breakdown, single series\n if (!breakdownValues || breakdownValues.length === 0) {\n const chartData = periods.map((period) => {\n const row = rows.find((r) => r.period === period && !r.breakdownValue)\n return {\n period,\n periodLabel: formatPeriodLabel(period, granularity),\n [defaultSeriesName]: row ? row.retentionRate : null,\n cohortSize: row?.cohortSize ?? 0,\n retainedUsers: row?.retainedUsers ?? 0,\n }\n })\n return { chartData, seriesKeys: [defaultSeriesName], defaultSeriesName }\n }\n\n // With breakdown, create series per breakdown value\n const chartData = periods.map((period) => {\n const dataPoint: any = {\n period,\n periodLabel: formatPeriodLabel(period, granularity),\n }\n\n breakdownValues.forEach((bv) => {\n const row = rows.find((r) => r.period === period && r.breakdownValue === bv)\n dataPoint[bv] = row ? row.retentionRate : null\n dataPoint[`${bv}_cohortSize`] = row?.cohortSize ?? 0\n dataPoint[`${bv}_retainedUsers`] = row?.retainedUsers ?? 0\n })\n\n return dataPoint\n })\n\n return { chartData, seriesKeys: breakdownValues, defaultSeriesName }\n}\n\ninterface TooltipData {\n period: number\n breakdownValue?: string | null\n cohortSize: number\n retainedUsers: number\n retentionRate: number\n x: number\n y: number\n}\n\n/**\n * RetentionCombinedChart Component\n */\nconst RetentionCombinedChart = React.memo(function RetentionCombinedChart({\n data,\n height = '100%',\n displayConfig,\n colorPalette,\n}: ChartProps) {\n const [hoveredLegend, setHoveredLegend] = useState<string | null>(null)\n const [heatmapTooltip, setHeatmapTooltip] = useState<TooltipData | null>(null)\n\n // Parse retention data\n const retentionData = useMemo<RetentionChartData | null>(() => {\n if (!data) return null\n\n // Check if data is already in RetentionChartData format\n if (isRetentionData(data)) {\n return data\n }\n\n // If data is an array of RetentionResultRow, convert it\n if (Array.isArray(data) && data.length > 0) {\n const rows = data as RetentionResultRow[]\n const periods = [...new Set(rows.map((r) => r.period))].sort((a, b) => a - b)\n const breakdownValues = [\n ...new Set(rows.filter((r) => r.breakdownValue).map((r) => r.breakdownValue!)),\n ]\n\n return {\n rows,\n periods,\n breakdownValues: breakdownValues.length > 0 ? breakdownValues : undefined,\n }\n }\n\n return null\n }, [data])\n\n // Transform data for chart\n const { chartData, seriesKeys, defaultSeriesName } = useMemo(() => {\n if (!retentionData) {\n return { chartData: [], seriesKeys: [], defaultSeriesName: 'Retention' }\n }\n return transformRetentionData(\n retentionData.rows,\n retentionData.periods,\n retentionData.breakdownValues,\n retentionData.granularity,\n retentionData.bindingKeyLabel\n )\n }, [retentionData])\n\n // Get cohort label for heatmap column header\n const cohortLabel = getCohortLabel(retentionData?.bindingKeyLabel)\n\n // Display mode from config\n const displayMode: RetentionDisplayMode =\n (displayConfig as any)?.retentionDisplayMode || 'line'\n\n const showLegend = displayConfig?.showLegend ?? true\n const showGrid = displayConfig?.showGrid ?? true\n const showTooltip = displayConfig?.showTooltip ?? true\n\n // Handle empty/loading states\n if (!data || (Array.isArray(data) && data.length === 0)) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\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 Configure retention analysis to see results\n </div>\n </div>\n </div>\n )\n }\n\n if (!chartData || chartData.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Unable to render retention data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">Data format may be incorrect</div>\n </div>\n </div>\n )\n }\n\n // Render line chart component (reused in line and combined modes)\n const renderLineChart = (chartHeight: string | number) => {\n const chartMargins = {\n ...CHART_MARGINS,\n left: 50,\n right: 20,\n }\n\n return (\n <ChartContainer height={chartHeight}>\n <ComposedChart data={chartData} margin={chartMargins} accessibilityLayer={false}>\n {showGrid && <CartesianGrid strokeDasharray=\"3 3\" />}\n <XAxis\n dataKey=\"periodLabel\"\n tick={{ fontSize: 12 }}\n axisLine={{ stroke: 'var(--dc-border)' }}\n tickLine={{ stroke: 'var(--dc-border)' }}\n />\n <YAxis\n domain={[0, 1]}\n tickFormatter={(value) => formatPercentage(value)}\n tick={{ fontSize: 12 }}\n axisLine={{ stroke: 'var(--dc-border)' }}\n tickLine={{ stroke: 'var(--dc-border)' }}\n label={{\n value: 'Retention %',\n angle: -90,\n position: 'insideLeft',\n style: { textAnchor: 'middle', fontSize: '12px', fill: 'var(--dc-text-secondary)' },\n }}\n />\n {showTooltip && (\n <ChartTooltip\n formatter={(value: any, name: string) => {\n if (value === null || value === undefined) {\n return ['No data', name]\n }\n return [formatPercentage(value), name]\n }}\n labelFormatter={(label: string) => label}\n />\n )}\n {showLegend && (\n <Legend\n wrapperStyle={{ fontSize: '12px', paddingTop: '10px' }}\n iconType=\"line\"\n iconSize={8}\n layout=\"horizontal\"\n align=\"center\"\n verticalAlign=\"bottom\"\n onMouseEnter={(o) => setHoveredLegend(String(o.dataKey || ''))}\n onMouseLeave={() => setHoveredLegend(null)}\n />\n )}\n\n {/* Render lines */}\n {seriesKeys.map((seriesKey, index) => (\n <Line\n key={seriesKey}\n type=\"monotone\"\n dataKey={seriesKey}\n stroke={\n (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n }\n strokeWidth={2}\n dot={{ r: 4, strokeWidth: 2 }}\n activeDot={{ r: 6 }}\n strokeOpacity={hoveredLegend ? (hoveredLegend === seriesKey ? 1 : 0.3) : 1}\n connectNulls={false}\n />\n ))}\n </ComposedChart>\n </ChartContainer>\n )\n }\n\n // Render heatmap table component (reused in heatmap and combined modes)\n const renderHeatmapTable = () => (\n <table className=\"dc:w-full dc:border-collapse dc:text-sm\">\n <thead className=\"dc:sticky dc:top-0 bg-dc-bg dc:z-10\">\n <tr>\n <th className=\"dc:text-left dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[100px] dc:whitespace-nowrap\">\n {retentionData?.breakdownValues?.length ? 'Segment' : 'Cohort'}\n </th>\n <th className=\"dc:text-right dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[60px] dc:whitespace-nowrap\">\n {cohortLabel}\n </th>\n {retentionData?.periods.map((period) => (\n <th\n key={period}\n className=\"dc:text-center dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[70px] dc:whitespace-nowrap\"\n >\n {formatPeriodLabel(period, retentionData?.granularity)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {seriesKeys.map((seriesKey, rowIndex) => {\n const period0Data = chartData.find((d) => d.period === 0)\n const isDefaultSeries = seriesKey === defaultSeriesName\n const cohortSize = isDefaultSeries\n ? period0Data?.cohortSize ?? 0\n : period0Data?.[`${seriesKey}_cohortSize`] ?? 0\n\n return (\n <tr\n key={seriesKey}\n className={rowIndex % 2 === 0 ? 'bg-dc-bg' : 'bg-dc-surface-secondary'}\n >\n <td className=\"dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:whitespace-nowrap\">\n {seriesKey}\n </td>\n <td className=\"dc:p-2 dc:text-right text-dc-text-secondary dc:border-b border-dc-border\">\n {cohortSize.toLocaleString()}\n </td>\n {retentionData?.periods.map((period) => {\n const dataPoint = chartData.find((d) => d.period === period)\n const rate = dataPoint?.[seriesKey] ?? 0\n const bgColor = rate > 0 ? getRetentionColor(rate) : 'transparent'\n const textColor = rate > 0.5 ? '#ffffff' : 'var(--dc-text)'\n\n return (\n <td\n key={period}\n className=\"dc:p-2 dc:text-center dc:border-b border-dc-border dc:cursor-default dc:transition-opacity dc:hover:opacity-80\"\n style={{ backgroundColor: bgColor, color: textColor }}\n onMouseEnter={(e) => {\n const rect = e.currentTarget.getBoundingClientRect()\n const retainedUsers = isDefaultSeries\n ? dataPoint?.retainedUsers ?? 0\n : dataPoint?.[`${seriesKey}_retainedUsers`] ?? 0\n setHeatmapTooltip({\n period,\n breakdownValue: isDefaultSeries ? null : seriesKey,\n cohortSize,\n retainedUsers,\n retentionRate: rate,\n x: rect.left + rect.width / 2,\n y: rect.top,\n })\n }}\n onMouseLeave={() => setHeatmapTooltip(null)}\n >\n {rate > 0 ? formatPercentage(rate) : '-'}\n </td>\n )\n })}\n </tr>\n )\n })}\n </tbody>\n </table>\n )\n\n // Render heatmap tooltip (shared between heatmap and combined modes)\n const renderHeatmapTooltip = () =>\n heatmapTooltip && (\n <div\n className=\"dc:fixed dc:z-50 dc:px-3 dc:py-2 bg-dc-surface dc:border border-dc-border dc:rounded dc:shadow-lg dc:text-sm dc:pointer-events-none\"\n style={{\n left: heatmapTooltip.x,\n top: heatmapTooltip.y - 10,\n transform: 'translate(-50%, -100%)',\n }}\n >\n <div className=\"dc:font-medium text-dc-text dc:mb-1\">\n {heatmapTooltip.breakdownValue\n ? `${heatmapTooltip.breakdownValue} - ${formatPeriodLabel(heatmapTooltip.period, retentionData?.granularity)}`\n : formatPeriodLabel(heatmapTooltip.period, retentionData?.granularity)}\n </div>\n <div className=\"text-dc-text-secondary dc:space-y-0.5\">\n <div>Cohort Size: {heatmapTooltip.cohortSize.toLocaleString()}</div>\n <div>Retained: {heatmapTooltip.retainedUsers.toLocaleString()}</div>\n <div className=\"dc:font-medium text-dc-text\">\n Rate: {formatPercentage(heatmapTooltip.retentionRate)}\n </div>\n </div>\n </div>\n )\n\n // Render heatmap mode (table-based only)\n if (displayMode === 'heatmap') {\n return (\n <div className=\"dc:relative dc:w-full dc:h-full dc:overflow-auto\" style={{ height }}>\n {renderHeatmapTable()}\n {renderHeatmapTooltip()}\n </div>\n )\n }\n\n // Combined mode: line chart on top, heatmap table below\n if (displayMode === 'combined') {\n return (\n <div className=\"dc:flex dc:flex-col dc:w-full dc:h-full\" style={{ height }}>\n {/* Line chart - takes remaining space after heatmap */}\n <div className=\"dc:flex-1 dc:min-h-[200px]\">\n {renderLineChart('100%')}\n </div>\n {/* Heatmap table - auto-height based on content, scrolls if needed */}\n <div className=\"dc:flex-shrink-0 dc:max-h-[40%] dc:overflow-auto dc:border-t border-dc-border\">\n {renderHeatmapTable()}\n </div>\n {/* Shared heatmap tooltip */}\n {renderHeatmapTooltip()}\n </div>\n )\n }\n\n // Line mode: just the line chart\n return renderLineChart(height)\n})\n\nexport default RetentionCombinedChart\n"],"mappings":";;;;;;;AA2CA,SAAS,EAAkB,GAAsB;AAG/C,QAAO,qBADO,KADM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,EAAK,CAAC,GAChB,GACA;;AAMpC,SAAS,EAAiB,GAAsB;AAC9C,QAAO,GAAG,KAAK,MAAM,IAAO,IAAI,CAAC;;AAQnC,SAAS,EAAkB,GAAgB,GAA4C;CACrF,IAAM,IAAS,MAAgB,QAAQ,QACnC,MAAgB,SAAS,SACzB,MAAgB,UAAU,UAC1B;AAOJ,QAJI,MAAW,IACN,IAAc,OAAO,MAAW,OAGlC,IAAc,GAAG,EAAO,GAAG,MAAW,IAAI;;AAOnD,SAAS,EAAe,GAAmC;AACzD,QAAO;;AAOT,SAAS,EAAqB,GAAkC;AAE9D,QADK,IACE,GAAG,EAAgB,cADG;;AAQ/B,SAAS,EACP,GACA,GACA,GACA,GACA,GACuE;CACvE,IAAM,IAAoB,EAAqB,EAAgB;AAkC/D,QA/BI,CAAC,KAAmB,EAAgB,WAAW,IAW1C;EAAE,WAVS,EAAQ,KAAK,MAAW;GACxC,IAAM,IAAM,EAAK,MAAM,MAAM,EAAE,WAAW,KAAU,CAAC,EAAE,eAAe;AACtE,UAAO;IACL;IACA,aAAa,EAAkB,GAAQ,EAAY;KAClD,IAAoB,IAAM,EAAI,gBAAgB;IAC/C,YAAY,GAAK,cAAc;IAC/B,eAAe,GAAK,iBAAiB;IACtC;IACD;EACkB,YAAY,CAAC,EAAkB;EAAE;EAAmB,GAoBnE;EAAE,WAhBS,EAAQ,KAAK,MAAW;GACxC,IAAM,IAAiB;IACrB;IACA,aAAa,EAAkB,GAAQ,EAAY;IACpD;AASD,UAPA,EAAgB,SAAS,MAAO;IAC9B,IAAM,IAAM,EAAK,MAAM,MAAM,EAAE,WAAW,KAAU,EAAE,mBAAmB,EAAG;AAG5E,IAFA,EAAU,KAAM,IAAM,EAAI,gBAAgB,MAC1C,EAAU,GAAG,EAAG,gBAAgB,GAAK,cAAc,GACnD,EAAU,GAAG,EAAG,mBAAmB,GAAK,iBAAiB;KACzD,EAEK;IACP;EAEkB,YAAY;EAAiB;EAAmB;;AAgBtE,IAAM,IAAyB,EAAM,KAAK,SAAgC,EACxE,SACA,YAAS,QACT,kBACA,mBACa;CACb,IAAM,CAAC,GAAe,KAAoB,EAAwB,KAAK,EACjE,CAAC,GAAgB,KAAqB,EAA6B,KAAK,EAGxE,IAAgB,QAAyC;AAC7D,MAAI,CAAC,EAAM,QAAO;AAGlB,MAAI,EAAgB,EAAK,CACvB,QAAO;AAIT,MAAI,MAAM,QAAQ,EAAK,IAAI,EAAK,SAAS,GAAG;GAC1C,IAAM,IAAO,GACP,IAAU,CAAC,GAAG,IAAI,IAAI,EAAK,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE,EACvE,IAAkB,CACtB,GAAG,IAAI,IAAI,EAAK,QAAQ,MAAM,EAAE,eAAe,CAAC,KAAK,MAAM,EAAE,eAAgB,CAAC,CAC/E;AAED,UAAO;IACL;IACA;IACA,iBAAiB,EAAgB,SAAS,IAAI,IAAkB,KAAA;IACjE;;AAGH,SAAO;IACN,CAAC,EAAK,CAAC,EAGJ,EAAE,cAAW,eAAY,yBAAsB,QAC9C,IAGE,EACL,EAAc,MACd,EAAc,SACd,EAAc,iBACd,EAAc,aACd,EAAc,gBACf,GARQ;EAAE,WAAW,EAAE;EAAE,YAAY,EAAE;EAAE,mBAAmB;EAAa,EASzE,CAAC,EAAc,CAAC,EAGb,IAAc,EAAe,GAAe,gBAAgB,EAG5D,IACH,GAAuB,wBAAwB,QAE5C,IAAa,GAAe,cAAc,IAC1C,IAAW,GAAe,YAAY,IACtC,IAAc,GAAe,eAAe;AAGlD,KAAI,CAAC,KAAS,MAAM,QAAQ,EAAK,IAAI,EAAK,WAAW,EACnD,QACE,kBAAC,OAAD;EACE,WAAU;EACV,OAAO,EAAE,WAAQ;YAEjB,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAsC;IAAuB,CAAA,EAC5E,kBAAC,OAAD;IAAK,WAAU;cAAoC;IAE7C,CAAA,CACF;;EACF,CAAA;AAIV,KAAI,CAAC,KAAa,EAAU,WAAW,EACrC,QACE,kBAAC,OAAD;EACE,WAAU;EACV,OAAO,EAAE,WAAQ;YAEjB,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAsC;IAAqC,CAAA,EAC1F,kBAAC,OAAD;IAAK,WAAU;cAAoC;IAAkC,CAAA,CACjF;;EACF,CAAA;CAKV,IAAM,KAAmB,MAQrB,kBAAC,GAAD;EAAgB,QAAQ;YACtB,kBAAC,GAAD;GAAe,MAAM;GAAW,QARf;IACnB,GAAG;IACH,MAAM;IACN,OAAO;IACR;GAIyD,oBAAoB;aAA1E;IACG,KAAY,kBAAC,GAAD,EAAe,iBAAgB,OAAQ,CAAA;IACpD,kBAAC,GAAD;KACE,SAAQ;KACR,MAAM,EAAE,UAAU,IAAI;KACtB,UAAU,EAAE,QAAQ,oBAAoB;KACxC,UAAU,EAAE,QAAQ,oBAAoB;KACxC,CAAA;IACF,kBAAC,GAAD;KACE,QAAQ,CAAC,GAAG,EAAE;KACd,gBAAgB,MAAU,EAAiB,EAAM;KACjD,MAAM,EAAE,UAAU,IAAI;KACtB,UAAU,EAAE,QAAQ,oBAAoB;KACxC,UAAU,EAAE,QAAQ,oBAAoB;KACxC,OAAO;MACL,OAAO;MACP,OAAO;MACP,UAAU;MACV,OAAO;OAAE,YAAY;OAAU,UAAU;OAAQ,MAAM;OAA4B;MACpF;KACD,CAAA;IACD,KACC,kBAAC,GAAD;KACE,YAAY,GAAY,MAClB,KAAU,OACL,CAAC,WAAW,EAAK,GAEnB,CAAC,EAAiB,EAAM,EAAE,EAAK;KAExC,iBAAiB,MAAkB;KACnC,CAAA;IAEH,KACC,kBAAC,GAAD;KACE,cAAc;MAAE,UAAU;MAAQ,YAAY;MAAQ;KACtD,UAAS;KACT,UAAU;KACV,QAAO;KACP,OAAM;KACN,eAAc;KACd,eAAe,MAAM,EAAiB,OAAO,EAAE,WAAW,GAAG,CAAC;KAC9D,oBAAoB,EAAiB,KAAK;KAC1C,CAAA;IAIH,EAAW,KAAK,GAAW,MAC1B,kBAAC,GAAD;KAEE,MAAK;KACL,SAAS;KACT,QACG,GAAc,UAAU,EAAa,OAAO,IAAQ,EAAa,OAAO,WACzE,EAAa,IAAQ,EAAa;KAEpC,aAAa;KACb,KAAK;MAAE,GAAG;MAAG,aAAa;MAAG;KAC7B,WAAW,EAAE,GAAG,GAAG;KACnB,eAAe,IAAiB,MAAkB,IAAY,IAAI,KAAO;KACzE,cAAc;KACd,EAZK,EAYL,CACF;IACY;;EACD,CAAA,EAKf,UACJ,kBAAC,SAAD;EAAO,WAAU;YAAjB,CACE,kBAAC,SAAD;GAAO,WAAU;aACf,kBAAC,MAAD,EAAA,UAAA;IACE,kBAAC,MAAD;KAAI,WAAU;eACX,GAAe,iBAAiB,SAAS,YAAY;KACnD,CAAA;IACL,kBAAC,MAAD;KAAI,WAAU;eACX;KACE,CAAA;IACJ,GAAe,QAAQ,KAAK,MAC3B,kBAAC,MAAD;KAEE,WAAU;eAET,EAAkB,GAAQ,GAAe,YAAY;KACnD,EAJE,EAIF,CACL;IACC,EAAA,CAAA;GACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAW,KAAK,GAAW,MAAa;GACvC,IAAM,IAAc,EAAU,MAAM,MAAM,EAAE,WAAW,EAAE,EACnD,IAAkB,MAAc,GAChC,IAAa,IACf,GAAa,cAAc,IAC3B,IAAc,GAAG,EAAU,iBAAiB;AAEhD,UACE,kBAAC,MAAD;IAEE,WAAW,IAAW,KAAM,IAAI,aAAa;cAF/C;KAIE,kBAAC,MAAD;MAAI,WAAU;gBACX;MACE,CAAA;KACL,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAW,gBAAgB;MACzB,CAAA;KACJ,GAAe,QAAQ,KAAK,MAAW;MACtC,IAAM,IAAY,EAAU,MAAM,MAAM,EAAE,WAAW,EAAO,EACtD,IAAO,IAAY,MAAc;AAIvC,aACE,kBAAC,MAAD;OAEE,WAAU;OACV,OAAO;QAAE,iBAPG,IAAO,IAAI,EAAkB,EAAK,GAAG;QAOd,OANrB,IAAO,KAAM,YAAY;QAMc;OACrD,eAAe,MAAM;QACnB,IAAM,IAAO,EAAE,cAAc,uBAAuB;AAIpD,UAAkB;SAChB;SACA,gBAAgB,IAAkB,OAAO;SACzC;SACA,eAPoB,IAClB,GAAW,iBAAiB,IAC5B,IAAY,GAAG,EAAU,oBAAoB;SAM/C,eAAe;SACf,GAAG,EAAK,OAAO,EAAK,QAAQ;SAC5B,GAAG,EAAK;SACT,CAAC;;OAEJ,oBAAoB,EAAkB,KAAK;iBAE1C,IAAO,IAAI,EAAiB,EAAK,GAAG;OAClC,EArBE,EAqBF;OAEP;KACC;MAzCE,EAyCF;IAEP,EACI,CAAA,CACF;KAIJ,UACJ,KACE,kBAAC,OAAD;EACE,WAAU;EACV,OAAO;GACL,MAAM,EAAe;GACrB,KAAK,EAAe,IAAI;GACxB,WAAW;GACZ;YANH,CAQE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAe,iBACZ,GAAG,EAAe,eAAe,KAAK,EAAkB,EAAe,QAAQ,GAAe,YAAY,KAC1G,EAAkB,EAAe,QAAQ,GAAe,YAAY;GACpE,CAAA,EACN,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD,EAAA,UAAA,CAAK,iBAAc,EAAe,WAAW,gBAAgB,CAAO,EAAA,CAAA;IACpE,kBAAC,OAAD,EAAA,UAAA,CAAK,cAAW,EAAe,cAAc,gBAAgB,CAAO,EAAA,CAAA;IACpE,kBAAC,OAAD;KAAK,WAAU;eAAf,CAA6C,UACpC,EAAiB,EAAe,cAAc,CACjD;;IACF;KACF;;AAgCV,QA5BI,MAAgB,YAEhB,kBAAC,OAAD;EAAK,WAAU;EAAmD,OAAO,EAAE,WAAQ;YAAnF,CACG,GAAoB,EACpB,GAAsB,CACnB;MAKN,MAAgB,aAEhB,kBAAC,OAAD;EAAK,WAAU;EAA0C,OAAO,EAAE,WAAQ;YAA1E;GAEE,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAgB,OAAO;IACpB,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cACZ,GAAoB;IACjB,CAAA;GAEL,GAAsB;GACnB;MAKH,EAAgB,EAAO;EAC9B"}
@@ -190,4 +190,4 @@ var u = t.memo(function({ data: t, height: u = "100%", displayConfig: d }) {
190
190
  //#endregion
191
191
  export { u as default };
192
192
 
193
- //# sourceMappingURL=RetentionHeatmap-Dn2ocjVf.js.map
193
+ //# sourceMappingURL=RetentionHeatmap-CyREolyP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RetentionHeatmap-Dn2ocjVf.js","names":[],"sources":["../../../src/client/components/charts/RetentionHeatmap.tsx"],"sourcesContent":["/**\n * RetentionHeatmap Component\n *\n * Visualizes retention analysis data as a cohort × period matrix.\n * Displays retention rates with color intensity based on percentage.\n *\n * Features:\n * - Cohort labels in first column (e.g., \"2024-01\", \"2024-02\")\n * - Cohort size in second column\n * - Period columns (P0, P1, P2, ... PN)\n * - Cell background color intensity based on retention rate\n * - Hover tooltip with detailed stats\n */\n\nimport React, { useMemo, useState } from 'react'\nimport type { ChartProps } from '../../types'\nimport type { RetentionChartData, RetentionResultRow } from '../../types/retention'\nimport { isRetentionData } from '../../types/retention'\n\n/**\n * Get color with opacity based on retention rate\n * Uses a green gradient: higher retention = more saturated green\n */\nfunction getRetentionColor(rate: number): string {\n // Clamp rate between 0 and 1\n const clampedRate = Math.max(0, Math.min(1, rate))\n\n // Use CSS variable for theming support\n // Fallback to a green color if CSS var not available\n const alpha = 0.1 + clampedRate * 0.7 // Range from 0.1 to 0.8 opacity\n\n // Green color (success color)\n return `rgba(34, 197, 94, ${alpha})`\n}\n\n/**\n * Get text color that contrasts with background\n */\nfunction getTextColor(rate: number): string {\n // Use dark text for lower rates, light text for higher rates\n return rate > 0.5 ? '#ffffff' : 'var(--dc-text)'\n}\n\n/**\n * Format cohort period for display\n * Converts date strings to readable format\n */\nfunction formatCohortPeriod(cohort: string): string {\n // If it's already in YYYY-MM format, return as-is\n if (/^\\d{4}-\\d{2}$/.test(cohort)) {\n return cohort\n }\n\n // Try to parse as date\n const date = new Date(cohort)\n if (!isNaN(date.getTime())) {\n return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })\n }\n\n return cohort\n}\n\n/**\n * Format percentage for display\n */\nfunction formatPercentage(rate: number): string {\n return `${Math.round(rate * 100)}%`\n}\n\ninterface TooltipData {\n cohort: string\n period: number\n cohortSize: number\n retainedUsers: number\n retentionRate: number\n x: number\n y: number\n}\n\n/**\n * RetentionHeatmap Component\n */\nconst RetentionHeatmap = React.memo(function RetentionHeatmap({\n data,\n height = '100%',\n displayConfig,\n}: ChartProps) {\n const [tooltip, setTooltip] = useState<TooltipData | null>(null)\n\n // Parse retention data\n const retentionData = useMemo<RetentionChartData | null>(() => {\n if (!data) return null\n\n // Check if data is already in RetentionChartData format\n if (isRetentionData(data)) {\n return data\n }\n\n // If data is an array of RetentionResultRow, convert it\n if (Array.isArray(data) && data.length > 0) {\n const rows = data as RetentionResultRow[]\n const breakdownValues = [...new Set(rows.map(r => r.breakdownValue || 'All Users'))].sort()\n const periods = [...new Set(rows.map(r => r.period))].sort((a, b) => a - b)\n\n return {\n rows,\n breakdownValues: breakdownValues.length > 1 || breakdownValues[0] !== 'All Users' ? breakdownValues : undefined,\n periods,\n }\n }\n\n return null\n }, [data])\n\n // Build matrix for display\n // In the new simplified format, rows are grouped by breakdownValue (or 'All Users' if no breakdown)\n const matrix = useMemo(() => {\n if (!retentionData) return null\n\n const { rows, breakdownValues, periods } = retentionData\n\n // Determine segments: use breakdownValues if available, otherwise single 'All Users' segment\n const segments = breakdownValues || ['All Users']\n\n // Create a lookup map for quick access: segment:period -> row\n const lookup = new Map<string, RetentionResultRow>()\n for (const row of rows) {\n const segment = row.breakdownValue || 'All Users'\n lookup.set(`${segment}:${row.period}`, row)\n }\n\n // Build matrix structure - one row per segment\n return segments.map((segment: string) => {\n const segmentRows = periods.map(period => {\n const row = lookup.get(`${segment}:${period}`)\n return row || null\n })\n\n // Get cohort size from period 0\n const period0 = segmentRows[0]\n const cohortSize = period0?.cohortSize ?? 0\n\n return {\n cohort: segment, // Keep 'cohort' key for compatibility with rendering\n cohortSize,\n periods: segmentRows,\n }\n })\n }, [retentionData])\n\n // Handle mouse enter on cell\n const handleMouseEnter = (\n event: React.MouseEvent,\n cohort: string,\n period: number,\n row: RetentionResultRow | null\n ) => {\n if (!row) return\n\n const rect = event.currentTarget.getBoundingClientRect()\n setTooltip({\n cohort,\n period,\n cohortSize: row.cohortSize,\n retainedUsers: row.retainedUsers,\n retentionRate: row.retentionRate,\n x: rect.left + rect.width / 2,\n y: rect.top,\n })\n }\n\n const handleMouseLeave = () => {\n setTooltip(null)\n }\n\n // Handle empty/loading states\n if (!data || (Array.isArray(data) && data.length === 0)) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\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 Configure retention analysis to see results\n </div>\n </div>\n </div>\n )\n }\n\n if (!matrix || matrix.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Unable to render retention data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n Data format may be incorrect\n </div>\n </div>\n </div>\n )\n }\n\n const periods = retentionData?.periods ?? []\n const showLegend = displayConfig?.showLegend ?? true\n\n return (\n <div className=\"dc:relative dc:w-full dc:h-full dc:overflow-auto\" style={{ height }}>\n {/* Retention Matrix Table */}\n <table className=\"dc:w-full dc:border-collapse dc:text-sm\">\n <thead className=\"dc:sticky dc:top-0 bg-dc-bg dc:z-10\">\n <tr>\n <th className=\"dc:text-left dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[100px]\">\n Cohort\n </th>\n <th className=\"dc:text-right dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[80px]\">\n Users\n </th>\n {periods.map(period => (\n <th\n key={period}\n className=\"dc:text-center dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[60px]\"\n >\n P{period}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {matrix.map((row, rowIndex) => (\n <tr key={row.cohort} className={rowIndex % 2 === 0 ? 'bg-dc-bg' : 'bg-dc-surface-secondary'}>\n <td className=\"dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:whitespace-nowrap\">\n {formatCohortPeriod(row.cohort)}\n </td>\n <td className=\"dc:p-2 dc:text-right text-dc-text-secondary dc:border-b border-dc-border\">\n {row.cohortSize.toLocaleString()}\n </td>\n {row.periods.map((cell, periodIndex) => {\n const period = periods[periodIndex]\n const rate = cell?.retentionRate ?? 0\n const bgColor = cell ? getRetentionColor(rate) : 'transparent'\n const textColor = cell ? getTextColor(rate) : 'var(--dc-text-muted)'\n\n return (\n <td\n key={period}\n className=\"dc:p-2 dc:text-center dc:border-b border-dc-border dc:cursor-default dc:transition-opacity dc:hover:opacity-80\"\n style={{ backgroundColor: bgColor, color: textColor }}\n onMouseEnter={(e) => handleMouseEnter(e, row.cohort, period, cell)}\n onMouseLeave={handleMouseLeave}\n >\n {cell ? formatPercentage(rate) : '-'}\n </td>\n )\n })}\n </tr>\n ))}\n </tbody>\n </table>\n\n {/* Legend */}\n {showLegend && (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:mt-4 dc:gap-2 dc:text-xs text-dc-text-secondary\">\n <span>0%</span>\n <div className=\"dc:flex dc:h-4\">\n {[0, 0.2, 0.4, 0.6, 0.8, 1].map(rate => (\n <div\n key={rate}\n className=\"dc:w-6 dc:h-4\"\n style={{ backgroundColor: getRetentionColor(rate) }}\n />\n ))}\n </div>\n <span>100%</span>\n </div>\n )}\n\n {/* Tooltip */}\n {tooltip && (\n <div\n className=\"dc:fixed dc:z-50 dc:px-3 dc:py-2 bg-dc-surface dc:border border-dc-border dc:rounded dc:shadow-lg dc:text-sm dc:pointer-events-none\"\n style={{\n left: tooltip.x,\n top: tooltip.y - 10,\n transform: 'translate(-50%, -100%)',\n }}\n >\n <div className=\"dc:font-medium text-dc-text dc:mb-1\">\n {formatCohortPeriod(tooltip.cohort)} - Period {tooltip.period}\n </div>\n <div className=\"text-dc-text-secondary dc:space-y-0.5\">\n <div>Cohort Size: {tooltip.cohortSize.toLocaleString()}</div>\n <div>Retained: {tooltip.retainedUsers.toLocaleString()}</div>\n <div className=\"dc:font-medium text-dc-text\">\n Rate: {formatPercentage(tooltip.retentionRate)}\n </div>\n </div>\n </div>\n )}\n </div>\n )\n})\n\nexport default RetentionHeatmap\n"],"mappings":"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"}
1
+ {"version":3,"file":"RetentionHeatmap-CyREolyP.js","names":[],"sources":["../../../src/client/components/charts/RetentionHeatmap.tsx"],"sourcesContent":["/**\n * RetentionHeatmap Component\n *\n * Visualizes retention analysis data as a cohort × period matrix.\n * Displays retention rates with color intensity based on percentage.\n *\n * Features:\n * - Cohort labels in first column (e.g., \"2024-01\", \"2024-02\")\n * - Cohort size in second column\n * - Period columns (P0, P1, P2, ... PN)\n * - Cell background color intensity based on retention rate\n * - Hover tooltip with detailed stats\n */\n\nimport React, { useMemo, useState } from 'react'\nimport type { ChartProps } from '../../types'\nimport type { RetentionChartData, RetentionResultRow } from '../../types/retention'\nimport { isRetentionData } from '../../types/retention'\n\n/**\n * Get color with opacity based on retention rate\n * Uses a green gradient: higher retention = more saturated green\n */\nfunction getRetentionColor(rate: number): string {\n // Clamp rate between 0 and 1\n const clampedRate = Math.max(0, Math.min(1, rate))\n\n // Use CSS variable for theming support\n // Fallback to a green color if CSS var not available\n const alpha = 0.1 + clampedRate * 0.7 // Range from 0.1 to 0.8 opacity\n\n // Green color (success color)\n return `rgba(34, 197, 94, ${alpha})`\n}\n\n/**\n * Get text color that contrasts with background\n */\nfunction getTextColor(rate: number): string {\n // Use dark text for lower rates, light text for higher rates\n return rate > 0.5 ? '#ffffff' : 'var(--dc-text)'\n}\n\n/**\n * Format cohort period for display\n * Converts date strings to readable format\n */\nfunction formatCohortPeriod(cohort: string): string {\n // If it's already in YYYY-MM format, return as-is\n if (/^\\d{4}-\\d{2}$/.test(cohort)) {\n return cohort\n }\n\n // Try to parse as date\n const date = new Date(cohort)\n if (!isNaN(date.getTime())) {\n return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short' })\n }\n\n return cohort\n}\n\n/**\n * Format percentage for display\n */\nfunction formatPercentage(rate: number): string {\n return `${Math.round(rate * 100)}%`\n}\n\ninterface TooltipData {\n cohort: string\n period: number\n cohortSize: number\n retainedUsers: number\n retentionRate: number\n x: number\n y: number\n}\n\n/**\n * RetentionHeatmap Component\n */\nconst RetentionHeatmap = React.memo(function RetentionHeatmap({\n data,\n height = '100%',\n displayConfig,\n}: ChartProps) {\n const [tooltip, setTooltip] = useState<TooltipData | null>(null)\n\n // Parse retention data\n const retentionData = useMemo<RetentionChartData | null>(() => {\n if (!data) return null\n\n // Check if data is already in RetentionChartData format\n if (isRetentionData(data)) {\n return data\n }\n\n // If data is an array of RetentionResultRow, convert it\n if (Array.isArray(data) && data.length > 0) {\n const rows = data as RetentionResultRow[]\n const breakdownValues = [...new Set(rows.map(r => r.breakdownValue || 'All Users'))].sort()\n const periods = [...new Set(rows.map(r => r.period))].sort((a, b) => a - b)\n\n return {\n rows,\n breakdownValues: breakdownValues.length > 1 || breakdownValues[0] !== 'All Users' ? breakdownValues : undefined,\n periods,\n }\n }\n\n return null\n }, [data])\n\n // Build matrix for display\n // In the new simplified format, rows are grouped by breakdownValue (or 'All Users' if no breakdown)\n const matrix = useMemo(() => {\n if (!retentionData) return null\n\n const { rows, breakdownValues, periods } = retentionData\n\n // Determine segments: use breakdownValues if available, otherwise single 'All Users' segment\n const segments = breakdownValues || ['All Users']\n\n // Create a lookup map for quick access: segment:period -> row\n const lookup = new Map<string, RetentionResultRow>()\n for (const row of rows) {\n const segment = row.breakdownValue || 'All Users'\n lookup.set(`${segment}:${row.period}`, row)\n }\n\n // Build matrix structure - one row per segment\n return segments.map((segment: string) => {\n const segmentRows = periods.map(period => {\n const row = lookup.get(`${segment}:${period}`)\n return row || null\n })\n\n // Get cohort size from period 0\n const period0 = segmentRows[0]\n const cohortSize = period0?.cohortSize ?? 0\n\n return {\n cohort: segment, // Keep 'cohort' key for compatibility with rendering\n cohortSize,\n periods: segmentRows,\n }\n })\n }, [retentionData])\n\n // Handle mouse enter on cell\n const handleMouseEnter = (\n event: React.MouseEvent,\n cohort: string,\n period: number,\n row: RetentionResultRow | null\n ) => {\n if (!row) return\n\n const rect = event.currentTarget.getBoundingClientRect()\n setTooltip({\n cohort,\n period,\n cohortSize: row.cohortSize,\n retainedUsers: row.retainedUsers,\n retentionRate: row.retentionRate,\n x: rect.left + rect.width / 2,\n y: rect.top,\n })\n }\n\n const handleMouseLeave = () => {\n setTooltip(null)\n }\n\n // Handle empty/loading states\n if (!data || (Array.isArray(data) && data.length === 0)) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\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 Configure retention analysis to see results\n </div>\n </div>\n </div>\n )\n }\n\n if (!matrix || matrix.length === 0) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\"\n style={{ height }}\n >\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">Unable to render retention data</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n Data format may be incorrect\n </div>\n </div>\n </div>\n )\n }\n\n const periods = retentionData?.periods ?? []\n const showLegend = displayConfig?.showLegend ?? true\n\n return (\n <div className=\"dc:relative dc:w-full dc:h-full dc:overflow-auto\" style={{ height }}>\n {/* Retention Matrix Table */}\n <table className=\"dc:w-full dc:border-collapse dc:text-sm\">\n <thead className=\"dc:sticky dc:top-0 bg-dc-bg dc:z-10\">\n <tr>\n <th className=\"dc:text-left dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[100px]\">\n Cohort\n </th>\n <th className=\"dc:text-right dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[80px]\">\n Users\n </th>\n {periods.map(period => (\n <th\n key={period}\n className=\"dc:text-center dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:min-w-[60px]\"\n >\n P{period}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {matrix.map((row, rowIndex) => (\n <tr key={row.cohort} className={rowIndex % 2 === 0 ? 'bg-dc-bg' : 'bg-dc-surface-secondary'}>\n <td className=\"dc:p-2 dc:font-medium text-dc-text dc:border-b border-dc-border dc:whitespace-nowrap\">\n {formatCohortPeriod(row.cohort)}\n </td>\n <td className=\"dc:p-2 dc:text-right text-dc-text-secondary dc:border-b border-dc-border\">\n {row.cohortSize.toLocaleString()}\n </td>\n {row.periods.map((cell, periodIndex) => {\n const period = periods[periodIndex]\n const rate = cell?.retentionRate ?? 0\n const bgColor = cell ? getRetentionColor(rate) : 'transparent'\n const textColor = cell ? getTextColor(rate) : 'var(--dc-text-muted)'\n\n return (\n <td\n key={period}\n className=\"dc:p-2 dc:text-center dc:border-b border-dc-border dc:cursor-default dc:transition-opacity dc:hover:opacity-80\"\n style={{ backgroundColor: bgColor, color: textColor }}\n onMouseEnter={(e) => handleMouseEnter(e, row.cohort, period, cell)}\n onMouseLeave={handleMouseLeave}\n >\n {cell ? formatPercentage(rate) : '-'}\n </td>\n )\n })}\n </tr>\n ))}\n </tbody>\n </table>\n\n {/* Legend */}\n {showLegend && (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:mt-4 dc:gap-2 dc:text-xs text-dc-text-secondary\">\n <span>0%</span>\n <div className=\"dc:flex dc:h-4\">\n {[0, 0.2, 0.4, 0.6, 0.8, 1].map(rate => (\n <div\n key={rate}\n className=\"dc:w-6 dc:h-4\"\n style={{ backgroundColor: getRetentionColor(rate) }}\n />\n ))}\n </div>\n <span>100%</span>\n </div>\n )}\n\n {/* Tooltip */}\n {tooltip && (\n <div\n className=\"dc:fixed dc:z-50 dc:px-3 dc:py-2 bg-dc-surface dc:border border-dc-border dc:rounded dc:shadow-lg dc:text-sm dc:pointer-events-none\"\n style={{\n left: tooltip.x,\n top: tooltip.y - 10,\n transform: 'translate(-50%, -100%)',\n }}\n >\n <div className=\"dc:font-medium text-dc-text dc:mb-1\">\n {formatCohortPeriod(tooltip.cohort)} - Period {tooltip.period}\n </div>\n <div className=\"text-dc-text-secondary dc:space-y-0.5\">\n <div>Cohort Size: {tooltip.cohortSize.toLocaleString()}</div>\n <div>Retained: {tooltip.retainedUsers.toLocaleString()}</div>\n <div className=\"dc:font-medium text-dc-text\">\n Rate: {formatPercentage(tooltip.retentionRate)}\n </div>\n </div>\n </div>\n )}\n </div>\n )\n})\n\nexport default RetentionHeatmap\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { t as e } from "./schema-visualization-t1KiOORo.js";
2
+ export { e as SchemaVisualization, e as default };
@@ -0,0 +1,2 @@
1
+ import { n as e } from "./schema-visualization-t1KiOORo.js";
2
+ export { e as SchemaVisualizationLazy };
@@ -1,10 +1,10 @@
1
- import { A as e, J as t, O as n, P as r, T as i, V as a, b as o, l as s, u as c, x as l } from "./chart-data-table-BZ7StNWv.js";
2
- import { r as u, t as d } from "./useExplainAI-CxdzY2N0.js";
3
- import { A as f } from "./chart-activity-grid-wR2Twpo7.js";
1
+ import { A as e, O as t, P as n, T as r, V as i, Z as a, b as o, l as s, u as c, x as l } from "./chart-data-table-2iCsn0CF.js";
2
+ import { r as u, t as d } from "./useExplainAI-DBIfYwz-.js";
3
+ import { A as f } from "./chart-activity-grid-DLktOINm.js";
4
4
  import { i as p, n as m, o as h, r as g, s as _ } from "./retention-YhT1Oohi.js";
5
- import { d as v, f as y, g as b, i as x, n as S, r as C, t as w, u as T } from "./FieldSearchModal-trURu9Sa.js";
6
- import { C as E, I as D, N as O, P as ee, c as te, d as k, m as A, n as ne, t as j, u as M } from "./analysis-builder-shared-DaqtrLxd.js";
7
- import { n as N } from "./charts-core-Cy3rHADX.js";
5
+ import { d as v, f as y, g as b, i as x, n as S, r as C, t as w, u as T } from "./FieldSearchModal-D75vy4Wb.js";
6
+ import { C as E, I as D, N as O, P as ee, c as te, d as k, m as A, n as ne, t as j, u as M } from "./analysis-builder-shared-rkjJfWLT.js";
7
+ import { n as N } from "./charts-core-C5Yokk-x.js";
8
8
  import P, { Component as re, forwardRef as ie, memo as F, useCallback as I, useEffect as L, useImperativeHandle as ae, useMemo as R, useRef as z, useState as B, useSyncExternalStore as oe } from "react";
9
9
  import { Fragment as V, jsx as H, jsxs as U } from "react/jsx-runtime";
10
10
  //#region src/client/shared/components/QueryAnalysisPanel.tsx
@@ -372,8 +372,8 @@ function le(e) {
372
372
  function ue(e) {
373
373
  return typeof e == "object" && !!e && "funnel" in e && typeof e.funnel == "object";
374
374
  }
375
- function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig: a, setChartConfig: o, displayConfig: s, setDisplayConfig: c, setUserManuallySelectedChart: l, setActiveView: u, aiEndpoint: d = "/api/ai", analysisType: f, setAnalysisType: p, loadFunnelFromServerQuery: m, getFullConfig: h, loadFullConfig: g }) {
376
- let { apiOptions: _ } = t(), [b, x] = B({
375
+ function de({ state: e, setState: t, chartType: n, setChartType: r, chartConfig: i, setChartConfig: o, displayConfig: s, setDisplayConfig: c, setUserManuallySelectedChart: l, setActiveView: u, aiEndpoint: d = "/api/ai", analysisType: f, setAnalysisType: p, loadFunnelFromServerQuery: m, getFullConfig: h, loadFullConfig: g }) {
376
+ let { apiOptions: _ } = a(), [b, x] = B({
377
377
  isOpen: !1,
378
378
  userPrompt: "",
379
379
  isGenerating: !1,
@@ -396,8 +396,8 @@ function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig:
396
396
  metrics: [...e.metrics],
397
397
  breakdowns: [...e.breakdowns],
398
398
  filters: [...e.filters],
399
- chartType: r,
400
- chartConfig: { ...a },
399
+ chartType: n,
400
+ chartConfig: { ...i },
401
401
  displayConfig: { ...s },
402
402
  analysisType: f || "query"
403
403
  },
@@ -407,8 +407,8 @@ function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig:
407
407
  e.metrics,
408
408
  e.breakdowns,
409
409
  e.filters,
410
- r,
411
- a,
410
+ n,
411
+ i,
412
412
  s,
413
413
  f,
414
414
  h
@@ -436,17 +436,17 @@ function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig:
436
436
  error: null
437
437
  }));
438
438
  try {
439
- let e = le(await ce("", b.userPrompt, d, _?.headers)), t = JSON.parse(e), r = "query" in t && t.query ? t.query : t, a = "chartType" in t ? t.chartType : void 0, s = "chartConfig" in t ? t.chartConfig : void 0;
440
- if (ue(r)) if (p && m) {
441
- p("funnel"), m(r), i("funnel"), l(!0), s && o(s), u("chart"), x((e) => ({
439
+ let e = le(await ce("", b.userPrompt, d, _?.headers)), n = JSON.parse(e), i = "query" in n && n.query ? n.query : n, a = "chartType" in n ? n.chartType : void 0, s = "chartConfig" in n ? n.chartConfig : void 0;
440
+ if (ue(i)) if (p && m) {
441
+ p("funnel"), m(i), r("funnel"), l(!0), s && o(s), u("chart"), x((e) => ({
442
442
  ...e,
443
443
  isGenerating: !1,
444
444
  hasGeneratedQuery: !0
445
445
  }));
446
446
  return;
447
447
  } else throw Error("Funnel queries require funnel mode support. Please switch to funnel mode manually.");
448
- let c = r;
449
- n((e) => ({
448
+ let c = i;
449
+ t((e) => ({
450
450
  ...e,
451
451
  metrics: (c.measures || []).map((e, t) => ({
452
452
  id: v(),
@@ -466,7 +466,7 @@ function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig:
466
466
  filters: c.filters || [],
467
467
  order: c.order || void 0,
468
468
  limit: c.limit ?? void 0
469
- })), f === "funnel" && p && p("query"), a && (i(a), l(!0)), s && o(s), u("chart"), x((e) => ({
469
+ })), f === "funnel" && p && p("query"), a && (r(a), l(!0)), s && o(s), u("chart"), x((e) => ({
470
470
  ...e,
471
471
  isGenerating: !1,
472
472
  hasGeneratedQuery: !0
@@ -483,8 +483,8 @@ function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig:
483
483
  b.userPrompt,
484
484
  d,
485
485
  _?.headers,
486
- n,
487
- i,
486
+ t,
487
+ r,
488
488
  l,
489
489
  o,
490
490
  u,
@@ -504,12 +504,12 @@ function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig:
504
504
  });
505
505
  }, []),
506
506
  handleCancelAI: I(() => {
507
- b.previousConfig && g ? g(b.previousConfig) : b.previousState && (n((e) => ({
507
+ b.previousConfig && g ? g(b.previousConfig) : b.previousState && (t((e) => ({
508
508
  ...e,
509
509
  metrics: b.previousState.metrics,
510
510
  breakdowns: b.previousState.breakdowns,
511
511
  filters: b.previousState.filters
512
- })), i(b.previousState.chartType), o(b.previousState.chartConfig), c(b.previousState.displayConfig), p && b.previousState.analysisType && p(b.previousState.analysisType)), x({
512
+ })), r(b.previousState.chartType), o(b.previousState.chartConfig), c(b.previousState.displayConfig), p && b.previousState.analysisType && p(b.previousState.analysisType)), x({
513
513
  isOpen: !1,
514
514
  userPrompt: "",
515
515
  isGenerating: !1,
@@ -521,8 +521,8 @@ function de({ state: e, setState: n, chartType: r, setChartType: i, chartConfig:
521
521
  }, [
522
522
  b.previousState,
523
523
  b.previousConfig,
524
- n,
525
- i,
524
+ t,
525
+ r,
526
526
  o,
527
527
  c,
528
528
  p,
@@ -555,7 +555,7 @@ function fe({ isValidQuery: e, getAnalysisConfig: t }) {
555
555
  }
556
556
  //#endregion
557
557
  //#region src/client/components/AnalysisBuilder/AnalysisResultsPanel.tsx
558
- var pe = P.lazy(() => import("./schema-visualization-DVdfx6N8.js").then((e) => e.r).then((e) => ({ default: e.SchemaVisualizationLazy })));
558
+ var pe = P.lazy(() => import("./SchemaVisualizationLazy-DymwT34e.js").then((e) => ({ default: e.SchemaVisualizationLazy })));
559
559
  function me(e, t, n) {
560
560
  let r = [];
561
561
  if (r.push("# Query Execution Plan"), r.push(""), t && (r.push("## Cube Query"), r.push(""), r.push("```json"), r.push(JSON.stringify(t, null, 2)), r.push("```"), r.push("")), r.push("## Query Summary"), r.push(""), r.push(`- **Cubes:** ${e.cubesInvolved.join(", ")}`), r.push(`- **Query Type:** ${e.querySummary.queryType.replace(/_/g, " ")}`), r.push(`- **Joins:** ${e.querySummary.joinCount}`), r.push(`- **CTEs:** ${e.querySummary.cteCount}`), r.push(""), r.push("## Primary Cube Selection"), r.push(""), r.push(`**Selected:** ${e.primaryCube.selectedCube}`), r.push(`**Reason:** ${e.primaryCube.reason.replace(/_/g, " ")}`), r.push(`**Explanation:** ${e.primaryCube.explanation}`), r.push(""), e.primaryCube.candidates && e.primaryCube.candidates.length > 1) {
@@ -600,8 +600,8 @@ function me(e, t, n) {
600
600
  }
601
601
  return n?.sql && (r.push("## Generated SQL"), r.push(""), r.push("```sql"), r.push(n.sql), r.push("```")), r.join("\n");
602
602
  }
603
- var he = F(function({ executionStatus: t, executionResults: n, executionError: r, totalRowCount: o, resultsStale: s = !1, chartType: c = "line", chartConfig: f = {}, displayConfig: p = {}, colorPalette: m, currentPaletteName: h, onColorPaletteChange: g, allQueries: _, funnelExecutedQueries: v, activeView: y = "chart", onActiveViewChange: x, displayLimit: w = 100, onDisplayLimitChange: T, hasMetrics: E = !1, debugDataPerQuery: D = [], onShareClick: O, canShare: te = !1, shareButtonState: k = "idle", onRefreshClick: A, canRefresh: ne = !1, isRefreshing: j = !1, needsRefresh: M = !1, onClearClick: N, canClear: re = !1, enableAI: ie = !1, isAIOpen: F = !1, onAIToggle: ae, queryCount: oe = 1, perQueryResults: W, activeTableIndex: G = 0, onActiveTableChange: ce, analysisType: le, isFunnelMode: ue = !1, funnelServerQuery: de, funnelDebugData: fe, flowServerQuery: he, flowDebugData: ge, retentionServerQuery: _e, retentionDebugData: ve, retentionChartData: K, retentionValidation: ye, warnings: be, highlightedFields: xe, onSchemaFieldClick: Se }) {
604
- let q = le === "funnel" || ue, J = le === "flow", Y = le === "retention", { features: Ce } = a(), [X, we] = B(!1), [Z, Te] = B(!1), [Q, Ee] = B(0), [De, Oe] = B(!1), [ke, Ae] = B(!1), [je, Me] = B(!1), [Ne, Pe] = B("idle");
603
+ var he = F(function({ executionStatus: t, executionResults: n, executionError: a, totalRowCount: o, resultsStale: s = !1, chartType: c = "line", chartConfig: f = {}, displayConfig: p = {}, colorPalette: m, currentPaletteName: h, onColorPaletteChange: g, allQueries: _, funnelExecutedQueries: v, activeView: y = "chart", onActiveViewChange: x, displayLimit: w = 100, onDisplayLimitChange: T, hasMetrics: E = !1, debugDataPerQuery: D = [], onShareClick: O, canShare: te = !1, shareButtonState: k = "idle", onRefreshClick: A, canRefresh: ne = !1, isRefreshing: j = !1, needsRefresh: M = !1, onClearClick: N, canClear: re = !1, enableAI: ie = !1, isAIOpen: F = !1, onAIToggle: ae, queryCount: oe = 1, perQueryResults: W, activeTableIndex: G = 0, onActiveTableChange: ce, analysisType: le, isFunnelMode: ue = !1, funnelServerQuery: de, funnelDebugData: fe, flowServerQuery: he, flowDebugData: ge, retentionServerQuery: _e, retentionDebugData: ve, retentionChartData: K, retentionValidation: ye, warnings: be, highlightedFields: xe, onSchemaFieldClick: Se }) {
604
+ let q = le === "funnel" || ue, J = le === "flow", Y = le === "retention", { features: Ce } = i(), [X, we] = B(!1), [Z, Te] = B(!1), [Q, Ee] = B(0), [De, Oe] = B(!1), [ke, Ae] = B(!1), [je, Me] = B(!1), [Ne, Pe] = B("idle");
605
605
  L(() => {
606
606
  let e = (e) => {
607
607
  e.key === "Shift" && Ae(!0);
@@ -714,11 +714,11 @@ var he = F(function({ executionStatus: t, executionResults: n, executionError: r
714
714
  className: "dc:text-sm text-dc-text-secondary dc:mb-4",
715
715
  children: "There was an error executing your query. Please check the query and try again."
716
716
  }),
717
- r && /* @__PURE__ */ H("div", {
717
+ a && /* @__PURE__ */ H("div", {
718
718
  className: "bg-dc-danger-bg dc:border border-dc-error dc:rounded-lg dc:p-3 dc:text-left",
719
719
  children: /* @__PURE__ */ H("div", {
720
720
  className: "dc:text-xs dc:font-mono text-dc-error dc:break-words",
721
- children: r
721
+ children: a
722
722
  })
723
723
  })
724
724
  ]
@@ -853,7 +853,7 @@ var he = F(function({ executionStatus: t, executionResults: n, executionError: r
853
853
  })
854
854
  });
855
855
  let e = c === "sankey" && p?.flowVisualization === "sunburst" ? "sunburst" : c;
856
- return i(e) ? /* @__PURE__ */ H(l, {
856
+ return r(e) ? /* @__PURE__ */ H(l, {
857
857
  chartType: e,
858
858
  data: Y && K ? K : n,
859
859
  chartConfig: f,
@@ -882,14 +882,14 @@ var he = F(function({ executionStatus: t, executionResults: n, executionError: r
882
882
  ]
883
883
  })
884
884
  });
885
- }, Bt = () => r ? /* @__PURE__ */ U("div", {
885
+ }, Bt = () => a ? /* @__PURE__ */ U("div", {
886
886
  className: "bg-dc-danger-bg dark:bg-dc-danger-bg dc:border border-dc-error dark:border-dc-error dc:rounded dc:p-3",
887
887
  children: [/* @__PURE__ */ H("h4", {
888
888
  className: "dc:text-sm dc:font-semibold text-dc-error dark:text-dc-error dc:mb-1",
889
889
  children: "Execution Error"
890
890
  }), /* @__PURE__ */ H("p", {
891
891
  className: "dc:text-sm text-dc-error dark:text-dc-error",
892
- children: r
892
+ children: a
893
893
  })]
894
894
  }) : null, Vt = () => /* @__PURE__ */ U("div", {
895
895
  className: "dc:grid dc:grid-cols-1 dc:md:grid-cols-2 dc:gap-4",
@@ -1009,14 +1009,14 @@ var he = F(function({ executionStatus: t, executionResults: n, executionError: r
1009
1009
  }, t))
1010
1010
  })]
1011
1011
  }),
1012
- r && /* @__PURE__ */ U("div", {
1012
+ a && /* @__PURE__ */ U("div", {
1013
1013
  className: "bg-dc-danger-bg dark:bg-dc-danger-bg dc:border border-dc-error dark:border-dc-error dc:rounded dc:p-3",
1014
1014
  children: [/* @__PURE__ */ H("h4", {
1015
1015
  className: "dc:text-sm dc:font-semibold text-dc-error dark:text-dc-error dc:mb-1",
1016
1016
  children: "Execution Error"
1017
1017
  }), /* @__PURE__ */ H("p", {
1018
1018
  className: "dc:text-sm text-dc-error dark:text-dc-error",
1019
- children: r
1019
+ children: a
1020
1020
  })]
1021
1021
  }),
1022
1022
  /* @__PURE__ */ U("div", { children: [/* @__PURE__ */ U("div", {
@@ -1678,7 +1678,7 @@ var he = F(function({ executionStatus: t, executionResults: n, executionError: r
1678
1678
  },
1679
1679
  className: `dc:p-1.5 dc:rounded dc:transition-colors dc:relative ${X ? "bg-dc-primary text-white" : "text-dc-text-secondary hover:text-dc-text hover:bg-dc-surface-hover"}`,
1680
1680
  title: X ? "Hide debug info" : "Show debug info",
1681
- children: [/* @__PURE__ */ H(wt, { className: "dc:w-4 dc:h-4" }), (r || D.some((e) => e.error)) && !X && /* @__PURE__ */ H("span", { className: "dc:absolute dc:-top-0.5 dc:-right-0.5 dc:w-2 dc:h-2 bg-dc-danger-bg0 dc:rounded-full" })]
1681
+ children: [/* @__PURE__ */ H(wt, { className: "dc:w-4 dc:h-4" }), (a || D.some((e) => e.error)) && !X && /* @__PURE__ */ H("span", { className: "dc:absolute dc:-top-0.5 dc:-right-0.5 dc:w-2 dc:h-2 bg-dc-danger-bg0 dc:rounded-full" })]
1682
1682
  })
1683
1683
  ]
1684
1684
  })]
@@ -1856,8 +1856,8 @@ var he = F(function({ executionStatus: t, executionResults: n, executionError: r
1856
1856
  })
1857
1857
  ]
1858
1858
  });
1859
- }), ge = F(function({ metric: t, fieldMeta: n, onRemove: i, sortDirection: a, sortPriority: o, onToggleSort: s, index: c, isDragging: l, onDragStart: u, onDragEnd: d }) {
1860
- let f = e("close"), p = e("chevronUp"), m = e("chevronDown"), h = e("chevronUpDown"), g = r(n?.type || "count") || e("measure"), _ = n?.shortTitle || n?.title || t.field.split(".").pop() || t.field, v = t.field.split(".")[0], y = () => {
1859
+ }), ge = F(function({ metric: t, fieldMeta: r, onRemove: i, sortDirection: a, sortPriority: o, onToggleSort: s, index: c, isDragging: l, onDragStart: u, onDragEnd: d }) {
1860
+ let f = e("close"), p = e("chevronUp"), m = e("chevronDown"), h = e("chevronUpDown"), g = n(r?.type || "count") || e("measure"), _ = r?.shortTitle || r?.title || t.field.split(".").pop() || t.field, v = t.field.split(".")[0], y = () => {
1861
1861
  switch (a) {
1862
1862
  case "asc": return p ? /* @__PURE__ */ H(p, { className: "dc:w-4 dc:h-4" }) : "↑";
1863
1863
  case "desc": return m ? /* @__PURE__ */ H(m, { className: "dc:w-4 dc:h-4" }) : "↓";
@@ -2359,7 +2359,7 @@ function X({ limit: e, onLimitChange: t }) {
2359
2359
  //#endregion
2360
2360
  //#region src/client/components/AnalysisBuilder/AnalysisAxisDropZone.tsx
2361
2361
  var we = e("close"), Z = e("dimension"), Te = e("timeDimension"), Q = e("measure");
2362
- function Ee({ config: e, fields: t, onDrop: n, onRemove: i, onDragStart: a, onDragEnd: o, onDragOver: s, onReorder: c, draggedItem: l, getFieldMeta: u, yAxisAssignment: d, onYAxisAssignmentChange: f }) {
2362
+ function Ee({ config: e, fields: t, onDrop: r, onRemove: i, onDragStart: a, onDragEnd: o, onDragOver: s, onReorder: c, draggedItem: l, getFieldMeta: u, yAxisAssignment: d, onYAxisAssignmentChange: f }) {
2363
2363
  let { key: p, label: m, description: h, mandatory: g, maxItems: _, emptyText: v } = e, [y, b] = B(null), [x, S] = B(!1), [C, w] = B(!1), T = z(null), E = z(null), D = z(t);
2364
2364
  D.current = t;
2365
2365
  let O = z(null), ee = () => {
@@ -2437,7 +2437,7 @@ function Ee({ config: e, fields: t, onDrop: n, onRemove: i, onDragStart: a, onDr
2437
2437
  };
2438
2438
  }, ie = (e) => e.type === "measure" ? /* @__PURE__ */ H("span", {
2439
2439
  className: "dc:w-6 dc:h-6 dc:flex dc:items-center dc:justify-center dc:rounded bg-dc-measure text-dc-measure-text dc:flex-shrink-0",
2440
- children: /* @__PURE__ */ H(r(e.measureType || "count") || Q, { className: "dc:w-4 dc:h-4" })
2440
+ children: /* @__PURE__ */ H(n(e.measureType || "count") || Q, { className: "dc:w-4 dc:h-4" })
2441
2441
  }) : e.type === "timeDimension" ? /* @__PURE__ */ H("span", {
2442
2442
  className: "dc:w-6 dc:h-6 dc:flex dc:items-center dc:justify-center dc:rounded bg-dc-time-dimension text-dc-time-dimension-text dc:flex-shrink-0",
2443
2443
  children: /* @__PURE__ */ H(Te, { className: "dc:w-4 dc:h-4" })
@@ -2477,7 +2477,7 @@ function Ee({ config: e, fields: t, onDrop: n, onRemove: i, onDragStart: a, onDr
2477
2477
  (n || i || e.currentTarget === e.target) && (S(!1), w(!1));
2478
2478
  },
2479
2479
  onDrop: (e) => {
2480
- l && l.fromAxis === p && l.fromIndex !== void 0 || (k || _ === 1 ? n(e, p) : e.preventDefault(), S(!1), w(!1));
2480
+ l && l.fromAxis === p && l.fromIndex !== void 0 || (k || _ === 1 ? r(e, p) : e.preventDefault(), S(!1), w(!1));
2481
2481
  },
2482
2482
  children: t.length === 0 ? /* @__PURE__ */ H("div", {
2483
2483
  className: "dc:text-sm text-dc-text-muted dc:text-center dc:py-2",
@@ -2577,8 +2577,8 @@ function Ee({ config: e, fields: t, onDrop: n, onRemove: i, onDragStart: a, onDr
2577
2577
  function De(e) {
2578
2578
  return c[e]?.label || e;
2579
2579
  }
2580
- function Oe({ selectedType: e, onTypeChange: t, className: r = "", compact: i = !1, availability: a, excludeTypes: o = [] }) {
2581
- let [l, u] = B(!1), d = R(() => Object.keys(c).filter((e) => !o.includes(e)).sort((e, t) => De(e).localeCompare(De(t))), [o, oe(s.subscribe, s.getSnapshot)]), f = n(e), p = De(e);
2580
+ function Oe({ selectedType: e, onTypeChange: n, className: r = "", compact: i = !1, availability: a, excludeTypes: o = [] }) {
2581
+ let [l, u] = B(!1), d = R(() => Object.keys(c).filter((e) => !o.includes(e)).sort((e, t) => De(e).localeCompare(De(t))), [o, oe(s.subscribe, s.getSnapshot)]), f = t(e), p = De(e);
2582
2582
  return /* @__PURE__ */ U("div", {
2583
2583
  className: `${r} dc:relative`,
2584
2584
  children: [/* @__PURE__ */ U("button", {
@@ -2610,11 +2610,11 @@ function Oe({ selectedType: e, onTypeChange: t, className: r = "", compact: i =
2610
2610
  children: /* @__PURE__ */ H("div", {
2611
2611
  className: `dc:grid dc:gap-1.5 ${i ? "dc:grid-cols-2" : "dc:grid-cols-2 dc:sm:grid-cols-3 dc:lg:grid-cols-4"}`,
2612
2612
  children: d.map((r) => {
2613
- let i = c[r], o = n(r), s = De(r), l = e === r, d = i?.description, f = i?.useCase, p = a?.[r], m = p?.available ?? !0, h = p?.reason, g = !m && h ? h : [d, f].filter(Boolean).join(". ");
2613
+ let i = c[r], o = t(r), s = De(r), l = e === r, d = i?.description, f = i?.useCase, p = a?.[r], m = p?.available ?? !0, h = p?.reason, g = !m && h ? h : [d, f].filter(Boolean).join(". ");
2614
2614
  return /* @__PURE__ */ U("button", {
2615
2615
  type: "button",
2616
2616
  onClick: () => {
2617
- m && (t(r), u(!1));
2617
+ m && (n(r), u(!1));
2618
2618
  },
2619
2619
  disabled: !m,
2620
2620
  className: `
@@ -2648,12 +2648,12 @@ function Oe({ selectedType: e, onTypeChange: t, className: r = "", compact: i =
2648
2648
  //#endregion
2649
2649
  //#region src/client/components/AnalysisBuilder/AnalysisChartConfigPanel.tsx
2650
2650
  var ke = e("measure"), Ae = e("dimension"), je = e("timeDimension");
2651
- function Me({ chartType: e, chartConfig: t, metrics: n, breakdowns: i, schema: a, chartAvailability: s, onChartTypeChange: c, onChartConfigChange: l }) {
2651
+ function Me({ chartType: e, chartConfig: t, metrics: r, breakdowns: i, schema: a, chartAvailability: s, onChartTypeChange: c, onChartConfigChange: l }) {
2652
2652
  let [u, d] = B(null), f = R(() => ({
2653
- measures: n.map((e) => e.field),
2653
+ measures: r.map((e) => e.field),
2654
2654
  dimensions: i.filter((e) => !e.isTimeDimension).map((e) => e.field),
2655
2655
  timeDimensions: i.filter((e) => e.isTimeDimension).map((e) => e.field)
2656
- }), [n, i]), { config: p, loaded: m } = o(e), h = p.skipQuery === !0, g = I((e) => {
2656
+ }), [r, i]), { config: p, loaded: m } = o(e), h = p.skipQuery === !0, g = I((e) => {
2657
2657
  let n = t[e];
2658
2658
  return Array.isArray(n) ? n : typeof n == "string" ? [n] : [];
2659
2659
  }, [t]);
@@ -2851,12 +2851,12 @@ function Me({ chartType: e, chartConfig: t, metrics: n, breakdowns: i, schema: a
2851
2851
  className: "dc:space-y-2",
2852
2852
  children: [
2853
2853
  D.measures.map((e) => {
2854
- let t = y(e), n = u && u.field === e && u.fromAxis === "available", i = r(t.measureType || "count") || ke;
2854
+ let t = y(e), r = u && u.field === e && u.fromAxis === "available", i = n(t.measureType || "count") || ke;
2855
2855
  return /* @__PURE__ */ U("div", {
2856
2856
  draggable: !0,
2857
2857
  onDragStart: (t) => b(t, e, "available"),
2858
2858
  onDragEnd: S,
2859
- className: `dc:flex dc:items-center dc:gap-2 dc:p-2 bg-dc-surface dc:rounded-lg hover:bg-dc-surface-tertiary dc:transition-colors dc:cursor-move ${n ? "dc:opacity-50 dc:cursor-grabbing" : ""}`,
2859
+ className: `dc:flex dc:items-center dc:gap-2 dc:p-2 bg-dc-surface dc:rounded-lg hover:bg-dc-surface-tertiary dc:transition-colors dc:cursor-move ${r ? "dc:opacity-50 dc:cursor-grabbing" : ""}`,
2860
2860
  title: e,
2861
2861
  children: [/* @__PURE__ */ H("span", {
2862
2862
  className: "dc:w-6 dc:h-6 dc:flex dc:items-center dc:justify-center dc:rounded bg-dc-measure text-dc-measure-text dc:flex-shrink-0",
@@ -4978,8 +4978,8 @@ var Jt = e("warning"), Yt = e("refresh"), Xt = class extends re {
4978
4978
  ]
4979
4979
  }) : this.props.children;
4980
4980
  }
4981
- }, Zt = ie(({ className: e = "", maxHeight: t, initialData: n, colorPalette: r, hideSettings: i = !1, hideShare: o = !1, onQueryChange: s, onChartConfigChange: c }, l) => {
4982
- let { meta: u } = f(), { features: d } = a(), p = te({
4981
+ }, Zt = ie(({ className: e = "", maxHeight: t, initialData: n, colorPalette: r, hideSettings: a = !1, hideShare: o = !1, onQueryChange: s, onChartConfigChange: c }, l) => {
4982
+ let { meta: u } = f(), { features: d } = i(), p = te({
4983
4983
  initialData: n,
4984
4984
  externalColorPalette: r,
4985
4985
  onQueryChange: s,
@@ -5362,4 +5362,4 @@ Qt.displayName = "AnalysisBuilder";
5362
5362
  //#endregion
5363
5363
  export { Qt as default };
5364
5364
 
5365
- //# sourceMappingURL=analysis-builder-B7XSIMkr.js.map
5365
+ //# sourceMappingURL=analysis-builder-C1CJ0c7L.js.map