drizzle-cube 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/express/index.cjs +1 -1
- package/dist/adapters/{adapters/express → express}/index.d.ts +3 -3
- package/dist/adapters/express/index.js +1 -1
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/{adapters/fastify → fastify}/index.d.ts +3 -3
- package/dist/adapters/fastify/index.js +1 -1
- package/dist/adapters/{adapters/hono → hono}/agent-handler.d.ts +3 -3
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/{adapters/hono → hono}/index.d.ts +4 -4
- package/dist/adapters/hono/index.js +1 -1
- package/dist/adapters/{adapters/hono → hono}/mcp-handler.d.ts +2 -2
- package/dist/adapters/{adapters/locale.d.ts → locale.d.ts} +1 -1
- package/dist/adapters/{adapters/mcp-tools-handlers.d.ts → mcp-tools-handlers.d.ts} +2 -2
- package/dist/adapters/mcp-tools.cjs +1 -1
- package/dist/adapters/{adapters/mcp-tools.d.ts → mcp-tools.d.ts} +5 -5
- package/dist/adapters/mcp-tools.js +1 -1
- package/dist/adapters/mcp-transport-B7ddET3M.cjs +40 -0
- package/dist/adapters/mcp-transport-Dfuj4j4q.js +591 -0
- package/dist/adapters/{adapters/mcp-transport.d.ts → mcp-transport.d.ts} +3 -3
- package/dist/adapters/nextjs/index.cjs +1 -1
- package/dist/adapters/{adapters/nextjs → nextjs}/index.d.ts +3 -3
- package/dist/adapters/nextjs/index.js +1 -1
- package/dist/adapters/{adapters/nextjs → nextjs}/mcp-handler.d.ts +2 -2
- package/dist/adapters/{adapters/types.d.ts → types.d.ts} +1 -1
- package/dist/adapters/{adapters/utils.d.ts → utils.d.ts} +16 -16
- package/dist/cli/index.cjs +2 -2
- package/dist/client/adapters/adapterRegistry.d.ts +2 -2
- package/dist/client/adapters/flowModeAdapter.d.ts +2 -2
- package/dist/client/adapters/funnelModeAdapter.d.ts +2 -2
- package/dist/client/adapters/index.d.ts +9 -9
- package/dist/client/adapters/modeAdapter.d.ts +1 -1
- package/dist/client/adapters/queryModeAdapter.d.ts +3 -3
- package/dist/client/adapters/retentionModeAdapter.d.ts +2 -2
- package/dist/client/charts/ChartLoader.d.ts +2 -2
- package/dist/client/charts/chartComponentRegistry.d.ts +1 -1
- package/dist/client/charts/chartConfigHelpers.d.ts +1 -1
- package/dist/client/charts/chartConfigRegistry.d.ts +1 -1
- package/dist/client/charts/chartPlugin.d.ts +3 -3
- package/dist/client/charts/lazyChartConfigRegistry.d.ts +2 -2
- package/dist/client/charts.d.ts +8 -8
- package/dist/client/chunks/DashboardEditModal-okVfH8ZK.js.map +1 -1
- package/dist/client/chunks/RetentionCombinedChart-BgbDhsPz.js.map +1 -1
- package/dist/client/chunks/RetentionHeatmap-DjXZaTPq.js.map +1 -1
- package/dist/client/chunks/analysis-builder-DB88FojM.js.map +1 -1
- package/dist/client/chunks/analysis-builder-shared-BVK4TYfR.js.map +1 -1
- package/dist/client/chunks/chart-activity-grid-DX0SJbxs.js.map +1 -1
- package/dist/client/chunks/chart-area-of01_62R.js.map +1 -1
- package/dist/client/chunks/chart-bar-BqelQE_I.js.map +1 -1
- package/dist/client/chunks/chart-box-plot-kkBixZ27.js.map +1 -1
- package/dist/client/chunks/chart-bubble-B2he1--4.js.map +1 -1
- package/dist/client/chunks/chart-candlestick-DZp19Tzh.js.map +1 -1
- package/dist/client/chunks/chart-config-activity-grid-D_UX4NHC.js.map +1 -1
- package/dist/client/chunks/chart-config-area-BNigHUy8.js.map +1 -1
- package/dist/client/chunks/chart-config-bar-DSO_LRTx.js.map +1 -1
- package/dist/client/chunks/chart-config-box-plot-oW8axV2q.js.map +1 -1
- package/dist/client/chunks/chart-config-bubble-gIoqVyjZ.js.map +1 -1
- package/dist/client/chunks/chart-config-candlestick-N6DchAA3.js.map +1 -1
- package/dist/client/chunks/chart-config-data-table-d7VBY-y_.js.map +1 -1
- package/dist/client/chunks/chart-config-funnel-DEYMcxsD.js.map +1 -1
- package/dist/client/chunks/chart-config-gauge-Dq-_H9UN.js.map +1 -1
- package/dist/client/chunks/chart-config-heat-map-CfRnRNcw.js.map +1 -1
- package/dist/client/chunks/chart-config-kpi-delta-DSQbvqu_.js.map +1 -1
- package/dist/client/chunks/chart-config-kpi-number-EFSWY1We.js.map +1 -1
- package/dist/client/chunks/chart-config-kpi-text-KM3V5X2u.js.map +1 -1
- package/dist/client/chunks/chart-config-line-D6jG8PCH.js.map +1 -1
- package/dist/client/chunks/chart-config-markdown-BtRIe8JN.js.map +1 -1
- package/dist/client/chunks/chart-config-measure-profile-DxRGa-zf.js.map +1 -1
- package/dist/client/chunks/chart-config-pie-BhzW-fdn.js.map +1 -1
- package/dist/client/chunks/chart-config-radar-D7REP1q_.js.map +1 -1
- package/dist/client/chunks/chart-config-radial-bar-Byx6qOPU.js.map +1 -1
- package/dist/client/chunks/chart-config-sankey-BTnWA7EW.js.map +1 -1
- package/dist/client/chunks/chart-config-scatter-DSYTjwRb.js.map +1 -1
- package/dist/client/chunks/chart-config-sunburst-Bwjtdf7X.js.map +1 -1
- package/dist/client/chunks/chart-config-tree-map-DVrvf3yQ.js.map +1 -1
- package/dist/client/chunks/chart-config-waterfall-DmFeQdIk.js.map +1 -1
- package/dist/client/chunks/chart-data-table-CKauQXme.js.map +1 -1
- package/dist/client/chunks/chart-funnel-CToKSBaL.js.map +1 -1
- package/dist/client/chunks/chart-gauge-DTVezSk7.js.map +1 -1
- package/dist/client/chunks/chart-heat-map-DTuUl0BR.js.map +1 -1
- package/dist/client/chunks/chart-kpi-delta-Dn-jjO-2.js.map +1 -1
- package/dist/client/chunks/chart-kpi-number-P_WBiO5S.js.map +1 -1
- package/dist/client/chunks/chart-kpi-text-C-Y4eb5H.js.map +1 -1
- package/dist/client/chunks/chart-line-DKgrQA6c.js.map +1 -1
- package/dist/client/chunks/chart-markdown-CV75S_zL.js.map +1 -1
- package/dist/client/chunks/chart-measure-profile-Ket8fJyf.js.map +1 -1
- package/dist/client/chunks/chart-pie-ByieAX5H.js.map +1 -1
- package/dist/client/chunks/chart-radar-CiSwHWp4.js.map +1 -1
- package/dist/client/chunks/chart-radial-bar-BF6Mhl6f.js.map +1 -1
- package/dist/client/chunks/chart-sankey-DjrvKw6K.js.map +1 -1
- package/dist/client/chunks/chart-scatter-Dd9WFqnS.js.map +1 -1
- package/dist/client/chunks/chart-sunburst-leGpuDj7.js.map +1 -1
- package/dist/client/chunks/chart-tree-map-Ceq5sLZA.js.map +1 -1
- package/dist/client/chunks/chart-waterfall-DyvQReN5.js.map +1 -1
- package/dist/client/chunks/charts-core-DaXSt1Dd.js.map +1 -1
- package/dist/client/chunks/charts-loader-DdTeCeNo.js.map +1 -1
- package/dist/client/chunks/retention-ChW9jYdy.js.map +1 -1
- package/dist/client/chunks/schema-visualization-Cb_E9_Gd.js.map +1 -1
- package/dist/client/chunks/useDirtyStateTracking-MbpxH_v6.js.map +1 -1
- package/dist/client/chunks/useExplainAI-evnZkjCY.js.map +1 -1
- package/dist/client/chunks/utils-3P6z1vz5.js.map +1 -1
- package/dist/client/client/BatchCoordinator.d.ts +1 -1
- package/dist/client/client/CubeClient.d.ts +1 -1
- package/dist/client/components/AIAssistant/index.d.ts +3 -3
- package/dist/client/components/AIAssistant/utils.d.ts +1 -1
- package/dist/client/components/AgenticNotebook/ChatMessage.d.ts +1 -1
- package/dist/client/components/AgenticNotebook/NotebookCanvas.d.ts +1 -1
- package/dist/client/components/AgenticNotebook/NotebookMarkdownBlock.d.ts +1 -1
- package/dist/client/components/AgenticNotebook/NotebookPortletBlock.d.ts +2 -2
- package/dist/client/components/AgenticNotebook/chatMessageParts.d.ts +1 -1
- package/dist/client/components/AgenticNotebook/index.d.ts +2 -2
- package/dist/client/components/AgenticNotebook/useAgentChatController.d.ts +1 -1
- package/dist/client/components/AgenticNotebook/useNotebookAutosave.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisAxisDropZone.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisChartConfigPanel.d.ts +4 -4
- package/dist/client/components/AnalysisBuilder/AnalysisDisplayConfigPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisFilterGroup.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/AnalysisFilterItem.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/AnalysisFilterSection.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/AnalysisModeErrorBoundary.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisQueryPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisQueryPanelParts.d.ts +3 -3
- package/dist/client/components/AnalysisBuilder/AnalysisResultsPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/AnalysisTypeSelector.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/BreakdownItemCard.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/BreakdownRow.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/BreakdownSection.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/DisplayOptionControl.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/ExecutionPlanPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/ExecutionPlanPanelParts.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/ExplainAIPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FieldDetailPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FieldSearchItem.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FieldSearchModal.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FieldSearchResults.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/FilterConfigModal.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/FilterValueInput.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/FlowConfigPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FlowDepthControls.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FlowModeContent.d.ts +3 -3
- package/dist/client/components/AnalysisBuilder/FlowVisualizationPicker.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FunnelBindingKeySelector.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FunnelConfigPanel.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FunnelModeContent.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/FunnelStepCard.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/FunnelStepList.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/LegacyBooleanOptions.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/MetricItemCard.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/MetricRow.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/MetricsSection.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/RetentionConfigPanel.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/RetentionModeContent.d.ts +3 -3
- package/dist/client/components/AnalysisBuilder/filterConfigModalUtils.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/hooks/useAnalysisBuilderImperativeHandle.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/hooks/useFieldSearchKeyboard.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/index.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/types.d.ts +28 -28
- package/dist/client/components/AnalysisBuilder/utils/axisConfigUtils.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/utils/executionPlanMarkdown.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/utils/fieldUtils.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/utils/filterUtils.d.ts +1 -1
- package/dist/client/components/AnalysisBuilder/utils/index.d.ts +6 -6
- package/dist/client/components/AnalysisBuilder/utils/queryUtils.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/utils/recentFieldsUtils.d.ts +2 -2
- package/dist/client/components/AnalysisBuilder/utils/shareStateUtils.d.ts +16 -16
- package/dist/client/components/AnalysisBuilder/utils/storageUtils.d.ts +2 -2
- package/dist/client/components/AnalysisBuilderLazy.d.ts +1 -1
- package/dist/client/components/AnalyticsDashboard.d.ts +1 -1
- package/dist/client/components/AnalyticsPortlet.d.ts +1 -1
- package/dist/client/components/ChartTypeSelector.d.ts +2 -2
- package/dist/client/components/DashboardFilterPanel.d.ts +1 -1
- package/dist/client/components/DashboardFilters/CompactFilterBar.d.ts +1 -1
- package/dist/client/components/DashboardFilters/CompactFilterBarParts.d.ts +1 -1
- package/dist/client/components/DashboardFilters/DashboardFilterConfigModal.d.ts +2 -2
- package/dist/client/components/DashboardFilters/DashboardFilterConfigModalParts.d.ts +2 -2
- package/dist/client/components/DashboardFilters/DashboardFilterItem.d.ts +2 -2
- package/dist/client/components/DashboardFilters/DashboardFilterValueInput.d.ts +2 -2
- package/dist/client/components/DashboardFilters/EditModeFilterList.d.ts +1 -1
- package/dist/client/components/DashboardFilters/FilterChip.d.ts +1 -1
- package/dist/client/components/DashboardFilters/FilterEditModal.d.ts +2 -2
- package/dist/client/components/DashboardFilters/FilterValuePopover.d.ts +1 -1
- package/dist/client/components/DashboardFilters/ReadOnlyFilterList.d.ts +2 -2
- package/dist/client/components/DashboardFilters/dashboardFilterConfigModalUtils.d.ts +2 -2
- package/dist/client/components/DashboardFilters/useCompactFilterBar.d.ts +1 -1
- package/dist/client/components/DashboardFilters/useDashboardFilterConfigModal.d.ts +6 -6
- package/dist/client/components/DashboardFilters/useDateRangeState.d.ts +2 -2
- package/dist/client/components/DashboardFilters/useFilterValueFetch.d.ts +1 -1
- package/dist/client/components/DashboardGrid.d.ts +2 -2
- package/dist/client/components/DashboardPortletCard.d.ts +1 -1
- package/dist/client/components/DebugModal.d.ts +2 -2
- package/dist/client/components/DrillBreadcrumb.d.ts +1 -1
- package/dist/client/components/DrillMenu.d.ts +1 -1
- package/dist/client/components/FloatingEditToolbar.d.ts +1 -1
- package/dist/client/components/MobileStackedLayout.d.ts +2 -2
- package/dist/client/components/PortletAnalysisModal.d.ts +1 -1
- package/dist/client/components/PortletContainer.d.ts +1 -1
- package/dist/client/components/PortletFilterConfigModal.d.ts +1 -1
- package/dist/client/components/RowManagedLayout.d.ts +1 -1
- package/dist/client/components/SchemaVisualization/CubeNode.d.ts +1 -1
- package/dist/client/components/SchemaVisualization/FieldDetailPanel.d.ts +1 -1
- package/dist/client/components/SchemaVisualization/RelationshipEdge.d.ts +1 -1
- package/dist/client/components/SchemaVisualization/SchemaVisualizationLazy.d.ts +1 -1
- package/dist/client/components/TextPortletModal.d.ts +2 -2
- package/dist/client/components/analyticsPortlet/PortletChart.d.ts +4 -4
- package/dist/client/components/analyticsPortlet/PortletChartView.d.ts +5 -5
- package/dist/client/components/analyticsPortlet/PortletStates.d.ts +2 -2
- package/dist/client/components/analyticsPortlet/parsePortletQuery.d.ts +3 -3
- package/dist/client/components/analyticsPortlet/portletRenderState.d.ts +3 -3
- package/dist/client/components/analyticsPortlet/usePortletDebugData.d.ts +4 -4
- package/dist/client/components/analyticsPortlet/usePortletDrillState.d.ts +2 -2
- package/dist/client/components/analyticsPortlet/usePortletQueryResults.d.ts +4 -4
- package/dist/client/components/charts/ActivityGridChart.config.d.ts +1 -1
- package/dist/client/components/charts/ActivityGridChart.d.ts +1 -1
- package/dist/client/components/charts/ActivityGridChart.helpers.d.ts +1 -1
- package/dist/client/components/charts/ActivityGridChart.render.d.ts +3 -3
- package/dist/client/components/charts/AreaChart.config.d.ts +1 -1
- package/dist/client/components/charts/AreaChart.d.ts +1 -1
- package/dist/client/components/charts/AxisFormatControls.d.ts +1 -1
- package/dist/client/components/charts/BarChart.config.d.ts +1 -1
- package/dist/client/components/charts/BarChart.d.ts +1 -1
- package/dist/client/components/charts/BarChart.helpers.d.ts +1 -1
- package/dist/client/components/charts/BarSeries.d.ts +2 -2
- package/dist/client/components/charts/BoxPlotChart.config.d.ts +1 -1
- package/dist/client/components/charts/BoxPlotChart.d.ts +1 -1
- package/dist/client/components/charts/BubbleChart.config.d.ts +1 -1
- package/dist/client/components/charts/BubbleChart.d.ts +1 -1
- package/dist/client/components/charts/BubbleChart.helpers.d.ts +1 -1
- package/dist/client/components/charts/BubbleChart.render.d.ts +2 -2
- package/dist/client/components/charts/CandlestickChart.config.d.ts +1 -1
- package/dist/client/components/charts/CandlestickChart.d.ts +1 -1
- package/dist/client/components/charts/DataTable.config.d.ts +1 -1
- package/dist/client/components/charts/DataTable.d.ts +1 -1
- package/dist/client/components/charts/FunnelChart.config.d.ts +1 -1
- package/dist/client/components/charts/FunnelChart.d.ts +1 -1
- package/dist/client/components/charts/FunnelChart.helpers.d.ts +2 -2
- package/dist/client/components/charts/FunnelViews.d.ts +2 -2
- package/dist/client/components/charts/GaugeChart.config.d.ts +1 -1
- package/dist/client/components/charts/GaugeChart.d.ts +1 -1
- package/dist/client/components/charts/HeatMapCanvas.d.ts +1 -1
- package/dist/client/components/charts/HeatMapChart.config.d.ts +1 -1
- package/dist/client/components/charts/HeatMapChart.d.ts +1 -1
- package/dist/client/components/charts/HeatMapChart.helpers.d.ts +1 -1
- package/dist/client/components/charts/KpiDelta.config.d.ts +1 -1
- package/dist/client/components/charts/KpiDelta.d.ts +1 -1
- package/dist/client/components/charts/KpiDelta.helpers.d.ts +1 -1
- package/dist/client/components/charts/KpiNumber.config.d.ts +1 -1
- package/dist/client/components/charts/KpiNumber.d.ts +1 -1
- package/dist/client/components/charts/KpiNumber.helpers.d.ts +1 -1
- package/dist/client/components/charts/KpiText.config.d.ts +1 -1
- package/dist/client/components/charts/KpiText.d.ts +1 -1
- package/dist/client/components/charts/LineChart.config.d.ts +1 -1
- package/dist/client/components/charts/LineChart.d.ts +1 -1
- package/dist/client/components/charts/MarkdownChart.config.d.ts +1 -1
- package/dist/client/components/charts/MarkdownChart.d.ts +1 -1
- package/dist/client/components/charts/MeasureProfileChart.config.d.ts +1 -1
- package/dist/client/components/charts/MeasureProfileChart.d.ts +1 -1
- package/dist/client/components/charts/PieChart.config.d.ts +1 -1
- package/dist/client/components/charts/PieChart.d.ts +1 -1
- package/dist/client/components/charts/RadarChart.config.d.ts +1 -1
- package/dist/client/components/charts/RadarChart.d.ts +1 -1
- package/dist/client/components/charts/RadialBarChart.config.d.ts +1 -1
- package/dist/client/components/charts/RadialBarChart.d.ts +1 -1
- package/dist/client/components/charts/RetentionCombinedChart.config.d.ts +1 -1
- package/dist/client/components/charts/RetentionCombinedChart.d.ts +1 -1
- package/dist/client/components/charts/RetentionHeatmap.config.d.ts +1 -1
- package/dist/client/components/charts/RetentionHeatmap.d.ts +1 -1
- package/dist/client/components/charts/SankeyChart.config.d.ts +1 -1
- package/dist/client/components/charts/SankeyChart.d.ts +1 -1
- package/dist/client/components/charts/ScatterChart.config.d.ts +1 -1
- package/dist/client/components/charts/ScatterChart.d.ts +1 -1
- package/dist/client/components/charts/ScatterChart.helpers.d.ts +2 -2
- package/dist/client/components/charts/ScatterSeries.d.ts +2 -2
- package/dist/client/components/charts/ScatterTooltip.d.ts +2 -2
- package/dist/client/components/charts/SunburstChart.config.d.ts +1 -1
- package/dist/client/components/charts/SunburstChart.d.ts +1 -1
- package/dist/client/components/charts/TreeMapChart.config.d.ts +1 -1
- package/dist/client/components/charts/TreeMapChart.d.ts +1 -1
- package/dist/client/components/charts/TreeMapChart.helpers.d.ts +1 -1
- package/dist/client/components/charts/TreeMapContent.d.ts +3 -3
- package/dist/client/components/charts/TreeMapLegend.d.ts +2 -2
- package/dist/client/components/charts/WaterfallChart.config.d.ts +1 -1
- package/dist/client/components/charts/WaterfallChart.d.ts +1 -1
- package/dist/client/components/charts/cartesianChartHelpers.d.ts +1 -1
- package/dist/client/components/charts/chartAxisResolution.d.ts +1 -1
- package/dist/client/components/charts/chartScaffolding.d.ts +1 -1
- package/dist/client/components/charts/gaugeChartHelpers.d.ts +1 -1
- package/dist/client/components/charts/index.d.ts +21 -21
- package/dist/client/components/charts/kpiTextHelpers.d.ts +1 -1
- package/dist/client/components/charts/radialBarChartHelpers.d.ts +1 -1
- package/dist/client/components/dashboard/DashboardContext.d.ts +6 -6
- package/dist/client/components/dashboard/DashboardCoordinator.d.ts +1 -1
- package/dist/client/components/dashboard/DashboardProvider.d.ts +1 -1
- package/dist/client/components/dashboard/dashboardGridUtils.d.ts +1 -1
- package/dist/client/components/dashboard/index.d.ts +7 -7
- package/dist/client/components/dashboardPortletCard/FilterFieldChip.d.ts +1 -1
- package/dist/client/components/dashboardPortletCard/PortletCardHeader.d.ts +2 -2
- package/dist/client/components/dashboardPortletCard/cardStyles.d.ts +1 -1
- package/dist/client/components/dashboardPortletCard/filterField.d.ts +1 -1
- package/dist/client/components/dashboardPortletCard/propsEqual.d.ts +2 -2
- package/dist/client/components/dashboardPortletCard/usePortletCardActions.d.ts +1 -1
- package/dist/client/components/shared/DateRangeFilter.d.ts +1 -1
- package/dist/client/components/shared/FilterBuilder.d.ts +1 -1
- package/dist/client/components/shared/FilterGroup.d.ts +1 -1
- package/dist/client/components/shared/FilterItem.d.ts +1 -1
- package/dist/client/components/shared/FilterValueSelector.d.ts +1 -1
- package/dist/client/components/shared/dateRangeUtils.d.ts +1 -1
- package/dist/client/components/shared/filterItem/FilterDateRangeSelector.d.ts +1 -1
- package/dist/client/components/shared/filterItem/FilterFieldDropdown.d.ts +1 -1
- package/dist/client/components/shared/filterItem/dateRangeSync.d.ts +1 -1
- package/dist/client/components/shared/filterItem/fieldVisuals.d.ts +1 -1
- package/dist/client/components/shared/filterValueSelector/useFilterValueSelectorState.d.ts +2 -2
- package/dist/client/components/shared/queryFieldUtils.d.ts +2 -2
- package/dist/client/components/shared/types.d.ts +8 -8
- package/dist/client/components/shared/utils.d.ts +7 -7
- package/dist/client/components.d.ts +11 -11
- package/dist/client/hooks/agentChatStream.d.ts +1 -1
- package/dist/client/hooks/dashboard/layoutUtils.d.ts +1 -1
- package/dist/client/hooks/dashboard/useDashboardController.d.ts +2 -2
- package/dist/client/hooks/dashboard/useGridLayoutEngine.d.ts +1 -1
- package/dist/client/hooks/dashboard/useRowLayoutEngine.d.ts +1 -1
- package/dist/client/hooks/drillNavigation.d.ts +2 -2
- package/dist/client/hooks/queries/index.d.ts +9 -9
- package/dist/client/hooks/queries/useCubeLoadQuery.d.ts +2 -2
- package/dist/client/hooks/queries/useCubeMetaQuery.d.ts +2 -2
- package/dist/client/hooks/queries/useDryRunQuery.d.ts +2 -2
- package/dist/client/hooks/queries/useExplainAI.d.ts +1 -1
- package/dist/client/hooks/queries/useExplainQuery.d.ts +1 -1
- package/dist/client/hooks/queries/useFlowQuery.d.ts +1 -1
- package/dist/client/hooks/queries/useFunnelQuery.d.ts +1 -1
- package/dist/client/hooks/queries/useMultiCubeLoadQuery.d.ts +1 -1
- package/dist/client/hooks/queries/useRetentionQuery.d.ts +1 -1
- package/dist/client/hooks/useAgentChat.d.ts +1 -1
- package/dist/client/hooks/useAnalysisAI.d.ts +4 -4
- package/dist/client/hooks/useAnalysisBuilderHook.d.ts +27 -27
- package/dist/client/hooks/useAnalysisChartDefaults.d.ts +4 -4
- package/dist/client/hooks/useAnalysisCombinedFields.d.ts +2 -2
- package/dist/client/hooks/useAnalysisInitialization.d.ts +1 -1
- package/dist/client/hooks/useAnalysisQueryBuilder.d.ts +3 -3
- package/dist/client/hooks/useAnalysisQueryExecution.d.ts +7 -7
- package/dist/client/hooks/useAnalysisShare.d.ts +1 -1
- package/dist/client/hooks/useAnalysisUIState.d.ts +2 -2
- package/dist/client/hooks/useDashboardHook.d.ts +2 -2
- package/dist/client/hooks/useDataBrowser.d.ts +5 -5
- package/dist/client/hooks/useDrillInteraction.d.ts +1 -1
- package/dist/client/hooks/useTheme.d.ts +1 -1
- package/dist/client/hooks/useTranslation.d.ts +1 -1
- package/dist/client/hooks.d.ts +11 -11
- package/dist/client/icons/defaultIcons.d.ts +1 -1
- package/dist/client/icons/index.d.ts +3 -3
- package/dist/client/icons/registry.d.ts +1 -1
- package/dist/client/index.d.ts +74 -74
- package/dist/client/index.js.map +1 -1
- package/dist/client/providers/CubeApiProvider.d.ts +3 -3
- package/dist/client/providers/CubeFeaturesProvider.d.ts +1 -1
- package/dist/client/providers/CubeMetaContext.d.ts +1 -1
- package/dist/client/providers/CubeProvider.d.ts +7 -7
- package/dist/client/providers/I18nProvider.d.ts +1 -1
- package/dist/client/providers.d.ts +4 -4
- package/dist/client/schema.d.ts +2 -2
- package/dist/client/shared/chartConfigBuilders.d.ts +2 -2
- package/dist/client/shared/chartDefaults.d.ts +4 -4
- package/dist/client/shared/components/QueryAnalysisPanel.d.ts +1 -1
- package/dist/client/shared/components/QueryAnalysisPanel.sections.d.ts +1 -1
- package/dist/client/shared/index.d.ts +7 -7
- package/dist/client/shared/queryTransforms.d.ts +1 -1
- package/dist/client/shared/types.d.ts +1 -1
- package/dist/client/shared/utils.d.ts +3 -3
- package/dist/client/stores/analysisBuilderStore.d.ts +9 -9
- package/dist/client/stores/dashboardStore.d.ts +3 -3
- package/dist/client/stores/dataBrowserStore.d.ts +1 -1
- package/dist/client/stores/notebookStore.d.ts +1 -1
- package/dist/client/stores/optionsToAnalysisConfig.d.ts +4 -4
- package/dist/client/stores/slices/coreSlice.d.ts +3 -3
- package/dist/client/stores/slices/flowSlice.d.ts +3 -3
- package/dist/client/stores/slices/funnelSlice.d.ts +3 -3
- package/dist/client/stores/slices/index.d.ts +7 -7
- package/dist/client/stores/slices/querySlice.d.ts +3 -3
- package/dist/client/stores/slices/retentionSlice.d.ts +3 -3
- package/dist/client/stores/slices/uiSlice.d.ts +2 -2
- package/dist/client/types/analysisConfig.d.ts +4 -4
- package/dist/client/types/drill.d.ts +5 -5
- package/dist/client/types/flow.d.ts +2 -2
- package/dist/client/types/funnel.d.ts +1 -1
- package/dist/client/types/retention.d.ts +2 -2
- package/dist/client/types.d.ts +12 -12
- package/dist/client/utils/axisValueFormatting.d.ts +1 -1
- package/dist/client/utils/chartUtils.d.ts +1 -1
- package/dist/client/utils/configMigration.d.ts +2 -2
- package/dist/client/utils/drillQueryBuilder.d.ts +2 -2
- package/dist/client/utils/exportXlsx.d.ts +2 -2
- package/dist/client/utils/filterUtils.d.ts +1 -1
- package/dist/client/utils/funnelExecution.d.ts +2 -2
- package/dist/client/utils/funnelValidation.d.ts +2 -2
- package/dist/client/utils/index.d.ts +10 -10
- package/dist/client/utils/joinReachability.d.ts +1 -1
- package/dist/client/utils/multiQueryUtils.d.ts +1 -1
- package/dist/client/utils/multiQueryValidation.d.ts +1 -1
- package/dist/client/utils/pivotUtils.d.ts +1 -1
- package/dist/client/utils/shareUtils.d.ts +1 -1
- package/dist/client/utils/thumbnail.d.ts +1 -1
- package/dist/client/utils.d.ts +2 -2
- package/dist/mcp-app/mcp-app.html +33 -33
- package/dist/server/{server/adapters → adapters}/base-adapter.d.ts +1 -1
- package/dist/server/{server/adapters → adapters}/databend-adapter.d.ts +2 -2
- package/dist/server/{server/adapters → adapters}/duckdb-adapter.d.ts +2 -2
- package/dist/server/{server/adapters → adapters}/mysql-adapter.d.ts +2 -2
- package/dist/server/{server/adapters → adapters}/postgres-adapter.d.ts +2 -2
- package/dist/server/{server/adapters → adapters}/singlestore-adapter.d.ts +1 -1
- package/dist/server/{server/adapters → adapters}/snowflake-adapter.d.ts +2 -2
- package/dist/server/{server/adapters → adapters}/sqlite-adapter.d.ts +2 -2
- package/dist/server/{server/adapters → adapters}/window-function-builder.d.ts +1 -1
- package/dist/server/{server/agent → agent}/handler-steps.d.ts +3 -3
- package/dist/server/{server/agent → agent}/handler.d.ts +3 -3
- package/dist/server/agent/index.d.ts +11 -0
- package/dist/server/{server/agent → agent}/providers/anthropic.d.ts +1 -1
- package/dist/server/{server/agent → agent}/providers/factory.d.ts +1 -1
- package/dist/server/{server/agent → agent}/providers/google.d.ts +1 -1
- package/dist/server/agent/providers/index.d.ts +6 -0
- package/dist/server/{server/agent → agent}/providers/openai.d.ts +1 -1
- package/dist/server/{server/agent → agent}/system-prompt.d.ts +1 -1
- package/dist/server/{server/agent → agent}/tools.d.ts +4 -4
- package/dist/server/{server/agent → agent}/types.d.ts +1 -1
- package/dist/server/{server/ai → ai}/discovery-helpers.d.ts +1 -1
- package/dist/server/{server/ai → ai}/discovery.d.ts +2 -2
- package/dist/server/{server/ai → ai}/index.d.ts +6 -6
- package/dist/server/{server/ai → ai}/suggestion-helpers.d.ts +1 -1
- package/dist/server/{server/ai → ai}/suggestion.d.ts +2 -2
- package/dist/server/{server/ai → ai}/validation-helpers.d.ts +4 -4
- package/dist/server/{server/ai → ai}/validation.d.ts +2 -2
- package/dist/server/{server/builders → builders}/analysis-utils.d.ts +1 -1
- package/dist/server/{server/builders → builders}/comparison-query-builder.d.ts +2 -2
- package/dist/server/{server/builders → builders}/cte-builder.d.ts +2 -2
- package/dist/server/{server/builders → builders}/date-time-builder.d.ts +2 -2
- package/dist/server/{server/builders → builders}/date-time-helpers.d.ts +1 -1
- package/dist/server/{server/builders → builders}/filter-builder.d.ts +3 -3
- package/dist/server/{server/builders → builders}/filter-operators.d.ts +3 -3
- package/dist/server/{server/builders → builders}/flow-query-builder.d.ts +4 -4
- package/dist/server/{server/builders → builders}/funnel-query-builder.d.ts +3 -3
- package/dist/server/{server/builders → builders}/group-by-builder.d.ts +2 -2
- package/dist/server/builders/index.d.ts +13 -0
- package/dist/server/{server/builders → builders}/measure-builder.d.ts +3 -3
- package/dist/server/{server/builders → builders}/retention-query-builder.d.ts +3 -3
- package/dist/server/cache-providers/index.d.ts +5 -0
- package/dist/server/{server/cache-providers → cache-providers}/memory.d.ts +1 -1
- package/dist/server/{server/cache-utils.d.ts → cache-utils.d.ts} +1 -1
- package/dist/server/{server/compiler-metadata.d.ts → compiler-metadata.d.ts} +1 -1
- package/dist/server/{server/compiler.d.ts → compiler.d.ts} +3 -3
- package/dist/server/{server/cube-utils.d.ts → cube-utils.d.ts} +1 -1
- package/dist/server/{server/database-utils.d.ts → database-utils.d.ts} +1 -1
- package/dist/server/{server/execution → execution}/annotation-builder.d.ts +1 -1
- package/dist/server/{server/execution → execution}/filter-cache-preloader.d.ts +3 -3
- package/dist/server/{server/execution → execution}/mode-router.d.ts +5 -5
- package/dist/server/{server/execution → execution}/query-result-cache.d.ts +1 -1
- package/dist/server/{server/execution → execution}/result-post-processor.d.ts +2 -2
- package/dist/server/{server/executor.d.ts → executor.d.ts} +3 -3
- package/dist/server/{server/executors → executors}/base-executor.d.ts +2 -2
- package/dist/server/{server/executors → executors}/databend-executor.d.ts +2 -2
- package/dist/server/{server/executors → executors}/duckdb-executor.d.ts +2 -2
- package/dist/server/{server/executors → executors}/index.d.ts +9 -9
- package/dist/server/{server/executors → executors}/mysql-executor.d.ts +2 -2
- package/dist/server/{server/executors → executors}/postgres-executor.d.ts +2 -2
- package/dist/server/{server/executors → executors}/singlestore-executor.d.ts +2 -2
- package/dist/server/{server/executors → executors}/snowflake-executor.d.ts +2 -2
- package/dist/server/{server/executors → executors}/sqlite-executor.d.ts +2 -2
- package/dist/server/{server/explain → explain}/databend-parser.d.ts +1 -1
- package/dist/server/{server/explain → explain}/duckdb-parser.d.ts +1 -1
- package/dist/server/{server/explain → explain}/explain-tree.d.ts +1 -1
- package/dist/server/explain/index.d.ts +9 -0
- package/dist/server/{server/explain → explain}/mysql-parser.d.ts +1 -1
- package/dist/server/{server/explain → explain}/postgres-parser.d.ts +1 -1
- package/dist/server/{server/explain → explain}/snowflake-parser.d.ts +1 -1
- package/dist/server/{server/explain → explain}/sqlite-parser.d.ts +1 -1
- package/dist/server/{server/filter-cache.d.ts → filter-cache.d.ts} +1 -1
- package/dist/server/{server/gap-filler.d.ts → gap-filler.d.ts} +2 -2
- package/dist/server/index.d.ts +38 -2
- package/dist/server/{server/logical-plan → logical-plan}/cte-planner-helpers.d.ts +1 -1
- package/dist/server/{server/logical-plan → logical-plan}/cte-planner.d.ts +4 -4
- package/dist/server/{server/logical-plan → logical-plan}/filter-propagation.d.ts +1 -1
- package/dist/server/{server/logical-plan → logical-plan}/index.d.ts +11 -11
- package/dist/server/{server/logical-plan → logical-plan}/join-planner.d.ts +3 -3
- package/dist/server/{server/logical-plan → logical-plan}/logical-plan-builder.d.ts +5 -5
- package/dist/server/{server/logical-plan → logical-plan}/logical-planner.d.ts +2 -2
- package/dist/server/{server/logical-plan → logical-plan}/optimiser.d.ts +1 -1
- package/dist/server/{server/logical-plan → logical-plan}/plan-analysis-reporter.d.ts +2 -2
- package/dist/server/{server/logical-plan → logical-plan}/planner-utils.d.ts +2 -2
- package/dist/server/{server/logical-plan → logical-plan}/types.d.ts +3 -3
- package/dist/server/{server/measure-classification.d.ts → measure-classification.d.ts} +1 -1
- package/dist/server/{server/physical-plan → physical-plan}/drizzle-plan-builder.d.ts +5 -5
- package/dist/server/{server/physical-plan → physical-plan}/drizzle-sql-builder.d.ts +3 -3
- package/dist/server/physical-plan/index.d.ts +2 -0
- package/dist/server/{server/physical-plan → physical-plan}/processors/cte-processor.d.ts +2 -2
- package/dist/server/physical-plan/processors/index.d.ts +8 -0
- package/dist/server/{server/physical-plan → physical-plan}/processors/joins-processor.d.ts +2 -2
- package/dist/server/{server/physical-plan → physical-plan}/processors/keys-dedup-processor.d.ts +2 -2
- package/dist/server/{server/physical-plan → physical-plan}/processors/multi-fact-processor.d.ts +2 -2
- package/dist/server/{server/physical-plan → physical-plan}/processors/predicates-processor.d.ts +2 -2
- package/dist/server/{server/physical-plan → physical-plan}/processors/selection-processor.d.ts +2 -2
- package/dist/server/{server/physical-plan → physical-plan}/processors/shared.d.ts +4 -4
- package/dist/server/{server/physical-plan → physical-plan}/processors/window-processor.d.ts +2 -2
- package/dist/server/{server/query-handlers.d.ts → query-handlers.d.ts} +3 -3
- package/dist/server/{server/query-modes.d.ts → query-modes.d.ts} +1 -1
- package/dist/server/{server/query-validator.d.ts → query-validator.d.ts} +1 -1
- package/dist/server/{server/resolvers → resolvers}/calculated-measure-resolver.d.ts +1 -1
- package/dist/server/{server/resolvers → resolvers}/index.d.ts +2 -2
- package/dist/server/{server/resolvers → resolvers}/join-path-resolver.d.ts +1 -1
- package/dist/server/{server/template-substitution.d.ts → template-substitution.d.ts} +1 -1
- package/dist/server/{server/types → types}/cache.d.ts +1 -1
- package/dist/server/{server/types → types}/cube.d.ts +4 -4
- package/dist/server/{server/types → types}/executor.d.ts +2 -2
- package/dist/server/{server/types → types}/flow.d.ts +2 -2
- package/dist/server/{server/types → types}/funnel.d.ts +1 -1
- package/dist/server/types/index.d.ts +11 -0
- package/dist/server/{server/types → types}/metadata.d.ts +1 -1
- package/dist/server/{server/types → types}/query.d.ts +4 -4
- package/dist/server/{server/types → types}/retention.d.ts +1 -1
- package/dist/server/{server/types → types}/utils.d.ts +1 -1
- package/package.json +12 -4
- package/dist/adapters/mcp-transport-Chiaj4ll.cjs +0 -40
- package/dist/adapters/mcp-transport-H96VG3WY.js +0 -591
- package/dist/server/server/agent/index.d.ts +0 -11
- package/dist/server/server/agent/providers/index.d.ts +0 -6
- package/dist/server/server/builders/index.d.ts +0 -13
- package/dist/server/server/cache-providers/index.d.ts +0 -5
- package/dist/server/server/explain/index.d.ts +0 -9
- package/dist/server/server/index.d.ts +0 -38
- package/dist/server/server/physical-plan/index.d.ts +0 -2
- package/dist/server/server/physical-plan/processors/index.d.ts +0 -8
- package/dist/server/server/types/index.d.ts +0 -11
- /package/dist/server/{server/agent → agent}/chart-validation.d.ts +0 -0
- /package/dist/server/{server/agent → agent}/providers/types.d.ts +0 -0
- /package/dist/server/{server/ai → ai}/mcp-prompts.d.ts +0 -0
- /package/dist/server/{server/ai → ai}/query-schema.d.ts +0 -0
- /package/dist/server/{server/ai → ai}/schemas.d.ts +0 -0
- /package/dist/server/{server/executors → executors}/explain-utils.d.ts +0 -0
- /package/dist/server/{server/prompts → prompts}/explain-analysis-prompt.d.ts +0 -0
- /package/dist/server/{server/prompts → prompts}/index.d.ts +0 -0
- /package/dist/server/{server/prompts → prompts}/single-step-prompt.d.ts +0 -0
- /package/dist/server/{server/prompts → prompts}/step0-validation-prompt.d.ts +0 -0
- /package/dist/server/{server/prompts → prompts}/step1-shape-prompt.d.ts +0 -0
- /package/dist/server/{server/prompts → prompts}/step2-complete-prompt.d.ts +0 -0
- /package/dist/server/{server/prompts → prompts}/types.d.ts +0 -0
- /package/dist/server/{server/sql-format.d.ts → sql-format.d.ts} +0 -0
- /package/dist/server/{server/types → types}/analysis.d.ts +0 -0
- /package/dist/server/{server/types → types}/core.d.ts +0 -0
- /package/dist/server/{server/types → types}/validation.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-tree-map-Ceq5sLZA.js","names":[],"sources":["../../../src/client/components/charts/TreeMapChart.helpers.ts","../../../src/client/components/charts/TreeMapContent.tsx","../../../src/client/components/charts/TreeMapLegend.tsx","../../../src/client/components/charts/TreeMapChart.tsx"],"sourcesContent":["/**\n * Co-located helpers for TreeMapChart.\n *\n * Pure data-shaping + legend computation extracted from the component. No\n * behaviour change — mirrors the original inline logic exactly.\n */\nimport { scaleQuantize, scaleOrdinal } from 'd3'\nimport { CHART_COLORS, CHART_COLORS_GRADIENT } from '../../utils/chartConstants'\nimport { formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils'\nimport type { AxisFormatConfig, ChartAxisConfig, ColorPalette, CubeQuery } from '../../types'\n\nexport interface TreemapDatum {\n name: string\n size: number\n fill?: string\n series?: string\n // Index signature so the rows satisfy recharts' Treemap data + drill payloads\n [key: string]: unknown\n}\n\n/** First element of a config field that may be a string, string[] or undefined. */\nfunction pickField(value: string | string[] | undefined): string {\n if (!value) return ''\n return Array.isArray(value) ? value[0] : value\n}\n\n/** Coerce a possibly-string numeric cell to a number (NaN-safe via fallback). */\nfunction toNumber(value: unknown): number {\n return typeof value === 'string' ? parseFloat(value) : ((value as number) || 0)\n}\n\n/** Numeric value of a series cell (string or number), used for colour scaling. */\nfunction seriesNumber(value: unknown): number {\n return typeof value === 'string' ? parseFloat(value) : (value as number)\n}\n\nexport interface TreemapBuildResult {\n treemapData: TreemapDatum[]\n isNumericSeries: boolean\n seriesField?: string\n}\n\n/** Build treemap rows from the new (configured) chart config format. */\nfunction buildFromConfig(\n data: Record<string, any>[],\n chartConfig: ChartAxisConfig,\n queryObject: CubeQuery | undefined,\n colorPalette: ColorPalette | undefined\n): TreemapBuildResult {\n const xAxisField = pickField(chartConfig.xAxis)\n const yAxisField = pickField(chartConfig.yAxis)\n const seriesField = Array.isArray(chartConfig.series) ? chartConfig.series[0] : chartConfig.series\n const granularity = getFieldGranularity(queryObject, xAxisField)\n\n const nameOf = (item: Record<string, any>) =>\n formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown'\n\n if (!seriesField) {\n // No series grouping - use index-based colors\n const treemapData = data.map((item, index) => ({\n name: nameOf(item),\n size: toNumber(item[yAxisField]),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n }))\n return { treemapData, isNumericSeries: false, seriesField }\n }\n\n // Check if series field is numeric for color scaling\n const seriesValues = data\n .map((item) => seriesNumber(item[seriesField]))\n .filter((val) => !isNaN(val))\n const isNumericSeries =\n seriesValues.length === data.length && seriesValues.every((val) => typeof val === 'number')\n\n if (isNumericSeries) {\n const colorScale = scaleQuantize<string>()\n .domain([Math.min(...seriesValues), Math.max(...seriesValues)])\n .range(CHART_COLORS_GRADIENT)\n const treemapData = data.map((item) => ({\n name: nameOf(item),\n size: toNumber(item[yAxisField]),\n fill: colorScale(seriesNumber(item[seriesField])),\n series: String(item[seriesField])\n }))\n return { treemapData, isNumericSeries, seriesField }\n }\n\n const uniqueSeriesValues = [...new Set(data.map((item) => String(item[seriesField])))]\n const colorScale = scaleOrdinal<string>()\n .domain(uniqueSeriesValues)\n .range(colorPalette?.colors || CHART_COLORS)\n const treemapData = data.map((item) => ({\n name: nameOf(item),\n size: toNumber(item[yAxisField]),\n fill: colorScale(String(item[seriesField])),\n series: String(item[seriesField])\n }))\n return { treemapData, isNumericSeries, seriesField }\n}\n\n/** Resolve a friendly name for a legacy/auto-detected row. */\nfunction legacyName(value: unknown): string {\n if (typeof value === 'boolean') return value ? 'Active' : 'Inactive'\n if (value === 'true' || value === 'false') return value === 'true' ? 'Active' : 'Inactive'\n return String(value)\n}\n\n/** Build treemap rows by auto-detecting name/size fields (legacy format). */\nfunction buildFromAutoDetect(\n data: Record<string, any>[],\n colorPalette: ColorPalette | undefined\n): TreemapBuildResult | null {\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n\n const nameField =\n keys.find(\n (key) =>\n typeof firstRow[key] === 'string' ||\n key.toLowerCase().includes('name') ||\n key.toLowerCase().includes('label') ||\n key.toLowerCase().includes('category')\n ) || keys[0]\n\n const sizeField =\n keys.find((key) => key.toLowerCase().includes('size')) ||\n keys.find((key) => typeof firstRow[key] === 'number' && key !== nameField) ||\n keys[1]\n\n if (!sizeField) return null\n\n const treemapData = data.map((item, index) => ({\n name: legacyName(item[nameField]),\n size: toNumber(item[sizeField]),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n }))\n return { treemapData, isNumericSeries: false, seriesField: undefined }\n}\n\n/**\n * Build treemap data (config or auto-detect), then drop non-positive sizes.\n * Returns `null` when the legacy path can't find a usable size field.\n */\nexport function buildTreemapData(\n data: Record<string, any>[],\n chartConfig: ChartAxisConfig | undefined,\n queryObject: CubeQuery | undefined,\n colorPalette: ColorPalette | undefined\n): TreemapBuildResult | null {\n const result =\n chartConfig?.xAxis && chartConfig?.yAxis\n ? buildFromConfig(data, chartConfig, queryObject, colorPalette)\n : buildFromAutoDetect(data, colorPalette)\n\n if (!result) return null\n\n return {\n ...result,\n treemapData: result.treemapData.filter((item) => item.size != null && item.size > 0)\n }\n}\n\n/** Min/max of the (numeric) series field across the raw rows. */\nexport function seriesMinMax(\n data: Record<string, any>[],\n seriesField: string\n): { min: number; max: number } {\n const values = data.map((item) => seriesNumber(item[seriesField]))\n return { min: Math.min(...values), max: Math.max(...values) }\n}\n\n/** Format a numeric value with the optional axis format (or `.toFixed(2)`). */\nexport function formatSeriesValue(value: number, format: AxisFormatConfig | undefined): string {\n return format ? formatAxisValue(value, format) : value.toFixed(2)\n}\n\nexport interface LegendEntry {\n value: string\n type: 'rect'\n color: string\n}\n\n/**\n * Build the legend entries for the treemap: a gradient ramp for numeric series,\n * or discrete swatches for categorical series. Empty when not applicable.\n */\nexport function buildTreemapLegend(\n data: Record<string, any>[],\n treemapData: TreemapDatum[],\n showLegend: boolean,\n seriesField: string | undefined,\n isNumericSeries: boolean,\n leftYAxisFormat: AxisFormatConfig | undefined\n): LegendEntry[] {\n if (!showLegend || !seriesField) return []\n\n if (isNumericSeries) {\n const { min, max } = seriesMinMax(data, seriesField)\n return CHART_COLORS_GRADIENT.map((color, index) => {\n const ratio = index / (CHART_COLORS_GRADIENT.length - 1)\n const value = min + (max - min) * ratio\n return { value: formatSeriesValue(value, leftYAxisFormat), type: 'rect' as const, color }\n })\n }\n\n const uniqueSeries = [...new Set(treemapData.map((item) => item.series).filter(Boolean))]\n if (uniqueSeries.length > 1) {\n return uniqueSeries.map((series, index) => ({\n value: series as string,\n type: 'rect' as const,\n color: CHART_COLORS[index % CHART_COLORS.length]\n }))\n }\n return []\n}\n\n/** Adjust the outer container height to make room for a legend, if present. */\nexport function adjustHeightForLegend(\n height: string | number,\n hasLegend: boolean\n): string | number {\n if (!hasLegend) return height\n if (typeof height === 'string' && height.includes('%')) return height\n if (typeof height === 'number') return height + 60\n return `calc(${height} + 60px)`\n}\n","import React from 'react'\nimport { CHART_COLORS } from '../../utils/chartConstants'\nimport { formatAxisValue } from '../../utils/chartUtils'\nimport type { AxisFormatConfig, ChartAxisConfig, ColorPalette, CubeQuery } from '../../types'\nimport type { ChartDataPointClickEvent } from '../../types/drill'\nimport type { TreemapDatum } from './TreeMapChart.helpers'\n\ninterface TreeMapContentOptions {\n treemapData: TreemapDatum[]\n colorPalette?: ColorPalette\n hoveredIndex: number | null\n setHoveredIndex: (index: number | null) => void\n leftYAxisFormat?: AxisFormatConfig\n drillEnabled?: boolean\n onDataPointClick?: (event: ChartDataPointClickEvent) => void\n queryObject?: CubeQuery\n chartConfig?: ChartAxisConfig\n}\n\n/** Fill opacity for a treemap cell given the currently hovered index. */\nfunction cellOpacity(hoveredIndex: number | null, index: number): number {\n if (hoveredIndex === null) return 0.8\n return hoveredIndex === index ? 1 : 0.6\n}\n\n/** Format the size label shown inside a treemap cell. */\nfunction formatSize(size: unknown, format: AxisFormatConfig | undefined): string {\n if (format) return formatAxisValue(size as number, format)\n return typeof size === 'number' ? size.toLocaleString() : String(size)\n}\n\n/**\n * Build the Recharts `content` renderer for treemap cells.\n *\n * Encapsulates the per-cell rect + foreignObject overlay, hover state and drill\n * click handler that previously lived inline in TreeMapChart (the highest-\n * complexity hot spots). Behaviour is identical to the original.\n */\nexport function makeTreeMapContent({\n treemapData,\n colorPalette,\n hoveredIndex,\n setHoveredIndex,\n leftYAxisFormat,\n drillEnabled,\n onDataPointClick,\n queryObject,\n chartConfig,\n}: TreeMapContentOptions) {\n return function CustomizedContent(props: any) {\n const { x, y, width, height, index, name, size } = props\n\n if (width < 20 || height < 20) return null // Skip very small cells\n\n const handleClick = (event: React.MouseEvent) => {\n event.stopPropagation()\n const cellData = treemapData[index]\n if (cellData && onDataPointClick) {\n // Use query measures for proper field name (chartConfig.yAxis may hold labels)\n const measureField = queryObject?.measures?.[0] || chartConfig?.yAxis?.[0] || ''\n onDataPointClick({\n dataPoint: cellData,\n clickedField: measureField,\n xValue: name,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event\n })\n }\n }\n\n const fill =\n treemapData[index]?.fill ||\n ((colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length])\n\n return (\n <g>\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n style={{\n fill,\n fillOpacity: cellOpacity(hoveredIndex, index),\n stroke: '#fff',\n strokeWidth: 2,\n cursor: drillEnabled ? 'pointer' : 'default',\n pointerEvents: 'all'\n }}\n onMouseEnter={() => setHoveredIndex(index)}\n onMouseLeave={() => setHoveredIndex(null)}\n onClick={drillEnabled && onDataPointClick ? handleClick : undefined}\n />\n <foreignObject\n x={x}\n y={y}\n width={width}\n height={height}\n style={{ pointerEvents: 'none', overflow: 'visible' }}\n >\n <div\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '4px',\n boxSizing: 'border-box',\n color: '#ffffff',\n textShadow: '0 1px 2px rgba(0,0,0,0.8)',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n overflow: 'hidden'\n }}\n >\n {width > 40 && height > 30 && (\n <div\n style={{\n fontSize: `${Math.max(10, Math.min(width / 8, height / 8, 16))}px`,\n fontWeight: '600',\n textAlign: 'center',\n lineHeight: '1.2',\n marginBottom: width > 60 && height > 45 ? '4px' : '0',\n wordBreak: 'break-word',\n hyphens: 'auto'\n }}\n >\n {name}\n </div>\n )}\n {width > 60 && height > 45 && (\n <div\n style={{\n fontSize: `${Math.max(8, Math.min(width / 10, height / 10, 14))}px`,\n textAlign: 'center',\n opacity: 0.9\n }}\n >\n {formatSize(size, leftYAxisFormat)}\n </div>\n )}\n </div>\n </foreignObject>\n </g>\n )\n }\n}\n","import { CHART_COLORS_GRADIENT } from '../../utils/chartConstants'\nimport type { AxisFormatConfig } from '../../types'\nimport {\n seriesMinMax,\n formatSeriesValue,\n type LegendEntry\n} from './TreeMapChart.helpers'\n\ninterface TreeMapLegendProps {\n isNumericSeries: boolean\n seriesField?: string\n seriesLabel: string\n legendPayload: LegendEntry[]\n data: Record<string, any>[]\n leftYAxisFormat?: AxisFormatConfig\n}\n\n/** Gradient ramp legend for a numeric series field. */\nfunction NumericLegend({\n seriesLabel,\n data,\n seriesField,\n leftYAxisFormat,\n}: {\n seriesLabel: string\n data: Record<string, any>[]\n seriesField: string\n leftYAxisFormat?: AxisFormatConfig\n}) {\n const { min, max } = seriesMinMax(data, seriesField)\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center\">\n <div className=\"dc:text-xs dc:font-semibold text-dc-text-primary dc:mb-2\">\n {seriesLabel}\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-2\">\n <span className=\"dc:text-xs text-dc-text-muted\">\n {formatSeriesValue(min, leftYAxisFormat)}\n </span>\n <div\n className=\"dc:h-4 dc:rounded-sm\"\n style={{\n width: '200px',\n background: `linear-gradient(to right, ${CHART_COLORS_GRADIENT.join(', ')})`\n }}\n />\n <span className=\"dc:text-xs text-dc-text-muted\">\n {formatSeriesValue(max, leftYAxisFormat)}\n </span>\n </div>\n </div>\n )\n}\n\n/** Discrete swatch legend for a categorical series field. */\nfunction CategoricalLegend({ legendPayload }: { legendPayload: LegendEntry[] }) {\n return (\n <div className=\"dc:flex dc:flex-wrap dc:justify-center dc:gap-4\">\n {legendPayload.map((item, index) => (\n <div key={index} className=\"dc:flex dc:items-center dc:gap-2\">\n <div className=\"dc:w-3 dc:h-3 rounded-xs\" style={{ backgroundColor: item.color }} />\n <span className=\"dc:text-xs text-dc-text-muted\">{item.value}</span>\n </div>\n ))}\n </div>\n )\n}\n\n/** Treemap legend wrapper — gradient for numeric series, swatches otherwise. */\nexport function TreeMapLegend({\n isNumericSeries,\n seriesField,\n seriesLabel,\n legendPayload,\n data,\n leftYAxisFormat,\n}: TreeMapLegendProps) {\n return (\n <div className=\"dc:flex dc:justify-center dc:items-center dc:mt-4 dc:pb-2\">\n {isNumericSeries && seriesField ? (\n <NumericLegend\n seriesLabel={seriesLabel}\n data={data}\n seriesField={seriesField}\n leftYAxisFormat={leftYAxisFormat}\n />\n ) : (\n <CategoricalLegend legendPayload={legendPayload} />\n )}\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { Treemap } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport { ChartEmptyState, ChartConfigError, ChartRenderError } from './ChartStates'\nimport { formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport {\n buildTreemapData,\n buildTreemapLegend,\n adjustHeightForLegend\n} from './TreeMapChart.helpers'\nimport { makeTreeMapContent } from './TreeMapContent'\nimport { TreeMapLegend } from './TreeMapLegend'\nimport type { ChartProps } from '../../types'\n\nconst TreeMapChart = React.memo(function TreeMapChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n onDataPointClick,\n drillEnabled\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n try {\n const safeDisplayConfig = {\n showTooltip: displayConfig?.showTooltip ?? true,\n showLegend: displayConfig?.showLegend ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat\n }\n\n if (!data || data.length === 0) {\n return <ChartEmptyState height={height} hint={t('chart.runtime.noDataHint.treemap')} />\n }\n\n // Build treemap rows (config or auto-detect) — null means no usable size field\n const built = buildTreemapData(data, chartConfig, queryObject, colorPalette)\n if (!built) {\n return <ChartConfigError height={height} hint={t('chart.runtime.configErrorHint.treemapNumeric')} />\n }\n\n const { treemapData, isNumericSeries, seriesField } = built\n\n if (treemapData.length === 0) {\n return (\n <ChartEmptyState\n height={height}\n titleKey=\"chart.runtime.noValidData\"\n hint=\"No valid data points for treemap chart after transformation\"\n />\n )\n }\n\n // Custom content renderer for treemap cells with HTML overlays\n const CustomizedContent = makeTreeMapContent({\n treemapData,\n colorPalette,\n hoveredIndex,\n setHoveredIndex,\n leftYAxisFormat: safeDisplayConfig.leftYAxisFormat,\n drillEnabled,\n onDataPointClick,\n queryObject,\n chartConfig\n })\n\n // Build legend payload (gradient for numeric series, swatches otherwise)\n const legendPayload = buildTreemapLegend(\n data,\n treemapData,\n safeDisplayConfig.showLegend,\n seriesField,\n isNumericSeries,\n safeDisplayConfig.leftYAxisFormat\n )\n\n const hasLegend = safeDisplayConfig.showLegend && legendPayload.length > 0\n const adjustedHeight = adjustHeightForLegend(height, hasLegend)\n\n return (\n <div className=\"dc:w-full\" style={{ height: adjustedHeight }}>\n <ChartContainer height={hasLegend ? `calc(100% - 50px)` : \"100%\"}>\n <Treemap\n data={treemapData}\n dataKey=\"size\"\n aspectRatio={4 / 3}\n stroke=\"#fff\"\n content={<CustomizedContent />}\n >\n {safeDisplayConfig.showTooltip && (\n <ChartTooltip\n formatter={safeDisplayConfig.leftYAxisFormat\n ? (value: any, name: string) => [formatAxisValue(value, safeDisplayConfig.leftYAxisFormat), name]\n : undefined\n }\n />\n )}\n </Treemap>\n </ChartContainer>\n\n {/* Custom Legend outside ChartContainer */}\n {hasLegend && (\n <TreeMapLegend\n isNumericSeries={isNumericSeries}\n seriesField={seriesField}\n seriesLabel={seriesField ? getFieldLabel(seriesField) : ''}\n legendPayload={legendPayload}\n data={data}\n leftYAxisFormat={safeDisplayConfig.leftYAxisFormat}\n />\n )}\n </div>\n )\n } catch (error) {\n // 'TreeMapChart rendering error\n return <ChartRenderError height={height} chartType=\"TreeMap Chart\" error={error} />\n }\n})\n\nexport default TreeMapChart\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-tree-map-Ceq5sLZA.js","names":[],"sources":["../../../src/client/components/charts/TreeMapChart.helpers.ts","../../../src/client/components/charts/TreeMapContent.tsx","../../../src/client/components/charts/TreeMapLegend.tsx","../../../src/client/components/charts/TreeMapChart.tsx"],"sourcesContent":["/**\n * Co-located helpers for TreeMapChart.\n *\n * Pure data-shaping + legend computation extracted from the component. No\n * behaviour change — mirrors the original inline logic exactly.\n */\nimport { scaleQuantize, scaleOrdinal } from 'd3'\nimport { CHART_COLORS, CHART_COLORS_GRADIENT } from '../../utils/chartConstants.js'\nimport { formatTimeValue, getFieldGranularity, formatAxisValue } from '../../utils/chartUtils.js'\nimport type { AxisFormatConfig, ChartAxisConfig, ColorPalette, CubeQuery } from '../../types.js'\n\nexport interface TreemapDatum {\n name: string\n size: number\n fill?: string\n series?: string\n // Index signature so the rows satisfy recharts' Treemap data + drill payloads\n [key: string]: unknown\n}\n\n/** First element of a config field that may be a string, string[] or undefined. */\nfunction pickField(value: string | string[] | undefined): string {\n if (!value) return ''\n return Array.isArray(value) ? value[0] : value\n}\n\n/** Coerce a possibly-string numeric cell to a number (NaN-safe via fallback). */\nfunction toNumber(value: unknown): number {\n return typeof value === 'string' ? parseFloat(value) : ((value as number) || 0)\n}\n\n/** Numeric value of a series cell (string or number), used for colour scaling. */\nfunction seriesNumber(value: unknown): number {\n return typeof value === 'string' ? parseFloat(value) : (value as number)\n}\n\nexport interface TreemapBuildResult {\n treemapData: TreemapDatum[]\n isNumericSeries: boolean\n seriesField?: string\n}\n\n/** Build treemap rows from the new (configured) chart config format. */\nfunction buildFromConfig(\n data: Record<string, any>[],\n chartConfig: ChartAxisConfig,\n queryObject: CubeQuery | undefined,\n colorPalette: ColorPalette | undefined\n): TreemapBuildResult {\n const xAxisField = pickField(chartConfig.xAxis)\n const yAxisField = pickField(chartConfig.yAxis)\n const seriesField = Array.isArray(chartConfig.series) ? chartConfig.series[0] : chartConfig.series\n const granularity = getFieldGranularity(queryObject, xAxisField)\n\n const nameOf = (item: Record<string, any>) =>\n formatTimeValue(item[xAxisField], granularity) || String(item[xAxisField]) || 'Unknown'\n\n if (!seriesField) {\n // No series grouping - use index-based colors\n const treemapData = data.map((item, index) => ({\n name: nameOf(item),\n size: toNumber(item[yAxisField]),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n }))\n return { treemapData, isNumericSeries: false, seriesField }\n }\n\n // Check if series field is numeric for color scaling\n const seriesValues = data\n .map((item) => seriesNumber(item[seriesField]))\n .filter((val) => !isNaN(val))\n const isNumericSeries =\n seriesValues.length === data.length && seriesValues.every((val) => typeof val === 'number')\n\n if (isNumericSeries) {\n const colorScale = scaleQuantize<string>()\n .domain([Math.min(...seriesValues), Math.max(...seriesValues)])\n .range(CHART_COLORS_GRADIENT)\n const treemapData = data.map((item) => ({\n name: nameOf(item),\n size: toNumber(item[yAxisField]),\n fill: colorScale(seriesNumber(item[seriesField])),\n series: String(item[seriesField])\n }))\n return { treemapData, isNumericSeries, seriesField }\n }\n\n const uniqueSeriesValues = [...new Set(data.map((item) => String(item[seriesField])))]\n const colorScale = scaleOrdinal<string>()\n .domain(uniqueSeriesValues)\n .range(colorPalette?.colors || CHART_COLORS)\n const treemapData = data.map((item) => ({\n name: nameOf(item),\n size: toNumber(item[yAxisField]),\n fill: colorScale(String(item[seriesField])),\n series: String(item[seriesField])\n }))\n return { treemapData, isNumericSeries, seriesField }\n}\n\n/** Resolve a friendly name for a legacy/auto-detected row. */\nfunction legacyName(value: unknown): string {\n if (typeof value === 'boolean') return value ? 'Active' : 'Inactive'\n if (value === 'true' || value === 'false') return value === 'true' ? 'Active' : 'Inactive'\n return String(value)\n}\n\n/** Build treemap rows by auto-detecting name/size fields (legacy format). */\nfunction buildFromAutoDetect(\n data: Record<string, any>[],\n colorPalette: ColorPalette | undefined\n): TreemapBuildResult | null {\n const firstRow = data[0]\n const keys = Object.keys(firstRow)\n\n const nameField =\n keys.find(\n (key) =>\n typeof firstRow[key] === 'string' ||\n key.toLowerCase().includes('name') ||\n key.toLowerCase().includes('label') ||\n key.toLowerCase().includes('category')\n ) || keys[0]\n\n const sizeField =\n keys.find((key) => key.toLowerCase().includes('size')) ||\n keys.find((key) => typeof firstRow[key] === 'number' && key !== nameField) ||\n keys[1]\n\n if (!sizeField) return null\n\n const treemapData = data.map((item, index) => ({\n name: legacyName(item[nameField]),\n size: toNumber(item[sizeField]),\n fill: (colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length]\n }))\n return { treemapData, isNumericSeries: false, seriesField: undefined }\n}\n\n/**\n * Build treemap data (config or auto-detect), then drop non-positive sizes.\n * Returns `null` when the legacy path can't find a usable size field.\n */\nexport function buildTreemapData(\n data: Record<string, any>[],\n chartConfig: ChartAxisConfig | undefined,\n queryObject: CubeQuery | undefined,\n colorPalette: ColorPalette | undefined\n): TreemapBuildResult | null {\n const result =\n chartConfig?.xAxis && chartConfig?.yAxis\n ? buildFromConfig(data, chartConfig, queryObject, colorPalette)\n : buildFromAutoDetect(data, colorPalette)\n\n if (!result) return null\n\n return {\n ...result,\n treemapData: result.treemapData.filter((item) => item.size != null && item.size > 0)\n }\n}\n\n/** Min/max of the (numeric) series field across the raw rows. */\nexport function seriesMinMax(\n data: Record<string, any>[],\n seriesField: string\n): { min: number; max: number } {\n const values = data.map((item) => seriesNumber(item[seriesField]))\n return { min: Math.min(...values), max: Math.max(...values) }\n}\n\n/** Format a numeric value with the optional axis format (or `.toFixed(2)`). */\nexport function formatSeriesValue(value: number, format: AxisFormatConfig | undefined): string {\n return format ? formatAxisValue(value, format) : value.toFixed(2)\n}\n\nexport interface LegendEntry {\n value: string\n type: 'rect'\n color: string\n}\n\n/**\n * Build the legend entries for the treemap: a gradient ramp for numeric series,\n * or discrete swatches for categorical series. Empty when not applicable.\n */\nexport function buildTreemapLegend(\n data: Record<string, any>[],\n treemapData: TreemapDatum[],\n showLegend: boolean,\n seriesField: string | undefined,\n isNumericSeries: boolean,\n leftYAxisFormat: AxisFormatConfig | undefined\n): LegendEntry[] {\n if (!showLegend || !seriesField) return []\n\n if (isNumericSeries) {\n const { min, max } = seriesMinMax(data, seriesField)\n return CHART_COLORS_GRADIENT.map((color, index) => {\n const ratio = index / (CHART_COLORS_GRADIENT.length - 1)\n const value = min + (max - min) * ratio\n return { value: formatSeriesValue(value, leftYAxisFormat), type: 'rect' as const, color }\n })\n }\n\n const uniqueSeries = [...new Set(treemapData.map((item) => item.series).filter(Boolean))]\n if (uniqueSeries.length > 1) {\n return uniqueSeries.map((series, index) => ({\n value: series as string,\n type: 'rect' as const,\n color: CHART_COLORS[index % CHART_COLORS.length]\n }))\n }\n return []\n}\n\n/** Adjust the outer container height to make room for a legend, if present. */\nexport function adjustHeightForLegend(\n height: string | number,\n hasLegend: boolean\n): string | number {\n if (!hasLegend) return height\n if (typeof height === 'string' && height.includes('%')) return height\n if (typeof height === 'number') return height + 60\n return `calc(${height} + 60px)`\n}\n","import React from 'react'\nimport { CHART_COLORS } from '../../utils/chartConstants.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport type { AxisFormatConfig, ChartAxisConfig, ColorPalette, CubeQuery } from '../../types.js'\nimport type { ChartDataPointClickEvent } from '../../types/drill.js'\nimport type { TreemapDatum } from './TreeMapChart.helpers.js'\n\ninterface TreeMapContentOptions {\n treemapData: TreemapDatum[]\n colorPalette?: ColorPalette\n hoveredIndex: number | null\n setHoveredIndex: (index: number | null) => void\n leftYAxisFormat?: AxisFormatConfig\n drillEnabled?: boolean\n onDataPointClick?: (event: ChartDataPointClickEvent) => void\n queryObject?: CubeQuery\n chartConfig?: ChartAxisConfig\n}\n\n/** Fill opacity for a treemap cell given the currently hovered index. */\nfunction cellOpacity(hoveredIndex: number | null, index: number): number {\n if (hoveredIndex === null) return 0.8\n return hoveredIndex === index ? 1 : 0.6\n}\n\n/** Format the size label shown inside a treemap cell. */\nfunction formatSize(size: unknown, format: AxisFormatConfig | undefined): string {\n if (format) return formatAxisValue(size as number, format)\n return typeof size === 'number' ? size.toLocaleString() : String(size)\n}\n\n/**\n * Build the Recharts `content` renderer for treemap cells.\n *\n * Encapsulates the per-cell rect + foreignObject overlay, hover state and drill\n * click handler that previously lived inline in TreeMapChart (the highest-\n * complexity hot spots). Behaviour is identical to the original.\n */\nexport function makeTreeMapContent({\n treemapData,\n colorPalette,\n hoveredIndex,\n setHoveredIndex,\n leftYAxisFormat,\n drillEnabled,\n onDataPointClick,\n queryObject,\n chartConfig,\n}: TreeMapContentOptions) {\n return function CustomizedContent(props: any) {\n const { x, y, width, height, index, name, size } = props\n\n if (width < 20 || height < 20) return null // Skip very small cells\n\n const handleClick = (event: React.MouseEvent) => {\n event.stopPropagation()\n const cellData = treemapData[index]\n if (cellData && onDataPointClick) {\n // Use query measures for proper field name (chartConfig.yAxis may hold labels)\n const measureField = queryObject?.measures?.[0] || chartConfig?.yAxis?.[0] || ''\n onDataPointClick({\n dataPoint: cellData,\n clickedField: measureField,\n xValue: name,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event\n })\n }\n }\n\n const fill =\n treemapData[index]?.fill ||\n ((colorPalette?.colors && colorPalette.colors[index % colorPalette.colors.length]) ||\n CHART_COLORS[index % CHART_COLORS.length])\n\n return (\n <g>\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n style={{\n fill,\n fillOpacity: cellOpacity(hoveredIndex, index),\n stroke: '#fff',\n strokeWidth: 2,\n cursor: drillEnabled ? 'pointer' : 'default',\n pointerEvents: 'all'\n }}\n onMouseEnter={() => setHoveredIndex(index)}\n onMouseLeave={() => setHoveredIndex(null)}\n onClick={drillEnabled && onDataPointClick ? handleClick : undefined}\n />\n <foreignObject\n x={x}\n y={y}\n width={width}\n height={height}\n style={{ pointerEvents: 'none', overflow: 'visible' }}\n >\n <div\n style={{\n width: '100%',\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '4px',\n boxSizing: 'border-box',\n color: '#ffffff',\n textShadow: '0 1px 2px rgba(0,0,0,0.8)',\n fontFamily: 'system-ui, -apple-system, sans-serif',\n overflow: 'hidden'\n }}\n >\n {width > 40 && height > 30 && (\n <div\n style={{\n fontSize: `${Math.max(10, Math.min(width / 8, height / 8, 16))}px`,\n fontWeight: '600',\n textAlign: 'center',\n lineHeight: '1.2',\n marginBottom: width > 60 && height > 45 ? '4px' : '0',\n wordBreak: 'break-word',\n hyphens: 'auto'\n }}\n >\n {name}\n </div>\n )}\n {width > 60 && height > 45 && (\n <div\n style={{\n fontSize: `${Math.max(8, Math.min(width / 10, height / 10, 14))}px`,\n textAlign: 'center',\n opacity: 0.9\n }}\n >\n {formatSize(size, leftYAxisFormat)}\n </div>\n )}\n </div>\n </foreignObject>\n </g>\n )\n }\n}\n","import { CHART_COLORS_GRADIENT } from '../../utils/chartConstants.js'\nimport type { AxisFormatConfig } from '../../types.js'\nimport {\n seriesMinMax,\n formatSeriesValue,\n type LegendEntry\n} from './TreeMapChart.helpers.js'\n\ninterface TreeMapLegendProps {\n isNumericSeries: boolean\n seriesField?: string\n seriesLabel: string\n legendPayload: LegendEntry[]\n data: Record<string, any>[]\n leftYAxisFormat?: AxisFormatConfig\n}\n\n/** Gradient ramp legend for a numeric series field. */\nfunction NumericLegend({\n seriesLabel,\n data,\n seriesField,\n leftYAxisFormat,\n}: {\n seriesLabel: string\n data: Record<string, any>[]\n seriesField: string\n leftYAxisFormat?: AxisFormatConfig\n}) {\n const { min, max } = seriesMinMax(data, seriesField)\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center\">\n <div className=\"dc:text-xs dc:font-semibold text-dc-text-primary dc:mb-2\">\n {seriesLabel}\n </div>\n <div className=\"dc:flex dc:items-center dc:gap-2\">\n <span className=\"dc:text-xs text-dc-text-muted\">\n {formatSeriesValue(min, leftYAxisFormat)}\n </span>\n <div\n className=\"dc:h-4 dc:rounded-sm\"\n style={{\n width: '200px',\n background: `linear-gradient(to right, ${CHART_COLORS_GRADIENT.join(', ')})`\n }}\n />\n <span className=\"dc:text-xs text-dc-text-muted\">\n {formatSeriesValue(max, leftYAxisFormat)}\n </span>\n </div>\n </div>\n )\n}\n\n/** Discrete swatch legend for a categorical series field. */\nfunction CategoricalLegend({ legendPayload }: { legendPayload: LegendEntry[] }) {\n return (\n <div className=\"dc:flex dc:flex-wrap dc:justify-center dc:gap-4\">\n {legendPayload.map((item, index) => (\n <div key={index} className=\"dc:flex dc:items-center dc:gap-2\">\n <div className=\"dc:w-3 dc:h-3 rounded-xs\" style={{ backgroundColor: item.color }} />\n <span className=\"dc:text-xs text-dc-text-muted\">{item.value}</span>\n </div>\n ))}\n </div>\n )\n}\n\n/** Treemap legend wrapper — gradient for numeric series, swatches otherwise. */\nexport function TreeMapLegend({\n isNumericSeries,\n seriesField,\n seriesLabel,\n legendPayload,\n data,\n leftYAxisFormat,\n}: TreeMapLegendProps) {\n return (\n <div className=\"dc:flex dc:justify-center dc:items-center dc:mt-4 dc:pb-2\">\n {isNumericSeries && seriesField ? (\n <NumericLegend\n seriesLabel={seriesLabel}\n data={data}\n seriesField={seriesField}\n leftYAxisFormat={leftYAxisFormat}\n />\n ) : (\n <CategoricalLegend legendPayload={legendPayload} />\n )}\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { Treemap } from 'recharts'\nimport ChartContainer from './ChartContainer.js'\nimport ChartTooltip from './ChartTooltip.js'\nimport { ChartEmptyState, ChartConfigError, ChartRenderError } from './ChartStates.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel.js'\nimport {\n buildTreemapData,\n buildTreemapLegend,\n adjustHeightForLegend\n} from './TreeMapChart.helpers.js'\nimport { makeTreeMapContent } from './TreeMapContent.js'\nimport { TreeMapLegend } from './TreeMapLegend.js'\nimport type { ChartProps } from '../../types.js'\n\nconst TreeMapChart = React.memo(function TreeMapChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette,\n onDataPointClick,\n drillEnabled\n}: ChartProps) {\n const { t } = useTranslation()\n const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)\n // Use specialized hook to avoid re-renders from unrelated context changes\n const getFieldLabel = useCubeFieldLabel()\n\n try {\n const safeDisplayConfig = {\n showTooltip: displayConfig?.showTooltip ?? true,\n showLegend: displayConfig?.showLegend ?? true,\n leftYAxisFormat: displayConfig?.leftYAxisFormat\n }\n\n if (!data || data.length === 0) {\n return <ChartEmptyState height={height} hint={t('chart.runtime.noDataHint.treemap')} />\n }\n\n // Build treemap rows (config or auto-detect) — null means no usable size field\n const built = buildTreemapData(data, chartConfig, queryObject, colorPalette)\n if (!built) {\n return <ChartConfigError height={height} hint={t('chart.runtime.configErrorHint.treemapNumeric')} />\n }\n\n const { treemapData, isNumericSeries, seriesField } = built\n\n if (treemapData.length === 0) {\n return (\n <ChartEmptyState\n height={height}\n titleKey=\"chart.runtime.noValidData\"\n hint=\"No valid data points for treemap chart after transformation\"\n />\n )\n }\n\n // Custom content renderer for treemap cells with HTML overlays\n const CustomizedContent = makeTreeMapContent({\n treemapData,\n colorPalette,\n hoveredIndex,\n setHoveredIndex,\n leftYAxisFormat: safeDisplayConfig.leftYAxisFormat,\n drillEnabled,\n onDataPointClick,\n queryObject,\n chartConfig\n })\n\n // Build legend payload (gradient for numeric series, swatches otherwise)\n const legendPayload = buildTreemapLegend(\n data,\n treemapData,\n safeDisplayConfig.showLegend,\n seriesField,\n isNumericSeries,\n safeDisplayConfig.leftYAxisFormat\n )\n\n const hasLegend = safeDisplayConfig.showLegend && legendPayload.length > 0\n const adjustedHeight = adjustHeightForLegend(height, hasLegend)\n\n return (\n <div className=\"dc:w-full\" style={{ height: adjustedHeight }}>\n <ChartContainer height={hasLegend ? `calc(100% - 50px)` : \"100%\"}>\n <Treemap\n data={treemapData}\n dataKey=\"size\"\n aspectRatio={4 / 3}\n stroke=\"#fff\"\n content={<CustomizedContent />}\n >\n {safeDisplayConfig.showTooltip && (\n <ChartTooltip\n formatter={safeDisplayConfig.leftYAxisFormat\n ? (value: any, name: string) => [formatAxisValue(value, safeDisplayConfig.leftYAxisFormat), name]\n : undefined\n }\n />\n )}\n </Treemap>\n </ChartContainer>\n\n {/* Custom Legend outside ChartContainer */}\n {hasLegend && (\n <TreeMapLegend\n isNumericSeries={isNumericSeries}\n seriesField={seriesField}\n seriesLabel={seriesField ? getFieldLabel(seriesField) : ''}\n legendPayload={legendPayload}\n data={data}\n leftYAxisFormat={safeDisplayConfig.leftYAxisFormat}\n />\n )}\n </div>\n )\n } catch (error) {\n // 'TreeMapChart rendering error\n return <ChartRenderError height={height} chartType=\"TreeMap Chart\" error={error} />\n }\n})\n\nexport default TreeMapChart\n"],"mappings":";;;;;;;;AAqBA,SAAS,EAAU,GAA8C;CAE/D,OADK,IACE,MAAM,QAAQ,CAAK,IAAI,EAAM,KAAK,IADtB;AAErB;AAGA,SAAS,EAAS,GAAwB;CACxC,OAAO,OAAO,KAAU,WAAW,WAAW,CAAK,IAAM,KAAoB;AAC/E;AAGA,SAAS,EAAa,GAAwB;CAC5C,OAAO,OAAO,KAAU,WAAW,WAAW,CAAK,IAAK;AAC1D;AASA,SAAS,EACP,GACA,GACA,GACA,GACoB;CACpB,IAAM,IAAa,EAAU,EAAY,KAAK,GACxC,IAAa,EAAU,EAAY,KAAK,GACxC,IAAc,MAAM,QAAQ,EAAY,MAAM,IAAI,EAAY,OAAO,KAAK,EAAY,QACtF,IAAc,EAAoB,GAAa,CAAU,GAEzD,KAAU,MACd,EAAgB,EAAK,IAAa,CAAW,KAAK,OAAO,EAAK,EAAW,KAAK;CAEhF,IAAI,CAAC,GAQH,OAAO;EAAE,aANW,EAAK,KAAK,GAAM,OAAW;GAC7C,MAAM,EAAO,CAAI;GACjB,MAAM,EAAS,EAAK,EAAW;GAC/B,MAAO,GAAc,UAAU,EAAa,OAAO,IAAQ,EAAa,OAAO,WAC7E,EAAa,IAAQ,EAAa;EACtC,EACS;EAAa,iBAAiB;EAAO;CAAY;CAI5D,IAAM,IAAe,EAClB,KAAK,MAAS,EAAa,EAAK,EAAY,CAAC,EAC7C,QAAQ,MAAQ,CAAC,MAAM,CAAG,CAAC,GACxB,IACJ,EAAa,WAAW,EAAK,UAAU,EAAa,OAAO,MAAQ,OAAO,KAAQ,QAAQ;CAE5F,IAAI,GAAiB;EACnB,IAAM,IAAa,EAAsB,EACtC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAY,GAAG,KAAK,IAAI,GAAG,CAAY,CAAC,CAAC,EAC7D,MAAM,CAAqB;EAO9B,OAAO;GAAE,aANW,EAAK,KAAK,OAAU;IACtC,MAAM,EAAO,CAAI;IACjB,MAAM,EAAS,EAAK,EAAW;IAC/B,MAAM,EAAW,EAAa,EAAK,EAAY,CAAC;IAChD,QAAQ,OAAO,EAAK,EAAY;GAClC,EACS;GAAa;GAAiB;EAAY;CACrD;CAEA,IAAM,IAAqB,CAAC,GAAG,IAAI,IAAI,EAAK,KAAK,MAAS,OAAO,EAAK,EAAY,CAAC,CAAC,CAAC,GAC/E,IAAa,EAAqB,EACrC,OAAO,CAAkB,EACzB,MAAM,GAAc,UAAU,CAAY;CAO7C,OAAO;EAAE,aANW,EAAK,KAAK,OAAU;GACtC,MAAM,EAAO,CAAI;GACjB,MAAM,EAAS,EAAK,EAAW;GAC/B,MAAM,EAAW,OAAO,EAAK,EAAY,CAAC;GAC1C,QAAQ,OAAO,EAAK,EAAY;EAClC,EACS;EAAa;EAAiB;CAAY;AACrD;AAGA,SAAS,EAAW,GAAwB;CAG1C,OAFI,OAAO,KAAU,YAAkB,IAAQ,WAAW,aACtD,MAAU,UAAU,MAAU,UAAgB,MAAU,SAAS,WAAW,aACzE,OAAO,CAAK;AACrB;AAGA,SAAS,EACP,GACA,GAC2B;CAC3B,IAAM,IAAW,EAAK,IAChB,IAAO,OAAO,KAAK,CAAQ,GAE3B,IACJ,EAAK,MACF,MACC,OAAO,EAAS,MAAS,YACzB,EAAI,YAAY,EAAE,SAAS,MAAM,KACjC,EAAI,YAAY,EAAE,SAAS,OAAO,KAClC,EAAI,YAAY,EAAE,SAAS,UAAU,CACzC,KAAK,EAAK,IAEN,IACJ,EAAK,MAAM,MAAQ,EAAI,YAAY,EAAE,SAAS,MAAM,CAAC,KACrD,EAAK,MAAM,MAAQ,OAAO,EAAS,MAAS,YAAY,MAAQ,CAAS,KACzE,EAAK;CAUP,OARK,IAQE;EAAE,aANW,EAAK,KAAK,GAAM,OAAW;GAC7C,MAAM,EAAW,EAAK,EAAU;GAChC,MAAM,EAAS,EAAK,EAAU;GAC9B,MAAO,GAAc,UAAU,EAAa,OAAO,IAAQ,EAAa,OAAO,WAC7E,EAAa,IAAQ,EAAa;EACtC,EACS;EAAa,iBAAiB;EAAO,aAAa,KAAA;CAAU,IAR9C;AASzB;AAMA,SAAgB,EACd,GACA,GACA,GACA,GAC2B;CAC3B,IAAM,IACJ,GAAa,SAAS,GAAa,QAC/B,EAAgB,GAAM,GAAa,GAAa,CAAY,IAC5D,EAAoB,GAAM,CAAY;CAI5C,OAFK,IAEE;EACL,GAAG;EACH,aAAa,EAAO,YAAY,QAAQ,MAAS,EAAK,QAAQ,QAAQ,EAAK,OAAO,CAAC;CACrF,IALoB;AAMtB;AAGA,SAAgB,EACd,GACA,GAC8B;CAC9B,IAAM,IAAS,EAAK,KAAK,MAAS,EAAa,EAAK,EAAY,CAAC;CACjE,OAAO;EAAE,KAAK,KAAK,IAAI,GAAG,CAAM;EAAG,KAAK,KAAK,IAAI,GAAG,CAAM;CAAE;AAC9D;AAGA,SAAgB,EAAkB,GAAe,GAA8C;CAC7F,OAAO,IAAS,EAAgB,GAAO,CAAM,IAAI,EAAM,QAAQ,CAAC;AAClE;AAYA,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA,GACe;CACf,IAAI,CAAC,KAAc,CAAC,GAAa,OAAO,CAAC;CAEzC,IAAI,GAAiB;EACnB,IAAM,EAAE,QAAK,WAAQ,EAAa,GAAM,CAAW;EACnD,OAAO,EAAsB,KAAK,GAAO,MAAU;GACjD,IAAM,IAAQ,KAAS,EAAsB,SAAS;GAEtD,OAAO;IAAE,OAAO,EADF,KAAO,IAAM,KAAO,GACO,CAAe;IAAG,MAAM;IAAiB;GAAM;EAC1F,CAAC;CACH;CAEA,IAAM,IAAe,CAAC,GAAG,IAAI,IAAI,EAAY,KAAK,MAAS,EAAK,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC;CAQxF,OAPI,EAAa,SAAS,IACjB,EAAa,KAAK,GAAQ,OAAW;EAC1C,OAAO;EACP,MAAM;EACN,OAAO,EAAa,IAAQ,EAAa;CAC3C,EAAE,IAEG,CAAC;AACV;AAGA,SAAgB,EACd,GACA,GACiB;CAIjB,OAHI,CAAC,KACD,OAAO,KAAW,YAAY,EAAO,SAAS,GAAG,IAAU,IAC3D,OAAO,KAAW,WAAiB,IAAS,KACzC,QAAQ,EAAO;AACxB;;;AC/MA,SAAS,EAAY,GAA6B,GAAuB;CAEvE,OADI,MAAiB,OAAa,KAC3B,MAAiB,IAAQ,IAAI;AACtC;AAGA,SAAS,EAAW,GAAe,GAA8C;CAE/E,OADI,IAAe,EAAgB,GAAgB,CAAM,IAClD,OAAO,KAAS,WAAW,EAAK,eAAe,IAAI,OAAO,CAAI;AACvE;AASA,SAAgB,EAAmB,EACjC,gBACA,iBACA,iBACA,oBACA,oBACA,iBACA,qBACA,gBACA,kBACwB;CACxB,OAAO,SAA2B,GAAY;EAC5C,IAAM,EAAE,MAAG,MAAG,UAAO,WAAQ,UAAO,SAAM,YAAS;EAyBnD,OAvBI,IAAQ,MAAM,IAAS,KAAW,OAwBpC,kBAAC,KAAD,EAAA,UAAA,CACE,kBAAC,QAAD;GACK;GACA;GACI;GACC;GACR,OAAO;IACL,MAZN,EAAY,IAAQ,QAClB,GAAc,UAAU,EAAa,OAAO,IAAQ,EAAa,OAAO,WACxE,EAAa,IAAQ,EAAa;IAW9B,aAAa,EAAY,GAAc,CAAK;IAC5C,QAAQ;IACR,aAAa;IACb,QAAQ,IAAe,YAAY;IACnC,eAAe;GACjB;GACA,oBAAoB,EAAgB,CAAK;GACzC,oBAAoB,EAAgB,IAAI;GACxC,SAAS,KAAgB,KAtCV,MAA4B;IAC/C,EAAM,gBAAgB;IACtB,IAAM,IAAW,EAAY;IAC7B,AAAI,KAAY,KAGd,EAAiB;KACf,WAAW;KACX,cAHmB,GAAa,WAAW,MAAM,GAAa,QAAQ,MAAM;KAI5E,QAAQ;KACR,UAAU;MAAE,GAAG,EAAM;MAAS,GAAG,EAAM;KAAQ;KAC/C,aAAa;IACf,CAAC;GAEL,IAwBgE,KAAA;EAC3D,CAAA,GACD,kBAAC,iBAAD;GACK;GACA;GACI;GACC;GACR,OAAO;IAAE,eAAe;IAAQ,UAAU;GAAU;aAEpD,kBAAC,OAAD;IACE,OAAO;KACL,OAAO;KACP,QAAQ;KACR,SAAS;KACT,eAAe;KACf,YAAY;KACZ,gBAAgB;KAChB,SAAS;KACT,WAAW;KACX,OAAO;KACP,YAAY;KACZ,YAAY;KACZ,UAAU;IACZ;cAdF,CAgBG,IAAQ,MAAM,IAAS,MACtB,kBAAC,OAAD;KACE,OAAO;MACL,UAAU,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,IAAQ,GAAG,IAAS,GAAG,EAAE,CAAC,EAAE;MAC/D,YAAY;MACZ,WAAW;MACX,YAAY;MACZ,cAAc,IAAQ,MAAM,IAAS,KAAK,QAAQ;MAClD,WAAW;MACX,SAAS;KACX;eAEC;IACE,CAAA,GAEN,IAAQ,MAAM,IAAS,MACtB,kBAAC,OAAD;KACE,OAAO;MACL,UAAU,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,IAAQ,IAAI,IAAS,IAAI,EAAE,CAAC,EAAE;MAChE,WAAW;MACX,SAAS;KACX;eAEC,EAAW,GAAM,CAAe;IAC9B,CAAA,CAEJ;;EACQ,CAAA,CACd,EAAA,CAAA;CAEP;AACF;;;AClIA,SAAS,EAAc,EACrB,gBACA,SACA,gBACA,sBAMC;CACD,IAAM,EAAE,QAAK,WAAQ,EAAa,GAAM,CAAW;CACnD,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ;EACE,CAAA,GACL,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,QAAD;KAAM,WAAU;eACb,EAAkB,GAAK,CAAe;IACnC,CAAA;IACN,kBAAC,OAAD;KACE,WAAU;KACV,OAAO;MACL,OAAO;MACP,YAAY,6BAA6B,EAAsB,KAAK,IAAI,EAAE;KAC5E;IACD,CAAA;IACD,kBAAC,QAAD;KAAM,WAAU;eACb,EAAkB,GAAK,CAAe;IACnC,CAAA;GACH;IACF;;AAET;AAGA,SAAS,EAAkB,EAAE,oBAAmD;CAC9E,OACE,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAc,KAAK,GAAM,MACxB,kBAAC,OAAD;GAAiB,WAAU;aAA3B,CACE,kBAAC,OAAD;IAAK,WAAU;IAA2B,OAAO,EAAE,iBAAiB,EAAK,MAAM;GAAI,CAAA,GACnF,kBAAC,QAAD;IAAM,WAAU;cAAiC,EAAK;GAAY,CAAA,CAC/D;KAHK,CAGL,CACN;CACE,CAAA;AAET;AAGA,SAAgB,EAAc,EAC5B,oBACA,gBACA,gBACA,kBACA,SACA,sBACqB;CACrB,OACE,kBAAC,OAAD;EAAK,WAAU;YACZ,KAAmB,IAClB,kBAAC,GAAD;GACe;GACP;GACO;GACI;EAClB,CAAA,IAED,kBAAC,GAAD,EAAkC,iBAAgB,CAAA;CAEjD,CAAA;AAET;;;iDC1EM,IAAe,EAAM,KAAK,SAAsB,EACpD,SACA,gBACA,mBAAgB,CAAC,GACjB,gBACA,YAAS,QACT,iBACA,qBACA,mBACa;CACb,IAAM,EAAE,SAAM,EAAe,GACvB,CAAC,GAAc,KAAmB,EAAwB,IAAI,GAE9D,IAAgB,EAAkB;CAExC,IAAI;EACF,IAAM,IAAoB;GACxB,aAAa,GAAe,eAAe;GAC3C,YAAY,GAAe,cAAc;GACzC,iBAAiB,GAAe;EAClC;EAEA,IAAI,CAAC,KAAQ,EAAK,WAAW,GAC3B,OAAO,kBAAC,GAAD;GAAyB;GAAQ,MAAM,EAAE,kCAAkC;EAAI,CAAA;EAIxF,IAAM,IAAQ,EAAiB,GAAM,GAAa,GAAa,CAAY;EAC3E,IAAI,CAAC,GACH,OAAO,kBAAC,GAAD;GAA0B;GAAQ,MAAM,EAAE,8CAA8C;EAAI,CAAA;EAGrG,IAAM,EAAE,gBAAa,oBAAiB,mBAAgB;EAEtD,IAAI,EAAY,WAAW,GACzB,OACE,kBAAC,GAAD;GACU;GACR,UAAS;GACT,MAAK;EACN,CAAA;EAKL,IAAM,IAAoB,EAAmB;GAC3C;GACA;GACA;GACA;GACA,iBAAiB,EAAkB;GACnC;GACA;GACA;GACA;EACF,CAAC,GAGK,IAAgB,EACpB,GACA,GACA,EAAkB,YAClB,GACA,GACA,EAAkB,eACpB,GAEM,IAAY,EAAkB,cAAc,EAAc,SAAS;EAGzE,OACE,kBAAC,OAAD;GAAK,WAAU;GAAY,OAAO,EAAE,QAHf,EAAsB,GAAQ,CAGP,EAAe;aAA3D,CACE,kBAAC,GAAD;IAAgB,QAAQ,IAAY,sBAAsB;cACxD,kBAAC,GAAD;KACE,MAAM;KACN,SAAQ;KACR,aAAa,IAAI;KACjB,QAAO;KACP,SAAS,kBAAC,GAAD,CAAoB,CAAA;eAE5B,EAAkB,eACjB,kBAAC,GAAD,EACE,WAAW,EAAkB,mBACxB,GAAY,MAAiB,CAAC,EAAgB,GAAO,EAAkB,eAAe,GAAG,CAAI,IAC9F,KAAA,EAEL,CAAA;IAEI,CAAA;GACK,CAAA,GAGf,KACC,kBAAC,GAAD;IACmB;IACJ;IACb,aAAa,IAAc,EAAc,CAAW,IAAI;IACzC;IACT;IACN,iBAAiB,EAAkB;GACpC,CAAA,CAEA;;CAET,SAAS,GAAO;EAEd,OAAO,kBAAC,GAAD;GAA0B;GAAQ,WAAU;GAAuB;EAAQ,CAAA;CACpF;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-waterfall-DyvQReN5.js","names":[],"sources":["../../../src/client/components/charts/WaterfallChart.tsx"],"sourcesContent":["import React, { useMemo } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport { ComposedChart, Bar, Line, XAxis, YAxis, CartesianGrid, Cell, LabelList, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer'\nimport ChartTooltip from './ChartTooltip'\nimport AngledXAxisTick from './AngledXAxisTick'\nimport { CHART_MARGINS } from '../../utils/chartConstants'\nimport { formatAxisValue } from '../../utils/chartUtils'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel'\nimport type { ChartProps } from '../../types'\n\nconst POSITIVE_COLOR = '#22c55e'\nconst NEGATIVE_COLOR = '#ef4444'\nconst TOTAL_COLOR = '#6366f1'\nconst CONNECTOR_COLOR = '#94a3b8'\n\ninterface WaterfallDataPoint {\n label: string\n value: number\n runningBase: number\n isTotal: boolean\n isNegative: boolean\n displayValue: number\n originalIndex: number\n}\n\nfunction transformToWaterfall(\n data: Record<string, unknown>[],\n xField: string,\n yField: string,\n showTotal: boolean,\n getFieldLabel: (field: string) => string\n): WaterfallDataPoint[] {\n let running = 0\n const result: WaterfallDataPoint[] = data.map((row, i) => {\n const label = String(row[xField] ?? `Row ${i + 1}`)\n const rawValue = row[yField]\n const parsed = typeof rawValue === 'number' ? rawValue : parseFloat(String(rawValue ?? ''))\n const value = isNaN(parsed) ? 0 : parsed\n const isNegative = value < 0\n const base = isNegative ? running + value : running\n const point: WaterfallDataPoint = {\n label,\n value: Math.abs(value),\n runningBase: base,\n isTotal: false,\n isNegative,\n displayValue: value,\n originalIndex: i,\n }\n running += value\n return point\n })\n\n if (showTotal) {\n const totalLabel = getFieldLabel(yField) || 'Total'\n result.push({\n label: totalLabel,\n value: Math.abs(running),\n runningBase: running >= 0 ? 0 : running,\n isTotal: true,\n isNegative: running < 0,\n displayValue: running,\n originalIndex: result.length,\n })\n }\n\n return result\n}\n\ninterface ValueLabelProps {\n x?: number\n y?: number\n width?: number\n value?: number\n isNegative?: boolean\n displayValue?: number\n}\n\nfunction ValueLabel(props: ValueLabelProps) {\n const { x = 0, y = 0, width = 0, value = 0, isNegative, displayValue } = props\n if (displayValue === undefined || displayValue === null) return null\n const numericValue = Number(displayValue)\n const isNeg = isNegative || numericValue < 0\n const yPos = isNeg ? y + value + 14 : y - 6\n return (\n <text\n x={x + width / 2}\n y={yPos}\n fill=\"currentColor\"\n textAnchor=\"middle\"\n fontSize={11}\n >\n {numericValue >= 0 ? '+' : ''}{numericValue.toLocaleString()}\n </text>\n )\n}\n\nconst WaterfallChart = React.memo(function WaterfallChart({\n data,\n chartConfig,\n displayConfig = {},\n height = '100%',\n onDataPointClick,\n drillEnabled,\n}: ChartProps) {\n const { t } = useTranslation()\n const getFieldLabel = useCubeFieldLabel()\n\n const showTotal = displayConfig?.showTotal ?? true\n const showConnectorLine = displayConfig?.showConnectorLine ?? true\n const showDataLabels = displayConfig?.showDataLabels ?? false\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\n const { xAxisField, yAxisField, configError } = useMemo(() => {\n const xAxisField: string | undefined = Array.isArray(chartConfig?.xAxis)\n ? chartConfig.xAxis[0]\n : chartConfig?.x\n const yAxisField: string | undefined = Array.isArray(chartConfig?.yAxis)\n ? chartConfig.yAxis[0]\n : chartConfig?.y?.[0]\n const configError =\n !xAxisField || !yAxisField\n ? 'Waterfall chart requires an X-axis dimension and a Y-axis measure'\n : null\n return { xAxisField, yAxisField, configError }\n }, [chartConfig])\n\n const waterfallData = useMemo(() => {\n if (configError || !data || data.length === 0 || !xAxisField || !yAxisField) return []\n return transformToWaterfall(\n data as Record<string, unknown>[],\n xAxisField,\n yAxisField,\n showTotal,\n getFieldLabel\n )\n }, [data, xAxisField, yAxisField, showTotal, getFieldLabel, configError])\n\n const connectorData = useMemo(() => {\n if (!showConnectorLine || waterfallData.length === 0) return []\n return waterfallData.map((d) => {\n const connectorY = d.isNegative ? d.runningBase : d.runningBase + d.value\n return { label: d.label, _connector: connectorY }\n })\n }, [waterfallData, showConnectorLine])\n\n const chartData = useMemo(() => {\n return waterfallData.map((d, i) => ({\n ...d,\n _connector: connectorData[i]?._connector,\n }))\n }, [waterfallData, connectorData])\n\n try {\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.waterfall')}</div>\n </div>\n </div>\n )\n }\n\n if (configError) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.configError')}</div>\n <div className=\"dc:text-xs\">{configError}</div>\n </div>\n </div>\n )\n }\n return (\n <div className=\"dc:relative dc:w-full\" style={{ height }}>\n <ChartContainer height=\"100%\">\n <ComposedChart data={chartData} margin={{ ...CHART_MARGINS, left: 40 }} accessibilityLayer={false}>\n <CartesianGrid strokeDasharray=\"3 3\" style={{ pointerEvents: 'none' }} />\n <XAxis dataKey=\"label\" type=\"category\" tick={<AngledXAxisTick />} height={60} />\n <YAxis\n tick={{ fontSize: 12 }}\n tickFormatter={yAxisFormat ? (v) => formatAxisValue(v, yAxisFormat) : undefined}\n />\n <ChartTooltip\n formatter={(value: any, name: any, props: any) => {\n if (name === '_connector') return ['', '']\n const entry = props?.payload\n if (!entry) return [value, name]\n const displayValue = entry.displayValue ?? value\n return [\n yAxisFormat ? formatAxisValue(displayValue, yAxisFormat) : displayValue?.toLocaleString?.() ?? displayValue,\n entry.isTotal ? 'Total' : entry.isNegative ? 'Decrease' : 'Increase',\n ]\n }}\n labelFormatter={(label: string) => label}\n />\n <Legend\n wrapperStyle={{ fontSize: '12px', paddingTop: '8px' }}\n {...{\n payload: [\n { value: 'Increase', type: 'rect' as const, color: POSITIVE_COLOR },\n { value: 'Decrease', type: 'rect' as const, color: NEGATIVE_COLOR },\n ...(showTotal ? [{ value: 'Total', type: 'rect' as const, color: TOTAL_COLOR }] : []),\n ],\n }}\n />\n <Bar dataKey=\"runningBase\" stackId=\"wf\" fill=\"transparent\" legendType=\"none\" isAnimationActive={false} />\n <Bar\n dataKey=\"value\"\n stackId=\"wf\"\n isAnimationActive={false}\n cursor={drillEnabled ? 'pointer' : undefined}\n onClick={(barData: any, _index: number, event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled && barData && !barData.isTotal) {\n onDataPointClick({\n dataPoint: barData,\n clickedField: yAxisField!,\n xValue: barData.label,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event,\n })\n }\n }}\n >\n {showDataLabels && (\n <LabelList\n dataKey=\"displayValue\"\n content={(props: any) => (\n <ValueLabel\n {...props}\n runningBase={chartData[props.index]?.runningBase}\n isNegative={chartData[props.index]?.isNegative}\n displayValue={chartData[props.index]?.displayValue}\n />\n )}\n />\n )}\n {chartData.map((entry, index) => (\n <Cell\n key={`cell-${index}`}\n fill={entry.isTotal ? TOTAL_COLOR : entry.isNegative ? NEGATIVE_COLOR : POSITIVE_COLOR}\n />\n ))}\n </Bar>\n {showConnectorLine && (\n <Line\n type=\"stepAfter\"\n dataKey=\"_connector\"\n stroke={CONNECTOR_COLOR}\n strokeWidth={1.5}\n strokeDasharray=\"4 2\"\n dot={false}\n activeDot={false}\n legendType=\"none\"\n isAnimationActive={false}\n />\n )}\n </ComposedChart>\n </ChartContainer>\n </div>\n )\n } catch (error) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full text-dc-error dc:p-4\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.chartError', { chartType: 'Waterfall Chart' })}</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : t('chart.runtime.unknownError')}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">{t('chart.runtime.checkConfig')}</div>\n </div>\n </div>\n )\n }\n})\n\nexport default WaterfallChart\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-waterfall-DyvQReN5.js","names":[],"sources":["../../../src/client/components/charts/WaterfallChart.tsx"],"sourcesContent":["import React, { useMemo } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { ComposedChart, Bar, Line, XAxis, YAxis, CartesianGrid, Cell, LabelList, Legend } from 'recharts'\nimport ChartContainer from './ChartContainer.js'\nimport ChartTooltip from './ChartTooltip.js'\nimport AngledXAxisTick from './AngledXAxisTick.js'\nimport { CHART_MARGINS } from '../../utils/chartConstants.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel.js'\nimport type { ChartProps } from '../../types.js'\n\nconst POSITIVE_COLOR = '#22c55e'\nconst NEGATIVE_COLOR = '#ef4444'\nconst TOTAL_COLOR = '#6366f1'\nconst CONNECTOR_COLOR = '#94a3b8'\n\ninterface WaterfallDataPoint {\n label: string\n value: number\n runningBase: number\n isTotal: boolean\n isNegative: boolean\n displayValue: number\n originalIndex: number\n}\n\nfunction transformToWaterfall(\n data: Record<string, unknown>[],\n xField: string,\n yField: string,\n showTotal: boolean,\n getFieldLabel: (field: string) => string\n): WaterfallDataPoint[] {\n let running = 0\n const result: WaterfallDataPoint[] = data.map((row, i) => {\n const label = String(row[xField] ?? `Row ${i + 1}`)\n const rawValue = row[yField]\n const parsed = typeof rawValue === 'number' ? rawValue : parseFloat(String(rawValue ?? ''))\n const value = isNaN(parsed) ? 0 : parsed\n const isNegative = value < 0\n const base = isNegative ? running + value : running\n const point: WaterfallDataPoint = {\n label,\n value: Math.abs(value),\n runningBase: base,\n isTotal: false,\n isNegative,\n displayValue: value,\n originalIndex: i,\n }\n running += value\n return point\n })\n\n if (showTotal) {\n const totalLabel = getFieldLabel(yField) || 'Total'\n result.push({\n label: totalLabel,\n value: Math.abs(running),\n runningBase: running >= 0 ? 0 : running,\n isTotal: true,\n isNegative: running < 0,\n displayValue: running,\n originalIndex: result.length,\n })\n }\n\n return result\n}\n\ninterface ValueLabelProps {\n x?: number\n y?: number\n width?: number\n value?: number\n isNegative?: boolean\n displayValue?: number\n}\n\nfunction ValueLabel(props: ValueLabelProps) {\n const { x = 0, y = 0, width = 0, value = 0, isNegative, displayValue } = props\n if (displayValue === undefined || displayValue === null) return null\n const numericValue = Number(displayValue)\n const isNeg = isNegative || numericValue < 0\n const yPos = isNeg ? y + value + 14 : y - 6\n return (\n <text\n x={x + width / 2}\n y={yPos}\n fill=\"currentColor\"\n textAnchor=\"middle\"\n fontSize={11}\n >\n {numericValue >= 0 ? '+' : ''}{numericValue.toLocaleString()}\n </text>\n )\n}\n\nconst WaterfallChart = React.memo(function WaterfallChart({\n data,\n chartConfig,\n displayConfig = {},\n height = '100%',\n onDataPointClick,\n drillEnabled,\n}: ChartProps) {\n const { t } = useTranslation()\n const getFieldLabel = useCubeFieldLabel()\n\n const showTotal = displayConfig?.showTotal ?? true\n const showConnectorLine = displayConfig?.showConnectorLine ?? true\n const showDataLabels = displayConfig?.showDataLabels ?? false\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\n const { xAxisField, yAxisField, configError } = useMemo(() => {\n const xAxisField: string | undefined = Array.isArray(chartConfig?.xAxis)\n ? chartConfig.xAxis[0]\n : chartConfig?.x\n const yAxisField: string | undefined = Array.isArray(chartConfig?.yAxis)\n ? chartConfig.yAxis[0]\n : chartConfig?.y?.[0]\n const configError =\n !xAxisField || !yAxisField\n ? 'Waterfall chart requires an X-axis dimension and a Y-axis measure'\n : null\n return { xAxisField, yAxisField, configError }\n }, [chartConfig])\n\n const waterfallData = useMemo(() => {\n if (configError || !data || data.length === 0 || !xAxisField || !yAxisField) return []\n return transformToWaterfall(\n data as Record<string, unknown>[],\n xAxisField,\n yAxisField,\n showTotal,\n getFieldLabel\n )\n }, [data, xAxisField, yAxisField, showTotal, getFieldLabel, configError])\n\n const connectorData = useMemo(() => {\n if (!showConnectorLine || waterfallData.length === 0) return []\n return waterfallData.map((d) => {\n const connectorY = d.isNegative ? d.runningBase : d.runningBase + d.value\n return { label: d.label, _connector: connectorY }\n })\n }, [waterfallData, showConnectorLine])\n\n const chartData = useMemo(() => {\n return waterfallData.map((d, i) => ({\n ...d,\n _connector: connectorData[i]?._connector,\n }))\n }, [waterfallData, connectorData])\n\n try {\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.waterfall')}</div>\n </div>\n </div>\n )\n }\n\n if (configError) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.configError')}</div>\n <div className=\"dc:text-xs\">{configError}</div>\n </div>\n </div>\n )\n }\n return (\n <div className=\"dc:relative dc:w-full\" style={{ height }}>\n <ChartContainer height=\"100%\">\n <ComposedChart data={chartData} margin={{ ...CHART_MARGINS, left: 40 }} accessibilityLayer={false}>\n <CartesianGrid strokeDasharray=\"3 3\" style={{ pointerEvents: 'none' }} />\n <XAxis dataKey=\"label\" type=\"category\" tick={<AngledXAxisTick />} height={60} />\n <YAxis\n tick={{ fontSize: 12 }}\n tickFormatter={yAxisFormat ? (v) => formatAxisValue(v, yAxisFormat) : undefined}\n />\n <ChartTooltip\n formatter={(value: any, name: any, props: any) => {\n if (name === '_connector') return ['', '']\n const entry = props?.payload\n if (!entry) return [value, name]\n const displayValue = entry.displayValue ?? value\n return [\n yAxisFormat ? formatAxisValue(displayValue, yAxisFormat) : displayValue?.toLocaleString?.() ?? displayValue,\n entry.isTotal ? 'Total' : entry.isNegative ? 'Decrease' : 'Increase',\n ]\n }}\n labelFormatter={(label: string) => label}\n />\n <Legend\n wrapperStyle={{ fontSize: '12px', paddingTop: '8px' }}\n {...{\n payload: [\n { value: 'Increase', type: 'rect' as const, color: POSITIVE_COLOR },\n { value: 'Decrease', type: 'rect' as const, color: NEGATIVE_COLOR },\n ...(showTotal ? [{ value: 'Total', type: 'rect' as const, color: TOTAL_COLOR }] : []),\n ],\n }}\n />\n <Bar dataKey=\"runningBase\" stackId=\"wf\" fill=\"transparent\" legendType=\"none\" isAnimationActive={false} />\n <Bar\n dataKey=\"value\"\n stackId=\"wf\"\n isAnimationActive={false}\n cursor={drillEnabled ? 'pointer' : undefined}\n onClick={(barData: any, _index: number, event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled && barData && !barData.isTotal) {\n onDataPointClick({\n dataPoint: barData,\n clickedField: yAxisField!,\n xValue: barData.label,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event,\n })\n }\n }}\n >\n {showDataLabels && (\n <LabelList\n dataKey=\"displayValue\"\n content={(props: any) => (\n <ValueLabel\n {...props}\n runningBase={chartData[props.index]?.runningBase}\n isNegative={chartData[props.index]?.isNegative}\n displayValue={chartData[props.index]?.displayValue}\n />\n )}\n />\n )}\n {chartData.map((entry, index) => (\n <Cell\n key={`cell-${index}`}\n fill={entry.isTotal ? TOTAL_COLOR : entry.isNegative ? NEGATIVE_COLOR : POSITIVE_COLOR}\n />\n ))}\n </Bar>\n {showConnectorLine && (\n <Line\n type=\"stepAfter\"\n dataKey=\"_connector\"\n stroke={CONNECTOR_COLOR}\n strokeWidth={1.5}\n strokeDasharray=\"4 2\"\n dot={false}\n activeDot={false}\n legendType=\"none\"\n isAnimationActive={false}\n />\n )}\n </ComposedChart>\n </ChartContainer>\n </div>\n )\n } catch (error) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full text-dc-error dc:p-4\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.chartError', { chartType: 'Waterfall Chart' })}</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : t('chart.runtime.unknownError')}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">{t('chart.runtime.checkConfig')}</div>\n </div>\n </div>\n )\n }\n})\n\nexport default WaterfallChart\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"charts-core-DaXSt1Dd.js","names":[],"sources":["../../../src/client/components/AnalysisBuilder/SectionHeading.tsx","../../../src/client/components/charts/AxisFormatControls.tsx"],"sourcesContent":["/**\n * SectionHeading Component\n *\n * A reusable section heading for the Analysis Builder panels.\n * Provides consistent styling that can be easily adjusted in one place.\n */\n\nimport type { ReactNode } from 'react'\n\ninterface SectionHeadingProps {\n children: ReactNode\n /** Optional className to add additional styles */\n className?: string\n}\n\n/**\n * Consistent section heading style for Analysis Builder panels.\n * Change the styles here to update all section headings at once.\n */\nexport default function SectionHeading({ children, className = '' }: SectionHeadingProps) {\n return (\n <h3 className={`dc:text-sm dc:font-semibold text-dc-primary dc:uppercase dc:tracking-wide ${className}`}>\n {children}\n </h3>\n )\n}\n","/**\n * AxisFormatControls Component\n *\n * A reusable component for configuring axis number formatting.\n * Provides controls for unit type, abbreviation, decimal places, and custom labels.\n */\n\nimport { useMemo } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport SectionHeading from '../AnalysisBuilder/SectionHeading'\nimport type { AxisFormatConfig } from '../../types'\nimport { formatAxisValue } from '../../utils/chartUtils'\n\ninterface AxisFormatControlsProps {\n value: AxisFormatConfig\n onChange: (config: AxisFormatConfig) => void\n axisLabel: string // \"X-Axis\", \"Left Y-Axis\", \"Right Y-Axis\"\n /** Sample value for preview (default: 1250000) */\n previewValue?: number\n}\n\n/**\n * Get the currency symbol for the user's locale\n */\nfunction getLocaleCurrencySymbol(): string {\n const locale = typeof navigator !== 'undefined' ? navigator.language : 'en-US'\n // Format a number as currency and extract just the symbol\n const formatted = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: getCurrencyCodeForLocale(locale),\n currencyDisplay: 'narrowSymbol'\n }).format(0)\n // Extract the currency symbol (remove digits, spaces, and common separators)\n return formatted.replace(/[\\d.,\\s]/g, '').trim() || '$'\n}\n\n/**\n * Get the currency code for a given locale (duplicated from chartUtils for component isolation)\n */\nfunction getCurrencyCodeForLocale(locale: string): string {\n const parts = locale.split('-')\n const region = parts[1]?.toUpperCase()\n const currencyMap: Record<string, string> = {\n 'US': 'USD', 'CA': 'CAD', 'GB': 'GBP', 'UK': 'GBP', 'AU': 'AUD', 'NZ': 'NZD',\n 'EU': 'EUR', 'DE': 'EUR', 'FR': 'EUR', 'IT': 'EUR', 'ES': 'EUR', 'NL': 'EUR',\n 'BE': 'EUR', 'AT': 'EUR', 'IE': 'EUR', 'PT': 'EUR', 'FI': 'EUR',\n 'JP': 'JPY', 'CN': 'CNY', 'KR': 'KRW', 'IN': 'INR', 'BR': 'BRL', 'MX': 'MXN',\n 'CH': 'CHF', 'SE': 'SEK', 'NO': 'NOK', 'DK': 'DKK', 'PL': 'PLN', 'RU': 'RUB',\n 'ZA': 'ZAR', 'SG': 'SGD', 'HK': 'HKD', 'TW': 'TWD', 'TH': 'THB', 'MY': 'MYR',\n 'PH': 'PHP', 'ID': 'IDR', 'VN': 'VND', 'AE': 'AED', 'SA': 'SAR', 'IL': 'ILS', 'TR': 'TRY',\n }\n return currencyMap[region] || 'USD'\n}\n\n/**\n * Single axis format control section\n */\nexport function AxisFormatControls({\n value,\n onChange,\n axisLabel,\n previewValue = 1250000\n}: AxisFormatControlsProps) {\n const { t } = useTranslation()\n const config = useMemo(() => value || {}, [value])\n\n // Get locale-aware currency symbol for the button\n const currencySymbol = useMemo(() => getLocaleCurrencySymbol(), [])\n\n // Generate preview of formatted value\n const preview = useMemo(() => {\n return formatAxisValue(previewValue, config)\n }, [previewValue, config])\n\n const handleChange = (updates: Partial<AxisFormatConfig>) => {\n onChange({ ...config, ...updates })\n }\n\n const unitButtons: Array<{ value: AxisFormatConfig['unit']; label: string }> = [\n { value: 'currency', label: currencySymbol },\n { value: 'percent', label: '%' },\n { value: 'number', label: '#' },\n { value: 'custom', label: t('chart.runtime.axisFormat.custom') }\n ]\n\n return (\n <div className=\"dc:space-y-3 dc:pb-4\">\n {/* Axis Header */}\n <SectionHeading>{axisLabel}</SectionHeading>\n\n {/* Label Input */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.label')}</label>\n <input\n type=\"text\"\n value={config.label || ''}\n onChange={(e) => handleChange({ label: e.target.value || undefined })}\n placeholder={t('chart.runtime.axisFormat.autoLabel')}\n className=\"dc:w-full dc:px-2 dc:py-1 dc:text-sm dc:border border-dc-border dc:rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n\n {/* Unit Type */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.unit')}</label>\n <div className=\"dc:flex dc:border border-dc-border dc:rounded-sm dc:overflow-hidden\">\n {unitButtons.map((btn) => (\n <button\n key={btn.value}\n type=\"button\"\n onClick={() => handleChange({ unit: btn.value })}\n className={`dc:flex-1 dc:px-2 dc:py-1.5 dc:text-sm dc:font-medium dc:transition-colors ${\n config.unit === btn.value\n ? 'bg-dc-primary text-white'\n : 'bg-dc-surface text-dc-text hover:bg-dc-border'\n }`}\n >\n {btn.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Custom Prefix/Suffix (only when Custom is selected) */}\n {config.unit === 'custom' && (\n <div className=\"dc:flex dc:gap-2\">\n <div className=\"dc:flex-1 dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.prefix')}</label>\n <input\n type=\"text\"\n value={config.customPrefix || ''}\n onChange={(e) => handleChange({ customPrefix: e.target.value || undefined })}\n placeholder={t('chart.runtime.axisFormat.prefixExample')}\n className=\"dc:w-full dc:px-2 dc:py-1 dc:text-sm dc:border border-dc-border dc:rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n <div className=\"dc:flex-1 dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.suffix')}</label>\n <input\n type=\"text\"\n value={config.customSuffix || ''}\n onChange={(e) => handleChange({ customSuffix: e.target.value || undefined })}\n placeholder={t('chart.runtime.axisFormat.suffixExample')}\n className=\"dc:w-full dc:px-2 dc:py-1 dc:text-sm dc:border border-dc-border dc:rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n </div>\n )}\n\n {/* Abbreviation Toggle */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.abbreviation')}</label>\n <div className=\"dc:flex dc:border border-dc-border dc:rounded-sm dc:overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => handleChange({ abbreviate: true })}\n className={`dc:flex-1 dc:px-3 dc:py-1.5 dc:text-sm dc:font-medium dc:transition-colors ${\n config.abbreviate !== false\n ? 'bg-dc-primary text-white'\n : 'bg-dc-surface text-dc-text hover:bg-dc-border'\n }`}\n >\n {t('chart.runtime.axisFormat.yes')}\n </button>\n <button\n type=\"button\"\n onClick={() => handleChange({ abbreviate: false })}\n className={`dc:flex-1 dc:px-3 dc:py-1.5 dc:text-sm dc:font-medium dc:transition-colors ${\n config.abbreviate === false\n ? 'bg-dc-primary text-white'\n : 'bg-dc-surface text-dc-text hover:bg-dc-border'\n }`}\n >\n {t('chart.runtime.axisFormat.no')}\n </button>\n </div>\n </div>\n\n {/* Decimals */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.decimals')}</label>\n <div className=\"dc:flex dc:gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n const current = config.decimals ?? 2\n if (current > 0) handleChange({ decimals: current - 1 })\n }}\n disabled={(config.decimals ?? 2) <= 0}\n className=\"dc:flex-1 dc:px-3 dc:py-2 dc:text-sm dc:border border-dc-border dc:rounded-sm bg-dc-surface text-dc-text hover:bg-dc-border dc:disabled:opacity-40 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n ← .0\n </button>\n <button\n type=\"button\"\n onClick={() => {\n const current = config.decimals ?? 2\n if (current < 4) handleChange({ decimals: current + 1 })\n }}\n disabled={(config.decimals ?? 2) >= 4}\n className=\"dc:flex-1 dc:px-3 dc:py-2 dc:text-sm dc:border border-dc-border dc:rounded-sm bg-dc-surface text-dc-text hover:bg-dc-border dc:disabled:opacity-40 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n .00 →\n </button>\n </div>\n </div>\n\n {/* Preview */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.preview')}</label>\n <div className=\"dc:text-sm dc:font-mono text-dc-text\">\n {preview}\n </div>\n </div>\n </div>\n )\n}\n\ninterface MultiAxisFormatControlsProps {\n displayConfig: {\n xAxisFormat?: AxisFormatConfig\n leftYAxisFormat?: AxisFormatConfig\n rightYAxisFormat?: AxisFormatConfig\n }\n onChange: (updates: {\n xAxisFormat?: AxisFormatConfig\n leftYAxisFormat?: AxisFormatConfig\n rightYAxisFormat?: AxisFormatConfig\n }) => void\n /** Which axes to show controls for */\n showAxes?: {\n xAxis?: boolean\n leftYAxis?: boolean\n rightYAxis?: boolean\n }\n}\n\ntype AxisKey = 'xAxisFormat' | 'leftYAxisFormat' | 'rightYAxisFormat'\n\ninterface AxisEntry {\n show: boolean | undefined\n key: AxisKey\n labelKey: string\n previewValue?: number\n}\n\n/**\n * Container component for multiple axis format controls. Each configured axis\n * renders an `AxisFormatControls`; the per-axis entries are data-driven so the\n * three branches collapse into a single map.\n */\nexport function MultiAxisFormatControls({\n displayConfig,\n onChange,\n showAxes = { leftYAxis: true, rightYAxis: true }\n}: MultiAxisFormatControlsProps) {\n const { t } = useTranslation()\n\n const entries: AxisEntry[] = [\n { show: showAxes.leftYAxis, key: 'leftYAxisFormat', labelKey: 'chart.runtime.axisFormat.leftYAxis' },\n { show: showAxes.rightYAxis, key: 'rightYAxisFormat', labelKey: 'chart.runtime.axisFormat.rightYAxis' },\n // Use a year-like number for X-axis preview\n { show: showAxes.xAxis, key: 'xAxisFormat', labelKey: 'chart.runtime.axisFormat.xAxis', previewValue: 2024 }\n ]\n\n const updateAxis = (key: AxisKey, config: AxisFormatConfig) =>\n onChange({ ...displayConfig, [key]: Object.keys(config).length > 0 ? config : undefined })\n\n return (\n <div className=\"dc:space-y-4\">\n {entries.filter((entry) => entry.show).map((entry) => (\n <AxisFormatControls\n key={entry.key}\n axisLabel={t(entry.labelKey)}\n value={displayConfig[entry.key] || {}}\n onChange={(config) => updateAxis(entry.key, config)}\n previewValue={entry.previewValue}\n />\n ))}\n </div>\n )\n}\n\nexport default AxisFormatControls\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"charts-core-DaXSt1Dd.js","names":[],"sources":["../../../src/client/components/AnalysisBuilder/SectionHeading.tsx","../../../src/client/components/charts/AxisFormatControls.tsx"],"sourcesContent":["/**\n * SectionHeading Component\n *\n * A reusable section heading for the Analysis Builder panels.\n * Provides consistent styling that can be easily adjusted in one place.\n */\n\nimport type { ReactNode } from 'react'\n\ninterface SectionHeadingProps {\n children: ReactNode\n /** Optional className to add additional styles */\n className?: string\n}\n\n/**\n * Consistent section heading style for Analysis Builder panels.\n * Change the styles here to update all section headings at once.\n */\nexport default function SectionHeading({ children, className = '' }: SectionHeadingProps) {\n return (\n <h3 className={`dc:text-sm dc:font-semibold text-dc-primary dc:uppercase dc:tracking-wide ${className}`}>\n {children}\n </h3>\n )\n}\n","/**\n * AxisFormatControls Component\n *\n * A reusable component for configuring axis number formatting.\n * Provides controls for unit type, abbreviation, decimal places, and custom labels.\n */\n\nimport { useMemo } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport SectionHeading from '../AnalysisBuilder/SectionHeading.js'\nimport type { AxisFormatConfig } from '../../types.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\n\ninterface AxisFormatControlsProps {\n value: AxisFormatConfig\n onChange: (config: AxisFormatConfig) => void\n axisLabel: string // \"X-Axis\", \"Left Y-Axis\", \"Right Y-Axis\"\n /** Sample value for preview (default: 1250000) */\n previewValue?: number\n}\n\n/**\n * Get the currency symbol for the user's locale\n */\nfunction getLocaleCurrencySymbol(): string {\n const locale = typeof navigator !== 'undefined' ? navigator.language : 'en-US'\n // Format a number as currency and extract just the symbol\n const formatted = new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: getCurrencyCodeForLocale(locale),\n currencyDisplay: 'narrowSymbol'\n }).format(0)\n // Extract the currency symbol (remove digits, spaces, and common separators)\n return formatted.replace(/[\\d.,\\s]/g, '').trim() || '$'\n}\n\n/**\n * Get the currency code for a given locale (duplicated from chartUtils for component isolation)\n */\nfunction getCurrencyCodeForLocale(locale: string): string {\n const parts = locale.split('-')\n const region = parts[1]?.toUpperCase()\n const currencyMap: Record<string, string> = {\n 'US': 'USD', 'CA': 'CAD', 'GB': 'GBP', 'UK': 'GBP', 'AU': 'AUD', 'NZ': 'NZD',\n 'EU': 'EUR', 'DE': 'EUR', 'FR': 'EUR', 'IT': 'EUR', 'ES': 'EUR', 'NL': 'EUR',\n 'BE': 'EUR', 'AT': 'EUR', 'IE': 'EUR', 'PT': 'EUR', 'FI': 'EUR',\n 'JP': 'JPY', 'CN': 'CNY', 'KR': 'KRW', 'IN': 'INR', 'BR': 'BRL', 'MX': 'MXN',\n 'CH': 'CHF', 'SE': 'SEK', 'NO': 'NOK', 'DK': 'DKK', 'PL': 'PLN', 'RU': 'RUB',\n 'ZA': 'ZAR', 'SG': 'SGD', 'HK': 'HKD', 'TW': 'TWD', 'TH': 'THB', 'MY': 'MYR',\n 'PH': 'PHP', 'ID': 'IDR', 'VN': 'VND', 'AE': 'AED', 'SA': 'SAR', 'IL': 'ILS', 'TR': 'TRY',\n }\n return currencyMap[region] || 'USD'\n}\n\n/**\n * Single axis format control section\n */\nexport function AxisFormatControls({\n value,\n onChange,\n axisLabel,\n previewValue = 1250000\n}: AxisFormatControlsProps) {\n const { t } = useTranslation()\n const config = useMemo(() => value || {}, [value])\n\n // Get locale-aware currency symbol for the button\n const currencySymbol = useMemo(() => getLocaleCurrencySymbol(), [])\n\n // Generate preview of formatted value\n const preview = useMemo(() => {\n return formatAxisValue(previewValue, config)\n }, [previewValue, config])\n\n const handleChange = (updates: Partial<AxisFormatConfig>) => {\n onChange({ ...config, ...updates })\n }\n\n const unitButtons: Array<{ value: AxisFormatConfig['unit']; label: string }> = [\n { value: 'currency', label: currencySymbol },\n { value: 'percent', label: '%' },\n { value: 'number', label: '#' },\n { value: 'custom', label: t('chart.runtime.axisFormat.custom') }\n ]\n\n return (\n <div className=\"dc:space-y-3 dc:pb-4\">\n {/* Axis Header */}\n <SectionHeading>{axisLabel}</SectionHeading>\n\n {/* Label Input */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.label')}</label>\n <input\n type=\"text\"\n value={config.label || ''}\n onChange={(e) => handleChange({ label: e.target.value || undefined })}\n placeholder={t('chart.runtime.axisFormat.autoLabel')}\n className=\"dc:w-full dc:px-2 dc:py-1 dc:text-sm dc:border border-dc-border dc:rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n\n {/* Unit Type */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.unit')}</label>\n <div className=\"dc:flex dc:border border-dc-border dc:rounded-sm dc:overflow-hidden\">\n {unitButtons.map((btn) => (\n <button\n key={btn.value}\n type=\"button\"\n onClick={() => handleChange({ unit: btn.value })}\n className={`dc:flex-1 dc:px-2 dc:py-1.5 dc:text-sm dc:font-medium dc:transition-colors ${\n config.unit === btn.value\n ? 'bg-dc-primary text-white'\n : 'bg-dc-surface text-dc-text hover:bg-dc-border'\n }`}\n >\n {btn.label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Custom Prefix/Suffix (only when Custom is selected) */}\n {config.unit === 'custom' && (\n <div className=\"dc:flex dc:gap-2\">\n <div className=\"dc:flex-1 dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.prefix')}</label>\n <input\n type=\"text\"\n value={config.customPrefix || ''}\n onChange={(e) => handleChange({ customPrefix: e.target.value || undefined })}\n placeholder={t('chart.runtime.axisFormat.prefixExample')}\n className=\"dc:w-full dc:px-2 dc:py-1 dc:text-sm dc:border border-dc-border dc:rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n <div className=\"dc:flex-1 dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.suffix')}</label>\n <input\n type=\"text\"\n value={config.customSuffix || ''}\n onChange={(e) => handleChange({ customSuffix: e.target.value || undefined })}\n placeholder={t('chart.runtime.axisFormat.suffixExample')}\n className=\"dc:w-full dc:px-2 dc:py-1 dc:text-sm dc:border border-dc-border dc:rounded-sm focus:ring-dc-accent focus:border-dc-accent bg-dc-surface text-dc-text\"\n />\n </div>\n </div>\n )}\n\n {/* Abbreviation Toggle */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.abbreviation')}</label>\n <div className=\"dc:flex dc:border border-dc-border dc:rounded-sm dc:overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => handleChange({ abbreviate: true })}\n className={`dc:flex-1 dc:px-3 dc:py-1.5 dc:text-sm dc:font-medium dc:transition-colors ${\n config.abbreviate !== false\n ? 'bg-dc-primary text-white'\n : 'bg-dc-surface text-dc-text hover:bg-dc-border'\n }`}\n >\n {t('chart.runtime.axisFormat.yes')}\n </button>\n <button\n type=\"button\"\n onClick={() => handleChange({ abbreviate: false })}\n className={`dc:flex-1 dc:px-3 dc:py-1.5 dc:text-sm dc:font-medium dc:transition-colors ${\n config.abbreviate === false\n ? 'bg-dc-primary text-white'\n : 'bg-dc-surface text-dc-text hover:bg-dc-border'\n }`}\n >\n {t('chart.runtime.axisFormat.no')}\n </button>\n </div>\n </div>\n\n {/* Decimals */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.decimals')}</label>\n <div className=\"dc:flex dc:gap-2\">\n <button\n type=\"button\"\n onClick={() => {\n const current = config.decimals ?? 2\n if (current > 0) handleChange({ decimals: current - 1 })\n }}\n disabled={(config.decimals ?? 2) <= 0}\n className=\"dc:flex-1 dc:px-3 dc:py-2 dc:text-sm dc:border border-dc-border dc:rounded-sm bg-dc-surface text-dc-text hover:bg-dc-border dc:disabled:opacity-40 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n ← .0\n </button>\n <button\n type=\"button\"\n onClick={() => {\n const current = config.decimals ?? 2\n if (current < 4) handleChange({ decimals: current + 1 })\n }}\n disabled={(config.decimals ?? 2) >= 4}\n className=\"dc:flex-1 dc:px-3 dc:py-2 dc:text-sm dc:border border-dc-border dc:rounded-sm bg-dc-surface text-dc-text hover:bg-dc-border dc:disabled:opacity-40 dc:disabled:cursor-not-allowed dc:transition-colors\"\n >\n .00 →\n </button>\n </div>\n </div>\n\n {/* Preview */}\n <div className=\"dc:space-y-1\">\n <label className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.axisFormat.preview')}</label>\n <div className=\"dc:text-sm dc:font-mono text-dc-text\">\n {preview}\n </div>\n </div>\n </div>\n )\n}\n\ninterface MultiAxisFormatControlsProps {\n displayConfig: {\n xAxisFormat?: AxisFormatConfig\n leftYAxisFormat?: AxisFormatConfig\n rightYAxisFormat?: AxisFormatConfig\n }\n onChange: (updates: {\n xAxisFormat?: AxisFormatConfig\n leftYAxisFormat?: AxisFormatConfig\n rightYAxisFormat?: AxisFormatConfig\n }) => void\n /** Which axes to show controls for */\n showAxes?: {\n xAxis?: boolean\n leftYAxis?: boolean\n rightYAxis?: boolean\n }\n}\n\ntype AxisKey = 'xAxisFormat' | 'leftYAxisFormat' | 'rightYAxisFormat'\n\ninterface AxisEntry {\n show: boolean | undefined\n key: AxisKey\n labelKey: string\n previewValue?: number\n}\n\n/**\n * Container component for multiple axis format controls. Each configured axis\n * renders an `AxisFormatControls`; the per-axis entries are data-driven so the\n * three branches collapse into a single map.\n */\nexport function MultiAxisFormatControls({\n displayConfig,\n onChange,\n showAxes = { leftYAxis: true, rightYAxis: true }\n}: MultiAxisFormatControlsProps) {\n const { t } = useTranslation()\n\n const entries: AxisEntry[] = [\n { show: showAxes.leftYAxis, key: 'leftYAxisFormat', labelKey: 'chart.runtime.axisFormat.leftYAxis' },\n { show: showAxes.rightYAxis, key: 'rightYAxisFormat', labelKey: 'chart.runtime.axisFormat.rightYAxis' },\n // Use a year-like number for X-axis preview\n { show: showAxes.xAxis, key: 'xAxisFormat', labelKey: 'chart.runtime.axisFormat.xAxis', previewValue: 2024 }\n ]\n\n const updateAxis = (key: AxisKey, config: AxisFormatConfig) =>\n onChange({ ...displayConfig, [key]: Object.keys(config).length > 0 ? config : undefined })\n\n return (\n <div className=\"dc:space-y-4\">\n {entries.filter((entry) => entry.show).map((entry) => (\n <AxisFormatControls\n key={entry.key}\n axisLabel={t(entry.labelKey)}\n value={displayConfig[entry.key] || {}}\n onChange={(config) => updateAxis(entry.key, config)}\n previewValue={entry.previewValue}\n />\n ))}\n </div>\n )\n}\n\nexport default AxisFormatControls\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"charts-loader-DdTeCeNo.js","names":[],"sources":["../../../src/client/charts/ChartLoader.tsx"],"sourcesContent":["/**\n * Lazy Chart Loader\n *\n * Provides React.lazy-based dynamic loading for chart components.\n * This enables code splitting - each chart type loads only when needed.\n *\n * Handles missing optional dependencies gracefully by showing a fallback\n * component instead of crashing the application.\n */\n\nimport { lazy, Suspense, ReactNode, LazyExoticComponent } from 'react'\nimport type { BuiltInChartType, ChartType, ChartProps } from '../types'\nimport {\n type LazyChartComponent,\n chartLoaderCache,\n failedChartTypes,\n customChartMap,\n createSafeImport,\n createUnknownChartFallback\n} from './chartComponentRegistry'\n\n// The custom-chart registration API lives in chartComponentRegistry to avoid an\n// import cycle (chartPlugin → ChartLoader → DataTable → CubeProvider → chartPlugin).\n// Re-exported here so existing import paths keep working.\nexport { registerChartComponent, unregisterChartComponent } from './chartComponentRegistry'\n\n// Dynamic import functions for built-in chart types\nconst chartImportMap: Record<BuiltInChartType, () => Promise<{ default: LazyChartComponent }>> = {\n bar: () => import('../components/charts/BarChart'),\n line: () => import('../components/charts/LineChart'),\n area: () => import('../components/charts/AreaChart'),\n pie: () => import('../components/charts/PieChart'),\n scatter: () => import('../components/charts/ScatterChart'),\n radar: () => import('../components/charts/RadarChart'),\n radialBar: () => import('../components/charts/RadialBarChart'),\n treemap: () => import('../components/charts/TreeMapChart'),\n bubble: () => import('../components/charts/BubbleChart'),\n table: () => import('../components/charts/DataTable'),\n activityGrid: () => import('../components/charts/ActivityGridChart'),\n kpiNumber: () => import('../components/charts/KpiNumber'),\n kpiDelta: () => import('../components/charts/KpiDelta'),\n kpiText: () => import('../components/charts/KpiText'),\n markdown: () => import('../components/charts/MarkdownChart'),\n funnel: () => import('../components/charts/FunnelChart'),\n sankey: () => import('../components/charts/SankeyChart'),\n sunburst: () => import('../components/charts/SunburstChart'),\n heatmap: () => import('../components/charts/HeatMapChart'),\n retentionHeatmap: () => import('../components/charts/RetentionHeatmap'),\n retentionCombined: () => import('../components/charts/RetentionCombinedChart'),\n boxPlot: () => import('../components/charts/BoxPlotChart'),\n waterfall: () => import('../components/charts/WaterfallChart'),\n candlestick: () => import('../components/charts/CandlestickChart'),\n measureProfile: () => import('../components/charts/MeasureProfileChart'),\n gauge: () => import('../components/charts/GaugeChart'),\n}\n\n/**\n * Get or create a lazy component for a chart type.\n * Checks custom (plugin) charts first, then built-in charts.\n * Returns an unknown chart fallback for unregistered types instead of throwing.\n */\nfunction getLazyChart(chartType: ChartType): LazyExoticComponent<LazyChartComponent> {\n // 1. Check custom charts first (allows overriding built-ins)\n const customChart = customChartMap.get(chartType)\n if (customChart) {\n return customChart\n }\n\n // 2. Check built-in cache\n if (chartLoaderCache.has(chartType)) {\n return chartLoaderCache.get(chartType)!\n }\n\n // 3. Check built-in import map\n const importFn = chartImportMap[chartType as BuiltInChartType]\n if (importFn) {\n const safeImport = createSafeImport(chartType, importFn)\n chartLoaderCache.set(chartType, lazy(safeImport))\n return chartLoaderCache.get(chartType)!\n }\n\n // 4. Unknown chart type — return graceful fallback\n return lazy(() => Promise.resolve({ default: createUnknownChartFallback(chartType) }))\n}\n\n/**\n * Check if a chart type is supported (built-in or custom plugin)\n */\nexport function isValidChartType(chartType: string): chartType is ChartType {\n return chartType in chartImportMap || customChartMap.has(chartType)\n}\n\n// Props for the LazyChart wrapper\nexport interface LazyChartProps extends ChartProps {\n chartType: ChartType\n fallback?: ReactNode\n}\n\n/**\n * Default loading placeholder for charts\n */\nfunction DefaultChartFallback({ height }: { height?: string | number }) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height: typeof height === 'number' ? `${height}px` : height || '200px' }}\n >\n <div className=\"dc:animate-pulse bg-dc-surface-secondary dc:rounded dc:w-full dc:h-full dc:min-h-[100px]\" />\n </div>\n )\n}\n\n/**\n * Lazy Chart Component\n *\n * Renders a chart component with React.lazy dynamic loading.\n * The chart type determines which chart component is loaded.\n *\n * @example\n * ```tsx\n * <LazyChart\n * chartType=\"bar\"\n * data={chartData}\n * chartConfig={{ yAxis: ['value'] }}\n * height={300}\n * />\n * ```\n */\nexport function LazyChart({\n chartType,\n fallback,\n height,\n ...chartProps\n}: LazyChartProps) {\n const ChartComponent = getLazyChart(chartType)\n\n return (\n <Suspense fallback={fallback ?? <DefaultChartFallback height={height} />}>\n <ChartComponent height={height} {...chartProps} />\n </Suspense>\n )\n}\n\n/**\n * Preload a chart type\n *\n * Triggers the dynamic import without rendering.\n * Useful for prefetching charts that will likely be needed.\n *\n * @example\n * ```tsx\n * // Preload bar chart on hover\n * onMouseEnter={() => preloadChart('bar')}\n * ```\n */\nexport function preloadChart(chartType: ChartType): void {\n const importFn = chartImportMap[chartType as BuiltInChartType]\n if (importFn) {\n importFn()\n }\n}\n\n/**\n * Preload multiple chart types\n *\n * @example\n * ```tsx\n * // Preload common charts on app init\n * useEffect(() => {\n * preloadCharts(['bar', 'line', 'pie'])\n * }, [])\n * ```\n */\nexport function preloadCharts(chartTypes: ChartType[]): void {\n chartTypes.forEach(preloadChart)\n}\n\n/**\n * Get all available chart types (built-in + custom plugins)\n */\nexport function getAvailableChartTypes(): ChartType[] {\n const builtIn = Object.keys(chartImportMap) as ChartType[]\n const custom = Array.from(customChartMap.keys())\n // Deduplicate in case a custom chart overrides a built-in\n return [...new Set([...builtIn, ...custom])]\n}\n\n/**\n * Check if a chart type has loaded successfully.\n * Returns false if the chart failed to load due to missing dependencies.\n *\n * Note: This only returns accurate results after the chart has been attempted to load.\n * Use this for conditional UI logic (e.g., hiding unavailable chart types).\n */\nexport function isChartTypeAvailable(chartType: ChartType): boolean {\n return !failedChartTypes.has(chartType)\n}\n\n/**\n * Get list of chart types that failed to load due to missing dependencies.\n */\nexport function getUnavailableChartTypes(): ChartType[] {\n return Array.from(failedChartTypes)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"charts-loader-DdTeCeNo.js","names":[],"sources":["../../../src/client/charts/ChartLoader.tsx"],"sourcesContent":["/**\n * Lazy Chart Loader\n *\n * Provides React.lazy-based dynamic loading for chart components.\n * This enables code splitting - each chart type loads only when needed.\n *\n * Handles missing optional dependencies gracefully by showing a fallback\n * component instead of crashing the application.\n */\n\nimport { lazy, Suspense, ReactNode, LazyExoticComponent } from 'react'\nimport type { BuiltInChartType, ChartType, ChartProps } from '../types.js'\nimport {\n type LazyChartComponent,\n chartLoaderCache,\n failedChartTypes,\n customChartMap,\n createSafeImport,\n createUnknownChartFallback\n} from './chartComponentRegistry.js'\n\n// The custom-chart registration API lives in chartComponentRegistry to avoid an\n// import cycle (chartPlugin → ChartLoader → DataTable → CubeProvider → chartPlugin).\n// Re-exported here so existing import paths keep working.\nexport { registerChartComponent, unregisterChartComponent } from './chartComponentRegistry.js'\n\n// Dynamic import functions for built-in chart types\nconst chartImportMap: Record<BuiltInChartType, () => Promise<{ default: LazyChartComponent }>> = {\n bar: () => import('../components/charts/BarChart.js'),\n line: () => import('../components/charts/LineChart.js'),\n area: () => import('../components/charts/AreaChart.js'),\n pie: () => import('../components/charts/PieChart.js'),\n scatter: () => import('../components/charts/ScatterChart.js'),\n radar: () => import('../components/charts/RadarChart.js'),\n radialBar: () => import('../components/charts/RadialBarChart.js'),\n treemap: () => import('../components/charts/TreeMapChart.js'),\n bubble: () => import('../components/charts/BubbleChart.js'),\n table: () => import('../components/charts/DataTable.js'),\n activityGrid: () => import('../components/charts/ActivityGridChart.js'),\n kpiNumber: () => import('../components/charts/KpiNumber.js'),\n kpiDelta: () => import('../components/charts/KpiDelta.js'),\n kpiText: () => import('../components/charts/KpiText.js'),\n markdown: () => import('../components/charts/MarkdownChart.js'),\n funnel: () => import('../components/charts/FunnelChart.js'),\n sankey: () => import('../components/charts/SankeyChart.js'),\n sunburst: () => import('../components/charts/SunburstChart.js'),\n heatmap: () => import('../components/charts/HeatMapChart.js'),\n retentionHeatmap: () => import('../components/charts/RetentionHeatmap.js'),\n retentionCombined: () => import('../components/charts/RetentionCombinedChart.js'),\n boxPlot: () => import('../components/charts/BoxPlotChart.js'),\n waterfall: () => import('../components/charts/WaterfallChart.js'),\n candlestick: () => import('../components/charts/CandlestickChart.js'),\n measureProfile: () => import('../components/charts/MeasureProfileChart.js'),\n gauge: () => import('../components/charts/GaugeChart.js'),\n}\n\n/**\n * Get or create a lazy component for a chart type.\n * Checks custom (plugin) charts first, then built-in charts.\n * Returns an unknown chart fallback for unregistered types instead of throwing.\n */\nfunction getLazyChart(chartType: ChartType): LazyExoticComponent<LazyChartComponent> {\n // 1. Check custom charts first (allows overriding built-ins)\n const customChart = customChartMap.get(chartType)\n if (customChart) {\n return customChart\n }\n\n // 2. Check built-in cache\n if (chartLoaderCache.has(chartType)) {\n return chartLoaderCache.get(chartType)!\n }\n\n // 3. Check built-in import map\n const importFn = chartImportMap[chartType as BuiltInChartType]\n if (importFn) {\n const safeImport = createSafeImport(chartType, importFn)\n chartLoaderCache.set(chartType, lazy(safeImport))\n return chartLoaderCache.get(chartType)!\n }\n\n // 4. Unknown chart type — return graceful fallback\n return lazy(() => Promise.resolve({ default: createUnknownChartFallback(chartType) }))\n}\n\n/**\n * Check if a chart type is supported (built-in or custom plugin)\n */\nexport function isValidChartType(chartType: string): chartType is ChartType {\n return chartType in chartImportMap || customChartMap.has(chartType)\n}\n\n// Props for the LazyChart wrapper\nexport interface LazyChartProps extends ChartProps {\n chartType: ChartType\n fallback?: ReactNode\n}\n\n/**\n * Default loading placeholder for charts\n */\nfunction DefaultChartFallback({ height }: { height?: string | number }) {\n return (\n <div\n className=\"dc:flex dc:items-center dc:justify-center dc:w-full\"\n style={{ height: typeof height === 'number' ? `${height}px` : height || '200px' }}\n >\n <div className=\"dc:animate-pulse bg-dc-surface-secondary dc:rounded dc:w-full dc:h-full dc:min-h-[100px]\" />\n </div>\n )\n}\n\n/**\n * Lazy Chart Component\n *\n * Renders a chart component with React.lazy dynamic loading.\n * The chart type determines which chart component is loaded.\n *\n * @example\n * ```tsx\n * <LazyChart\n * chartType=\"bar\"\n * data={chartData}\n * chartConfig={{ yAxis: ['value'] }}\n * height={300}\n * />\n * ```\n */\nexport function LazyChart({\n chartType,\n fallback,\n height,\n ...chartProps\n}: LazyChartProps) {\n const ChartComponent = getLazyChart(chartType)\n\n return (\n <Suspense fallback={fallback ?? <DefaultChartFallback height={height} />}>\n <ChartComponent height={height} {...chartProps} />\n </Suspense>\n )\n}\n\n/**\n * Preload a chart type\n *\n * Triggers the dynamic import without rendering.\n * Useful for prefetching charts that will likely be needed.\n *\n * @example\n * ```tsx\n * // Preload bar chart on hover\n * onMouseEnter={() => preloadChart('bar')}\n * ```\n */\nexport function preloadChart(chartType: ChartType): void {\n const importFn = chartImportMap[chartType as BuiltInChartType]\n if (importFn) {\n importFn()\n }\n}\n\n/**\n * Preload multiple chart types\n *\n * @example\n * ```tsx\n * // Preload common charts on app init\n * useEffect(() => {\n * preloadCharts(['bar', 'line', 'pie'])\n * }, [])\n * ```\n */\nexport function preloadCharts(chartTypes: ChartType[]): void {\n chartTypes.forEach(preloadChart)\n}\n\n/**\n * Get all available chart types (built-in + custom plugins)\n */\nexport function getAvailableChartTypes(): ChartType[] {\n const builtIn = Object.keys(chartImportMap) as ChartType[]\n const custom = Array.from(customChartMap.keys())\n // Deduplicate in case a custom chart overrides a built-in\n return [...new Set([...builtIn, ...custom])]\n}\n\n/**\n * Check if a chart type has loaded successfully.\n * Returns false if the chart failed to load due to missing dependencies.\n *\n * Note: This only returns accurate results after the chart has been attempted to load.\n * Use this for conditional UI logic (e.g., hiding unavailable chart types).\n */\nexport function isChartTypeAvailable(chartType: ChartType): boolean {\n return !failedChartTypes.has(chartType)\n}\n\n/**\n * Get list of chart types that failed to load due to missing dependencies.\n */\nexport function getUnavailableChartTypes(): ChartType[] {\n return Array.from(failedChartTypes)\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retention-ChW9jYdy.js","names":[],"sources":["../../../src/client/types/retention.ts"],"sourcesContent":["/**\n * Retention Analysis Types\n *\n * Types for Retention analysis mode which tracks cohort-based retention over time.\n * Retention analysis measures what percentage of users from each cohort return\n * in subsequent time periods.\n */\n\nimport type { Filter } from '../types'\nimport type { FunnelBindingKey } from './funnel'\n\n// ============================================================================\n// Date Range Types\n// ============================================================================\n\n/**\n * Date range for cohort analysis (REQUIRED)\n * Matches server's RetentionDateRange interface\n */\nexport interface DateRange {\n /** Start date (inclusive), ISO 8601 format (YYYY-MM-DD) */\n start: string\n /** End date (inclusive), ISO 8601 format (YYYY-MM-DD) */\n end: string\n}\n\n/**\n * Preset date range type\n */\nexport type DateRangePreset =\n | 'last_30_days'\n | 'last_3_months'\n | 'last_6_months'\n | 'last_12_months'\n | 'this_year'\n | 'last_year'\n | 'custom'\n\n/**\n * Preset date range options for the UI\n */\nexport const RETENTION_DATE_RANGE_PRESETS: { value: DateRangePreset; label: string }[] = [\n { value: 'last_30_days', label: 'Last 30 days' },\n { value: 'last_3_months', label: 'Last 3 months' },\n { value: 'last_6_months', label: 'Last 6 months' },\n { value: 'last_12_months', label: 'Last 12 months' },\n { value: 'this_year', label: 'This year' },\n { value: 'last_year', label: 'Last year' },\n { value: 'custom', label: 'Custom range' },\n]\n\n/**\n * Default preset for retention date range\n */\nexport const DEFAULT_DATE_RANGE_PRESET: DateRangePreset = 'last_3_months'\n\n/**\n * Calculate date range from a preset value\n * Returns ISO date strings (YYYY-MM-DD)\n */\nexport function getDateRangeFromPreset(preset: DateRangePreset): DateRange {\n const now = new Date()\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n\n switch (preset) {\n case 'last_30_days': {\n const start = new Date(today)\n start.setDate(start.getDate() - 30)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(today),\n }\n }\n case 'last_3_months': {\n // Start of 3 months ago to end of last month\n const start = new Date(today.getFullYear(), today.getMonth() - 3, 1)\n const end = new Date(today.getFullYear(), today.getMonth(), 0) // Last day of previous month\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'last_6_months': {\n const start = new Date(today.getFullYear(), today.getMonth() - 6, 1)\n const end = new Date(today.getFullYear(), today.getMonth(), 0)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'last_12_months': {\n const start = new Date(today.getFullYear(), today.getMonth() - 12, 1)\n const end = new Date(today.getFullYear(), today.getMonth(), 0)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'this_year': {\n const start = new Date(today.getFullYear(), 0, 1)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(today),\n }\n }\n case 'last_year': {\n const start = new Date(today.getFullYear() - 1, 0, 1)\n const end = new Date(today.getFullYear() - 1, 11, 31)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'custom':\n default:\n // For custom, return last 3 months as fallback\n return getDateRangeFromPreset('last_3_months')\n }\n}\n\n/**\n * Format a Date object to ISO date string (YYYY-MM-DD)\n */\nfunction formatDateToISO(date: Date): string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\n/**\n * Detect which preset a date range matches, if any\n */\nexport function detectDateRangePreset(range: DateRange): DateRangePreset {\n for (const preset of RETENTION_DATE_RANGE_PRESETS) {\n if (preset.value === 'custom') continue\n const presetRange = getDateRangeFromPreset(preset.value)\n if (presetRange.start === range.start && presetRange.end === range.end) {\n return preset.value\n }\n }\n return 'custom'\n}\n\n// ============================================================================\n// Server Query Format\n// ============================================================================\n\n/**\n * Server retention query format\n * This is the shape sent to the server for execution\n * Wrapped in { retention: {...} } similar to funnel queries\n */\nexport interface ServerRetentionQuery {\n retention: RetentionQueryConfig\n}\n\n/**\n * Retention query configuration\n * Contains all parameters needed for server-side retention analysis\n *\n * Simplified Mixpanel-style format:\n * - Single cube and timestamp dimension\n * - Single cohort (date range defines the cohort, not granularity)\n * - Optional breakdown dimension for segmentation\n */\nexport interface RetentionQueryConfig {\n /**\n * Single timestamp dimension for the analysis.\n * String format (e.g., 'Events.timestamp'),\n * Object format for multi-cube with explicit cube reference.\n */\n timeDimension: string | { cube: string; dimension: string }\n\n /**\n * Binding key - dimension that links users across events.\n * This is typically a user ID or other entity identifier.\n * String for single-cube (e.g., 'Events.userId'),\n * Array for multi-cube with different column names per cube.\n */\n bindingKey: string | { cube: string; dimension: string }[]\n\n /**\n * Date range for cohort analysis (REQUIRED).\n * Users who first performed the cohort action within this range are included.\n */\n dateRange: DateRange\n\n /**\n * Granularity for viewing retention periods.\n * Determines how retention periods are measured (day/week/month).\n */\n granularity: RetentionGranularity\n\n /**\n * Number of periods to calculate (e.g., 12 for 12 weeks).\n * Period 0 is always the cohort entry period.\n */\n periods: number\n\n /**\n * Retention type:\n * - 'classic': User returned exactly in period N (bounded)\n * - 'rolling': User returned in period N or any later period (unbounded)\n */\n retentionType: RetentionType\n\n /**\n * Optional filters on cohort entry events.\n * Applied when identifying which users enter the cohort.\n */\n cohortFilters?: Filter | Filter[]\n\n /**\n * Optional filters on return activity events.\n * Applied when checking for user activity in each period.\n */\n activityFilters?: Filter | Filter[]\n\n /**\n * Optional breakdown dimensions for segmenting the cohort.\n * When provided, retention is calculated per breakdown value combination.\n * e.g., [\"Events.country\"] or [\"Events.country\", \"Events.plan\"]\n */\n breakdownDimensions?: string[]\n}\n\n// ============================================================================\n// Enums and Unions\n// ============================================================================\n\n/**\n * Supported granularity levels for retention analysis\n */\nexport type RetentionGranularity = 'day' | 'week' | 'month'\n\n/**\n * Retention calculation types\n * - classic: User active exactly in period N\n * - rolling: User active in period N or any later period\n */\nexport type RetentionType = 'classic' | 'rolling'\n\n// ============================================================================\n// Result Types\n// ============================================================================\n\n/**\n * Single retention data point returned from server\n * Results are returned as a flat array; client transforms to matrix if needed\n */\nexport interface RetentionResultRow {\n /** Period number (0 = cohort entry, 1 = first retention period, etc.) */\n period: number\n\n /** Number of users in the cohort */\n cohortSize: number\n\n /** Number of users retained in this period */\n retainedUsers: number\n\n /** Retention rate as decimal (0-1), e.g., 0.45 for 45% */\n retentionRate: number\n\n /** Breakdown value when breakdown dimension is specified (e.g., \"US\", \"UK\") */\n breakdownValue?: string | null\n}\n\n/**\n * Retention chart data format for visualization\n * Supports both heatmap and line chart modes\n */\nexport interface RetentionChartData {\n rows: RetentionResultRow[]\n /** Period numbers (0 to periods) */\n periods: number[]\n /** Breakdown values when breakdown dimension is specified */\n breakdownValues?: string[]\n /** Summary statistics */\n summary?: RetentionSummary\n /** Granularity of retention periods (day/week/month) for period label formatting */\n granularity?: RetentionGranularity\n /** Human-readable label extracted from the binding key dimension (e.g., \"userId\" from \"Users.userId\") */\n bindingKeyLabel?: string\n}\n\n/**\n * Summary statistics for retention analysis\n */\nexport interface RetentionSummary {\n /** Total unique users in the cohort */\n totalUsers: number\n /** Average retention rate across all periods for period 1 */\n avgPeriod1Retention: number\n /** Highest retention rate for period 1 */\n maxPeriod1Retention: number\n /** Lowest retention rate for period 1 */\n minPeriod1Retention: number\n /** Number of breakdown segments (1 if no breakdown) */\n segmentCount?: number\n}\n\n// ============================================================================\n// Breakdown Types\n// ============================================================================\n\n/**\n * Breakdown item for retention analysis (single dimension)\n * Follows Mixpanel pattern - one breakdown dimension only\n */\nexport interface RetentionBreakdownItem {\n /** Full dimension name (e.g., \"Events.country\") */\n field: string\n /** Display label for the dimension */\n label?: string\n}\n\n// ============================================================================\n// Slice State (for Zustand store)\n// ============================================================================\n\n/**\n * Retention mode state for the AnalysisBuilder store\n * Simplified Mixpanel-style with single global configuration\n *\n * Key simplifications from previous version:\n * - Single cube for all (no separate cohort/activity cubes)\n * - Single timestamp dimension\n * - Single cohort with breakdown support (no cohort explosion)\n * - Granularity = viewing periods only\n */\nexport interface RetentionSliceState {\n /** Single cube for retention analysis */\n retentionCube: string | null\n\n /** Binding key that identifies entities (reuses funnel binding key type) */\n retentionBindingKey: FunnelBindingKey | null\n\n /** Single timestamp dimension for both cohort entry and activity */\n retentionTimeDimension: string | null\n\n /** Date range for cohort analysis (REQUIRED) */\n retentionDateRange: DateRange\n\n /** Filters that define who enters the cohort */\n retentionCohortFilters: Filter[]\n\n /** Filters that define what counts as a return */\n retentionActivityFilters: Filter[]\n\n /** Optional breakdown dimensions for segmenting the cohort */\n retentionBreakdowns: RetentionBreakdownItem[]\n\n /** Granularity for viewing retention periods (day/week/month) */\n retentionViewGranularity: RetentionGranularity\n\n /** Number of periods to analyze (1-52) */\n retentionPeriods: number\n\n /** Type of retention calculation */\n retentionType: RetentionType\n}\n\n/**\n * Retention slice actions for the store\n */\nexport interface RetentionSliceActions {\n /** Set the single cube for retention analysis */\n setRetentionCube: (cube: string | null) => void\n /** Set the retention binding key */\n setRetentionBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the single timestamp dimension */\n setRetentionTimeDimension: (dim: string | null) => void\n /** Set the date range (REQUIRED) */\n setRetentionDateRange: (range: DateRange) => void\n /** Set all cohort filters at once */\n setRetentionCohortFilters: (filters: Filter[]) => void\n /** Add a cohort filter */\n addRetentionCohortFilter: (filter: Filter) => void\n /** Remove a cohort filter by index */\n removeRetentionCohortFilter: (index: number) => void\n /** Update a cohort filter by index */\n updateRetentionCohortFilter: (index: number, filter: Filter) => void\n /** Set all activity filters at once */\n setRetentionActivityFilters: (filters: Filter[]) => void\n /** Add an activity filter */\n addRetentionActivityFilter: (filter: Filter) => void\n /** Remove an activity filter by index */\n removeRetentionActivityFilter: (index: number) => void\n /** Update an activity filter by index */\n updateRetentionActivityFilter: (index: number, filter: Filter) => void\n /** Set all breakdown dimensions */\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) => void\n /** Add a breakdown dimension */\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) => void\n /** Remove a breakdown dimension by field name */\n removeRetentionBreakdown: (field: string) => void\n /** Set the view granularity */\n setRetentionViewGranularity: (granularity: RetentionGranularity) => void\n /** Set the number of periods */\n setRetentionPeriods: (periods: number) => void\n /** Set the retention type */\n setRetentionType: (type: RetentionType) => void\n /** Check if in retention mode (analysisType === 'retention') */\n isRetentionMode: () => boolean\n /** Check if retention mode is properly configured and ready for execution */\n isRetentionModeEnabled: () => boolean\n /** Build ServerRetentionQuery from retention state */\n buildRetentionQuery: () => ServerRetentionQuery | null\n /** Get validation errors explaining why retention query cannot be built */\n getRetentionValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Type guard to check if data is retention chart data\n */\nexport function isRetentionData(data: unknown): data is RetentionChartData {\n if (!data || typeof data !== 'object') return false\n const d = data as Record<string, unknown>\n return (\n Array.isArray(d.rows) &&\n Array.isArray(d.periods)\n )\n}\n\n/**\n * Type guard to detect server retention query format\n * Used to distinguish { retention: {...} } from CubeQuery, etc.\n */\nexport function isServerRetentionQuery(obj: unknown): obj is ServerRetentionQuery {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n 'retention' in obj &&\n typeof (obj as { retention: unknown }).retention === 'object'\n )\n}\n\n/**\n * Field name → expected `typeof` result for the required retention-result-row\n * fields. Used by `isRetentionResultRow` to validate a row in a single pass.\n */\nconst RETENTION_RESULT_ROW_FIELD_TYPES: Record<string, 'string' | 'number'> = {\n cohortPeriod: 'string',\n period: 'number',\n cohortSize: 'number',\n retainedUsers: 'number',\n retentionRate: 'number',\n}\n\n/**\n * Type guard for retention result row\n */\nexport function isRetentionResultRow(row: unknown): row is RetentionResultRow {\n if (!row || typeof row !== 'object') return false\n const r = row as Record<string, unknown>\n return Object.entries(RETENTION_RESULT_ROW_FIELD_TYPES).every(\n ([field, expectedType]) => typeof r[field] === expectedType\n )\n}\n\n// ============================================================================\n// Default Values\n// ============================================================================\n\n/**\n * Default retention slice state for store initialization\n */\nexport const defaultRetentionSliceState: RetentionSliceState = {\n retentionCube: null,\n retentionBindingKey: null,\n retentionTimeDimension: null,\n retentionDateRange: getDateRangeFromPreset(DEFAULT_DATE_RANGE_PRESET),\n retentionCohortFilters: [],\n retentionActivityFilters: [],\n retentionBreakdowns: [],\n retentionViewGranularity: 'week',\n retentionPeriods: 12,\n retentionType: 'classic',\n}\n\n/**\n * Minimum and maximum values for retention periods\n */\nexport const RETENTION_MIN_PERIODS = 1\nexport const RETENTION_MAX_PERIODS = 52\n\n/**\n * Available granularity options\n */\nexport const RETENTION_GRANULARITY_OPTIONS: { value: RetentionGranularity; label: string }[] = [\n { value: 'day', label: 'Daily' },\n { value: 'week', label: 'Weekly' },\n { value: 'month', label: 'Monthly' },\n]\n\n/**\n * Available retention type options\n */\nexport const RETENTION_TYPE_OPTIONS: { value: RetentionType; label: string; description: string }[] = [\n {\n value: 'classic',\n label: 'Classic',\n description: 'User was active in exactly period N',\n },\n {\n value: 'rolling',\n label: 'Rolling',\n description: 'User was active in period N or later',\n },\n]\n"],"mappings":";AAyCA,IAAa,IAA4E;CACvF;EAAE,OAAO;EAAgB,OAAO;CAAe;CAC/C;EAAE,OAAO;EAAiB,OAAO;CAAgB;CACjD;EAAE,OAAO;EAAiB,OAAO;CAAgB;CACjD;EAAE,OAAO;EAAkB,OAAO;CAAiB;CACnD;EAAE,OAAO;EAAa,OAAO;CAAY;CACzC;EAAE,OAAO;EAAa,OAAO;CAAY;CACzC;EAAE,OAAO;EAAU,OAAO;CAAe;AAC3C,GAKa,IAA6C;AAM1D,SAAgB,EAAuB,GAAoC;CACzE,IAAM,oBAAM,IAAI,KAAK,GACf,IAAQ,IAAI,KAAK,EAAI,YAAY,GAAG,EAAI,SAAS,GAAG,EAAI,QAAQ,CAAC;CAEvE,QAAQ,GAAR;EACE,KAAK,gBAAgB;GACnB,IAAM,IAAQ,IAAI,KAAK,CAAK;GAE5B,OADA,EAAM,QAAQ,EAAM,QAAQ,IAAI,EAAE,GAC3B;IACL,OAAO,EAAgB,CAAK;IAC5B,KAAK,EAAgB,CAAK;GAC5B;EACF;EACA,KAAK,iBAAiB;GAEpB,IAAM,IAAQ,IAAI,KAAK,EAAM,YAAY,GAAG,EAAM,SAAS,IAAI,GAAG,CAAC,GAC7D,IAAM,IAAI,KAAK,EAAM,YAAY,GAAG,EAAM,SAAS,GAAG,CAAC;GAC7D,OAAO;IACL,OAAO,EAAgB,CAAK;IAC5B,KAAK,EAAgB,CAAG;GAC1B;EACF;EACA,KAAK,iBAAiB;GACpB,IAAM,IAAQ,IAAI,KAAK,EAAM,YAAY,GAAG,EAAM,SAAS,IAAI,GAAG,CAAC,GAC7D,IAAM,IAAI,KAAK,EAAM,YAAY,GAAG,EAAM,SAAS,GAAG,CAAC;GAC7D,OAAO;IACL,OAAO,EAAgB,CAAK;IAC5B,KAAK,EAAgB,CAAG;GAC1B;EACF;EACA,KAAK,kBAAkB;GACrB,IAAM,IAAQ,IAAI,KAAK,EAAM,YAAY,GAAG,EAAM,SAAS,IAAI,IAAI,CAAC,GAC9D,IAAM,IAAI,KAAK,EAAM,YAAY,GAAG,EAAM,SAAS,GAAG,CAAC;GAC7D,OAAO;IACL,OAAO,EAAgB,CAAK;IAC5B,KAAK,EAAgB,CAAG;GAC1B;EACF;EACA,KAAK,aAEH,OAAO;GACL,OAAO,EAAgB,IAFP,KAAK,EAAM,YAAY,GAAG,GAAG,CAEtB,CAAK;GAC5B,KAAK,EAAgB,CAAK;EAC5B;EAEF,KAAK,aAAa;GAChB,IAAM,IAAQ,IAAI,KAAK,EAAM,YAAY,IAAI,GAAG,GAAG,CAAC,GAC9C,IAAM,IAAI,KAAK,EAAM,YAAY,IAAI,GAAG,IAAI,EAAE;GACpD,OAAO;IACL,OAAO,EAAgB,CAAK;IAC5B,KAAK,EAAgB,CAAG;GAC1B;EACF;EAEA,SAEE,OAAO,EAAuB,eAAe;CACjD;AACF;AAKA,SAAS,EAAgB,GAAoB;CAI3C,OAAO,GAHM,EAAK,YAGR,EAAK,GAFD,OAAO,EAAK,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAEpC,EAAM,GADZ,OAAO,EAAK,QAAQ,CAAC,EAAE,SAAS,GAAG,GACpB;AAC7B;AAKA,SAAgB,EAAsB,GAAmC;CACvE,KAAK,IAAM,KAAU,GAA8B;EACjD,IAAI,EAAO,UAAU,UAAU;EAC/B,IAAM,IAAc,EAAuB,EAAO,KAAK;EACvD,IAAI,EAAY,UAAU,EAAM,SAAS,EAAY,QAAQ,EAAM,KACjE,OAAO,EAAO;CAElB;CACA,OAAO;AACT;AAsRA,SAAgB,EAAgB,GAA2C;CACzE,IAAI,CAAC,KAAQ,OAAO,KAAS,UAAU,OAAO;CAC9C,IAAM,IAAI;CACV,OACE,MAAM,QAAQ,EAAE,IAAI,KACpB,MAAM,QAAQ,EAAE,OAAO;AAE3B;AAMA,SAAgB,EAAuB,GAA2C;CAChF,OACE,OAAO,KAAQ,cACf,KACA,eAAe,KACf,OAAQ,EAA+B,aAAc;AAEzD;AAgCA,IAAa,IAAkD;CAC7D,eAAe;CACf,qBAAqB;CACrB,wBAAwB;CACxB,oBAAoB,EAAuB,CAAyB;CACpE,wBAAwB,CAAC;CACzB,0BAA0B,CAAC;CAC3B,qBAAqB,CAAC;CACtB,0BAA0B;CAC1B,kBAAkB;CAClB,eAAe;AACjB,GAWa,IAAkF;CAC7F;EAAE,OAAO;EAAO,OAAO;CAAQ;CAC/B;EAAE,OAAO;EAAQ,OAAO;CAAS;CACjC;EAAE,OAAO;EAAS,OAAO;CAAU;AACrC,GAKa,IAAyF,CACpG;CACE,OAAO;CACP,OAAO;CACP,aAAa;AACf,GACA;CACE,OAAO;CACP,OAAO;CACP,aAAa;AACf,CACF"}
|
|
1
|
+
{"version":3,"file":"retention-ChW9jYdy.js","names":[],"sources":["../../../src/client/types/retention.ts"],"sourcesContent":["/**\n * Retention Analysis Types\n *\n * Types for Retention analysis mode which tracks cohort-based retention over time.\n * Retention analysis measures what percentage of users from each cohort return\n * in subsequent time periods.\n */\n\nimport type { Filter } from '../types.js'\nimport type { FunnelBindingKey } from './funnel.js'\n\n// ============================================================================\n// Date Range Types\n// ============================================================================\n\n/**\n * Date range for cohort analysis (REQUIRED)\n * Matches server's RetentionDateRange interface\n */\nexport interface DateRange {\n /** Start date (inclusive), ISO 8601 format (YYYY-MM-DD) */\n start: string\n /** End date (inclusive), ISO 8601 format (YYYY-MM-DD) */\n end: string\n}\n\n/**\n * Preset date range type\n */\nexport type DateRangePreset =\n | 'last_30_days'\n | 'last_3_months'\n | 'last_6_months'\n | 'last_12_months'\n | 'this_year'\n | 'last_year'\n | 'custom'\n\n/**\n * Preset date range options for the UI\n */\nexport const RETENTION_DATE_RANGE_PRESETS: { value: DateRangePreset; label: string }[] = [\n { value: 'last_30_days', label: 'Last 30 days' },\n { value: 'last_3_months', label: 'Last 3 months' },\n { value: 'last_6_months', label: 'Last 6 months' },\n { value: 'last_12_months', label: 'Last 12 months' },\n { value: 'this_year', label: 'This year' },\n { value: 'last_year', label: 'Last year' },\n { value: 'custom', label: 'Custom range' },\n]\n\n/**\n * Default preset for retention date range\n */\nexport const DEFAULT_DATE_RANGE_PRESET: DateRangePreset = 'last_3_months'\n\n/**\n * Calculate date range from a preset value\n * Returns ISO date strings (YYYY-MM-DD)\n */\nexport function getDateRangeFromPreset(preset: DateRangePreset): DateRange {\n const now = new Date()\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n\n switch (preset) {\n case 'last_30_days': {\n const start = new Date(today)\n start.setDate(start.getDate() - 30)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(today),\n }\n }\n case 'last_3_months': {\n // Start of 3 months ago to end of last month\n const start = new Date(today.getFullYear(), today.getMonth() - 3, 1)\n const end = new Date(today.getFullYear(), today.getMonth(), 0) // Last day of previous month\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'last_6_months': {\n const start = new Date(today.getFullYear(), today.getMonth() - 6, 1)\n const end = new Date(today.getFullYear(), today.getMonth(), 0)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'last_12_months': {\n const start = new Date(today.getFullYear(), today.getMonth() - 12, 1)\n const end = new Date(today.getFullYear(), today.getMonth(), 0)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'this_year': {\n const start = new Date(today.getFullYear(), 0, 1)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(today),\n }\n }\n case 'last_year': {\n const start = new Date(today.getFullYear() - 1, 0, 1)\n const end = new Date(today.getFullYear() - 1, 11, 31)\n return {\n start: formatDateToISO(start),\n end: formatDateToISO(end),\n }\n }\n case 'custom':\n default:\n // For custom, return last 3 months as fallback\n return getDateRangeFromPreset('last_3_months')\n }\n}\n\n/**\n * Format a Date object to ISO date string (YYYY-MM-DD)\n */\nfunction formatDateToISO(date: Date): string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\n/**\n * Detect which preset a date range matches, if any\n */\nexport function detectDateRangePreset(range: DateRange): DateRangePreset {\n for (const preset of RETENTION_DATE_RANGE_PRESETS) {\n if (preset.value === 'custom') continue\n const presetRange = getDateRangeFromPreset(preset.value)\n if (presetRange.start === range.start && presetRange.end === range.end) {\n return preset.value\n }\n }\n return 'custom'\n}\n\n// ============================================================================\n// Server Query Format\n// ============================================================================\n\n/**\n * Server retention query format\n * This is the shape sent to the server for execution\n * Wrapped in { retention: {...} } similar to funnel queries\n */\nexport interface ServerRetentionQuery {\n retention: RetentionQueryConfig\n}\n\n/**\n * Retention query configuration\n * Contains all parameters needed for server-side retention analysis\n *\n * Simplified Mixpanel-style format:\n * - Single cube and timestamp dimension\n * - Single cohort (date range defines the cohort, not granularity)\n * - Optional breakdown dimension for segmentation\n */\nexport interface RetentionQueryConfig {\n /**\n * Single timestamp dimension for the analysis.\n * String format (e.g., 'Events.timestamp'),\n * Object format for multi-cube with explicit cube reference.\n */\n timeDimension: string | { cube: string; dimension: string }\n\n /**\n * Binding key - dimension that links users across events.\n * This is typically a user ID or other entity identifier.\n * String for single-cube (e.g., 'Events.userId'),\n * Array for multi-cube with different column names per cube.\n */\n bindingKey: string | { cube: string; dimension: string }[]\n\n /**\n * Date range for cohort analysis (REQUIRED).\n * Users who first performed the cohort action within this range are included.\n */\n dateRange: DateRange\n\n /**\n * Granularity for viewing retention periods.\n * Determines how retention periods are measured (day/week/month).\n */\n granularity: RetentionGranularity\n\n /**\n * Number of periods to calculate (e.g., 12 for 12 weeks).\n * Period 0 is always the cohort entry period.\n */\n periods: number\n\n /**\n * Retention type:\n * - 'classic': User returned exactly in period N (bounded)\n * - 'rolling': User returned in period N or any later period (unbounded)\n */\n retentionType: RetentionType\n\n /**\n * Optional filters on cohort entry events.\n * Applied when identifying which users enter the cohort.\n */\n cohortFilters?: Filter | Filter[]\n\n /**\n * Optional filters on return activity events.\n * Applied when checking for user activity in each period.\n */\n activityFilters?: Filter | Filter[]\n\n /**\n * Optional breakdown dimensions for segmenting the cohort.\n * When provided, retention is calculated per breakdown value combination.\n * e.g., [\"Events.country\"] or [\"Events.country\", \"Events.plan\"]\n */\n breakdownDimensions?: string[]\n}\n\n// ============================================================================\n// Enums and Unions\n// ============================================================================\n\n/**\n * Supported granularity levels for retention analysis\n */\nexport type RetentionGranularity = 'day' | 'week' | 'month'\n\n/**\n * Retention calculation types\n * - classic: User active exactly in period N\n * - rolling: User active in period N or any later period\n */\nexport type RetentionType = 'classic' | 'rolling'\n\n// ============================================================================\n// Result Types\n// ============================================================================\n\n/**\n * Single retention data point returned from server\n * Results are returned as a flat array; client transforms to matrix if needed\n */\nexport interface RetentionResultRow {\n /** Period number (0 = cohort entry, 1 = first retention period, etc.) */\n period: number\n\n /** Number of users in the cohort */\n cohortSize: number\n\n /** Number of users retained in this period */\n retainedUsers: number\n\n /** Retention rate as decimal (0-1), e.g., 0.45 for 45% */\n retentionRate: number\n\n /** Breakdown value when breakdown dimension is specified (e.g., \"US\", \"UK\") */\n breakdownValue?: string | null\n}\n\n/**\n * Retention chart data format for visualization\n * Supports both heatmap and line chart modes\n */\nexport interface RetentionChartData {\n rows: RetentionResultRow[]\n /** Period numbers (0 to periods) */\n periods: number[]\n /** Breakdown values when breakdown dimension is specified */\n breakdownValues?: string[]\n /** Summary statistics */\n summary?: RetentionSummary\n /** Granularity of retention periods (day/week/month) for period label formatting */\n granularity?: RetentionGranularity\n /** Human-readable label extracted from the binding key dimension (e.g., \"userId\" from \"Users.userId\") */\n bindingKeyLabel?: string\n}\n\n/**\n * Summary statistics for retention analysis\n */\nexport interface RetentionSummary {\n /** Total unique users in the cohort */\n totalUsers: number\n /** Average retention rate across all periods for period 1 */\n avgPeriod1Retention: number\n /** Highest retention rate for period 1 */\n maxPeriod1Retention: number\n /** Lowest retention rate for period 1 */\n minPeriod1Retention: number\n /** Number of breakdown segments (1 if no breakdown) */\n segmentCount?: number\n}\n\n// ============================================================================\n// Breakdown Types\n// ============================================================================\n\n/**\n * Breakdown item for retention analysis (single dimension)\n * Follows Mixpanel pattern - one breakdown dimension only\n */\nexport interface RetentionBreakdownItem {\n /** Full dimension name (e.g., \"Events.country\") */\n field: string\n /** Display label for the dimension */\n label?: string\n}\n\n// ============================================================================\n// Slice State (for Zustand store)\n// ============================================================================\n\n/**\n * Retention mode state for the AnalysisBuilder store\n * Simplified Mixpanel-style with single global configuration\n *\n * Key simplifications from previous version:\n * - Single cube for all (no separate cohort/activity cubes)\n * - Single timestamp dimension\n * - Single cohort with breakdown support (no cohort explosion)\n * - Granularity = viewing periods only\n */\nexport interface RetentionSliceState {\n /** Single cube for retention analysis */\n retentionCube: string | null\n\n /** Binding key that identifies entities (reuses funnel binding key type) */\n retentionBindingKey: FunnelBindingKey | null\n\n /** Single timestamp dimension for both cohort entry and activity */\n retentionTimeDimension: string | null\n\n /** Date range for cohort analysis (REQUIRED) */\n retentionDateRange: DateRange\n\n /** Filters that define who enters the cohort */\n retentionCohortFilters: Filter[]\n\n /** Filters that define what counts as a return */\n retentionActivityFilters: Filter[]\n\n /** Optional breakdown dimensions for segmenting the cohort */\n retentionBreakdowns: RetentionBreakdownItem[]\n\n /** Granularity for viewing retention periods (day/week/month) */\n retentionViewGranularity: RetentionGranularity\n\n /** Number of periods to analyze (1-52) */\n retentionPeriods: number\n\n /** Type of retention calculation */\n retentionType: RetentionType\n}\n\n/**\n * Retention slice actions for the store\n */\nexport interface RetentionSliceActions {\n /** Set the single cube for retention analysis */\n setRetentionCube: (cube: string | null) => void\n /** Set the retention binding key */\n setRetentionBindingKey: (key: FunnelBindingKey | null) => void\n /** Set the single timestamp dimension */\n setRetentionTimeDimension: (dim: string | null) => void\n /** Set the date range (REQUIRED) */\n setRetentionDateRange: (range: DateRange) => void\n /** Set all cohort filters at once */\n setRetentionCohortFilters: (filters: Filter[]) => void\n /** Add a cohort filter */\n addRetentionCohortFilter: (filter: Filter) => void\n /** Remove a cohort filter by index */\n removeRetentionCohortFilter: (index: number) => void\n /** Update a cohort filter by index */\n updateRetentionCohortFilter: (index: number, filter: Filter) => void\n /** Set all activity filters at once */\n setRetentionActivityFilters: (filters: Filter[]) => void\n /** Add an activity filter */\n addRetentionActivityFilter: (filter: Filter) => void\n /** Remove an activity filter by index */\n removeRetentionActivityFilter: (index: number) => void\n /** Update an activity filter by index */\n updateRetentionActivityFilter: (index: number, filter: Filter) => void\n /** Set all breakdown dimensions */\n setRetentionBreakdowns: (breakdowns: RetentionBreakdownItem[]) => void\n /** Add a breakdown dimension */\n addRetentionBreakdown: (breakdown: RetentionBreakdownItem) => void\n /** Remove a breakdown dimension by field name */\n removeRetentionBreakdown: (field: string) => void\n /** Set the view granularity */\n setRetentionViewGranularity: (granularity: RetentionGranularity) => void\n /** Set the number of periods */\n setRetentionPeriods: (periods: number) => void\n /** Set the retention type */\n setRetentionType: (type: RetentionType) => void\n /** Check if in retention mode (analysisType === 'retention') */\n isRetentionMode: () => boolean\n /** Check if retention mode is properly configured and ready for execution */\n isRetentionModeEnabled: () => boolean\n /** Build ServerRetentionQuery from retention state */\n buildRetentionQuery: () => ServerRetentionQuery | null\n /** Get validation errors explaining why retention query cannot be built */\n getRetentionValidation: () => { isValid: boolean; errors: string[]; warnings: string[] }\n}\n\n// ============================================================================\n// Type Guards\n// ============================================================================\n\n/**\n * Type guard to check if data is retention chart data\n */\nexport function isRetentionData(data: unknown): data is RetentionChartData {\n if (!data || typeof data !== 'object') return false\n const d = data as Record<string, unknown>\n return (\n Array.isArray(d.rows) &&\n Array.isArray(d.periods)\n )\n}\n\n/**\n * Type guard to detect server retention query format\n * Used to distinguish { retention: {...} } from CubeQuery, etc.\n */\nexport function isServerRetentionQuery(obj: unknown): obj is ServerRetentionQuery {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n 'retention' in obj &&\n typeof (obj as { retention: unknown }).retention === 'object'\n )\n}\n\n/**\n * Field name → expected `typeof` result for the required retention-result-row\n * fields. Used by `isRetentionResultRow` to validate a row in a single pass.\n */\nconst RETENTION_RESULT_ROW_FIELD_TYPES: Record<string, 'string' | 'number'> = {\n cohortPeriod: 'string',\n period: 'number',\n cohortSize: 'number',\n retainedUsers: 'number',\n retentionRate: 'number',\n}\n\n/**\n * Type guard for retention result row\n */\nexport function isRetentionResultRow(row: unknown): row is RetentionResultRow {\n if (!row || typeof row !== 'object') return false\n const r = row as Record<string, unknown>\n return Object.entries(RETENTION_RESULT_ROW_FIELD_TYPES).every(\n ([field, expectedType]) => typeof r[field] === expectedType\n )\n}\n\n// ============================================================================\n// Default Values\n// ============================================================================\n\n/**\n * Default retention slice state for store initialization\n */\nexport const defaultRetentionSliceState: RetentionSliceState = {\n retentionCube: null,\n retentionBindingKey: null,\n retentionTimeDimension: null,\n retentionDateRange: getDateRangeFromPreset(DEFAULT_DATE_RANGE_PRESET),\n retentionCohortFilters: [],\n retentionActivityFilters: [],\n retentionBreakdowns: [],\n retentionViewGranularity: 'week',\n retentionPeriods: 12,\n retentionType: 'classic',\n}\n\n/**\n * Minimum and maximum values for retention periods\n */\nexport const RETENTION_MIN_PERIODS = 1\nexport const RETENTION_MAX_PERIODS = 52\n\n/**\n * Available granularity options\n */\nexport const RETENTION_GRANULARITY_OPTIONS: { value: RetentionGranularity; label: string }[] = [\n { value: 'day', label: 'Daily' },\n { value: 'week', label: 'Weekly' },\n { value: 'month', label: 'Monthly' },\n]\n\n/**\n * Available retention type options\n */\nexport const RETENTION_TYPE_OPTIONS: { value: RetentionType; label: string; description: string }[] = [\n {\n value: 'classic',\n label: 'Classic',\n description: 'User was active in exactly period N',\n },\n {\n value: 'rolling',\n label: 'Rolling',\n description: 'User was active in period N or later',\n },\n]\n"],"mappings":"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"}
|