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.
- package/README.md +1 -1
- package/dist/adapters/express/index.cjs +1 -1
- package/dist/adapters/express/index.js +2 -2
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/fastify/index.js +2 -2
- package/dist/adapters/{handler-dHHEEbG9.cjs → handler-BneUGY0k.cjs} +1 -1
- package/dist/adapters/{handler-fto6TSVn.js → handler-CiQoQsnP.js} +1 -1
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/hono/index.js +5 -5
- package/dist/adapters/{mcp-transport-tB5a7Het.js → mcp-transport-CC3hQOnb.js} +1099 -1338
- package/dist/adapters/mcp-transport-mmuPvjfR.cjs +255 -0
- package/dist/adapters/nextjs/index.cjs +1 -1
- package/dist/adapters/nextjs/index.js +2 -2
- package/dist/adapters/{openai-Ckpe7iU7.js → openai-CQfaz257.js} +1 -1
- package/dist/{server/openai-DKpZPCay.cjs → adapters/openai-CZ74gWd4.cjs} +1 -1
- package/dist/adapters/{openai-Bc8qwEKW.cjs → openai-DLfardui.cjs} +1 -1
- package/dist/adapters/{openai-DxeVtl8X.js → openai-DaxuhJLS.js} +1 -1
- package/dist/client/charts.js +12 -12
- package/dist/client/chunks/{DashboardEditModal-4zzjtZRR.js → DashboardEditModal-BTdV528l.js} +1421 -1396
- package/dist/client/chunks/DashboardEditModal-BTdV528l.js.map +1 -0
- package/dist/client/chunks/{FieldSearchModal-trURu9Sa.js → FieldSearchModal-D75vy4Wb.js} +4 -4
- package/dist/client/chunks/{FieldSearchModal-trURu9Sa.js.map → FieldSearchModal-D75vy4Wb.js.map} +1 -1
- package/dist/client/chunks/KpiDelta-Bk8bzKYM.js +2 -0
- package/dist/client/chunks/KpiNumber-CKF-8e_T.js +2 -0
- package/dist/client/chunks/KpiText-Iz1vIvu_.js +2 -0
- package/dist/client/chunks/{RetentionCombinedChart-B1hUYaXt.js → RetentionCombinedChart-DIhK5pD8.js} +3 -3
- package/dist/client/chunks/{RetentionCombinedChart-B1hUYaXt.js.map → RetentionCombinedChart-DIhK5pD8.js.map} +1 -1
- package/dist/client/chunks/{RetentionHeatmap-Dn2ocjVf.js → RetentionHeatmap-CyREolyP.js} +1 -1
- package/dist/client/chunks/{RetentionHeatmap-Dn2ocjVf.js.map → RetentionHeatmap-CyREolyP.js.map} +1 -1
- package/dist/client/chunks/SchemaVisualization-B1GUT-FM.js +2 -0
- package/dist/client/chunks/SchemaVisualizationLazy-DymwT34e.js +2 -0
- package/dist/client/chunks/{analysis-builder-B7XSIMkr.js → analysis-builder-C1CJ0c7L.js} +52 -52
- package/dist/client/chunks/{analysis-builder-B7XSIMkr.js.map → analysis-builder-C1CJ0c7L.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-shared-DaqtrLxd.js → analysis-builder-shared-rkjJfWLT.js} +9 -9
- package/dist/client/chunks/{analysis-builder-shared-DaqtrLxd.js.map → analysis-builder-shared-rkjJfWLT.js.map} +1 -1
- package/dist/client/chunks/{chart-activity-grid-wR2Twpo7.js → chart-activity-grid-DLktOINm.js} +2 -2
- package/dist/client/chunks/{chart-activity-grid-wR2Twpo7.js.map → chart-activity-grid-DLktOINm.js.map} +1 -1
- package/dist/client/chunks/{chart-area-e9ysnatQ.js → chart-area-BwYaflNk.js} +3 -3
- package/dist/client/chunks/{chart-area-e9ysnatQ.js.map → chart-area-BwYaflNk.js.map} +1 -1
- package/dist/client/chunks/{chart-bar-CPt67rLR.js → chart-bar-BiENfFgE.js} +4 -4
- package/dist/client/chunks/{chart-bar-CPt67rLR.js.map → chart-bar-BiENfFgE.js.map} +1 -1
- package/dist/client/chunks/{chart-box-plot-Dp_nqQen.js → chart-box-plot-BJF1tBXC.js} +3 -3
- package/dist/client/chunks/{chart-box-plot-Dp_nqQen.js.map → chart-box-plot-BJF1tBXC.js.map} +1 -1
- package/dist/client/chunks/{chart-bubble-CYQ8loeS.js → chart-bubble-DQQhGVDJ.js} +3 -3
- package/dist/client/chunks/{chart-bubble-CYQ8loeS.js.map → chart-bubble-DQQhGVDJ.js.map} +1 -1
- package/dist/client/chunks/{chart-candlestick-DTeSf7C5.js → chart-candlestick-C2UuXbLe.js} +3 -3
- package/dist/client/chunks/{chart-candlestick-DTeSf7C5.js.map → chart-candlestick-C2UuXbLe.js.map} +1 -1
- package/dist/client/chunks/{chart-config-activity-grid-BSWS08cI.js → chart-config-activity-grid-DJOU3TEz.js} +2 -2
- package/dist/client/chunks/{chart-config-activity-grid-BSWS08cI.js.map → chart-config-activity-grid-DJOU3TEz.js.map} +1 -1
- package/dist/client/chunks/{chart-config-area-DKwgcHp4.js → chart-config-area-CWnWVT6a.js} +2 -2
- package/dist/client/chunks/{chart-config-area-DKwgcHp4.js.map → chart-config-area-CWnWVT6a.js.map} +1 -1
- package/dist/client/chunks/{chart-config-bar-deTjEhap.js → chart-config-bar-C-7Dr1Ho.js} +2 -2
- package/dist/client/chunks/{chart-config-bar-deTjEhap.js.map → chart-config-bar-C-7Dr1Ho.js.map} +1 -1
- package/dist/client/chunks/{chart-config-box-plot-DU4iWk3V.js → chart-config-box-plot-mVOwmLdu.js} +2 -2
- package/dist/client/chunks/{chart-config-box-plot-DU4iWk3V.js.map → chart-config-box-plot-mVOwmLdu.js.map} +1 -1
- package/dist/client/chunks/{chart-config-bubble-B8FSHSW-.js → chart-config-bubble-BPE2CeiD.js} +2 -2
- package/dist/client/chunks/{chart-config-bubble-B8FSHSW-.js.map → chart-config-bubble-BPE2CeiD.js.map} +1 -1
- package/dist/client/chunks/{chart-config-candlestick-BGfyWFft.js → chart-config-candlestick-BSB9DRy2.js} +2 -2
- package/dist/client/chunks/{chart-config-candlestick-BGfyWFft.js.map → chart-config-candlestick-BSB9DRy2.js.map} +1 -1
- package/dist/client/chunks/{chart-config-data-table-DKRcGa8t.js → chart-config-data-table-Bhdx5Hem.js} +2 -2
- package/dist/client/chunks/{chart-config-data-table-DKRcGa8t.js.map → chart-config-data-table-Bhdx5Hem.js.map} +1 -1
- package/dist/client/chunks/{chart-config-funnel-Bt4iGFo_.js → chart-config-funnel-Cl-v-bm1.js} +2 -2
- package/dist/client/chunks/{chart-config-funnel-Bt4iGFo_.js.map → chart-config-funnel-Cl-v-bm1.js.map} +1 -1
- package/dist/client/chunks/{chart-config-gauge-Bk4Jjp3W.js → chart-config-gauge-CdrUTJMJ.js} +2 -2
- package/dist/client/chunks/{chart-config-gauge-Bk4Jjp3W.js.map → chart-config-gauge-CdrUTJMJ.js.map} +1 -1
- package/dist/client/chunks/{chart-config-heat-map-CkHsqkrY.js → chart-config-heat-map-DGE3NzoF.js} +2 -2
- package/dist/client/chunks/{chart-config-heat-map-CkHsqkrY.js.map → chart-config-heat-map-DGE3NzoF.js.map} +1 -1
- package/dist/client/chunks/{chart-config-kpi-delta-CkUX98JV.js → chart-config-kpi-delta-DMrQerUW.js} +2 -2
- package/dist/client/chunks/{chart-config-kpi-delta-CkUX98JV.js.map → chart-config-kpi-delta-DMrQerUW.js.map} +1 -1
- package/dist/client/chunks/{chart-config-kpi-number-DcxyiUgs.js → chart-config-kpi-number-DCytCytn.js} +2 -2
- package/dist/client/chunks/{chart-config-kpi-number-DcxyiUgs.js.map → chart-config-kpi-number-DCytCytn.js.map} +1 -1
- package/dist/client/chunks/{chart-config-kpi-text-DI4mj8CN.js → chart-config-kpi-text-KdKQUvHo.js} +2 -2
- package/dist/client/chunks/{chart-config-kpi-text-DI4mj8CN.js.map → chart-config-kpi-text-KdKQUvHo.js.map} +1 -1
- package/dist/client/chunks/{chart-config-line--j7-dLue.js → chart-config-line-Bl9VDAdz.js} +2 -2
- package/dist/client/chunks/{chart-config-line--j7-dLue.js.map → chart-config-line-Bl9VDAdz.js.map} +1 -1
- package/dist/client/chunks/{chart-config-markdown-DUjvVjV4.js → chart-config-markdown-BX26b94i.js} +2 -2
- package/dist/client/chunks/{chart-config-markdown-DUjvVjV4.js.map → chart-config-markdown-BX26b94i.js.map} +1 -1
- package/dist/client/chunks/{chart-config-measure-profile-B9FKBNGc.js → chart-config-measure-profile-DwtRhEFh.js} +2 -2
- package/dist/client/chunks/{chart-config-measure-profile-B9FKBNGc.js.map → chart-config-measure-profile-DwtRhEFh.js.map} +1 -1
- package/dist/client/chunks/{chart-config-pie-yU4jipl9.js → chart-config-pie-BzBcqPMJ.js} +2 -2
- package/dist/client/chunks/{chart-config-pie-yU4jipl9.js.map → chart-config-pie-BzBcqPMJ.js.map} +1 -1
- package/dist/client/chunks/{chart-config-radar-R9Fkc8wL.js → chart-config-radar-6ZOgt__z.js} +2 -2
- package/dist/client/chunks/{chart-config-radar-R9Fkc8wL.js.map → chart-config-radar-6ZOgt__z.js.map} +1 -1
- package/dist/client/chunks/{chart-config-radial-bar-DeoXfpIp.js → chart-config-radial-bar-Df6Eta7N.js} +2 -2
- package/dist/client/chunks/{chart-config-radial-bar-DeoXfpIp.js.map → chart-config-radial-bar-Df6Eta7N.js.map} +1 -1
- package/dist/client/chunks/{chart-config-sankey-CXEsxo6s.js → chart-config-sankey-DgqKBFvN.js} +2 -2
- package/dist/client/chunks/{chart-config-sankey-CXEsxo6s.js.map → chart-config-sankey-DgqKBFvN.js.map} +1 -1
- package/dist/client/chunks/{chart-config-scatter-MVUFupub.js → chart-config-scatter-D5nVLDvi.js} +2 -2
- package/dist/client/chunks/{chart-config-scatter-MVUFupub.js.map → chart-config-scatter-D5nVLDvi.js.map} +1 -1
- package/dist/client/chunks/{chart-config-sunburst-Z_gqIY5u.js → chart-config-sunburst-Ca3FX9nW.js} +2 -2
- package/dist/client/chunks/{chart-config-sunburst-Z_gqIY5u.js.map → chart-config-sunburst-Ca3FX9nW.js.map} +1 -1
- package/dist/client/chunks/{chart-config-tree-map-BD-xAeIy.js → chart-config-tree-map-Bjy4QNa3.js} +2 -2
- package/dist/client/chunks/{chart-config-tree-map-BD-xAeIy.js.map → chart-config-tree-map-Bjy4QNa3.js.map} +1 -1
- package/dist/client/chunks/{chart-config-waterfall-CHwVkXZc.js → chart-config-waterfall-C5K2eqR7.js} +2 -2
- package/dist/client/chunks/{chart-config-waterfall-CHwVkXZc.js.map → chart-config-waterfall-C5K2eqR7.js.map} +1 -1
- package/dist/client/chunks/{chart-data-table-BZ7StNWv.js → chart-data-table-2iCsn0CF.js} +1099 -933
- package/dist/client/chunks/chart-data-table-2iCsn0CF.js.map +1 -0
- package/dist/client/chunks/{chart-funnel-C9JRW79j.js → chart-funnel-poyOf7-e.js} +3 -3
- package/dist/client/chunks/{chart-funnel-C9JRW79j.js.map → chart-funnel-poyOf7-e.js.map} +1 -1
- package/dist/client/chunks/{chart-gauge-_Xdgk_qI.js → chart-gauge-D5J4gRky.js} +3 -3
- package/dist/client/chunks/{chart-gauge-_Xdgk_qI.js.map → chart-gauge-D5J4gRky.js.map} +1 -1
- package/dist/client/chunks/{chart-heat-map-BOMQeUDL.js → chart-heat-map-BAMVhLGG.js} +3 -3
- package/dist/client/chunks/{chart-heat-map-BOMQeUDL.js.map → chart-heat-map-BAMVhLGG.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-delta-C2tdpWki.js → chart-kpi-delta-KQjUIeal.js} +71 -73
- package/dist/client/chunks/{chart-kpi-delta-C2tdpWki.js.map → chart-kpi-delta-KQjUIeal.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-number-BUNKM7yg.js → chart-kpi-number-CsQgV_x3.js} +62 -63
- package/dist/client/chunks/{chart-kpi-number-BUNKM7yg.js.map → chart-kpi-number-CsQgV_x3.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-text-COF8iN0K.js → chart-kpi-text-BR0IyeUU.js} +26 -27
- package/dist/client/chunks/{chart-kpi-text-COF8iN0K.js.map → chart-kpi-text-BR0IyeUU.js.map} +1 -1
- package/dist/client/chunks/{chart-line-D3SEwXDS.js → chart-line-B5_WntY5.js} +4 -4
- package/dist/client/chunks/{chart-line-D3SEwXDS.js.map → chart-line-B5_WntY5.js.map} +1 -1
- package/dist/client/chunks/{chart-markdown-DMekYkKz.js → chart-markdown-B6bENbel.js} +2 -2
- package/dist/client/chunks/{chart-markdown-DMekYkKz.js.map → chart-markdown-B6bENbel.js.map} +1 -1
- package/dist/client/chunks/{chart-measure-profile-BPhI1Z9s.js → chart-measure-profile-yWk-obNb.js} +4 -4
- package/dist/client/chunks/{chart-measure-profile-BPhI1Z9s.js.map → chart-measure-profile-yWk-obNb.js.map} +1 -1
- package/dist/client/chunks/{chart-pie-COl3Rmdk.js → chart-pie-BodrUoHv.js} +4 -4
- package/dist/client/chunks/{chart-pie-COl3Rmdk.js.map → chart-pie-BodrUoHv.js.map} +1 -1
- package/dist/client/chunks/{chart-radar-BKZXylBB.js → chart-radar-gG3zfLud.js} +4 -4
- package/dist/client/chunks/{chart-radar-BKZXylBB.js.map → chart-radar-gG3zfLud.js.map} +1 -1
- package/dist/client/chunks/{chart-radial-bar-CMfC7SPd.js → chart-radial-bar-C2IPCV8c.js} +4 -4
- package/dist/client/chunks/{chart-radial-bar-CMfC7SPd.js.map → chart-radial-bar-C2IPCV8c.js.map} +1 -1
- package/dist/client/chunks/{chart-sankey-8nRYnupt.js → chart-sankey-BOyxfG1Q.js} +3 -3
- package/dist/client/chunks/{chart-sankey-8nRYnupt.js.map → chart-sankey-BOyxfG1Q.js.map} +1 -1
- package/dist/client/chunks/{chart-scatter-xQMa3dUt.js → chart-scatter-B8OwlsAX.js} +4 -4
- package/dist/client/chunks/{chart-scatter-xQMa3dUt.js.map → chart-scatter-B8OwlsAX.js.map} +1 -1
- package/dist/client/chunks/{chart-sunburst-BGhJ4fui.js → chart-sunburst-D9lGEOCc.js} +4 -4
- package/dist/client/chunks/{chart-sunburst-BGhJ4fui.js.map → chart-sunburst-D9lGEOCc.js.map} +1 -1
- package/dist/client/chunks/{chart-tree-map-Cn1pmrAw.js → chart-tree-map-DZaKy9he.js} +4 -4
- package/dist/client/chunks/{chart-tree-map-Cn1pmrAw.js.map → chart-tree-map-DZaKy9he.js.map} +1 -1
- package/dist/client/chunks/{chart-waterfall-C2nVN4pn.js → chart-waterfall-BCdUx4DC.js} +4 -4
- package/dist/client/chunks/{chart-waterfall-C2nVN4pn.js.map → chart-waterfall-BCdUx4DC.js.map} +1 -1
- package/dist/client/chunks/{charts-core-Cy3rHADX.js → charts-core-C5Yokk-x.js} +2 -2
- package/dist/client/chunks/{charts-core-Cy3rHADX.js.map → charts-core-C5Yokk-x.js.map} +1 -1
- package/dist/client/chunks/{core-BdWfCZ3y.js → core-DcfMGTVa.js} +2 -2
- package/dist/client/chunks/{core-BdWfCZ3y.js.map → core-DcfMGTVa.js.map} +1 -1
- package/dist/client/chunks/{dist-BWPE2m_X.js → dist-eZurnOde.js} +1 -1
- package/dist/client/chunks/{dist-BWPE2m_X.js.map → dist-eZurnOde.js.map} +1 -1
- package/dist/client/chunks/exceljs.min-CcjgM-qg.js +31986 -0
- package/dist/client/chunks/exceljs.min-CcjgM-qg.js.map +1 -0
- package/dist/client/chunks/{javascript-O1RIRkZr.js → javascript-DFvvCuoP.js} +1 -1
- package/dist/client/chunks/{javascript-O1RIRkZr.js.map → javascript-DFvvCuoP.js.map} +1 -1
- package/dist/client/chunks/{json-C5bX2tt1.js → json-BBm9TlrA.js} +1 -1
- package/dist/client/chunks/{json-C5bX2tt1.js.map → json-BBm9TlrA.js.map} +1 -1
- package/dist/client/chunks/{rolldown-runtime-lc2dmIiU.js → rolldown-runtime-CCl2IeXn.js} +5 -2
- package/dist/client/chunks/{schema-visualization-DVdfx6N8.js → schema-visualization-t1KiOORo.js} +261 -265
- package/dist/client/chunks/{schema-visualization-DVdfx6N8.js.map → schema-visualization-t1KiOORo.js.map} +1 -1
- package/dist/client/chunks/{sql-D2qikO5q.js → sql-k0GA6oZ_.js} +1 -1
- package/dist/client/chunks/{sql-D2qikO5q.js.map → sql-k0GA6oZ_.js.map} +1 -1
- package/dist/client/chunks/{syntaxHighlighting-BYYWYmjr.js → syntaxHighlighting-CnDujqwg.js} +2 -2
- package/dist/client/chunks/{syntaxHighlighting-BYYWYmjr.js.map → syntaxHighlighting-CnDujqwg.js.map} +1 -1
- package/dist/client/chunks/{useDebounce-Bel8J05v.js → useDebounce-CKqkM42n.js} +11 -14
- package/dist/client/chunks/{useDebounce-Bel8J05v.js.map → useDebounce-CKqkM42n.js.map} +1 -1
- package/dist/client/chunks/{useExplainAI-CxdzY2N0.js → useExplainAI-DBIfYwz-.js} +12 -12
- package/dist/client/chunks/{useExplainAI-CxdzY2N0.js.map → useExplainAI-DBIfYwz-.js.map} +1 -1
- package/dist/client/chunks/{utils-CMkS7h9x.js → utils--qCr8Yn5.js} +2 -2
- package/dist/client/chunks/utils--qCr8Yn5.js.map +1 -0
- package/dist/client/chunks/{vendor-BoWEubRu.js → vendor-BRlsCGnK.js} +46 -46
- package/dist/client/chunks/{vendor-BoWEubRu.js.map → vendor-BRlsCGnK.js.map} +1 -1
- package/dist/client/components.js +3 -3
- package/dist/client/hooks.js +3 -3
- package/dist/client/icons/types.d.ts +1 -0
- package/dist/client/icons.js +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +168 -168
- package/dist/client/index.js.map +1 -1
- package/dist/client/providers.js +1 -1
- package/dist/client/schema.js +1 -1
- package/dist/client/types.d.ts +6 -0
- package/dist/client/utils/exportXlsx.d.ts +20 -0
- package/dist/client/utils/index.d.ts +1 -0
- package/dist/client/utils.js +7 -7
- package/dist/client-bundle-stats.html +1 -1
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/{openai-DqCEogm0.js → openai-CqZg6zYL.js} +1 -1
- package/dist/server/{openai-0HbLlZq6.cjs → openai-D9Zjuby1.cjs} +1 -1
- package/dist/{adapters/openai-C96O8M75.cjs → server/openai-DmuEbFd6.cjs} +1 -1
- package/dist/server/{openai-DnGeU9PT.js → openai-rwauPzCT.js} +1 -1
- package/package.json +6 -1
- package/dist/adapters/mcp-transport-ro4OL4BW.cjs +0 -255
- package/dist/client/chunks/DashboardEditModal-4zzjtZRR.js.map +0 -1
- package/dist/client/chunks/chart-data-table-BZ7StNWv.js.map +0 -1
- package/dist/client/chunks/utils-CMkS7h9x.js.map +0 -1
package/dist/client/chunks/{RetentionCombinedChart-B1hUYaXt.js → RetentionCombinedChart-DIhK5pD8.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as e, n as t } from "./chart-activity-grid-
|
|
2
|
-
import { c as n, l as r } from "./chart-area-
|
|
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-
|
|
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"}
|
package/dist/client/chunks/{RetentionHeatmap-Dn2ocjVf.js.map → RetentionHeatmap-CyREolyP.js.map}
RENAMED
|
@@ -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":";;;;AAuBA,SAAS,EAAkB,GAAsB;AAS/C,QAAO,qBAHO,KAJM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,EAAK,CAAC,GAIhB,GAGA;;AAMpC,SAAS,EAAa,GAAsB;AAE1C,QAAO,IAAO,KAAM,YAAY;;AAOlC,SAAS,EAAmB,GAAwB;AAElD,KAAI,gBAAgB,KAAK,EAAO,CAC9B,QAAO;CAIT,IAAM,IAAO,IAAI,KAAK,EAAO;AAK7B,QAJK,MAAM,EAAK,SAAS,CAAC,GAInB,IAHE,EAAK,mBAAmB,SAAS;EAAE,MAAM;EAAW,OAAO;EAAS,CAAC;;AAShF,SAAS,EAAiB,GAAsB;AAC9C,QAAO,GAAG,KAAK,MAAM,IAAO,IAAI,CAAC;;AAgBnC,IAAM,IAAmB,EAAM,KAAK,SAA0B,EAC5D,SACA,YAAS,QACT,oBACa;CACb,IAAM,CAAC,GAAS,KAAc,EAA6B,KAAK,EAG1D,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,IAAkB,CAAC,GAAG,IAAI,IAAI,EAAK,KAAI,MAAK,EAAE,kBAAkB,YAAY,CAAC,CAAC,CAAC,MAAM,EACrF,IAAU,CAAC,GAAG,IAAI,IAAI,EAAK,KAAI,MAAK,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE;AAE3E,UAAO;IACL;IACA,iBAAiB,EAAgB,SAAS,KAAK,EAAgB,OAAO,cAAc,IAAkB,KAAA;IACtG;IACD;;AAGH,SAAO;IACN,CAAC,EAAK,CAAC,EAIJ,IAAS,QAAc;AAC3B,MAAI,CAAC,EAAe,QAAO;EAE3B,IAAM,EAAE,SAAM,oBAAiB,eAAY,GAGrC,IAAW,KAAmB,CAAC,YAAY,EAG3C,oBAAS,IAAI,KAAiC;AACpD,OAAK,IAAM,KAAO,EAEhB,GAAO,IAAI,GADK,EAAI,kBAAkB,YAChB,GAAG,EAAI,UAAU,EAAI;AAI7C,SAAO,EAAS,KAAK,MAAoB;GACvC,IAAM,IAAc,EAAQ,KAAI,MAClB,EAAO,IAAI,GAAG,EAAQ,GAAG,IAAS,IAChC,KACd;AAMF,UAAO;IACL,QAAQ;IACR,YALc,EAAY,IACA,cAAc;IAKxC,SAAS;IACV;IACD;IACD,CAAC,EAAc,CAAC,EAGb,KACJ,GACA,GACA,GACA,MACG;AACH,MAAI,CAAC,EAAK;EAEV,IAAM,IAAO,EAAM,cAAc,uBAAuB;AACxD,IAAW;GACT;GACA;GACA,YAAY,EAAI;GAChB,eAAe,EAAI;GACnB,eAAe,EAAI;GACnB,GAAG,EAAK,OAAO,EAAK,QAAQ;GAC5B,GAAG,EAAK;GACT,CAAC;IAGE,UAAyB;AAC7B,IAAW,KAAK;;AAIlB,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,KAAU,EAAO,WAAW,EAC/B,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;IAE7C,CAAA,CACF;;EACF,CAAA;CAIV,IAAM,IAAU,GAAe,WAAW,EAAE,EACtC,IAAa,GAAe,cAAc;AAEhD,QACE,kBAAC,OAAD;EAAK,WAAU;EAAmD,OAAO,EAAE,WAAQ;YAAnF;GAEE,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD;KAAO,WAAU;eACf,kBAAC,MAAD,EAAA,UAAA;MACE,kBAAC,MAAD;OAAI,WAAU;iBAAgG;OAEzG,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBAAgG;OAEzG,CAAA;MACJ,EAAQ,KAAI,MACX,kBAAC,MAAD;OAEE,WAAU;iBAFZ,CAGC,KACG,EACC;SAJE,EAIF,CACL;MACC,EAAA,CAAA;KACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAO,KAAK,GAAK,MAChB,kBAAC,MAAD;KAAqB,WAAW,IAAW,KAAM,IAAI,aAAa;eAAlE;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAmB,EAAI,OAAO;OAC5B,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAI,WAAW,gBAAgB;OAC7B,CAAA;MACJ,EAAI,QAAQ,KAAK,GAAM,MAAgB;OACtC,IAAM,IAAS,EAAQ,IACjB,IAAO,GAAM,iBAAiB;AAIpC,cACE,kBAAC,MAAD;QAEE,WAAU;QACV,OAAO;SAAE,iBAPG,IAAO,EAAkB,EAAK,GAAG;SAOV,OANrB,IAAO,EAAa,EAAK,GAAG;SAMW;QACrD,eAAe,MAAM,EAAiB,GAAG,EAAI,QAAQ,GAAQ,EAAK;QAClE,cAAc;kBAEb,IAAO,EAAiB,EAAK,GAAG;QAC9B,EAPE,EAOF;QAEP;MACC;OAzBI,EAAI,OAyBR,CACL,EACI,CAAA,CACF;;GAGP,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD,EAAA,UAAM,MAAS,CAAA;KACf,kBAAC,OAAD;MAAK,WAAU;gBACZ;OAAC;OAAG;OAAK;OAAK;OAAK;OAAK;OAAE,CAAC,KAAI,MAC9B,kBAAC,OAAD;OAEE,WAAU;OACV,OAAO,EAAE,iBAAiB,EAAkB,EAAK,EAAE;OACnD,EAHK,EAGL,CACF;MACE,CAAA;KACN,kBAAC,QAAD,EAAA,UAAM,QAAW,CAAA;KACb;;GAIP,KACC,kBAAC,OAAD;IACE,WAAU;IACV,OAAO;KACL,MAAM,EAAQ;KACd,KAAK,EAAQ,IAAI;KACjB,WAAW;KACZ;cANH,CAQE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,EAAmB,EAAQ,OAAO;MAAC;MAAW,EAAQ;MACnD;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD,EAAA,UAAA,CAAK,iBAAc,EAAQ,WAAW,gBAAgB,CAAO,EAAA,CAAA;MAC7D,kBAAC,OAAD,EAAA,UAAA,CAAK,cAAW,EAAQ,cAAc,gBAAgB,CAAO,EAAA,CAAA;MAC7D,kBAAC,OAAD;OAAK,WAAU;iBAAf,CAA6C,UACpC,EAAiB,EAAQ,cAAc,CAC1C;;MACF;OACF;;GAEJ;;EAER"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { A as e,
|
|
2
|
-
import { r as u, t as d } from "./useExplainAI-
|
|
3
|
-
import { A as f } from "./chart-activity-grid-
|
|
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-
|
|
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-
|
|
7
|
-
import { n as N } from "./charts-core-
|
|
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:
|
|
376
|
-
let { apiOptions: _ } =
|
|
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:
|
|
400
|
-
chartConfig: { ...
|
|
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
|
-
|
|
411
|
-
|
|
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)),
|
|
440
|
-
if (ue(
|
|
441
|
-
p("funnel"), m(
|
|
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 =
|
|
449
|
-
|
|
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 && (
|
|
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
|
-
|
|
487
|
-
|
|
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 && (
|
|
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
|
-
})),
|
|
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
|
-
|
|
525
|
-
|
|
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("./
|
|
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:
|
|
604
|
-
let q = le === "funnel" || ue, J = le === "flow", Y = le === "retention", { features: Ce } =
|
|
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
|
-
|
|
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:
|
|
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
|
|
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 = () =>
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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" }), (
|
|
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:
|
|
1860
|
-
let f = e("close"), p = e("chevronUp"), m = e("chevronDown"), h = e("chevronUpDown"), g = r
|
|
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:
|
|
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(
|
|
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 ?
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 && (
|
|
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:
|
|
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:
|
|
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
|
-
}), [
|
|
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),
|
|
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 ${
|
|
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:
|
|
4982
|
-
let { meta: u } = f(), { features: d } =
|
|
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-
|
|
5365
|
+
//# sourceMappingURL=analysis-builder-C1CJ0c7L.js.map
|